
























@@ -8,6 +8,7 @@ import {
88writeBundleProbeMcpServer,
99writeClaudeBundle,
1010writeFakeClaudeCli,
11+writeFakeClaudeLiveCli,
1112} from "./bundle-mcp.test-harness.js";
12131314vi.mock("./cli-runner/helpers.js", async () => {
@@ -92,4 +93,80 @@ describe("runCliAgent bundle MCP e2e", () => {
9293}
9394},
9495);
96+97+it(
98+"exits one-shot Claude live-session runs and closes the MCP loopback server",
99+{ timeout: E2E_TIMEOUT_MS },
100+async () => {
101+const { runCliAgent } = await import("./cli-runner.js");
102+const { closeMcpLoopbackServer, getActiveMcpLoopbackRuntime } =
103+await import("../gateway/mcp-http.js");
104+const { resetGlobalHookRunner } = await import("../plugins/hook-runner-global.js");
105+const envSnapshot = captureEnv(["HOME"]);
106+const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-cli-live-cleanup-"));
107+process.env.HOME = tempHome;
108+resetGlobalHookRunner();
109+await closeMcpLoopbackServer();
110+111+const workspaceDir = path.join(tempHome, "workspace");
112+const sessionFile = path.join(tempHome, "session.jsonl");
113+const binDir = path.join(tempHome, "bin");
114+const serverScriptPath = path.join(tempHome, "mcp", "bundle-probe.mjs");
115+const fakeClaudePath = path.join(binDir, "fake-live-claude.mjs");
116+const fakeClaudePidPath = path.join(tempHome, "fake-live-claude.pid");
117+const pluginRoot = path.join(tempHome, ".openclaw", "extensions", "bundle-probe");
118+await fs.mkdir(workspaceDir, { recursive: true });
119+await writeBundleProbeMcpServer(serverScriptPath);
120+await writeFakeClaudeLiveCli({ filePath: fakeClaudePath, pidPath: fakeClaudePidPath });
121+await writeClaudeBundle({ pluginRoot, serverScriptPath });
122+123+const config: OpenClawConfig = {
124+agents: {
125+defaults: {
126+workspace: workspaceDir,
127+cliBackends: {
128+"claude-cli": {
129+command: "node",
130+args: [fakeClaudePath],
131+clearEnv: [],
132+liveSession: "claude-stdio",
133+},
134+},
135+},
136+},
137+plugins: {
138+entries: {
139+"bundle-probe": { enabled: true },
140+},
141+},
142+};
143+144+try {
145+const result = await runCliAgent({
146+sessionId: "session:test-live-cleanup",
147+ sessionFile,
148+ workspaceDir,
149+ config,
150+prompt: "Use your configured MCP tools and report the bundle probe text.",
151+provider: "claude-cli",
152+model: "test-live-bundle",
153+timeoutMs: 20_000,
154+runId: "bundle-mcp-live-cleanup-e2e",
155+cleanupBundleMcpOnRunEnd: true,
156+cleanupCliLiveSessionOnRunEnd: true,
157+});
158+159+expect(result.payloads?.[0]?.text).toContain("LIVE BUNDLE MCP OK FROM-BUNDLE");
160+expect(getActiveMcpLoopbackRuntime()).toBeUndefined();
161+const fakeClaudePid = Number.parseInt(await fs.readFile(fakeClaudePidPath, "utf-8"), 10);
162+expect(Number.isFinite(fakeClaudePid)).toBe(true);
163+expect(() => process.kill(fakeClaudePid, 0)).toThrow();
164+} finally {
165+await closeMcpLoopbackServer();
166+resetGlobalHookRunner();
167+await fs.rm(tempHome, { recursive: true, force: true });
168+envSnapshot.restore();
169+}
170+},
171+);
95172});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。