import { describe, expect, it, vi } from
"vitest";
import {
createPluginSetupWizardConfigure,
createPluginSetupWizardStatus,
createTestWizardPrompter,
runSetupWizardConfigure,
type WizardPrompter,
} from
"../../../test/helpers/plugins/setup-wizard.js";
import type { OpenClawConfig } from
"../api.js";
import { TlonAuthorizationSchema, TlonConfigSchema } from
"./config-schema.js";
import { tlonSetupWizard } from
"./setup-surface.js";
import { normalizeShip, resolveTlonOutboundTarget } from
"./targets.js";
import { listTlonAccountIds, resolveTlonAccount } from
"./types.js";
const tlonTestPlugin = {
id:
"tlon",
meta: { label:
"Tlon" },
setupWizard: tlonSetupWizard,
config: {
listAccountIds: listTlonAccountIds,
defaultAccountId: () =>
"default",
resolveAllowFrom: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId?: string |
null }) =>
resolveTlonAccount(cfg, accountId).dmAllowlist,
formatAllowFrom: ({
allowFrom,
}: {
cfg: OpenClawConfig;
allowFrom: Array<string | number> | undefined |
null;
}) => (allowFrom ?? []).map((entry) => normalizeShip(String(entry))).filter(
Boolean),
},
setup: {
resolveAccountId: ({ accountId }: { cfg: OpenClawConfig; accountId?: string |
null }) =>
accountId ??
"default",
},
};
const tlonConfigure = createPluginSetupWizardConfigure(tlonTestPlugin);
const tlonStatus = createPluginSetupWizardStatus(tlonTestPlugin);
describe(
"tlon core", () => {
it(
"formats dm allowlist entries through the shared hybrid adapter", () => {
expect(
tlonTestPlugin.config.formatAllowFrom?.({
cfg: {} as OpenClawConfig,
allowFrom: [
"zod",
" ~nec "],
}),
).toEqual([
"~zod",
"~nec"]);
});
it(
"returns an empty dm allowlist when the default account is unconfigured", () => {
expect(
tlonTestPlugin.config.resolveAllowFrom?.({
cfg: {} as OpenClawConfig,
accountId:
"default",
}),
).toEqual([]);
});
it(
"resolves dm allowlist from the default account", () => {
expect(
tlonTestPlugin.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?.network?.dangerouslyAllowPrivateNetwork).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");
});
it(
"setup status labels the selected account", async () => {
const status = await tlonStatus({
cfg: {
channels: {
tlon: {
ship:
"~zod",
url:
"https://urbit.example.com",
code:
"base-code",
accounts: {
work: {},
},
},
},
} as OpenClawConfig,
accountOverrides: { tlon:
"work" },
});
expect(status.configured).toBe(
true);
expect(status.statusLines).toEqual([
"Tlon (work): configured"]);
});
});