* fix(sidebar): show Cursor rows and stop a stray "claude" title hijacking OpenCode
Two defects in the same title-resolution path.
**#10258** — Cursor's only native OSC title is the literal `cursor agent`, which both title trackers dropped unconditionally. A hookless Cursor pane therefore had neither a status entry nor any title carrying Cursor identity, so the worktree card showed nothing at all.
**#8940** — two owner-blind paths let an incidental `claude` token anywhere in an OpenCode session or task title outrank the pane's known owner, so the tab icon and sidebar row flipped to Claude Code.
#10258: let the literal through exactly once as identity, so a restored or mobile tab keeps its Cursor row instead of vanishing. #8940: require an *identity frame* — after stripping status decoration the title must PRESENT Claude, not merely mention it — before a Claude title may reclaim a pane from its prior identity, and make the sidebar row builder owner-aware.
> These two are in one PR because they share the `ownerAgentType` plumbing through `buildTitleDerivedAgentRow` — split apart, neither half compiles on its own.
Fixes#10258Fixes#8940
Co-authored-by: Orca <help@stably.ai>
* test(e2e): add recordable proof for sidebar-agent-row-identity
Fails on origin/main, passes on this branch.
Test: sidebar keeps a Cursor pane visible and an OpenCode pane out of Claude Code hands
Co-authored-by: Orca <help@stably.ai>
* fix(terminal): preserve restored Cursor identity
* test(terminal): cover restored Cursor redraw suppression
* refactor(terminal): tighten Cursor identity handling and Claude frame matching
Review follow-ups on the title-resolution path:
- pty-transport dropped a native Cursor literal that main emits whenever a
non-Cursor title preceded it, re-introducing the #10258 blank row in the
renderer path. The pre-filter now projects the predecessor the drain will
actually see, and defers to the drain gate while facts are still queued.
- applyTrackedPtyTitle threaded the cursor flag through 12 sites, including
ptyRecordChanged bookkeeping the sole caller ignores. Force the status null
once, and the activity-gated effects fall out unchanged.
- isClaudeIdentityFrameTitle missed a multiplexer-wrapped Claude title
("zsh | Claude Code"), costing a genuine Claude pane its identity. Reuse
the ' | ' segment split that agent-title-owner already had inline.
- Keep title normalization on launchAgent: it only rewrites within an
identity group (OMP wraps Pi), so a split does not make it wrong, and
the hook-row path normalizes the same way.
- Drop the tab.ptyId tracker fallback, which read a pty that the pane
identity check had just rejected.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>