chat: rename sessions in Claude's store + delete confirm

Rename appends a {"type":"summary",...} entry to the session's JSONL transcript
(Claude's own format, so the title lives in .claude); the reader takes the last
summary as the title, without a timestamp so it doesn't reorder the list.
PATCH /chat/sessions/:id/title backs it. The list gets inline rename (pencil ->
edit in place) and a two-step delete confirm so a stray click can't nuke a
transcript. Rename verified against a synthetic store.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 12:01:16 +00:00
co-authored by Claude Opus 4.8
parent 4215c8df0a
commit b3b8a59863
4 changed files with 161 additions and 49 deletions
+11 -1
View File
@@ -1,5 +1,5 @@
import { createRouter } from '../../create-router';
import { getClaudeSessionsCwd, listClaudeSessions, loadClaudeSession, deleteClaudeSession } from './claude-sessions';
import { getClaudeSessionsCwd, listClaudeSessions, loadClaudeSession, deleteClaudeSession, renameClaudeSession } from './claude-sessions';
export const chatRouter = createRouter();
@@ -26,3 +26,13 @@ chatRouter.delete('/sessions/:id', (ctx) => {
if (!ok) return ctx.text('Not found', 404);
return ctx.json({ ok: true });
});
// PATCH /chat/sessions/:id/title — rename by writing a summary entry into Claude's transcript.
chatRouter.patch('/sessions/:id/title', async (ctx) => {
const email = ctx.get('user').email;
const { title } = await ctx.req.json<{ title?: string }>();
if (!title?.trim()) return ctx.text('title is required', 400);
const ok = renameClaudeSession(email, getClaudeSessionsCwd(email), ctx.req.param('id'), title.trim());
if (!ok) return ctx.text('Not found', 404);
return ctx.json({ ok: true });
});