fix(sessions): stop co-located sessions from sharing one preview/topic#727
fix(sessions): stop co-located sessions from sharing one preview/topic#727muqsitnawaz wants to merge 1 commit into
Conversation
`sessions --active` showed the IDENTICAL preview + topic for every session in one cwd — 6 editor tabs, or two worktree siblings, all looked like duplicate cards. Root cause: findClaudeSessionFile fell back to the newest `.jsonl` in the cwd whenever a session's `<id>.jsonl` wasn't found, so N distinct sessions collapsed onto ONE file (preview + topic derive solely from that file). The id goes stale because an editor caches the launch uuid in live-terminals.json, but Claude rotates its transcript uuid on resume/compact — so the cached id no longer matches any file. - Extract `pickSessionFile(projectDir, id?)`: a concrete id returns its own file or undefined, NEVER a sibling's; the newest-file fallback is gated to the no-id case. - listTerminalsActive resolves each tab's EXACT id from the pid registry first (mirroring the headless path), so a tab finds its OWN current transcript. - classifyActivity: no resolvable file now means `idle`, not `running` (an unfindable session isn't evidence of activity — this path fires more now that we don't borrow). - Test active.pickfile.test.ts (real temp files, no mocks): a missing id yields undefined; two distinct missing ids don't collapse; no-id still picks newest. Verified end-to-end against the live fleet: 6 codium tabs went from 6x identical preview -> 6x distinct (blank, idle). Note: showing each tab's REAL preview still needs the upstream stale-id fix (editor should register the rotated uuid, or the pid registry must cover editor-launched pids) — tracked as follow-up.
Code ReviewerVerdict: Ready to merge — but hold per author's own instruction (rebase onto Build: Instructions read: Changes that work wellThe extraction of
Real temp files, no mocks — consistent with the repo's "real services only" testing rule. One thing to verify
In const resolvedId = readPidSessionEntry(t.pid)?.sessionId ?? t.sessionId;
const sessionFile = findSessionFileForKind(t.kind, t.cwd ?? undefined, resolvedId);
// ...
sessionId: t.sessionId ?? sessionIdFromFile(sessionFile), // ← still t.sessionIdWhen the pid registry has a fresh (post-rotate) uuid and This is a pre-existing pattern (the headless path has the same shape), and the PR description already acknowledges it as a known limitation — upstream fix is the editor registering the rotated uuid. Not a blocker; noting it so it lands in the follow-up ticket. Merge holdPer the PR description: hold merge until #724 restructure all-clear + rebase onto the new Reviewed by Code Reviewer — actually ran the build and tests on this branch. |
#728) * fix(sessions): stop co-located sessions from sharing one preview/topic `sessions --active` showed the IDENTICAL preview + topic for every session in one cwd — 6 editor tabs, or two worktree siblings, all looked like duplicate cards. Root cause: findClaudeSessionFile fell back to the newest `.jsonl` in the cwd whenever a session's `<id>.jsonl` wasn't found, so N distinct sessions collapsed onto ONE file (preview + topic derive solely from that file). The id goes stale because an editor caches the launch uuid in live-terminals.json, but Claude rotates its transcript uuid on resume/compact. - Extract `pickSessionFile(projectDir, id?)`: a concrete id returns its own file or undefined, NEVER a sibling's; the newest-file fallback is gated to the no-id case. - listTerminalsActive resolves each tab's EXACT id from the pid registry first (mirroring the headless path). - classifyActivity: no resolvable file now means `idle`, not `running`. - Test active.pickfile.test.ts (vitest, real temp files, no mocks). Verified end-to-end pre-restructure: 6 codium tabs went from 6x identical preview -> 6x distinct (blank, idle). Rebuilt on the apps/cli layout after #724. Supersedes #727 (which targeted the pre-restructure src/ path). * docs(sessions): correct pid-registry comment — no-op for editor shell pids Reviewer flagged the comment overstated the registry lookup: live-terminals.json stores the shell pid but the by-pid registry is keyed by the agent pid, so for editor-launched terminals the lookup returns undefined and falls back to the cached id. The duplicate-card fix is pickSessionFile no longer borrowing a sibling. Comment now says so; no behavior change.
Bug
agents sessions --activeshowed the identical preview + topic for every session in one cwd — 6 editor tabs, or two worktree siblings, all rendered the same activity and looked like duplicate cards.Root cause (debugged + verified by 2 independent reviewers)
findClaudeSessionFilefell through to the newest.jsonlin the cwd whenever a session's<id>.jsonlwasn't found, so N distinct sessions collapsed onto ONE file — andpreview/topicderive solely from that file. The id goes stale because an editor caches the launch uuid inlive-terminals.json, but Claude rotates its transcript uuid on resume/compact, so the cached id no longer matches any file.Fix
pickSessionFile(dir, id?): a concrete id returns its own file or undefined, never a sibling's; the newest-file fallback is gated to the no-id case.listTerminalsActiveresolves each tab's exact id from the pid registry first (mirroring the headless path).classifyActivity: no resolvable file ⇒ idle, not running.active.pickfile.test.ts(real temp files, no mocks).Verification
Live fleet: 6 codium tabs went from 6× identical preview → 6× distinct (blank, idle).
tscclean; active + pickfile tests green (7 pass).Known limitation / follow-up: previews are now blank (not each tab's real content) because the pid registry doesn't cover editor-launched pids and the cached ids are stale. Showing the real per-tab preview needs the upstream fix (editor registers the rotated uuid, or the pid registry covers those pids).