@ai-agent-forge/plugin-process-exec 0.86.0 → 0.86.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-forge.json +1 -1
- package/dist/node-adapter.d.ts +9 -0
- package/dist/node-adapter.d.ts.map +1 -1
- package/dist/node-adapter.js +86 -15
- package/dist/node-adapter.js.map +1 -1
- package/package.json +3 -3
- package/plugin.json +1 -1
package/agent-forge.json
CHANGED
package/dist/node-adapter.d.ts
CHANGED
|
@@ -16,6 +16,15 @@ export interface NodeProcessExecAdapterOptionsV1 {
|
|
|
16
16
|
/** Deterministic host seam; production defaults to Node's shell-free spawn. */
|
|
17
17
|
readonly spawn?: typeof spawn;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Builds a bounded preview from the retained capture. `captured` holds the
|
|
21
|
+
* complete output when `totalBytes <= previewBytes`; otherwise it holds the
|
|
22
|
+
* first `head` bytes followed by the last `tail` bytes of the stream, and the
|
|
23
|
+
* two segments are joined with an omission marker. The marker rides on top of
|
|
24
|
+
* the segment budgets but the assembled preview never exceeds
|
|
25
|
+
* `PROCESS_EXEC_MAX_PREVIEW_BYTES_V1`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function buildHeadTailPreviewV1(captured: Uint8Array, previewBytes: number, totalBytes: number): string;
|
|
19
28
|
/** Redacts credentials and host paths before a preview can reach the model. */
|
|
20
29
|
export declare function sanitizeProcessTextV1(value: string, maximumChars?: number, cwd?: string): string;
|
|
21
30
|
/** Node host adapter with shell-free argv execution and bounded output previews. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-adapter.d.ts","sourceRoot":"","sources":["../src/node-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG3C,OAAO,EAGN,KAAK,oBAAoB,EAGzB,MAAM,YAAY,CAAC;AAKpB,eAAO,MAAM,gCAAgC,QAAc,CAAC;AAE5D,eAAO,MAAM,iCAAiC,OAAO,CAAC;AAItD,eAAO,MAAM,sCAAsC,MAAM,CAAC;AAE1D,MAAM,WAAW,+BAA+B;IAC/C,iEAAiE;IACjE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,4DAA4D;IAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CAC9B;AAQD,+EAA+E;AAC/E,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,MAAM,EACb,YAAY,SAAoC,EAChD,GAAG,CAAC,EAAE,MAAM,GACV,MAAM,CAUR;AAwID,oFAAoF;AACpF,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,+BAA+B,GAAG,oBAAoB,CAwL7G","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { isAbsolute } from \"node:path\";\nimport { killProcessTree, sanitizeBinaryOutput } from \"./shell-utils.ts\";\nimport {\n\tPROCESS_EXEC_HOST_ADAPTER_ID_V1,\n\tPROCESS_EXEC_HOST_ADAPTER_VERSION_V1,\n\ttype ProcessExecAdapterV1,\n\ttype ProcessExecRequestV1,\n\ttype ProcessExecResultV1,\n} from \"./types.ts\";\n\nconst DEFAULT_TIMEOUT_MS_V1 = 30_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_OUTPUT_BYTES_V1 = 64 * 1024;\nexport const PROCESS_EXEC_MAX_OUTPUT_BYTES_V1 = 1024 * 1024;\nconst DEFAULT_PREVIEW_BYTES_V1 = 4096;\nexport const PROCESS_EXEC_MAX_PREVIEW_BYTES_V1 = 8192;\nconst MAX_ARGS_V1 = 256;\nconst MAX_COMMAND_CHARS_V1 = 512;\nconst MAX_ARG_CHARS_V1 = 4096;\nexport const PROCESS_EXEC_MAX_OPERATION_ID_CHARS_V1 = 256;\n\nexport interface NodeProcessExecAdapterOptionsV1 {\n\t/** Host-owned working directory; requests cannot override it. */\n\treadonly cwd: string;\n\treadonly env?: Readonly<Record<string, string>>;\n\treadonly defaultTimeoutMs?: number;\n\treadonly maxStdoutBytes?: number;\n\treadonly maxStderrBytes?: number;\n\treadonly previewBytes?: number;\n\t/** Test seam for the host-owned process-tree terminator. */\n\treadonly killProcessTree?: (pid: number) => void;\n\t/** Deterministic host seam; production defaults to Node's shell-free spawn. */\n\treadonly spawn?: typeof spawn;\n}\n\nconst SAFE_ENVIRONMENT_KEYS_V1 = new Set(\n\t[\"PATH\", \"PATHEXT\", \"SystemRoot\", \"SYSTEMROOT\", \"WINDIR\", \"TEMP\", \"TMP\", \"TMPDIR\", \"LANG\", \"LC_ALL\"].map((key) =>\n\t\tkey.toLowerCase(),\n\t),\n);\n\n/** Redacts credentials and host paths before a preview can reach the model. */\nexport function sanitizeProcessTextV1(\n\tvalue: string,\n\tmaximumChars = PROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\tcwd?: string,\n): string {\n\tlet text = sanitizeBinaryOutput(value);\n\tif (cwd !== undefined && cwd !== \"\") text = text.replaceAll(cwd, \"[redacted-path]\");\n\ttext = text\n\t\t.replace(\n\t\t\t/((?:api[-_ ]?key|access[-_ ]?token|auth(?:orization)?|bearer|password|passwd|secret|token)\\s*[:=]\\s*)([^\\s,;]+)/giu,\n\t\t\t\"$1[redacted-secret]\",\n\t\t)\n\t\t.replace(/(?:[A-Za-z]:[\\\\/]|\\\\\\\\|\\/(?:home|Users|private|tmp|var|workspace)\\/)[^\\s\"'<>]*/gu, \"[redacted-path]\");\n\treturn text.length <= maximumChars ? text : text.slice(0, maximumChars);\n}\n\nfunction hostEnvironment(explicit: Readonly<Record<string, string>> | undefined): NodeJS.ProcessEnv {\n\tconst inherited: NodeJS.ProcessEnv = {};\n\tfor (const [key, value] of Object.entries(process.env)) {\n\t\tif (value !== undefined && SAFE_ENVIRONMENT_KEYS_V1.has(key.toLowerCase())) inherited[key] = value;\n\t}\n\treturn { ...inherited, ...(explicit ?? {}) };\n}\n\nfunction positiveBound(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result < 1 || result > maximum)\n\t\tthrow new Error(`${label} must be a positive integer at most ${maximum}`);\n\treturn result;\n}\n\nfunction inputError(operationId: string, message: string): ProcessExecResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: \"Process request was invalid\",\n\t\tstdoutBytes: 0,\n\t\tstderrBytes: 0,\n\t\tstdoutPreview: \"\",\n\t\tstderrPreview: \"\",\n\t\tstdoutTruncated: false,\n\t\tstderrTruncated: false,\n\t\terror: { version: 1, code: \"invalid_input\", message },\n\t};\n}\n\nfunction cancelled(operationId: string): ProcessExecResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"cancelled\",\n\t\tsummary: \"Process execution was cancelled\",\n\t\tstdoutBytes: 0,\n\t\tstderrBytes: 0,\n\t\tstdoutPreview: \"\",\n\t\tstderrPreview: \"\",\n\t\tstdoutTruncated: false,\n\t\tstderrTruncated: false,\n\t\terror: { version: 1, code: \"cancelled\", message: \"Process execution was cancelled\" },\n\t};\n}\n\nfunction validateRequest(request: ProcessExecRequestV1): string | undefined {\n\tif (request.version !== 1) return \"version must be 1\";\n\tif (\n\t\ttypeof request.operationId !== \"string\" ||\n\t\trequest.operationId.trim() === \"\" ||\n\t\trequest.operationId.length > PROCESS_EXEC_MAX_OPERATION_ID_CHARS_V1\n\t)\n\t\treturn \"operationId is invalid\";\n\tif (\n\t\ttypeof request.command !== \"string\" ||\n\t\trequest.command.trim() === \"\" ||\n\t\trequest.command.length > MAX_COMMAND_CHARS_V1 ||\n\t\t/[\\u0000\\r\\n]/u.test(request.command)\n\t)\n\t\treturn \"command is invalid\";\n\tif (!Array.isArray(request.args) || request.args.length > MAX_ARGS_V1) return \"args are invalid\";\n\tif (\n\t\trequest.args.some((arg) => typeof arg !== \"string\" || arg.length > MAX_ARG_CHARS_V1 || /[\\u0000\\r\\n]/u.test(arg))\n\t)\n\t\treturn \"args are invalid\";\n\tif (\n\t\trequest.timeoutMs !== undefined &&\n\t\t(!Number.isSafeInteger(request.timeoutMs) || request.timeoutMs < 1 || request.timeoutMs > MAX_TIMEOUT_MS_V1)\n\t)\n\t\treturn `timeoutMs must be a positive integer at most ${MAX_TIMEOUT_MS_V1}`;\n\treturn undefined;\n}\n\nfunction previewText(bytes: Uint8Array): string {\n\treturn new TextDecoder().decode(bytes);\n}\n\nfunction result(\n\trequest: ProcessExecRequestV1,\n\tstatus: ProcessExecResultV1[\"status\"],\n\tstdout: Uint8Array,\n\tstderr: Uint8Array,\n\tstdoutBytes: number,\n\tstderrBytes: number,\n\tpreviewBytes: number,\n\ttermination?: \"timeout\" | \"output_budget_exceeded\" | \"spawn_failed\" | \"exit_nonzero\" | \"cancelled\",\n\tcode?: number,\n\tcwd?: string,\n): ProcessExecResultV1 {\n\tconst stdoutPreview = sanitizeProcessTextV1(previewText(stdout.subarray(0, previewBytes)), previewBytes, cwd);\n\tconst stderrPreview = sanitizeProcessTextV1(previewText(stderr.subarray(0, previewBytes)), previewBytes, cwd);\n\tconst errorCode = termination;\n\tconst error =\n\t\terrorCode === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tversion: 1 as const,\n\t\t\t\t\tcode: errorCode,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\terrorCode === \"exit_nonzero\"\n\t\t\t\t\t\t\t? \"Process exited with a non-zero status\"\n\t\t\t\t\t\t\t: errorCode === \"cancelled\"\n\t\t\t\t\t\t\t\t? \"Process execution was cancelled\"\n\t\t\t\t\t\t\t\t: \"Process execution failed\",\n\t\t\t\t};\n\treturn {\n\t\tversion: 1,\n\t\toperationId: request.operationId,\n\t\tstatus,\n\t\tsummary:\n\t\t\tstatus === \"succeeded\"\n\t\t\t\t? \"Process completed successfully\"\n\t\t\t\t: termination === \"cancelled\"\n\t\t\t\t\t? \"Process execution was cancelled\"\n\t\t\t\t\t: termination === \"timeout\"\n\t\t\t\t\t\t? \"Process execution timed out\"\n\t\t\t\t\t\t: termination === \"output_budget_exceeded\"\n\t\t\t\t\t\t\t? \"Process output exceeded the host budget\"\n\t\t\t\t\t\t\t: termination === \"spawn_failed\"\n\t\t\t\t\t\t\t\t? \"Process could not be started\"\n\t\t\t\t\t\t\t\t: \"Process exited with a non-zero status\",\n\t\t...(code === undefined ? {} : { exitCode: code }),\n\t\tstdoutBytes,\n\t\tstderrBytes,\n\t\tstdoutPreview,\n\t\tstderrPreview,\n\t\tstdoutTruncated: stdoutBytes > previewBytes,\n\t\tstderrTruncated: stderrBytes > previewBytes,\n\t\t...(error === undefined ? {} : { error }),\n\t};\n}\n\n/** Node host adapter with shell-free argv execution and bounded output previews. */\nexport function createNodeProcessExecAdapterV1(options: NodeProcessExecAdapterOptionsV1): ProcessExecAdapterV1 {\n\tif (typeof options.cwd !== \"string\" || !isAbsolute(options.cwd)) throw new Error(\"cwd must be an absolute path\");\n\tconst defaultTimeoutMs = positiveBound(\n\t\toptions.defaultTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"defaultTimeoutMs\",\n\t);\n\tconst maxStdoutBytes = positiveBound(\n\t\toptions.maxStdoutBytes,\n\t\tDEFAULT_OUTPUT_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_OUTPUT_BYTES_V1,\n\t\t\"maxStdoutBytes\",\n\t);\n\tconst maxStderrBytes = positiveBound(\n\t\toptions.maxStderrBytes,\n\t\tDEFAULT_OUTPUT_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_OUTPUT_BYTES_V1,\n\t\t\"maxStderrBytes\",\n\t);\n\tconst previewBytes = positiveBound(\n\t\toptions.previewBytes,\n\t\tDEFAULT_PREVIEW_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\t\t\"previewBytes\",\n\t);\n\tconst env = hostEnvironment(options.env);\n\tconst spawnProcess = options.spawn ?? spawn;\n\tconst terminateTree = options.killProcessTree ?? killProcessTree;\n\n\treturn {\n\t\tadapterId: PROCESS_EXEC_HOST_ADAPTER_ID_V1,\n\t\tadapterVersion: PROCESS_EXEC_HOST_ADAPTER_VERSION_V1,\n\t\trun: (request, signal) => {\n\t\t\tconst operationId =\n\t\t\t\ttypeof request.operationId === \"string\" && request.operationId.trim() !== \"\"\n\t\t\t\t\t? request.operationId\n\t\t\t\t\t: \"invalid-process-operation\";\n\t\t\tconst invalid = validateRequest(request);\n\t\t\tif (invalid !== undefined) return Promise.resolve(inputError(operationId, invalid));\n\t\t\tif (signal?.aborted) return Promise.resolve(cancelled(operationId));\n\t\t\tconst timeoutMs = request.timeoutMs ?? defaultTimeoutMs;\n\t\t\treturn new Promise<ProcessExecResultV1>((resolve) => {\n\t\t\t\tlet child: ReturnType<typeof spawn>;\n\t\t\t\ttry {\n\t\t\t\t\tchild = spawnProcess(request.command, [...request.args], {\n\t\t\t\t\t\tcwd: options.cwd,\n\t\t\t\t\t\t...(env === undefined ? {} : { env }),\n\t\t\t\t\t\tshell: false,\n\t\t\t\t\t\twindowsHide: true,\n\t\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\t});\n\t\t\t\t} catch {\n\t\t\t\t\tresolve(\n\t\t\t\t\t\tresult(\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\t\"failed\",\n\t\t\t\t\t\t\tnew Uint8Array(),\n\t\t\t\t\t\t\tnew Uint8Array(),\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tpreviewBytes,\n\t\t\t\t\t\t\t\"spawn_failed\",\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\toptions.cwd,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet stdoutBytes = 0;\n\t\t\t\tlet stderrBytes = 0;\n\t\t\t\tconst stdoutPreview = new Uint8Array(previewBytes);\n\t\t\t\tconst stderrPreview = new Uint8Array(previewBytes);\n\t\t\t\tlet stdoutPreviewLength = 0;\n\t\t\t\tlet stderrPreviewLength = 0;\n\t\t\t\tlet termination:\n\t\t\t\t\t| \"timeout\"\n\t\t\t\t\t| \"output_budget_exceeded\"\n\t\t\t\t\t| \"spawn_failed\"\n\t\t\t\t\t| \"exit_nonzero\"\n\t\t\t\t\t| \"cancelled\"\n\t\t\t\t\t| undefined;\n\t\t\t\tlet settled = false;\n\t\t\t\tlet exited = false;\n\t\t\t\tlet terminationRequested = false;\n\t\t\t\tlet forceKillTimer: ReturnType<typeof setTimeout> | undefined;\n\t\t\t\tlet hardFinishTimer: ReturnType<typeof setTimeout> | undefined;\n\t\t\t\tconst append = (target: Uint8Array, length: number, chunk: Uint8Array): number => {\n\t\t\t\t\tconst copy = Math.min(chunk.byteLength, target.byteLength - length);\n\t\t\t\t\ttarget.set(chunk.subarray(0, copy), length);\n\t\t\t\t\treturn length + copy;\n\t\t\t\t};\n\t\t\t\tconst forceTerminate = (): void => {\n\t\t\t\t\tif (exited) return;\n\t\t\t\t\tif (typeof child.pid === \"number\" && child.pid > 0) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tterminateTree(child.pid);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// The host cleanup boundary is best-effort; close/error still settles the operation.\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!child.killed) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// The close/error event remains authoritative.\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tconst armForceTermination = (): void => {\n\t\t\t\t\tif (forceKillTimer !== undefined) return;\n\t\t\t\t\tforceKillTimer = setTimeout(() => {\n\t\t\t\t\t\tforceTerminate();\n\t\t\t\t\t\thardFinishTimer = setTimeout(() => finalize(null), 500);\n\t\t\t\t\t}, 2000);\n\t\t\t\t};\n\t\t\t\tconst terminate = (reason: \"timeout\" | \"output_budget_exceeded\" | \"spawn_failed\" | \"cancelled\"): void => {\n\t\t\t\t\tif (termination === undefined) termination = reason;\n\t\t\t\t\tif (!terminationRequested) {\n\t\t\t\t\t\tterminationRequested = true;\n\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// The force cleanup timer still runs.\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tarmForceTermination();\n\t\t\t\t};\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tterminate(\"cancelled\");\n\t\t\t\t};\n\t\t\t\tconst finalize = (code: number | null): void => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\texited = true;\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tif (forceKillTimer !== undefined) clearTimeout(forceKillTimer);\n\t\t\t\t\tif (hardFinishTimer !== undefined) clearTimeout(hardFinishTimer);\n\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tif (signal?.aborted && termination === undefined) termination = \"cancelled\";\n\t\t\t\t\tif (termination === undefined && code !== 0) termination = \"exit_nonzero\";\n\t\t\t\t\tconst status =\n\t\t\t\t\t\ttermination === undefined ? \"succeeded\" : termination === \"cancelled\" ? \"cancelled\" : \"failed\";\n\t\t\t\t\tresolve(\n\t\t\t\t\t\tresult(\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t\tstdoutPreview.subarray(0, stdoutPreviewLength),\n\t\t\t\t\t\t\tstderrPreview.subarray(0, stderrPreviewLength),\n\t\t\t\t\t\t\tstdoutBytes,\n\t\t\t\t\t\t\tstderrBytes,\n\t\t\t\t\t\t\tpreviewBytes,\n\t\t\t\t\t\t\ttermination,\n\t\t\t\t\t\t\tcode ?? undefined,\n\t\t\t\t\t\t\toptions.cwd,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t\tconst timeout = setTimeout(() => terminate(\"timeout\"), timeoutMs);\n\t\t\t\tif (signal !== undefined) signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer | Uint8Array) => {\n\t\t\t\t\tconst bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);\n\t\t\t\t\tstdoutBytes += bytes.byteLength;\n\t\t\t\t\tstdoutPreviewLength = append(stdoutPreview, stdoutPreviewLength, bytes);\n\t\t\t\t\tif (stdoutBytes > maxStdoutBytes) terminate(\"output_budget_exceeded\");\n\t\t\t\t});\n\t\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer | Uint8Array) => {\n\t\t\t\t\tconst bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);\n\t\t\t\t\tstderrBytes += bytes.byteLength;\n\t\t\t\t\tstderrPreviewLength = append(stderrPreview, stderrPreviewLength, bytes);\n\t\t\t\t\tif (stderrBytes > maxStderrBytes) terminate(\"output_budget_exceeded\");\n\t\t\t\t});\n\t\t\t\tchild.once(\"error\", () => {\n\t\t\t\t\tterminate(\"spawn_failed\");\n\t\t\t\t});\n\t\t\t\tchild.once(\"close\", (code) => {\n\t\t\t\t\texited = true;\n\t\t\t\t\tfinalize(code);\n\t\t\t\t});\n\t\t\t});\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"node-adapter.d.ts","sourceRoot":"","sources":["../src/node-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG3C,OAAO,EAGN,KAAK,oBAAoB,EAGzB,MAAM,YAAY,CAAC;AAKpB,eAAO,MAAM,gCAAgC,QAAc,CAAC;AAE5D,eAAO,MAAM,iCAAiC,OAAO,CAAC;AAItD,eAAO,MAAM,sCAAsC,MAAM,CAAC;AAE1D,MAAM,WAAW,+BAA+B;IAC/C,iEAAiE;IACjE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,4DAA4D;IAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CAC9B;AAkBD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAc7G;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,MAAM,EACb,YAAY,SAAoC,EAChD,GAAG,CAAC,EAAE,MAAM,GACV,MAAM,CAkBR;AAgMD,oFAAoF;AACpF,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,+BAA+B,GAAG,oBAAoB,CAiL7G","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { isAbsolute } from \"node:path\";\nimport { killProcessTree, sanitizeBinaryOutput } from \"./shell-utils.ts\";\nimport {\n\tPROCESS_EXEC_HOST_ADAPTER_ID_V1,\n\tPROCESS_EXEC_HOST_ADAPTER_VERSION_V1,\n\ttype ProcessExecAdapterV1,\n\ttype ProcessExecRequestV1,\n\ttype ProcessExecResultV1,\n} from \"./types.ts\";\n\nconst DEFAULT_TIMEOUT_MS_V1 = 30_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_OUTPUT_BYTES_V1 = 64 * 1024;\nexport const PROCESS_EXEC_MAX_OUTPUT_BYTES_V1 = 1024 * 1024;\nconst DEFAULT_PREVIEW_BYTES_V1 = 4096;\nexport const PROCESS_EXEC_MAX_PREVIEW_BYTES_V1 = 8192;\nconst MAX_ARGS_V1 = 256;\nconst MAX_COMMAND_CHARS_V1 = 512;\nconst MAX_ARG_CHARS_V1 = 4096;\nexport const PROCESS_EXEC_MAX_OPERATION_ID_CHARS_V1 = 256;\n\nexport interface NodeProcessExecAdapterOptionsV1 {\n\t/** Host-owned working directory; requests cannot override it. */\n\treadonly cwd: string;\n\treadonly env?: Readonly<Record<string, string>>;\n\treadonly defaultTimeoutMs?: number;\n\treadonly maxStdoutBytes?: number;\n\treadonly maxStderrBytes?: number;\n\treadonly previewBytes?: number;\n\t/** Test seam for the host-owned process-tree terminator. */\n\treadonly killProcessTree?: (pid: number) => void;\n\t/** Deterministic host seam; production defaults to Node's shell-free spawn. */\n\treadonly spawn?: typeof spawn;\n}\n\nconst SAFE_ENVIRONMENT_KEYS_V1 = new Set(\n\t[\"PATH\", \"PATHEXT\", \"SystemRoot\", \"SYSTEMROOT\", \"WINDIR\", \"TEMP\", \"TMP\", \"TMPDIR\", \"LANG\", \"LC_ALL\"].map((key) =>\n\t\tkey.toLowerCase(),\n\t),\n);\n\n/** Splits a preview budget into head/tail segments (75% head, rest tail; head wins on tiny budgets). */\nfunction splitPreviewBudgetV1(budget: number): { head: number; tail: number } {\n\tconst head = Math.ceil((budget * 3) / 4);\n\treturn { head, tail: Math.max(0, budget - head) };\n}\n\nfunction omissionMarkerV1(omitted: number, unit: \"bytes\" | \"chars\"): string {\n\treturn `\\n... [${omitted} ${unit} omitted] ...\\n`;\n}\n\n/**\n * Builds a bounded preview from the retained capture. `captured` holds the\n * complete output when `totalBytes <= previewBytes`; otherwise it holds the\n * first `head` bytes followed by the last `tail` bytes of the stream, and the\n * two segments are joined with an omission marker. The marker rides on top of\n * the segment budgets but the assembled preview never exceeds\n * `PROCESS_EXEC_MAX_PREVIEW_BYTES_V1`.\n */\nexport function buildHeadTailPreviewV1(captured: Uint8Array, previewBytes: number, totalBytes: number): string {\n\tif (totalBytes <= previewBytes) return previewText(captured);\n\tconst budget = splitPreviewBudgetV1(previewBytes);\n\tconst headPart = captured.subarray(0, Math.min(budget.head, captured.byteLength));\n\tlet tailBytes = Math.min(budget.tail, Math.max(0, captured.byteLength - headPart.byteLength));\n\tlet marker = omissionMarkerV1(Math.max(0, totalBytes - headPart.byteLength - tailBytes), \"bytes\");\n\twhile (headPart.byteLength + tailBytes + marker.length > PROCESS_EXEC_MAX_PREVIEW_BYTES_V1 && tailBytes > 0) {\n\t\ttailBytes = Math.max(\n\t\t\t0,\n\t\t\tMath.min(tailBytes, PROCESS_EXEC_MAX_PREVIEW_BYTES_V1 - headPart.byteLength - marker.length),\n\t\t);\n\t\tmarker = omissionMarkerV1(Math.max(0, totalBytes - headPart.byteLength - tailBytes), \"bytes\");\n\t}\n\treturn previewText(headPart) + marker + previewText(captured.subarray(captured.byteLength - tailBytes));\n}\n\n/** Redacts credentials and host paths before a preview can reach the model. */\nexport function sanitizeProcessTextV1(\n\tvalue: string,\n\tmaximumChars = PROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\tcwd?: string,\n): string {\n\tlet text = sanitizeBinaryOutput(value);\n\tif (cwd !== undefined && cwd !== \"\") text = text.replaceAll(cwd, \"[redacted-path]\");\n\ttext = text\n\t\t.replace(\n\t\t\t/((?:api[-_ ]?key|access[-_ ]?token|auth(?:orization)?|bearer|password|passwd|secret|token)\\s*[:=]\\s*)([^\\s,;]+)/giu,\n\t\t\t\"$1[redacted-secret]\",\n\t\t)\n\t\t.replace(/(?:[A-Za-z]:[\\\\/]|\\\\\\\\|\\/(?:home|Users|private|tmp|var|workspace)\\/)[^\\s\"'<>]*/gu, \"[redacted-path]\");\n\tif (text.length <= maximumChars) return text;\n\tconst head = Math.ceil((maximumChars * 3) / 4);\n\tlet tail = maximumChars - head;\n\tlet marker = omissionMarkerV1(text.length - head - tail, \"chars\");\n\twhile (head + tail + marker.length > maximumChars && tail > 0) {\n\t\ttail = Math.max(0, Math.min(tail, maximumChars - head - marker.length));\n\t\tmarker = omissionMarkerV1(text.length - head - tail, \"chars\");\n\t}\n\treturn text.slice(0, head) + marker + (tail > 0 ? text.slice(text.length - tail) : \"\");\n}\n\nfunction hostEnvironment(explicit: Readonly<Record<string, string>> | undefined): NodeJS.ProcessEnv {\n\tconst inherited: NodeJS.ProcessEnv = {};\n\tfor (const [key, value] of Object.entries(process.env)) {\n\t\tif (value !== undefined && SAFE_ENVIRONMENT_KEYS_V1.has(key.toLowerCase())) inherited[key] = value;\n\t}\n\treturn { ...inherited, ...(explicit ?? {}) };\n}\n\nfunction positiveBound(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result < 1 || result > maximum)\n\t\tthrow new Error(`${label} must be a positive integer at most ${maximum}`);\n\treturn result;\n}\n\nfunction inputError(operationId: string, message: string): ProcessExecResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: \"Process request was invalid\",\n\t\tstdoutBytes: 0,\n\t\tstderrBytes: 0,\n\t\tstdoutPreview: \"\",\n\t\tstderrPreview: \"\",\n\t\tstdoutTruncated: false,\n\t\tstderrTruncated: false,\n\t\terror: { version: 1, code: \"invalid_input\", message },\n\t};\n}\n\nfunction cancelled(operationId: string): ProcessExecResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"cancelled\",\n\t\tsummary: \"Process execution was cancelled\",\n\t\tstdoutBytes: 0,\n\t\tstderrBytes: 0,\n\t\tstdoutPreview: \"\",\n\t\tstderrPreview: \"\",\n\t\tstdoutTruncated: false,\n\t\tstderrTruncated: false,\n\t\terror: { version: 1, code: \"cancelled\", message: \"Process execution was cancelled\" },\n\t};\n}\n\nfunction validateRequest(request: ProcessExecRequestV1): string | undefined {\n\tif (request.version !== 1) return \"version must be 1\";\n\tif (\n\t\ttypeof request.operationId !== \"string\" ||\n\t\trequest.operationId.trim() === \"\" ||\n\t\trequest.operationId.length > PROCESS_EXEC_MAX_OPERATION_ID_CHARS_V1\n\t)\n\t\treturn \"operationId is invalid\";\n\tif (\n\t\ttypeof request.command !== \"string\" ||\n\t\trequest.command.trim() === \"\" ||\n\t\trequest.command.length > MAX_COMMAND_CHARS_V1 ||\n\t\t/[\\u0000\\r\\n]/u.test(request.command)\n\t)\n\t\treturn \"command is invalid\";\n\tif (!Array.isArray(request.args) || request.args.length > MAX_ARGS_V1) return \"args are invalid\";\n\tif (\n\t\trequest.args.some((arg) => typeof arg !== \"string\" || arg.length > MAX_ARG_CHARS_V1 || /[\\u0000\\r\\n]/u.test(arg))\n\t)\n\t\treturn \"args are invalid\";\n\tif (\n\t\trequest.timeoutMs !== undefined &&\n\t\t(!Number.isSafeInteger(request.timeoutMs) || request.timeoutMs < 1 || request.timeoutMs > MAX_TIMEOUT_MS_V1)\n\t)\n\t\treturn `timeoutMs must be a positive integer at most ${MAX_TIMEOUT_MS_V1}`;\n\treturn undefined;\n}\n\nfunction previewText(bytes: Uint8Array): string {\n\treturn new TextDecoder().decode(bytes);\n}\n\ninterface PreviewCaptureV1 {\n\treadonly head: Uint8Array;\n\treadonly tail: Uint8Array;\n\theadLength: number;\n\ttailLength: number;\n}\n\n/** Retains the first head-budget and last tail-budget bytes of a stream for head+tail previews. */\nfunction createPreviewCaptureV1(previewBytes: number): PreviewCaptureV1 {\n\tconst budget = splitPreviewBudgetV1(previewBytes);\n\treturn { head: new Uint8Array(budget.head), tail: new Uint8Array(budget.tail), headLength: 0, tailLength: 0 };\n}\n\nfunction capturePreviewChunkV1(capture: PreviewCaptureV1, chunk: Uint8Array): void {\n\tconst headCopy = Math.min(chunk.byteLength, capture.head.byteLength - capture.headLength);\n\tcapture.head.set(chunk.subarray(0, headCopy), capture.headLength);\n\tcapture.headLength += headCopy;\n\tconst tailSize = capture.tail.byteLength;\n\tif (tailSize === 0) return;\n\tif (chunk.byteLength >= tailSize) {\n\t\tcapture.tail.set(chunk.subarray(chunk.byteLength - tailSize));\n\t\tcapture.tailLength = tailSize;\n\t\treturn;\n\t}\n\tcapture.tail.copyWithin(0, chunk.byteLength);\n\tcapture.tail.set(chunk, tailSize - chunk.byteLength);\n\tcapture.tailLength = Math.min(tailSize, capture.tailLength + chunk.byteLength);\n}\n\n/** Materializes the retained bytes: the full output when it fit the budget, else head followed by tail. */\nfunction previewCaptureBytesV1(capture: PreviewCaptureV1, totalBytes: number): Uint8Array {\n\tconst capacity = capture.head.byteLength + capture.tail.byteLength;\n\tif (totalBytes <= capture.head.byteLength) return capture.head.subarray(0, totalBytes);\n\tif (totalBytes <= capacity) {\n\t\tconst tailFrom = totalBytes - capture.head.byteLength;\n\t\tconst captured = new Uint8Array(totalBytes);\n\t\tcaptured.set(capture.head);\n\t\tcaptured.set(capture.tail.subarray(capture.tailLength - tailFrom, capture.tailLength), capture.headLength);\n\t\treturn captured;\n\t}\n\tconst captured = new Uint8Array(capacity);\n\tcaptured.set(capture.head.subarray(0, capture.headLength));\n\tcaptured.set(capture.tail.subarray(0, capture.tailLength), capture.headLength);\n\treturn captured;\n}\n\nfunction result(\n\trequest: ProcessExecRequestV1,\n\tstatus: ProcessExecResultV1[\"status\"],\n\tstdout: Uint8Array,\n\tstderr: Uint8Array,\n\tstdoutBytes: number,\n\tstderrBytes: number,\n\tpreviewBytes: number,\n\ttermination?: \"timeout\" | \"output_budget_exceeded\" | \"spawn_failed\" | \"exit_nonzero\" | \"cancelled\",\n\tcode?: number,\n\tcwd?: string,\n): ProcessExecResultV1 {\n\t// The byte-level head/tail split is authoritative; sanitize only redacts and\n\t// acts as the absolute-size circuit breaker at the contract cap.\n\tconst stdoutPreview = sanitizeProcessTextV1(\n\t\tbuildHeadTailPreviewV1(stdout, previewBytes, stdoutBytes),\n\t\tPROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\t\tcwd,\n\t);\n\tconst stderrPreview = sanitizeProcessTextV1(\n\t\tbuildHeadTailPreviewV1(stderr, previewBytes, stderrBytes),\n\t\tPROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\t\tcwd,\n\t);\n\tconst errorCode = termination;\n\tconst error =\n\t\terrorCode === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tversion: 1 as const,\n\t\t\t\t\tcode: errorCode,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\terrorCode === \"exit_nonzero\"\n\t\t\t\t\t\t\t? \"Process exited with a non-zero status\"\n\t\t\t\t\t\t\t: errorCode === \"cancelled\"\n\t\t\t\t\t\t\t\t? \"Process execution was cancelled\"\n\t\t\t\t\t\t\t\t: \"Process execution failed\",\n\t\t\t\t};\n\treturn {\n\t\tversion: 1,\n\t\toperationId: request.operationId,\n\t\tstatus,\n\t\tsummary:\n\t\t\tstatus === \"succeeded\"\n\t\t\t\t? \"Process completed successfully\"\n\t\t\t\t: termination === \"cancelled\"\n\t\t\t\t\t? \"Process execution was cancelled\"\n\t\t\t\t\t: termination === \"timeout\"\n\t\t\t\t\t\t? \"Process execution timed out\"\n\t\t\t\t\t\t: termination === \"output_budget_exceeded\"\n\t\t\t\t\t\t\t? \"Process output exceeded the host budget\"\n\t\t\t\t\t\t\t: termination === \"spawn_failed\"\n\t\t\t\t\t\t\t\t? \"Process could not be started\"\n\t\t\t\t\t\t\t\t: \"Process exited with a non-zero status\",\n\t\t...(code === undefined ? {} : { exitCode: code }),\n\t\tstdoutBytes,\n\t\tstderrBytes,\n\t\tstdoutPreview,\n\t\tstderrPreview,\n\t\tstdoutTruncated: stdoutBytes > previewBytes,\n\t\tstderrTruncated: stderrBytes > previewBytes,\n\t\t...(error === undefined ? {} : { error }),\n\t};\n}\n\n/** Node host adapter with shell-free argv execution and bounded output previews. */\nexport function createNodeProcessExecAdapterV1(options: NodeProcessExecAdapterOptionsV1): ProcessExecAdapterV1 {\n\tif (typeof options.cwd !== \"string\" || !isAbsolute(options.cwd)) throw new Error(\"cwd must be an absolute path\");\n\tconst defaultTimeoutMs = positiveBound(\n\t\toptions.defaultTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"defaultTimeoutMs\",\n\t);\n\tconst maxStdoutBytes = positiveBound(\n\t\toptions.maxStdoutBytes,\n\t\tDEFAULT_OUTPUT_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_OUTPUT_BYTES_V1,\n\t\t\"maxStdoutBytes\",\n\t);\n\tconst maxStderrBytes = positiveBound(\n\t\toptions.maxStderrBytes,\n\t\tDEFAULT_OUTPUT_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_OUTPUT_BYTES_V1,\n\t\t\"maxStderrBytes\",\n\t);\n\tconst previewBytes = positiveBound(\n\t\toptions.previewBytes,\n\t\tDEFAULT_PREVIEW_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\t\t\"previewBytes\",\n\t);\n\tconst env = hostEnvironment(options.env);\n\tconst spawnProcess = options.spawn ?? spawn;\n\tconst terminateTree = options.killProcessTree ?? killProcessTree;\n\n\treturn {\n\t\tadapterId: PROCESS_EXEC_HOST_ADAPTER_ID_V1,\n\t\tadapterVersion: PROCESS_EXEC_HOST_ADAPTER_VERSION_V1,\n\t\trun: (request, signal) => {\n\t\t\tconst operationId =\n\t\t\t\ttypeof request.operationId === \"string\" && request.operationId.trim() !== \"\"\n\t\t\t\t\t? request.operationId\n\t\t\t\t\t: \"invalid-process-operation\";\n\t\t\tconst invalid = validateRequest(request);\n\t\t\tif (invalid !== undefined) return Promise.resolve(inputError(operationId, invalid));\n\t\t\tif (signal?.aborted) return Promise.resolve(cancelled(operationId));\n\t\t\tconst timeoutMs = request.timeoutMs ?? defaultTimeoutMs;\n\t\t\treturn new Promise<ProcessExecResultV1>((resolve) => {\n\t\t\t\tlet child: ReturnType<typeof spawn>;\n\t\t\t\ttry {\n\t\t\t\t\tchild = spawnProcess(request.command, [...request.args], {\n\t\t\t\t\t\tcwd: options.cwd,\n\t\t\t\t\t\t...(env === undefined ? {} : { env }),\n\t\t\t\t\t\tshell: false,\n\t\t\t\t\t\twindowsHide: true,\n\t\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\t});\n\t\t\t\t} catch {\n\t\t\t\t\tresolve(\n\t\t\t\t\t\tresult(\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\t\"failed\",\n\t\t\t\t\t\t\tnew Uint8Array(),\n\t\t\t\t\t\t\tnew Uint8Array(),\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tpreviewBytes,\n\t\t\t\t\t\t\t\"spawn_failed\",\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\toptions.cwd,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet stdoutBytes = 0;\n\t\t\t\tlet stderrBytes = 0;\n\t\t\t\tconst stdoutCapture = createPreviewCaptureV1(previewBytes);\n\t\t\t\tconst stderrCapture = createPreviewCaptureV1(previewBytes);\n\t\t\t\tlet termination:\n\t\t\t\t\t| \"timeout\"\n\t\t\t\t\t| \"output_budget_exceeded\"\n\t\t\t\t\t| \"spawn_failed\"\n\t\t\t\t\t| \"exit_nonzero\"\n\t\t\t\t\t| \"cancelled\"\n\t\t\t\t\t| undefined;\n\t\t\t\tlet settled = false;\n\t\t\t\tlet exited = false;\n\t\t\t\tlet terminationRequested = false;\n\t\t\t\tlet forceKillTimer: ReturnType<typeof setTimeout> | undefined;\n\t\t\t\tlet hardFinishTimer: ReturnType<typeof setTimeout> | undefined;\n\t\t\t\tconst forceTerminate = (): void => {\n\t\t\t\t\tif (exited) return;\n\t\t\t\t\tif (typeof child.pid === \"number\" && child.pid > 0) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tterminateTree(child.pid);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// The host cleanup boundary is best-effort; close/error still settles the operation.\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!child.killed) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// The close/error event remains authoritative.\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tconst armForceTermination = (): void => {\n\t\t\t\t\tif (forceKillTimer !== undefined) return;\n\t\t\t\t\tforceKillTimer = setTimeout(() => {\n\t\t\t\t\t\tforceTerminate();\n\t\t\t\t\t\thardFinishTimer = setTimeout(() => finalize(null), 500);\n\t\t\t\t\t}, 2000);\n\t\t\t\t};\n\t\t\t\tconst terminate = (reason: \"timeout\" | \"output_budget_exceeded\" | \"spawn_failed\" | \"cancelled\"): void => {\n\t\t\t\t\tif (termination === undefined) termination = reason;\n\t\t\t\t\tif (!terminationRequested) {\n\t\t\t\t\t\tterminationRequested = true;\n\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// The force cleanup timer still runs.\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tarmForceTermination();\n\t\t\t\t};\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tterminate(\"cancelled\");\n\t\t\t\t};\n\t\t\t\tconst finalize = (code: number | null): void => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\texited = true;\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tif (forceKillTimer !== undefined) clearTimeout(forceKillTimer);\n\t\t\t\t\tif (hardFinishTimer !== undefined) clearTimeout(hardFinishTimer);\n\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tif (signal?.aborted && termination === undefined) termination = \"cancelled\";\n\t\t\t\t\tif (termination === undefined && code !== 0) termination = \"exit_nonzero\";\n\t\t\t\t\tconst status =\n\t\t\t\t\t\ttermination === undefined ? \"succeeded\" : termination === \"cancelled\" ? \"cancelled\" : \"failed\";\n\t\t\t\t\tresolve(\n\t\t\t\t\t\tresult(\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t\tpreviewCaptureBytesV1(stdoutCapture, stdoutBytes),\n\t\t\t\t\t\t\tpreviewCaptureBytesV1(stderrCapture, stderrBytes),\n\t\t\t\t\t\t\tstdoutBytes,\n\t\t\t\t\t\t\tstderrBytes,\n\t\t\t\t\t\t\tpreviewBytes,\n\t\t\t\t\t\t\ttermination,\n\t\t\t\t\t\t\tcode ?? undefined,\n\t\t\t\t\t\t\toptions.cwd,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t\tconst timeout = setTimeout(() => terminate(\"timeout\"), timeoutMs);\n\t\t\t\tif (signal !== undefined) signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer | Uint8Array) => {\n\t\t\t\t\tconst bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);\n\t\t\t\t\tstdoutBytes += bytes.byteLength;\n\t\t\t\t\tcapturePreviewChunkV1(stdoutCapture, bytes);\n\t\t\t\t\tif (stdoutBytes > maxStdoutBytes) terminate(\"output_budget_exceeded\");\n\t\t\t\t});\n\t\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer | Uint8Array) => {\n\t\t\t\t\tconst bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);\n\t\t\t\t\tstderrBytes += bytes.byteLength;\n\t\t\t\t\tcapturePreviewChunkV1(stderrCapture, bytes);\n\t\t\t\t\tif (stderrBytes > maxStderrBytes) terminate(\"output_budget_exceeded\");\n\t\t\t\t});\n\t\t\t\tchild.once(\"error\", () => {\n\t\t\t\t\tterminate(\"spawn_failed\");\n\t\t\t\t});\n\t\t\t\tchild.once(\"close\", (code) => {\n\t\t\t\t\texited = true;\n\t\t\t\t\tfinalize(code);\n\t\t\t\t});\n\t\t\t});\n\t\t},\n\t};\n}\n"]}
|
package/dist/node-adapter.js
CHANGED
|
@@ -13,6 +13,35 @@ const MAX_COMMAND_CHARS_V1 = 512;
|
|
|
13
13
|
const MAX_ARG_CHARS_V1 = 4096;
|
|
14
14
|
export const PROCESS_EXEC_MAX_OPERATION_ID_CHARS_V1 = 256;
|
|
15
15
|
const SAFE_ENVIRONMENT_KEYS_V1 = new Set(["PATH", "PATHEXT", "SystemRoot", "SYSTEMROOT", "WINDIR", "TEMP", "TMP", "TMPDIR", "LANG", "LC_ALL"].map((key) => key.toLowerCase()));
|
|
16
|
+
/** Splits a preview budget into head/tail segments (75% head, rest tail; head wins on tiny budgets). */
|
|
17
|
+
function splitPreviewBudgetV1(budget) {
|
|
18
|
+
const head = Math.ceil((budget * 3) / 4);
|
|
19
|
+
return { head, tail: Math.max(0, budget - head) };
|
|
20
|
+
}
|
|
21
|
+
function omissionMarkerV1(omitted, unit) {
|
|
22
|
+
return `\n... [${omitted} ${unit} omitted] ...\n`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Builds a bounded preview from the retained capture. `captured` holds the
|
|
26
|
+
* complete output when `totalBytes <= previewBytes`; otherwise it holds the
|
|
27
|
+
* first `head` bytes followed by the last `tail` bytes of the stream, and the
|
|
28
|
+
* two segments are joined with an omission marker. The marker rides on top of
|
|
29
|
+
* the segment budgets but the assembled preview never exceeds
|
|
30
|
+
* `PROCESS_EXEC_MAX_PREVIEW_BYTES_V1`.
|
|
31
|
+
*/
|
|
32
|
+
export function buildHeadTailPreviewV1(captured, previewBytes, totalBytes) {
|
|
33
|
+
if (totalBytes <= previewBytes)
|
|
34
|
+
return previewText(captured);
|
|
35
|
+
const budget = splitPreviewBudgetV1(previewBytes);
|
|
36
|
+
const headPart = captured.subarray(0, Math.min(budget.head, captured.byteLength));
|
|
37
|
+
let tailBytes = Math.min(budget.tail, Math.max(0, captured.byteLength - headPart.byteLength));
|
|
38
|
+
let marker = omissionMarkerV1(Math.max(0, totalBytes - headPart.byteLength - tailBytes), "bytes");
|
|
39
|
+
while (headPart.byteLength + tailBytes + marker.length > PROCESS_EXEC_MAX_PREVIEW_BYTES_V1 && tailBytes > 0) {
|
|
40
|
+
tailBytes = Math.max(0, Math.min(tailBytes, PROCESS_EXEC_MAX_PREVIEW_BYTES_V1 - headPart.byteLength - marker.length));
|
|
41
|
+
marker = omissionMarkerV1(Math.max(0, totalBytes - headPart.byteLength - tailBytes), "bytes");
|
|
42
|
+
}
|
|
43
|
+
return previewText(headPart) + marker + previewText(captured.subarray(captured.byteLength - tailBytes));
|
|
44
|
+
}
|
|
16
45
|
/** Redacts credentials and host paths before a preview can reach the model. */
|
|
17
46
|
export function sanitizeProcessTextV1(value, maximumChars = PROCESS_EXEC_MAX_PREVIEW_BYTES_V1, cwd) {
|
|
18
47
|
let text = sanitizeBinaryOutput(value);
|
|
@@ -21,7 +50,16 @@ export function sanitizeProcessTextV1(value, maximumChars = PROCESS_EXEC_MAX_PRE
|
|
|
21
50
|
text = text
|
|
22
51
|
.replace(/((?:api[-_ ]?key|access[-_ ]?token|auth(?:orization)?|bearer|password|passwd|secret|token)\s*[:=]\s*)([^\s,;]+)/giu, "$1[redacted-secret]")
|
|
23
52
|
.replace(/(?:[A-Za-z]:[\\/]|\\\\|\/(?:home|Users|private|tmp|var|workspace)\/)[^\s"'<>]*/gu, "[redacted-path]");
|
|
24
|
-
|
|
53
|
+
if (text.length <= maximumChars)
|
|
54
|
+
return text;
|
|
55
|
+
const head = Math.ceil((maximumChars * 3) / 4);
|
|
56
|
+
let tail = maximumChars - head;
|
|
57
|
+
let marker = omissionMarkerV1(text.length - head - tail, "chars");
|
|
58
|
+
while (head + tail + marker.length > maximumChars && tail > 0) {
|
|
59
|
+
tail = Math.max(0, Math.min(tail, maximumChars - head - marker.length));
|
|
60
|
+
marker = omissionMarkerV1(text.length - head - tail, "chars");
|
|
61
|
+
}
|
|
62
|
+
return text.slice(0, head) + marker + (tail > 0 ? text.slice(text.length - tail) : "");
|
|
25
63
|
}
|
|
26
64
|
function hostEnvironment(explicit) {
|
|
27
65
|
const inherited = {};
|
|
@@ -91,9 +129,49 @@ function validateRequest(request) {
|
|
|
91
129
|
function previewText(bytes) {
|
|
92
130
|
return new TextDecoder().decode(bytes);
|
|
93
131
|
}
|
|
132
|
+
/** Retains the first head-budget and last tail-budget bytes of a stream for head+tail previews. */
|
|
133
|
+
function createPreviewCaptureV1(previewBytes) {
|
|
134
|
+
const budget = splitPreviewBudgetV1(previewBytes);
|
|
135
|
+
return { head: new Uint8Array(budget.head), tail: new Uint8Array(budget.tail), headLength: 0, tailLength: 0 };
|
|
136
|
+
}
|
|
137
|
+
function capturePreviewChunkV1(capture, chunk) {
|
|
138
|
+
const headCopy = Math.min(chunk.byteLength, capture.head.byteLength - capture.headLength);
|
|
139
|
+
capture.head.set(chunk.subarray(0, headCopy), capture.headLength);
|
|
140
|
+
capture.headLength += headCopy;
|
|
141
|
+
const tailSize = capture.tail.byteLength;
|
|
142
|
+
if (tailSize === 0)
|
|
143
|
+
return;
|
|
144
|
+
if (chunk.byteLength >= tailSize) {
|
|
145
|
+
capture.tail.set(chunk.subarray(chunk.byteLength - tailSize));
|
|
146
|
+
capture.tailLength = tailSize;
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
capture.tail.copyWithin(0, chunk.byteLength);
|
|
150
|
+
capture.tail.set(chunk, tailSize - chunk.byteLength);
|
|
151
|
+
capture.tailLength = Math.min(tailSize, capture.tailLength + chunk.byteLength);
|
|
152
|
+
}
|
|
153
|
+
/** Materializes the retained bytes: the full output when it fit the budget, else head followed by tail. */
|
|
154
|
+
function previewCaptureBytesV1(capture, totalBytes) {
|
|
155
|
+
const capacity = capture.head.byteLength + capture.tail.byteLength;
|
|
156
|
+
if (totalBytes <= capture.head.byteLength)
|
|
157
|
+
return capture.head.subarray(0, totalBytes);
|
|
158
|
+
if (totalBytes <= capacity) {
|
|
159
|
+
const tailFrom = totalBytes - capture.head.byteLength;
|
|
160
|
+
const captured = new Uint8Array(totalBytes);
|
|
161
|
+
captured.set(capture.head);
|
|
162
|
+
captured.set(capture.tail.subarray(capture.tailLength - tailFrom, capture.tailLength), capture.headLength);
|
|
163
|
+
return captured;
|
|
164
|
+
}
|
|
165
|
+
const captured = new Uint8Array(capacity);
|
|
166
|
+
captured.set(capture.head.subarray(0, capture.headLength));
|
|
167
|
+
captured.set(capture.tail.subarray(0, capture.tailLength), capture.headLength);
|
|
168
|
+
return captured;
|
|
169
|
+
}
|
|
94
170
|
function result(request, status, stdout, stderr, stdoutBytes, stderrBytes, previewBytes, termination, code, cwd) {
|
|
95
|
-
|
|
96
|
-
|
|
171
|
+
// The byte-level head/tail split is authoritative; sanitize only redacts and
|
|
172
|
+
// acts as the absolute-size circuit breaker at the contract cap.
|
|
173
|
+
const stdoutPreview = sanitizeProcessTextV1(buildHeadTailPreviewV1(stdout, previewBytes, stdoutBytes), PROCESS_EXEC_MAX_PREVIEW_BYTES_V1, cwd);
|
|
174
|
+
const stderrPreview = sanitizeProcessTextV1(buildHeadTailPreviewV1(stderr, previewBytes, stderrBytes), PROCESS_EXEC_MAX_PREVIEW_BYTES_V1, cwd);
|
|
97
175
|
const errorCode = termination;
|
|
98
176
|
const error = errorCode === undefined
|
|
99
177
|
? undefined
|
|
@@ -173,21 +251,14 @@ export function createNodeProcessExecAdapterV1(options) {
|
|
|
173
251
|
}
|
|
174
252
|
let stdoutBytes = 0;
|
|
175
253
|
let stderrBytes = 0;
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
let stdoutPreviewLength = 0;
|
|
179
|
-
let stderrPreviewLength = 0;
|
|
254
|
+
const stdoutCapture = createPreviewCaptureV1(previewBytes);
|
|
255
|
+
const stderrCapture = createPreviewCaptureV1(previewBytes);
|
|
180
256
|
let termination;
|
|
181
257
|
let settled = false;
|
|
182
258
|
let exited = false;
|
|
183
259
|
let terminationRequested = false;
|
|
184
260
|
let forceKillTimer;
|
|
185
261
|
let hardFinishTimer;
|
|
186
|
-
const append = (target, length, chunk) => {
|
|
187
|
-
const copy = Math.min(chunk.byteLength, target.byteLength - length);
|
|
188
|
-
target.set(chunk.subarray(0, copy), length);
|
|
189
|
-
return length + copy;
|
|
190
|
-
};
|
|
191
262
|
const forceTerminate = () => {
|
|
192
263
|
if (exited)
|
|
193
264
|
return;
|
|
@@ -251,7 +322,7 @@ export function createNodeProcessExecAdapterV1(options) {
|
|
|
251
322
|
if (termination === undefined && code !== 0)
|
|
252
323
|
termination = "exit_nonzero";
|
|
253
324
|
const status = termination === undefined ? "succeeded" : termination === "cancelled" ? "cancelled" : "failed";
|
|
254
|
-
resolve(result(request, status,
|
|
325
|
+
resolve(result(request, status, previewCaptureBytesV1(stdoutCapture, stdoutBytes), previewCaptureBytesV1(stderrCapture, stderrBytes), stdoutBytes, stderrBytes, previewBytes, termination, code ?? undefined, options.cwd));
|
|
255
326
|
};
|
|
256
327
|
const timeout = setTimeout(() => terminate("timeout"), timeoutMs);
|
|
257
328
|
if (signal !== undefined)
|
|
@@ -259,14 +330,14 @@ export function createNodeProcessExecAdapterV1(options) {
|
|
|
259
330
|
child.stdout?.on("data", (chunk) => {
|
|
260
331
|
const bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);
|
|
261
332
|
stdoutBytes += bytes.byteLength;
|
|
262
|
-
|
|
333
|
+
capturePreviewChunkV1(stdoutCapture, bytes);
|
|
263
334
|
if (stdoutBytes > maxStdoutBytes)
|
|
264
335
|
terminate("output_budget_exceeded");
|
|
265
336
|
});
|
|
266
337
|
child.stderr?.on("data", (chunk) => {
|
|
267
338
|
const bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);
|
|
268
339
|
stderrBytes += bytes.byteLength;
|
|
269
|
-
|
|
340
|
+
capturePreviewChunkV1(stderrCapture, bytes);
|
|
270
341
|
if (stderrBytes > maxStderrBytes)
|
|
271
342
|
terminate("output_budget_exceeded");
|
|
272
343
|
});
|
package/dist/node-adapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-adapter.js","sourceRoot":"","sources":["../src/node-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { isAbsolute } from \"node:path\";\nimport { killProcessTree, sanitizeBinaryOutput } from \"./shell-utils.ts\";\nimport {\n\tPROCESS_EXEC_HOST_ADAPTER_ID_V1,\n\tPROCESS_EXEC_HOST_ADAPTER_VERSION_V1,\n\ttype ProcessExecAdapterV1,\n\ttype ProcessExecRequestV1,\n\ttype ProcessExecResultV1,\n} from \"./types.ts\";\n\nconst DEFAULT_TIMEOUT_MS_V1 = 30_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_OUTPUT_BYTES_V1 = 64 * 1024;\nexport const PROCESS_EXEC_MAX_OUTPUT_BYTES_V1 = 1024 * 1024;\nconst DEFAULT_PREVIEW_BYTES_V1 = 4096;\nexport const PROCESS_EXEC_MAX_PREVIEW_BYTES_V1 = 8192;\nconst MAX_ARGS_V1 = 256;\nconst MAX_COMMAND_CHARS_V1 = 512;\nconst MAX_ARG_CHARS_V1 = 4096;\nexport const PROCESS_EXEC_MAX_OPERATION_ID_CHARS_V1 = 256;\n\nexport interface NodeProcessExecAdapterOptionsV1 {\n\t/** Host-owned working directory; requests cannot override it. */\n\treadonly cwd: string;\n\treadonly env?: Readonly<Record<string, string>>;\n\treadonly defaultTimeoutMs?: number;\n\treadonly maxStdoutBytes?: number;\n\treadonly maxStderrBytes?: number;\n\treadonly previewBytes?: number;\n\t/** Test seam for the host-owned process-tree terminator. */\n\treadonly killProcessTree?: (pid: number) => void;\n\t/** Deterministic host seam; production defaults to Node's shell-free spawn. */\n\treadonly spawn?: typeof spawn;\n}\n\nconst SAFE_ENVIRONMENT_KEYS_V1 = new Set(\n\t[\"PATH\", \"PATHEXT\", \"SystemRoot\", \"SYSTEMROOT\", \"WINDIR\", \"TEMP\", \"TMP\", \"TMPDIR\", \"LANG\", \"LC_ALL\"].map((key) =>\n\t\tkey.toLowerCase(),\n\t),\n);\n\n/** Redacts credentials and host paths before a preview can reach the model. */\nexport function sanitizeProcessTextV1(\n\tvalue: string,\n\tmaximumChars = PROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\tcwd?: string,\n): string {\n\tlet text = sanitizeBinaryOutput(value);\n\tif (cwd !== undefined && cwd !== \"\") text = text.replaceAll(cwd, \"[redacted-path]\");\n\ttext = text\n\t\t.replace(\n\t\t\t/((?:api[-_ ]?key|access[-_ ]?token|auth(?:orization)?|bearer|password|passwd|secret|token)\\s*[:=]\\s*)([^\\s,;]+)/giu,\n\t\t\t\"$1[redacted-secret]\",\n\t\t)\n\t\t.replace(/(?:[A-Za-z]:[\\\\/]|\\\\\\\\|\\/(?:home|Users|private|tmp|var|workspace)\\/)[^\\s\"'<>]*/gu, \"[redacted-path]\");\n\treturn text.length <= maximumChars ? text : text.slice(0, maximumChars);\n}\n\nfunction hostEnvironment(explicit: Readonly<Record<string, string>> | undefined): NodeJS.ProcessEnv {\n\tconst inherited: NodeJS.ProcessEnv = {};\n\tfor (const [key, value] of Object.entries(process.env)) {\n\t\tif (value !== undefined && SAFE_ENVIRONMENT_KEYS_V1.has(key.toLowerCase())) inherited[key] = value;\n\t}\n\treturn { ...inherited, ...(explicit ?? {}) };\n}\n\nfunction positiveBound(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result < 1 || result > maximum)\n\t\tthrow new Error(`${label} must be a positive integer at most ${maximum}`);\n\treturn result;\n}\n\nfunction inputError(operationId: string, message: string): ProcessExecResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: \"Process request was invalid\",\n\t\tstdoutBytes: 0,\n\t\tstderrBytes: 0,\n\t\tstdoutPreview: \"\",\n\t\tstderrPreview: \"\",\n\t\tstdoutTruncated: false,\n\t\tstderrTruncated: false,\n\t\terror: { version: 1, code: \"invalid_input\", message },\n\t};\n}\n\nfunction cancelled(operationId: string): ProcessExecResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"cancelled\",\n\t\tsummary: \"Process execution was cancelled\",\n\t\tstdoutBytes: 0,\n\t\tstderrBytes: 0,\n\t\tstdoutPreview: \"\",\n\t\tstderrPreview: \"\",\n\t\tstdoutTruncated: false,\n\t\tstderrTruncated: false,\n\t\terror: { version: 1, code: \"cancelled\", message: \"Process execution was cancelled\" },\n\t};\n}\n\nfunction validateRequest(request: ProcessExecRequestV1): string | undefined {\n\tif (request.version !== 1) return \"version must be 1\";\n\tif (\n\t\ttypeof request.operationId !== \"string\" ||\n\t\trequest.operationId.trim() === \"\" ||\n\t\trequest.operationId.length > PROCESS_EXEC_MAX_OPERATION_ID_CHARS_V1\n\t)\n\t\treturn \"operationId is invalid\";\n\tif (\n\t\ttypeof request.command !== \"string\" ||\n\t\trequest.command.trim() === \"\" ||\n\t\trequest.command.length > MAX_COMMAND_CHARS_V1 ||\n\t\t/[\\u0000\\r\\n]/u.test(request.command)\n\t)\n\t\treturn \"command is invalid\";\n\tif (!Array.isArray(request.args) || request.args.length > MAX_ARGS_V1) return \"args are invalid\";\n\tif (\n\t\trequest.args.some((arg) => typeof arg !== \"string\" || arg.length > MAX_ARG_CHARS_V1 || /[\\u0000\\r\\n]/u.test(arg))\n\t)\n\t\treturn \"args are invalid\";\n\tif (\n\t\trequest.timeoutMs !== undefined &&\n\t\t(!Number.isSafeInteger(request.timeoutMs) || request.timeoutMs < 1 || request.timeoutMs > MAX_TIMEOUT_MS_V1)\n\t)\n\t\treturn `timeoutMs must be a positive integer at most ${MAX_TIMEOUT_MS_V1}`;\n\treturn undefined;\n}\n\nfunction previewText(bytes: Uint8Array): string {\n\treturn new TextDecoder().decode(bytes);\n}\n\nfunction result(\n\trequest: ProcessExecRequestV1,\n\tstatus: ProcessExecResultV1[\"status\"],\n\tstdout: Uint8Array,\n\tstderr: Uint8Array,\n\tstdoutBytes: number,\n\tstderrBytes: number,\n\tpreviewBytes: number,\n\ttermination?: \"timeout\" | \"output_budget_exceeded\" | \"spawn_failed\" | \"exit_nonzero\" | \"cancelled\",\n\tcode?: number,\n\tcwd?: string,\n): ProcessExecResultV1 {\n\tconst stdoutPreview = sanitizeProcessTextV1(previewText(stdout.subarray(0, previewBytes)), previewBytes, cwd);\n\tconst stderrPreview = sanitizeProcessTextV1(previewText(stderr.subarray(0, previewBytes)), previewBytes, cwd);\n\tconst errorCode = termination;\n\tconst error =\n\t\terrorCode === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tversion: 1 as const,\n\t\t\t\t\tcode: errorCode,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\terrorCode === \"exit_nonzero\"\n\t\t\t\t\t\t\t? \"Process exited with a non-zero status\"\n\t\t\t\t\t\t\t: errorCode === \"cancelled\"\n\t\t\t\t\t\t\t\t? \"Process execution was cancelled\"\n\t\t\t\t\t\t\t\t: \"Process execution failed\",\n\t\t\t\t};\n\treturn {\n\t\tversion: 1,\n\t\toperationId: request.operationId,\n\t\tstatus,\n\t\tsummary:\n\t\t\tstatus === \"succeeded\"\n\t\t\t\t? \"Process completed successfully\"\n\t\t\t\t: termination === \"cancelled\"\n\t\t\t\t\t? \"Process execution was cancelled\"\n\t\t\t\t\t: termination === \"timeout\"\n\t\t\t\t\t\t? \"Process execution timed out\"\n\t\t\t\t\t\t: termination === \"output_budget_exceeded\"\n\t\t\t\t\t\t\t? \"Process output exceeded the host budget\"\n\t\t\t\t\t\t\t: termination === \"spawn_failed\"\n\t\t\t\t\t\t\t\t? \"Process could not be started\"\n\t\t\t\t\t\t\t\t: \"Process exited with a non-zero status\",\n\t\t...(code === undefined ? {} : { exitCode: code }),\n\t\tstdoutBytes,\n\t\tstderrBytes,\n\t\tstdoutPreview,\n\t\tstderrPreview,\n\t\tstdoutTruncated: stdoutBytes > previewBytes,\n\t\tstderrTruncated: stderrBytes > previewBytes,\n\t\t...(error === undefined ? {} : { error }),\n\t};\n}\n\n/** Node host adapter with shell-free argv execution and bounded output previews. */\nexport function createNodeProcessExecAdapterV1(options: NodeProcessExecAdapterOptionsV1): ProcessExecAdapterV1 {\n\tif (typeof options.cwd !== \"string\" || !isAbsolute(options.cwd)) throw new Error(\"cwd must be an absolute path\");\n\tconst defaultTimeoutMs = positiveBound(\n\t\toptions.defaultTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"defaultTimeoutMs\",\n\t);\n\tconst maxStdoutBytes = positiveBound(\n\t\toptions.maxStdoutBytes,\n\t\tDEFAULT_OUTPUT_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_OUTPUT_BYTES_V1,\n\t\t\"maxStdoutBytes\",\n\t);\n\tconst maxStderrBytes = positiveBound(\n\t\toptions.maxStderrBytes,\n\t\tDEFAULT_OUTPUT_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_OUTPUT_BYTES_V1,\n\t\t\"maxStderrBytes\",\n\t);\n\tconst previewBytes = positiveBound(\n\t\toptions.previewBytes,\n\t\tDEFAULT_PREVIEW_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\t\t\"previewBytes\",\n\t);\n\tconst env = hostEnvironment(options.env);\n\tconst spawnProcess = options.spawn ?? spawn;\n\tconst terminateTree = options.killProcessTree ?? killProcessTree;\n\n\treturn {\n\t\tadapterId: PROCESS_EXEC_HOST_ADAPTER_ID_V1,\n\t\tadapterVersion: PROCESS_EXEC_HOST_ADAPTER_VERSION_V1,\n\t\trun: (request, signal) => {\n\t\t\tconst operationId =\n\t\t\t\ttypeof request.operationId === \"string\" && request.operationId.trim() !== \"\"\n\t\t\t\t\t? request.operationId\n\t\t\t\t\t: \"invalid-process-operation\";\n\t\t\tconst invalid = validateRequest(request);\n\t\t\tif (invalid !== undefined) return Promise.resolve(inputError(operationId, invalid));\n\t\t\tif (signal?.aborted) return Promise.resolve(cancelled(operationId));\n\t\t\tconst timeoutMs = request.timeoutMs ?? defaultTimeoutMs;\n\t\t\treturn new Promise<ProcessExecResultV1>((resolve) => {\n\t\t\t\tlet child: ReturnType<typeof spawn>;\n\t\t\t\ttry {\n\t\t\t\t\tchild = spawnProcess(request.command, [...request.args], {\n\t\t\t\t\t\tcwd: options.cwd,\n\t\t\t\t\t\t...(env === undefined ? {} : { env }),\n\t\t\t\t\t\tshell: false,\n\t\t\t\t\t\twindowsHide: true,\n\t\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\t});\n\t\t\t\t} catch {\n\t\t\t\t\tresolve(\n\t\t\t\t\t\tresult(\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\t\"failed\",\n\t\t\t\t\t\t\tnew Uint8Array(),\n\t\t\t\t\t\t\tnew Uint8Array(),\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tpreviewBytes,\n\t\t\t\t\t\t\t\"spawn_failed\",\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\toptions.cwd,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet stdoutBytes = 0;\n\t\t\t\tlet stderrBytes = 0;\n\t\t\t\tconst stdoutPreview = new Uint8Array(previewBytes);\n\t\t\t\tconst stderrPreview = new Uint8Array(previewBytes);\n\t\t\t\tlet stdoutPreviewLength = 0;\n\t\t\t\tlet stderrPreviewLength = 0;\n\t\t\t\tlet termination:\n\t\t\t\t\t| \"timeout\"\n\t\t\t\t\t| \"output_budget_exceeded\"\n\t\t\t\t\t| \"spawn_failed\"\n\t\t\t\t\t| \"exit_nonzero\"\n\t\t\t\t\t| \"cancelled\"\n\t\t\t\t\t| undefined;\n\t\t\t\tlet settled = false;\n\t\t\t\tlet exited = false;\n\t\t\t\tlet terminationRequested = false;\n\t\t\t\tlet forceKillTimer: ReturnType<typeof setTimeout> | undefined;\n\t\t\t\tlet hardFinishTimer: ReturnType<typeof setTimeout> | undefined;\n\t\t\t\tconst append = (target: Uint8Array, length: number, chunk: Uint8Array): number => {\n\t\t\t\t\tconst copy = Math.min(chunk.byteLength, target.byteLength - length);\n\t\t\t\t\ttarget.set(chunk.subarray(0, copy), length);\n\t\t\t\t\treturn length + copy;\n\t\t\t\t};\n\t\t\t\tconst forceTerminate = (): void => {\n\t\t\t\t\tif (exited) return;\n\t\t\t\t\tif (typeof child.pid === \"number\" && child.pid > 0) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tterminateTree(child.pid);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// The host cleanup boundary is best-effort; close/error still settles the operation.\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!child.killed) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// The close/error event remains authoritative.\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tconst armForceTermination = (): void => {\n\t\t\t\t\tif (forceKillTimer !== undefined) return;\n\t\t\t\t\tforceKillTimer = setTimeout(() => {\n\t\t\t\t\t\tforceTerminate();\n\t\t\t\t\t\thardFinishTimer = setTimeout(() => finalize(null), 500);\n\t\t\t\t\t}, 2000);\n\t\t\t\t};\n\t\t\t\tconst terminate = (reason: \"timeout\" | \"output_budget_exceeded\" | \"spawn_failed\" | \"cancelled\"): void => {\n\t\t\t\t\tif (termination === undefined) termination = reason;\n\t\t\t\t\tif (!terminationRequested) {\n\t\t\t\t\t\tterminationRequested = true;\n\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// The force cleanup timer still runs.\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tarmForceTermination();\n\t\t\t\t};\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tterminate(\"cancelled\");\n\t\t\t\t};\n\t\t\t\tconst finalize = (code: number | null): void => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\texited = true;\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tif (forceKillTimer !== undefined) clearTimeout(forceKillTimer);\n\t\t\t\t\tif (hardFinishTimer !== undefined) clearTimeout(hardFinishTimer);\n\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tif (signal?.aborted && termination === undefined) termination = \"cancelled\";\n\t\t\t\t\tif (termination === undefined && code !== 0) termination = \"exit_nonzero\";\n\t\t\t\t\tconst status =\n\t\t\t\t\t\ttermination === undefined ? \"succeeded\" : termination === \"cancelled\" ? \"cancelled\" : \"failed\";\n\t\t\t\t\tresolve(\n\t\t\t\t\t\tresult(\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t\tstdoutPreview.subarray(0, stdoutPreviewLength),\n\t\t\t\t\t\t\tstderrPreview.subarray(0, stderrPreviewLength),\n\t\t\t\t\t\t\tstdoutBytes,\n\t\t\t\t\t\t\tstderrBytes,\n\t\t\t\t\t\t\tpreviewBytes,\n\t\t\t\t\t\t\ttermination,\n\t\t\t\t\t\t\tcode ?? undefined,\n\t\t\t\t\t\t\toptions.cwd,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t\tconst timeout = setTimeout(() => terminate(\"timeout\"), timeoutMs);\n\t\t\t\tif (signal !== undefined) signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer | Uint8Array) => {\n\t\t\t\t\tconst bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);\n\t\t\t\t\tstdoutBytes += bytes.byteLength;\n\t\t\t\t\tstdoutPreviewLength = append(stdoutPreview, stdoutPreviewLength, bytes);\n\t\t\t\t\tif (stdoutBytes > maxStdoutBytes) terminate(\"output_budget_exceeded\");\n\t\t\t\t});\n\t\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer | Uint8Array) => {\n\t\t\t\t\tconst bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);\n\t\t\t\t\tstderrBytes += bytes.byteLength;\n\t\t\t\t\tstderrPreviewLength = append(stderrPreview, stderrPreviewLength, bytes);\n\t\t\t\t\tif (stderrBytes > maxStderrBytes) terminate(\"output_budget_exceeded\");\n\t\t\t\t});\n\t\t\t\tchild.once(\"error\", () => {\n\t\t\t\t\tterminate(\"spawn_failed\");\n\t\t\t\t});\n\t\t\t\tchild.once(\"close\", (code) => {\n\t\t\t\t\texited = true;\n\t\t\t\t\tfinalize(code);\n\t\t\t\t});\n\t\t\t});\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"node-adapter.js","sourceRoot":"","sources":["../src/node-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { isAbsolute } from \"node:path\";\nimport { killProcessTree, sanitizeBinaryOutput } from \"./shell-utils.ts\";\nimport {\n\tPROCESS_EXEC_HOST_ADAPTER_ID_V1,\n\tPROCESS_EXEC_HOST_ADAPTER_VERSION_V1,\n\ttype ProcessExecAdapterV1,\n\ttype ProcessExecRequestV1,\n\ttype ProcessExecResultV1,\n} from \"./types.ts\";\n\nconst DEFAULT_TIMEOUT_MS_V1 = 30_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_OUTPUT_BYTES_V1 = 64 * 1024;\nexport const PROCESS_EXEC_MAX_OUTPUT_BYTES_V1 = 1024 * 1024;\nconst DEFAULT_PREVIEW_BYTES_V1 = 4096;\nexport const PROCESS_EXEC_MAX_PREVIEW_BYTES_V1 = 8192;\nconst MAX_ARGS_V1 = 256;\nconst MAX_COMMAND_CHARS_V1 = 512;\nconst MAX_ARG_CHARS_V1 = 4096;\nexport const PROCESS_EXEC_MAX_OPERATION_ID_CHARS_V1 = 256;\n\nexport interface NodeProcessExecAdapterOptionsV1 {\n\t/** Host-owned working directory; requests cannot override it. */\n\treadonly cwd: string;\n\treadonly env?: Readonly<Record<string, string>>;\n\treadonly defaultTimeoutMs?: number;\n\treadonly maxStdoutBytes?: number;\n\treadonly maxStderrBytes?: number;\n\treadonly previewBytes?: number;\n\t/** Test seam for the host-owned process-tree terminator. */\n\treadonly killProcessTree?: (pid: number) => void;\n\t/** Deterministic host seam; production defaults to Node's shell-free spawn. */\n\treadonly spawn?: typeof spawn;\n}\n\nconst SAFE_ENVIRONMENT_KEYS_V1 = new Set(\n\t[\"PATH\", \"PATHEXT\", \"SystemRoot\", \"SYSTEMROOT\", \"WINDIR\", \"TEMP\", \"TMP\", \"TMPDIR\", \"LANG\", \"LC_ALL\"].map((key) =>\n\t\tkey.toLowerCase(),\n\t),\n);\n\n/** Splits a preview budget into head/tail segments (75% head, rest tail; head wins on tiny budgets). */\nfunction splitPreviewBudgetV1(budget: number): { head: number; tail: number } {\n\tconst head = Math.ceil((budget * 3) / 4);\n\treturn { head, tail: Math.max(0, budget - head) };\n}\n\nfunction omissionMarkerV1(omitted: number, unit: \"bytes\" | \"chars\"): string {\n\treturn `\\n... [${omitted} ${unit} omitted] ...\\n`;\n}\n\n/**\n * Builds a bounded preview from the retained capture. `captured` holds the\n * complete output when `totalBytes <= previewBytes`; otherwise it holds the\n * first `head` bytes followed by the last `tail` bytes of the stream, and the\n * two segments are joined with an omission marker. The marker rides on top of\n * the segment budgets but the assembled preview never exceeds\n * `PROCESS_EXEC_MAX_PREVIEW_BYTES_V1`.\n */\nexport function buildHeadTailPreviewV1(captured: Uint8Array, previewBytes: number, totalBytes: number): string {\n\tif (totalBytes <= previewBytes) return previewText(captured);\n\tconst budget = splitPreviewBudgetV1(previewBytes);\n\tconst headPart = captured.subarray(0, Math.min(budget.head, captured.byteLength));\n\tlet tailBytes = Math.min(budget.tail, Math.max(0, captured.byteLength - headPart.byteLength));\n\tlet marker = omissionMarkerV1(Math.max(0, totalBytes - headPart.byteLength - tailBytes), \"bytes\");\n\twhile (headPart.byteLength + tailBytes + marker.length > PROCESS_EXEC_MAX_PREVIEW_BYTES_V1 && tailBytes > 0) {\n\t\ttailBytes = Math.max(\n\t\t\t0,\n\t\t\tMath.min(tailBytes, PROCESS_EXEC_MAX_PREVIEW_BYTES_V1 - headPart.byteLength - marker.length),\n\t\t);\n\t\tmarker = omissionMarkerV1(Math.max(0, totalBytes - headPart.byteLength - tailBytes), \"bytes\");\n\t}\n\treturn previewText(headPart) + marker + previewText(captured.subarray(captured.byteLength - tailBytes));\n}\n\n/** Redacts credentials and host paths before a preview can reach the model. */\nexport function sanitizeProcessTextV1(\n\tvalue: string,\n\tmaximumChars = PROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\tcwd?: string,\n): string {\n\tlet text = sanitizeBinaryOutput(value);\n\tif (cwd !== undefined && cwd !== \"\") text = text.replaceAll(cwd, \"[redacted-path]\");\n\ttext = text\n\t\t.replace(\n\t\t\t/((?:api[-_ ]?key|access[-_ ]?token|auth(?:orization)?|bearer|password|passwd|secret|token)\\s*[:=]\\s*)([^\\s,;]+)/giu,\n\t\t\t\"$1[redacted-secret]\",\n\t\t)\n\t\t.replace(/(?:[A-Za-z]:[\\\\/]|\\\\\\\\|\\/(?:home|Users|private|tmp|var|workspace)\\/)[^\\s\"'<>]*/gu, \"[redacted-path]\");\n\tif (text.length <= maximumChars) return text;\n\tconst head = Math.ceil((maximumChars * 3) / 4);\n\tlet tail = maximumChars - head;\n\tlet marker = omissionMarkerV1(text.length - head - tail, \"chars\");\n\twhile (head + tail + marker.length > maximumChars && tail > 0) {\n\t\ttail = Math.max(0, Math.min(tail, maximumChars - head - marker.length));\n\t\tmarker = omissionMarkerV1(text.length - head - tail, \"chars\");\n\t}\n\treturn text.slice(0, head) + marker + (tail > 0 ? text.slice(text.length - tail) : \"\");\n}\n\nfunction hostEnvironment(explicit: Readonly<Record<string, string>> | undefined): NodeJS.ProcessEnv {\n\tconst inherited: NodeJS.ProcessEnv = {};\n\tfor (const [key, value] of Object.entries(process.env)) {\n\t\tif (value !== undefined && SAFE_ENVIRONMENT_KEYS_V1.has(key.toLowerCase())) inherited[key] = value;\n\t}\n\treturn { ...inherited, ...(explicit ?? {}) };\n}\n\nfunction positiveBound(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result < 1 || result > maximum)\n\t\tthrow new Error(`${label} must be a positive integer at most ${maximum}`);\n\treturn result;\n}\n\nfunction inputError(operationId: string, message: string): ProcessExecResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: \"Process request was invalid\",\n\t\tstdoutBytes: 0,\n\t\tstderrBytes: 0,\n\t\tstdoutPreview: \"\",\n\t\tstderrPreview: \"\",\n\t\tstdoutTruncated: false,\n\t\tstderrTruncated: false,\n\t\terror: { version: 1, code: \"invalid_input\", message },\n\t};\n}\n\nfunction cancelled(operationId: string): ProcessExecResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"cancelled\",\n\t\tsummary: \"Process execution was cancelled\",\n\t\tstdoutBytes: 0,\n\t\tstderrBytes: 0,\n\t\tstdoutPreview: \"\",\n\t\tstderrPreview: \"\",\n\t\tstdoutTruncated: false,\n\t\tstderrTruncated: false,\n\t\terror: { version: 1, code: \"cancelled\", message: \"Process execution was cancelled\" },\n\t};\n}\n\nfunction validateRequest(request: ProcessExecRequestV1): string | undefined {\n\tif (request.version !== 1) return \"version must be 1\";\n\tif (\n\t\ttypeof request.operationId !== \"string\" ||\n\t\trequest.operationId.trim() === \"\" ||\n\t\trequest.operationId.length > PROCESS_EXEC_MAX_OPERATION_ID_CHARS_V1\n\t)\n\t\treturn \"operationId is invalid\";\n\tif (\n\t\ttypeof request.command !== \"string\" ||\n\t\trequest.command.trim() === \"\" ||\n\t\trequest.command.length > MAX_COMMAND_CHARS_V1 ||\n\t\t/[\\u0000\\r\\n]/u.test(request.command)\n\t)\n\t\treturn \"command is invalid\";\n\tif (!Array.isArray(request.args) || request.args.length > MAX_ARGS_V1) return \"args are invalid\";\n\tif (\n\t\trequest.args.some((arg) => typeof arg !== \"string\" || arg.length > MAX_ARG_CHARS_V1 || /[\\u0000\\r\\n]/u.test(arg))\n\t)\n\t\treturn \"args are invalid\";\n\tif (\n\t\trequest.timeoutMs !== undefined &&\n\t\t(!Number.isSafeInteger(request.timeoutMs) || request.timeoutMs < 1 || request.timeoutMs > MAX_TIMEOUT_MS_V1)\n\t)\n\t\treturn `timeoutMs must be a positive integer at most ${MAX_TIMEOUT_MS_V1}`;\n\treturn undefined;\n}\n\nfunction previewText(bytes: Uint8Array): string {\n\treturn new TextDecoder().decode(bytes);\n}\n\ninterface PreviewCaptureV1 {\n\treadonly head: Uint8Array;\n\treadonly tail: Uint8Array;\n\theadLength: number;\n\ttailLength: number;\n}\n\n/** Retains the first head-budget and last tail-budget bytes of a stream for head+tail previews. */\nfunction createPreviewCaptureV1(previewBytes: number): PreviewCaptureV1 {\n\tconst budget = splitPreviewBudgetV1(previewBytes);\n\treturn { head: new Uint8Array(budget.head), tail: new Uint8Array(budget.tail), headLength: 0, tailLength: 0 };\n}\n\nfunction capturePreviewChunkV1(capture: PreviewCaptureV1, chunk: Uint8Array): void {\n\tconst headCopy = Math.min(chunk.byteLength, capture.head.byteLength - capture.headLength);\n\tcapture.head.set(chunk.subarray(0, headCopy), capture.headLength);\n\tcapture.headLength += headCopy;\n\tconst tailSize = capture.tail.byteLength;\n\tif (tailSize === 0) return;\n\tif (chunk.byteLength >= tailSize) {\n\t\tcapture.tail.set(chunk.subarray(chunk.byteLength - tailSize));\n\t\tcapture.tailLength = tailSize;\n\t\treturn;\n\t}\n\tcapture.tail.copyWithin(0, chunk.byteLength);\n\tcapture.tail.set(chunk, tailSize - chunk.byteLength);\n\tcapture.tailLength = Math.min(tailSize, capture.tailLength + chunk.byteLength);\n}\n\n/** Materializes the retained bytes: the full output when it fit the budget, else head followed by tail. */\nfunction previewCaptureBytesV1(capture: PreviewCaptureV1, totalBytes: number): Uint8Array {\n\tconst capacity = capture.head.byteLength + capture.tail.byteLength;\n\tif (totalBytes <= capture.head.byteLength) return capture.head.subarray(0, totalBytes);\n\tif (totalBytes <= capacity) {\n\t\tconst tailFrom = totalBytes - capture.head.byteLength;\n\t\tconst captured = new Uint8Array(totalBytes);\n\t\tcaptured.set(capture.head);\n\t\tcaptured.set(capture.tail.subarray(capture.tailLength - tailFrom, capture.tailLength), capture.headLength);\n\t\treturn captured;\n\t}\n\tconst captured = new Uint8Array(capacity);\n\tcaptured.set(capture.head.subarray(0, capture.headLength));\n\tcaptured.set(capture.tail.subarray(0, capture.tailLength), capture.headLength);\n\treturn captured;\n}\n\nfunction result(\n\trequest: ProcessExecRequestV1,\n\tstatus: ProcessExecResultV1[\"status\"],\n\tstdout: Uint8Array,\n\tstderr: Uint8Array,\n\tstdoutBytes: number,\n\tstderrBytes: number,\n\tpreviewBytes: number,\n\ttermination?: \"timeout\" | \"output_budget_exceeded\" | \"spawn_failed\" | \"exit_nonzero\" | \"cancelled\",\n\tcode?: number,\n\tcwd?: string,\n): ProcessExecResultV1 {\n\t// The byte-level head/tail split is authoritative; sanitize only redacts and\n\t// acts as the absolute-size circuit breaker at the contract cap.\n\tconst stdoutPreview = sanitizeProcessTextV1(\n\t\tbuildHeadTailPreviewV1(stdout, previewBytes, stdoutBytes),\n\t\tPROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\t\tcwd,\n\t);\n\tconst stderrPreview = sanitizeProcessTextV1(\n\t\tbuildHeadTailPreviewV1(stderr, previewBytes, stderrBytes),\n\t\tPROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\t\tcwd,\n\t);\n\tconst errorCode = termination;\n\tconst error =\n\t\terrorCode === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tversion: 1 as const,\n\t\t\t\t\tcode: errorCode,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\terrorCode === \"exit_nonzero\"\n\t\t\t\t\t\t\t? \"Process exited with a non-zero status\"\n\t\t\t\t\t\t\t: errorCode === \"cancelled\"\n\t\t\t\t\t\t\t\t? \"Process execution was cancelled\"\n\t\t\t\t\t\t\t\t: \"Process execution failed\",\n\t\t\t\t};\n\treturn {\n\t\tversion: 1,\n\t\toperationId: request.operationId,\n\t\tstatus,\n\t\tsummary:\n\t\t\tstatus === \"succeeded\"\n\t\t\t\t? \"Process completed successfully\"\n\t\t\t\t: termination === \"cancelled\"\n\t\t\t\t\t? \"Process execution was cancelled\"\n\t\t\t\t\t: termination === \"timeout\"\n\t\t\t\t\t\t? \"Process execution timed out\"\n\t\t\t\t\t\t: termination === \"output_budget_exceeded\"\n\t\t\t\t\t\t\t? \"Process output exceeded the host budget\"\n\t\t\t\t\t\t\t: termination === \"spawn_failed\"\n\t\t\t\t\t\t\t\t? \"Process could not be started\"\n\t\t\t\t\t\t\t\t: \"Process exited with a non-zero status\",\n\t\t...(code === undefined ? {} : { exitCode: code }),\n\t\tstdoutBytes,\n\t\tstderrBytes,\n\t\tstdoutPreview,\n\t\tstderrPreview,\n\t\tstdoutTruncated: stdoutBytes > previewBytes,\n\t\tstderrTruncated: stderrBytes > previewBytes,\n\t\t...(error === undefined ? {} : { error }),\n\t};\n}\n\n/** Node host adapter with shell-free argv execution and bounded output previews. */\nexport function createNodeProcessExecAdapterV1(options: NodeProcessExecAdapterOptionsV1): ProcessExecAdapterV1 {\n\tif (typeof options.cwd !== \"string\" || !isAbsolute(options.cwd)) throw new Error(\"cwd must be an absolute path\");\n\tconst defaultTimeoutMs = positiveBound(\n\t\toptions.defaultTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"defaultTimeoutMs\",\n\t);\n\tconst maxStdoutBytes = positiveBound(\n\t\toptions.maxStdoutBytes,\n\t\tDEFAULT_OUTPUT_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_OUTPUT_BYTES_V1,\n\t\t\"maxStdoutBytes\",\n\t);\n\tconst maxStderrBytes = positiveBound(\n\t\toptions.maxStderrBytes,\n\t\tDEFAULT_OUTPUT_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_OUTPUT_BYTES_V1,\n\t\t\"maxStderrBytes\",\n\t);\n\tconst previewBytes = positiveBound(\n\t\toptions.previewBytes,\n\t\tDEFAULT_PREVIEW_BYTES_V1,\n\t\tPROCESS_EXEC_MAX_PREVIEW_BYTES_V1,\n\t\t\"previewBytes\",\n\t);\n\tconst env = hostEnvironment(options.env);\n\tconst spawnProcess = options.spawn ?? spawn;\n\tconst terminateTree = options.killProcessTree ?? killProcessTree;\n\n\treturn {\n\t\tadapterId: PROCESS_EXEC_HOST_ADAPTER_ID_V1,\n\t\tadapterVersion: PROCESS_EXEC_HOST_ADAPTER_VERSION_V1,\n\t\trun: (request, signal) => {\n\t\t\tconst operationId =\n\t\t\t\ttypeof request.operationId === \"string\" && request.operationId.trim() !== \"\"\n\t\t\t\t\t? request.operationId\n\t\t\t\t\t: \"invalid-process-operation\";\n\t\t\tconst invalid = validateRequest(request);\n\t\t\tif (invalid !== undefined) return Promise.resolve(inputError(operationId, invalid));\n\t\t\tif (signal?.aborted) return Promise.resolve(cancelled(operationId));\n\t\t\tconst timeoutMs = request.timeoutMs ?? defaultTimeoutMs;\n\t\t\treturn new Promise<ProcessExecResultV1>((resolve) => {\n\t\t\t\tlet child: ReturnType<typeof spawn>;\n\t\t\t\ttry {\n\t\t\t\t\tchild = spawnProcess(request.command, [...request.args], {\n\t\t\t\t\t\tcwd: options.cwd,\n\t\t\t\t\t\t...(env === undefined ? {} : { env }),\n\t\t\t\t\t\tshell: false,\n\t\t\t\t\t\twindowsHide: true,\n\t\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\t});\n\t\t\t\t} catch {\n\t\t\t\t\tresolve(\n\t\t\t\t\t\tresult(\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\t\"failed\",\n\t\t\t\t\t\t\tnew Uint8Array(),\n\t\t\t\t\t\t\tnew Uint8Array(),\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tpreviewBytes,\n\t\t\t\t\t\t\t\"spawn_failed\",\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\toptions.cwd,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet stdoutBytes = 0;\n\t\t\t\tlet stderrBytes = 0;\n\t\t\t\tconst stdoutCapture = createPreviewCaptureV1(previewBytes);\n\t\t\t\tconst stderrCapture = createPreviewCaptureV1(previewBytes);\n\t\t\t\tlet termination:\n\t\t\t\t\t| \"timeout\"\n\t\t\t\t\t| \"output_budget_exceeded\"\n\t\t\t\t\t| \"spawn_failed\"\n\t\t\t\t\t| \"exit_nonzero\"\n\t\t\t\t\t| \"cancelled\"\n\t\t\t\t\t| undefined;\n\t\t\t\tlet settled = false;\n\t\t\t\tlet exited = false;\n\t\t\t\tlet terminationRequested = false;\n\t\t\t\tlet forceKillTimer: ReturnType<typeof setTimeout> | undefined;\n\t\t\t\tlet hardFinishTimer: ReturnType<typeof setTimeout> | undefined;\n\t\t\t\tconst forceTerminate = (): void => {\n\t\t\t\t\tif (exited) return;\n\t\t\t\t\tif (typeof child.pid === \"number\" && child.pid > 0) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tterminateTree(child.pid);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// The host cleanup boundary is best-effort; close/error still settles the operation.\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!child.killed) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// The close/error event remains authoritative.\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tconst armForceTermination = (): void => {\n\t\t\t\t\tif (forceKillTimer !== undefined) return;\n\t\t\t\t\tforceKillTimer = setTimeout(() => {\n\t\t\t\t\t\tforceTerminate();\n\t\t\t\t\t\thardFinishTimer = setTimeout(() => finalize(null), 500);\n\t\t\t\t\t}, 2000);\n\t\t\t\t};\n\t\t\t\tconst terminate = (reason: \"timeout\" | \"output_budget_exceeded\" | \"spawn_failed\" | \"cancelled\"): void => {\n\t\t\t\t\tif (termination === undefined) termination = reason;\n\t\t\t\t\tif (!terminationRequested) {\n\t\t\t\t\t\tterminationRequested = true;\n\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// The force cleanup timer still runs.\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tarmForceTermination();\n\t\t\t\t};\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tterminate(\"cancelled\");\n\t\t\t\t};\n\t\t\t\tconst finalize = (code: number | null): void => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\texited = true;\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tif (forceKillTimer !== undefined) clearTimeout(forceKillTimer);\n\t\t\t\t\tif (hardFinishTimer !== undefined) clearTimeout(hardFinishTimer);\n\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tif (signal?.aborted && termination === undefined) termination = \"cancelled\";\n\t\t\t\t\tif (termination === undefined && code !== 0) termination = \"exit_nonzero\";\n\t\t\t\t\tconst status =\n\t\t\t\t\t\ttermination === undefined ? \"succeeded\" : termination === \"cancelled\" ? \"cancelled\" : \"failed\";\n\t\t\t\t\tresolve(\n\t\t\t\t\t\tresult(\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t\tpreviewCaptureBytesV1(stdoutCapture, stdoutBytes),\n\t\t\t\t\t\t\tpreviewCaptureBytesV1(stderrCapture, stderrBytes),\n\t\t\t\t\t\t\tstdoutBytes,\n\t\t\t\t\t\t\tstderrBytes,\n\t\t\t\t\t\t\tpreviewBytes,\n\t\t\t\t\t\t\ttermination,\n\t\t\t\t\t\t\tcode ?? undefined,\n\t\t\t\t\t\t\toptions.cwd,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t\tconst timeout = setTimeout(() => terminate(\"timeout\"), timeoutMs);\n\t\t\t\tif (signal !== undefined) signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer | Uint8Array) => {\n\t\t\t\t\tconst bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);\n\t\t\t\t\tstdoutBytes += bytes.byteLength;\n\t\t\t\t\tcapturePreviewChunkV1(stdoutCapture, bytes);\n\t\t\t\t\tif (stdoutBytes > maxStdoutBytes) terminate(\"output_budget_exceeded\");\n\t\t\t\t});\n\t\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer | Uint8Array) => {\n\t\t\t\t\tconst bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);\n\t\t\t\t\tstderrBytes += bytes.byteLength;\n\t\t\t\t\tcapturePreviewChunkV1(stderrCapture, bytes);\n\t\t\t\t\tif (stderrBytes > maxStderrBytes) terminate(\"output_budget_exceeded\");\n\t\t\t\t});\n\t\t\t\tchild.once(\"error\", () => {\n\t\t\t\t\tterminate(\"spawn_failed\");\n\t\t\t\t});\n\t\t\t\tchild.once(\"close\", (code) => {\n\t\t\t\t\texited = true;\n\t\t\t\t\tfinalize(code);\n\t\t\t\t});\n\t\t\t});\n\t\t},\n\t};\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-agent-forge/plugin-process-exec",
|
|
3
|
-
"version": "0.86.
|
|
3
|
+
"version": "0.86.1",
|
|
4
4
|
"description": "Process execution capability plugin for Agent Forge (full-control process_exec tool)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"typebox": "1.3.27",
|
|
48
|
-
"@ai-agent-forge/plugin-sdk": "^0.86.
|
|
48
|
+
"@ai-agent-forge/plugin-sdk": "^0.86.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"shx": "0.4.0",
|
|
52
52
|
"vitest": "4.1.9",
|
|
53
|
-
"@ai-agent-forge/agent-forge": "^0.86.
|
|
53
|
+
"@ai-agent-forge/agent-forge": "^0.86.1"
|
|
54
54
|
}
|
|
55
55
|
}
|