Repository navigation
fix(remote): make the host's tab name the one source for CLI and desktop renames - #30037
Conversation
…top renames A desktop connected to a remote Orca server kept its own copy of a tab's manual name, and ranked its saved-session title (a resumed Codex chat) above the live title the server publishes. So orca terminal rename on the server never showed on a resumed tab, and a desktop rename never reached the server. The server now publishes the tab's manual name as an optional customTitle on each terminal surface, and the desktop mirror adopts it. Desktop renames go to the server: terminal.rename by handle, plus session.tabs.setTabProps customTitle by tab id for panes that are asleep or starting. Older servers omit customTitle and strip the new param, so the desktop keeps its own name with them, as before. Fixes #29975
📝 Walkthrough
Priority: ⬇️ Low Merge Risk: 🔵 Low · up to
|
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
8d304aca-84e7-4016-859d-aac11945cfeb
📒 Files selected for processing: 19
src/main/runtime/mobile-session-terminal-projection.tssrc/main/runtime/orca-runtime-tests/headless-terminal-rename-publication.spec.tssrc/main/runtime/orca-runtime.test.tssrc/main/runtime/rpc/methods/session-tab-mutation-methods.tssrc/main/runtime/runtime-mobile-session-projection.tssrc/main/runtime/session-tabs/headless-tab-properties.tssrc/main/runtime/session-tabs/headless-terminal-tab-close.tssrc/main/runtime/session-tabs/pty-backed-session-publication.tssrc/main/runtime/workspaces/startup/workspace-terminal-provisioning.tssrc/main/runtime/workspaces/workspace-removal-target.tssrc/renderer/src/runtime/sync-runtime-graph/mobile-session-terminal-tabs.tssrc/renderer/src/runtime/web-runtime-terminal-actions.tssrc/renderer/src/runtime/web-runtime-terminal-rename.test.tssrc/renderer/src/runtime/web-runtime-terminal-rename.tssrc/renderer/src/runtime/web-session-tabs-sync/mirrored-terminal-custom-title.test.tssrc/renderer/src/runtime/web-session-tabs-sync/terminal-build.tssrc/renderer/src/store/terminals/terminal-tab-appearance.tssrc/shared/rpc-contract/session-tabs-schemas-params.tssrc/shared/runtime-mobile-session-tab-contracts.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.
| this.applyHeadlessSessionTabPropsToSnapshot(worktreeId, hostTabId, { | ||
| ...args, | ||
| ...(customTitle !== undefined && liveHandles.length === 0 | ||
| ? { | ||
| customTitle, | ||
| title: customTitle ?? this.headlessTerminalFallbackTitle(worktreeId, hostTabId) | ||
| } | ||
| : {}) | ||
| }) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Publish the normalized customTitle on the live-pane path, not the raw args.customTitle.
Line 293 normalizes the value: it trims it, and a blank value becomes null. The live-pane path does not use the normalized value.
- When
liveHandles.length > 0, the conditional override on lines 318-323 does not apply. ...argsthen writes the untrimmedargs.customTitleinto the snapshot. This overwrites the trimmed value thatrenameTerminalpublished.- With input
" foo ", the host publishescustomTitle: " foo ". - With a whitespace-only clear such as
" ", the host publishes" "instead ofnull. Clients then never see the name as cleared.
When a notifier with renameTerminal exists, renameTerminal skips its own snapshot write. This spread is then the only thing that publishes customTitle, so the raw value always reaches clients.
Always spread the normalized value. Keep the title override for paneless tabs only.
🐛 Proposed fix
--- "a/src/main/runtime/session-tabs/headless-terminal-tab-close.ts"
+++ "b/src/main/runtime/session-tabs/headless-terminal-tab-close.ts"
@@ -313,15 +313,13 @@
this.persistHeadlessTerminalTitle(worktreeId, hostTabId, customTitle)
}
// A live pane's rename above already set its title; only a paneless tab needs `title` here.
this.applyHeadlessSessionTabPropsToSnapshot(worktreeId, hostTabId, {
...args,
- ...(customTitle !== undefined && liveHandles.length === 0
- ? {
- customTitle,
- title: customTitle ?? this.headlessTerminalFallbackTitle(worktreeId, hostTabId)
- }
- : {})
+ ...(customTitle !== undefined ? { customTitle } : {}),
+ ...(customTitle !== undefined && liveHandles.length === 0
+ ? { title: customTitle ?? this.headlessTerminalFallbackTitle(worktreeId, hostTabId) }
+ : {})
})
return { updated: true }
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| this.applyHeadlessSessionTabPropsToSnapshot(worktreeId, hostTabId, { | |
| ...args, | |
| ...(customTitle !== undefined && liveHandles.length === 0 | |
| ? { | |
| customTitle, | |
| title: customTitle ?? this.headlessTerminalFallbackTitle(worktreeId, hostTabId) | |
| } | |
| : {}) | |
| }) | |
| this.applyHeadlessSessionTabPropsToSnapshot(worktreeId, hostTabId, { | |
| ...args, | |
| ...(customTitle !== undefined ? { customTitle } : {}), | |
| ...(customTitle !== undefined && liveHandles.length === 0 | |
| ? { title: customTitle ?? this.headlessTerminalFallbackTitle(worktreeId, hostTabId) } | |
| : {}) | |
| }) |
…cs (#30897) The daily full E2E run on main fails these specs every time because the product moved on and PR CI only runs specs a PR touches: - editor header menu renamed to File actions (#30129) - terminal attention: an on-screen bell leaves no unread marker (#28637) - terminal file drops carry their source host (#26830) - single-choice questions auto-submit (#26288) - phone terminal rows carry customTitle (#30037) - gh/git preflight re-reads the login shell PATH (#25183) - board drag starts after the target column is in view - chat history anchor read after scroll settles
ELI5
When your desktop is connected to a remote Orca server, the tab name you see and the name
orca terminal rename/orca terminal showuse on the server could drift apart. A resumed Codex chat made it worse: the desktop showed the chat's saved name and ignored the server's rename. Now the server holds the tab's name, and both sides read and write that one name.What Changed
orca terminal renameon the server returnedok: trueandterminal showreported the new name. The desktop tab kept showing the resumed Codex session's saved name.terminal showon the server kept the old name.resume.orca terminal show, and on phones. Clearing a name works in both directions too.customTitle> … > saved-session title (aiVaultTitle) > generated > live title (src/shared/tab-title-resolution.ts). For a remote tab,customTitlewas only ever this desktop's own copy (buildMirroredTerminalTabskeptexisting?.customTitle). The server's rename arrived only as the livetitle, which sits below the saved-session title. AndsetTabCustomTitlenever told the server anything.session.tabs.listget an optionalcustomTitle: string | nullfield: the host's manual name,nullwhen there is none. It is published by headless hosts (mobile-session-terminal-projection.ts,pty-backed-session-publication.ts, and on rename viaapplyHeadlessSessionTabPropsToSnapshot) and by desktop hosts (mobile-session-terminal-tabs.ts). The live projection passes it through.customTitlewhen the field is present. When it's absent (an older host), the mirror keeps its own name as before.terminal.renameby handle when a pane is bound, plus the new optionalsession.tabs.setTabProps { customTitle }by tab id. The tab-id path reaches panes that are asleep, still starting, or bound to a handle the host has forgotten. On a headless host it renames live panes the same wayterminal.renamedoes. For a paneless tab it persists the name and updatestitleas well, so phones and older desktops, which read onlytitle, see it too.Why
There are two possible sources of truth: the desktop or the host. The host is the only one every reader shares (CLI, phones, other desktops), and the execution host owns execution state. Making the desktop authoritative would need a new path to push names to the CLI and phones. Ranking the host's live title above the saved-session title would let any agent OSC title override a resumed chat's name. A separate "manual" field keeps that ranking intact and only promotes names a person actually chose.
Mixed versions: both wire additions are optional. An old host omits
customTitle, and the new desktop keeps its own name, as today. An old host'ssetTabPropsschema is non-strict, so it strips the new param and answersupdated: true. Theterminal.renamethe desktop also sends still works against old hosts. Old desktops ignore the new field. One deliberate behavior change: against a new host, a name a desktop only ever kept locally is replaced by the host's (usually none) on the first snapshot after upgrade.Overlap: #28713 (fork PR, mobile rename, #28665) also adds
customTitleto the terminal surface contract, along with much else. This PR uses the same field name and type, so the two can be reconciled, and this PR keeps to the desktop/remote path. Codex review (high) went five rounds. It found three real issues, all fixed with tests: paneless tabs reverting, stale retained handles, and the publishedtitlenot updating for tab-id renames and resets.Linked Issue
Fixes #29975
Visual Proof
N/A: no layout change. The tab shows the server's name, and the before/after above is verified as described under Testing. I didn't drive a desktop window against the remote server here.
Testing
New
orca-runtime-tests/headless-terminal-rename-publication.spec.ts(six cases):customTitleon a live headless surface, and clearing it publishesnull.title, and clearing restores the saved title.terminal.rename.New
mirrored-terminal-custom-title.test.ts: the host name outranks the saved-session title, the host'snullclears the desktop's name, and an older host keeps the desktop's name.New
web-runtime-terminal-rename.test.ts: by handle, through a split pane's handle, by tab id, local tabs untouched, disconnected server untouched.The host and mirror tests failed on main. Locally I ran
src/renderer/src/runtime,src/renderer/src/store/terminals,src/main/runtime/{session-tabs,workspaces,rpc},src/shared/rpc-contractandorca-runtime.test.ts, single worker: 7,638 passed. The one failure ispreserves existing badgeColor on runtime cloneRepo…, a macOS/private/vartmpdir path mismatch that also fails on main and is unrelated. I also ranpnpm tc, the changed-code quality gate, and the rest of the static-analysis job steps.Live (macOS, isolated orcad built from this branch under /tmp with its own HOME/user-data/XDG, port 6871, no window):
orca terminal rename --title 'Codex · 绑定实现'madesession.tabs.listpublishtitleandcustomTitle: "Codex · 绑定实现".--title ''publishedcustomTitle: null.session.tabs.setTabProps { tabId, customTitle: "绑定" }, which is what the desktop now sends, madeorca terminal showreturntitle: "绑定". That covers the issue's reverse direction.I manually tested these changes locally
Automated tests added/updated, or explained why not below
Agent skill upstream boundary
Notes
SSH and folder workspaces: the change is per tab on whichever host runs the terminal, with no worktree assumptions. Mobile: phones read
title, which tab-id renames now update. A newer phone could adoptcustomTitlelater.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)