diff --git a/.changeset/cli-session-name-matches-tab.md b/.changeset/cli-session-name-matches-tab.md new file mode 100644 index 00000000..26b0e08b --- /dev/null +++ b/.changeset/cli-session-name-matches-tab.md @@ -0,0 +1,5 @@ +--- +'aicodeman': minor +--- + +A Claude session is now launched with `--name ` for every tab, not only for ones you renamed. Claude Code's prompt-box label, `/resume` entry and its remote session list used to show Claude's own generated title (for example "Git indicator guard test and teardown flake") for a tab that Codeman called `w4-Codeman`; they now read the same as the tab. A rename or an auto-name reaches the CLI at its next spawn. diff --git a/src/session.ts b/src/session.ts index c9d494cb..92809e49 100644 --- a/src/session.ts +++ b/src/session.ts @@ -1806,16 +1806,19 @@ export class Session extends EventEmitter { } /** - * The name to pin on the Claude CLI as `--name`, or undefined to let Claude - * title the conversation itself. `--name` is the prompt-box label, the - * `/resume` picker entry and the terminal title all at once, and a pinned - * title stops Claude generating its own, so only a name the user chose is - * worth pinning. Pinning the `w1-myapp` placeholder gave every conversation - * in a case the same `/resume` entry; an auto name is a cut of the first - * prompt, which Claude's own generated title already beats. + * The name to pin on the Claude CLI as `--name`: the tab's own name, whatever its source, + * so the CLI's prompt-box label, `/resume` entry and terminal title (and Claude Code's + * remote session list) read the same as the tab. Leaving a placeholder or auto-named tab + * unpinned let Claude generate its own title, which then differed from the tab it was + * running in (`w4-myapp` in Codeman, "Fix the flaky teardown" in Claude). + * + * The cost is that every conversation of a case starts with the same `/resume` entry shape + * (`w1-myapp`, `w2-myapp`); the tab number keeps those distinct per tab. A rename or an + * auto-name reaches the CLI at the next spawn: a process started with `--name` re-appends its + * in-memory title after each turn (see claude-session-title.ts). */ get cliPinnedName(): string | undefined { - return this._nameSource === 'manual' ? this._name : undefined; + return this._name.trim() ? this._name : undefined; } setAutoClear(enabled: boolean, threshold?: number): void { diff --git a/test/claude-resume-title.test.ts b/test/claude-resume-title.test.ts index 6f477e6a..3321db0a 100644 --- a/test/claude-resume-title.test.ts +++ b/test/claude-resume-title.test.ts @@ -1,11 +1,10 @@ /** - * @fileoverview Claude's `/resume` title belongs to Claude unless the user chose one. + * @fileoverview The CLI's session name is the tab's name. * * `--name` sets the prompt-box label, the `/resume` picker entry and the terminal - * title, and a pinned title stops Claude generating its own. Pinning the - * `w1-myapp` placeholder therefore listed every conversation of a case under the - * same name in `/resume`. Only a manual name is pinned now (`cliPinnedName`), and - * a rename reaches the transcript as a `custom-title` row. + * title, and a pinned title stops Claude generating its own. Every tab's name is pinned + * (`cliPinnedName`), placeholder and auto names included, so Claude's own session list + * matches the tab. A rename reaches the transcript as a `custom-title` row. */ import { mkdtempSync, readFileSync, rmSync, writeFileSync, existsSync } from 'node:fs'; @@ -18,19 +17,18 @@ import { appendClaudeCustomTitle } from '../src/claude-session-title.js'; type RespawnOptionsProbe = { _buildRespawnPaneOptions(): { name?: string; cliName?: string } }; describe('Session.cliPinnedName', () => { - it('pins nothing for a placeholder, so Claude titles the conversation itself', () => { + it('pins the placeholder name, so the CLI session matches the tab', () => { const session = new Session({ workingDir: '/tmp', name: 'w1-demo' }); - expect(session.cliPinnedName).toBeUndefined(); + expect(session.cliPinnedName).toBe('w1-demo'); const options = (session as unknown as RespawnOptionsProbe)._buildRespawnPaneOptions(); - // The tab keeps its name; only the CLI flag is withheld. expect(options.name).toBe('w1-demo'); - expect(options.cliName).toBeUndefined(); + expect(options.cliName).toBe('w1-demo'); }); - it('pins nothing for an auto name, whose cut of the prompt Claude beats', () => { + it('pins an auto name too, from the next spawn', () => { const session = new Session({ workingDir: '/tmp', name: 'w1-demo' }); expect(session.applyAutoName('w1-demo: fix the login redirect')).toBe(true); - expect(session.cliPinnedName).toBeUndefined(); + expect(session.cliPinnedName).toBe('w1-demo: fix the login redirect'); }); it('pins a name the user chose, at creation or by a rename', () => {