{"record":{"id":"4629632c0469f4b0","repo":"stablyai/orca","slug":"refusing-to-patch-node-pty-packagejson-version","errorCode":null,"errorMessage":"Refusing to patch node-pty ${packageJson.version}; expected ${EXPECTED_NODE_PTY_VERSION}","messagePattern":"Refusing to patch node-pty (.+?); expected (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/relay-assets/node-pty-1.1.0-console-list-agent-patch.cjs","lineNumber":24,"sourceCode":"const ORIGINAL_SOURCE_SHA256 = '0d010879bb6680a0253d44363183d53e631f42972594eb6dcb1fb842c8c85e52'\nconst PATCHED_SOURCE_SHA256 = '84df20cfe711a88d2bef35078615c58a6ce14f39348a4aef40e852b854dcd857'\nconst ORIGINAL_BODY = 'var consoleProcessList = getConsoleProcessList(shellPid);'\nconst PATCHED_BODY = `var consoleProcessList;\ntry {\n    consoleProcessList = getConsoleProcessList(shellPid);\n}\ncatch (_a) {\n    // Why: AttachConsole can fail without a Win32 console; use node-pty's timeout fallback immediately.\n    consoleProcessList = [shellPid];\n}`\n\nfunction inspectNodePtyConsoleListAgent(relayDir = process.cwd()) {\n  const nodePtyDir = resolve(relayDir, 'node_modules', 'node-pty')\n  const packageJsonPath = join(nodePtyDir, 'package.json')\n  const agentPath = join(nodePtyDir, 'lib', 'conpty_console_list_agent.js')\n  const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))\n  if (packageJson.version !== EXPECTED_NODE_PTY_VERSION) {\n    throw new Error(\n      `Refusing to patch node-pty ${packageJson.version}; expected ${EXPECTED_NODE_PTY_VERSION}`\n    )\n  }\n  const source = readFileSync(agentPath, 'utf8')\n  return { agentPath, source }\n}\n\nfunction assertPatchedNodePtyConsoleListAgent(relayDir = process.cwd()) {\n  const inspected = inspectNodePtyConsoleListAgent(relayDir)\n  if (sourceSha256(inspected.source) !== PATCHED_SOURCE_SHA256) {\n    throw new Error('node-pty ConPTY console-list fallback is not installed')\n  }\n}\n\nfunction patchNodePtyConsoleListAgent(relayDir = process.cwd()) {\n  const inspected = inspectNodePtyConsoleListAgent(relayDir)\n  const sourceHash = sourceSha256(inspected.source)\n  if (sourceHash === PATCHED_SOURCE_SHA256) {","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/relay-assets/node-pty-1.1.0-console-list-agent-patch.cjs#L6-L42","documentation":"Thrown by inspectNodePtyConsoleListAgent when the installed node-pty's package.json version is not exactly '1.1.0' (EXPECTED_NODE_PTY_VERSION). The patch is pinned by exact SHA256 hashes of the original and patched source, so applying it to any other version would silently corrupt the file; the guard refuses to proceed.","triggerScenarios":"Calling patchNodePtyConsoleListAgent or assertPatchedNodePtyConsoleListAgent after node-pty was upgraded or downgraded away from 1.1.0; a lockfile resolve bumped node-pty to a patch release (e.g. 1.1.1).","commonSituations":"Dependency refresh (pnpm update node-pty) pulled a newer release; a transitive dependency forced a different node-pty; the relay install ran against a fresh node_modules where node-pty resolved higher than the lockfile intended.","solutions":["Pin node-pty to 1.1.0 in the lockfile (pnpm add node-pty@1.1.0 or pnpm install --frozen-lockfile) and retry.","If upgrading node-pty is intentional, re-derive ORIGINAL_SOURCE_SHA256 and PATCHED_SOURCE_SHA256 against the new lib/conpty_console_list_agent.js and update EXPECTED_NODE_PTY_VERSION plus both hashes in config/relay-assets/node-pty-1.1.0-console-list-agent-patch.cjs.","Verify the new node-pty still ships lib/conpty_console_list_agent.js with the ORIGINAL_BODY string before re-hashing.","Re-run the relay postinstall hook to confirm assertPatchedNodePtyConsoleListAgent passes."],"exampleFix":"// before — lockfile drifted to 1.1.1\n// pnpm update node-pty\n\n// after — repin\n// pnpm add node-pty@1.1.0\n// node config/relay-assets/node-pty-1.1.0-console-list-agent-patch.cjs","handlingStrategy":"validation","validationCode":"const { readFileSync } = require('node:fs')\nconst { join } = require('node:path')\n\nfunction assertNodePtyVersion(relayDir, expected = '1.1.0') {\n  const pkg = JSON.parse(readFileSync(join(relayDir, 'node_modules', 'node-pty', 'package.json'), 'utf8'))\n  if (pkg.version !== expected) {\n    throw new Error(`node-pty is ${pkg.version}, expected ${expected}. Run 'pnpm add node-pty@${expected}'.`)\n  }\n}\n// assertNodePtyVersion(process.cwd()) before invoking the patch","typeGuard":null,"tryCatchPattern":"try {\n  inspectNodePtyConsoleListAgent(relayDir)\n} catch (error) {\n  if (/Refusing to patch node-pty/.test(error.message)) {\n    console.error(`${error.message}\\nPin node-pty@1.1.0 in the lockfile, or re-derive the patch hashes for the new version.`)\n    process.exit(1)\n  }\n  throw error\n}","preventionTips":["Pin node-pty@1.1.0 exactly (not ^1.1.0) in package.json so patch releases cannot drift in.","Add a CI check that asserts node-pty's installed version equals EXPECTED_NODE_PTY_VERSION before the relay postinstall runs.","When upgrading node-pty, treat re-deriving ORIGINAL/PATCHED hashes as a required step of the upgrade PR."],"tags":["node-pty","dependency","version-pin","patch","relay"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}