openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
133 lines (132 loc) • 4.63 kB
JavaScript
import { n as sliceUtf16Safe } from "./utf16-slice-D_ngcYKd.js";
import { t as killProcessTree } from "./kill-tree-CR2oLt9D.js";
import { p as redactSensitiveText, u as redactSensitiveFieldValue } from "./redact-BtvPPfTi.js";
import { t as _usingCtx } from "./usingCtx-CTfBxUtw.js";
import { t as prepareSecretInputStdio } from "./spawn-secret-input-vgiq-G6B.js";
import { t as attachErrorDiagnostic } from "./error-diagnostics-BM-F2vsk.js";
import "./error-runtime-Bz9Tw57Z.js";
import "./process-runtime-pcN9RjT8.js";
import "./logging-core-yEitd9NN.js";
import "./text-utility-runtime-BjzvUG99.js";
import { spawn } from "node:child_process";
//#region extensions/anthropic/cli-process.ts
const STDERR_CAPTURE_CHARS = 8192;
const STDERR_DRAIN_GRACE_MS = 200;
function spawnClaudeCliProcess(options, secretInput, observeStderr) {
try {
var _usingCtx$1 = _usingCtx();
const stdio = [
"pipe",
"pipe",
"pipe"
];
const secretDelivery = _usingCtx$1.u(prepareSecretInputStdio(stdio, secretInput));
const child = spawn(options.command, options.args, {
argv0: options.argv0,
cwd: options.cwd,
detached: process.platform !== "win32",
env: options.env,
signal: options.signal,
stdio,
windowsHide: true
});
observeStderr(child);
const killChild = child.kill.bind(child);
child.kill = (signal) => {
if (!child.pid || signal !== void 0 && signal !== "SIGTERM" && signal !== "SIGKILL") return killChild(signal);
killProcessTree(child.pid, {
detached: process.platform !== "win32",
...signal === "SIGKILL" ? { force: true } : {}
});
return true;
};
secretDelivery?.deliverTo(child).catch(() => child.kill());
return child;
} catch (_) {
_usingCtx$1.e = _;
} finally {
_usingCtx$1.d();
}
}
/** Owns process-wide diagnostics and the credentials needed to redact warm turns. */
function createClaudeCliProcessOwner(currentContext, secretInput) {
const assertCurrent = () => {
const context = currentContext();
if (!context) throw new Error("Claude CLI run is no longer active.");
context.assertCurrent?.();
};
assertCurrent();
const credential = secretInput?.createData();
let environment = {};
let child;
let drained;
let disposed = false;
let tail = "";
let dropPartialLine = false;
const observeStderr = (process) => {
child = process;
drained = new Promise((resolve) => {
process.stderr.once("close", resolve);
});
process.stderr.setEncoding("utf8");
process.stderr.on("error", () => {});
process.stderr.on("data", (chunk) => {
let text = chunk;
if (disposed) return;
if (dropPartialLine) {
const newline = text.indexOf("\n");
if (newline < 0) return;
text = text.slice(newline + 1);
dropPartialLine = false;
}
tail += text;
if (tail.length > STDERR_CAPTURE_CHARS) {
const bounded = sliceUtf16Safe(tail, -8192);
const newline = bounded.indexOf("\n");
tail = newline < 0 ? "" : bounded.slice(newline + 1);
dropPartialLine = newline < 0;
}
});
};
return {
[Symbol.dispose]() {
disposed = true;
credential?.fill(0);
environment = {};
tail = "";
},
spawn: (options) => {
assertCurrent();
environment = options.env;
return spawnClaudeCliProcess(options, secretInput, observeStderr);
},
async withDiagnostics(error) {
const context = currentContext();
if (disposed || !context || context.abortSignal?.aborted) return error;
if (child && (child.exitCode !== null || child.signalCode !== null)) {
let timer;
try {
await Promise.race([drained, new Promise((resolve) => {
timer = setTimeout(resolve, STDERR_DRAIN_GRACE_MS);
})]);
} finally {
clearTimeout(timer);
}
}
if (disposed || currentContext() !== context || context.abortSignal?.aborted) return error;
let diagnostic = tail;
const secrets = [environment, context.env].flatMap((env) => Object.entries(env).flatMap(([name, value]) => value && redactSensitiveFieldValue(name, value, { mode: "tools" }) !== value ? [value] : []));
if (credential) secrets.push(credential.toString("utf8"));
for (const secret of secrets.filter(Boolean)) for (const value of [
secret,
encodeURIComponent(secret),
JSON.stringify(secret).slice(1, -1)
]) diagnostic = diagnostic.replaceAll(value, "[REDACTED]");
diagnostic = sliceUtf16Safe(redactSensitiveText(diagnostic, { mode: "tools" }), -2e3).trim();
if (diagnostic && error instanceof Error) attachErrorDiagnostic(error, `stderr (process-wide; may include earlier turns): ${diagnostic}`);
return error;
}
};
}
//#endregion
export { createClaudeCliProcessOwner as t };