Skip to content

Releases: Samuel0101010/wisp-agentdiff

v1.4.1 — accept v2.1+ Agent tool_use name in transcript parser

19 May 22:30

Choose a tag to compare

Bugfix. Closes the label-correlation loop end-to-end on Claude Code v2.1+.

The bug

v1.3's transcript correlator parsed the session JSONL via transcript_path from the WorktreeCreate payload and filtered tool_uses with name === "Task" to find subagent dispatches. Claude Code v2.1.x renamed that tool_use to name === "Agent" in its on-disk transcript schema, so the filter rejected every entry. pending-tasks stayed empty, displayLabel was never written, and the TUI fell back to the hex worktree slug.

The v1.4 TUI render-side fix (prefer displayLabel over name) was working correctly — there was just nothing to render because of this upstream parse miss.

Evidence from a real v2.1.144 session

In the user's plugin-test session JSONL:

  • "name":"Task"
  • "name":"Agent" (e.g. {"type":"tool_use","name":"Agent","id":"toolu_...","input":{"subagent_type":"wisp-self-test",...}})

payloadKeys from the WorktreeCreate hook log confirmed transcript_path IS delivered — the data was always there, our filter was wrong.

The fix

One line in src/wrap/transcript-correlator.ts:

if (p.type !== "tool_use" || (p.name !== "Task" && p.name !== "Agent")) continue;

Accept both names so legacy and v2.1+ transcripts both work.

Tests

