fix: eye icon follows /clear to the new Claude conversation (#76)

Interactive Claude CLI never emits session_id on stdout, so the
Session's _claudeSessionId stayed pinned to the pre-/clear jsonl and
the last-response viewer kept showing the old conversation.

Two complementary update paths:

- Session.adoptClaudeSessionId() — public setter mirroring the existing
  no-op-if-same guard. Called from POST /api/hook-event when Claude Code
  hooks carry data.session_id (works once hooks are configured).

- /api/sessions/:id/last-response now resolves the active id from
  ~/.claude/history.jsonl before reading the transcript. This is the
  only source-of-truth that does not require hooks, and we intentionally
  don't write hooks into arbitrary user repos.

History scan filters out sessionIds held by other Codeman sessions in
the same cwd, and validates via jsonl mtime to avoid inheriting a dead
prior session's id.

Co-authored-by: Teigen <teigen@TeigendeMac-mini.local>
This commit is contained in:
Tenggan Zhang
2026-04-28 03:03:11 +02:00
committed by GitHub
co-authored by Teigen
parent e549e15cb8
commit f21df2a9fb
3 changed files with 104 additions and 3 deletions
+8
View File
@@ -43,6 +43,14 @@ export function registerHookEventRoutes(
}
}
// Sync Claude's current conversation id. Interactive PTY mode never emits
// `session_id` on stdout, so hooks are the only reliable way to learn that
// the user ran `/clear` (which spins up a new conversation jsonl).
if (data && typeof data.session_id === 'string' && data.session_id) {
const session = ctx.sessions.get(sessionId);
session?.adoptClaudeSessionId(data.session_id);
}
// Sanitize forwarded data: only include known safe fields, limit size
const safeData = sanitizeHookData(data);
ctx.broadcast(`hook:${event}`, { sessionId, timestamp: Date.now(), ...safeData });