import { describe, expect, it, vi } from "vitest"; import { createPluginSetupWizardConfigure, createTestWizardPrompter, runSetupWizardConfigure, type WizardPrompter, } from "../../../test/helpers/extensions/setup-wizard.js"; import type { OpenClawConfig } from "../api.js"; import { tlonPlugin } from "./channel.js"; import { TlonAuthorizationSchema, TlonConfigSchema } from "./config-schema.js"; import { resolveTlonOutboundTarget } from "./targets.js"; import { listTlonAccountIds, resolveTlonAccount } from "./types.js"; const tlonConfigure = createPluginSetupWizardConfigure(tlonPlugin); describe("tlon core", () => { it("formats dm allowlist entries through the shared hybrid adapter", () => { expect( tlonPlugin.config.formatAllowFrom?.({ cfg: {} as OpenClawConfig, allowFrom: ["zod", " ~nec "], }), ).toEqual(["~zod", "~nec"]); }); it("resolves dm allowlist from the default account", () => { expect( tlonPlugin.config.resolveAllowFrom?.({ cfg: { channels: { tlon: { ship: "~sampel-palnet", url: "https://urbit.example.com", code: "lidlut-tabwed-pillex-ridrup", dmAllowlist: ["~zod"], }, }, } as OpenClawConfig, accountId: "default", }), ).toEqual(["~zod"]); }); it("accepts channelRules with string keys", () => { const parsed = TlonAuthorizationSchema.parse({ channelRules: { "chat/~zod/test": { mode: "open", allowedShips: ["~zod"], }, }, }); expect(parsed.channelRules?.["chat/~zod/test"]?.mode).toBe("open"); }); it("accepts accounts with string keys", () => { const parsed = TlonConfigSchema.parse({ accounts: { primary: { ship: "~zod", url: "https://example.com", code: "code-123", }, }, }); expect(parsed.accounts?.primary?.ship).toBe("~zod"); }); it("configures ship, auth, and discovery settings", async () => { const prompter = createTestWizardPrompter({ text: vi.fn(async ({ message }: { message: string }) => { if (message === "Ship name") { return "sampel-palnet"; } if (message === "Ship URL") { return "https://urbit.example.com"; } if (message === "Login code") { return "lidlut-tabwed-pillex-ridrup"; } if (message === "Group channels (comma-separated)") { return "chat/~host-ship/general, chat/~host-ship/support"; } if (message === "DM allowlist (comma-separated ship names)") { return "~zod, nec"; } throw new Error(`Unexpected prompt: ${message}`); }) as WizardPrompter["text"], confirm: vi.fn(async ({ message }: { message: string }) => { if (message === "Add group channels manually? (optional)") { return true; } if (message === "Restrict DMs with an allowlist?") { return true; } if (message === "Enable auto-discovery of group channels?") { return true; } return false; }), }); const result = await runSetupWizardConfigure({ configure: tlonConfigure, cfg: {} as OpenClawConfig, prompter, options: {}, }); expect(result.accountId).toBe("default"); expect(result.cfg.channels?.tlon?.enabled).toBe(true); expect(result.cfg.channels?.tlon?.ship).toBe("~sampel-palnet"); expect(result.cfg.channels?.tlon?.url).toBe("https://urbit.example.com"); expect(result.cfg.channels?.tlon?.code).toBe("lidlut-tabwed-pillex-ridrup"); expect(result.cfg.channels?.tlon?.groupChannels).toEqual([ "chat/~host-ship/general", "chat/~host-ship/support", ]); expect(result.cfg.channels?.tlon?.dmAllowlist).toEqual(["~zod", "~nec"]); expect(result.cfg.channels?.tlon?.autoDiscoverChannels).toBe(true); expect(result.cfg.channels?.tlon?.allowPrivateNetwork).toBe(false); }); it("resolves dm targets to normalized ships", () => { expect(resolveTlonOutboundTarget("dm/sampel-palnet")).toEqual({ ok: true, to: "~sampel-palnet", }); }); it("resolves group targets to canonical chat nests", () => { expect(resolveTlonOutboundTarget("group:host-ship/general")).toEqual({ ok: true, to: "chat/~host-ship/general", }); }); it("returns a helpful error for invalid targets", () => { const resolved = resolveTlonOutboundTarget("group:bad-target"); expect(resolved.ok).toBe(false); if (resolved.ok) { throw new Error("expected invalid target"); } expect(resolved.error.message).toMatch(/invalid tlon target/i); }); it("lists named accounts and the implicit default account", () => { const cfg = { channels: { tlon: { ship: "~zod", accounts: { Work: { ship: "~bus" }, alerts: { ship: "~nec" }, }, }, }, } as OpenClawConfig; expect(listTlonAccountIds(cfg)).toEqual(["alerts", "default", "work"]); }); it("merges named account config over channel defaults", () => { const resolved = resolveTlonAccount( { channels: { tlon: { name: "Base", ship: "~zod", url: "https://urbit.example.com", code: "base-code", dmAllowlist: ["~nec"], groupInviteAllowlist: ["~bus"], defaultAuthorizedShips: ["~marzod"], accounts: { Work: { name: "Work", code: "work-code", dmAllowlist: ["~rovnys"], }, }, }, }, } as OpenClawConfig, "work", ); expect(resolved.accountId).toBe("work"); expect(resolved.name).toBe("Work"); expect(resolved.ship).toBe("~zod"); expect(resolved.url).toBe("https://urbit.example.com"); expect(resolved.code).toBe("work-code"); expect(resolved.dmAllowlist).toEqual(["~rovnys"]); expect(resolved.groupInviteAllowlist).toEqual(["~bus"]); expect(resolved.defaultAuthorizedShips).toEqual(["~marzod"]); expect(resolved.configured).toBe(true); }); it("keeps the default account on channel-level config only", () => { const resolved = resolveTlonAccount( { channels: { tlon: { ship: "~zod", url: "https://urbit.example.com", code: "base-code", accounts: { default: { ship: "~ignored", code: "ignored-code", }, }, }, }, } as OpenClawConfig, "default", ); expect(resolved.ship).toBe("~zod"); expect(resolved.code).toBe("base-code"); }); });