82 → 83 (+1). New case asserts the v2.1+ "Agent" shape with a plugin-namespaced subagent_type (matching what the user's actual session writes). Existing "ignores tool_uses for tools other than Task" test renamed to "...other than Task/Agent".

Upgrade (cache-busting required)

/plugin marketplace remove wisp-agentdiff
/plugin marketplace add Samuel0101010/wisp-agentdiff

Then Update now in /plugin (or uninstall + install with --scope if it was installed in user scope).

After that, dispatch Task(subagent_type: "wisp-agentdiff:wisp-self-test", prompt: "go") and run /review-agents — the new tab should finally show wisp-self-test (or wisp-agentdiff:wisp-self-test), not the hex slug.

v1.4.0 — outer-repo resolver + TUI displayLabel render

19 May 22:10

Choose a tag to compare

Two real-world bugs surfaced during the v1.3.0 end-to-end verification, both fixed here.

Fixed

Bug 1 — Nested wisp-agentdiff worktrees leaked state into inner repos

When Claude Code dispatched a worktree-isolated subagent while the parent's cwd was already inside an existing .claude/worktrees/wisp-agentdiff/agent-<hex>/ worktree, the WorktreeCreate hook resolved repo-root via the inner worktree's git-toplevel. The new worktree was created nested inside the old one and state landed in an inner state file invisible to the outer /review-agents invocation.

Fix: new src/wrap/resolve-repo-root.ts walks out of nested wisp-agentdiff worktree patterns (up to 10 levels) and returns the outermost non-wisp git root. All three entry points (pre-spawn-hook, post-spawn-hook, prune) now route through it. The debug log emits a [v1.4] retargeting signal on every rewrite so you can see in .claude/wisp-agentdiff/debug.log when it engages.

Bug 2 — TUI showed hex-id agent.name even when displayLabel was populated

The v1.3 transcript correlator wrote displayLabel = "wisp-self-test" into the state file, but the TUI rendered agent.name everywhere, so tab headers always showed agent-a4925f3· rather than the subagent_type.

Fix: centralized agentLabel() helper in src/tui/lib/agent-label.ts — returns displayLabel when non-empty after trim, else falls back to name. Underlying name still used for React keys, branch lookups, and merge operations.

Tests

69 → 82 (+13). New: resolve-repo-root.test.ts (6 cases incl. double-nesting and realpath round-trip), pre-spawn-hook-nested.test.ts (2 integration cases that build a real nested-repo scenario and assert state lands at outer + the retargeting debug-log signal is emitted), tui-label-preference.test.ts (5 helper cases).

All gates green on Linux / macOS / Windows × Node 20 + 22.

Upgrade

/plugin uninstall wisp-agentdiff
/plugin marketplace remove wisp-agentdiff
/plugin marketplace add Samuel0101010/wisp-agentdiff
/plugin install wisp-agentdiff@wisp-agentdiff

(The middle two steps are required — Claude Code caches the marketplace manifest and won't see the new version without a refresh.)

v1.3.0 — real subagent_type labels + worktree garbage collection

19 May 21:44

Choose a tag to compare

Two roadmap items from v1.2.1 land together — both built on real diagnostic evidence from a fresh /plugin install, not assumption.

What's new

Real displayLabel from the session transcript

The TUI now labels each agent by its actual `subagent_type` (`wisp-self-test`, `Explore`, …) instead of Claude Code's opaque hex worktree id.

The previously-shipped PreToolUse:Task path (v1.2.0) never actually fired on Claude Code v2. v1.3 sidesteps this by reading the `transcript_path` Claude Code DOES pass into the WorktreeCreate payload. New module `src/wrap/transcript-correlator.ts` streams the JSONL, finds `tool_use {name:"Task"}` blocks, and enqueues each into the existing pending-tasks store keyed by `tool_use_id`. WorktreeCreate dequeues FIFO. The PreToolUse path stays in the code as a fallback for any future Claude Code build that starts firing the hook.

`wisp-agentdiff prune`

Cleans up orphaned worktrees + `wisp-agentdiff/agent-*` branches that accumulate across sessions because Claude Code rarely fires `WorktreeRemove`.

```text
wisp-agentdiff prune --dry-run # preview the plan
wisp-agentdiff prune --older-than-hours 24 # only entries older than a day
wisp-agentdiff prune --all # ignore age cutoff
```

Handles three categories: state-orphan (state entry without worktree on disk), fs-orphan (worktree on disk without state entry), aged-out (state + worktree older than threshold). Exits 0 always; errors are per-item not fatal.

Tests

69 passing (was 53, +16 new). Lint + typecheck + build clean. CI matrix Linux / macOS / Windows × Node 20 + 22.

Known limitation carried forward to v1.4

  • Agent status still stays `running` indefinitely — Claude Code persists subagent worktrees until session-end and almost never fires `WorktreeRemove`. v1.2.1's live-diff fallback at review-time sidesteps this so it's cosmetic, not blocking.

Upgrade

```text
/plugin uninstall wisp-agentdiff
/plugin marketplace remove wisp-agentdiff
/plugin marketplace add Samuel0101010/wisp-agentdiff
/plugin install wisp-agentdiff@wisp-agentdiff
```

Then `Task(subagent_type: "wisp-agentdiff:wisp-self-test", prompt: "go")` → `/review-agents` should now show a tab labelled `wisp-self-test` with a real one-line diff. Run `wisp-agentdiff prune --dry-run` to inspect the worktree clutter accumulated across earlier sessions.

v1.2.1 — live worktree diff at review time

19 May 21:25

Choose a tag to compare

End-to-end diagnostic against Claude Code v2 surfaced two of v1.2.0's architectural assumptions as wrong. This patch sidesteps both so the captured diff actually shows up in the TUI.

Diagnostics from the user's real debug.log

  • PreToolUse: Task does not fire on Claude Code v2. Zero pre-tool-use.queued events appeared after /plugin install of v1.2.0, despite the matcher and command being valid. The pending-tasks buffer stayed empty, so the v1.2.0 `displayLabel` was never set in practice.
  • WorktreeRemove does not fire on subagent completion. Claude Code persists subagent worktrees until session-end or explicit `--remove-worktree`. All three captured agents in the user's session stayed at `status: "running"` and the cached diff JSON was never written.

Fix

`buildAgentReport` now falls back to a live `git diff ` against the agent's still-existing worktree when the cached diff is missing or empty. Read-only — no commits, no mutation. Captures committed AND uncommitted changes. A new `diffSource` field reports `"stored"` / `"live"` / `"missing"` for diagnostics.

Net effect: the canary's diff (and any real subagent's edits) now show up in the TUI regardless of whether WorktreeRemove ever fires.

Carried forward to v1.3

  • `transcript_path`-based subagent_type extraction (replaces the unfired PreToolUse:Task scaffolding, which stays in the codebase as a fallback for the day Claude Code starts firing the hook).
  • `wisp-agentdiff prune` to garbage-collect the worktrees + `wisp-agentdiff/agent-*` branches left behind by unfired WorktreeRemove.

Upgrade

```text
/plugin uninstall wisp-agentdiff
/plugin marketplace remove wisp-agentdiff
/plugin marketplace add Samuel0101010/wisp-agentdiff
/plugin install wisp-agentdiff@wisp-agentdiff
```

Then dispatch the canary; `/review-agents` should now show a real one-line diff (`+ wisp-agentdiff hook verification — `) on the new agent's tab. The tab label remains the hex worktree id until v1.3.

Tests

53 passing (+1 new for the live-diff fallback). Lint, typecheck, build all green.

v1.2.0 — subagent_type labels in the review TUI

19 May 21:12

Choose a tag to compare

The review TUI now shows real subagent_type labels (`wisp-self-test`, `Explore`, etc.) instead of Claude Code's opaque hex worktree id.

How it works

Three new hook moving parts paired with the existing WorktreeCreate handler:

  1. PreToolUse: Task fires before any subagent spawn. The hook records `{subagentType, description?, queuedAt}` into a FIFO pending-tasks buffer at `.claude/wisp-agentdiff/pending-tasks.json` (60 s TTL).
  2. WorktreeCreate dequeues the oldest non-stale pending entry and stamps the subagent_type onto the new `AgentRecord` as `displayLabel`.
  3. The TUI tab bar renders `displayLabel ?? name` — fallback to the worktree slug for direct `claude --worktree …` invocations that never go through Task.

What changed

New files

  • `src/wrap/pending-tasks.ts` — FIFO store with TTL pruning and corruption-safe load.
  • `src/wrap/pre-tool-use-hook.ts` — `handlePreToolUse`; never throws (PreToolUse must not block tool execution).

Modified

  • `src/wrap/state.ts` — optional `displayLabel` on `AgentRecord`.
  • `src/wrap/pre-spawn-hook.ts` — calls `dequeueOldestUnstale` and stamps the label; emits `worktree-create.label-correlated` in the debug log.
  • `src/index.ts` — new `hook pre-tool-use` subcommand.
  • `hooks/hooks.json` — `PreToolUse` block with `matcher: "Task"`.
  • `src/tui/tab-bar.tsx` — single-line: `displayLabel ?? name`.

Tests

  • `tests/pending-tasks.test.ts` (7), `tests/pre-tool-use.test.ts` (5), `tests/correlation.test.ts` (2), `tests/tui.test.tsx` (one new case).
  • 52 tests total (was 38), all green on Linux / macOS / Windows × Node 20 / 22.

Known limitations carrying forward

  • Subagents that don't commit inside their worktree still produce empty diffs (the bundled `wisp-self-test` canary commits itself as a belt-and-braces). v1.3 will add a working-tree snapshot fallback.

Upgrade

```text
/plugin uninstall wisp-agentdiff
/plugin marketplace remove wisp-agentdiff
/plugin marketplace add Samuel0101010/wisp-agentdiff
/plugin install wisp-agentdiff@wisp-agentdiff
```

Then `Task(subagent_type: "wisp-agentdiff:wisp-self-test", prompt: "go")` and `/review-agents` — the captured agent now appears in the tab bar as `wisp-self-test`.

v1.1.3 — canary commits its own diff + hook debug log

19 May 20:57

Choose a tag to compare

End-to-end verification in v1.1.2 confirmed the worktree-hook loop works, but surfaced two UX issues for the bundled canary path. This release fixes them.

Fixes

Canary now commits its own diff so the review TUI is non-empty

`wisp-self-test` now runs `git add wisp-self-test.txt && git commit -q -m "wisp-self-test: canary verification"` inside the worktree before reporting. The review TUI computes the diff between the worktree branch and the base ref — an uncommitted file produces a `+0 -0` diff and looks like the plugin is broken. Committing inside the worktree makes the verification path deterministic regardless of Claude Code's worktree-teardown timing.

Real subagents that mutate the working tree without committing will still produce empty diffs in v1.1.x. A working-tree snapshot fallback is planned for v1.2 (see `docs/roadmap.md`).

Always-on hook diagnostic log

`.claude/wisp-agentdiff/debug.log` now captures every `WorktreeCreate` and `WorktreeRemove` invocation with agent id, name, path existence, commit sha (if any), file count, diff bytes — so the next "empty diff" or "no subagents recorded" report can be diagnosed without re-running the failing session. Soft-rotated at 64 KiB. Logging never propagates failures up — hooks stay side-effect-free even when logging fails.

Known limitations carrying into v1.2

  • Agent label in the TUI is Claude Code's worktree id (e.g. `agent-abe343b9...`) not the subagent_type. Fixing this requires a `PreToolUse: Task` correlation layer that pairs the type with the next `WorktreeCreate`.
  • Subagents that don't commit inside their worktree produce empty diffs. v1.2 will add a working-tree snapshot fallback.

Upgrade

```text
/plugin uninstall wisp-agentdiff
/plugin marketplace remove wisp-agentdiff
/plugin marketplace add Samuel0101010/wisp-agentdiff
/plugin install wisp-agentdiff@wisp-agentdiff
```

Then `wisp-agentdiff:wisp-self-test` to verify, then `/review-agents` to see the captured diff.

v1.1.2 — self-test canary + doctor subcommand

19 May 20:42

Choose a tag to compare

Closes the verification gap. v1.1.1 made the plugin installable; v1.1.2 makes it self-verifiable without depending on the user having their own `isolation: worktree` subagent definitions.

What's new

  • Bundled canary subagent `agents/wisp-self-test.md`. Has `isolation: worktree` in its frontmatter, makes a single one-line file edit inside the worktree, then exits. Dispatch with:
    ```
    Task(subagent_type: "wisp-self-test", description: "verify wisp-agentdiff hooks fire", prompt: "go")
    ```
    After it finishes, `/review-agents` should show one agent labelled `wisp-self-test` with that single diff. If it doesn't, the WorktreeCreate hook isn't firing.

  • `wisp-agentdiff doctor` subcommand. Renders an OK / WARN / FAIL checklist for: workspace is git, binary present, plugin manifest reachable (with version), state file present (and how recently mtime'd, agent count), skill registered in `~/.claude`. Exits non-zero on FAIL, 0 with explanatory hint on WARN-only.
    ```
    node "${CLAUDE_PLUGIN_ROOT}/dist/index.js" doctor --repo .
    ```

  • README adds a Verify the install section walking from empty-state → doctor → canary dispatch → `/review-agents`.

  • SKILL description triggers on "test wisp-agentdiff", "verify wisp-agentdiff", "is wisp-agentdiff working" in addition to the original review-related phrases.

Bug-fix follow-up reminder

After upgrading bust the manifest cache: `/plugin uninstall wisp-agentdiff` → `/plugin marketplace remove wisp-agentdiff` → `/plugin marketplace add Samuel0101010/wisp-agentdiff` → `/plugin install wisp-agentdiff@wisp-agentdiff`.

CLI behaviour for the original review / install / hook / demo subcommands is unchanged.

v1.1.1 — fix: ship dist/ in the plugin clone

19 May 20:29

Choose a tag to compare

Bug fix for the v1.1.0 plugin shipment.

v1.1.0 published the plugin metadata correctly but the plugin clone arrived without a built CLI — `dist/` was gitignored. Hooks fell back to `npx -y wisp-agentdiff@latest`, which Claude Code's auto-mode classifier blocks as an external package fetch. So `/review-agents` and the worktree hooks could never run on a freshly installed plugin.

Fix

  • `dist/` is now committed to the repo. Sourcemap inside it uses only relative `../src/...` paths — no absolute paths or PII leak.
  • `hooks/hooks.json` invokes `node "${CLAUDE_PLUGIN_ROOT}/dist/index.js" hook worktree-{create,remove}` — plugin-local, network-free, classifier-clean.
  • `commands/review-agents.md` prefers `node "${CLAUDE_PLUGIN_ROOT}/dist/index.js" review --repo .` and falls back to a globally-installed `wisp-agentdiff` only for npm-path users.
  • `allowed-tools` for the slash command widened to `Bash(node *), Bash(wisp-agentdiff *)`.

CLI behaviour byte-identical to 1.1.0; this is structural-fix-only.

Action for plugin users

Bust the local manifest cache and reinstall:

```text
/plugin uninstall wisp-agentdiff
/plugin marketplace remove wisp-agentdiff
/plugin marketplace add Samuel0101010/wisp-agentdiff
/plugin install wisp-agentdiff@wisp-agentdiff
```

v1.1.0 — Claude Code plugin installable

19 May 20:19

Choose a tag to compare

Now installable as a Claude Code plugin in addition to the existing npx wisp-agentdiff install path.

/plugin marketplace add Samuel0101010/wisp-agentdiff
/plugin install wisp-agentdiff@wisp-agentdiff

Claude Code clones the repo, registers the wisp-agentdiff skill + /review-agents slash command, and wires the native WorktreeCreate / WorktreeRemove hooks automatically — no more manual settings.json edit.

What changed since v1.0.0

Plugin support

  • .claude-plugin/plugin.json — plugin manifest
  • .claude-plugin/marketplace.json — marketplace listing with {source:"github", repo:"..."} form
  • skills/wisp-agentdiff/SKILL.md — moved from templates/ to plugin-standard path
  • commands/review-agents.md — moved from templates/; allowed-tools matcher fixed to space form
  • hooks/hooks.json — three-layer matcher-envelope shape Claude Code's loader requires
  • src/install.ts now reads from the new paths (single source of truth for both flows)

Documentation

  • Three TUI screenshots in the README, now aligned to a uniform 68-cell width (the renderer asserts at build time)
  • About-panel topics, description, and homepage URL set on the public repo
  • Related section in the README cross-links to wisp-orchestrator
  • README install block now documents both the plugin path and the npm path

CLI behavior — unchanged

  • All hook handlers, the review TUI, the merge approver, and the conflict detector are byte-identical to v1.0.0
  • wisp-agentdiff@1.0.0 on npm continues to work for users on the npm install path
  • The plugin's hooks invoke npx -y wisp-agentdiff@latest — so plugin-installed users get whichever npm version is @latest at the moment their first worktree fires

Tests

  • 37 tests still pass on the Linux / macOS / Windows × Node 20 + 22 CI matrix

Hard-won schema rules (memorialised in global Claude Code rules)

Plugin schema notes that took multiple /plugin install rounds to nail:

  • plugin.json repository MUST be a STRING (npm-style {type,url} object is rejected)
  • marketplace.json plugins[].source MUST be an OBJECT {source:"github",repo:"..."} (bare path string is rejected)
  • hooks/hooks.json MUST be three-layer: top-level hooks wrapper, event maps to an array, each entry is a {matcher, hooks:[{type,command}]} envelope
  • WorktreeCreate + WorktreeRemove ARE real hook events (subagent validators with stale event lists will tell you they aren't)
  • /plugin marketplace add defaults to SSH — users without a GitHub SSH key need git config --global "url.https://github.com/.insteadOf" "git@github.com:" once

npm

wisp-agentdiff@1.1.0 is not yet on npm — wisp-agentdiff@1.0.0 is the latest published. Run npm publish from a clean checkout when ready to ship the 1.1.0 tarball.

v1.0.0 — Per-agent diffs for Claude Code parallel subagents

18 May 18:56

Choose a tag to compare

Live on npm: npx wisp-agentdiff installhttps://www.npmjs.com/package/wisp-agentdiff

wisp-agentdiff consumes Claude Code's native WorktreeCreate / WorktreeRemove hooks, captures the diff + JSONL transcript of every subagent worktree, and opens a tabbed Ink TUI where each subagent gets its own pane with single-key approve / revert / merge.

Highlights

  • Per-agent review — one tab per subagent, with diff, token + tool-call telemetry, and decision glyph.
  • Cross-agent conflict detection — if two approved agents touched the same file, the merge step refuses until one side is reverted.
  • Native worktree integration — hooks into Claude Code's WorktreeCreate / WorktreeRemove, no shadow process.
  • Single-key flowa approve, r revert, n / p next/prev, c conflict view, m merge approved, j / k scroll, q quit.

Install

\``bash
npx wisp-agentdiff install
````

Paste the printed hook snippet once into ~/.claude/settings.json and every subagent Claude Code spawns with `isolation: worktree` in its frontmatter is captured automatically.

What's inside

37 tests, CI matrix Linux / macOS / Windows × Node 20 + 22, MIT, TypeScript. Three module groups: `wrap/` (worktree manager + pre/post-spawn hook handlers), `collect/` (unified-diff parser + JSONL transcript reader + per-agent report aggregation), `tui/` (Ink components + pure-reducer hotkey core), `merge/` (cross-agent conflict detector + sequential `git merge --no-ff` approver with abort-on-conflict).

See `docs/architecture.md` for the full pipeline, `docs/roadmap.md` for what's next.