refactor(desktop): couple host-service to Electron, drop adoption

Merged
KI
6mo ago
+163-588

Summary

Host-service no longer survives Electron. The detach + manifest-adoption machinery was load-bearing back when host-service owned PTYs directly; now that pty-daemon (separate detached lifecycle, supervised by host-service) owns PTY survival, host-service itself has no reason to outlive the app.

  • Coordinator — spawn with `detached: false`. Remove `tryAdopt`, `discoverAll`, `teardownKnownManifests`, `releaseAll`, adopted-liveness timer, and the version-mismatch healing branch. `stop` / `stopAll` / `restart` / `reset` kept; `reset` is still the SIGKILL escape hatch for wedged manifests.
  • Quit path — `before-quit` always SIGTERMs host-services. `runFullQuitCleanup` collapses into `teardownTerminalHost` (v1 only).
  • Parent watchdog — host-service polls `process.ppid` against `HOST_PARENT_PID`. If Electron crashes / force-quits without sending SIGTERM, the child reaps itself within ~2s. CLI-spawned standalone host-services don't set the env var and skip the watchdog.
  • Graceful shutdown — SIGTERM gets a 3s drain, then `closeAllConnections` forces SSE/WS streams (chat completions, file watchers) closed so we don't hang.
  • Manifest — still written by the child so the CLI (`packages/cli`) can find a running service. Desktop coordinator no longer reads it for adoption, only for the `reset` recovery path.
  • Docs and tests updated; `HOST_SERVICE_LIFECYCLE.md` rewritten.

Net: ~390 lines deleted, simpler lifecycle, no orphan host-services.

Test plan

  • `bun run lint` clean
  • `bun run typecheck` clean in apps/desktop
  • All 1959 desktop tests pass
  • Manual: open a chat completion, Cmd+R the window, verify the renderer reconnects to a fresh host-service cleanly
  • Manual: `kill -9` the Electron process while a host-service is running, then `ps aux | grep host-service` ~10s later — should be empty (watchdog reaped it)
  • Manual: run auto-update install, verify new version's host-service starts fresh (no stale-adoption)
  • Manual: CLI `superset status` while desktop running — should still find host-service via manifest

Open in Stage

Summary by cubic

Coupled the desktop host-service to Electron so it starts and stops with the app; removed manifest adoption and simplified quit paths. PTY survival is handled by a detached pty-daemon, keeping terminals intact across restarts.

  • Refactors

    • Spawn host-service attached (detached: false); before-quit calls coordinator.stopAll().
    • Removed adoption code: tryAdopt, discoverAll, teardownKnownManifests, releaseAll, adopted-liveness timer, version-mismatch branch.
    • Deleted unused APIs: hasActiveInstances, listManifests; dropped spawnedByAppVersion from manifest and SUPERSET_APP_VERSION env.
    • Replaced runFullQuitCleanup with teardownTerminalHost (v1 only); dev SIGTERM/SIGINT also stops services.
    • Manifests still written by the child; desktop reads them only for reset. CLI in packages/cli still reads them.
  • Bug Fixes

    • Parent-pid watchdog starts at process boot so the child self-exits even if Electron crashes during startup.
    • Graceful SIGTERM with a 3s drain; closeAllConnections ends SSE/WS so shutdown doesn’t hang.
    • Removes the “wedged adopted service” path and prevents orphan host-service processes.

Summary by CodeRabbit

  • Improvements

    • Host services perform graceful shutdown with connection draining and forced-exit fallback for more reliable quits.
    • Host services monitor parent app health and self-exit if the app crashes, preventing orphaned processes.
  • Changes

    • Host-service lifecycle is now owned by the app—services stop on quit and are not re-adopted on restart.
    • Terminal PTYs survive via a separate daemon so open terminals persist after quitting.
    • CLI now consumes service manifests for status/control; manifests are removed on stop.

Review Change Stack