feat(cockpit): worker inspector drawer — timeline, worktree forensics, breadcrumbs (closes #70) - #74
Merged
Merged
Conversation
Adds GET /api/worker/<role>/<task> to cockpit-serve.sh: an event timeline (newest first) from events.jsonl, the latest --detail breadcrumbs surfaced separately, and live worktree forensics (branch, status --short, last 5 commits, diffstat vs main's merge-base) computed by shelling out to git — zero agent tokens. The worker's worktree is located by conventional directory name (.claude/worktrees/issue-<task>) or, failing that, by scanning `git worktree list` for a branch matching feat/issue-<task>-*; no match degrades to a clear found:false marker rather than erroring. Wires a click-to-open inspector drawer into the served dashboard's live- progress table (static one-shot cockpit.sh output is unchanged), rendering the three sections above with every dynamic value via textContent only. Also lands the two PR #73-flagged 3a followups: - cockpit-serve.sh's bash EXIT trap for its mktemp'd HTML file never fired (exec node replaces the shell), leaking one temp file per invocation; cleanup now happens in node's own 'exit' handler instead. - /events' SSE tailer went stale forever once log-event.sh's rotation shrank events.jsonl below the subscriber's read offset; pump() now resets the offset to 0 whenever the file has shrunk. Extends the log-event.sh paragraphs in orchestrator/implementer/reviewer.md so every phase-transition call also passes a terse --detail breadcrumb, and extends cockpit.test.sh with an offline worker-inspector smoke case (synthetic temp git repo/worktree under $TMPDIR, mirroring .claude/self/smoke-fanout.sh's own git-init/worktree-add pattern) plus regression checks for both fixes. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NTZEsfFT4mrZpv8CY67Frd
…in role/task
Correctness review (BLOCKING): a malformed percent-escape in
/api/worker/<role>/<task> reached decodeURIComponent() outside
handleWorkerInspector's try/catch, throwing an uncaught URIError that
killed the whole node process for every client (no
process.on("uncaughtException") handler exists). The route now passes
the raw matched segments through, and handleWorkerInspector decodes
them itself inside a try/catch, responding 400 JSON on failure instead
of crashing.
Hardening (both reviewers flagged): role/task are interpolated into
path.join(WORKTREES_ROOT, ...) and a RegExp branch scan. Reject any
decoded value containing a path separator, "..", or NUL up front with
400 JSON, closing the traversal note (git calls already use
execFileSync with arg arrays, so this is defense-in-depth).
Adds an offline regression test hitting the endpoint with a malformed
percent-escape and a traversal-shaped task, asserting both return 400
and that the server is still serving valid requests afterward --
proving the crash is fixed rather than just changing a status code.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NTZEsfFT4mrZpv8CY67Frd
robercano
approved these changes
Jul 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Cockpit 3b — worker inspector drawer. Clicking a worker row in the served dashboard opens an inspector drawer with three sections, backed by a new
GET /api/worker/<role>/<task>JSON endpoint incockpit-serve.sh:.claude/state/events.jsonlrecord for that role+task (phases +--detailbreadcrumbs), newest first.git: current branch,git status --short, last 5 commits, and diffstat vs merge-base withmain. Located by.claude/worktrees/issue-<task>dir orfeat/issue-<task>-*branch. Degrades gracefully to a "no worktree found" marker when absent.--detailvalues, surfaced prominently.Endpoint stays 127.0.0.1-only, node built-ins only, all dynamic content escaped (drawer renders via
textContent, notinnerHTML).Why
Part 2 of 3 of the cockpit design (tracking #68), building on 3a (serve mode + SSE, #73). Gives a zero-token forensic view of what each worker is doing.
Agent prompt nudges
Additive
--detailbreadcrumb convention added to the existinglog-event.shparagraphs inorchestrator.md,implementer.md,reviewer.md(one terse sentence per phase transition; never blocks work if log-event fails). Dogfooded during this run.3a follow-up fixes (reviewer-flagged in #73)
EXITtrap afterexec node(never fired) — cleanup now runs via node's ownprocess.on("exit")across normal, shutdown, and error paths.events.jsonlis rotated (file size < current read offset), the SSE offset resets to 0 so tailing resumes correctly.Hardening (from correctness review)
decodeURIComponentis wrapped in try/catch returning 400 JSON.role/taskcontaining path separators,.., or NUL are rejected up front with 400 (defense-in-depth; git calls already useexecFileSyncarg arrays).Testing
Extended
.claude/scripts/cockpit.test.shwith fully offline drawer coverage: a synthetic temp git repo/worktree under$TMPDIR(mirroringsmoke-fanout.sh), asserting the endpoint returns timeline + forensics fields (branch/status/commits/diffstat), newest-first ordering, breadcrumbs, thefound:falsedegrade path, both 3a fixes, and the malformed/traversal → 400 + server-stays-up regression. No network/gh in tests. Self gates green (build / lint / test).Reviewed through correctness and tests lenses (consensus all).
Closes #70.
🤖 Generated with Claude Code