openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
131 lines (130 loc) • 5.07 kB
JavaScript
import { t as mergeDeep } from "./deep-merge-B-AVx-Uc.mjs";
import { t as readByteStreamWithLimit } from "./read-byte-stream-with-limit-CNew-qG0.mjs";
import { createReadStream, existsSync } from "node:fs";
import path from "node:path";
import { TextDecoder } from "node:util";
//#region src/commands/agent-exec-input.ts
const AGENT_EXEC_MESSAGE_MAX_BYTES = 4194304;
const UTF8_DECODER = new TextDecoder("utf-8", { fatal: true });
function decodePrompt(bytes, source) {
let value;
try {
value = UTF8_DECODER.decode(bytes).replace(/^\uFEFF/, "");
} catch {
throw new Error(`${source} must be valid UTF-8`);
}
if (!value.trim()) throw new Error(`${source} is empty`);
return value;
}
async function readPromptStream(stream, source) {
return decodePrompt(await readByteStreamWithLimit(stream, {
maxBytes: AGENT_EXEC_MESSAGE_MAX_BYTES,
onOverflow: () => /* @__PURE__ */ new Error(`${source} exceeds ${String(AGENT_EXEC_MESSAGE_MAX_BYTES)} bytes`)
}), source);
}
/** Resolve the one allowed prompt source for `agent exec`. */
async function resolveAgentExecPrompt(positionalMessage, messageFile, stdin = process.stdin) {
const file = messageFile?.trim();
if (positionalMessage !== void 0 && file) throw new Error("Use either the prompt argument or --message-file, not both.");
if (messageFile !== void 0 && !file) throw new Error("--message-file must not be empty.");
if (file) {
const stream = file === "-" ? stdin : createReadStream(file);
try {
return await readPromptStream(stream, file === "-" ? "stdin" : `Message file ${file}`);
} catch (error) {
if (file === "-" || !(error instanceof Error) || !("code" in error)) throw error;
if (error.code === "ENOENT") throw new Error(`Message file not found: ${file}`, { cause: error });
throw error;
}
}
if (!positionalMessage?.trim()) throw new Error("Missing prompt. Pass text or use --message-file <path>.");
return positionalMessage;
}
/**
* Keep state under exec's lock and bind every agent to the requested folder.
* Per-agent workspaces outrank defaults; ACP cwd can redirect the native harness.
* Channel binding cwd needs no adjustment because exec matches no channel.
*/
function pinExecAgentLocations(base, cwd) {
const { session, ...root } = base;
const { store: _store, ...sessionWithoutStore } = session ?? {};
const withoutSessionStore = session ? {
...root,
session: sessionWithoutStore
} : base;
const entries = withoutSessionStore.agents?.entries;
if (!entries) return withoutSessionStore;
return {
...withoutSessionStore,
agents: {
...withoutSessionStore.agents,
entries: Object.fromEntries(Object.entries(entries).map(([id, entry]) => {
const { agentDir: _agentDir, runtime, ...rest } = entry;
if (runtime?.type !== "acp" || runtime.acp?.cwd === void 0) return [id, {
...rest,
workspace: cwd,
...runtime ? { runtime } : {}
}];
const { cwd: _cwd, ...acp } = runtime.acp;
return [id, {
...rest,
workspace: cwd,
runtime: {
...runtime,
acp
}
}];
}))
}
};
}
/**
* Coding one-shot defaults. These merge *under* the resolved config so an
* operator who configured a tool profile, shell env, or sandbox keeps it;
* notably exec must never downgrade a configured sandbox to `off`.
*/
function buildExecConfigDefaults() {
return {
env: { shellEnv: { enabled: false } },
agents: { defaults: { sandbox: { mode: "off" } } },
tools: {
profile: "coding",
fs: { workspaceOnly: true },
exec: { mode: "full" }
}
};
}
/**
* Config is a credential source (provider keys, headers, env and shell imports).
* Environment-only execution therefore skips it entirely; ordinary exec inherits it.
*/
async function resolveExecBaseConfig(opts) {
if (opts.config && (opts.isolated || opts.authEnvOnly === true)) {
const conflicting = opts.isolated ? "--isolated" : "--auth-env-only";
throw new Error(`--config cannot be combined with ${conflicting}.`);
}
if (opts.isolated || opts.authEnvOnly === true) {
const { migratePersistedImplicitMainRoster } = await import("./legacy.roster-BZQw6dFo.mjs");
const { coerceConfig } = await import("./io.read-helpers-B7jvxAiR.mjs");
return coerceConfig(migratePersistedImplicitMainRoster({}).config);
}
const { createConfigIO, getRuntimeConfig } = await import("./io-BFXJQ9PP.mjs");
if (!opts.config) return getRuntimeConfig();
const io = createConfigIO({ configPath: path.resolve(opts.config) });
if (!existsSync(io.configPath)) throw new Error(`--config file not found: ${io.configPath}`);
return io.loadConfig();
}
function buildExecRunConfig(params) {
const opts = params.opts ?? {};
const base = pinExecAgentLocations(params.base, params.cwd);
return mergeDeep(mergeDeep(buildExecConfigDefaults(), base), {
agents: { defaults: {
workspace: params.cwd,
skipBootstrap: true,
...opts.localModelLean ? { experimental: { localModelLean: true } } : {}
} },
skills: { load: { watch: false } }
});
}
//#endregion
export { resolveAgentExecPrompt as n, resolveExecBaseConfig as r, buildExecRunConfig as t };