You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(terminal): one tab agent icon rule for desktop and mobile - #33963
Stacked on #33959: review the commits after f48b6b1.
ELI5
The agent icon on a terminal tab is now picked by the same code on the phone and on desktop. Before, the phone used a simpler order, so after you quit Claude and started Codex in the same tab, the phone kept showing Claude. Desktop also had two drifted copies of its own rule; now there is one.
What Changed
One desktop rule.src/renderer/src/lib/tab-agent-from-signals.ts moved to src/shared/tab-agent-from-signals.ts. The real tab strip (use-tab-agent.ts) had its own exported copy of resolveTabAgentFromSignals and resolveLaunchedAgentExitEvidence that had drifted from the tested file. That copy is deleted, and the hook imports the shared rule. The icon mapping agentTypeToIconAgent moved to src/shared/agent-type-icon-agent.ts; agent-status.ts re-exports it.
One snapshot entry point.resolveTabAgentFromSignalSnapshot (previously the logic inside open-tab-occupant-agent.ts) calls the resolver with partial signals as a remote client. Open-tab search and the phone both use it. hasObservedTabAgentSignal is shared by the tab strip and the snapshot path.
Before: hook, then launch agent, then the host's Cursor identity, then title. Launch Claude, /exit, run codex: the phone kept Claude. Now the Codex title takes the pane back from the finished Claude hook, as on desktop.
Before: an OMP tab whose hook reports pi showed Pi. Now it shows OMP, the owner.
The host's cursor identity (Cursor imports Claude hooks) is fed in as the process signal only when no hook or launch agent owns the tab, the same place the old phone code ranked it.
Desktop tab-strip changes (the tested rule replacing the drifted copy):
process, title and finished-hook signals are matched against the launch agent when it owns the pane (OMP/Pi);
an OMP wrapper title on a Pi-owned pane (or the reverse) no longer counts as another agent taking the pane over;
Windows Git Bash prompt titles count as "no agent", so exit detection clears the launch agent there.
Sleeping-session identity is kept on shell/exit evidence, as the shipping copy did, so a hibernated agent keeps its icon.
Why
Mobile and desktop disagreed on the icon. Desktop's tested rule wasn't the one the tab strip ran. Moving the pure resolver to src/shared leaves one copy for the tab strip, open-tab search and the phone.
Linked Issue
Part of the mobile/desktop parity audit
Visual Proof
N/A: this adopts desktop's existing rule, resolveTabAgentFromSignals (now src/shared/tab-agent-from-signals.ts).
Testing
I manually tested these changes locally
Automated tests added/updated, or explained why not below
Focused desktop tests (use-tab-agent*, open-tab occupant, decision table, hibernation shell-foreground) and mobile src/session. New phone tests cover the reclaim-after-exit and OMP/Pi cases, both failing on the old code, plus the cached-Cursor and unowned-Cursor cases. The decision-table counts match their values before #21714. No device run for this fleet.
AI Disclosure
Review
Agent skill upstream boundary
Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.
Notes
Mobile behaviors removed:
A hook agent name that isn't a known icon agent no longer passes through as the icon id.
A finished hook no longer always beats the title or the launch agent.
The host's cursor identity no longer ranks above the title when a hook or launch agent owns the tab.
Not done, and why:
The phone gets no process, sleeping-session or sibling-pane signals, so a tab whose only evidence is one of those shows no icon (or the launch agent) on the phone.
The phone receives the display title, so a renamed tab can't use the title signal. Fixing that needs a new wire field.
The fix(terminal): clear stale agent identity after shell exit #21714 fix (don't bring back a stale sleeping identity after /exit at a local shell) was only ever in the tested copy, not in the shipped tab strip. It conflicts with hibernation, which keeps the wake record on purpose, so the tab strip keeps the shipped behavior and that case stays open.
No wire changes; mixed phone/host versions are unaffected.
Checklist
This PR is small and focused
I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
Before/after screenshots or videos attached for UI changes, or N/A with reason
Self-reviewed for correctness, security, and performance
Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)
The changes update terminal keyboard-mode tracking, mode-aware input encoding, program-status query handling, selection, viewport, and contrast behavior. They also centralize agent identity resolution and worker-terminal takeover reporting in shared modules. Mobile and renderer callers and tests are updated to use these shared behaviors.
Priority: Normal
Merge Risk: Low · up to 3413d
Open-tab search can show an agent icon after the local terminal has returned to the shell. Align its identity resolution with the tab strip; this is a bounded display inconsistency rather than a blocker.
Pre-merge checks: 4 · 1
Failed checks: 1 inconclusive
Check name
Status
Explanation
Resolution
Docstring Coverage
Docstring coverage is 26.19% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surv…
Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed checks: 4 passed
Check name
Status
Explanation
Title check
The title clearly identifies the primary change: using one tab-agent icon rule across desktop and mobile.
Description check
The description covers the required change, rationale, testing, visual proof, scope, compatibility notes, and checklist. It does not include an issue number in the Linked Issue section, but the rest o…
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
Check skipped because no linked issues were found for this pull request.
Full details: Description check
Explanation
The description covers the required change, rationale, testing, visual proof, scope, compatibility notes, and checklist. It does not include an issue number in the Linked Issue section, but the rest of the description is complete and relevant.
Full details: Docstring Coverage
Explanation
Docstring coverage is 26.19% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 42 functions across 50 files. (26 skipped: 26 over the file limit.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
Finishing Touches: 💡 1
📝 Generate docstrings: 💡
Commit to this branch
Create a new PR
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
- ZWJ emoji width: activate the shared Orca unicode provider instead of plain Unicode 11.
- Contrast floor: share desktop's resolver and background parser; translucent
backgrounds composite over the published light/dark surface.
- Word selection: use xterm's default word separators via a shared rule.
- Takeover reports: share the 30 s gate and single retry between desktop and mobile.
- Use the shared viewport minimums and default scrollback rows.
Moves the tab-strip identity resolver to src/shared and deletes the drifted copy in use-tab-agent.ts, so the desktop tab strip, open-tab search and the phone all run one rule.
…vidence
The kill that hibernates a pane can report the shell foreground while the wake record is kept on purpose; the tab strip never retired sleeping identity on exit evidence, so the shared resolver keeps that behavior.
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.
Pass desktop shell evidence to the snapshot resolver.
resolveOpenTabOccupantAgent reads shellForeground but does not pass it to resolveTabAgentFromSignalSnapshot. That resolver forces isRemote: true, so idleIdentitySuppressed cannot clear a completed-hook identity for a local shell return. Open-tab search can therefore retain the completed-hook icon while useTabAgent clears it.
Make isRemote and processShellForeground optional snapshot inputs. Pass desktop values and keep the current mobile defaults.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #33959: review the commits after f48b6b1.
ELI5
The agent icon on a terminal tab is now picked by the same code on the phone and on desktop. Before, the phone used a simpler order, so after you quit Claude and started Codex in the same tab, the phone kept showing Claude. Desktop also had two drifted copies of its own rule; now there is one.
What Changed
src/renderer/src/lib/tab-agent-from-signals.tsmoved tosrc/shared/tab-agent-from-signals.ts. The real tab strip (use-tab-agent.ts) had its own exported copy ofresolveTabAgentFromSignalsandresolveLaunchedAgentExitEvidencethat had drifted from the tested file. That copy is deleted, and the hook imports the shared rule. The icon mappingagentTypeToIconAgentmoved tosrc/shared/agent-type-icon-agent.ts;agent-status.tsre-exports it.resolveTabAgentFromSignalSnapshot(previously the logic insideopen-tab-occupant-agent.ts) calls the resolver with partial signals as a remote client. Open-tab search and the phone both use it.hasObservedTabAgentSignalis shared by the tab strip and the snapshot path.resolveMobileTerminalTabAgentIdnow calls the shared rule with what the phone receives: a hook whose state isn'tdonecounts as live, adonehook as completed, plus the launch agent and the title./exit, runcodex: the phone kept Claude. Now the Codex title takes the pane back from the finished Claude hook, as on desktop.pishowed Pi. Now it shows OMP, the owner.cursoridentity (Cursor imports Claude hooks) is fed in as the process signal only when no hook or launch agent owns the tab, the same place the old phone code ranked it.Why
Mobile and desktop disagreed on the icon. Desktop's tested rule wasn't the one the tab strip ran. Moving the pure resolver to
src/sharedleaves one copy for the tab strip, open-tab search and the phone.Linked Issue
Part of the mobile/desktop parity audit
Visual Proof
N/A: this adopts desktop's existing rule,
resolveTabAgentFromSignals(nowsrc/shared/tab-agent-from-signals.ts).Testing
Focused desktop tests (
use-tab-agent*, open-tab occupant, decision table, hibernation shell-foreground) and mobilesrc/session. New phone tests cover the reclaim-after-exit and OMP/Pi cases, both failing on the old code, plus the cached-Cursor and unowned-Cursor cases. The decision-table counts match their values before #21714. No device run for this fleet.AI Disclosure
Review
Agent skill upstream boundary
Notes
Mobile behaviors removed:
cursoridentity no longer ranks above the title when a hook or launch agent owns the tab.Not done, and why:
/exitat a local shell) was only ever in the tested copy, not in the shipped tab strip. It conflicts with hibernation, which keeps the wake record on purpose, so the tab strip keeps the shipped behavior and that case stays open.No wire changes; mixed phone/host versions are unaffected.
Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)