fix(hooks): run hooks in the session cwd; honest process-level config + best-effort session-start; surface systemMessage drop
Address review on the bridges: - Hook cwd (blocking): the bridges never passed a workdir to runHook, so hooks ran in the executor default (the ACP server launch dir), not the session cwd — a hook doing `pwd`/relative reads/marker writes operated in the wrong tree. Both bridges now thread the agent's session `header.cwd` (the session/new.cwd) as the hook workdir for agent-scoped points. Regression per bridge: server cwd ≠ session cwd, a `pwd` hook proves it ran in the session workspace (proven red without the workdir). - Example config honesty (blocking): `configPath: ./hooks.json` is read ONCE at load against the PROCESS cwd, not per-session — the comment/README now say so explicitly (a project-local per-session hooks.json is not discovered; TODO(per-session-hook-config)). The hooks-run-in-session-cwd fix above is the distinct, separately-documented half. - Session-start timing (blocking): agent/session-start is a synchronous emit and the hook runs on a detached .then, so injected context is BEST-EFFORT — not guaranteed before the first request. Downgrade the contract in code comments + README + RFC (TODO(session-start-gating)) rather than implying "first request sees it", and add a no-wait regression that asserts the safe properties without pre-waiting for the inject. - systemMessage (non-blocking): the merge collects merged.systemMessages but no bridge surfaced it. Warn per hook (like updatedInput) and document it as deferred in both READMEs + the RFC; tests assert the warn + non-surfacing.
This commit is contained in:
@@ -86,11 +86,14 @@
|
||||
- id: tool-todo
|
||||
name: '@deepseek-ai/dsh-tool-todo'
|
||||
|
||||
# The Claude Code hook bridge, pointed at a `hooks.json` in the session cwd. A
|
||||
# scenario that ships `workspace/hooks.json` (copied into the cwd before the run)
|
||||
# exercises the hooks path end-to-end; every other scenario has no such file, so
|
||||
# the bridge's parse fails-soft and it registers nothing (a silent no-op — the
|
||||
# ACP app loads no logger exporter, so the warning never reaches stdout).
|
||||
# The Claude Code hook bridge. `configPath` is read ONCE at load and resolves
|
||||
# `./hooks.json` against the PROCESS cwd (not per-session) — in these snapshot
|
||||
# runs the harness launches the subprocess with process cwd = the scenario's temp
|
||||
# workspace, so a scenario that ships `workspace/hooks.json` (copied into that cwd
|
||||
# before the run) exercises the hooks path end-to-end; every other scenario has no
|
||||
# such file, so the parse fails-soft and the bridge registers nothing (a silent
|
||||
# no-op — the ACP app loads no logger exporter, so the warning never reaches
|
||||
# stdout). Hooks themselves run in the session cwd (the bridge passes it as workdir).
|
||||
- id: hooks-claude
|
||||
name: '@deepseek-ai/dsh-hooks-claude'
|
||||
config:
|
||||
|
||||
@@ -96,11 +96,16 @@
|
||||
- id: tool-todo
|
||||
name: '@deepseek-ai/dsh-tool-todo'
|
||||
|
||||
# The Claude Code hook bridge, pointed at a `hooks.json` in the session cwd. With
|
||||
# no such file present the parse fails-soft and the bridge registers nothing (a
|
||||
# silent no-op); a session whose cwd holds a `hooks.json` runs those hooks on the
|
||||
# interception seams. stdout is the ACP JSON-RPC channel — the bridge's warnings
|
||||
# go through ctx.logger (no exporter here), never to stdout.
|
||||
# The Claude Code hook bridge. `configPath` is PROCESS-LEVEL: it is read ONCE at
|
||||
# load and the relative `./hooks.json` resolves against the ACP server's launch
|
||||
# cwd, NOT each `session/new.cwd`. So a single `hooks.json` next to where the
|
||||
# server starts applies to every session; a project-local, per-session hooks.json
|
||||
# is NOT discovered (per-session config resolution is a TODO — see the bridge
|
||||
# README). With no file present the parse fails-soft and the bridge registers
|
||||
# nothing (a silent no-op). Hooks THEMSELVES run in the session cwd (the bridge
|
||||
# passes it as the workdir); only WHERE the config is read from is process-level.
|
||||
# stdout is the ACP JSON-RPC channel — the bridge's warnings go through ctx.logger
|
||||
# (no exporter here), never to stdout.
|
||||
- id: hooks-claude
|
||||
name: '@deepseek-ai/dsh-hooks-claude'
|
||||
config:
|
||||
|
||||
Reference in New Issue
Block a user