Guard the remaining harness manifests against a dead node runtime

Bugbot caught the Codex plugin builder still invoking node directly, and the
same reasoning covers GitHub Copilot and Grok Build: all three shipped the
exact failure this branch exists to stop, and sat visibly inconsistent with
their guarded siblings.

Route them through guardedNode with no notice, matching Codex and Cursor.
GitHub gains a second property from it: outside a git repository
`$(git rev-parse --show-toplevel)` expands to nothing, so the old command
handed node a path that could not exist and failed the turn. The file test
now short-circuits that to exit 0.

Every builder carries the probe; only the two Claude manifests carry the
notice, which is the only harness whose response shape is confirmed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Abdul Wahab
2026-07-26 20:58:49 +05:00
co-authored by Claude Opus 5
parent 8397d532b9
commit 0c19098754
4 changed files with 17 additions and 14 deletions
+11 -9
View File
@@ -60,10 +60,12 @@ const CLAUDE_PROJECT_HOOK = '${CLAUDE_PROJECT_DIR}/.claude/skills/impeccable/scr
//
// `notice` is the shell that reports the dead runtime to the user, and it is
// passed in rather than baked in because the wire format is per harness. Claude
// Code reads a `systemMessage` field off stdout on exit 0; what Codex and Cursor
// do with stdout they did not ask for is unconfirmed, so they take the probe
// alone and an unsupported runtime stays as quiet there as it was before the
// probe existed. Adding their shape later is one more argument at the call site.
// Code reads a `systemMessage` field off stdout on exit 0. Codex expects
// `hookSpecificOutput` and Cursor a permission-shaped payload, so handing either
// a Claude response gets it discarded or printed raw; until those shapes are
// confirmed every non-Claude harness takes the probe alone, and an unsupported
// runtime stays as quiet there as it was before the probe existed. Adding a
// shape later is one more argument at that harness's call site.
const guardedNode = (hookPath, notice = '') => {
const probe = notice
? `! { node -e "import('fs')" 2>/dev/null || { ${notice}; exit 0; }; }`
@@ -156,14 +158,14 @@ export function buildCodexPluginHooksManifest() {
hooks: [
{
type: 'command',
command: `node "${CODEX_PLUGIN_HOOK}"`,
command: guardedNode(CODEX_PLUGIN_HOOK),
timeout: TIMEOUT_SECONDS,
statusMessage: STATUS_MESSAGE,
},
],
},
],
Stop: [stopEntry(`node "${CODEX_PLUGIN_HOOK}"`)],
Stop: [stopEntry(guardedNode(CODEX_PLUGIN_HOOK))],
},
};
}
@@ -226,7 +228,7 @@ export function buildGitHubHooksManifest() {
{
type: 'command',
matcher: 'edit|create|apply_patch',
bash: `node "${GITHUB_PROJECT_HOOK}"`,
bash: guardedNode(GITHUB_PROJECT_HOOK),
timeoutSec: TIMEOUT_SECONDS,
},
],
@@ -248,14 +250,14 @@ export function buildGrokHooksManifest() {
hooks: [
{
type: 'command',
command: `node "${GROK_PROJECT_HOOK}"`,
command: guardedNode(GROK_PROJECT_HOOK),
timeout: TIMEOUT_SECONDS,
statusMessage: STATUS_MESSAGE,
},
],
},
],
Stop: [stopEntry(`node "${GROK_PROJECT_HOOK}"`)],
Stop: [stopEntry(guardedNode(GROK_PROJECT_HOOK))],
},
};
}