* feat: gate terminal-agent teardown on ServerConfig.ownsTerminalAgent
Adds ownsTerminalAgent?: boolean to ServerConfig (default true). Wraps the
three shutdown side effects (pkill -f terminal-agent\.ts + 2 safeUnlinkQuiet
calls for terminal-port and terminal-internal-token) inside a single
if (ownsTerminalAgent) block. Embedders (gbrowser phoenix overlay) pass
false to keep their own PTY lifecycle intact across gstack's teardown.
CLI start() call site passes ownsTerminalAgent: true explicitly; static-grep
test in the new test file catches a refactor that drops it.
Strict opt-out: only explicit false flips the gate (cfg.ownsTerminalAgent
=== false ? false : true). Defends against JS callers passing truthy non-bool
values.
Adds __resetShuttingDown test-only export mirroring __resetRegistry. The
module-scoped isShuttingDown latch otherwise silently no-ops a second
shutdown() in the same process.
Drops dead try/catch wrappers around safeUnlinkQuiet inside the new gate —
safeUnlinkQuiet already swallows all errors internally.
New test file (4 cases) stubs both process.exit AND child_process.spawnSync
so a real pkill -f terminal-agent\.ts never fires on the developer machine.
beforeAll/afterAll save and restore real-daemon file contents in the state
dir so the test cannot clobber a running gstack session.
* chore: file followup TODOs (identity-based pkill, cfg.config composition gap, ownership-object trigger)
Three P3 followups surfaced by /autoplan + /plan-eng-review while reviewing
the ownsTerminalAgent gate:
- Identity-based terminal-agent kill: pkill -f terminal-agent\.ts is a latent
CLI footgun (regex match kills sibling gstack sessions, editor processes,
etc.). Replace with PID-tracked process.kill at both cli.ts:1047 and
server.ts:1281.
- shutdown() reads module-level config, not cfg.config (pre-existing
composition gap). Same gap applies to cleanSingletonLocks(resolveChromiumProfile())
at server.ts:1298 (should be cfg.chromiumProfile). Both are followup work
for the embedder-composition story.
- 4th caller-owned teardown gate trigger: today ServerConfig has 3 (xvfb?,
proxyBridge?, ownsTerminalAgent). If a 4th appears, collapse to
cfg.callerOwns?: Set<...> ownership object.
* chore: bump version and changelog (v1.42.1.0)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: note ServerConfig.ownsTerminalAgent in CLAUDE.md sidebar block
Adds a one-paragraph reference for the v1.42.1.0 embedder teardown gate
right after the Sidebar architecture block. Covers default semantics,
when embedders must pass `false`, polarity inversion vs xvfb?/proxyBridge?,
and the static-grep CI test that pins the CLI call site.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>