Fix hooks for current Claude Code, show permission details, update dependencies - #93
Closed
jeckyl2010 wants to merge 15 commits into
Closed
jeckyl2010 wants to merge 15 commits into
jeckyl2010 wants to merge 15 commits into
Conversation
Node loads a .js file by the nearest package.json above it, so a "type": "module" one in the home directory (such as bun init leaves) made hook.js load as an ES module, where require is undefined, and every hook failed. As hook.mjs with import, Node loads it as an ES module whatever lies above it. Installs running hook.js move to hook.mjs on their own: the extension's migration on activation now also rewrites those commands, setup.js counts them as not set up, and the uninstaller removes both.
Claude Code sends a failed tool's reason as `error` on PostToolUseFailure, not as `tool_response`, so every failure showed as an empty [FAILED]. Read `error`, falling back to `tool_response` for older versions; mark the call as an error in the UI, and show an interrupt as [INTERRUPTED] rather than a failure.
* PermissionRequest: the agent that asked, and the tool and command it waits on, in its detail card and on the timeline block. Once a session sends it, the generic permission Notification is skipped; it remains the fallback for Claude Code versions without the event. * Hooks run with async: true, so Claude Code never waits on the forwarder. A fast tool's end can now arrive before its start: the hook server tracks tool_use_id, shows a start for an early end, and drops the late one. * Existing installs are configured again when an event or async is missing from their hooks. * Repeated permission reports for one wait keep one timeline block, and a wait on an agent not on the canvas shows on the main agent.
* next 16.3, react 19.3, vite 8.3, tailwindcss 4.3, postcss, tsx and the React types * esbuild 0.28, for the extension's and the app's builds Every build and CI check passes; major updates are left for their own changes.
TypeScript 7 no longer includes every installed @types package by default, so the extension names the two it uses. The web build still type-checks under it: a planted type error fails next build.
Its Vite configs are ES modules; Vite 8.3 warns that a package without "type": "module" loads them as CommonJS. Nothing in web/ is CommonJS.
Imports name their file extension, and paths come from import.meta.dirname rather than __dirname, which ES modules lack. The app build no longer warns; the webview build still does, as it imports the extension's constants, which are CommonJS.
pnpm reads it and switches to that version inside the repo, so a newer global pnpm can't rewrite the lockfile in a format CI's pnpm refuses. CI's pnpm/action-setup now takes the version from it too: naming it in both places is an error.
npx under pnpm warned about pnpm's settings in the environment, which npm doesn't know. The build now runs the web package's own Vite with the current Node: no npm and no shell.
|
|
The published app sent anonymous usage telemetry unless it was turned off. It now sends nothing, and writes nothing to ~/.agent-flow, unless AGENT_FLOW_TELEMETRY=true is set; DO_NOT_TRACK=1 still wins over it.
plugin/ is a Claude Code mod that sends a session's events to a running Agent Flow in the hook payload shape its hook server already reads, found through the same discovery files. From inside Claude Code it reports what the settings.json hooks and the transcript can only infer: a tool call's start and end from one wrapped call, a permission request only when its dialog shows, subagents by their real ids under the agent that started them, each model request's model and usage, the session's cost, and answers and thinking as they stream. For a session the mod reports, the hook server drops the command hooks' copies of its events, and the transcript side leaves tool calls, subagents, answers and the permission guess to the mod. The hook server also sends each model request as a model_step event with the agent's usage totals, and stops treating a subagent's stop as a return to itself.
… answers For agents the bridge mod reports, the canvas now shows what the API measured rather than estimates: - Cost: each model request priced from its usage at its own model's rates, which now differ by version within a family and price cache reads apart. The session total is Claude Code's own; a figure that is partly estimated is marked with ~. - Cache: a ring around each agent for the share of its latest request the prompt cache served, and in the cost panel the overall share and what the cache saved. - Heartbeat: every model request pulses out from its agent, sized by what it wrote and colored by why it stopped. - Streaming: answers and thinking type into their bubble as they arrive. The context ring and bar fill to the measured total, a measured count is no longer raised by tool result estimates, and an attached image's note no longer names the main agent.
The bridge mod now reports the effort each model request ran with. Under each agent, a chip names its current model with one hex pip per effort level, low to max. When the model or effort changes, the chip decodes into its new value with a sweep across it and a hexagonal shockwave from the node, and the change is marked on the agent's timeline row. Heartbeat pulses are now hexagons like the nodes, echoed once per effort level above medium.
A finished agent keeps its model tag while its node fades, so a subagent that runs for a few seconds still shows what it ran on. The cache share moves from a label beside the ring, which collided with the cards and bubbles around small subagent nodes, into the agent's model tag. Claude Code's SubagentHandback call, its plumbing for returning a subagent's answer, is no longer drawn as a tool call.
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.
Fixes for current Claude Code (2.1.288), permission details in the UI, async hooks, and dependency updates. Each commit stands on its own and passes CI, so this can be split into smaller PRs if you prefer.
Fixes
The hook fails when a
package.jsonabove it says"type": "module". Node picks a.jsfile's module type from the nearestpackage.json. A~/package.jsonwith"type": "module"(asbun initleaves in a home directory) makes~/.claude/agent-flow/hook.jsload as an ES module, whererequireis undefined, so every hook fails withReferenceError: require is not defined in ES module scopeand no events reach Agent Flow.hook.mjs, written withimport: Node always loads it as an ES module, whatever lies above it.hook.jscommands,setup.jstreats them as not set up, and the uninstaller removes both.A failed tool shows no reason. Claude Code sends it as
erroronPostToolUseFailure, not astool_response, so every failure showed an empty[FAILED]. It now readserror(falling back totool_responsefor older versions), marks the call as an error in the UI, and shows an interrupt as[INTERRUPTED].Features
What a permission waits for. A new
PermissionRequesthook gives the agent that asked, and the tool and command it waits on. The agent's detail card shows it, and the timeline block reads e.g. "Permission: Bash". Once a session sends it, the generic permissionNotificationis skipped; that remains the fallback for Claude Code versions without the event. Repeated reports of one wait keep one timeline block.Async hooks. Hooks run with
async: true, so Claude Code never waits for the forwarder. A fast tool's end can then arrive before its start, so the hook server trackstool_use_id: an early end gets a start shown first, and the late start is dropped. Installs whose hooks lack an event orasyncare configured again.Updates
nodeandvscodeintypes, as TypeScript 7 no longer includes every installed@typespackage.next buildstill type-checks under it (a planted type error fails the build).web/is now"type": "module", and its configs use file extensions andimport.meta.dirname. The app build no longer warns; the webview build still does, as it imports the extension's constants, which are CommonJS.packageManager: pnpm@10.34.6: pnpm switches to it inside the repo, so a newer global pnpm can't rewrite the lockfile in a format CI's refuses. CI'spnpm/action-setupnow reads the version from it; naming it in both places is an error.app/build.jsruns Vite directly instead of throughnpx, which under pnpm warned about pnpm's settings in the environment.Left out on purpose:
@types/vscodeand@types/nodestay matched to the oldest supported VS Code and its Node;concurrently10 and the GitHub Actions major versions are better as their own changes.Testing
pnpm install --frozen-lockfile."type": "module"package.jsonandhook.jshooks:setup.jsmoved them tohook.mjswithasyncon all ten events, kept the user's own hooks, and the installed hook forwarded a real event. A second run changed nothing.