fix(ui): the viewer server exits when the command it runs under is killed (#2119)

`codegraph ui` re-execs itself with `--liftoff-only`; the shim the user
started blocks in spawnSync and cannot forward a signal. Killing it by pid —
a process manager, an IDE task, `kill` — left the re-exec'd server serving
its port forever (found during a sweep: servers from hours earlier were still
answering on ports 4801–4808 against deleted indexes, holding their stdout
pipes so the harness that started them never exited). Ctrl+C was unaffected
(the signal reaches the whole process group).

`index`/`init` already guard this with the #277 PPID watchdog. Factor it out
of installCommandSupervision as `watchParent(onLost)` and use it in `ui` with
the same shutdown as SIGINT/SIGTERM (close the index, then the socket). The
liveness watchdog is deliberately not installed for `ui`: a long Steps
computation can legitimately hold the event loop.

Test: POSIX end-to-end through the real relaunch (CODEGRAPH_WASM_RELAUNCHED
unset, 200ms poll) — SIGKILL the shim, the port stops answering; confirmed
failing without the fix.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-09-30 04:17:34 +00:00
committed by GitHub
parent b50c7c0a70
commit 7cc2edadce
4 changed files with 67 additions and 26 deletions
+2
View File
@@ -169,6 +169,8 @@ These describe `codegraph ui` and its screens. They were taken out of `## [Unrel
## Fixes — Symbols, tests and the viewer
- **Stopping `codegraph ui` stops the server.** Killing the command by its process id, as a process manager, an editor task or `kill` does, left the server running on its port with no way to reach it, until the machine restarted. The server now notices it has been left behind and shuts down, closing the index first. Ctrl+C was never affected.
- **A SwiftUI view with a preview is no longer listed as a file that runs something.** A `#Preview { … }` sits at the top level of a view's file, so every view with one showed up under entry points as if it ran code. A preview is Xcode's canvas, not code the app runs: its calls no longer count, and a file whose only top-level code is previews leaves the list.
- **The Map opens a Maven or Gradle project on its packages.** A Java project keeps every file under `src/main/java/org/<company>/<app>/`, and those folders hold nothing but the next one, so the Map drew the whole program as one `src/main/java/org` box and no grouping option reached further. A folder with one subfolder and no files of its own no longer counts as a level: petclinic opens on `owner`, `vet`, `model` and `system`, each labelled `src/main/java/…/petclinic/owner`, with the full path on hover.