Agents: narrow cli runner hotspot tests

This commit is contained in:
Peter Steinberger
2026-04-07 02:26:23 +08:00
parent 9f4c2caf06
commit ff414df15f
2 changed files with 229 additions and 218 deletions

View File

@@ -6,11 +6,59 @@ import {
setupCliRunnerTestModule, setupCliRunnerTestModule,
supervisorSpawnMock, supervisorSpawnMock,
} from "./cli-runner.test-support.js"; } from "./cli-runner.test-support.js";
import { executePreparedCliRun } from "./cli-runner/execute.js";
import { resolveCliNoOutputTimeoutMs } from "./cli-runner/helpers.js"; import { resolveCliNoOutputTimeoutMs } from "./cli-runner/helpers.js";
import type { PreparedCliRunContext } from "./cli-runner/types.js";
function buildPreparedContext(params?: {
sessionKey?: string;
cliSessionId?: string;
runId?: string;
}): PreparedCliRunContext {
const backend = {
command: "codex",
args: ["exec", "--json"],
output: "text" as const,
input: "arg" as const,
modelArg: "--model",
sessionMode: "existing" as const,
serialize: true,
};
return {
params: {
sessionId: "s1",
sessionKey: params?.sessionKey,
sessionFile: "/tmp/session.jsonl",
workspaceDir: "/tmp",
prompt: "hi",
provider: "codex-cli",
model: "gpt-5.4",
timeoutMs: 1_000,
runId: params?.runId ?? "run-2",
},
started: Date.now(),
workspaceDir: "/tmp",
backendResolved: {
id: "codex-cli",
config: backend,
bundleMcp: false,
pluginId: "openai",
},
preparedBackend: {
backend,
env: {},
},
reusableCliSession: params?.cliSessionId ? { sessionId: params.cliSessionId } : {},
modelId: "gpt-5.4",
normalizedModel: "gpt-5.4",
systemPrompt: "You are a helpful assistant.",
systemPromptReport: {} as PreparedCliRunContext["systemPromptReport"],
bootstrapPromptWarningLines: [],
};
}
describe("runCliAgent reliability", () => { describe("runCliAgent reliability", () => {
it("fails with timeout when no-output watchdog trips", async () => { it("fails with timeout when no-output watchdog trips", async () => {
const runCliAgent = await setupCliRunnerTestModule();
supervisorSpawnMock.mockResolvedValueOnce( supervisorSpawnMock.mockResolvedValueOnce(
createManagedRun({ createManagedRun({
reason: "no-output-timeout", reason: "no-output-timeout",
@@ -25,22 +73,14 @@ describe("runCliAgent reliability", () => {
); );
await expect( await expect(
runCliAgent({ executePreparedCliRun(
sessionId: "s1", buildPreparedContext({ cliSessionId: "thread-123", runId: "run-2" }),
sessionFile: "/tmp/session.jsonl", "thread-123",
workspaceDir: "/tmp", ),
prompt: "hi",
provider: "codex-cli",
model: "gpt-5.4",
timeoutMs: 1_000,
runId: "run-2",
cliSessionId: "thread-123",
}),
).rejects.toThrow("produced no output"); ).rejects.toThrow("produced no output");
}); });
it("enqueues a system event and heartbeat wake on no-output watchdog timeout for session runs", async () => { it("enqueues a system event and heartbeat wake on no-output watchdog timeout for session runs", async () => {
const runCliAgent = await setupCliRunnerTestModule();
supervisorSpawnMock.mockResolvedValueOnce( supervisorSpawnMock.mockResolvedValueOnce(
createManagedRun({ createManagedRun({
reason: "no-output-timeout", reason: "no-output-timeout",
@@ -55,18 +95,14 @@ describe("runCliAgent reliability", () => {
); );
await expect( await expect(
runCliAgent({ executePreparedCliRun(
sessionId: "s1", buildPreparedContext({
sessionKey: "agent:main:main", sessionKey: "agent:main:main",
sessionFile: "/tmp/session.jsonl", cliSessionId: "thread-123",
workspaceDir: "/tmp", runId: "run-2b",
prompt: "hi", }),
provider: "codex-cli", "thread-123",
model: "gpt-5.4", ),
timeoutMs: 1_000,
runId: "run-2b",
cliSessionId: "thread-123",
}),
).rejects.toThrow("produced no output"); ).rejects.toThrow("produced no output");
expect(enqueueSystemEventMock).toHaveBeenCalledTimes(1); expect(enqueueSystemEventMock).toHaveBeenCalledTimes(1);
@@ -81,7 +117,6 @@ describe("runCliAgent reliability", () => {
}); });
it("fails with timeout when overall timeout trips", async () => { it("fails with timeout when overall timeout trips", async () => {
const runCliAgent = await setupCliRunnerTestModule();
supervisorSpawnMock.mockResolvedValueOnce( supervisorSpawnMock.mockResolvedValueOnce(
createManagedRun({ createManagedRun({
reason: "overall-timeout", reason: "overall-timeout",
@@ -96,17 +131,10 @@ describe("runCliAgent reliability", () => {
); );
await expect( await expect(
runCliAgent({ executePreparedCliRun(
sessionId: "s1", buildPreparedContext({ cliSessionId: "thread-123", runId: "run-3" }),
sessionFile: "/tmp/session.jsonl", "thread-123",
workspaceDir: "/tmp", ),
prompt: "hi",
provider: "codex-cli",
model: "gpt-5.4",
timeoutMs: 1_000,
runId: "run-3",
cliSessionId: "thread-123",
}),
).rejects.toThrow("exceeded timeout"); ).rejects.toThrow("exceeded timeout");
}); });

View File

@@ -2,7 +2,6 @@ import fs from "node:fs/promises";
import os from "node:os"; import os from "node:os";
import path from "node:path"; import path from "node:path";
import { beforeEach, describe, expect, it, vi } from "vitest"; import { beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { onAgentEvent, resetAgentEventsForTest } from "../infra/agent-events.js"; import { onAgentEvent, resetAgentEventsForTest } from "../infra/agent-events.js";
import { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js"; import { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js";
import { import {
@@ -13,10 +12,8 @@ import {
createManagedRun, createManagedRun,
mockSuccessfulCliRun, mockSuccessfulCliRun,
restoreCliRunnerPrepareTestDeps, restoreCliRunnerPrepareTestDeps,
runCliAgentWithBackendConfig,
setupCliRunnerTestModule, setupCliRunnerTestModule,
SMALL_PNG_BASE64, SMALL_PNG_BASE64,
stubBootstrapContext,
supervisorSpawnMock, supervisorSpawnMock,
} from "./cli-runner.test-support.js"; } from "./cli-runner.test-support.js";
import { executePreparedCliRun } from "./cli-runner/execute.js"; import { executePreparedCliRun } from "./cli-runner/execute.js";
@@ -26,8 +23,71 @@ import type { PreparedCliRunContext } from "./cli-runner/types.js";
beforeEach(() => { beforeEach(() => {
resetAgentEventsForTest(); resetAgentEventsForTest();
restoreCliRunnerPrepareTestDeps(); restoreCliRunnerPrepareTestDeps();
supervisorSpawnMock.mockClear();
}); });
function buildPreparedCliRunContext(params: {
provider: "claude-cli" | "codex-cli";
model: string;
runId: string;
prompt?: string;
backend?: Partial<PreparedCliRunContext["preparedBackend"]["backend"]>;
}): PreparedCliRunContext {
const baseBackend =
params.provider === "claude-cli"
? {
command: "claude",
args: ["-p", "--output-format", "stream-json"],
output: "jsonl" as const,
input: "stdin" as const,
modelArg: "--model",
systemPromptArg: "--append-system-prompt",
systemPromptWhen: "first" as const,
serialize: true,
}
: {
command: "codex",
args: ["exec", "--json"],
resumeArgs: ["exec", "resume", "{sessionId}", "--json"],
output: "text" as const,
input: "arg" as const,
modelArg: "--model",
sessionMode: "existing" as const,
serialize: true,
};
const backend = { ...baseBackend, ...params.backend };
return {
params: {
sessionId: "s1",
sessionFile: "/tmp/session.jsonl",
workspaceDir: "/tmp",
prompt: params.prompt ?? "hi",
provider: params.provider,
model: params.model,
timeoutMs: 1_000,
runId: params.runId,
},
started: Date.now(),
workspaceDir: "/tmp",
backendResolved: {
id: params.provider,
config: backend,
bundleMcp: params.provider === "claude-cli",
pluginId: params.provider === "claude-cli" ? "anthropic" : "openai",
},
preparedBackend: {
backend,
env: {},
},
reusableCliSession: {},
modelId: params.model,
normalizedModel: params.model,
systemPrompt: "You are a helpful assistant.",
systemPromptReport: {} as PreparedCliRunContext["systemPromptReport"],
bootstrapPromptWarningLines: [],
};
}
describe("runCliAgent spawn path", () => { describe("runCliAgent spawn path", () => {
it("does not inject hardcoded 'Tools are disabled' text into CLI arguments", async () => { it("does not inject hardcoded 'Tools are disabled' text into CLI arguments", async () => {
supervisorSpawnMock.mockResolvedValueOnce( supervisorSpawnMock.mockResolvedValueOnce(
@@ -93,7 +153,6 @@ describe("runCliAgent spawn path", () => {
}); });
it("pipes Claude prompts over stdin instead of argv", async () => { it("pipes Claude prompts over stdin instead of argv", async () => {
const runCliAgent = await setupCliRunnerTestModule();
supervisorSpawnMock.mockResolvedValueOnce( supervisorSpawnMock.mockResolvedValueOnce(
createManagedRun({ createManagedRun({
reason: "exit", reason: "exit",
@@ -107,16 +166,14 @@ describe("runCliAgent spawn path", () => {
}), }),
); );
await runCliAgent({ await executePreparedCliRun(
sessionId: "s1", buildPreparedCliRunContext({
sessionFile: "/tmp/session.jsonl", provider: "claude-cli",
workspaceDir: "/tmp", model: "sonnet",
prompt: "Explain this diff", runId: "run-stdin-claude",
provider: "claude-cli", prompt: "Explain this diff",
model: "sonnet", }),
timeoutMs: 1_000, );
runId: "run-stdin-claude",
});
const input = supervisorSpawnMock.mock.calls[0]?.[0] as { const input = supervisorSpawnMock.mock.calls[0]?.[0] as {
argv?: string[]; argv?: string[];
@@ -127,7 +184,6 @@ describe("runCliAgent spawn path", () => {
}); });
it("runs CLI through supervisor and returns payload", async () => { it("runs CLI through supervisor and returns payload", async () => {
const runCliAgent = await setupCliRunnerTestModule();
supervisorSpawnMock.mockResolvedValueOnce( supervisorSpawnMock.mockResolvedValueOnce(
createManagedRun({ createManagedRun({
reason: "exit", reason: "exit",
@@ -141,19 +197,16 @@ describe("runCliAgent spawn path", () => {
}), }),
); );
const result = await runCliAgent({ const context = buildPreparedCliRunContext({
sessionId: "s1",
sessionFile: "/tmp/session.jsonl",
workspaceDir: "/tmp",
prompt: "hi",
provider: "codex-cli", provider: "codex-cli",
model: "gpt-5.4", model: "gpt-5.4",
timeoutMs: 1_000,
runId: "run-1", runId: "run-1",
cliSessionId: "thread-123",
}); });
context.reusableCliSession = { sessionId: "thread-123" };
expect(result.payloads?.[0]?.text).toBe("ok"); const result = await executePreparedCliRun(context, "thread-123");
expect(result.text).toBe("ok");
const input = supervisorSpawnMock.mock.calls[0]?.[0] as { const input = supervisorSpawnMock.mock.calls[0]?.[0] as {
argv?: string[]; argv?: string[];
mode?: string; mode?: string;
@@ -171,7 +224,6 @@ describe("runCliAgent spawn path", () => {
}); });
it("cancels the managed CLI run when the abort signal fires", async () => { it("cancels the managed CLI run when the abort signal fires", async () => {
const runCliAgent = await setupCliRunnerTestModule();
const abortController = new AbortController(); const abortController = new AbortController();
let resolveWait!: (value: { let resolveWait!: (value: {
reason: reason:
@@ -215,17 +267,14 @@ describe("runCliAgent spawn path", () => {
cancel, cancel,
}); });
const runPromise = runCliAgent({ const context = buildPreparedCliRunContext({
sessionId: "s1",
sessionFile: "/tmp/session.jsonl",
workspaceDir: "/tmp",
prompt: "hi",
provider: "codex-cli", provider: "codex-cli",
model: "gpt-5.4", model: "gpt-5.4",
timeoutMs: 1_000,
runId: "run-abort", runId: "run-abort",
abortSignal: abortController.signal,
}); });
context.params.abortSignal = abortController.signal;
const runPromise = executePreparedCliRun(context);
await vi.waitFor(() => { await vi.waitFor(() => {
expect(supervisorSpawnMock).toHaveBeenCalledTimes(1); expect(supervisorSpawnMock).toHaveBeenCalledTimes(1);
@@ -237,7 +286,6 @@ describe("runCliAgent spawn path", () => {
}); });
it("streams Claude text deltas from stream-json stdout", async () => { it("streams Claude text deltas from stream-json stdout", async () => {
const runCliAgent = await setupCliRunnerTestModule();
const agentEvents: Array<{ stream: string; text?: string; delta?: string }> = []; const agentEvents: Array<{ stream: string; text?: string; delta?: string }> = [];
const stop = onAgentEvent((evt) => { const stop = onAgentEvent((evt) => {
agentEvents.push({ agentEvents.push({
@@ -291,18 +339,15 @@ describe("runCliAgent spawn path", () => {
}); });
try { try {
const result = await runCliAgent({ const result = await executePreparedCliRun(
sessionId: "s1", buildPreparedCliRunContext({
sessionFile: "/tmp/session.jsonl", provider: "claude-cli",
workspaceDir: "/tmp", model: "sonnet",
prompt: "hi", runId: "run-claude-stream-json",
provider: "claude-cli", }),
model: "sonnet", );
timeoutMs: 1_000,
runId: "run-claude-stream-json",
});
expect(result.payloads?.[0]?.text).toBe("Hello world"); expect(result.text).toBe("Hello world");
expect(agentEvents).toEqual([ expect(agentEvents).toEqual([
{ stream: "assistant", text: "Hello", delta: "Hello" }, { stream: "assistant", text: "Hello", delta: "Hello" },
{ stream: "assistant", text: "Hello world", delta: " world" }, { stream: "assistant", text: "Hello world", delta: " world" },
@@ -313,22 +358,24 @@ describe("runCliAgent spawn path", () => {
}); });
it("sanitizes dangerous backend env overrides before spawn", async () => { it("sanitizes dangerous backend env overrides before spawn", async () => {
const runCliAgent = await setupCliRunnerTestModule();
mockSuccessfulCliRun(); mockSuccessfulCliRun();
await runCliAgentWithBackendConfig({ await executePreparedCliRun(
runCliAgent, buildPreparedCliRunContext({
backend: { provider: "codex-cli",
command: "codex", model: "gpt-5.4",
env: { runId: "run-env-sanitized",
NODE_OPTIONS: "--require ./malicious.js", backend: {
LD_PRELOAD: "/tmp/pwn.so", env: {
PATH: "/tmp/evil", NODE_OPTIONS: "--require ./malicious.js",
HOME: "/tmp/evil-home", LD_PRELOAD: "/tmp/pwn.so",
SAFE_KEY: "ok", PATH: "/tmp/evil",
HOME: "/tmp/evil-home",
SAFE_KEY: "ok",
},
}, },
}, }),
runId: "run-env-sanitized", "thread-123",
}); );
const input = supervisorSpawnMock.mock.calls[0]?.[0] as { const input = supervisorSpawnMock.mock.calls[0]?.[0] as {
env?: Record<string, string | undefined>; env?: Record<string, string | undefined>;
@@ -341,20 +388,22 @@ describe("runCliAgent spawn path", () => {
}); });
it("applies clearEnv after sanitizing backend env overrides", async () => { it("applies clearEnv after sanitizing backend env overrides", async () => {
const runCliAgent = await setupCliRunnerTestModule();
process.env.SAFE_CLEAR = "from-base"; process.env.SAFE_CLEAR = "from-base";
mockSuccessfulCliRun(); mockSuccessfulCliRun();
await runCliAgentWithBackendConfig({ await executePreparedCliRun(
runCliAgent, buildPreparedCliRunContext({
backend: { provider: "codex-cli",
command: "codex", model: "gpt-5.4",
env: { runId: "run-clear-env",
SAFE_KEEP: "keep-me", backend: {
env: {
SAFE_KEEP: "keep-me",
},
clearEnv: ["SAFE_CLEAR"],
}, },
clearEnv: ["SAFE_CLEAR"], }),
}, "thread-123",
runId: "run-clear-env", );
});
const input = supervisorSpawnMock.mock.calls[0]?.[0] as { const input = supervisorSpawnMock.mock.calls[0]?.[0] as {
env?: Record<string, string | undefined>; env?: Record<string, string | undefined>;
@@ -364,20 +413,22 @@ describe("runCliAgent spawn path", () => {
}); });
it("keeps explicit backend env overrides even when clearEnv drops inherited values", async () => { it("keeps explicit backend env overrides even when clearEnv drops inherited values", async () => {
const runCliAgent = await setupCliRunnerTestModule();
process.env.SAFE_OVERRIDE = "from-base"; process.env.SAFE_OVERRIDE = "from-base";
mockSuccessfulCliRun(); mockSuccessfulCliRun();
await runCliAgentWithBackendConfig({ await executePreparedCliRun(
runCliAgent, buildPreparedCliRunContext({
backend: { provider: "codex-cli",
command: "codex", model: "gpt-5.4",
env: { runId: "run-clear-env-override",
SAFE_OVERRIDE: "from-override", backend: {
env: {
SAFE_OVERRIDE: "from-override",
},
clearEnv: ["SAFE_OVERRIDE"],
}, },
clearEnv: ["SAFE_OVERRIDE"], }),
}, "thread-123",
runId: "run-clear-env-override", );
});
const input = supervisorSpawnMock.mock.calls[0]?.[0] as { const input = supervisorSpawnMock.mock.calls[0]?.[0] as {
env?: Record<string, string | undefined>; env?: Record<string, string | undefined>;
@@ -386,7 +437,6 @@ describe("runCliAgent spawn path", () => {
}); });
it("clears claude-cli provider-routing, auth, and telemetry env while keeping host-managed hardening", async () => { it("clears claude-cli provider-routing, auth, and telemetry env while keeping host-managed hardening", async () => {
const runCliAgent = await setupCliRunnerTestModule();
vi.stubEnv("ANTHROPIC_BASE_URL", "https://proxy.example.com/v1"); vi.stubEnv("ANTHROPIC_BASE_URL", "https://proxy.example.com/v1");
vi.stubEnv("CLAUDE_CODE_USE_BEDROCK", "1"); vi.stubEnv("CLAUDE_CODE_USE_BEDROCK", "1");
vi.stubEnv("ANTHROPIC_AUTH_TOKEN", "env-auth-token"); vi.stubEnv("ANTHROPIC_AUTH_TOKEN", "env-auth-token");
@@ -400,32 +450,34 @@ describe("runCliAgent spawn path", () => {
vi.stubEnv("OTEL_SDK_DISABLED", "true"); vi.stubEnv("OTEL_SDK_DISABLED", "true");
mockSuccessfulCliRun(); mockSuccessfulCliRun();
await runCliAgent({ await executePreparedCliRun(
sessionId: "s1", buildPreparedCliRunContext({
sessionFile: "/tmp/session.jsonl", provider: "claude-cli",
workspaceDir: "/tmp", model: "claude-sonnet-4-6",
config: { runId: "run-claude-env-hardened",
agents: { backend: {
defaults: { env: {
cliBackends: { SAFE_KEEP: "ok",
"claude-cli": { ANTHROPIC_BASE_URL: "https://override.example.com/v1",
command: "claude", CLAUDE_CODE_OAUTH_TOKEN: "override-oauth-token",
env: { CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST: "1",
SAFE_KEEP: "ok",
ANTHROPIC_BASE_URL: "https://override.example.com/v1",
CLAUDE_CODE_OAUTH_TOKEN: "override-oauth-token",
},
},
},
}, },
clearEnv: [
"ANTHROPIC_BASE_URL",
"CLAUDE_CODE_USE_BEDROCK",
"ANTHROPIC_AUTH_TOKEN",
"CLAUDE_CODE_OAUTH_TOKEN",
"CLAUDE_CODE_REMOTE",
"ANTHROPIC_UNIX_SOCKET",
"OTEL_LOGS_EXPORTER",
"OTEL_METRICS_EXPORTER",
"OTEL_TRACES_EXPORTER",
"OTEL_EXPORTER_OTLP_PROTOCOL",
"OTEL_SDK_DISABLED",
],
}, },
} satisfies OpenClawConfig, }),
prompt: "hi", );
provider: "claude-cli",
model: "claude-sonnet-4-6",
timeoutMs: 1_000,
runId: "run-claude-env-hardened",
});
const input = supervisorSpawnMock.mock.calls[0]?.[0] as { const input = supervisorSpawnMock.mock.calls[0]?.[0] as {
env?: Record<string, string | undefined>; env?: Record<string, string | undefined>;
@@ -446,7 +498,6 @@ describe("runCliAgent spawn path", () => {
}); });
it("prepends bootstrap warnings to the CLI prompt body", async () => { it("prepends bootstrap warnings to the CLI prompt body", async () => {
const runCliAgent = await setupCliRunnerTestModule();
supervisorSpawnMock.mockResolvedValueOnce( supervisorSpawnMock.mockResolvedValueOnce(
createManagedRun({ createManagedRun({
reason: "exit", reason: "exit",
@@ -459,37 +510,18 @@ describe("runCliAgent spawn path", () => {
noOutputTimedOut: false, noOutputTimedOut: false,
}), }),
); );
stubBootstrapContext({ const context = buildPreparedCliRunContext({
bootstrapFiles: [
{
name: "AGENTS.md",
path: "/tmp/AGENTS.md",
content: "A".repeat(200),
missing: false,
},
],
contextFiles: [{ path: "AGENTS.md", content: "A".repeat(20) }],
});
await runCliAgent({
sessionId: "s1",
sessionFile: "/tmp/session.jsonl",
workspaceDir: "/tmp",
config: {
agents: {
defaults: {
bootstrapMaxChars: 50,
bootstrapTotalMaxChars: 50,
},
},
} satisfies OpenClawConfig,
prompt: "hi",
provider: "codex-cli", provider: "codex-cli",
model: "gpt-5.4", model: "gpt-5.4",
timeoutMs: 1_000,
runId: "run-warning", runId: "run-warning",
cliSessionId: "thread-123",
}); });
context.reusableCliSession = { sessionId: "thread-123" };
context.bootstrapPromptWarningLines = [
"[Bootstrap truncation warning]",
"- AGENTS.md: 200 raw -> 20 injected",
];
await executePreparedCliRun(context, "thread-123");
const input = supervisorSpawnMock.mock.calls[0]?.[0] as { const input = supervisorSpawnMock.mock.calls[0]?.[0] as {
argv?: string[]; argv?: string[];
@@ -713,53 +745,4 @@ describe("runCliAgent spawn path", () => {
const argv = input.argv ?? []; const argv = input.argv ?? [];
expect(argv.filter((arg) => arg === "--image")).toHaveLength(1); expect(argv.filter((arg) => arg === "--image")).toHaveLength(1);
}); });
it("falls back to per-agent workspace when workspaceDir is missing", async () => {
const runCliAgent = await setupCliRunnerTestModule();
const tempDir = await fs.mkdtemp(
path.join(process.env.TMPDIR ?? "/tmp", "openclaw-cli-runner-"),
);
const fallbackWorkspace = path.join(tempDir, "workspace-main");
await fs.mkdir(fallbackWorkspace, { recursive: true });
const cfg = {
agents: {
defaults: {
workspace: fallbackWorkspace,
},
},
} satisfies OpenClawConfig;
supervisorSpawnMock.mockResolvedValueOnce(
createManagedRun({
reason: "exit",
exitCode: 0,
exitSignal: null,
durationMs: 25,
stdout: "ok",
stderr: "",
timedOut: false,
noOutputTimedOut: false,
}),
);
try {
await runCliAgent({
sessionId: "s1",
sessionKey: "agent:main:subagent:missing-workspace",
sessionFile: "/tmp/session.jsonl",
workspaceDir: undefined as unknown as string,
config: cfg,
prompt: "hi",
provider: "codex-cli",
model: "gpt-5.4",
timeoutMs: 1_000,
runId: "run-4",
});
} finally {
await fs.rm(tempDir, { recursive: true, force: true });
}
const input = supervisorSpawnMock.mock.calls[0]?.[0] as { cwd?: string };
expect(input.cwd).toBe(path.resolve(fallbackWorkspace));
});
}); });