
























@@ -15,6 +15,7 @@ vi.mock("./runtime-entry.js", () => ({
15151616import plugin from "./index.js";
1717import { createVoiceCallRuntime } from "./runtime-entry.js";
18+import { __testing as voiceCallCliTesting } from "./src/cli.js";
18191920const noopLogger = {
2021info: vi.fn(),
@@ -23,6 +24,8 @@ const noopLogger = {
2324debug: vi.fn(),
2425};
252627+const callGatewayFromCliMock = vi.fn();
28+2629type Registered = {
2730methods: Map<string, unknown>;
2831tools: unknown[];
@@ -144,11 +147,15 @@ describe("voice-call plugin", () => {
144147noopLogger.error.mockClear();
145148noopLogger.debug.mockClear();
146149runtimeStub = createRuntimeStub();
150+callGatewayFromCliMock.mockReset();
151+callGatewayFromCliMock.mockRejectedValue(new Error("connect ECONNREFUSED 127.0.0.1:18789"));
152+voiceCallCliTesting.setCallGatewayFromCliForTests(callGatewayFromCliMock);
147153vi.mocked(createVoiceCallRuntime).mockReset();
148154vi.mocked(createVoiceCallRuntime).mockImplementation(async () => runtimeStub);
149155});
150156151157afterEach(() => {
158+voiceCallCliTesting.setCallGatewayFromCliForTests();
152159vi.restoreAllMocks();
153160vi.unstubAllEnvs();
154161delete (globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw.voice-call.runtime")];
@@ -205,6 +212,29 @@ describe("voice-call plugin", () => {
205212expect(respond).toHaveBeenCalledWith(true, { callId: "call-1", initiated: true });
206213});
207214215+it("does not start the webhook runtime for CLI-only plugin loading", async () => {
216+vi.stubEnv("OPENCLAW_CLI", "1");
217+const { service } = setup({ provider: "mock" });
218+219+await service?.start(createServiceContext());
220+221+expect(createVoiceCallRuntime).not.toHaveBeenCalled();
222+});
223+224+it("still starts the webhook runtime for gateway CLI processes", async () => {
225+const previousArgv = process.argv;
226+vi.stubEnv("OPENCLAW_CLI", "1");
227+process.argv = ["node", "openclaw", "gateway", "run"];
228+const { service } = setup({ provider: "mock" });
229+230+try {
231+await service?.start(createServiceContext());
232+expect(createVoiceCallRuntime).toHaveBeenCalledTimes(1);
233+} finally {
234+process.argv = previousArgv;
235+}
236+});
237+208238it("creates a fresh shared runtime after service stop", async () => {
209239const first = setup({ provider: "mock" });
210240await first.service?.start(createServiceContext());
@@ -462,6 +492,29 @@ describe("voice-call plugin", () => {
462492}
463493});
464494495+it("CLI start delegates to the running gateway runtime", async () => {
496+callGatewayFromCliMock.mockResolvedValueOnce({ callId: "gateway-call", initiated: true });
497+const program = new Command();
498+const stdout = captureStdout();
499+await registerVoiceCallCli(program);
500+501+try {
502+await program.parseAsync(["voicecall", "start", "--to", "+1", "--message", "Hello"], {
503+from: "user",
504+});
505+expect(callGatewayFromCliMock).toHaveBeenCalledWith(
506+"voicecall.start",
507+{ json: true, timeout: "5000" },
508+{ to: "+1", message: "Hello", mode: "conversation" },
509+{ progress: false },
510+);
511+expect(createVoiceCallRuntime).not.toHaveBeenCalled();
512+expect(stdout.output()).toContain('"callId": "gateway-call"');
513+} finally {
514+stdout.restore();
515+}
516+});
517+465518it("CLI setup prints human-readable checks by default", async () => {
466519const program = new Command();
467520const stdout = captureStdout();
@@ -527,6 +580,33 @@ describe("voice-call plugin", () => {
527580}
528581});
529582583+it("CLI status lists active calls through the running gateway runtime", async () => {
584+callGatewayFromCliMock.mockResolvedValueOnce({
585+found: true,
586+calls: [{ callId: "gateway-call" }],
587+});
588+const program = new Command();
589+const stdout = captureStdout();
590+await registerVoiceCallCli(program);
591+592+try {
593+await program.parseAsync(["voicecall", "status", "--json"], { from: "user" });
594+const parsed = JSON.parse(stdout.output()) as {
595+calls?: Array<{ callId?: string }>;
596+};
597+expect(callGatewayFromCliMock).toHaveBeenCalledWith(
598+"voicecall.status",
599+{ json: true, timeout: "5000" },
600+undefined,
601+{ progress: false },
602+);
603+expect(createVoiceCallRuntime).not.toHaveBeenCalled();
604+expect(parsed.calls).toEqual([expect.objectContaining({ callId: "gateway-call" })]);
605+} finally {
606+stdout.restore();
607+}
608+});
609+530610it("CLI smoke dry-runs a live call unless --yes is passed", async () => {
531611const program = new Command();
532612const stdout = captureStdout();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。