openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
523 lines (522 loc) • 23.6 kB
JavaScript
import { C as parseStrictNonNegativeInteger } from "./number-coercion-CLj0HTDM.js";
import { a as writeRuntimeJson, o as writeRuntimeStdout } from "./runtime-CF2WjnNZ.js";
import { t as mergeDeep } from "./deep-merge-DhxZfAYh.js";
import { t as formatCliCommand } from "./command-format-C7YfyMTd.js";
import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js";
import { n as isExecutionIdentityCollectionEnabled } from "./audit-config-BKFiXlHH.js";
import { n as getInstallationTarget, t as LOCAL_INSTALLATION_TARGET_UNSUPPORTED } from "./installation-target-context-BP05Rs6C.js";
import { a as createAgentToolExecutionBudget } from "./agent-tool-source-execution-guard-C6m-5OB2.js";
import { n as findAgentRunTerminalOutcome } from "./agent-run-terminal-error-BLySVFXs.js";
import { t as readByteStreamWithLimit } from "./read-byte-stream-with-limit-CNew-qG0.js";
import { createReadStream, existsSync } from "node:fs";
import { TextDecoder } from "node:util";
import path from "node:path";
import fs$1 from "node:fs/promises";
import os from "node:os";
import { randomUUID } from "node:crypto";
//#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;
}
/**
* Facts owned by this invocation rather than by any config, so they win over
* both the ambient config and `--config`: exec is always scoped to the folder
* it was pointed at, a one-shot turn never bootstraps, and explicit flags
* outrank whatever the resolved config says.
*/
/**
* Drops inherited state and workspace location overrides, which outrank the
* facts this invocation owns. `session.store` and `agentDir` can redirect state
* outside the invocation root, where its lock or temporary cleanup cannot own
* it; a native harness `runtime.acp.cwd` can make the turn edit the wrong repo.
* `agents.bindings[].acp.cwd` needs no equivalent because exec runs no channel,
* so no binding matches.
*/
function stripInheritedAgentLocations(base) {
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,
...runtime ? { runtime } : {}
}];
const { cwd: _cwd, ...acp } = runtime.acp;
return [id, {
...rest,
runtime: {
...runtime,
acp
}
}];
}))
}
};
}
function buildExecRunOverlay(params) {
const entries = Object.keys(params.base.agents?.entries ?? {});
return {
agents: {
defaults: {
workspace: params.cwd,
skipBootstrap: true,
...params.opts.localModelLean ? { experimental: { localModelLean: true } } : {}
},
...entries.length > 0 ? { entries: Object.fromEntries(entries.map((id) => [id, { workspace: params.cwd }])) } : {}
},
skills: { load: { watch: false } }
};
}
/**
* 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" }
}
};
}
/**
* Resolves the config exec runs against. Default is the ambient config, so a
* one-shot turn behaves like other folder-scoped coding CLIs and can reach
* configured providers, credentials, and `agentRuntime` harness choices.
*
* `--auth-env-only` opts out of that inheritance entirely rather than trying to
* launder the resolved config. A config is a credential store by design -- API
* keys, secret headers, request auth, an inline `env` block, and login-shell
* import all feed provider auth -- so the only closed way to promise
* environment-only credentials is to not read 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-DY965anC.js");
const { coerceConfig } = await import("./io.read-helpers-DaS5i-uJ.js");
return coerceConfig(migratePersistedImplicitMainRoster({}).config);
}
const { createConfigIO, getRuntimeConfig } = await import("./io-ssMwu02B.js");
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 = stripInheritedAgentLocations(params.base);
return mergeDeep(mergeDeep(buildExecConfigDefaults(), base), buildExecRunOverlay({
base,
cwd: params.cwd,
opts
}));
}
//#endregion
//#region src/commands/agent-exec-result.ts
function projectAgentExecPayload(payload) {
return {
...typeof payload.text === "string" ? { text: payload.text } : {},
...payload.mediaUrl !== void 0 ? { mediaUrl: payload.mediaUrl } : {},
...Array.isArray(payload.mediaUrls) ? { mediaUrls: [...payload.mediaUrls] } : {},
...payload.isError === true ? { isError: true } : {},
...payload.isReasoning === true ? { isReasoning: true } : {},
...payload.isCommentary === true ? { isCommentary: true } : {}
};
}
function finalTextFromResult(result, payloads, allowMetadataFallback) {
return payloads.filter((payload) => payload.isError !== true && payload.isReasoning !== true && payload.isCommentary !== true && typeof payload.text === "string" && payload.text.trim().length > 0).map((payload) => payload.text.trimEnd()).join("\n") || (allowMetadataFallback ? result.meta.finalAssistantVisibleText?.trimEnd() : "") || "";
}
function firstErrorPayload(result) {
return result.payloads?.find((payload) => payload.isError === true);
}
/** Classify an embedded result into the strict `agent exec` process contract. */
function classifyAgentExecResult(result, fallbackExhausted = false, projectedErrorPayload) {
const meta = result.meta;
const errorPayload = firstErrorPayload(result);
const errorPayloadMessage = typeof projectedErrorPayload === "string" ? projectedErrorPayload : typeof errorPayload?.text === "string" && errorPayload.text.trim() ? errorPayload.text : void 0;
const hasErrorPayload = projectedErrorPayload !== void 0 || errorPayload !== void 0;
const payloads = (result.payloads ?? []).map(projectAgentExecPayload);
if (typeof projectedErrorPayload === "string") {
const projectedErrorIndex = payloads.findIndex((payload) => payload.isError !== true && payload.text === projectedErrorPayload);
if (projectedErrorIndex >= 0) payloads[projectedErrorIndex] = {
...payloads[projectedErrorIndex],
isError: true
};
}
const timeout = meta.stopReason === "timeout" || meta.timeoutPhase !== void 0;
const failed = fallbackExhausted || meta.aborted === true || meta.error !== void 0 || meta.stopReason === "error" || hasErrorPayload;
const status = timeout ? "timeout" : failed ? "error" : "ok";
const errorMessage = timeout ? meta.error?.message ?? errorPayloadMessage ?? "Agent run timed out" : fallbackExhausted ? meta.error?.message ?? errorPayloadMessage ?? "All model fallback candidates failed" : meta.error?.message ?? errorPayloadMessage ?? (failed ? "Agent run failed" : void 0);
const errorKind = timeout ? "timeout" : fallbackExhausted ? "fallback_exhausted" : meta.error?.kind ? meta.error.kind : meta.aborted ? "aborted" : hasErrorPayload ? "error_payload" : failed ? "agent_error" : void 0;
const agentMeta = meta.agentMeta;
return {
ok: status === "ok",
status,
final: finalTextFromResult(result, payloads, !hasErrorPayload),
payloads,
...agentMeta?.usage ? { usage: agentMeta.usage } : {},
...agentMeta?.costUsd !== void 0 ? { costUsd: agentMeta.costUsd } : {},
...agentMeta?.codeModeEngaged !== void 0 ? { codeModeEngaged: agentMeta.codeModeEngaged } : {},
...agentMeta?.assistantTurns !== void 0 ? { assistantTurns: agentMeta.assistantTurns } : {},
...agentMeta?.bridgeCalls ? { bridgeCalls: agentMeta.bridgeCalls } : {},
...meta.toolSummary ? { toolSummary: meta.toolSummary } : {},
model: agentMeta?.model ?? null,
provider: agentMeta?.provider ?? null,
sessionId: agentMeta?.sessionId ?? "",
...errorMessage && errorKind ? { error: {
message: errorMessage,
kind: errorKind
} } : {}
};
}
//#endregion
//#region src/commands/agent-exec.ts
const AGENT_EXEC_DEFAULT_TIMEOUT_SECONDS = 600;
function exitCodeForEnvelope(envelope) {
return envelope.status === "ok" ? 0 : envelope.status === "timeout" ? 2 : 1;
}
function normalizeCodeMode(value) {
if (value === void 0) return;
if (value === "direct") return false;
if (value === "auto") return "auto";
if (value === "code") return true;
throw new Error("--code-mode must be one of direct, auto, code.");
}
function normalizeTimeoutSeconds(value) {
const raw = value ?? String(AGENT_EXEC_DEFAULT_TIMEOUT_SECONDS);
if (parseStrictNonNegativeInteger(raw) === void 0) throw new Error("--timeout must be a non-negative integer in seconds.");
return raw;
}
function normalizeFallbacks(model, values) {
const fallbacks = (values ?? []).map((value) => value.trim()).filter(Boolean);
if (fallbacks.length > 0 && !model?.trim()) throw new Error("--fallback requires --model so the primary model is explicit.");
return fallbacks;
}
async function requireDirectory(value, label) {
const resolved = path.resolve(value);
let stat;
try {
stat = await fs$1.stat(resolved);
} catch (error) {
throw new Error(`${label} does not exist: ${resolved}`, { cause: error });
}
if (!stat.isDirectory()) throw new Error(`${label} is not a directory: ${resolved}`);
return resolved;
}
function setAgentExecEnvironment(params) {
const previousStateDir = process.env.OPENCLAW_STATE_DIR;
const previousConfigPath = process.env.OPENCLAW_CONFIG_PATH;
const previousWorkspaceDir = process.env.OPENCLAW_WORKSPACE_DIR;
process.env.OPENCLAW_STATE_DIR = params.stateDir;
delete process.env.OPENCLAW_CONFIG_PATH;
process.env.OPENCLAW_WORKSPACE_DIR = params.cwd;
return () => {
if (previousStateDir === void 0) delete process.env.OPENCLAW_STATE_DIR;
else process.env.OPENCLAW_STATE_DIR = previousStateDir;
if (previousConfigPath === void 0) delete process.env.OPENCLAW_CONFIG_PATH;
else process.env.OPENCLAW_CONFIG_PATH = previousConfigPath;
if (previousWorkspaceDir === void 0) delete process.env.OPENCLAW_WORKSPACE_DIR;
else process.env.OPENCLAW_WORKSPACE_DIR = previousWorkspaceDir;
};
}
function formatActiveGatewayExecRefusal(identity) {
return `A Gateway is running for this state directory (pid ${identity.pid}, port ${identity.port}). Omit --state-dir to use isolated temporary state, or stop the Gateway first (${formatCliCommand("openclaw gateway stop")}).`;
}
function isStructuredTimeoutError(error) {
if (findAgentRunTerminalOutcome(error)?.status === "timeout") return true;
let candidate = error;
for (let depth = 0; depth < 4; depth += 1) {
if (!candidate || typeof candidate !== "object") return false;
const record = candidate;
if (record.name === "TimeoutError" || record.code === "ETIMEDOUT" || record.reason === "timeout") return true;
candidate = record.cause;
}
return false;
}
function errorEnvelope(error, sessionId) {
const status = isStructuredTimeoutError(error) ? "timeout" : "error";
return {
ok: false,
status,
final: "",
payloads: [],
model: null,
provider: null,
sessionId,
error: {
message: formatErrorMessage(error),
kind: status === "timeout" ? "timeout" : "exception"
}
};
}
function writeAgentExecOutput(runtime, envelope, json) {
if (json) writeRuntimeJson(runtime, envelope);
else if (envelope.final) writeRuntimeStdout(runtime, envelope.final);
if (!envelope.ok && envelope.error) runtime.error(envelope.error.message);
}
/** Run one isolated embedded agent turn and project its stable CLI result. */
async function agentExecCommand(positionalMessage, opts, runtime, deps = {}) {
const sessionId = randomUUID();
const abortController = new AbortController();
const signal = deps.abortSignal ? AbortSignal.any([abortController.signal, deps.abortSignal]) : abortController.signal;
const toolBudget = createAgentToolExecutionBudget({
maxToolCalls: deps.maxToolCalls,
signal,
abort: (reason) => abortController.abort(reason),
isCurrent: deps.isCurrent
});
let timeoutTimer;
let processScopeKey;
let commandResult;
let temporaryStateDir;
let restoreEnvironment;
let restoreConfigEnvironment;
let restoreRuntimeConfigSnapshot;
let runtimePaths;
let configIo;
let stopLocalAuditWriter;
let stateLock;
let signalBridge;
try {
signal.throwIfAborted();
if (deps.maxToolCalls !== void 0 && (!Number.isSafeInteger(deps.maxToolCalls) || deps.maxToolCalls < 0)) throw new Error("maxToolCalls must be a non-negative safe integer");
if (deps.timeoutMs !== void 0) {
if (!Number.isSafeInteger(deps.timeoutMs) || deps.timeoutMs <= 0) throw new Error("timeoutMs must be a positive safe integer");
timeoutTimer = setTimeout(() => abortController.abort(new DOMException("Agent execution deadline elapsed", "TimeoutError")), deps.timeoutMs);
timeoutTimer.unref();
}
const codeModeOverride = normalizeCodeMode(opts.codeMode);
const prompt = await resolveAgentExecPrompt(positionalMessage, opts.messageFile, deps.stdin ?? process.stdin);
const cwd = await requireDirectory(opts.cwd ?? process.cwd(), "Working directory");
const stateDir = opts.stateDir ? await requireDirectory(opts.stateDir, "State directory") : await fs$1.mkdtemp(path.join(os.tmpdir(), "openclaw-agent-exec-"));
temporaryStateDir = opts.stateDir ? void 0 : stateDir;
configIo = await import("./io-ssMwu02B.js");
const previousRuntimeConfigSnapshot = configIo.getRuntimeConfigSnapshot();
const snapshotIo = configIo;
restoreRuntimeConfigSnapshot = () => {
if (previousRuntimeConfigSnapshot) snapshotIo.setRuntimeConfigSnapshot(previousRuntimeConfigSnapshot);
else snapshotIo.clearRuntimeConfigSnapshot();
};
const { restoreEnvChangesIfUnchanged, snapshotEnv } = configIo;
const envBeforeConfigLoad = snapshotEnv(process.env);
const baseConfig = deps.baseConfig ?? await resolveExecBaseConfig(opts);
const envAfterConfigLoad = snapshotEnv(process.env);
restoreConfigEnvironment = () => restoreEnvChangesIfUnchanged({
env: process.env,
before: envBeforeConfigLoad,
after: envAfterConfigLoad
});
const runConfig = buildExecRunConfig({
base: baseConfig,
cwd,
opts
});
const pluginInstallContext = opts.isolated !== true && opts.authEnvOnly !== true ? await import("./install-root-context-C6EBQFHy.js") : void 0;
const pluginInstallRoots = pluginInstallContext?.resolvePluginInstallRoots();
const timeout = normalizeTimeoutSeconds(deps.timeoutMs === void 0 ? opts.timeout : String(Math.ceil(deps.timeoutMs / 1e3)));
const fallbacks = normalizeFallbacks(opts.model, deps.modelFallbacksOverride ?? opts.fallback);
const { resolveAgentDir, resolveAmbientOwnerAgentId } = await import("./agent-scope-config-K8hF78lq.js");
const execAgentId = resolveAmbientOwnerAgentId(baseConfig, deps.agentId, {
surface: "agent exec",
hint: "Set agents.defaults.systemAgent.agentId."
});
if (getInstallationTarget()) {
const [{ resolveSandboxConfigForAgent }, { resolveExecToolConfig }] = await Promise.all([import("./config-Bk-MkTzj.js"), import("./lazy-exec-tool-jWvqH5jz.js")]);
const execHost = resolveExecToolConfig({
cfg: runConfig,
agentId: execAgentId
}).host;
if (resolveSandboxConfigForAgent(runConfig, execAgentId).mode !== "off" || execHost === "node" || execHost === "sandbox") throw new Error(LOCAL_INSTALLATION_TARGET_UNSUPPORTED);
}
const storedAuthAgentDir = resolveAgentDir(baseConfig, execAgentId);
runtimePaths = await import("./paths-DIpSsLs8.js");
const storedAuthStateDir = runtimePaths.resolveStateDir();
processScopeKey = deps.timeoutMs !== void 0 || deps.maxToolCalls !== void 0 ? `agent:${execAgentId}:agent-exec:${sessionId}` : void 0;
restoreEnvironment = setAgentExecEnvironment({
stateDir,
cwd
});
runtimePaths.pinRuntimePaths();
if (opts.stateDir) {
const { acquireEmbeddedStateLock, createEmbeddedStateSignalBridge } = await import("./embedded-state-lock-6tAlep1Z.js");
signalBridge = createEmbeddedStateSignalBridge(deps.process ?? process);
stateLock = await acquireEmbeddedStateLock({
options: deps.gatewayLockOptions,
signal: signalBridge.signal,
formatActiveGatewayRefusal: formatActiveGatewayExecRefusal
});
}
snapshotIo.setRuntimeConfigSnapshot(runConfig);
if (isExecutionIdentityCollectionEnabled(runConfig)) try {
stopLocalAuditWriter = (await import("./agent-local-audit-CdkbqJHA.js")).startAgentLocalAuditWriter({ stateDir });
} catch {}
const [{ withAuthProfileStoreAgentDir, withEnvOnlyAuthProfileStore }, { withHostExecInheritedEnvOmitted }, { listKnownProviderAuthEnvVarNames }, runAgent] = await Promise.all([
import("./auth-profiles-DH_4tHev.js"),
import("./host-env-security-wD-wR_Lb.js"),
import("./provider-env-vars-DV--O0_r.js"),
deps.runAgent ? Promise.resolve(deps.runAgent) : import("./agent-BD0xoiB7.js").then((module) => module.agentCommand)
]);
let fallbackExhausted = false;
let resultErrorPayload;
const silentRuntime = {
log: () => {},
error: (...args) => runtime.error(...args),
exit: (code, exitOpts) => runtime.exit(code, exitOpts)
};
const invoke = async () => {
signal.throwIfAborted();
if (deps.isCurrent?.() === false) throw new Error("Agent execution scope is no longer active");
return await runAgent({
message: prompt,
sessionId,
...processScopeKey ? { sessionKey: processScopeKey } : {},
agentId: execAgentId,
workspaceDir: cwd,
cwd,
model: opts.model,
codeModeOverride,
thinking: opts.thinking,
timeout,
modelFallbacksOverride: fallbacks.length > 0 || deps.modelFallbacksOverride !== void 0 ? fallbacks : void 0,
cleanupBundleMcpOnRunEnd: true,
cleanupCliLiveSessionOnRunEnd: true,
oneShotCliRun: true,
abortSignal: signalBridge ? AbortSignal.any([signal, signalBridge.signal]) : signal,
onModelFallbackExhausted: () => {
fallbackExhausted = true;
},
onResultErrorPayload: (message) => {
resultErrorPayload = message ?? true;
}
}, silentRuntime);
};
const runWithPluginInstallRoots = () => pluginInstallContext && pluginInstallRoots ? pluginInstallContext.withPluginInstallRoots(pluginInstallRoots, invoke) : invoke();
const runWithAuthScope = () => opts.authEnvOnly === true ? withEnvOnlyAuthProfileStore(runWithPluginInstallRoots) : withAuthProfileStoreAgentDir(storedAuthAgentDir, storedAuthStateDir, runWithPluginInstallRoots);
const result = await toolBudget.run(() => withHostExecInheritedEnvOmitted(listKnownProviderAuthEnvVarNames({ env: process.env }), runWithAuthScope));
signal.throwIfAborted();
if (!result) throw new Error("Agent run returned no result");
const envelope = classifyAgentExecResult(result, fallbackExhausted, resultErrorPayload);
if (!envelope.sessionId) envelope.sessionId = sessionId;
commandResult = {
envelope,
exitCode: exitCodeForEnvelope(envelope),
toolCalls: toolBudget.toolCalls
};
} catch (error) {
const envelope = errorEnvelope(error, sessionId);
commandResult = {
envelope,
exitCode: exitCodeForEnvelope(envelope),
toolCalls: toolBudget.toolCalls
};
}
let cleanupError;
clearTimeout(timeoutTimer);
if (processScopeKey) {
abortController.abort(/* @__PURE__ */ new Error("Agent execution completed"));
try {
const { getProcessSupervisor } = await import("./supervisor-D53S3DI6.js");
const supervisor = getProcessSupervisor();
supervisor.cancelScope(processScopeKey);
await supervisor.waitForScope?.(processScopeKey);
} catch (error) {
cleanupError = error;
}
}
await stopLocalAuditWriter?.().catch(() => void 0);
await stateLock?.release().catch((error) => {
cleanupError ??= error;
});
const runCleanupStep = (step) => {
try {
step();
} catch (error) {
cleanupError ??= error;
}
};
runCleanupStep(() => restoreEnvironment?.());
runCleanupStep(() => restoreConfigEnvironment?.());
runCleanupStep(() => configIo?.clearConfigCache());
runCleanupStep(() => restoreRuntimeConfigSnapshot ? restoreRuntimeConfigSnapshot() : configIo?.clearRuntimeConfigSnapshot());
runCleanupStep(() => runtimePaths?.pinRuntimePaths());
if (temporaryStateDir) try {
await fs$1.rm(temporaryStateDir, {
recursive: true,
force: true
});
} catch (error) {
cleanupError ??= error;
}
if (cleanupError) {
const cleanupFailure = /* @__PURE__ */ new Error(`Agent exec cleanup failed: ${formatErrorMessage(cleanupError)}`);
if (commandResult.envelope.ok) {
const envelope = errorEnvelope(cleanupFailure, sessionId);
commandResult = {
envelope,
exitCode: exitCodeForEnvelope(envelope),
toolCalls: toolBudget.toolCalls
};
} else runtime.error(cleanupFailure.message);
}
const receivedSignal = signalBridge?.getReceivedSignal();
signalBridge?.dispose();
if (receivedSignal) {
runtime.exit(receivedSignal === "SIGINT" ? 130 : 143, { resetStream: process.stderr });
return commandResult;
}
writeAgentExecOutput(runtime, commandResult.envelope, opts.json === true);
return commandResult;
}
//#endregion
export { agentExecCommand };