Repository navigation
feat(tabs): rename the current tab from a shortcut and the palette - #1981
Conversation
… text on a second press
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 34 minutes. View limit details
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. Comment |
|
Merge pass review report. Overall: PASSED. This change is client only. The Astra gate (omo-native-gate-reviewer, gpt-6-astra) approved be1f8c8. What the gate checked:
Not exercised: scrolled-out tabs, a cramped lone tab, and duplicate ids across remote machines were checked by reading the code. CodeRabbit was rate-limited.
|
Closes #2019. ## Change A tab herdr still names by its number ("Tab 2") shows a few words of the first message its agent was given: about 24 columns, where a wide character counts as two, cut at a word's end with `…`. The tab's hover stays the pane's title. Tabs of the same agent can be told apart without opening each one. - **An Ovis display label, never written to herdr.** Labels are kept in the shared preferences as `tab_labels`, keyed `<paneStorageId>|<terminal_id>`. herdr reuses pane ids after a restart but never a terminal id, so a new pane never shows an old pane's words. On the server they live in their own `tab-labels.json`, like `muted-panes.json`, so an older release that rewrites `preferences.json` erases nothing. herdr's tab label, its TUI and the workspace name are untouched. - **Reading never writes.** A label read from a transcript shows on that page only. A user's action shares it with every browser: the New tab dialog's Start, or a message delivered from Chat to an agent's pane. Opening, reading or watching a page never sends `PUT /api/preferences`. A watching device shows the labels and learns none. - **Privacy.** Only the short label is stored (at most 64 UTF-16 units), never the message. A label leaves once a browser saw its pane and then saw it gone; that drop goes out with the next change someone makes. Turning the shared setting off deletes every stored label, and none is loaded or kept while it stays off. The setting's description says what is kept. - **The labels file never blocks other preferences.** A `tab-labels.json` that can't be read or written is logged, and the labels are left out of that save. Labels never count against the 64 KB size of a settings, pins or mutes save. - **Never covers a given name.** Only herdr's own numbered name counts as the default. A name from Rename tab (#1981), the New tab dialog's Name or a script is kept, even one that is just an agent's name. - **Where the words come from.** The first line that names something is used: a slash command, a path or a code fence is skipped. Sources, for every agent whose first prompt Ovis knows: - the New tab dialog's first message; - a conversation page read from its beginning (`cursor === null`), for every transcript-backed agent; - a Chat send to a pane with no transcript, once it is delivered (not one held, queued or answering a question; never a shell pane). - **Settings → Appearance → Name tabs from the first message**: shared, on by default. - The palette footer names a tab the way the strip does. Design follows the Codex app, which titles a thread from its first prompt, rather than asking the model for a title (a model call and a wait). DESIGN.md has the entry. ### Contract `GET/PUT /api/preferences`: - The document gains `tab_labels: { "<paneStorageId>|<terminal_id>": label }`. It is absent while none is kept, so an old document reads exactly as before. There are at most 64 labels (the oldest leave first), and each is one line of at most 64 units. - A PUT adds labels with `tab_labels` (a key already held keeps its label) and drops keys with `tab_labels_removed`. The server merges both per key, so two browsers saving at once lose neither's labels. - While `autoTabNames` is false the server keeps none. - A browser that gets an answer without the labels it sent treats the server as one that keeps none and sends no more, until its event stream reopens. Old clients ignore the fields. ## Validation - `bun run check fast`: ok at 2c5e318 (unit tests 10055 pass, 0 fail). - CI's `pane-mute-demo-regression` and `background-agent-detail-demo-regression` were reproduced locally and pass now (exit 0). - Failing-first: each new test fails without its change, either on the earlier commit or under a mutation. They cover: - a pane id reused after a restart; - the purge when the setting is turned off; - concurrent saves; - a stale roster; - an answer landing after the pane closed; - reading never writing; - a removal alone sending nothing; - only agent panes learning from a send; - an unreadable or unwritable labels file, and the setting turned off over one; - labels left out for size; - a failed delete while the setting is off. - Browser QA on an isolated herdr test session (`ovis-test-feat2019`, fresh state dir, port 0, built `dist/`), with two browser contexts, all PASS with no page errors: - A (Chat) showed "Fix the login redirect…"; the hover stayed the pane title. - Reading the transcript shared nothing: B still showed "Tab 1", and no `tab-labels.json` existed. - After a Chat send in A, B showed the label without a reload. - The file held only the short label under `<pane>|<terminal>`; herdr's tab label stayed "1" and the workspace name was unchanged. - A rename to "auth work" and to "codex" was kept; a rename back to "1" brought the label back. - Turning the setting off showed "Tab 1" in both browsers and emptied the file. - Screenshots at desktop 1280 and phone 390, Codex dark and light. - Codex Terra reviews (gpt-6.1-terra, xhigh; never Astra) over every round. Each finding was fixed, except one accepted edge, explained in the PR comments: old labels can return after a restart only if every delete of the file fails while the setting is off, through the save that turns it back on. - Skipped: `check full` (CI runs Integration and browser). This changes the `/api/preferences` HTTP contract, so it waits for a real review.
Change
Fixes #1141.
Rename tab is now a command palette action and a rebindable shortcut, so a tab can be renamed without the mouse. Both open the same inline name field as the tab menu's Rename, on the selected pane's tab: Enter saves and Escape cancels, as before.
rename-tabjoinsSHORTCUTSandCUSTOM_SHORTCUT_IDSwith no default key, like New tab and the splits. The free Mod+Shift letters are few, and the issue's suggestions are taken (Mod+Shift+E focuses the input, Mod+Shift+R is Chrome's hard reload). Bind it in Settings → Shortcuts and the palette shows the chord. A held chord does not repeat.Pencil), found by "edit tab name title" too. It is left out where the strip is not drawn (a lone tab on a cramped phone screen,loneTabHiddeninlib/paneCanvas.ts, now shared withTabStrip) or while the selected pane is not in the roster yet.{ machineId, paneId }request (lib/useRenameRequest.ts) that only the active half's strip for that pane receives. The strip opens the field and clears the request at once. The request is also dropped when the selection changes, so a request no strip took up (a crashed half) never fires later, and returning to the pane never reopens the field. A second press while the field is open keeps what was typed.Design reference: herdr's own TUI has
rename_tab(defaultprefix+shift+t), and VS Code and Zed offer Rename tab as palette commands. This follows herdr's action, bound to a web chord the browser leaves alone.Validation
bun scripts/shortcut-exact-modifiers-demo-regression.ts: PASS. On the demo build it records Mod+Shift+Y for Rename tab, which opens and focuses the name field; Escape keeps the name; leaving the pane and coming back does not reopen the field; a second press keeps typed text; Enter renames, and the demo's/api/sessionsnapshot carries the new name; the palette action opens and focuses the field. Negative check: without the "keep typed text" guard inTabStrip, the case fails (the field is reset and never closes).bun test src/lib/shortcuts.test.ts src/conventions.test.ts: 39 pass.tsc --noEmit: clean.bun run check faston be1f8c8: workflow syntax, generated types and themes, typecheck, build, and unit tests (7188 pass, 0 fail) all pass.