fix(hooks): delegate context-only hooks + default CLAUDE_PROJECT_DIR
Address review on the hook-bridges PR — two composability/compatibility bugs in both the CC and Codex bridges: 1. A hook that only attaches additionalContext (no block/deny) returned `allow`/`accept` WITHOUT calling next(), short-circuiting every later agent/prompt-submit / tools/post-execute listener. A policy/sandbox plugin registered after the bridge never saw the prompt. Now the context-only path delegates via next() and folds its context onto the downstream decision (concatContext): a downstream block/deny still wins and carries the bridge context; a downstream allow/accept keeps its own content rewrite and gains the context. Only a real hook deny/block short-circuits. 2. CLAUDE_PROJECT_DIR was empty in the default ACP wiring (no projectDir configured), breaking common unmodified hooks that reference $CLAUDE_PROJECT_DIR. It now defaults per-run to the agent's session workspace (the same cwd the hook runs in); an explicit config.projectDir still wins. Regression tests per bridge: a later listener blocks a prompt a context-only hook allowed; both contexts survive when the downstream also adds one; the default CLAUDE_PROJECT_DIR reaches the hook. Each proven red on the pre-fix code.
This commit is contained in:
@@ -40,9 +40,9 @@ The hooks themselves run in the agent's session workspace: for the agent-scoped
|
||||
| Codex hook | Harness seam | Mapping |
|
||||
|---|---|---|
|
||||
| `SessionStart` | `agent/session-start` (emit) | a plain-stdout hook's output → additionalContext → `agent.inject()` |
|
||||
| `UserPromptSubmit` | `agent/prompt-submit` (waterfall) | `block` (exit 2) → `PromptDecision.block`; additionalContext → `allow` with context |
|
||||
| `UserPromptSubmit` | `agent/prompt-submit` (waterfall) | `block` (exit 2) → `PromptDecision.block`; additionalContext-only → delegate via `next()` then fold context onto the downstream decision |
|
||||
| `PreToolUse` | `tools/pre-execute` (waterfall) | `block` → `PreToolDecision.deny` (no `allow`/`ask`) |
|
||||
| `PostToolUse` | `tools/post-execute` (waterfall) | `block` → `block` with feedback; additionalContext → `accept` with context |
|
||||
| `PostToolUse` | `tools/post-execute` (waterfall) | `block` → `block` with feedback; additionalContext-only → delegate via `next()` then fold context onto the downstream decision |
|
||||
| `Stop` | `agent/turn-continuation` (waterfall) | a blocking Stop hook forces `continue` with the reason as next-step steering |
|
||||
|
||||
A tool call's payload carries the real `tool_name` (the same value the matcher tests) and Codex's `tool_input: { command }` shape (the `command` arg when present, else `''`). The matcher subject is the tool name (`PreToolUse`/`PostToolUse`) or the session source (`SessionStart`); `UserPromptSubmit`/`Stop` ignore matchers.
|
||||
|
||||
Reference in New Issue
Block a user