{"record":{"id":"e39d5a9104917423","repo":"stablyai/orca","slug":"installed-launcher-did-not-preserve-a-running-scri","errorCode":null,"errorMessage":"Installed launcher did not preserve a running script failure","messagePattern":"Installed launcher did not preserve a running script failure","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/scripts/verify-agent-hook-stdin-lifecycle.mjs","lineNumber":348,"sourceCode":"  try {\n    const missingResult = await runShell(\n      command,\n      payload,\n      withoutOrcaEnvironment({ HOME: scratch })\n    )\n    assertSuccessfulWrite(missingResult, 'installed missing-script launcher')\n\n    const failingPath = join(scratch, '.orca', 'agent-hooks', 'claude-hook.sh')\n    mkdirSync(join(scratch, '.orca', 'agent-hooks'), { recursive: true })\n    writeFileSync(failingPath, '#!/bin/sh\\ncat >/dev/null\\nexit 7\\n', 'utf8')\n    chmodSync(failingPath, 0o755)\n    const failingResult = await runShell(\n      command,\n      payload,\n      withoutOrcaEnvironment({ HOME: scratch })\n    )\n    if (failingResult.exitCode !== 7 || failingResult.stdinErrors.length > 0) {\n      throw new Error('Installed launcher did not preserve a running script failure')\n    }\n  } finally {\n    rmSync(scratch, { recursive: true, force: true })\n  }\n}\n\nasync function main() {\n  const args = parseArgs(process.argv.slice(2))\n  const payload = JSON.stringify({\n    hook_event_name: 'PostToolUse',\n    tool_name: 'shell',\n    tool_output: 'x'.repeat(1_200_000)\n  })\n  const scripts = readGeneratedScripts(args.home, args.minMtime)\n  await verifyNoOpWrites(scripts, args.home, payload)\n  await verifyClaudeDevinSkip(scripts, args.home, payload)\n  await verifyForwarding(scripts, args.home, payload)\n  await verifyInstalledLauncher(args.home, payload)","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/verify-agent-hook-stdin-lifecycle.mjs#L330-L366","documentation":"This assertion is part of verifyInstalledLauncher, which validates the Claude agent-hook launcher that Electron installs into ~/.claude/settings.json. After writing a deliberately-failing hook script (exit 7) at $HOME/.orca/agent-hooks/claude-hook.sh, it runs the installed launcher and expects the launcher to propagate that non-zero exit AND to forward the large stdin payload without EPIPE/stdin errors. Failure means the launcher swallowed the child's exit code or dropped/broke the stdin pipe to the child.","triggerScenarios":"Invoked when failingResult.exitCode !== 7 OR failingResult.stdinErrors.length > 0 at line 347. This happens if the installed launcher masks the hook's exit code (e.g. always exits 0, or `|| true`), or if it closes stdin before the hook reads it (broken pipe / SIGPIPE) so that node's child.stdin emits an 'error' event captured in stdinErrors.","commonSituations":"A regression in the Electron-installed launcher template (the guarded `if [ -f ... ] && [ -r ... ]` shim) that changes how it forwards stdin or exit status; running the verifier against an older Electron home whose launcher predates stdin-safe forwarding; a shell that handles SIGPIPE differently.","solutions":["Inspect the installed command string in ~/.claude/settings.json and confirm it forwards stdin to the hook and exits with the hook's status (no `|| exit 0`, no `</dev/null`).","Reinstall the launcher from a current Electron build (`orca` settings write) so the guarded shim is regenerated, then rerun verify-agent-hook-stdin-lifecycle.mjs.","If stdinErrors is non-empty, check the launcher isn't redirecting stdin away from the child — the fix is to let the child inherit the launcher's stdin."],"exampleFix":"# before (launcher masks failure)\nif [ -f \"$HOME/.orca/agent-hooks/claude-hook.sh\" ]; then\n  \"$HOME/.orca/agent-hooks/claude-hook.sh\" || true\nfi\n# after (propagate exit + keep stdin connected)\nif [ -f \"$HOME/.orca/agent-hooks/claude-hook.sh\" ] && [ -r \"$HOME/.orca/agent-hooks/claude-hook.sh\" ]; then\n  \"$HOME/.orca/agent-hooks/claude-hook.sh\"\nelse\n  { command -p cat >/dev/null; } 2>/dev/null\nfi","handlingStrategy":"validation","validationCode":"// Validate the installed launcher propagates exit + stdin before the full suite.\nconst probe = '#!/bin/sh\\ncat >/dev/null\\nexit 7\\n'\nwriteFileSync(failingPath, probe, 'utf8')\nchmodSync(failingPath, 0o755)\nconst r = await runShell(command, payload, env)\nif (r.exitCode !== 7) throw new Error(`launcher exit not propagated: ${r.exitCode}`)\nif (r.stdinErrors.length > 0) throw new Error(`launcher broke stdin: ${r.stdinErrors.join(';')}`)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the installed launcher shim's `if [ -f ... ] && [ -r ... ]` shape intact so stdin forwarding and exit propagation are preserved.","Never redirect the hook's stdin (`</dev/null`) in the launcher.","Re-run verify-agent-hook-stdin-lifecycle.mjs after any change to the launcher template."],"tags":["agent-hooks","electron","stdin","launcher","claude","exit-code"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}