openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
132 lines (131 loc) • 8.32 kB
JavaScript
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs";
import { Et as _enum, Jn as string, Kt as custom, Lt as boolean, Pn as number, or as union, xn as literal } from "./schemas-BOYIvvln.mjs";
import { i as workerProtocolObject, r as workerProtocolIdentifier, t as WorkerGatewayNamespace } from "./protocol-record-BIYtFogM.mjs";
import { o as NodeWorkerWorkspaceTransferInputSchema } from "./node-workspace-transfer-protocol-Y75QFYww.mjs";
import { r as isWorkspaceInspectionCommand } from "./workspace-inspection-protocol-DPng6d5L.mjs";
import path from "node:path";
//#region src/worker/node-workspace-protocol.ts
const REQUEST_MAX_BYTES = 262144;
const NODE_WORKER_WORKSPACE_STDIN_MAX_BYTES = 131072;
const OUTPUT_MAX_BYTES = 65536;
const STDERR_MAX_BYTES = 16384;
const ARGV_MAX_ITEMS = 128;
const ARG_MAX_BYTES = 131072;
const TIMEOUT_MAX_MS = 6e5;
const NODE_WORKSPACE_DRAIN_COMMAND = "openclaw-internal-workspace-drain";
const SeedKey = string().regex(/^[a-f0-9]{64}$/u);
const WorkspaceProcessId = string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u);
const WorkspaceProcess = workerProtocolObject({
action: _enum([
"start",
"status",
"stop"
]),
processId: WorkspaceProcessId
});
const SeedInput = union([workerProtocolObject({
action: literal("apply"),
key: SeedKey
}), workerProtocolObject({
action: literal("store"),
key: SeedKey,
maxAgeMs: number().int().min(0).max(Number.MAX_SAFE_INTEGER)
})]);
const WorkspaceInput = workerProtocolObject({
gatewayNamespace: WorkerGatewayNamespace,
environmentId: workerProtocolIdentifier("environmentId"),
sessionId: workerProtocolIdentifier("sessionId"),
sessionKey: workerProtocolIdentifier("sessionKey", 1024).optional(),
preparationKey: custom((value) => typeof value === "string" && /^[a-f0-9]{64}$/u.test(value), { error: "INVALID_REQUEST: preparationKey must be a SHA-256 hex digest" }).optional(),
generation: custom((value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0, { error: "INVALID_REQUEST: generation must be a non-negative safe integer" }),
argv: custom((value) => Array.isArray(value) && value.length > 0 && value.length <= ARGV_MAX_ITEMS && value.every((arg) => typeof arg === "string" && arg.length > 0 && !arg.includes("\0") && Buffer.byteLength(arg, "utf8") <= ARG_MAX_BYTES), { error: "INVALID_REQUEST: argv must be a bounded non-empty string array" }).transform((argv) => [...argv]),
input: string({ error: "INVALID_REQUEST: workspace command input exceeds its bound" }).optional(),
timeoutMs: custom((value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 1 && value <= TIMEOUT_MAX_MS, { error: "INVALID_REQUEST: workspace command timeout is invalid" }).optional(),
resetWorkspace: boolean({ error: "INVALID_REQUEST: resetWorkspace must be a boolean" }).optional(),
transfer: NodeWorkerWorkspaceTransferInputSchema.optional(),
seed: SeedInput.optional(),
process: WorkspaceProcess.optional()
});
function parseJson(raw) {
if (!raw || Buffer.byteLength(raw, "utf8") > 4194304) throw new Error("INVALID_REQUEST: invalid node worker workspace request");
try {
return JSON.parse(raw);
} catch {
throw new Error("INVALID_REQUEST: malformed node worker workspace request");
}
}
function parseNodeWorkerWorkspaceExecInput(raw) {
const value = parseJson(raw);
const parsed = WorkspaceInput.safeParse(value);
if (!parsed.success) {
const issue = parsed.error.issues[0];
if (issue?.path[0] === "transfer") throw new Error("INVALID_REQUEST: workspace transfer is invalid");
if (issue?.path[0] === "process") throw new Error("INVALID_REQUEST: workspace process operation is invalid");
if (issue?.path[0] === "seed") {
const validKey = isRecord(value) && isRecord(value.seed) && SeedKey.safeParse(value.seed.key).success;
throw new Error(validKey ? "INVALID_REQUEST: workspace seed action or maxAgeMs is invalid" : "INVALID_REQUEST: workspace seed key must be a SHA-256 hex digest");
}
throw new Error(issue?.path.length ? issue.message : "INVALID_REQUEST: invalid node worker workspace request");
}
const input = parsed.data;
if (input.process && (input.seed || input.transfer || input.resetWorkspace !== void 0)) throw new Error("INVALID_REQUEST: workspace process owns its operation");
if (input.process && input.process.action !== "start" && (input.argv.length !== 1 || input.argv[0] !== "openclaw-internal-workspace-process" || input.input !== void 0)) throw new Error("INVALID_REQUEST: workspace process control accepts no command");
const inspection = isWorkspaceInspectionCommand(input.argv);
if (input.argv[0] === "openclaw-internal-workspace-drain" && (input.argv.length !== 1 || input.input !== void 0 || input.transfer !== void 0 || input.seed !== void 0 || input.process !== void 0 || input.resetWorkspace !== void 0)) throw new Error("INVALID_REQUEST: workspace drain owns its operation");
if (input.argv[0] === "openclaw-internal-workspace-inspect" && (!inspection || input.transfer !== void 0 || input.seed !== void 0 || input.process !== void 0 || input.resetWorkspace !== void 0)) throw new Error("INVALID_REQUEST: workspace inspection owns its operation");
if (!inspection && Buffer.byteLength(raw ?? "", "utf8") > REQUEST_MAX_BYTES) throw new Error("INVALID_REQUEST: workspace command request exceeds its bound");
if (input.input !== void 0 && Buffer.byteLength(input.input, "utf8") > (inspection ? 2097152 : 131072)) throw new Error("INVALID_REQUEST: workspace command input exceeds its bound");
if (input.seed !== void 0 && (input.transfer !== void 0 || input.resetWorkspace !== void 0)) throw new Error("INVALID_REQUEST: workspace seed cannot combine with transfer or resetWorkspace");
return input;
}
const TruncatedBytes = number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional();
const WorkspaceResult = workerProtocolObject({
workspaceDir: string().max(4096).refine((value) => path.posix.isAbsolute(value) || path.win32.isAbsolute(value)),
stdout: string(),
stderr: string().refine((value) => Buffer.byteLength(value, "utf8") <= STDERR_MAX_BYTES),
code: number().int().min(Number.MIN_SAFE_INTEGER).max(Number.MAX_SAFE_INTEGER).nullable(),
signal: string().min(1).max(32).nullable(),
killed: boolean(),
termination: _enum([
"exit",
"timeout",
"no-output-timeout",
"signal"
]),
stdoutTruncatedBytes: TruncatedBytes,
stderrTruncatedBytes: TruncatedBytes,
noOutputTimedOut: boolean().optional(),
outputLimitExceeded: boolean().optional(),
outputErrorStream: _enum(["stdout", "stderr"]).optional(),
process: workerProtocolObject({
processId: WorkspaceProcessId,
state: _enum(["running", "exited"])
}).optional()
});
function parseNodeWorkerWorkspaceExecResult(value, argv = []) {
const parsed = WorkspaceResult.safeParse(value);
if (!parsed.success || Buffer.byteLength(parsed.data.stdout, "utf8") > (isWorkspaceInspectionCommand(argv) ? 2097152 : OUTPUT_MAX_BYTES)) return null;
return value;
}
function projectNodeWorkerWorkspaceExecResult(workspaceDir, result, argv = []) {
const parsed = parseNodeWorkerWorkspaceExecResult({
workspaceDir,
stdout: result.stdout,
stderr: result.stderr,
code: result.code,
signal: result.signal,
killed: result.killed,
termination: result.termination,
...result.stdoutTruncatedBytes === void 0 ? {} : { stdoutTruncatedBytes: result.stdoutTruncatedBytes },
...result.stderrTruncatedBytes === void 0 ? {} : { stderrTruncatedBytes: result.stderrTruncatedBytes },
...result.noOutputTimedOut === void 0 ? {} : { noOutputTimedOut: result.noOutputTimedOut },
...result.outputLimitExceeded === void 0 ? {} : { outputLimitExceeded: result.outputLimitExceeded },
...result.outputErrorStream === void 0 ? {} : { outputErrorStream: result.outputErrorStream }
}, argv);
if (!parsed) throw new Error("node worker workspace result violated its bounded contract");
return parsed;
}
const NODE_WORKER_WORKSPACE_STDOUT_MAX_BYTES = OUTPUT_MAX_BYTES;
const NODE_WORKER_WORKSPACE_STDERR_MAX_BYTES = STDERR_MAX_BYTES;
//#endregion
export { parseNodeWorkerWorkspaceExecInput as a, NODE_WORKSPACE_DRAIN_COMMAND as i, NODE_WORKER_WORKSPACE_STDIN_MAX_BYTES as n, parseNodeWorkerWorkspaceExecResult as o, NODE_WORKER_WORKSPACE_STDOUT_MAX_BYTES as r, projectNodeWorkerWorkspaceExecResult as s, NODE_WORKER_WORKSPACE_STDERR_MAX_BYTES as t };