



























11/** Tests cron before_agent_reply gating at the CLI runner entrypoint. */
22import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
33import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
4+import type { CliOutput } from "./cli-output.js";
45import { cliBackendLog } from "./cli-runner/log.js";
5667// vi.mock factories are hoisted above imports, so any references inside them
@@ -28,9 +29,9 @@ const {
2829runBeforeAgentReplyMock: vi.fn<(event: unknown, ctx: unknown) => Promise<BeforeAgentReplyResult>>(
2930async () => undefined,
3031),
31-executePreparedCliRunMock: vi.fn(async (_context: unknown, _cliSessionIdToUse?: string) => ({
32-text: "",
33-})),
32+executePreparedCliRunMock: vi.fn<
33+(_context: unknown, _cliSessionIdToUse?: string) => Promise<CliOutput>
34+>(async () => ({ text: "" })),
3435prepareCliRunContextMock: vi.fn(),
3536closeClaudeLiveSessionForContextMock: vi.fn(),
3637closeMcpLoopbackServerMock: vi.fn(),
@@ -262,6 +263,35 @@ describe("runCliAgent cron before_agent_reply seam", () => {
262263expect(executePreparedCliRunMock).toHaveBeenCalledTimes(1);
263264});
264265266+it("reports confirmed CLI messaging delivery evidence without leaking it to later invocations", async () => {
267+executePreparedCliRunMock.mockResolvedValueOnce({
268+text: "sent",
269+didSendViaMessagingTool: true,
270+messagingToolSentTargets: [
271+{
272+tool: "message",
273+provider: "telegram",
274+to: "chat123",
275+},
276+],
277+});
278+executePreparedCliRunMock.mockResolvedValueOnce({ text: "later" });
279+280+const firstResult = await runCliAgent(baseRunParams);
281+expect(firstResult.didSendViaMessagingTool).toBe(true);
282+expect(firstResult.messagingToolSentTargets).toEqual([
283+expect.objectContaining({
284+tool: "message",
285+provider: "telegram",
286+to: "chat123",
287+}),
288+]);
289+290+const laterResult = await runCliAgent(baseRunParams);
291+expect(laterResult.didSendViaMessagingTool).toBeUndefined();
292+expect(laterResult.messagingToolSentTargets).toBeUndefined();
293+});
294+265295it("can close temporary CLI live sessions after a run", async () => {
266296executePreparedCliRunMock.mockResolvedValue({ text: "real reply" });
267297@@ -282,4 +312,27 @@ describe("runCliAgent cron before_agent_reply seam", () => {
282312expect(executePreparedCliRunMock).toHaveBeenCalledTimes(1);
283313expect(closeMcpLoopbackServerMock).toHaveBeenCalledTimes(1);
284314});
315+316+it("preserves confirmed delivery when bundle MCP cleanup fails", async () => {
317+executePreparedCliRunMock.mockResolvedValue({
318+text: "",
319+didSendViaMessagingTool: true,
320+});
321+closeMcpLoopbackServerMock.mockRejectedValue(new Error("loopback cleanup failed"));
322+323+await expect(
324+runCliAgent({ ...baseRunParams, cleanupBundleMcpOnRunEnd: true }),
325+).resolves.toMatchObject({
326+didSendViaMessagingTool: true,
327+});
328+});
329+330+it("surfaces bundle MCP cleanup failures when nothing was delivered", async () => {
331+executePreparedCliRunMock.mockResolvedValue({ text: "real reply" });
332+closeMcpLoopbackServerMock.mockRejectedValue(new Error("loopback cleanup failed"));
333+334+await expect(runCliAgent({ ...baseRunParams, cleanupBundleMcpOnRunEnd: true })).rejects.toThrow(
335+"loopback cleanup failed",
336+);
337+});
285338});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。