Commit Graph
8 Commits
Author SHA1 Message Date
Codeman maintainer a2db03cda5 fix(story-mode): commits in montages, lint verdicts, and a page that holds still
From review round 2 (a long turn, and a prompt added mid-turn):

- Commits fold last and a montage names them ("saves the work in 3
  commits"); a save counts its commits ("saves the work in 6 commits").
  Before, all three commits of a 16-step turn vanished into montages that
  read "runs 2 commands".
- Folding a full page starts at the oldest pair and grows a montage already
  there, and never takes the newest panel while another choice exists: a
  live page no longer reshuffles panels the reader is watching.
- A check whose output reports problems ("1 file would be reformatted",
  "Found 3 errors", "✖ 5 problems", `error TS…`) failed, though a trailing
  `; ls` hid the exit code: "The tests pass, but another check fails."
- Shell structure is not a command (`for x in`, `do`, `done`, `if`), so a
  `--version` probe in a loop reads as looking; `command -v` and
  `git config --get` too.
- The montage draws only the kinds of steps it folded, with a box for
  saves; the loop's arrow has a head and rests on a finished page; the
  "MISSION COMPLETE!" title has room for its tilt; drawer commands keep
  their line breaks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 11:10:14 +02:00
Codeman maintainer ca035dd41b fix(story-mode): files written in Bash, the advisor, and honest checks, from review round 2
- Files a Bash call writes through here-documents (`cat > f <<'EOF'`, `tee`)
  are whole-file edits on the event: in the diff drawer, on the code page,
  in "N files changed". Before, a worker that wrote seven files that way
  drew a page with zero files changed. Labels leave the bodies out (the wire
  row was a wall of file text), and a relative target resolves against the
  transcript line's cwd unless the command changed directory first.
- A caption names the part of a one-liner that decided it (`node --test`,
  the commit), not its first line.
- The advisor (a server tool, answer encrypted in the transcript) is drawn:
  "Claude asks the advisor for a second opinion." It is not counted as a
  helper. Server web search maps to the web panel.
- Checks that all pass from the start read "Build and test, N rounds. Every
  check passes.", not as fixing.
- pytest's collection errors are counted apart: "The tests don't even load."
- A result remark replaces a step announcement on its check.
- A turn still open when the next prompt starts has ended; an interrupted
  turn is timed by its span.
- The mission drawer keeps prompts up to 4000 characters.
- Drawer: diff headers, titles and commands read relative to the session
  folder (the folder itself reads "."); a bare name under an `ls dir:`
  header links into that folder; the chosen answer is marked, not struck
  through; boards count errors.
- While a question waits, the pencils say "Waiting for your answer…";
  balloons start below the LIVE tag; the loop's balloon points at its
  verdict, above the board.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 10:52:08 +02:00
Codeman maintainer d7a6644c2f fix(story-mode): one verdict per call, failed saves, and loops that end at a check
From review round 2 (a question, failing tests first, and a push):

- A run that reported failed tests is now failed on the event itself, so
  its drawer and wire tags agree with the panel (the TDD red run was a red
  panel with a green "ok" tag; `; echo "exit=$?"` had hidden the exit code).
- A save whose command failed says so ("Claude tries to send the work up,
  and the command fails."), stamps ERROR instead of SAVED, and counts the
  error in the Director's cut. A save still running stamps nothing.
- A loop ends at its last check: README, .gitignore and the like written
  after the tests passed are their own fix panel instead of disappearing
  into the loop's diff.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 10:43:04 +02:00
Codeman maintainer 848566828f fix(story-mode): read how current Claude Code builds deliver prompts and end turns
Found by replaying round-2 review transcripts while the reviews ran, then
surveyed across 150 local transcripts:

- A prompt typed while Claude works writes no user line in current builds,
  only a queued_command attachment where Claude took it in (602 of them
  locally, 485 of those background-task reports). It now joins the running
  turn; a report that lands mid-turn is a notice on the wire, not a new
  mission panel, and a background helper's answer joins back from it.
- Some sessions never write turn_duration (13 of 135 locally): the Stop
  hook's stop_hook_summary (never preventedContinuation in 815 seen) now
  ends the turn, timed by its own span. Before, such a session's turns
  never ended.
- A helper started as a teammate (teammate_spawned) is a background helper;
  its <teammate-message> reports (text or a JSON idle notification) join it
  by name, and the turn they start reads "readme-writer: README done".
- A <cross-session-message> names its sender; pasted text loses Claude
  Code's <pasted_content> wrapper (it showed in balloons and the picker).
- The mission panel, its balloon and its drawer follow who sent each
  prompt (you, a background job, another session), not who started the turn.
- A caption names a script by its first line that says something, not
  `set -e`, a bare `cd` or `S=/tmp/...`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 10:41:14 +02:00
Codeman maintainer 38585a806b fix(story-mode): draw what real sessions did, from review round 1
Three review agents watched real Claude Code workers build small programs
and compared every panel with the transcript. Replaying their transcripts
through the core found, and now fixes:

- A Bash call was classified from its 400-character display clip, so a
  commit or a test run late in a long one-liner vanished (a failing pytest
  run drew as "saves the work"). The intent, the printed files and whether
  a save ships are now read from the whole command.
- A test run that reports failures failed, even when `| tail` hid the exit
  code. With that, the real fix-test-fix-test sequence folds into one loop:
  "Fix and test, 2 rounds. It passes in the end."
- node:test (`# pass 7`), all-failing pytest (`3 failed in 0.1s`) and
  pytest errors are counted.
- A helper started in the background was drawn as finished, with Claude
  Code's internal launch notes as its answer. It now stays running until its
  task notification arrives; the answer, tool count and duration are joined
  back onto it, and the final panel says when helpers are still out.
- The notification turn reported Claude Code's own duration, counted from
  the first prompt (2 min 38 s for a 21 s turn); a turn is capped at its span.
- Logging into scratch (`| tee "$S/dry.txt"`, `> /tmp/x`) counted as an edit;
  redirect targets are read quote-aware, and a here-document's body is data.
- A probe (`pytest --version`) reads as looking around, not running a tool.
- A plan Claude writes as a numbered list (no plan tool, as in current
  Claude Code builds) is drawn as a plan panel; files it cats are file cards.
- A balloon: code spans stay whole, an ellipsis or e.g. does not end the
  sentence, a remark about the check that just ran stays on that check, and
  a loop shows the last word of its rounds.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 10:11:47 +02:00
Codeman maintainer fb71180632 feat(story-mode): a helper's own steps, from its transcript
GET /api/sessions/:id/story/helpers/:agentId draws one helper (an Agent call)
as a page from its own transcript, <conversation>/subagents/agent-<id>.jsonl
beside the session's, with the type, description and finished flag from its
.meta.json. The file is derived from the session's own transcript path and an
id checked against [A-Za-z0-9_-]{1,64}; a helper with no file yet is page
null, not an error. The reducer gains a sidechain mode (every helper line is a
sidechain line) and keeps the agentId of Agent results, so the main page links
each helper to its steps. Same gates and ETag/304 as /story, now shared.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 09:41:39 +02:00
Codeman maintainer fc279f998c fix(story-mode): judge each part of a Bash one-liner, and keep underscores in balloons
Found by watching real workers: `node --test` was drawn as plain terminal work,
`git -c user.name=x commit` was not seen as saving, and a probe such as
`pytest --version` became a failing test. Commands are now split into their
simple commands (quote-aware, at && || ; | and newlines); each part is judged by
what it starts with after env assignments and wrappers like timeout and sudo,
git's own -c/-C options are skipped, a --version/--help probe is not a run, and
the strongest intent wins (test, save, build, edit, run, look). File
housekeeping (mkdir, touch, cp, mv, rm) and git init/add are plain commands.

Balloons dropped every _ and * as markdown (test_wcount.py read testwcount.py);
now only paired emphasis at word boundaries and line-start markers go.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 09:38:24 +02:00
Codeman maintainer 2653db10b5 feat(story-mode): draw a Claude session's turns as comic pages, live
Story Mode is an opt-in header button (showStoryButton, per device, default
off, kept off phones) that opens the active Claude Code session as comic pages:
one page per prompt, panels for reading code, planning, helpers, edits, tests
(POW/KRAK), questions and saving, each with a plain story caption and a
Director's cut caption naming the tools. Files open in the existing file
preview, the code page opens the exact diff, a test board opens the output,
and a running turn redraws as Claude works.

Server: GET /api/sessions/:id/story (experimental) reads a bounded tail of the
session's own transcript. A pure core (src/story-mode.ts) reduces lines,
joins tool calls with their results, splits turns at prompts and
turn_duration, and groups events into at most 12 panels; Bash calls are
sorted by what the command does. The reader (src/story-reader.ts) caches
reduced entries and reads only appended bytes while the file grows.

Frontend: story-mode.js (canvas frame engine, live refresh from transcript and
hook SSE events plus a poll while a turn runs, details drawer, the wire) and
story-mode.css, with two self-hosted OFL comic fonts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 09:22:06 +02:00