{"record":{"id":"11f0dc5509ba3c9c","repo":"JuliusBrussee/caveman","slug":"non-node-windows-command-shim-executable","errorCode":null,"errorMessage":"non-Node Windows command shim: ${executable}","messagePattern":"non-Node Windows command shim: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"agents/delegate/portable-process.mjs","lineNumber":49,"sourceCode":"    if (!/(?:\\bnode(?:\\.exe)?\\b|_prog)/i.test(line) || !/%\\*/.test(line)) continue;\n    // Shim-relative target (npm cmd-shim, pnpm/yarn-classic @zkochan forms), or\n    // a drive-absolute target (pnpm emits one when the global bin dir and the\n    // store sit on different drives — path.relative crosses drives as absolute).\n    const match = line.match(/\"%(?:dp0%|~dp0)\\\\([^\"\\r\\n]+\\.(?:cjs|mjs|js))\"\\s+%\\*/i)\n      || line.match(/\"([A-Za-z]:[\\\\/][^\"\\r\\n]+\\.(?:cjs|mjs|js))\"\\s+%\\*/i);\n    if (match) return match[1];\n  }\n  return null;\n}\n\nexport function portableInvocation(command, args, platform = process.platform, env = process.env) {\n  if (platform !== \"win32\") return { command, args: [...args] };\n  const executable = resolveWindowsCommand(command, env) ?? command;\n  if (!/\\.(?:cmd|bat)$/i.test(executable)) return { command: executable, args: [...args] };\n  const stat = statSync(executable);\n  if (!stat.isFile() || stat.size > 256 * 1024) throw new Error(`unsafe Windows command shim: ${executable}`);\n  const relativeScript = parseWindowsNodeShim(readFileSync(executable, \"utf8\"));\n  if (!relativeScript) throw new Error(`non-Node Windows command shim: ${executable}`);\n  const script = /^[A-Za-z]:[\\\\/]/.test(relativeScript)\n    ? relativeScript\n    : resolve(dirname(executable), ...relativeScript.split(/[\\\\/]+/));\n  if (!statSync(script).isFile()) throw new Error(`Windows command shim target missing: ${script}`);\n  return { command: process.execPath, args: [script, ...args] };\n}\n\nexport function delegateSpawnOptions(platform = process.platform) {\n  return {\n    detached: platform !== \"win32\",\n    windowsHide: true,\n  };\n}\n\nexport async function killProcessTree(\n  child,\n  platform = process.platform,\n  taskkill = spawnSync,","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/agents/delegate/portable-process.mjs#L31-L67","documentation":"`portableInvocation` parses Windows .cmd/.bat shims looking for a Node script reference it can re-launch via process.execPath. If `parseWindowsNodeShim` cannot extract a relative script path from the shim's contents — the shim is not a recognizable Node wrapper — this error is thrown because running it through cmd.exe would be unsafe and there is no safe fallback.","triggerScenarios":"Calling a Windows command whose resolved executable matches /\\.(cmd|bat)$/i, is a regular file under 256KB, but whose text does not match the expected Node shim pattern (no \"%~dp0\\\\...js\" style target).","commonSituations":"A hand-written or vendor .cmd batch file that is not an npm-generated Node wrapper; a shim generated by a different tool (e.g. pnpm/yarn with different layout); a shim wrapping a non-Node executable (Python, shell).","solutions":["Invoke the underlying tool directly instead of the shim (e.g. `python tool.py` or `node tool.js`)","Regenerate the shim with npm so it is a standard Node wrapper (npm rebuild / reinstall)","Read the .cmd yourself to find the real target and spawn that target via node","Add a non-.cmd entry point for Windows in the package providing the tool"],"exampleFix":"// before\nspawn(\"mytool\", args, opts); // mytool.cmd is a custom batch file\n// after\nspawn(process.execPath, [\"C:/proj/tools/mytool.js\", ...args], opts);","handlingStrategy":"fallback","validationCode":"import { readFileSync, statSync } from \"node:fs\";\nfunction isNodeShim(p) {\n  try {\n    if (!/\\.(?:cmd|bat)$/i.test(p)) return true;\n    const s = statSync(p);\n    return s.isFile() && s.size <= 256 * 1024 &&\n      /\\.js\\b/i.test(readFileSync(p, \"utf8\"));\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  const inv = portableInvocation(command, args);\n  spawn(inv.command, inv.args, opts);\n} catch (e) {\n  if (String(e.message).startsWith(\"non-Node Windows command shim:\")) {\n    // fall back to invoking the real target yourself\n    spawn(\"node\", [resolveRealEntry(command), ...args], opts);\n  } else throw e;\n}","preventionTips":["Only expect portableInvocation to re-write npm-style Node shims, not arbitrary .cmd files","Document non-Node tools and call them directly instead of through the shim","Regenerate shims with npm rather than hand-writing .cmd wrappers","Keep tool entry points as plain .js scripts runnable with node"],"tags":["windows","spawn","shim"],"backgroundTag":"unsupported-operation","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}