fix(edit-history): review round 1 — record-bound deletion, load-time bounds, older reads per source

- The history is deleted when the session's persisted record goes (forgetEditHistory):
  kill via cleanupSession (a pinned record is only demoted and keeps it), the
  persisted-only DELETE, and stale cleanup at startup. After remove() neither a sync in
  flight nor a later request writes the file again; writes are serialized.
- load() re-bounds a damaged file: cursors, pending Bash calls (MAX_PENDING_BASH) and
  subagent labels (MAX_AGENTS, oldest unused dropped first).
- Load older reads one block of every transcript, budget split between them, and only
  the files it asked for; a block short of budget reads its end. A line longer than the
  budget is skipped going back as well (floorMidLine).
- Concurrent first callers share one store; a forward request folded with an older one
  still reads forward.
- Images outside the workspace get no thumbnail (one attachment id per render); a click
  opens the shared preview, which registers once with notify: false.
- Docs: per-edit diff cap, deletion rule, load-time bounds, thumbnails, follow triggers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
RandalixandClaude Opus 5.5 committed 2026-10-23 14:30:05 +02:00
1 parent 95e2272f89
commit dcdeaab98d
17 files changed
+508 -158

No files matched your search

+13 -8
View File
@@ -262,7 +262,7 @@ header next to Attachments. It is not shown on phones.
Click it for a draggable window listing the active session's edits, newest first:
- One row per Edit, Write or MultiEdit, with `new` for a file the agent created, `edit` otherwise,
- One row per Edit or Write, with `new` for a file the agent created, `edit` otherwise,
and the lines added and removed. **Click a row** to see that edit's diff inline, coloured like the
Git panel; a diff over 64 KB is cut short. **Click the path** to open the file in the preview.
- Edits made by subagents carry a chip with the subagent's task; hover it for the agent type and
@@ -271,16 +271,19 @@ Click it for a draggable window listing the active session's edits, newest first
- Images an agent produced with a shell command (a render, a plot, a screenshot) appear as rows with
a thumbnail: a `.png`, `.jpg`, `.gif`, `.webp` or `.avif` path named in the command or its output
counts when the file's modification time falls within that command's run. Images the agent sent
you count as well. Click one to open it in the preview.
- **Load older** reads further back in the conversation.
you count as well. Images outside the workspace show no thumbnail. Click one to open it in the
preview.
- **Load older** reads further back in the conversation, in the main agent's transcript and the
subagents' alike.
It works for local Claude sessions only. Remote (SSH), Docker and other CLIs' sessions say so instead.
How it reads:
- **Only while you look.** The history is read from the session's Claude transcript when you open
the window, and again after each edit while it stays open on that session. A closed window reads
nothing, and Codeman does no work in the background for sessions nobody looks at.
the window, and again after each tool call that can change files and at the end of each turn,
while it stays open on that session. A closed window reads nothing, and Codeman does no work in
the background for sessions nobody looks at.
- **The transcript is found through the session's hooks.** Each prompt tells Codeman where the
session's transcript is. Right after a server restart, before the next prompt, Codeman looks in
the session's `CLAUDE_CONFIG_DIR` if you set one for it in Codeman, else in the default config
@@ -290,10 +293,12 @@ How it reads:
- **The history is stored, and it holds secrets.** Every diff an agent wrote is copied to
`~/.codeman/edit-history/<session-id>.json`, including API keys or `.env` contents it edited. The file is
readable by your user only, capped at 500 edits and 4 MiB of diff text per session (the oldest
are dropped), never part of search, blocked from every file route, and deleted with the session.
are dropped), never part of search, blocked from every file route, and deleted when you delete
the session. A pinned session you kill keeps its record and its history until you unpin and
delete it.
- **Images go through the existing file routes.** A thumbnail inside the workspace uses the File
Viewer's route; one outside it is registered like a clicked path (no notification, same
file-type allowlist and sensitive-file blocklist). No new route serves a file.
Viewer's route. An image outside it opens like any clicked path outside the workspace (no
notification, same file-type allowlist and sensitive-file blocklist). No new route serves a file.
The data comes from `GET /api/sessions/:id/edits`, `GET /api/sessions/:id/edits/:entryId` and
`POST /api/sessions/:id/edits/older` (see the