mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-04 14:39:42 +02:00
* fix(sessions): stop pinning the w1-myapp placeholder as Claude's /resume title Local claude spawns passed the tab name as `--name`. That flag is not only the cross-session peer name: it is also the prompt-box label, the `/resume` picker entry and the terminal title, and a pinned title stops Claude generating its own (`customTitle ?? aiTitle`). So every conversation of a case was listed in `/resume` as the same `w1-myapp`, and none of them got a generated title. On one workspace, 34 of 34 conversations spawned with `--name` had no ai-title, while every conversation spawned without it had one. Only a name the user chose is pinned now: `Session.cliPinnedName` is the name when `nameSource === 'manual'`, carried to the builders as a separate `cliName` so the tab/mux name is untouched. Placeholder and auto names let Claude title the conversation again. A rename in Codeman also reaches `/resume`: the new name is appended to the conversation's transcript as the `custom-title` row `/rename` writes (never creating the file, never writing an empty title). For a pane spawned without `--name` this holds immediately; a pane spawned with one re-appends its own title each turn, so there the new name holds from the next spawn. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(sessions): skip no-op renames and docker sessions when syncing the /resume title A same-name PUT (the Session Options field saves on blur and recomposes the unchanged placeholder) no longer flips nameSource to manual or appends a custom-title row, and docker sessions skip the host transcript scan since their transcript lives in the container. The skill pages no longer use a w<N>- name as the peer-name example, and the changeset notes the re-append caveat. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: record that nameSource decides --name and renames reach /resume Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: codeman-local <codeman@local> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
46 lines
1.9 KiB
TypeScript
46 lines
1.9 KiB
TypeScript
/**
|
|
* @fileoverview Carry a Codeman rename into Claude Code's own session title.
|
|
*
|
|
* Claude Code keeps a conversation's title in its transcript as a
|
|
* `{"type":"custom-title"}` row (what `/rename` writes), last row wins, and the
|
|
* `/resume` picker shows `customTitle ?? aiTitle`. Renaming a tab in Codeman
|
|
* used to change only the tab, so `/resume` kept listing the old name.
|
|
*
|
|
* Appending the row is enough for a pane that was spawned WITHOUT `--name`
|
|
* (every placeholder- or auto-named tab, see `Session.cliPinnedName`): that
|
|
* process holds no title of its own and never writes one back. A process that
|
|
* WAS spawned with `--name` re-appends its in-memory title after each turn, so
|
|
* there the new title holds from the next spawn, which pins the new name.
|
|
*
|
|
* @module claude-session-title
|
|
*/
|
|
|
|
import fs from 'node:fs/promises';
|
|
|
|
/**
|
|
* Append a `custom-title` row for `conversationId` to an existing transcript.
|
|
* Never creates the file: a missing transcript means the conversation has not
|
|
* been written yet, and a file of only a title row would show up in `/resume`
|
|
* as an empty conversation. Returns whether a row was written.
|
|
*/
|
|
export async function appendClaudeCustomTitle(
|
|
transcriptPath: string,
|
|
conversationId: string,
|
|
title: string
|
|
): Promise<boolean> {
|
|
const customTitle = title.trim();
|
|
// Claude reads the row through `customTitle ?? aiTitle`, so an empty string
|
|
// would blank the picker entry rather than fall back to the generated title.
|
|
if (!customTitle) return false;
|
|
try {
|
|
if (!(await fs.stat(transcriptPath)).isFile()) return false;
|
|
} catch {
|
|
return false;
|
|
}
|
|
// One O_APPEND write of one line, the same way Claude appends its own rows,
|
|
// so it cannot interleave with a row the live process is writing.
|
|
const row = JSON.stringify({ type: 'custom-title', customTitle, sessionId: conversationId });
|
|
await fs.appendFile(transcriptPath, `${row}\n`);
|
|
return true;
|
|
}
|