Skip to content

fix: attribute /clear transcript to the agent whose activity stopped, not the active terminal - #366

Open
yshyuk wants to merge 1 commit into
pixel-agents-hq:mainfrom
yshyuk:fix/clear-claim-attribution
Open

fix: attribute /clear transcript to the agent whose activity stopped, not the active terminal#366
yshyuk wants to merge 1 commit into
pixel-agents-hq:mainfrom
yshyuk:fix/clear-claim-attribution

Conversation

@yshyuk

@yshyuk yshyuk commented Jul 28, 2026

Copy link
Copy Markdown

Fixes #251

Problem

With two Claude Code sessions in the same VS Code window (heuristic mode), running /clear in one session can swap the two characters' terminal bindings: clicking the busy-looking character focuses the cleared terminal and vice versa. See #251 for a detailed report and reproduction.

Cause

The heuristic /clear detection in server/src/fileWatcher.ts gated the claim of a freshly created /clear transcript on activeAgentIdRef.current === agentId — i.e. whichever agent owns the active terminal claims the new file. If /clear runs in a background session while the user is focused on a busy one, the busy agent claims the cleared session's transcript as soon as it goes idle for CLEAR_IDLE_THRESHOLD_MS (2 s, e.g. between tools), rebinding itself to the other session. Both agent records end up with correct-looking statuses but crossed terminalRefs — exactly the swap described in the issue.

A side effect of the old gate: a /clear in a non-active terminal was never detected at all.

Fix

Replace the active-terminal gate with pickClearClaimant(): among the eligible agents (internal, hookless, idle past the threshold), the one whose lastDataAt is closest to the new file's creation time (birthtimeMs) claims it. The session that ran /clear stopped writing its old transcript at exactly the moment the new file was created, so file-creation-time proximity is a far more reliable attribution signal than terminal focus. Each agent's own poll makes the decision, so no new coordination is needed; a poll simply skips the file when another agent is the better match.

The hooks path is unaffected — it already attributes /clear correctly via the per-agent pendingClear flag on SessionEnd(reason=clear).

Tests

  • New unit suite server/__tests__/pickClearClaimant.test.ts (5 cases): single-agent claim, best-match wins over the polling agent, polling agent keeps the file when it is the best match, busy agents excluded, external/hook-driven/terminal-less agents excluded.
  • npm run test:server — 283 passing.
  • npm run compile (types + lint + build) clean.

… not the active terminal

With two sessions in the same project dir, the heuristic /clear detection
claimed the new transcript for whichever agent owned the active terminal.
If /clear ran in a background session while the user watched a busy one,
the busy agent grabbed the cleared session's file as soon as it went idle
for 2s, swapping the two characters' terminal bindings (clicking the busy
character focused the cleared terminal and vice versa).

Replace the active-terminal gate with pickClearClaimant(): among eligible
idle internal agents, the one whose lastDataAt is closest to the new
file's creation time claims it — the session that ran /clear stopped
writing its old transcript at exactly that moment. This also allows
/clear in a non-active terminal to be detected at all.

Fixes pixel-agents-hq#251
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Clicking agent character opens wrong terminal after /clear in another session

1 participant