import type { RuntimeEnv, WizardPrompter } from "openclaw/plugin-sdk"; import { describe, expect, it, vi } from "vitest"; import { ircOnboardingAdapter } from "./onboarding.js"; import type { CoreConfig } from "./types.js"; const selectFirstOption = async (params: { options: Array<{ value: T }> }): Promise => { const first = params.options[0]; if (!first) { throw new Error("no options"); } return first.value; }; describe("irc onboarding", () => { it("configures host and nick via onboarding prompts", async () => { const prompter: WizardPrompter = { intro: vi.fn(async () => {}), outro: vi.fn(async () => {}), note: vi.fn(async () => {}), select: selectFirstOption as WizardPrompter["select"], multiselect: vi.fn(async () => []), text: vi.fn(async ({ message }: { message: string }) => { if (message === "IRC server host") { return "irc.libera.chat"; } if (message === "IRC server port") { return "6697"; } if (message === "IRC nick") { return "openclaw-bot"; } if (message === "IRC username") { return "openclaw"; } if (message === "IRC real name") { return "OpenClaw Bot"; } if (message.startsWith("Auto-join IRC channels")) { return "#openclaw, #ops"; } if (message.startsWith("IRC channels allowlist")) { return "#openclaw, #ops"; } throw new Error(`Unexpected prompt: ${message}`); }) as WizardPrompter["text"], confirm: vi.fn(async ({ message }: { message: string }) => { if (message === "Use TLS for IRC?") { return true; } if (message === "Configure IRC channels access?") { return true; } return false; }), progress: vi.fn(() => ({ update: vi.fn(), stop: vi.fn() })), }; const runtime: RuntimeEnv = { log: vi.fn(), error: vi.fn(), exit: vi.fn((code: number): never => { throw new Error(`exit ${code}`); }), }; const result = await ircOnboardingAdapter.configure({ cfg: {} as CoreConfig, runtime, prompter, options: {}, accountOverrides: {}, shouldPromptAccountIds: false, forceAllowFrom: false, }); expect(result.accountId).toBe("default"); expect(result.cfg.channels?.irc?.enabled).toBe(true); expect(result.cfg.channels?.irc?.host).toBe("irc.libera.chat"); expect(result.cfg.channels?.irc?.nick).toBe("openclaw-bot"); expect(result.cfg.channels?.irc?.tls).toBe(true); expect(result.cfg.channels?.irc?.channels).toEqual(["#openclaw", "#ops"]); expect(result.cfg.channels?.irc?.groupPolicy).toBe("allowlist"); expect(Object.keys(result.cfg.channels?.irc?.groups ?? {})).toEqual(["#openclaw", "#ops"]); }); it("writes DM allowFrom to top-level config for non-default account prompts", async () => { const prompter: WizardPrompter = { intro: vi.fn(async () => {}), outro: vi.fn(async () => {}), note: vi.fn(async () => {}), select: selectFirstOption as WizardPrompter["select"], multiselect: vi.fn(async () => []), text: vi.fn(async ({ message }: { message: string }) => { if (message === "IRC allowFrom (nick or nick!user@host)") { return "Alice, Bob!ident@example.org"; } throw new Error(`Unexpected prompt: ${message}`); }) as WizardPrompter["text"], confirm: vi.fn(async () => false), progress: vi.fn(() => ({ update: vi.fn(), stop: vi.fn() })), }; const promptAllowFrom = ircOnboardingAdapter.dmPolicy?.promptAllowFrom; expect(promptAllowFrom).toBeTypeOf("function"); const cfg: CoreConfig = { channels: { irc: { accounts: { work: { host: "irc.libera.chat", nick: "openclaw-work", }, }, }, }, }; const updated = (await promptAllowFrom?.({ cfg, prompter, accountId: "work", })) as CoreConfig; expect(updated.channels?.irc?.allowFrom).toEqual(["alice", "bob!ident@example.org"]); expect(updated.channels?.irc?.accounts?.work?.allowFrom).toBeUndefined(); }); });