refactor: rename clawdbot to moltbot with legacy compat

This commit is contained in:
Peter Steinberger
2026-01-27 12:19:58 +00:00
parent 83460df96f
commit 6d16a658e5
1839 changed files with 11250 additions and 11199 deletions

View File

@@ -1,22 +1,22 @@
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "clawdbot/plugin-sdk";
import { runZca, parseJsonOutput } from "./zca.js";
import type { ResolvedZalouserAccount, ZalouserAccountConfig, ZalouserConfig } from "./types.js";
function listConfiguredAccountIds(cfg: ClawdbotConfig): string[] {
function listConfiguredAccountIds(cfg: MoltbotConfig): string[] {
const accounts = (cfg.channels?.zalouser as ZalouserConfig | undefined)?.accounts;
if (!accounts || typeof accounts !== "object") return [];
return Object.keys(accounts).filter(Boolean);
}
export function listZalouserAccountIds(cfg: ClawdbotConfig): string[] {
export function listZalouserAccountIds(cfg: MoltbotConfig): string[] {
const ids = listConfiguredAccountIds(cfg);
if (ids.length === 0) return [DEFAULT_ACCOUNT_ID];
return ids.sort((a, b) => a.localeCompare(b));
}
export function resolveDefaultZalouserAccountId(cfg: ClawdbotConfig): string {
export function resolveDefaultZalouserAccountId(cfg: MoltbotConfig): string {
const zalouserConfig = cfg.channels?.zalouser as ZalouserConfig | undefined;
if (zalouserConfig?.defaultAccount?.trim()) return zalouserConfig.defaultAccount.trim();
const ids = listZalouserAccountIds(cfg);
@@ -25,7 +25,7 @@ export function resolveDefaultZalouserAccountId(cfg: ClawdbotConfig): string {
}
function resolveAccountConfig(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
accountId: string,
): ZalouserAccountConfig | undefined {
const accounts = (cfg.channels?.zalouser as ZalouserConfig | undefined)?.accounts;
@@ -34,7 +34,7 @@ function resolveAccountConfig(
}
function mergeZalouserAccountConfig(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
accountId: string,
): ZalouserAccountConfig {
const raw = (cfg.channels?.zalouser ?? {}) as ZalouserConfig;
@@ -56,7 +56,7 @@ export async function checkZcaAuthenticated(profile: string): Promise<boolean> {
}
export async function resolveZalouserAccount(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
accountId?: string | null;
}): Promise<ResolvedZalouserAccount> {
const accountId = normalizeAccountId(params.accountId);
@@ -78,7 +78,7 @@ export async function resolveZalouserAccount(params: {
}
export function resolveZalouserAccountSync(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
accountId?: string | null;
}): ResolvedZalouserAccount {
const accountId = normalizeAccountId(params.accountId);
@@ -99,7 +99,7 @@ export function resolveZalouserAccountSync(params: {
}
export async function listEnabledZalouserAccounts(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
): Promise<ResolvedZalouserAccount[]> {
const ids = listZalouserAccountIds(cfg);
const accounts = await Promise.all(

View File

@@ -4,7 +4,7 @@ import type {
ChannelDock,
ChannelGroupContext,
ChannelPlugin,
ClawdbotConfig,
MoltbotConfig,
GroupToolPolicyConfig,
} from "clawdbot/plugin-sdk";
import {
@@ -85,7 +85,7 @@ function resolveZalouserGroupToolPolicy(
params: ChannelGroupContext,
): GroupToolPolicyConfig | undefined {
const account = resolveZalouserAccountSync({
cfg: params.cfg as ClawdbotConfig,
cfg: params.cfg as MoltbotConfig,
accountId: params.accountId ?? undefined,
});
const groups = account.config.groups ?? {};
@@ -111,7 +111,7 @@ export const zalouserDock: ChannelDock = {
outbound: { textChunkLimit: 2000 },
config: {
resolveAllowFrom: ({ cfg, accountId }) =>
(resolveZalouserAccountSync({ cfg: cfg as ClawdbotConfig, accountId }).config.allowFrom ?? []).map(
(resolveZalouserAccountSync({ cfg: cfg as MoltbotConfig, accountId }).config.allowFrom ?? []).map(
(entry) => String(entry),
),
formatAllowFrom: ({ allowFrom }) =>
@@ -146,13 +146,13 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
reload: { configPrefixes: ["channels.zalouser"] },
configSchema: buildChannelConfigSchema(ZalouserConfigSchema),
config: {
listAccountIds: (cfg) => listZalouserAccountIds(cfg as ClawdbotConfig),
listAccountIds: (cfg) => listZalouserAccountIds(cfg as MoltbotConfig),
resolveAccount: (cfg, accountId) =>
resolveZalouserAccountSync({ cfg: cfg as ClawdbotConfig, accountId }),
defaultAccountId: (cfg) => resolveDefaultZalouserAccountId(cfg as ClawdbotConfig),
resolveZalouserAccountSync({ cfg: cfg as MoltbotConfig, accountId }),
defaultAccountId: (cfg) => resolveDefaultZalouserAccountId(cfg as MoltbotConfig),
setAccountEnabled: ({ cfg, accountId, enabled }) =>
setAccountEnabledInConfigSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
sectionKey: "zalouser",
accountId,
enabled,
@@ -160,7 +160,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
}),
deleteAccount: ({ cfg, accountId }) =>
deleteAccountFromConfigSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
sectionKey: "zalouser",
accountId,
clearBaseFields: ["profile", "name", "dmPolicy", "allowFrom", "groupPolicy", "groups", "messagePrefix"],
@@ -180,7 +180,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
configured: undefined,
}),
resolveAllowFrom: ({ cfg, accountId }) =>
(resolveZalouserAccountSync({ cfg: cfg as ClawdbotConfig, accountId }).config.allowFrom ?? []).map(
(resolveZalouserAccountSync({ cfg: cfg as MoltbotConfig, accountId }).config.allowFrom ?? []).map(
(entry) => String(entry),
),
formatAllowFrom: ({ allowFrom }) =>
@@ -194,7 +194,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
resolveDmPolicy: ({ cfg, accountId, account }) => {
const resolvedAccountId = accountId ?? account.accountId ?? DEFAULT_ACCOUNT_ID;
const useAccountPath = Boolean(
(cfg as ClawdbotConfig).channels?.zalouser?.accounts?.[resolvedAccountId],
(cfg as MoltbotConfig).channels?.zalouser?.accounts?.[resolvedAccountId],
);
const basePath = useAccountPath
? `channels.zalouser.accounts.${resolvedAccountId}.`
@@ -220,7 +220,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
applyAccountName: ({ cfg, accountId, name }) =>
applyAccountNameToChannelSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
channelKey: "zalouser",
accountId,
name,
@@ -228,7 +228,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
validateInput: () => null,
applyAccountConfig: ({ cfg, accountId, input }) => {
const namedConfig = applyAccountNameToChannelSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
channelKey: "zalouser",
accountId,
name: input.name,
@@ -250,7 +250,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
enabled: true,
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
return {
...next,
@@ -268,7 +268,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
},
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
},
},
messaging: {
@@ -290,7 +290,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
self: async ({ cfg, accountId, runtime }) => {
const ok = await checkZcaInstalled();
if (!ok) throw new Error("Missing dependency: `zca` not found in PATH");
const account = resolveZalouserAccountSync({ cfg: cfg as ClawdbotConfig, accountId });
const account = resolveZalouserAccountSync({ cfg: cfg as MoltbotConfig, accountId });
const result = await runZca(["me", "info", "-j"], { profile: account.profile, timeout: 10000 });
if (!result.ok) {
runtime.error(result.stderr || "Failed to fetch profile");
@@ -308,7 +308,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
listPeers: async ({ cfg, accountId, query, limit }) => {
const ok = await checkZcaInstalled();
if (!ok) throw new Error("Missing dependency: `zca` not found in PATH");
const account = resolveZalouserAccountSync({ cfg: cfg as ClawdbotConfig, accountId });
const account = resolveZalouserAccountSync({ cfg: cfg as MoltbotConfig, accountId });
const args = query?.trim()
? ["friend", "find", query.trim()]
: ["friend", "list", "-j"];
@@ -332,7 +332,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
listGroups: async ({ cfg, accountId, query, limit }) => {
const ok = await checkZcaInstalled();
if (!ok) throw new Error("Missing dependency: `zca` not found in PATH");
const account = resolveZalouserAccountSync({ cfg: cfg as ClawdbotConfig, accountId });
const account = resolveZalouserAccountSync({ cfg: cfg as MoltbotConfig, accountId });
const result = await runZca(["group", "list", "-j"], { profile: account.profile, timeout: 15000 });
if (!result.ok) {
throw new Error(result.stderr || "Failed to list groups");
@@ -356,7 +356,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
listGroupMembers: async ({ cfg, accountId, groupId, limit }) => {
const ok = await checkZcaInstalled();
if (!ok) throw new Error("Missing dependency: `zca` not found in PATH");
const account = resolveZalouserAccountSync({ cfg: cfg as ClawdbotConfig, accountId });
const account = resolveZalouserAccountSync({ cfg: cfg as MoltbotConfig, accountId });
const result = await runZca(["group", "members", groupId, "-j"], {
profile: account.profile,
timeout: 20000,
@@ -398,7 +398,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
}
try {
const account = resolveZalouserAccountSync({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
accountId: accountId ?? DEFAULT_ACCOUNT_ID,
});
const args =
@@ -454,7 +454,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
idLabel: "zalouserUserId",
normalizeAllowEntry: (entry) => entry.replace(/^(zalouser|zlu):/i, ""),
notifyApproval: async ({ cfg, id }) => {
const account = resolveZalouserAccountSync({ cfg: cfg as ClawdbotConfig });
const account = resolveZalouserAccountSync({ cfg: cfg as MoltbotConfig });
const authenticated = await checkZcaAuthenticated(account.profile);
if (!authenticated) throw new Error("Zalouser not authenticated");
await sendMessageZalouser(id, "Your pairing request has been approved.", {
@@ -465,7 +465,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
auth: {
login: async ({ cfg, accountId, runtime }) => {
const account = resolveZalouserAccountSync({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
accountId: accountId ?? DEFAULT_ACCOUNT_ID,
});
const ok = await checkZcaInstalled();
@@ -509,7 +509,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
chunkerMode: "text",
textChunkLimit: 2000,
sendText: async ({ to, text, accountId, cfg }) => {
const account = resolveZalouserAccountSync({ cfg: cfg as ClawdbotConfig, accountId });
const account = resolveZalouserAccountSync({ cfg: cfg as MoltbotConfig, accountId });
const result = await sendMessageZalouser(to, text, { profile: account.profile });
return {
channel: "zalouser",
@@ -519,7 +519,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
};
},
sendMedia: async ({ to, text, mediaUrl, accountId, cfg }) => {
const account = resolveZalouserAccountSync({ cfg: cfg as ClawdbotConfig, accountId });
const account = resolveZalouserAccountSync({ cfg: cfg as MoltbotConfig, accountId });
const result = await sendMessageZalouser(to, text, {
profile: account.profile,
mediaUrl,
@@ -589,7 +589,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
const { monitorZalouserProvider } = await import("./monitor.js");
return monitorZalouserProvider({
account,
config: ctx.cfg as ClawdbotConfig,
config: ctx.cfg as MoltbotConfig,
runtime: ctx.runtime,
abortSignal: ctx.abortSignal,
statusSink: (patch) => ctx.setStatus({ accountId: ctx.accountId, ...patch }),

View File

@@ -1,6 +1,6 @@
import type { ChildProcess } from "node:child_process";
import type { ClawdbotConfig, MarkdownTableMode, RuntimeEnv } from "clawdbot/plugin-sdk";
import type { MoltbotConfig, MarkdownTableMode, RuntimeEnv } from "clawdbot/plugin-sdk";
import { mergeAllowlist, summarizeMapping } from "clawdbot/plugin-sdk";
import { sendMessageZalouser } from "./send.js";
import type {
@@ -14,7 +14,7 @@ import { parseJsonOutput, runZca, runZcaStreaming } from "./zca.js";
export type ZalouserMonitorOptions = {
account: ResolvedZalouserAccount;
config: ClawdbotConfig;
config: MoltbotConfig;
runtime: RuntimeEnv;
abortSignal: AbortSignal;
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void;
@@ -149,7 +149,7 @@ function startZcaListener(
async function processMessage(
message: ZcaMessage,
account: ResolvedZalouserAccount,
config: ClawdbotConfig,
config: MoltbotConfig,
core: ZalouserCoreRuntime,
runtime: RuntimeEnv,
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void,
@@ -358,7 +358,7 @@ async function deliverZalouserReply(params: {
isGroup: boolean;
runtime: RuntimeEnv;
core: ZalouserCoreRuntime;
config: ClawdbotConfig;
config: MoltbotConfig;
accountId?: string;
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void;
tableMode?: MarkdownTableMode;

View File

@@ -1,7 +1,7 @@
import type {
ChannelOnboardingAdapter,
ChannelOnboardingDmPolicy,
ClawdbotConfig,
MoltbotConfig,
WizardPrompter,
} from "clawdbot/plugin-sdk";
import {
@@ -24,9 +24,9 @@ import type { ZcaFriend, ZcaGroup } from "./types.js";
const channel = "zalouser" as const;
function setZalouserDmPolicy(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
dmPolicy: "pairing" | "allowlist" | "open" | "disabled",
): ClawdbotConfig {
): MoltbotConfig {
const allowFrom =
dmPolicy === "open"
? addWildcardAllowFrom(cfg.channels?.zalouser?.allowFrom)
@@ -41,7 +41,7 @@ function setZalouserDmPolicy(
...(allowFrom ? { allowFrom } : {}),
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
async function noteZalouserHelp(prompter: WizardPrompter): Promise<void> {
@@ -60,10 +60,10 @@ async function noteZalouserHelp(prompter: WizardPrompter): Promise<void> {
}
async function promptZalouserAllowFrom(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
prompter: WizardPrompter;
accountId: string;
}): Promise<ClawdbotConfig> {
}): Promise<MoltbotConfig> {
const { cfg, prompter, accountId } = params;
const resolved = resolveZalouserAccountSync({ cfg, accountId });
const existingAllowFrom = resolved.config.allowFrom ?? [];
@@ -131,7 +131,7 @@ async function promptZalouserAllowFrom(params: {
allowFrom: unique,
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
return {
@@ -152,15 +152,15 @@ async function promptZalouserAllowFrom(params: {
},
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
}
function setZalouserGroupPolicy(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
accountId: string,
groupPolicy: "open" | "allowlist" | "disabled",
): ClawdbotConfig {
): MoltbotConfig {
if (accountId === DEFAULT_ACCOUNT_ID) {
return {
...cfg,
@@ -172,7 +172,7 @@ function setZalouserGroupPolicy(
groupPolicy,
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
return {
...cfg,
@@ -191,14 +191,14 @@ function setZalouserGroupPolicy(
},
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
function setZalouserGroupAllowlist(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
accountId: string,
groupKeys: string[],
): ClawdbotConfig {
): MoltbotConfig {
const groups = Object.fromEntries(groupKeys.map((key) => [key, { allow: true }]));
if (accountId === DEFAULT_ACCOUNT_ID) {
return {
@@ -211,7 +211,7 @@ function setZalouserGroupAllowlist(
groups,
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
return {
...cfg,
@@ -230,11 +230,11 @@ function setZalouserGroupAllowlist(
},
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
async function resolveZalouserGroups(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
accountId: string;
entries: string[];
}): Promise<Array<{ input: string; resolved: boolean; id?: string }>> {
@@ -270,15 +270,15 @@ const dmPolicy: ChannelOnboardingDmPolicy = {
channel,
policyKey: "channels.zalouser.dmPolicy",
allowFromKey: "channels.zalouser.allowFrom",
getCurrent: (cfg) => ((cfg as ClawdbotConfig).channels?.zalouser?.dmPolicy ?? "pairing") as "pairing",
setPolicy: (cfg, policy) => setZalouserDmPolicy(cfg as ClawdbotConfig, policy),
getCurrent: (cfg) => ((cfg as MoltbotConfig).channels?.zalouser?.dmPolicy ?? "pairing") as "pairing",
setPolicy: (cfg, policy) => setZalouserDmPolicy(cfg as MoltbotConfig, policy),
promptAllowFrom: async ({ cfg, prompter, accountId }) => {
const id =
accountId && normalizeAccountId(accountId)
? normalizeAccountId(accountId) ?? DEFAULT_ACCOUNT_ID
: resolveDefaultZalouserAccountId(cfg as ClawdbotConfig);
: resolveDefaultZalouserAccountId(cfg as MoltbotConfig);
return promptZalouserAllowFrom({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
prompter,
accountId: id,
});
@@ -289,10 +289,10 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
channel,
dmPolicy,
getStatus: async ({ cfg }) => {
const ids = listZalouserAccountIds(cfg as ClawdbotConfig);
const ids = listZalouserAccountIds(cfg as MoltbotConfig);
let configured = false;
for (const accountId of ids) {
const account = resolveZalouserAccountSync({ cfg: cfg as ClawdbotConfig, accountId });
const account = resolveZalouserAccountSync({ cfg: cfg as MoltbotConfig, accountId });
const isAuth = await checkZcaAuthenticated(account.profile);
if (isAuth) {
configured = true;
@@ -324,14 +324,14 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
}
const zalouserOverride = accountOverrides.zalouser?.trim();
const defaultAccountId = resolveDefaultZalouserAccountId(cfg as ClawdbotConfig);
const defaultAccountId = resolveDefaultZalouserAccountId(cfg as MoltbotConfig);
let accountId = zalouserOverride
? normalizeAccountId(zalouserOverride)
: defaultAccountId;
if (shouldPromptAccountIds && !zalouserOverride) {
accountId = await promptAccountId({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
prompter,
label: "Zalo Personal",
currentId: accountId,
@@ -340,7 +340,7 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
});
}
let next = cfg as ClawdbotConfig;
let next = cfg as MoltbotConfig;
const account = resolveZalouserAccountSync({ cfg: next, accountId });
const alreadyAuthenticated = await checkZcaAuthenticated(account.profile);
@@ -398,7 +398,7 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
profile: account.profile !== "default" ? account.profile : undefined,
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
} else {
next = {
...next,
@@ -417,7 +417,7 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
},
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
if (forceAllowFrom) {

View File

@@ -60,7 +60,7 @@ export function collectZalouserStatusIssues(
accountId,
kind: "auth",
message: "Not authenticated (no zca session).",
fix: "Run: clawdbot channels login --channel zalouser",
fix: "Run: moltbot channels login --channel zalouser",
});
}
continue;