Repository navigation
fix(hook): inject stderr context from pass hooks into tool output - #85
Conversation
When hooks exit 0 with stderr messages, the context was being discarded at all 4 hook call sites in prompt.ts. This adds <hook-context> wrapping to inject PreToolUse messages as prefix and PostToolUse messages as suffix into tool output for both built-in and MCP tools, fulfilling Issue #47 acceptance criteria for "exit 0: stderr context injection". Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The .catch() handlers on PostToolUse runHooks calls returned
{ action: "pass" } without message property, causing TS2339 when
accessing .message on the union type. Using HookResult as the return
type resolves this since it includes message?: string.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
This PR doesn't fully meet our contributing guidelines and PR template. What needs to be fixed:
Please edit this PR description to address the above within 2 hours, or it will be automatically closed. If you believe this was flagged incorrectly, please let a maintainer know. |
|
The following comment was made by an LLM, it may be inaccurate: |
There was a problem hiding this comment.
Pull request overview
This PR fixes hook “pass-with-stderr” behavior so that hook stderr (exit 0) is surfaced to the LLM by injecting it into tool output as <hook-context> for both built-in tools and MCP tools, aligning with the acceptance criteria from the hook issues.
Changes:
- Inject PreToolUse hook
messageas a prefix and PostToolUse hookmessageas a suffix in built-in tool outputs. - Apply the same injection pattern to MCP tool outputs.
- Add hook context-injection tests and tighten
.catch()fallback typing toHookResult.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/opencode/src/session/prompt.ts | Injects <hook-context> into tool outputs for built-in + MCP tools; adjusts post-hook .catch() typing. |
| packages/opencode/test/hook/context-injection.test.ts | Adds tests covering pass/block behavior and the expected <hook-context> prefix/suffix formatting. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Inject PreToolUse hook context into output | ||
| if (hookResult.message) { | ||
| output.output = `<hook-context>\n${hookResult.message}\n</hook-context>\n\n${output.output}` | ||
| } |
There was a problem hiding this comment.
Hook context injection is applied after the tool output has already been truncated (built-in tools are truncated in Tool.wrap). This can re-expand the final output beyond the truncation limits / provider size constraints if a hook writes a lot to stderr. Consider truncating again after injecting (or cap/summarize hookResult.message before injection) so tool outputs remain bounded.
| // Inject hook context from PreToolUse and PostToolUse | ||
| let mcpOutput = truncated.content | ||
| if (mcpHookResult.message) { | ||
| mcpOutput = `<hook-context>\n${mcpHookResult.message}\n</hook-context>\n\n${mcpOutput}` | ||
| } | ||
| if (mcpPostResult.message) { | ||
| mcpOutput = `${mcpOutput}\n\n<hook-context>\n${mcpPostResult.message}\n</hook-context>` | ||
| } |
There was a problem hiding this comment.
For MCP tools, hook context is injected after truncate.output(...) has produced truncated.content, so the final mcpOutput can exceed the truncation limits if hook stderr is large. Consider truncating the combined string (hook context + truncated content) or bounding hook messages before concatenation to keep tool results within expected size limits.
Replace direct mutation of const output.output with let finalOutput reassignment and spread return, matching the MCP path's immutable pattern. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Summary
prompt.tsの4つのhook呼び出し箇所で、pass時のhookResult.messageを<hook-context>タグとしてtool outputに注入.catch()の戻り値型をHookResultに修正What
Issue #47 の受入基準「exit 0: stderrがあればコンテキスト注入」を実装。
runHooks()は正しく pass message を返していたが、prompt.tsがaction === "block"のみチェックして破棄していた。Type
Verify
bun test test/hook/— 43テスト全パス (既存22 + schema13 + 新規8)bun typecheck— 全パッケージパス<hook-context>がtool outputに含まれることを確認Checklist
Issue
Closes #80
🤖 Generated with Claude Code