mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-05 02:43:32 +00:00
fix(hooks): emit top-level additionalContext under Codex runtime
The PostToolUse staleness hook always emitted Claude Code's `hookSpecificOutput.additionalContext` shape. Under Codex, the SDK expects a top-level `additionalContext` field, so Codex rejected the hook output with "invalid post-tool-use JSON output". Add isCodexRuntime() (detects CODEX_THREAD_ID / CODEX_CI / CODEX_MANAGED_PACKAGE_ROOT) and branch sendHookResponse() to emit the SDK-standard top-level shape under Codex while keeping the Claude Code shape everywhere else. Applied to both the CJS hook (npm package) and the claude-plugin hook. Adds a regression test asserting Codex runtime produces top-level additionalContext with no hookSpecificOutput wrapper.
This commit is contained in:
parent
50715e3894
commit
dd360261fc
3 changed files with 65 additions and 0 deletions
|
|
@ -238,10 +238,30 @@ function runGitNexusCli(args, cwd, timeout) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect whether the hook is running under Codex rather than Claude Code.
|
||||
* Codex sets CODEX_* environment variables in its hook runtime.
|
||||
*/
|
||||
function isCodexRuntime() {
|
||||
return Boolean(
|
||||
process.env.CODEX_THREAD_ID ||
|
||||
process.env.CODEX_CI ||
|
||||
process.env.CODEX_MANAGED_PACKAGE_ROOT,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a hook response with additional context for the agent.
|
||||
*
|
||||
* Claude Code expects the context nested under its hook-specific output
|
||||
* object; Codex's SDK expects a top-level `additionalContext`. Emitting the
|
||||
* wrong shape makes Codex reject the hook with "invalid post-tool-use JSON".
|
||||
*/
|
||||
function sendHookResponse(hookEventName, message) {
|
||||
if (isCodexRuntime()) {
|
||||
console.log(JSON.stringify({ additionalContext: message }));
|
||||
return;
|
||||
}
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
hookSpecificOutput: { hookEventName, additionalContext: message },
|
||||
|
|
|
|||
|
|
@ -274,10 +274,30 @@ function handlePreToolUse(input) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect whether the hook is running under Codex rather than Claude Code.
|
||||
* Codex sets CODEX_* environment variables in its hook runtime.
|
||||
*/
|
||||
function isCodexRuntime() {
|
||||
return Boolean(
|
||||
process.env.CODEX_THREAD_ID ||
|
||||
process.env.CODEX_CI ||
|
||||
process.env.CODEX_MANAGED_PACKAGE_ROOT,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a PostToolUse hook response with additional context for the agent.
|
||||
*
|
||||
* Claude Code expects the context nested under its hook-specific output
|
||||
* object; Codex's SDK expects a top-level `additionalContext`. Emitting the
|
||||
* wrong shape makes Codex reject the hook with "invalid post-tool-use JSON".
|
||||
*/
|
||||
function sendHookResponse(hookEventName, message) {
|
||||
if (isCodexRuntime()) {
|
||||
console.log(JSON.stringify({ additionalContext: message }));
|
||||
return;
|
||||
}
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
hookSpecificOutput: { hookEventName, additionalContext: message },
|
||||
|
|
|
|||
|
|
@ -1438,6 +1438,31 @@ describe('PostToolUse staleness detection (integration)', () => {
|
|||
const output = parseHookOutput(result.stdout);
|
||||
expect(output).not.toBeNull();
|
||||
});
|
||||
|
||||
it(`${label}: emits top-level additionalContext under Codex runtime`, () => {
|
||||
fs.writeFileSync(
|
||||
path.join(gitNexusDir, 'meta.json'),
|
||||
JSON.stringify({ lastCommit: 'aaaaaaa0000000000000000000000000deadbeef', stats: {} }),
|
||||
);
|
||||
|
||||
const result = runHook(
|
||||
hookPath,
|
||||
{
|
||||
hook_event_name: 'PostToolUse',
|
||||
tool_name: 'Bash',
|
||||
tool_input: { command: 'git commit -m "test"' },
|
||||
tool_output: { exit_code: 0 },
|
||||
cwd: tmpDir,
|
||||
},
|
||||
undefined,
|
||||
{ env: { ...process.env, CODEX_THREAD_ID: 'test-thread' } },
|
||||
);
|
||||
|
||||
// Codex expects top-level additionalContext, NOT hookSpecificOutput.
|
||||
const parsed = JSON.parse(result.stdout.trim());
|
||||
expect(parsed.additionalContext).toContain('stale');
|
||||
expect(parsed.hookSpecificOutput).toBeUndefined();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue