feat(story-mode): save as image, a helper's own steps, a way in on phones, and polish

- Save image: the page as one PNG to share (each panel canvas, then every
  caption, balloon and chip redrawn from its computed style and box).
- The helper drawer lists what the helper did, read live from its own
  transcript (GET .../story/helpers/:agentId), led by the task Claude gave it.
- Session Options has a Story button (same setting), the way in on phones.
- A turn a background task or another session started reads as a notice,
  not as your speech balloon.
- Wide panels keep their scene in a centered stage instead of spreading the
  art to both ends; the fix panel's agent stands next to the page.
- An unchanged page (same ETag) is neither parsed nor redrawn.
- Paths inside the session's folder are shown short; clicks keep full paths.
- Tab stays inside the overlay; a missing 2D context skips the art, not the page.
- A rebindable Story Mode shortcut (no default chord).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer committed 2026-10-18 09:51:48 +02:00
1 parent d313b868d4
commit 0c45682136
10 files changed
+511 -16

No files matched your search

+4
View File
@@ -1061,6 +1061,10 @@ Read-only. The session is resolved like every session route (ownership via `find
- `{ supported: false, reason }`: the session's CLI does not write a Claude Code transcript (registry `capabilities.transcript` is not `claude-jsonl`), or the session is remote or Docker, whose transcript is not on this host.
- `{ supported: true, turns, page }`: `turns` lists up to 60 turns, oldest first (`{ id, at, prompt, origin, complete, interrupted, toolCalls }`; `origin` is `human`, `task`, `peer` or `system`). `page` is the newest turn, or the one `turn=<id>` names, or `null` when there is none (an unknown id included).
Responses carry a weak `ETag` with `Cache-Control: no-cache`; a request with a matching `If-None-Match` gets a `304` without the page being rebuilt, which is what keeps a live view's frequent refetches cheap.
`GET /api/sessions/:id/story/helpers/:agentId` draws one helper (an Agent call; its `agentId` is on the main page's event as `helper.agentId`) from the helper's own transcript, `<conversation>/subagents/agent-<agentId>.jsonl` beside the session's. `data` is `{ supported: true, helper: { agentId, type?, description?, finished? }, page }`, the same page shape as above, or `page: null` while the helper has written nothing yet. `agentId` must match `[A-Za-z0-9_-]{1,64}` (`400` otherwise).
A `page` carries the turn's summary fields plus `events` (one per prompt, sentence Claude wrote and tool call, with `intent`, `ok` when the call returned, `edit` hunks in Claude Code's own `structuredPatch` shape, the tail of `output`, `helper`, `tests` counts), `panels` (each `{ kind, events, caption: { story, director }, balloon?, files?, ... }`, at most 12 per page, indices into `events`), `filesChanged`, `added`, `removed`, `helpers`, `partial` (the turn began before the part that was read) and `truncated` (older outputs were dropped to keep the page small). A transcript that cannot be read is a `500` with `OPERATION_FAILED`.
## Git worktrees of a case