import { describe, expect, it, vi } from "vitest"; import type { ClawdbotConfig } from "../config/config.js"; const mocks = vi.hoisted(() => ({ clackIntro: vi.fn(), clackOutro: vi.fn(), clackSelect: vi.fn(), clackText: vi.fn(), clackConfirm: vi.fn(), readConfigFileSnapshot: vi.fn(), writeConfigFile: vi.fn(), resolveGatewayPort: vi.fn(), ensureControlUiAssetsBuilt: vi.fn(), createClackPrompter: vi.fn(), note: vi.fn(), printWizardHeader: vi.fn(), probeGatewayReachable: vi.fn(), waitForGatewayReachable: vi.fn(), resolveControlUiLinks: vi.fn(), summarizeExistingConfig: vi.fn(), })); vi.mock("@clack/prompts", () => ({ intro: mocks.clackIntro, outro: mocks.clackOutro, select: mocks.clackSelect, text: mocks.clackText, confirm: mocks.clackConfirm, })); vi.mock("../config/config.js", () => ({ CONFIG_PATH_CLAWDBOT: "~/.clawdbot/clawdbot.json", readConfigFileSnapshot: mocks.readConfigFileSnapshot, writeConfigFile: mocks.writeConfigFile, resolveGatewayPort: mocks.resolveGatewayPort, })); vi.mock("../infra/control-ui-assets.js", () => ({ ensureControlUiAssetsBuilt: mocks.ensureControlUiAssetsBuilt, })); vi.mock("../wizard/clack-prompter.js", () => ({ createClackPrompter: mocks.createClackPrompter, })); vi.mock("../terminal/note.js", () => ({ note: mocks.note, })); vi.mock("./onboard-helpers.js", () => ({ DEFAULT_WORKSPACE: "~/.clawdbot/workspace", applyWizardMetadata: (cfg: ClawdbotConfig) => cfg, ensureWorkspaceAndSessions: vi.fn(), guardCancel: (value: T) => value, printWizardHeader: mocks.printWizardHeader, probeGatewayReachable: mocks.probeGatewayReachable, resolveControlUiLinks: mocks.resolveControlUiLinks, summarizeExistingConfig: mocks.summarizeExistingConfig, waitForGatewayReachable: mocks.waitForGatewayReachable, })); vi.mock("./health.js", () => ({ healthCommand: vi.fn(), })); vi.mock("./health-format.js", () => ({ formatHealthCheckFailure: vi.fn(), })); vi.mock("./configure.gateway.js", () => ({ promptGatewayConfig: vi.fn(), })); vi.mock("./configure.gateway-auth.js", () => ({ promptAuthConfig: vi.fn(), })); vi.mock("./configure.channels.js", () => ({ removeChannelConfigWizard: vi.fn(), })); vi.mock("./configure.daemon.js", () => ({ maybeInstallDaemon: vi.fn(), })); vi.mock("./onboard-remote.js", () => ({ promptRemoteGatewayConfig: vi.fn(), })); vi.mock("./onboard-skills.js", () => ({ setupSkills: vi.fn(), })); vi.mock("./onboard-channels.js", () => ({ setupChannels: vi.fn(), })); import { runConfigureWizard } from "./configure.wizard.js"; describe("runConfigureWizard", () => { it("persists gateway.mode=local when only the run mode is selected", async () => { mocks.readConfigFileSnapshot.mockResolvedValue({ exists: false, valid: true, config: {}, issues: [], }); mocks.resolveGatewayPort.mockReturnValue(18789); mocks.probeGatewayReachable.mockResolvedValue({ ok: false }); mocks.resolveControlUiLinks.mockReturnValue({ wsUrl: "ws://127.0.0.1:18789" }); mocks.summarizeExistingConfig.mockReturnValue(""); mocks.createClackPrompter.mockReturnValue({}); const selectQueue = ["local", "__continue"]; mocks.clackSelect.mockImplementation(async () => selectQueue.shift()); mocks.clackIntro.mockResolvedValue(undefined); mocks.clackOutro.mockResolvedValue(undefined); mocks.clackText.mockResolvedValue(""); mocks.clackConfirm.mockResolvedValue(false); await runConfigureWizard( { command: "configure" }, { log: vi.fn(), error: vi.fn(), exit: vi.fn(), }, ); expect(mocks.writeConfigFile).toHaveBeenCalledWith( expect.objectContaining({ gateway: expect.objectContaining({ mode: "local" }), }), ); }); });