Repository navigation
fix(agents): join sessions in remove, name what cleanup sweeps past, report failed launches (#56) - #170
Conversation
Phase 1 of #56 (F-022). A worktree listed at a symlinked spelling now has to resolve to its real directory before the session join, or the new case in "gitGetWorktreeList agent join" goes red. Mutation: with toRealPath(worktreePath) at src/lib/git.ts:401 replaced by worktreePath, vitest gave 1 failed (the new case only), 1201 passed; reverted. Gate 1: pnpm check, typecheck, docs typecheck, build, test (1202), docs:test (69), test-markers grep - all exit 0. Gate 2: reviewer subagent, PASS WITH NOTES (notes in context/notes.md).
… names what it sweeps past (#56) Phase 3 of #56 (F-030). The override now overrules the verdict, not the lookup: sessions are always gathered, the sweep is classified on agent-stripped copies so the removed set and the three hold-back headings match an agent-free run, and each removed worktree the agent-aware verdict would have held back is named under "Removing <n> worktree branch(es) despite a live agent session:", under --force and before the prompt. Gate 2 loop: the first review (PASS WITH NOTES) found the heading could also name a live session in a worktree whose directory is gone, with or without the flag. Fixed in-host by requiring the original verdict to have been unsafe, pinned by an it.each over both flag states (failed on the earlier code), plus a zero-session case; the herdr-spaces guide no longer overstates the flag. Re-review: PASS WITH NOTES. Gate 1: pnpm check, typecheck, docs typecheck, build, test (1213), docs:test (69), test-markers grep - all exit 0.
Phase 4 of #56 (F-018). spawnDetached now returns why a launch did not start - pid undefined, or a synchronous spawn throw - and dispatchAgent sequences on it: no "Agent started" line, the warning "The agent could not be started (<message>), so the brief was not delivered." printed and in warnings, agent null, exit 1. The success line, the async onError handler and the argv-only spawn are unchanged. Deviation from the plan: the synchronous-throw test drives a real throw (a NUL byte in an argument, ERR_INVALID_ARG_VALUE) instead of mocking spawn. Gate 2 loop 1: FAIL - the warning was recorded for the document but never printed, so a human run never saw it and a synchronous throw was silent. Fixed by warn() in place of recordWarning(), pinned by a warn spy. Re-review: PASS WITH NOTES (notes in context/notes.md). By-hand pass (plan section 8) against bin/run.js, agent.command naming a missing program: human and --json both print "Warning: The agent could not be started (spawn worktree-no-such-agent failed to start), so the brief was not delivered.", no "Agent started" line, "agent":null, exit 1. Gate 1: pnpm check, typecheck, docs typecheck, build, test (1218, under the pinned Node v26.12.1), docs:test (69), test-markers grep - all exit 0.
…force (#56) Phase 2 of #56 (F-032). remove makes the run's one session lookup and uses it on both paths: the picker renders the Agent: detail and a worktree holding a blocking session lands under "Active branches" through the existing isSafeToRemove; the named path prefixes "An agent session (<name>) is working in this worktree." to whichever prompt applied before; under --force (so every --json run) "Removed <branch> while an agent session (<name>) was working in it." goes to stderr and into warnings. Idle sessions neither warn nor move an entry. gitRemoveWorktree takes the session from its caller and gathers no sessions itself. Mutations (caller, reverted): dropping hasLiveAgent from the named-path options gate failed 2 tests; dropping it from the warning gate failed 2. Gate 1: pnpm check, typecheck, docs typecheck, build, test (1231), docs:test (69), test-markers grep - all exit 0. Gate 2: reviewer subagent, PASS WITH NOTES (notes in context/notes.md).
…nts that keep their own record (#56) Phase 5 of #56 (F-019, accepted per D8). The branch page, the configuration page and the worktree skill now say that a detached agent's output is not kept anywhere, so agent.command should name an agent that keeps its own session record: claude --bg, reachable through claude agents, or codex exec unless --ephemeral is passed. Checked against claude --help and codex exec --help on this machine. Gate 2 (PASS WITH NOTES) noted the branch page dropped the --ephemeral caveat and left a short line and an ambiguous "It"; fixed in-host and re-reviewed: PASS WITH NOTES. Gate 1 (docs-only, per verify.md Rules): pnpm check exit 0, plus pnpm --filter docs typecheck exit 0 and docs:test (69) since SKILL.md is embedded into the docs chat.
craig-o-curtis
left a comment
There was a problem hiding this comment.
Approving. Read the diff against 9134d60; CI is green so I didn't rerun the gates.
Checked specifically:
cleanup --ignore-agentsnow always gathers sessions. That's safe as an escape hatch:listRuntimeSessions/listHerdrEntriesswallow errors and the runtime listing is bounded at 10s, so a broken session source can't block the sweep. The stripped-copy reclassification keeps the removed set and the hold-back headings identical to pre-agent behaviour, andcarriedis empty by construction without the flag.remove: one lookup per run, the picker path returns the selected entries (which carryagent), sowarnRemovedWhileWorkingsees the session on both paths.warnrecords into the document, so--jsongets it inwarningsas the docs say.- Failed detached launch:
pid === undefinedis checked synchronously, the existing "brief reached no agent" path supplies exit 1, and the test pinsagentnull + exit 1.
Non-blocking nit: when the program is missing, the user sees two lines: the new warning with the generic spawn <x> failed to start, then the onError line Error: spawn <x> ENOENT on the next tick. Fine to leave; if you touch it again, consider dropping the onError log when spawnDetached already returned a failure.
|
Thanks for the review. The nit is real: when the program is missing, |
Closes #56
Settles the seven agent-session findings (F-018, F-019, F-021, F-022, F-030, F-032, F-033). The plan and its finished ledger are in #56.
Already fixed, closed on evidence: F-021, F-022 (session side) and F-033 were fixed by 38cffe1 (#80).
Phases landed
77a9f75pins worktree-side path normalisation in the agent join (F-022).743d52amakesremovejoin agent sessions, prefix the prompt and warn under--force(F-032).315dcdbmakescleanup --ignore-agentslook, decide as before and name what it sweeps past (F-030).ec90170reports a detached agent launch that fails as failed:agent: null, a warning, exit1(F-018).e4eac24documents the supported agent shape (F-019): output is discarded, so the agent must keep its own record.Release note: one
patchnote (.changeset/quiet-agents-join.md). This is waiting on the release pull request, so nothing here ships to npm on merge.Open owner checks: the Codex session visibility check is filed as #169. The other two were waived.