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
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { bluebubblesPlugin } from "./src/channel.js";
@@ -10,7 +10,7 @@ const plugin = {
name: "BlueBubbles",
description: "BlueBubbles channel plugin (macOS app)",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setBlueBubblesRuntime(api.runtime);
api.registerChannel({ plugin: bluebubblesPlugin });
api.registerHttpHandler(handleBlueBubblesWebhookRequest);
+2 -2
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/bluebubbles",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot BlueBubbles channel plugin",
"clawdbot": {
"description": "Moltbot BlueBubbles channel plugin",
"moltbot": {
"extensions": [
"./index.ts"
],
+8 -8
View File
@@ -1,4 +1,4 @@
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "clawdbot/plugin-sdk";
import { normalizeBlueBubblesServerUrl, type BlueBubblesAccountConfig } from "./types.js";
@@ -11,26 +11,26 @@ export type ResolvedBlueBubblesAccount = {
baseUrl?: string;
};
function listConfiguredAccountIds(cfg: ClawdbotConfig): string[] {
function listConfiguredAccountIds(cfg: MoltbotConfig): string[] {
const accounts = cfg.channels?.bluebubbles?.accounts;
if (!accounts || typeof accounts !== "object") return [];
return Object.keys(accounts).filter(Boolean);
}
export function listBlueBubblesAccountIds(cfg: ClawdbotConfig): string[] {
export function listBlueBubblesAccountIds(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 resolveDefaultBlueBubblesAccountId(cfg: ClawdbotConfig): string {
export function resolveDefaultBlueBubblesAccountId(cfg: MoltbotConfig): string {
const ids = listBlueBubblesAccountIds(cfg);
if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID;
return ids[0] ?? DEFAULT_ACCOUNT_ID;
}
function resolveAccountConfig(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
accountId: string,
): BlueBubblesAccountConfig | undefined {
const accounts = cfg.channels?.bluebubbles?.accounts;
@@ -39,7 +39,7 @@ function resolveAccountConfig(
}
function mergeBlueBubblesAccountConfig(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
accountId: string,
): BlueBubblesAccountConfig {
const base = (cfg.channels?.bluebubbles ?? {}) as BlueBubblesAccountConfig & {
@@ -52,7 +52,7 @@ function mergeBlueBubblesAccountConfig(
}
export function resolveBlueBubblesAccount(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
accountId?: string | null;
}): ResolvedBlueBubblesAccount {
const accountId = normalizeAccountId(params.accountId);
@@ -73,7 +73,7 @@ export function resolveBlueBubblesAccount(params: {
};
}
export function listEnabledBlueBubblesAccounts(cfg: ClawdbotConfig): ResolvedBlueBubblesAccount[] {
export function listEnabledBlueBubblesAccounts(cfg: MoltbotConfig): ResolvedBlueBubblesAccount[] {
return listBlueBubblesAccountIds(cfg)
.map((accountId) => resolveBlueBubblesAccount({ cfg, accountId }))
.filter((account) => account.enabled);
+22 -22
View File
@@ -1,7 +1,7 @@
import { describe, expect, it, vi, beforeEach } from "vitest";
import { bluebubblesMessageActions } from "./actions.js";
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
vi.mock("./accounts.js", () => ({
resolveBlueBubblesAccount: vi.fn(({ cfg, accountId }) => {
@@ -49,7 +49,7 @@ describe("bluebubblesMessageActions", () => {
describe("listActions", () => {
it("returns empty array when account is not enabled", () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: { bluebubbles: { enabled: false } },
};
const actions = bluebubblesMessageActions.listActions({ cfg });
@@ -57,7 +57,7 @@ describe("bluebubblesMessageActions", () => {
});
it("returns empty array when account is not configured", () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: { bluebubbles: { enabled: true } },
};
const actions = bluebubblesMessageActions.listActions({ cfg });
@@ -65,7 +65,7 @@ describe("bluebubblesMessageActions", () => {
});
it("returns react action when enabled and configured", () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
enabled: true,
@@ -79,7 +79,7 @@ describe("bluebubblesMessageActions", () => {
});
it("excludes react action when reactions are gated off", () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
enabled: true,
@@ -153,7 +153,7 @@ describe("bluebubblesMessageActions", () => {
describe("handleAction", () => {
it("throws for unsupported actions", async () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -172,7 +172,7 @@ describe("bluebubblesMessageActions", () => {
});
it("throws when emoji is missing for react action", async () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -191,7 +191,7 @@ describe("bluebubblesMessageActions", () => {
});
it("throws when messageId is missing", async () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -213,7 +213,7 @@ describe("bluebubblesMessageActions", () => {
const { resolveChatGuidForTarget } = await import("./send.js");
vi.mocked(resolveChatGuidForTarget).mockResolvedValueOnce(null);
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -234,7 +234,7 @@ describe("bluebubblesMessageActions", () => {
it("sends reaction successfully with chatGuid", async () => {
const { sendBlueBubblesReaction } = await import("./reactions.js");
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -269,7 +269,7 @@ describe("bluebubblesMessageActions", () => {
it("sends reaction removal successfully", async () => {
const { sendBlueBubblesReaction } = await import("./reactions.js");
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -305,7 +305,7 @@ describe("bluebubblesMessageActions", () => {
const { resolveChatGuidForTarget } = await import("./send.js");
vi.mocked(resolveChatGuidForTarget).mockResolvedValueOnce("iMessage;-;+15559876543");
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -335,7 +335,7 @@ describe("bluebubblesMessageActions", () => {
it("passes partIndex when provided", async () => {
const { sendBlueBubblesReaction } = await import("./reactions.js");
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -367,7 +367,7 @@ describe("bluebubblesMessageActions", () => {
const { resolveChatGuidForTarget } = await import("./send.js");
vi.mocked(resolveChatGuidForTarget).mockResolvedValueOnce("iMessage;-;+15550001111");
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -405,7 +405,7 @@ describe("bluebubblesMessageActions", () => {
const { sendBlueBubblesReaction } = await import("./reactions.js");
vi.mocked(resolveBlueBubblesMessageId).mockReturnValueOnce("resolved-uuid");
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -439,7 +439,7 @@ describe("bluebubblesMessageActions", () => {
throw new Error("short id expired");
});
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -465,7 +465,7 @@ describe("bluebubblesMessageActions", () => {
it("accepts message param for edit action", async () => {
const { editBlueBubblesMessage } = await import("./chat.js");
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -491,7 +491,7 @@ describe("bluebubblesMessageActions", () => {
it("accepts message/target aliases for sendWithEffect", async () => {
const { sendMessageBlueBubbles } = await import("./send.js");
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -524,7 +524,7 @@ describe("bluebubblesMessageActions", () => {
it("passes asVoice through sendAttachment", async () => {
const { sendBlueBubblesAttachment } = await import("./attachments.js");
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -558,7 +558,7 @@ describe("bluebubblesMessageActions", () => {
});
it("throws when buffer is missing for setGroupIcon", async () => {
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -580,7 +580,7 @@ describe("bluebubblesMessageActions", () => {
it("sets group icon successfully with chatGuid and buffer", async () => {
const { setGroupIconBlueBubbles } = await import("./chat.js");
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
@@ -619,7 +619,7 @@ describe("bluebubblesMessageActions", () => {
it("uses default filename when not provided for setGroupIcon", async () => {
const { setGroupIconBlueBubbles } = await import("./chat.js");
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
+5 -5
View File
@@ -9,7 +9,7 @@ import {
type ChannelMessageActionAdapter,
type ChannelMessageActionName,
type ChannelToolSend,
type ClawdbotConfig,
type MoltbotConfig,
} from "clawdbot/plugin-sdk";
import { resolveBlueBubblesAccount } from "./accounts.js";
@@ -66,9 +66,9 @@ const SUPPORTED_ACTIONS = new Set<ChannelMessageActionName>(BLUEBUBBLES_ACTION_N
export const bluebubblesMessageActions: ChannelMessageActionAdapter = {
listActions: ({ cfg }) => {
const account = resolveBlueBubblesAccount({ cfg: cfg as ClawdbotConfig });
const account = resolveBlueBubblesAccount({ cfg: cfg as MoltbotConfig });
if (!account.enabled || !account.configured) return [];
const gate = createActionGate((cfg as ClawdbotConfig).channels?.bluebubbles?.actions);
const gate = createActionGate((cfg as MoltbotConfig).channels?.bluebubbles?.actions);
const actions = new Set<ChannelMessageActionName>();
const macOS26 = isMacOS26OrHigher(account.accountId);
for (const action of BLUEBUBBLES_ACTION_NAMES) {
@@ -90,12 +90,12 @@ export const bluebubblesMessageActions: ChannelMessageActionAdapter = {
},
handleAction: async ({ action, params, cfg, accountId, toolContext }) => {
const account = resolveBlueBubblesAccount({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
accountId: accountId ?? undefined,
});
const baseUrl = account.config.serverUrl?.trim();
const password = account.config.password?.trim();
const opts = { cfg: cfg as ClawdbotConfig, accountId: accountId ?? undefined };
const opts = { cfg: cfg as MoltbotConfig, accountId: accountId ?? undefined };
// Helper to resolve chatGuid from various params or session context
const resolveChatGuid = async (): Promise<string> => {
+2 -2
View File
@@ -1,6 +1,6 @@
import crypto from "node:crypto";
import path from "node:path";
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import { resolveBlueBubblesAccount } from "./accounts.js";
import { resolveChatGuidForTarget } from "./send.js";
import { parseBlueBubblesTarget, normalizeBlueBubblesHandle } from "./targets.js";
@@ -16,7 +16,7 @@ export type BlueBubblesAttachmentOpts = {
password?: string;
accountId?: string;
timeoutMs?: number;
cfg?: ClawdbotConfig;
cfg?: MoltbotConfig;
};
const DEFAULT_ATTACHMENT_MAX_BYTES = 8 * 1024 * 1024;
+16 -16
View File
@@ -1,4 +1,4 @@
import type { ChannelAccountSnapshot, ChannelPlugin, ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { ChannelAccountSnapshot, ChannelPlugin, MoltbotConfig } from "clawdbot/plugin-sdk";
import {
applyAccountNameToChannelSection,
buildChannelConfigSchema,
@@ -78,13 +78,13 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
configSchema: buildChannelConfigSchema(BlueBubblesConfigSchema),
onboarding: blueBubblesOnboardingAdapter,
config: {
listAccountIds: (cfg) => listBlueBubblesAccountIds(cfg as ClawdbotConfig),
listAccountIds: (cfg) => listBlueBubblesAccountIds(cfg as MoltbotConfig),
resolveAccount: (cfg, accountId) =>
resolveBlueBubblesAccount({ cfg: cfg as ClawdbotConfig, accountId }),
defaultAccountId: (cfg) => resolveDefaultBlueBubblesAccountId(cfg as ClawdbotConfig),
resolveBlueBubblesAccount({ cfg: cfg as MoltbotConfig, accountId }),
defaultAccountId: (cfg) => resolveDefaultBlueBubblesAccountId(cfg as MoltbotConfig),
setAccountEnabled: ({ cfg, accountId, enabled }) =>
setAccountEnabledInConfigSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
sectionKey: "bluebubbles",
accountId,
enabled,
@@ -92,7 +92,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
}),
deleteAccount: ({ cfg, accountId }) =>
deleteAccountFromConfigSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
sectionKey: "bluebubbles",
accountId,
clearBaseFields: ["serverUrl", "password", "name", "webhookPath"],
@@ -106,7 +106,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
baseUrl: account.baseUrl,
}),
resolveAllowFrom: ({ cfg, accountId }) =>
(resolveBlueBubblesAccount({ cfg: cfg as ClawdbotConfig, accountId }).config.allowFrom ??
(resolveBlueBubblesAccount({ cfg: cfg as MoltbotConfig, accountId }).config.allowFrom ??
[]).map(
(entry) => String(entry),
),
@@ -122,7 +122,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
resolveDmPolicy: ({ cfg, accountId, account }) => {
const resolvedAccountId = accountId ?? account.accountId ?? DEFAULT_ACCOUNT_ID;
const useAccountPath = Boolean(
(cfg as ClawdbotConfig).channels?.bluebubbles?.accounts?.[resolvedAccountId],
(cfg as MoltbotConfig).channels?.bluebubbles?.accounts?.[resolvedAccountId],
);
const basePath = useAccountPath
? `channels.bluebubbles.accounts.${resolvedAccountId}.`
@@ -207,7 +207,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
applyAccountName: ({ cfg, accountId, name }) =>
applyAccountNameToChannelSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
channelKey: "bluebubbles",
accountId,
name,
@@ -222,7 +222,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
},
applyAccountConfig: ({ cfg, accountId, input }) => {
const namedConfig = applyAccountNameToChannelSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
channelKey: "bluebubbles",
accountId,
name: input.name,
@@ -247,7 +247,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
...(input.webhookPath ? { webhookPath: input.webhookPath } : {}),
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
return {
...next,
@@ -268,7 +268,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
},
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
},
},
pairing: {
@@ -276,7 +276,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
normalizeAllowEntry: (entry) => normalizeBlueBubblesHandle(entry.replace(/^bluebubbles:/i, "")),
notifyApproval: async ({ cfg, id }) => {
await sendMessageBlueBubbles(id, PAIRING_APPROVED_MESSAGE, {
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
});
},
},
@@ -300,7 +300,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
? resolveBlueBubblesMessageId(rawReplyToId, { requireKnownShortId: true })
: "";
const result = await sendMessageBlueBubbles(to, text, {
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
accountId: accountId ?? undefined,
replyToMessageGuid: replyToMessageGuid || undefined,
});
@@ -317,7 +317,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
};
const resolvedCaption = caption ?? text;
const result = await sendBlueBubblesMedia({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
to,
mediaUrl,
mediaPath,
@@ -388,7 +388,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
ctx.log?.info(`[${account.accountId}] starting provider (webhook=${webhookPath})`);
return monitorBlueBubblesProvider({
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 }),
+2 -2
View File
@@ -1,6 +1,6 @@
import crypto from "node:crypto";
import { resolveBlueBubblesAccount } from "./accounts.js";
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import { blueBubblesFetchWithTimeout, buildBlueBubblesApiUrl } from "./types.js";
export type BlueBubblesChatOpts = {
@@ -8,7 +8,7 @@ export type BlueBubblesChatOpts = {
password?: string;
accountId?: string;
timeoutMs?: number;
cfg?: ClawdbotConfig;
cfg?: MoltbotConfig;
};
function resolveAccount(params: BlueBubblesChatOpts) {
+2 -2
View File
@@ -1,7 +1,7 @@
import path from "node:path";
import { fileURLToPath } from "node:url";
import { resolveChannelMediaMaxBytes, type ClawdbotConfig } from "clawdbot/plugin-sdk";
import { resolveChannelMediaMaxBytes, type MoltbotConfig } from "clawdbot/plugin-sdk";
import { sendBlueBubblesAttachment } from "./attachments.js";
import { resolveBlueBubblesMessageId } from "./monitor.js";
@@ -49,7 +49,7 @@ function resolveFilenameFromSource(source?: string): string | undefined {
}
export async function sendBlueBubblesMedia(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
to: string;
mediaUrl?: string;
mediaPath?: string;
+47 -47
View File
@@ -3,7 +3,7 @@ import type { IncomingMessage, ServerResponse } from "node:http";
import { EventEmitter } from "node:events";
import { removeAckReactionAfterReply, shouldAckReaction } from "clawdbot/plugin-sdk";
import type { ClawdbotConfig, PluginRuntime } from "clawdbot/plugin-sdk";
import type { MoltbotConfig, PluginRuntime } from "clawdbot/plugin-sdk";
import {
handleBlueBubblesWebhookRequest,
registerBlueBubblesWebhookTarget,
@@ -178,7 +178,7 @@ function createMockRuntime(): PluginRuntime {
})) as unknown as PluginRuntime["logging"]["getChildLogger"],
},
state: {
resolveStateDir: vi.fn(() => "/tmp/clawdbot") as unknown as PluginRuntime["state"]["resolveStateDir"],
resolveStateDir: vi.fn(() => "/tmp/moltbot") as unknown as PluginRuntime["state"]["resolveStateDir"],
},
};
}
@@ -264,7 +264,7 @@ describe("BlueBubbles webhook monitor", () => {
describe("webhook parsing + auth handling", () => {
it("rejects non-POST requests", async () => {
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -287,7 +287,7 @@ describe("BlueBubbles webhook monitor", () => {
it("accepts POST requests with valid JSON payload", async () => {
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -323,7 +323,7 @@ describe("BlueBubbles webhook monitor", () => {
it("rejects requests with invalid JSON", async () => {
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -346,7 +346,7 @@ describe("BlueBubbles webhook monitor", () => {
it("authenticates via password query parameter", async () => {
const account = createMockAccount({ password: "secret-token" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -380,7 +380,7 @@ describe("BlueBubbles webhook monitor", () => {
it("authenticates via x-password header", async () => {
const account = createMockAccount({ password: "secret-token" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -418,7 +418,7 @@ describe("BlueBubbles webhook monitor", () => {
it("rejects unauthorized requests with wrong password", async () => {
const account = createMockAccount({ password: "secret-token" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -451,7 +451,7 @@ describe("BlueBubbles webhook monitor", () => {
it("allows localhost requests without authentication", async () => {
const account = createMockAccount({ password: "secret-token" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -497,7 +497,7 @@ describe("BlueBubbles webhook monitor", () => {
vi.mocked(resolveChatGuidForTarget).mockClear();
const account = createMockAccount({ groupPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -545,7 +545,7 @@ describe("BlueBubbles webhook monitor", () => {
});
const account = createMockAccount({ groupPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -591,7 +591,7 @@ describe("BlueBubbles webhook monitor", () => {
dmPolicy: "allowlist",
allowFrom: ["+15551234567"],
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -632,7 +632,7 @@ describe("BlueBubbles webhook monitor", () => {
dmPolicy: "allowlist",
allowFrom: ["+15559999999"], // Different number
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -673,7 +673,7 @@ describe("BlueBubbles webhook monitor", () => {
dmPolicy: "pairing",
allowFrom: ["+15559999999"], // Different number than sender
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -716,7 +716,7 @@ describe("BlueBubbles webhook monitor", () => {
dmPolicy: "pairing",
allowFrom: ["+15559999999"], // Different number than sender
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -757,7 +757,7 @@ describe("BlueBubbles webhook monitor", () => {
dmPolicy: "open",
allowFrom: [],
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -794,7 +794,7 @@ describe("BlueBubbles webhook monitor", () => {
const account = createMockAccount({
dmPolicy: "disabled",
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -833,7 +833,7 @@ describe("BlueBubbles webhook monitor", () => {
const account = createMockAccount({
groupPolicy: "open",
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -871,7 +871,7 @@ describe("BlueBubbles webhook monitor", () => {
const account = createMockAccount({
groupPolicy: "disabled",
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -910,7 +910,7 @@ describe("BlueBubbles webhook monitor", () => {
groupPolicy: "allowlist",
dmPolicy: "open",
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -949,7 +949,7 @@ describe("BlueBubbles webhook monitor", () => {
groupPolicy: "allowlist",
groupAllowFrom: ["chat_guid:iMessage;+;chat123456"],
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -990,7 +990,7 @@ describe("BlueBubbles webhook monitor", () => {
mockMatchesMentionPatterns.mockReturnValue(true);
const account = createMockAccount({ groupPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1031,7 +1031,7 @@ describe("BlueBubbles webhook monitor", () => {
mockMatchesMentionPatterns.mockReturnValue(false);
const account = createMockAccount({ groupPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1069,7 +1069,7 @@ describe("BlueBubbles webhook monitor", () => {
mockResolveRequireMention.mockReturnValue(false);
const account = createMockAccount({ groupPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1107,7 +1107,7 @@ describe("BlueBubbles webhook monitor", () => {
describe("group metadata", () => {
it("includes group subject + members in ctx", async () => {
const account = createMockAccount({ groupPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1153,7 +1153,7 @@ describe("BlueBubbles webhook monitor", () => {
describe("reply metadata", () => {
it("surfaces reply fields in ctx when provided", async () => {
const account = createMockAccount({ dmPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1201,7 +1201,7 @@ describe("BlueBubbles webhook monitor", () => {
it("preserves part index prefixes in reply tags when short IDs are unavailable", async () => {
const account = createMockAccount({ dmPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1246,7 +1246,7 @@ describe("BlueBubbles webhook monitor", () => {
it("hydrates missing reply sender/body from the recent-message cache", async () => {
const account = createMockAccount({ dmPolicy: "open", groupPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1316,7 +1316,7 @@ describe("BlueBubbles webhook monitor", () => {
it("falls back to threadOriginatorGuid when reply metadata is absent", async () => {
const account = createMockAccount({ dmPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1357,7 +1357,7 @@ describe("BlueBubbles webhook monitor", () => {
describe("tapback text parsing", () => {
it("does not rewrite tapback-like text without metadata", async () => {
const account = createMockAccount({ dmPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1397,7 +1397,7 @@ describe("BlueBubbles webhook monitor", () => {
it("parses tapback text with custom emoji when metadata is present", async () => {
const account = createMockAccount({ dmPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1442,7 +1442,7 @@ describe("BlueBubbles webhook monitor", () => {
vi.mocked(sendBlueBubblesReaction).mockClear();
const account = createMockAccount({ dmPolicy: "open" });
const config: ClawdbotConfig = {
const config: MoltbotConfig = {
messages: {
ackReaction: "❤️",
ackReactionScope: "direct",
@@ -1500,7 +1500,7 @@ describe("BlueBubbles webhook monitor", () => {
groupPolicy: "open",
allowFrom: ["+15551234567"],
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1543,7 +1543,7 @@ describe("BlueBubbles webhook monitor", () => {
groupPolicy: "open",
allowFrom: [], // No one authorized
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1586,7 +1586,7 @@ describe("BlueBubbles webhook monitor", () => {
const account = createMockAccount({
sendReadReceipts: true,
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1627,7 +1627,7 @@ describe("BlueBubbles webhook monitor", () => {
const account = createMockAccount({
sendReadReceipts: false,
});
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1666,7 +1666,7 @@ describe("BlueBubbles webhook monitor", () => {
vi.mocked(sendBlueBubblesTyping).mockClear();
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1714,7 +1714,7 @@ describe("BlueBubbles webhook monitor", () => {
vi.mocked(sendBlueBubblesTyping).mockClear();
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1763,7 +1763,7 @@ describe("BlueBubbles webhook monitor", () => {
vi.mocked(sendBlueBubblesTyping).mockClear();
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1813,7 +1813,7 @@ describe("BlueBubbles webhook monitor", () => {
});
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1859,7 +1859,7 @@ describe("BlueBubbles webhook monitor", () => {
mockEnqueueSystemEvent.mockClear();
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1899,7 +1899,7 @@ describe("BlueBubbles webhook monitor", () => {
mockEnqueueSystemEvent.mockClear();
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1939,7 +1939,7 @@ describe("BlueBubbles webhook monitor", () => {
mockEnqueueSystemEvent.mockClear();
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -1976,7 +1976,7 @@ describe("BlueBubbles webhook monitor", () => {
mockEnqueueSystemEvent.mockClear();
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -2017,7 +2017,7 @@ describe("BlueBubbles webhook monitor", () => {
describe("short message ID mapping", () => {
it("assigns sequential short IDs to messages", async () => {
const account = createMockAccount({ dmPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -2057,7 +2057,7 @@ describe("BlueBubbles webhook monitor", () => {
it("resolves short ID back to UUID", async () => {
const account = createMockAccount({ dmPolicy: "open" });
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
@@ -2110,7 +2110,7 @@ describe("BlueBubbles webhook monitor", () => {
describe("fromMe messages", () => {
it("ignores messages from self (fromMe=true)", async () => {
const account = createMockAccount();
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const core = createMockRuntime();
setBlueBubblesRuntime(core);
+5 -5
View File
@@ -1,6 +1,6 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import {
logAckFailure,
logInboundDrop,
@@ -26,7 +26,7 @@ export type BlueBubblesRuntimeEnv = {
export type BlueBubblesMonitorOptions = {
account: ResolvedBlueBubblesAccount;
config: ClawdbotConfig;
config: MoltbotConfig;
runtime: BlueBubblesRuntimeEnv;
abortSignal: AbortSignal;
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void;
@@ -243,7 +243,7 @@ function logGroupAllowlistHint(params: {
type WebhookTarget = {
account: ResolvedBlueBubblesAccount;
config: ClawdbotConfig;
config: MoltbotConfig;
runtime: BlueBubblesRuntimeEnv;
core: BlueBubblesCoreRuntime;
path: string;
@@ -340,7 +340,7 @@ const targetDebouncers = new Map<
>();
function resolveBlueBubblesDebounceMs(
config: ClawdbotConfig,
config: MoltbotConfig,
core: BlueBubblesCoreRuntime,
): number {
const inbound = config.messages?.inbound;
@@ -940,7 +940,7 @@ function maskSecret(value: string): string {
}
function resolveBlueBubblesAckReaction(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
agentId: string;
core: BlueBubblesCoreRuntime;
runtime: BlueBubblesRuntimeEnv;
+7 -7
View File
@@ -1,7 +1,7 @@
import type {
ChannelOnboardingAdapter,
ChannelOnboardingDmPolicy,
ClawdbotConfig,
MoltbotConfig,
DmPolicy,
WizardPrompter,
} from "clawdbot/plugin-sdk";
@@ -22,7 +22,7 @@ import { parseBlueBubblesAllowTarget, normalizeBlueBubblesHandle } from "./targe
const channel = "bluebubbles" as const;
function setBlueBubblesDmPolicy(cfg: ClawdbotConfig, dmPolicy: DmPolicy): ClawdbotConfig {
function setBlueBubblesDmPolicy(cfg: MoltbotConfig, dmPolicy: DmPolicy): MoltbotConfig {
const allowFrom =
dmPolicy === "open" ? addWildcardAllowFrom(cfg.channels?.bluebubbles?.allowFrom) : undefined;
return {
@@ -39,10 +39,10 @@ function setBlueBubblesDmPolicy(cfg: ClawdbotConfig, dmPolicy: DmPolicy): Clawdb
}
function setBlueBubblesAllowFrom(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
accountId: string,
allowFrom: string[],
): ClawdbotConfig {
): MoltbotConfig {
if (accountId === DEFAULT_ACCOUNT_ID) {
return {
...cfg,
@@ -81,10 +81,10 @@ function parseBlueBubblesAllowFromInput(raw: string): string[] {
}
async function promptBlueBubblesAllowFrom(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
prompter: WizardPrompter;
accountId?: string;
}): Promise<ClawdbotConfig> {
}): Promise<MoltbotConfig> {
const accountId =
params.accountId && normalizeAccountId(params.accountId)
? (normalizeAccountId(params.accountId) ?? DEFAULT_ACCOUNT_ID)
@@ -318,7 +318,7 @@ export const blueBubblesOnboardingAdapter: ChannelOnboardingAdapter = {
[
"Configure the webhook URL in BlueBubbles Server:",
"1. Open BlueBubbles Server → Settings → Webhooks",
"2. Add your Clawdbot gateway URL + webhook path",
"2. Add your Moltbot gateway URL + webhook path",
" Example: https://your-gateway-host:3000/bluebubbles-webhook",
"3. Enable the webhook and save",
"",
+2 -2
View File
@@ -1,5 +1,5 @@
import { resolveBlueBubblesAccount } from "./accounts.js";
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import { blueBubblesFetchWithTimeout, buildBlueBubblesApiUrl } from "./types.js";
export type BlueBubblesReactionOpts = {
@@ -7,7 +7,7 @@ export type BlueBubblesReactionOpts = {
password?: string;
accountId?: string;
timeoutMs?: number;
cfg?: ClawdbotConfig;
cfg?: MoltbotConfig;
};
const REACTION_TYPES = new Set([
+2 -2
View File
@@ -6,7 +6,7 @@ import {
normalizeBlueBubblesHandle,
parseBlueBubblesTarget,
} from "./targets.js";
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import {
blueBubblesFetchWithTimeout,
buildBlueBubblesApiUrl,
@@ -18,7 +18,7 @@ export type BlueBubblesSendOpts = {
password?: string;
accountId?: string;
timeoutMs?: number;
cfg?: ClawdbotConfig;
cfg?: MoltbotConfig;
/** Message GUID to reply to (reply threading) */
replyToMessageGuid?: string;
/** Part index for reply (default: 0) */
+2 -2
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/copilot-proxy",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot Copilot Proxy provider plugin",
"clawdbot": {
"description": "Moltbot Copilot Proxy provider plugin",
"moltbot": {
"extensions": [
"./index.ts"
]
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { createDiagnosticsOtelService } from "./src/service.js";
@@ -8,7 +8,7 @@ const plugin = {
name: "Diagnostics OpenTelemetry",
description: "Export diagnostics events to OpenTelemetry",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
api.registerService(createDiagnosticsOtelService());
},
};
+2 -2
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/diagnostics-otel",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot diagnostics OpenTelemetry exporter",
"clawdbot": {
"description": "Moltbot diagnostics OpenTelemetry exporter",
"moltbot": {
"extensions": [
"./index.ts"
]
+12 -12
View File
@@ -191,20 +191,20 @@ describe("diagnostics-otel service", () => {
attempt: 2,
});
expect(telemetryState.counters.get("clawdbot.webhook.received")?.add).toHaveBeenCalled();
expect(telemetryState.histograms.get("clawdbot.webhook.duration_ms")?.record).toHaveBeenCalled();
expect(telemetryState.counters.get("clawdbot.message.queued")?.add).toHaveBeenCalled();
expect(telemetryState.counters.get("clawdbot.message.processed")?.add).toHaveBeenCalled();
expect(telemetryState.histograms.get("clawdbot.message.duration_ms")?.record).toHaveBeenCalled();
expect(telemetryState.histograms.get("clawdbot.queue.wait_ms")?.record).toHaveBeenCalled();
expect(telemetryState.counters.get("clawdbot.session.stuck")?.add).toHaveBeenCalled();
expect(telemetryState.histograms.get("clawdbot.session.stuck_age_ms")?.record).toHaveBeenCalled();
expect(telemetryState.counters.get("clawdbot.run.attempt")?.add).toHaveBeenCalled();
expect(telemetryState.counters.get("moltbot.webhook.received")?.add).toHaveBeenCalled();
expect(telemetryState.histograms.get("moltbot.webhook.duration_ms")?.record).toHaveBeenCalled();
expect(telemetryState.counters.get("moltbot.message.queued")?.add).toHaveBeenCalled();
expect(telemetryState.counters.get("moltbot.message.processed")?.add).toHaveBeenCalled();
expect(telemetryState.histograms.get("moltbot.message.duration_ms")?.record).toHaveBeenCalled();
expect(telemetryState.histograms.get("moltbot.queue.wait_ms")?.record).toHaveBeenCalled();
expect(telemetryState.counters.get("moltbot.session.stuck")?.add).toHaveBeenCalled();
expect(telemetryState.histograms.get("moltbot.session.stuck_age_ms")?.record).toHaveBeenCalled();
expect(telemetryState.counters.get("moltbot.run.attempt")?.add).toHaveBeenCalled();
const spanNames = telemetryState.tracer.startSpan.mock.calls.map((call) => call[0]);
expect(spanNames).toContain("clawdbot.webhook.processed");
expect(spanNames).toContain("clawdbot.message.processed");
expect(spanNames).toContain("clawdbot.session.stuck");
expect(spanNames).toContain("moltbot.webhook.processed");
expect(spanNames).toContain("moltbot.message.processed");
expect(spanNames).toContain("moltbot.session.stuck");
expect(registerLogTransportMock).toHaveBeenCalledTimes(1);
expect(registeredTransports).toHaveLength(1);
+84 -84
View File
@@ -10,10 +10,10 @@ import { NodeSDK } from "@opentelemetry/sdk-node";
import { ParentBasedSampler, TraceIdRatioBasedSampler } from "@opentelemetry/sdk-trace-base";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
import type { ClawdbotPluginService, DiagnosticEventPayload } from "clawdbot/plugin-sdk";
import type { MoltbotPluginService, DiagnosticEventPayload } from "clawdbot/plugin-sdk";
import { onDiagnosticEvent, registerLogTransport } from "clawdbot/plugin-sdk";
const DEFAULT_SERVICE_NAME = "clawdbot";
const DEFAULT_SERVICE_NAME = "moltbot";
function normalizeEndpoint(endpoint?: string): string | undefined {
const trimmed = endpoint?.trim();
@@ -32,7 +32,7 @@ function resolveSampleRate(value: number | undefined): number | undefined {
return value;
}
export function createDiagnosticsOtelService(): ClawdbotPluginService {
export function createDiagnosticsOtelService(): MoltbotPluginService {
let sdk: NodeSDK | null = null;
let logProvider: LoggerProvider | null = null;
let stopLogTransport: (() => void) | null = null;
@@ -118,78 +118,78 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
FATAL: 21 as SeverityNumber,
};
const meter = metrics.getMeter("clawdbot");
const tracer = trace.getTracer("clawdbot");
const meter = metrics.getMeter("moltbot");
const tracer = trace.getTracer("moltbot");
const tokensCounter = meter.createCounter("clawdbot.tokens", {
const tokensCounter = meter.createCounter("moltbot.tokens", {
unit: "1",
description: "Token usage by type",
});
const costCounter = meter.createCounter("clawdbot.cost.usd", {
const costCounter = meter.createCounter("moltbot.cost.usd", {
unit: "1",
description: "Estimated model cost (USD)",
});
const durationHistogram = meter.createHistogram("clawdbot.run.duration_ms", {
const durationHistogram = meter.createHistogram("moltbot.run.duration_ms", {
unit: "ms",
description: "Agent run duration",
});
const contextHistogram = meter.createHistogram("clawdbot.context.tokens", {
const contextHistogram = meter.createHistogram("moltbot.context.tokens", {
unit: "1",
description: "Context window size and usage",
});
const webhookReceivedCounter = meter.createCounter("clawdbot.webhook.received", {
const webhookReceivedCounter = meter.createCounter("moltbot.webhook.received", {
unit: "1",
description: "Webhook requests received",
});
const webhookErrorCounter = meter.createCounter("clawdbot.webhook.error", {
const webhookErrorCounter = meter.createCounter("moltbot.webhook.error", {
unit: "1",
description: "Webhook processing errors",
});
const webhookDurationHistogram = meter.createHistogram("clawdbot.webhook.duration_ms", {
const webhookDurationHistogram = meter.createHistogram("moltbot.webhook.duration_ms", {
unit: "ms",
description: "Webhook processing duration",
});
const messageQueuedCounter = meter.createCounter("clawdbot.message.queued", {
const messageQueuedCounter = meter.createCounter("moltbot.message.queued", {
unit: "1",
description: "Messages queued for processing",
});
const messageProcessedCounter = meter.createCounter("clawdbot.message.processed", {
const messageProcessedCounter = meter.createCounter("moltbot.message.processed", {
unit: "1",
description: "Messages processed by outcome",
});
const messageDurationHistogram = meter.createHistogram("clawdbot.message.duration_ms", {
const messageDurationHistogram = meter.createHistogram("moltbot.message.duration_ms", {
unit: "ms",
description: "Message processing duration",
});
const queueDepthHistogram = meter.createHistogram("clawdbot.queue.depth", {
const queueDepthHistogram = meter.createHistogram("moltbot.queue.depth", {
unit: "1",
description: "Queue depth on enqueue/dequeue",
});
const queueWaitHistogram = meter.createHistogram("clawdbot.queue.wait_ms", {
const queueWaitHistogram = meter.createHistogram("moltbot.queue.wait_ms", {
unit: "ms",
description: "Queue wait time before execution",
});
const laneEnqueueCounter = meter.createCounter("clawdbot.queue.lane.enqueue", {
const laneEnqueueCounter = meter.createCounter("moltbot.queue.lane.enqueue", {
unit: "1",
description: "Command queue lane enqueue events",
});
const laneDequeueCounter = meter.createCounter("clawdbot.queue.lane.dequeue", {
const laneDequeueCounter = meter.createCounter("moltbot.queue.lane.dequeue", {
unit: "1",
description: "Command queue lane dequeue events",
});
const sessionStateCounter = meter.createCounter("clawdbot.session.state", {
const sessionStateCounter = meter.createCounter("moltbot.session.state", {
unit: "1",
description: "Session state transitions",
});
const sessionStuckCounter = meter.createCounter("clawdbot.session.stuck", {
const sessionStuckCounter = meter.createCounter("moltbot.session.stuck", {
unit: "1",
description: "Sessions stuck in processing",
});
const sessionStuckAgeHistogram = meter.createHistogram("clawdbot.session.stuck_age_ms", {
const sessionStuckAgeHistogram = meter.createHistogram("moltbot.session.stuck_age_ms", {
unit: "ms",
description: "Age of stuck sessions",
});
const runAttemptCounter = meter.createCounter("clawdbot.run.attempt", {
const runAttemptCounter = meter.createCounter("moltbot.run.attempt", {
unit: "1",
description: "Run attempts",
});
@@ -207,7 +207,7 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
: {}),
}),
);
const otelLogger = logProvider.getLogger("clawdbot");
const otelLogger = logProvider.getLogger("moltbot");
stopLogTransport = registerLogTransport((logObj) => {
const safeStringify = (value: unknown) => {
@@ -265,29 +265,29 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
}
const attributes: Record<string, string | number | boolean> = {
"clawdbot.log.level": logLevelName,
"moltbot.log.level": logLevelName,
};
if (meta?.name) attributes["clawdbot.logger"] = meta.name;
if (meta?.name) attributes["moltbot.logger"] = meta.name;
if (meta?.parentNames?.length) {
attributes["clawdbot.logger.parents"] = meta.parentNames.join(".");
attributes["moltbot.logger.parents"] = meta.parentNames.join(".");
}
if (bindings) {
for (const [key, value] of Object.entries(bindings)) {
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
attributes[`clawdbot.${key}`] = value;
attributes[`moltbot.${key}`] = value;
} else if (value != null) {
attributes[`clawdbot.${key}`] = safeStringify(value);
attributes[`moltbot.${key}`] = safeStringify(value);
}
}
}
if (numericArgs.length > 0) {
attributes["clawdbot.log.args"] = safeStringify(numericArgs);
attributes["moltbot.log.args"] = safeStringify(numericArgs);
}
if (meta?.path?.filePath) attributes["code.filepath"] = meta.path.filePath;
if (meta?.path?.fileLine) attributes["code.lineno"] = Number(meta.path.fileLine);
if (meta?.path?.method) attributes["code.function"] = meta.path.method;
if (meta?.path?.filePathWithLine) {
attributes["clawdbot.code.location"] = meta.path.filePathWithLine;
attributes["moltbot.code.location"] = meta.path.filePathWithLine;
}
otelLogger.emit({
@@ -316,48 +316,48 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
const recordModelUsage = (evt: Extract<DiagnosticEventPayload, { type: "model.usage" }>) => {
const attrs = {
"clawdbot.channel": evt.channel ?? "unknown",
"clawdbot.provider": evt.provider ?? "unknown",
"clawdbot.model": evt.model ?? "unknown",
"moltbot.channel": evt.channel ?? "unknown",
"moltbot.provider": evt.provider ?? "unknown",
"moltbot.model": evt.model ?? "unknown",
};
const usage = evt.usage;
if (usage.input) tokensCounter.add(usage.input, { ...attrs, "clawdbot.token": "input" });
if (usage.output) tokensCounter.add(usage.output, { ...attrs, "clawdbot.token": "output" });
if (usage.input) tokensCounter.add(usage.input, { ...attrs, "moltbot.token": "input" });
if (usage.output) tokensCounter.add(usage.output, { ...attrs, "moltbot.token": "output" });
if (usage.cacheRead)
tokensCounter.add(usage.cacheRead, { ...attrs, "clawdbot.token": "cache_read" });
tokensCounter.add(usage.cacheRead, { ...attrs, "moltbot.token": "cache_read" });
if (usage.cacheWrite)
tokensCounter.add(usage.cacheWrite, { ...attrs, "clawdbot.token": "cache_write" });
tokensCounter.add(usage.cacheWrite, { ...attrs, "moltbot.token": "cache_write" });
if (usage.promptTokens)
tokensCounter.add(usage.promptTokens, { ...attrs, "clawdbot.token": "prompt" });
if (usage.total) tokensCounter.add(usage.total, { ...attrs, "clawdbot.token": "total" });
tokensCounter.add(usage.promptTokens, { ...attrs, "moltbot.token": "prompt" });
if (usage.total) tokensCounter.add(usage.total, { ...attrs, "moltbot.token": "total" });
if (evt.costUsd) costCounter.add(evt.costUsd, attrs);
if (evt.durationMs) durationHistogram.record(evt.durationMs, attrs);
if (evt.context?.limit)
contextHistogram.record(evt.context.limit, {
...attrs,
"clawdbot.context": "limit",
"moltbot.context": "limit",
});
if (evt.context?.used)
contextHistogram.record(evt.context.used, {
...attrs,
"clawdbot.context": "used",
"moltbot.context": "used",
});
if (!tracesEnabled) return;
const spanAttrs: Record<string, string | number> = {
...attrs,
"clawdbot.sessionKey": evt.sessionKey ?? "",
"clawdbot.sessionId": evt.sessionId ?? "",
"clawdbot.tokens.input": usage.input ?? 0,
"clawdbot.tokens.output": usage.output ?? 0,
"clawdbot.tokens.cache_read": usage.cacheRead ?? 0,
"clawdbot.tokens.cache_write": usage.cacheWrite ?? 0,
"clawdbot.tokens.total": usage.total ?? 0,
"moltbot.sessionKey": evt.sessionKey ?? "",
"moltbot.sessionId": evt.sessionId ?? "",
"moltbot.tokens.input": usage.input ?? 0,
"moltbot.tokens.output": usage.output ?? 0,
"moltbot.tokens.cache_read": usage.cacheRead ?? 0,
"moltbot.tokens.cache_write": usage.cacheWrite ?? 0,
"moltbot.tokens.total": usage.total ?? 0,
};
const span = spanWithDuration("clawdbot.model.usage", spanAttrs, evt.durationMs);
const span = spanWithDuration("moltbot.model.usage", spanAttrs, evt.durationMs);
span.end();
};
@@ -365,8 +365,8 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
evt: Extract<DiagnosticEventPayload, { type: "webhook.received" }>,
) => {
const attrs = {
"clawdbot.channel": evt.channel ?? "unknown",
"clawdbot.webhook": evt.updateType ?? "unknown",
"moltbot.channel": evt.channel ?? "unknown",
"moltbot.webhook": evt.updateType ?? "unknown",
};
webhookReceivedCounter.add(1, attrs);
};
@@ -375,16 +375,16 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
evt: Extract<DiagnosticEventPayload, { type: "webhook.processed" }>,
) => {
const attrs = {
"clawdbot.channel": evt.channel ?? "unknown",
"clawdbot.webhook": evt.updateType ?? "unknown",
"moltbot.channel": evt.channel ?? "unknown",
"moltbot.webhook": evt.updateType ?? "unknown",
};
if (typeof evt.durationMs === "number") {
webhookDurationHistogram.record(evt.durationMs, attrs);
}
if (!tracesEnabled) return;
const spanAttrs: Record<string, string | number> = { ...attrs };
if (evt.chatId !== undefined) spanAttrs["clawdbot.chatId"] = String(evt.chatId);
const span = spanWithDuration("clawdbot.webhook.processed", spanAttrs, evt.durationMs);
if (evt.chatId !== undefined) spanAttrs["moltbot.chatId"] = String(evt.chatId);
const span = spanWithDuration("moltbot.webhook.processed", spanAttrs, evt.durationMs);
span.end();
};
@@ -392,17 +392,17 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
evt: Extract<DiagnosticEventPayload, { type: "webhook.error" }>,
) => {
const attrs = {
"clawdbot.channel": evt.channel ?? "unknown",
"clawdbot.webhook": evt.updateType ?? "unknown",
"moltbot.channel": evt.channel ?? "unknown",
"moltbot.webhook": evt.updateType ?? "unknown",
};
webhookErrorCounter.add(1, attrs);
if (!tracesEnabled) return;
const spanAttrs: Record<string, string | number> = {
...attrs,
"clawdbot.error": evt.error,
"moltbot.error": evt.error,
};
if (evt.chatId !== undefined) spanAttrs["clawdbot.chatId"] = String(evt.chatId);
const span = tracer.startSpan("clawdbot.webhook.error", {
if (evt.chatId !== undefined) spanAttrs["moltbot.chatId"] = String(evt.chatId);
const span = tracer.startSpan("moltbot.webhook.error", {
attributes: spanAttrs,
});
span.setStatus({ code: SpanStatusCode.ERROR, message: evt.error });
@@ -413,8 +413,8 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
evt: Extract<DiagnosticEventPayload, { type: "message.queued" }>,
) => {
const attrs = {
"clawdbot.channel": evt.channel ?? "unknown",
"clawdbot.source": evt.source ?? "unknown",
"moltbot.channel": evt.channel ?? "unknown",
"moltbot.source": evt.source ?? "unknown",
};
messageQueuedCounter.add(1, attrs);
if (typeof evt.queueDepth === "number") {
@@ -426,8 +426,8 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
evt: Extract<DiagnosticEventPayload, { type: "message.processed" }>,
) => {
const attrs = {
"clawdbot.channel": evt.channel ?? "unknown",
"clawdbot.outcome": evt.outcome ?? "unknown",
"moltbot.channel": evt.channel ?? "unknown",
"moltbot.outcome": evt.outcome ?? "unknown",
};
messageProcessedCounter.add(1, attrs);
if (typeof evt.durationMs === "number") {
@@ -435,12 +435,12 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
}
if (!tracesEnabled) return;
const spanAttrs: Record<string, string | number> = { ...attrs };
if (evt.sessionKey) spanAttrs["clawdbot.sessionKey"] = evt.sessionKey;
if (evt.sessionId) spanAttrs["clawdbot.sessionId"] = evt.sessionId;
if (evt.chatId !== undefined) spanAttrs["clawdbot.chatId"] = String(evt.chatId);
if (evt.messageId !== undefined) spanAttrs["clawdbot.messageId"] = String(evt.messageId);
if (evt.reason) spanAttrs["clawdbot.reason"] = evt.reason;
const span = spanWithDuration("clawdbot.message.processed", spanAttrs, evt.durationMs);
if (evt.sessionKey) spanAttrs["moltbot.sessionKey"] = evt.sessionKey;
if (evt.sessionId) spanAttrs["moltbot.sessionId"] = evt.sessionId;
if (evt.chatId !== undefined) spanAttrs["moltbot.chatId"] = String(evt.chatId);
if (evt.messageId !== undefined) spanAttrs["moltbot.messageId"] = String(evt.messageId);
if (evt.reason) spanAttrs["moltbot.reason"] = evt.reason;
const span = spanWithDuration("moltbot.message.processed", spanAttrs, evt.durationMs);
if (evt.outcome === "error") {
span.setStatus({ code: SpanStatusCode.ERROR, message: evt.error });
}
@@ -450,7 +450,7 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
const recordLaneEnqueue = (
evt: Extract<DiagnosticEventPayload, { type: "queue.lane.enqueue" }>,
) => {
const attrs = { "clawdbot.lane": evt.lane };
const attrs = { "moltbot.lane": evt.lane };
laneEnqueueCounter.add(1, attrs);
queueDepthHistogram.record(evt.queueSize, attrs);
};
@@ -458,7 +458,7 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
const recordLaneDequeue = (
evt: Extract<DiagnosticEventPayload, { type: "queue.lane.dequeue" }>,
) => {
const attrs = { "clawdbot.lane": evt.lane };
const attrs = { "moltbot.lane": evt.lane };
laneDequeueCounter.add(1, attrs);
queueDepthHistogram.record(evt.queueSize, attrs);
if (typeof evt.waitMs === "number") {
@@ -469,38 +469,38 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
const recordSessionState = (
evt: Extract<DiagnosticEventPayload, { type: "session.state" }>,
) => {
const attrs: Record<string, string> = { "clawdbot.state": evt.state };
if (evt.reason) attrs["clawdbot.reason"] = evt.reason;
const attrs: Record<string, string> = { "moltbot.state": evt.state };
if (evt.reason) attrs["moltbot.reason"] = evt.reason;
sessionStateCounter.add(1, attrs);
};
const recordSessionStuck = (
evt: Extract<DiagnosticEventPayload, { type: "session.stuck" }>,
) => {
const attrs: Record<string, string> = { "clawdbot.state": evt.state };
const attrs: Record<string, string> = { "moltbot.state": evt.state };
sessionStuckCounter.add(1, attrs);
if (typeof evt.ageMs === "number") {
sessionStuckAgeHistogram.record(evt.ageMs, attrs);
}
if (!tracesEnabled) return;
const spanAttrs: Record<string, string | number> = { ...attrs };
if (evt.sessionKey) spanAttrs["clawdbot.sessionKey"] = evt.sessionKey;
if (evt.sessionId) spanAttrs["clawdbot.sessionId"] = evt.sessionId;
spanAttrs["clawdbot.queueDepth"] = evt.queueDepth ?? 0;
spanAttrs["clawdbot.ageMs"] = evt.ageMs;
const span = tracer.startSpan("clawdbot.session.stuck", { attributes: spanAttrs });
if (evt.sessionKey) spanAttrs["moltbot.sessionKey"] = evt.sessionKey;
if (evt.sessionId) spanAttrs["moltbot.sessionId"] = evt.sessionId;
spanAttrs["moltbot.queueDepth"] = evt.queueDepth ?? 0;
spanAttrs["moltbot.ageMs"] = evt.ageMs;
const span = tracer.startSpan("moltbot.session.stuck", { attributes: spanAttrs });
span.setStatus({ code: SpanStatusCode.ERROR, message: "session stuck" });
span.end();
};
const recordRunAttempt = (evt: Extract<DiagnosticEventPayload, { type: "run.attempt" }>) => {
runAttemptCounter.add(1, { "clawdbot.attempt": evt.attempt });
runAttemptCounter.add(1, { "moltbot.attempt": evt.attempt });
};
const recordHeartbeat = (
evt: Extract<DiagnosticEventPayload, { type: "diagnostic.heartbeat" }>,
) => {
queueDepthHistogram.record(evt.queued, { "clawdbot.channel": "heartbeat" });
queueDepthHistogram.record(evt.queued, { "moltbot.channel": "heartbeat" });
};
unsubscribe = onDiagnosticEvent((evt: DiagnosticEventPayload) => {
@@ -562,5 +562,5 @@ export function createDiagnosticsOtelService(): ClawdbotPluginService {
sdk = null;
}
},
} satisfies ClawdbotPluginService;
} satisfies MoltbotPluginService;
}
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { discordPlugin } from "./src/channel.js";
@@ -9,7 +9,7 @@ const plugin = {
name: "Discord",
description: "Discord channel plugin",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setDiscordRuntime(api.runtime);
api.registerChannel({ plugin: discordPlugin });
},
+2 -2
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/discord",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot Discord channel plugin",
"clawdbot": {
"description": "Moltbot Discord channel plugin",
"moltbot": {
"extensions": [
"./index.ts"
]
+1 -1
View File
@@ -32,7 +32,7 @@ const RESPONSE_PAGE = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Clawdbot Antigravity OAuth</title>
<title>Moltbot Antigravity OAuth</title>
</head>
<body>
<main>
@@ -2,8 +2,8 @@
"name": "@moltbot/google-antigravity-auth",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot Google Antigravity OAuth provider plugin",
"clawdbot": {
"description": "Moltbot Google Antigravity OAuth provider plugin",
"moltbot": {
"extensions": [
"./index.ts"
]
+2 -2
View File
@@ -262,7 +262,7 @@ async function waitForLocalCallback(params: {
res.end(
"<!doctype html><html><head><meta charset='utf-8'/></head>" +
"<body><h2>Gemini CLI OAuth complete</h2>" +
"<p>You can close this window and return to Clawdbot.</p></body></html>",
"<p>You can close this window and return to Moltbot.</p></body></html>",
);
finish(undefined, { code, state });
@@ -367,7 +367,7 @@ async function discoverProject(accessToken: string): Promise<string> {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
"User-Agent": "google-api-nodejs-client/9.15.1",
"X-Goog-Api-Client": "gl-node/clawdbot",
"X-Goog-Api-Client": "gl-node/moltbot",
};
const loadBody = {
@@ -2,8 +2,8 @@
"name": "@moltbot/google-gemini-cli-auth",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot Gemini CLI OAuth provider plugin",
"clawdbot": {
"description": "Moltbot Gemini CLI OAuth provider plugin",
"moltbot": {
"extensions": [
"./index.ts"
]
+3 -3
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { googlechatDock, googlechatPlugin } from "./src/channel.js";
@@ -8,9 +8,9 @@ import { setGoogleChatRuntime } from "./src/runtime.js";
const plugin = {
id: "googlechat",
name: "Google Chat",
description: "Clawdbot Google Chat channel plugin",
description: "Moltbot Google Chat channel plugin",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setGoogleChatRuntime(api.runtime);
api.registerChannel({ plugin: googlechatPlugin, dock: googlechatDock });
api.registerHttpHandler(handleGoogleChatWebhookRequest);
+4 -4
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/googlechat",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot Google Chat channel plugin",
"clawdbot": {
"description": "Moltbot Google Chat channel plugin",
"moltbot": {
"extensions": [
"./index.ts"
],
@@ -31,9 +31,9 @@
"google-auth-library": "^10.5.0"
},
"devDependencies": {
"clawdbot": "workspace:*"
"moltbot": "workspace:*"
},
"peerDependencies": {
"clawdbot": ">=2026.1.26"
"moltbot": ">=2026.1.26"
}
}
+8 -8
View File
@@ -1,4 +1,4 @@
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "clawdbot/plugin-sdk";
import type { GoogleChatAccountConfig, GoogleChatConfig } from "./types.config.js";
@@ -18,19 +18,19 @@ export type ResolvedGoogleChatAccount = {
const ENV_SERVICE_ACCOUNT = "GOOGLE_CHAT_SERVICE_ACCOUNT";
const ENV_SERVICE_ACCOUNT_FILE = "GOOGLE_CHAT_SERVICE_ACCOUNT_FILE";
function listConfiguredAccountIds(cfg: ClawdbotConfig): string[] {
function listConfiguredAccountIds(cfg: MoltbotConfig): string[] {
const accounts = (cfg.channels?.["googlechat"] as GoogleChatConfig | undefined)?.accounts;
if (!accounts || typeof accounts !== "object") return [];
return Object.keys(accounts).filter(Boolean);
}
export function listGoogleChatAccountIds(cfg: ClawdbotConfig): string[] {
export function listGoogleChatAccountIds(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 resolveDefaultGoogleChatAccountId(cfg: ClawdbotConfig): string {
export function resolveDefaultGoogleChatAccountId(cfg: MoltbotConfig): string {
const channel = cfg.channels?.["googlechat"] as GoogleChatConfig | undefined;
if (channel?.defaultAccount?.trim()) return channel.defaultAccount.trim();
const ids = listGoogleChatAccountIds(cfg);
@@ -39,7 +39,7 @@ export function resolveDefaultGoogleChatAccountId(cfg: ClawdbotConfig): string {
}
function resolveAccountConfig(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
accountId: string,
): GoogleChatAccountConfig | undefined {
const accounts = (cfg.channels?.["googlechat"] as GoogleChatConfig | undefined)?.accounts;
@@ -48,7 +48,7 @@ function resolveAccountConfig(
}
function mergeGoogleChatAccountConfig(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
accountId: string,
): GoogleChatAccountConfig {
const raw = (cfg.channels?.["googlechat"] ?? {}) as GoogleChatConfig;
@@ -104,7 +104,7 @@ function resolveCredentialsFromConfig(params: {
}
export function resolveGoogleChatAccount(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
accountId?: string | null;
}): ResolvedGoogleChatAccount {
const accountId = normalizeAccountId(params.accountId);
@@ -126,7 +126,7 @@ export function resolveGoogleChatAccount(params: {
};
}
export function listEnabledGoogleChatAccounts(cfg: ClawdbotConfig): ResolvedGoogleChatAccount[] {
export function listEnabledGoogleChatAccounts(cfg: MoltbotConfig): ResolvedGoogleChatAccount[] {
return listGoogleChatAccountIds(cfg)
.map((accountId) => resolveGoogleChatAccount({ cfg, accountId }))
.filter((account) => account.enabled);
+6 -6
View File
@@ -1,7 +1,7 @@
import type {
ChannelMessageActionAdapter,
ChannelMessageActionName,
ClawdbotConfig,
MoltbotConfig,
} from "clawdbot/plugin-sdk";
import {
createActionGate,
@@ -24,13 +24,13 @@ import { resolveGoogleChatOutboundSpace } from "./targets.js";
const providerId = "googlechat";
function listEnabledAccounts(cfg: ClawdbotConfig) {
function listEnabledAccounts(cfg: MoltbotConfig) {
return listEnabledGoogleChatAccounts(cfg).filter(
(account) => account.enabled && account.credentialSource !== "none",
);
}
function isReactionsEnabled(accounts: ReturnType<typeof listEnabledAccounts>, cfg: ClawdbotConfig) {
function isReactionsEnabled(accounts: ReturnType<typeof listEnabledAccounts>, cfg: MoltbotConfig) {
for (const account of accounts) {
const gate = createActionGate(
(account.config.actions ?? (cfg.channels?.["googlechat"] as { actions?: unknown })?.actions) as Record<
@@ -49,11 +49,11 @@ function resolveAppUserNames(account: { config: { botUser?: string | null } }) {
export const googlechatMessageActions: ChannelMessageActionAdapter = {
listActions: ({ cfg }) => {
const accounts = listEnabledAccounts(cfg as ClawdbotConfig);
const accounts = listEnabledAccounts(cfg as MoltbotConfig);
if (accounts.length === 0) return [];
const actions = new Set<ChannelMessageActionName>([]);
actions.add("send");
if (isReactionsEnabled(accounts, cfg as ClawdbotConfig)) {
if (isReactionsEnabled(accounts, cfg as MoltbotConfig)) {
actions.add("react");
actions.add("reactions");
}
@@ -69,7 +69,7 @@ export const googlechatMessageActions: ChannelMessageActionAdapter = {
},
handleAction: async ({ action, params, cfg, accountId }) => {
const account = resolveGoogleChatAccount({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
accountId,
});
if (account.credentialSource === "none") {
+1 -1
View File
@@ -153,7 +153,7 @@ export async function uploadGoogleChatAttachment(params: {
contentType?: string;
}): Promise<{ attachmentUploadToken?: string }> {
const { account, space, filename, buffer, contentType } = params;
const boundary = `clawdbot-${crypto.randomUUID()}`;
const boundary = `moltbot-${crypto.randomUUID()}`;
const metadata = JSON.stringify({ filename });
const header = `--${boundary}\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n${metadata}\r\n`;
const mediaHeader = `--${boundary}\r\nContent-Type: ${contentType ?? "application/octet-stream"}\r\n\r\n`;
+21 -21
View File
@@ -15,7 +15,7 @@ import {
type ChannelDock,
type ChannelMessageActionAdapter,
type ChannelPlugin,
type ClawdbotConfig,
type MoltbotConfig,
} from "clawdbot/plugin-sdk";
import { GoogleChatConfigSchema } from "clawdbot/plugin-sdk";
@@ -59,7 +59,7 @@ export const googlechatDock: ChannelDock = {
outbound: { textChunkLimit: 4000 },
config: {
resolveAllowFrom: ({ cfg, accountId }) =>
(resolveGoogleChatAccount({ cfg: cfg as ClawdbotConfig, accountId }).config.dm?.allowFrom ??
(resolveGoogleChatAccount({ cfg: cfg as MoltbotConfig, accountId }).config.dm?.allowFrom ??
[]
).map((entry) => String(entry)),
formatAllowFrom: ({ allowFrom }) =>
@@ -103,7 +103,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
idLabel: "googlechatUserId",
normalizeAllowEntry: (entry) => formatAllowFromEntry(entry),
notifyApproval: async ({ cfg, id }) => {
const account = resolveGoogleChatAccount({ cfg: cfg as ClawdbotConfig });
const account = resolveGoogleChatAccount({ cfg: cfg as MoltbotConfig });
if (account.credentialSource === "none") return;
const user = normalizeGoogleChatTarget(id) ?? id;
const target = isGoogleChatUserTarget(user) ? user : `users/${user}`;
@@ -129,13 +129,13 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
reload: { configPrefixes: ["channels.googlechat"] },
configSchema: buildChannelConfigSchema(GoogleChatConfigSchema),
config: {
listAccountIds: (cfg) => listGoogleChatAccountIds(cfg as ClawdbotConfig),
listAccountIds: (cfg) => listGoogleChatAccountIds(cfg as MoltbotConfig),
resolveAccount: (cfg, accountId) =>
resolveGoogleChatAccount({ cfg: cfg as ClawdbotConfig, accountId }),
defaultAccountId: (cfg) => resolveDefaultGoogleChatAccountId(cfg as ClawdbotConfig),
resolveGoogleChatAccount({ cfg: cfg as MoltbotConfig, accountId }),
defaultAccountId: (cfg) => resolveDefaultGoogleChatAccountId(cfg as MoltbotConfig),
setAccountEnabled: ({ cfg, accountId, enabled }) =>
setAccountEnabledInConfigSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
sectionKey: "googlechat",
accountId,
enabled,
@@ -143,7 +143,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
}),
deleteAccount: ({ cfg, accountId }) =>
deleteAccountFromConfigSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
sectionKey: "googlechat",
accountId,
clearBaseFields: [
@@ -167,7 +167,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
}),
resolveAllowFrom: ({ cfg, accountId }) =>
(resolveGoogleChatAccount({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
accountId,
}).config.dm?.allowFrom ?? []
).map((entry) => String(entry)),
@@ -181,7 +181,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
resolveDmPolicy: ({ cfg, accountId, account }) => {
const resolvedAccountId = accountId ?? account.accountId ?? DEFAULT_ACCOUNT_ID;
const useAccountPath = Boolean(
(cfg as ClawdbotConfig).channels?.["googlechat"]?.accounts?.[resolvedAccountId],
(cfg as MoltbotConfig).channels?.["googlechat"]?.accounts?.[resolvedAccountId],
);
const allowFromPath = useAccountPath
? `channels.googlechat.accounts.${resolvedAccountId}.dm.`
@@ -231,7 +231,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
self: async () => null,
listPeers: async ({ cfg, accountId, query, limit }) => {
const account = resolveGoogleChatAccount({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
accountId,
});
const q = query?.trim().toLowerCase() || "";
@@ -251,7 +251,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
},
listGroups: async ({ cfg, accountId, query, limit }) => {
const account = resolveGoogleChatAccount({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
accountId,
});
const groups = account.config.groups ?? {};
@@ -291,7 +291,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
applyAccountName: ({ cfg, accountId, name }) =>
applyAccountNameToChannelSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
channelKey: "googlechat",
accountId,
name,
@@ -307,7 +307,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
},
applyAccountConfig: ({ cfg, accountId, input }) => {
const namedConfig = applyAccountNameToChannelSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
channelKey: "googlechat",
accountId,
name: input.name,
@@ -315,7 +315,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
const next =
accountId !== DEFAULT_ACCOUNT_ID
? migrateBaseNameToDefaultAccount({
cfg: namedConfig as ClawdbotConfig,
cfg: namedConfig as MoltbotConfig,
channelKey: "googlechat",
})
: namedConfig;
@@ -348,7 +348,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
...configPatch,
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
return {
...next,
@@ -367,7 +367,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
},
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
},
},
outbound: {
@@ -414,7 +414,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
},
sendText: async ({ cfg, to, text, accountId, replyToId, threadId }) => {
const account = resolveGoogleChatAccount({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
accountId,
});
const space = await resolveGoogleChatOutboundSpace({ account, target: to });
@@ -436,14 +436,14 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
throw new Error("Google Chat mediaUrl is required.");
}
const account = resolveGoogleChatAccount({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
accountId,
});
const space = await resolveGoogleChatOutboundSpace({ account, target: to });
const thread = (threadId ?? replyToId ?? undefined) as string | undefined;
const runtime = getGoogleChatRuntime();
const maxBytes = resolveChannelMediaMaxBytes({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
resolveChannelLimitMb: ({ cfg, accountId }) =>
(cfg.channels?.["googlechat"] as { accounts?: Record<string, { mediaMaxMb?: number }>; mediaMaxMb?: number } | undefined)
?.accounts?.[accountId]?.mediaMaxMb ??
@@ -560,7 +560,7 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
});
const unregister = await startGoogleChatMonitor({
account,
config: ctx.cfg as ClawdbotConfig,
config: ctx.cfg as MoltbotConfig,
runtime: ctx.runtime,
abortSignal: ctx.abortSignal,
webhookPath: account.config.webhookPath,
+8 -8
View File
@@ -1,6 +1,6 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import { resolveMentionGatingWithBypass } from "clawdbot/plugin-sdk";
import {
@@ -30,7 +30,7 @@ export type GoogleChatRuntimeEnv = {
export type GoogleChatMonitorOptions = {
account: ResolvedGoogleChatAccount;
config: ClawdbotConfig;
config: MoltbotConfig;
runtime: GoogleChatRuntimeEnv;
abortSignal: AbortSignal;
webhookPath?: string;
@@ -42,7 +42,7 @@ type GoogleChatCoreRuntime = ReturnType<typeof getGoogleChatRuntime>;
type WebhookTarget = {
account: ResolvedGoogleChatAccount;
config: ClawdbotConfig;
config: MoltbotConfig;
runtime: GoogleChatRuntimeEnv;
core: GoogleChatCoreRuntime;
path: string;
@@ -357,24 +357,24 @@ function extractMentionInfo(annotations: GoogleChatAnnotation[], botUser?: strin
* Resolve bot display name with fallback chain:
* 1. Account config name
* 2. Agent name from config
* 3. "Clawdbot" as generic fallback
* 3. "Moltbot" as generic fallback
*/
function resolveBotDisplayName(params: {
accountName?: string;
agentId: string;
config: ClawdbotConfig;
config: MoltbotConfig;
}): string {
const { accountName, agentId, config } = params;
if (accountName?.trim()) return accountName.trim();
const agent = config.agents?.list?.find((a) => a.id === agentId);
if (agent?.name?.trim()) return agent.name.trim();
return "Clawdbot";
return "Moltbot";
}
async function processMessageWithPipeline(params: {
event: GoogleChatEvent;
account: ResolvedGoogleChatAccount;
config: ClawdbotConfig;
config: MoltbotConfig;
runtime: GoogleChatRuntimeEnv;
core: GoogleChatCoreRuntime;
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void;
@@ -726,7 +726,7 @@ async function deliverGoogleChatReply(params: {
spaceId: string;
runtime: GoogleChatRuntimeEnv;
core: GoogleChatCoreRuntime;
config: ClawdbotConfig;
config: MoltbotConfig;
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void;
typingMessageName?: string;
}): Promise<void> {
+10 -10
View File
@@ -1,4 +1,4 @@
import type { ClawdbotConfig, DmPolicy } from "clawdbot/plugin-sdk";
import type { MoltbotConfig, DmPolicy } from "clawdbot/plugin-sdk";
import {
addWildcardAllowFrom,
formatDocsLink,
@@ -22,7 +22,7 @@ const channel = "googlechat" as const;
const ENV_SERVICE_ACCOUNT = "GOOGLE_CHAT_SERVICE_ACCOUNT";
const ENV_SERVICE_ACCOUNT_FILE = "GOOGLE_CHAT_SERVICE_ACCOUNT_FILE";
function setGoogleChatDmPolicy(cfg: ClawdbotConfig, policy: DmPolicy) {
function setGoogleChatDmPolicy(cfg: MoltbotConfig, policy: DmPolicy) {
const allowFrom =
policy === "open"
? addWildcardAllowFrom(cfg.channels?.["googlechat"]?.dm?.allowFrom)
@@ -51,9 +51,9 @@ function parseAllowFromInput(raw: string): string[] {
}
async function promptAllowFrom(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
prompter: WizardPrompter;
}): Promise<ClawdbotConfig> {
}): Promise<MoltbotConfig> {
const current = params.cfg.channels?.["googlechat"]?.dm?.allowFrom ?? [];
const entry = await params.prompter.text({
message: "Google Chat allowFrom (user id or email)",
@@ -91,10 +91,10 @@ const dmPolicy: ChannelOnboardingDmPolicy = {
};
function applyAccountConfig(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
accountId: string;
patch: Record<string, unknown>;
}): ClawdbotConfig {
}): MoltbotConfig {
const { cfg, accountId, patch } = params;
if (accountId === DEFAULT_ACCOUNT_ID) {
return {
@@ -130,10 +130,10 @@ function applyAccountConfig(params: {
}
async function promptCredentials(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
prompter: WizardPrompter;
accountId: string;
}): Promise<ClawdbotConfig> {
}): Promise<MoltbotConfig> {
const { cfg, prompter, accountId } = params;
const envReady =
accountId === DEFAULT_ACCOUNT_ID &&
@@ -184,10 +184,10 @@ async function promptCredentials(params: {
}
async function promptAudience(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
prompter: WizardPrompter;
accountId: string;
}): Promise<ClawdbotConfig> {
}): Promise<MoltbotConfig> {
const account = resolveGoogleChatAccount({
cfg: params.cfg,
accountId: params.accountId,
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { imessagePlugin } from "./src/channel.js";
@@ -9,7 +9,7 @@ const plugin = {
name: "iMessage",
description: "iMessage channel plugin",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setIMessageRuntime(api.runtime);
api.registerChannel({ plugin: imessagePlugin });
},
+2 -2
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/imessage",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot iMessage channel plugin",
"clawdbot": {
"description": "Moltbot iMessage channel plugin",
"moltbot": {
"extensions": [
"./index.ts"
]
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { linePlugin } from "./src/channel.js";
@@ -10,7 +10,7 @@ const plugin = {
name: "LINE",
description: "LINE Messaging API channel plugin",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setLineRuntime(api.runtime);
api.registerChannel({ plugin: linePlugin });
registerLineCardCommand(api);
+3 -3
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/line",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot LINE channel plugin",
"clawdbot": {
"description": "Moltbot LINE channel plugin",
"moltbot": {
"extensions": [
"./index.ts"
],
@@ -24,6 +24,6 @@
}
},
"devDependencies": {
"clawdbot": "workspace:*"
"moltbot": "workspace:*"
}
}
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi, LineChannelData, ReplyPayload } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi, LineChannelData, ReplyPayload } from "clawdbot/plugin-sdk";
import {
createActionCard,
createImageCard,
@@ -150,7 +150,7 @@ function parseCardArgs(argsStr: string): {
return result;
}
export function registerLineCardCommand(api: ClawdbotPluginApi): void {
export function registerLineCardCommand(api: MoltbotPluginApi): void {
api.registerCommand({
name: "card",
description: "Send a rich card message (LINE).",
+4 -4
View File
@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { ClawdbotConfig, PluginRuntime } from "clawdbot/plugin-sdk";
import type { MoltbotConfig, PluginRuntime } from "clawdbot/plugin-sdk";
import { linePlugin } from "./channel.js";
import { setLineRuntime } from "./runtime.js";
@@ -12,7 +12,7 @@ type LineRuntimeMocks = {
function createRuntime(): { runtime: PluginRuntime; mocks: LineRuntimeMocks } {
const writeConfigFile = vi.fn(async () => {});
const resolveLineAccount = vi.fn(({ cfg, accountId }: { cfg: ClawdbotConfig; accountId?: string }) => {
const resolveLineAccount = vi.fn(({ cfg, accountId }: { cfg: MoltbotConfig; accountId?: string }) => {
const lineConfig = (cfg.channels?.line ?? {}) as {
tokenFile?: string;
secretFile?: string;
@@ -48,7 +48,7 @@ describe("linePlugin gateway.logoutAccount", () => {
const { runtime, mocks } = createRuntime();
setLineRuntime(runtime);
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
line: {
tokenFile: "/tmp/token",
@@ -71,7 +71,7 @@ describe("linePlugin gateway.logoutAccount", () => {
const { runtime, mocks } = createRuntime();
setLineRuntime(runtime);
const cfg: ClawdbotConfig = {
const cfg: MoltbotConfig = {
channels: {
line: {
accounts: {
@@ -1,5 +1,5 @@
import { describe, expect, it, vi } from "vitest";
import type { ClawdbotConfig, PluginRuntime } from "clawdbot/plugin-sdk";
import type { MoltbotConfig, PluginRuntime } from "clawdbot/plugin-sdk";
import { linePlugin } from "./channel.js";
import { setLineRuntime } from "./runtime.js";
@@ -33,7 +33,7 @@ function createRuntime(): { runtime: PluginRuntime; mocks: LineRuntimeMocks } {
const sendMessageLine = vi.fn(async () => ({ messageId: "m-media", chatId: "c1" }));
const chunkMarkdownText = vi.fn((text: string) => [text]);
const resolveTextChunkLimit = vi.fn(() => 123);
const resolveLineAccount = vi.fn(({ cfg, accountId }: { cfg: ClawdbotConfig; accountId?: string }) => {
const resolveLineAccount = vi.fn(({ cfg, accountId }: { cfg: MoltbotConfig; accountId?: string }) => {
const resolved = accountId ?? "default";
const lineConfig = (cfg.channels?.line ?? {}) as {
accounts?: Record<string, Record<string, unknown>>;
@@ -90,7 +90,7 @@ describe("linePlugin outbound.sendPayload", () => {
it("sends flex message without dropping text", async () => {
const { runtime, mocks } = createRuntime();
setLineRuntime(runtime);
const cfg = { channels: { line: {} } } as ClawdbotConfig;
const cfg = { channels: { line: {} } } as MoltbotConfig;
const payload = {
text: "Now playing:",
@@ -121,7 +121,7 @@ describe("linePlugin outbound.sendPayload", () => {
it("sends template message without dropping text", async () => {
const { runtime, mocks } = createRuntime();
setLineRuntime(runtime);
const cfg = { channels: { line: {} } } as ClawdbotConfig;
const cfg = { channels: { line: {} } } as MoltbotConfig;
const payload = {
text: "Choose one:",
@@ -157,7 +157,7 @@ describe("linePlugin outbound.sendPayload", () => {
it("attaches quick replies when no text chunks are present", async () => {
const { runtime, mocks } = createRuntime();
setLineRuntime(runtime);
const cfg = { channels: { line: {} } } as ClawdbotConfig;
const cfg = { channels: { line: {} } } as MoltbotConfig;
const payload = {
channelData: {
@@ -197,7 +197,7 @@ describe("linePlugin outbound.sendPayload", () => {
it("sends media before quick-reply text so buttons stay visible", async () => {
const { runtime, mocks } = createRuntime();
setLineRuntime(runtime);
const cfg = { channels: { line: {} } } as ClawdbotConfig;
const cfg = { channels: { line: {} } } as MoltbotConfig;
const payload = {
text: "Hello",
@@ -235,7 +235,7 @@ describe("linePlugin outbound.sendPayload", () => {
it("uses configured text chunk limit for payloads", async () => {
const { runtime, mocks } = createRuntime();
setLineRuntime(runtime);
const cfg = { channels: { line: { textChunkLimit: 123 } } } as ClawdbotConfig;
const cfg = { channels: { line: { textChunkLimit: 123 } } } as MoltbotConfig;
const payload = {
text: "Hello world",
@@ -295,7 +295,7 @@ describe("linePlugin groups.resolveRequireMention", () => {
},
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
const requireMention = linePlugin.groups.resolveRequireMention({
cfg,
+4 -4
View File
@@ -4,7 +4,7 @@ import {
LineConfigSchema,
processLineMessage,
type ChannelPlugin,
type ClawdbotConfig,
type MoltbotConfig,
type LineConfig,
type LineChannelData,
type ResolvedLineAccount,
@@ -53,7 +53,7 @@ export const linePlugin: ChannelPlugin<ResolvedLineAccount> = {
if (!account.channelAccessToken) {
throw new Error("LINE channel access token not configured");
}
await line.pushMessageLine(id, "Clawdbot: your access has been approved.", {
await line.pushMessageLine(id, "Moltbot: your access has been approved.", {
channelAccessToken: account.channelAccessToken,
});
},
@@ -164,7 +164,7 @@ export const linePlugin: ChannelPlugin<ResolvedLineAccount> = {
allowFrom: account.config.allowFrom ?? [],
policyPath: `${basePath}dmPolicy`,
allowFromPath: basePath,
approveHint: "clawdbot pairing approve line <code>",
approveHint: "moltbot pairing approve line <code>",
normalizeEntry: (raw) => raw.replace(/^line:(?:user:)?/i, ""),
};
},
@@ -639,7 +639,7 @@ export const linePlugin: ChannelPlugin<ResolvedLineAccount> = {
},
logoutAccount: async ({ accountId, cfg }) => {
const envToken = process.env.LINE_CHANNEL_ACCESS_TOKEN?.trim() ?? "";
const nextCfg = { ...cfg } as ClawdbotConfig;
const nextCfg = { ...cfg } as MoltbotConfig;
const lineConfig = (cfg.channels?.line ?? {}) as LineConfig;
const nextLine = { ...lineConfig };
let cleared = false;
+2 -2
View File
@@ -1,7 +1,7 @@
import type { ClawdbotPluginApi } from "../../src/plugins/types.js";
import type { MoltbotPluginApi } from "../../src/plugins/types.js";
import { createLlmTaskTool } from "./src/llm-task-tool.js";
export default function register(api: ClawdbotPluginApi) {
export default function register(api: MoltbotPluginApi) {
api.registerTool(createLlmTaskTool(api), { optional: true });
}
+2 -2
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/llm-task",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot JSON-only LLM task plugin",
"clawdbot": {
"description": "Moltbot JSON-only LLM task plugin",
"moltbot": {
"extensions": [
"./index.ts"
]
+5 -5
View File
@@ -5,12 +5,12 @@ import fs from "node:fs/promises";
import Ajv from "ajv";
import { Type } from "@sinclair/typebox";
// NOTE: This extension is intended to be bundled with Clawdbot.
// When running from source (tests/dev), Clawdbot internals live under src/.
// NOTE: This extension is intended to be bundled with Moltbot.
// When running from source (tests/dev), Moltbot internals live under src/.
// When running from a built install, internals live under dist/ (no src/ tree).
// So we resolve internal imports dynamically with src-first, dist-fallback.
import type { ClawdbotPluginApi } from "../../../src/plugins/types.js";
import type { MoltbotPluginApi } from "../../../src/plugins/types.js";
type RunEmbeddedPiAgentFn = (params: Record<string, unknown>) => Promise<unknown>;
@@ -61,7 +61,7 @@ type PluginCfg = {
timeoutMs?: number;
};
export function createLlmTaskTool(api: ClawdbotPluginApi) {
export function createLlmTaskTool(api: MoltbotPluginApi) {
return {
name: "llm-task",
description:
@@ -154,7 +154,7 @@ export function createLlmTaskTool(api: ClawdbotPluginApi) {
let tmpDir: string | null = null;
try {
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-llm-task-"));
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-llm-task-"));
const sessionId = `llm-task-${Date.now()}`;
const sessionFile = path.join(tmpDir, "session.json");
+2 -2
View File
@@ -1,8 +1,8 @@
import type { ClawdbotPluginApi } from "../../src/plugins/types.js";
import type { MoltbotPluginApi } from "../../src/plugins/types.js";
import { createLobsterTool } from "./src/lobster-tool.js";
export default function register(api: ClawdbotPluginApi) {
export default function register(api: MoltbotPluginApi) {
api.registerTool(
(ctx) => {
if (ctx.sandboxed) return null;
+1 -1
View File
@@ -3,7 +3,7 @@
"version": "2026.1.26",
"type": "module",
"description": "Lobster workflow tool plugin (typed pipelines + resumable approvals)",
"clawdbot": {
"moltbot": {
"extensions": [
"./index.ts"
]
+7 -7
View File
@@ -4,10 +4,10 @@ import path from "node:path";
import { describe, expect, it } from "vitest";
import type { ClawdbotPluginApi, ClawdbotPluginToolContext } from "../../../src/plugins/types.js";
import type { MoltbotPluginApi, MoltbotPluginToolContext } from "../../../src/plugins/types.js";
import { createLobsterTool } from "./lobster-tool.js";
async function writeFakeLobsterScript(scriptBody: string, prefix = "clawdbot-lobster-plugin-") {
async function writeFakeLobsterScript(scriptBody: string, prefix = "moltbot-lobster-plugin-") {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
const isWindows = process.platform === "win32";
@@ -33,7 +33,7 @@ async function writeFakeLobster(params: { payload: unknown }) {
return await writeFakeLobsterScript(scriptBody);
}
function fakeApi(): ClawdbotPluginApi {
function fakeApi(): MoltbotPluginApi {
return {
id: "lobster",
name: "lobster",
@@ -52,7 +52,7 @@ function fakeApi(): ClawdbotPluginApi {
};
}
function fakeCtx(overrides: Partial<ClawdbotPluginToolContext> = {}): ClawdbotPluginToolContext {
function fakeCtx(overrides: Partial<MoltbotPluginToolContext> = {}): MoltbotPluginToolContext {
return {
config: {} as any,
workspaceDir: "/tmp",
@@ -89,7 +89,7 @@ describe("lobster plugin tool", () => {
`const payload = ${JSON.stringify(payload)};\n` +
`console.log("noise before json");\n` +
`process.stdout.write(JSON.stringify(payload));\n`,
"clawdbot-lobster-plugin-noisy-",
"moltbot-lobster-plugin-noisy-",
);
const tool = createLobsterTool(fakeApi());
@@ -117,7 +117,7 @@ describe("lobster plugin tool", () => {
it("rejects invalid JSON from lobster", async () => {
const { binPath } = await writeFakeLobsterScript(
`process.stdout.write("nope");\n`,
"clawdbot-lobster-plugin-bad-",
"moltbot-lobster-plugin-bad-",
);
const tool = createLobsterTool(fakeApi());
@@ -132,7 +132,7 @@ describe("lobster plugin tool", () => {
it("can be gated off in sandboxed contexts", async () => {
const api = fakeApi();
const factoryTool = (ctx: ClawdbotPluginToolContext) => {
const factoryTool = (ctx: MoltbotPluginToolContext) => {
if (ctx.sandboxed) return null;
return createLobsterTool(api);
};
+2 -2
View File
@@ -2,7 +2,7 @@ import { Type } from "@sinclair/typebox";
import { spawn } from "node:child_process";
import path from "node:path";
import type { ClawdbotPluginApi } from "../../../src/plugins/types.js";
import type { MoltbotPluginApi } from "../../../src/plugins/types.js";
type LobsterEnvelope =
| {
@@ -168,7 +168,7 @@ function parseEnvelope(stdout: string): LobsterEnvelope {
throw new Error("lobster returned invalid JSON envelope");
}
export function createLobsterTool(api: ClawdbotPluginApi) {
export function createLobsterTool(api: MoltbotPluginApi) {
return {
name: "lobster",
description:
+9 -9
View File
@@ -3,47 +3,47 @@
## 2026.1.23
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.22
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.21
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.20
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.17-1
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.17
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.16
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.15
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.14
### Features
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
- Matrix channel plugin with homeserver + user ID auth (access token or password login with device name).
- Direct messages with pairing/allowlist/open/disabled policies and allowFrom support.
- Group/room controls: allowlist policy, per-room config, mention gating, auto-reply, per-room skills/system prompts.
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { matrixPlugin } from "./src/channel.js";
@@ -9,7 +9,7 @@ const plugin = {
name: "Matrix",
description: "Matrix channel plugin (matrix-js-sdk)",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setMatrixRuntime(api.runtime);
api.registerChannel({ plugin: matrixPlugin });
},
+3 -3
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/matrix",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot Matrix channel plugin",
"clawdbot": {
"description": "Moltbot Matrix channel plugin",
"moltbot": {
"extensions": [
"./index.ts"
],
@@ -31,6 +31,6 @@
"zod": "^4.3.6"
},
"devDependencies": {
"clawdbot": "workspace:*"
"moltbot": "workspace:*"
}
}
@@ -125,7 +125,7 @@ export async function resolveMatrixAuth(params?: {
type: "m.login.password",
identifier: { type: "m.id.user", user: resolved.userId },
password: resolved.password,
initial_device_display_name: resolved.deviceName ?? "Clawdbot Gateway",
initial_device_display_name: resolved.deviceName ?? "Moltbot Gateway",
}),
});
@@ -252,12 +252,12 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
await sendMessageMatrix(
`room:${roomId}`,
[
"Clawdbot: access not configured.",
"Moltbot: access not configured.",
"",
`Pairing code: ${code}`,
"",
"Ask the bot owner to approve with:",
"clawdbot pairing approve matrix <code>",
"moltbot pairing approve matrix <code>",
].join("\n"),
{ client },
);
+1 -1
View File
@@ -318,7 +318,7 @@ export const matrixOnboardingAdapter: ChannelOnboardingAdapter = {
const deviceName = String(
await prompter.text({
message: "Matrix device name (optional)",
initialValue: existing.deviceName ?? "Clawdbot Gateway",
initialValue: existing.deviceName ?? "Moltbot Gateway",
}),
).trim();
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { mattermostPlugin } from "./src/channel.js";
@@ -9,7 +9,7 @@ const plugin = {
name: "Mattermost",
description: "Mattermost channel plugin",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setMattermostRuntime(api.runtime);
api.registerChannel({ plugin: mattermostPlugin });
},
+2 -2
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/mattermost",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot Mattermost channel plugin",
"clawdbot": {
"description": "Moltbot Mattermost channel plugin",
"moltbot": {
"extensions": [
"./index.ts"
],
@@ -1,4 +1,4 @@
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "clawdbot/plugin-sdk";
import type { MattermostAccountConfig, MattermostChatMode } from "../types.js";
@@ -24,26 +24,26 @@ export type ResolvedMattermostAccount = {
blockStreamingCoalesce?: MattermostAccountConfig["blockStreamingCoalesce"];
};
function listConfiguredAccountIds(cfg: ClawdbotConfig): string[] {
function listConfiguredAccountIds(cfg: MoltbotConfig): string[] {
const accounts = cfg.channels?.mattermost?.accounts;
if (!accounts || typeof accounts !== "object") return [];
return Object.keys(accounts).filter(Boolean);
}
export function listMattermostAccountIds(cfg: ClawdbotConfig): string[] {
export function listMattermostAccountIds(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 resolveDefaultMattermostAccountId(cfg: ClawdbotConfig): string {
export function resolveDefaultMattermostAccountId(cfg: MoltbotConfig): string {
const ids = listMattermostAccountIds(cfg);
if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID;
return ids[0] ?? DEFAULT_ACCOUNT_ID;
}
function resolveAccountConfig(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
accountId: string,
): MattermostAccountConfig | undefined {
const accounts = cfg.channels?.mattermost?.accounts;
@@ -52,7 +52,7 @@ function resolveAccountConfig(
}
function mergeMattermostAccountConfig(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
accountId: string,
): MattermostAccountConfig {
const { accounts: _ignored, ...base } = (cfg.channels?.mattermost ??
@@ -69,7 +69,7 @@ function resolveMattermostRequireMention(config: MattermostAccountConfig): boole
}
export function resolveMattermostAccount(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
accountId?: string | null;
}): ResolvedMattermostAccount {
const accountId = normalizeAccountId(params.accountId);
@@ -108,7 +108,7 @@ export function resolveMattermostAccount(params: {
};
}
export function listEnabledMattermostAccounts(cfg: ClawdbotConfig): ResolvedMattermostAccount[] {
export function listEnabledMattermostAccounts(cfg: MoltbotConfig): ResolvedMattermostAccount[] {
return listMattermostAccountIds(cfg)
.map((accountId) => resolveMattermostAccount({ cfg, accountId }))
.filter((account) => account.enabled);
@@ -2,7 +2,7 @@ import { Buffer } from "node:buffer";
import type WebSocket from "ws";
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
export type ResponsePrefixContext = {
model?: string;
@@ -114,20 +114,20 @@ function normalizeAgentId(value: string | undefined | null): string {
);
}
type AgentEntry = NonNullable<NonNullable<ClawdbotConfig["agents"]>["list"]>[number];
type AgentEntry = NonNullable<NonNullable<MoltbotConfig["agents"]>["list"]>[number];
function listAgents(cfg: ClawdbotConfig): AgentEntry[] {
function listAgents(cfg: MoltbotConfig): AgentEntry[] {
const list = cfg.agents?.list;
if (!Array.isArray(list)) return [];
return list.filter((entry): entry is AgentEntry => Boolean(entry && typeof entry === "object"));
}
function resolveAgentEntry(cfg: ClawdbotConfig, agentId: string): AgentEntry | undefined {
function resolveAgentEntry(cfg: MoltbotConfig, agentId: string): AgentEntry | undefined {
const id = normalizeAgentId(agentId);
return listAgents(cfg).find((entry) => normalizeAgentId(entry.id) === id);
}
export function resolveIdentityName(cfg: ClawdbotConfig, agentId: string): string | undefined {
export function resolveIdentityName(cfg: MoltbotConfig, agentId: string): string | undefined {
const entry = resolveAgentEntry(cfg, agentId);
return entry?.identity?.name?.trim() || undefined;
}
@@ -2,7 +2,7 @@ import WebSocket from "ws";
import type {
ChannelAccountSnapshot,
ClawdbotConfig,
MoltbotConfig,
ReplyPayload,
RuntimeEnv,
} from "clawdbot/plugin-sdk";
@@ -45,7 +45,7 @@ export type MonitorMattermostOpts = {
botToken?: string;
baseUrl?: string;
accountId?: string;
config?: ClawdbotConfig;
config?: MoltbotConfig;
runtime?: RuntimeEnv;
abortSignal?: AbortSignal;
statusSink?: (patch: Partial<ChannelAccountSnapshot>) => void;
@@ -1,12 +1,12 @@
import type { ClawdbotConfig, WizardPrompter } from "clawdbot/plugin-sdk";
import type { MoltbotConfig, WizardPrompter } from "clawdbot/plugin-sdk";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "clawdbot/plugin-sdk";
type PromptAccountIdParams = {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
prompter: WizardPrompter;
label: string;
currentId?: string;
listAccountIds: (cfg: ClawdbotConfig) => string[];
listAccountIds: (cfg: MoltbotConfig) => string[];
defaultAccountId: string;
};
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ChannelOnboardingAdapter, ClawdbotConfig, WizardPrompter } from "clawdbot/plugin-sdk";
import type { ChannelOnboardingAdapter, MoltbotConfig, WizardPrompter } from "clawdbot/plugin-sdk";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "clawdbot/plugin-sdk";
import {
@@ -177,7 +177,7 @@ export const mattermostOnboardingAdapter: ChannelOnboardingAdapter = {
return { cfg: next, accountId };
},
disable: (cfg: ClawdbotConfig) => ({
disable: (cfg: MoltbotConfig) => ({
...cfg,
channels: {
...cfg.channels,
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
const memoryCorePlugin = {
@@ -7,7 +7,7 @@ const memoryCorePlugin = {
description: "File-backed memory search tools and CLI",
kind: "memory",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
api.registerTool(
(ctx) => {
const memorySearchTool = api.runtime.tools.createMemorySearchTool({
+3 -3
View File
@@ -2,13 +2,13 @@
"name": "@moltbot/memory-core",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot core memory search plugin",
"clawdbot": {
"description": "Moltbot core memory search plugin",
"moltbot": {
"extensions": [
"./index.ts"
]
},
"peerDependencies": {
"clawdbot": ">=2026.1.26"
"moltbot": ">=2026.1.26"
}
}
+2 -2
View File
@@ -24,7 +24,7 @@ describe("memory plugin e2e", () => {
let dbPath: string;
beforeEach(async () => {
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-memory-test-"));
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-memory-test-"));
dbPath = path.join(tmpDir, "lancedb");
});
@@ -165,7 +165,7 @@ describeLive("memory plugin live tests", () => {
let dbPath: string;
beforeEach(async () => {
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-memory-live-"));
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-memory-live-"));
dbPath = path.join(tmpDir, "lancedb");
});
+3 -3
View File
@@ -1,5 +1,5 @@
/**
* Clawdbot Memory (LanceDB) Plugin
* Moltbot Memory (LanceDB) Plugin
*
* Long-term memory with vector search for AI conversations.
* Uses LanceDB for storage and OpenAI for embeddings.
@@ -10,7 +10,7 @@ import { Type } from "@sinclair/typebox";
import * as lancedb from "@lancedb/lancedb";
import OpenAI from "openai";
import { randomUUID } from "node:crypto";
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { stringEnum } from "clawdbot/plugin-sdk";
import {
@@ -220,7 +220,7 @@ const memoryPlugin = {
kind: "memory" as const,
configSchema: memoryConfigSchema,
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
const cfg = memoryConfigSchema.parse(api.pluginConfig);
const resolvedDbPath = api.resolvePath(cfg.dbPath!);
const vectorDim = vectorDimsForModel(cfg.embedding.model ?? "text-embedding-3-small");
+2 -2
View File
@@ -2,13 +2,13 @@
"name": "@moltbot/memory-lancedb",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot LanceDB-backed long-term memory plugin with auto-recall/capture",
"description": "Moltbot LanceDB-backed long-term memory plugin with auto-recall/capture",
"dependencies": {
"@lancedb/lancedb": "^0.23.0",
"@sinclair/typebox": "0.34.47",
"openai": "^6.16.0"
},
"clawdbot": {
"moltbot": {
"extensions": [
"./index.ts"
]
+7 -7
View File
@@ -3,37 +3,37 @@
## 2026.1.23
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.22
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.21
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.20
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.17-1
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.17
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.16
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.15
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { msteamsPlugin } from "./src/channel.js";
@@ -9,7 +9,7 @@ const plugin = {
name: "Microsoft Teams",
description: "Microsoft Teams channel plugin (Bot Framework)",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setMSTeamsRuntime(api.runtime);
api.registerChannel({ plugin: msteamsPlugin });
},
+3 -3
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/msteams",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot Microsoft Teams channel plugin",
"clawdbot": {
"description": "Moltbot Microsoft Teams channel plugin",
"moltbot": {
"extensions": [
"./index.ts"
],
@@ -29,7 +29,7 @@
"@microsoft/agents-hosting": "^1.2.2",
"@microsoft/agents-hosting-express": "^1.2.2",
"@microsoft/agents-hosting-extensions-teams": "^1.2.2",
"clawdbot": "workspace:*",
"moltbot": "workspace:*",
"express": "^5.2.1",
"proper-lockfile": "^4.1.2"
}
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import { msteamsPlugin } from "./channel.js";
@@ -21,7 +21,7 @@ describe("msteams directory", () => {
},
},
},
} as unknown as ClawdbotConfig;
} as unknown as MoltbotConfig;
expect(msteamsPlugin.directory).toBeTruthy();
expect(msteamsPlugin.directory?.listPeers).toBeTruthy();
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ChannelMessageActionName, ChannelPlugin, ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { ChannelMessageActionName, ChannelPlugin, MoltbotConfig } from "clawdbot/plugin-sdk";
import {
buildChannelConfigSchema,
DEFAULT_ACCOUNT_ID,
@@ -102,7 +102,7 @@ export const msteamsPlugin: ChannelPlugin<ResolvedMSTeamsAccount> = {
},
}),
deleteAccount: ({ cfg }) => {
const next = { ...cfg } as ClawdbotConfig;
const next = { ...cfg } as MoltbotConfig;
const nextChannels = { ...cfg.channels };
delete nextChannels.msteams;
if (Object.keys(nextChannels).length > 0) {
@@ -26,7 +26,7 @@ describe("msteams conversation store (fs)", () => {
});
it("filters and prunes expired entries (but keeps legacy ones)", async () => {
const stateDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "clawdbot-msteams-store-"));
const stateDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "moltbot-msteams-store-"));
const env: NodeJS.ProcessEnv = {
...process.env,
+4 -4
View File
@@ -36,8 +36,8 @@ export async function uploadToOneDrive(params: {
const fetchFn = params.fetchFn ?? fetch;
const token = await params.tokenProvider.getAccessToken(GRAPH_SCOPE);
// Use "ClawdbotShared" folder to organize bot-uploaded files
const uploadPath = `/ClawdbotShared/${encodeURIComponent(params.filename)}`;
// Use "MoltbotShared" folder to organize bot-uploaded files
const uploadPath = `/MoltbotShared/${encodeURIComponent(params.filename)}`;
const res = await fetchFn(`${GRAPH_ROOT}/me/drive/root:${uploadPath}:/content`, {
method: "PUT",
@@ -179,8 +179,8 @@ export async function uploadToSharePoint(params: {
const fetchFn = params.fetchFn ?? fetch;
const token = await params.tokenProvider.getAccessToken(GRAPH_SCOPE);
// Use "ClawdbotShared" folder to organize bot-uploaded files
const uploadPath = `/ClawdbotShared/${encodeURIComponent(params.filename)}`;
// Use "MoltbotShared" folder to organize bot-uploaded files
const uploadPath = `/MoltbotShared/${encodeURIComponent(params.filename)}`;
const res = await fetchFn(`${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content`, {
method: "PUT",
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotConfig, RuntimeEnv } from "clawdbot/plugin-sdk";
import type { MoltbotConfig, RuntimeEnv } from "clawdbot/plugin-sdk";
import type { MSTeamsConversationStore } from "./conversation-store.js";
import {
buildFileInfoCard,
@@ -27,7 +27,7 @@ export type MSTeamsActivityHandler = {
};
export type MSTeamsMessageHandlerDeps = {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
runtime: RuntimeEnv;
appId: string;
adapter: MSTeamsAdapter;
+2 -2
View File
@@ -2,7 +2,7 @@ import type { Request, Response } from "express";
import {
mergeAllowlist,
summarizeMapping,
type ClawdbotConfig,
type MoltbotConfig,
type RuntimeEnv,
} from "clawdbot/plugin-sdk";
import type { MSTeamsConversationStore } from "./conversation-store.js";
@@ -20,7 +20,7 @@ import { resolveMSTeamsCredentials } from "./token.js";
import { getMSTeamsRuntime } from "./runtime.js";
export type MonitorMSTeamsOpts = {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
runtime?: RuntimeEnv;
abortSignal?: AbortSignal;
conversationStore?: MSTeamsConversationStore;
+9 -9
View File
@@ -1,7 +1,7 @@
import type {
ChannelOnboardingAdapter,
ChannelOnboardingDmPolicy,
ClawdbotConfig,
MoltbotConfig,
DmPolicy,
WizardPrompter,
} from "clawdbot/plugin-sdk";
@@ -21,7 +21,7 @@ import {
const channel = "msteams" as const;
function setMSTeamsDmPolicy(cfg: ClawdbotConfig, dmPolicy: DmPolicy) {
function setMSTeamsDmPolicy(cfg: MoltbotConfig, dmPolicy: DmPolicy) {
const allowFrom =
dmPolicy === "open"
? addWildcardAllowFrom(cfg.channels?.msteams?.allowFrom)?.map((entry) => String(entry))
@@ -39,7 +39,7 @@ function setMSTeamsDmPolicy(cfg: ClawdbotConfig, dmPolicy: DmPolicy) {
};
}
function setMSTeamsAllowFrom(cfg: ClawdbotConfig, allowFrom: string[]): ClawdbotConfig {
function setMSTeamsAllowFrom(cfg: MoltbotConfig, allowFrom: string[]): MoltbotConfig {
return {
...cfg,
channels: {
@@ -64,9 +64,9 @@ function looksLikeGuid(value: string): boolean {
}
async function promptMSTeamsAllowFrom(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
prompter: WizardPrompter;
}): Promise<ClawdbotConfig> {
}): Promise<MoltbotConfig> {
const existing = params.cfg.channels?.msteams?.allowFrom ?? [];
await params.prompter.note(
[
@@ -144,9 +144,9 @@ async function noteMSTeamsCredentialHelp(prompter: WizardPrompter): Promise<void
}
function setMSTeamsGroupPolicy(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
groupPolicy: "open" | "allowlist" | "disabled",
): ClawdbotConfig {
): MoltbotConfig {
return {
...cfg,
channels: {
@@ -161,9 +161,9 @@ function setMSTeamsGroupPolicy(
}
function setMSTeamsTeamsAllowlist(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
entries: Array<{ teamKey: string; channelKey?: string }>,
): ClawdbotConfig {
): MoltbotConfig {
const baseTeams = cfg.channels?.msteams?.teams ?? {};
const teams: Record<string, { channels?: Record<string, unknown> }> = { ...baseTeams };
for (const entry of entries) {
+1 -1
View File
@@ -8,7 +8,7 @@ import { createMSTeamsPollStoreFs } from "./polls.js";
import { createMSTeamsPollStoreMemory } from "./polls-store-memory.js";
const createFsStore = async () => {
const stateDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "clawdbot-msteams-polls-"));
const stateDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "moltbot-msteams-polls-"));
return createMSTeamsPollStoreFs({ stateDir });
};
+2 -2
View File
@@ -39,7 +39,7 @@ describe("msteams polls", () => {
it("extracts poll votes from activity values", () => {
const vote = extractMSTeamsPollVote({
value: {
clawdbotPollId: "poll-1",
moltbotPollId: "poll-1",
choices: "0,1",
},
});
@@ -51,7 +51,7 @@ describe("msteams polls", () => {
});
it("stores and records poll votes", async () => {
const home = await fs.promises.mkdtemp(path.join(os.tmpdir(), "clawdbot-msteams-polls-"));
const home = await fs.promises.mkdtemp(path.join(os.tmpdir(), "moltbot-msteams-polls-"));
const store = createMSTeamsPollStoreFs({ homedir: () => home });
await store.createPoll({
id: "poll-2",
+8 -8
View File
@@ -97,13 +97,13 @@ export function extractMSTeamsPollVote(
const value = activity?.value;
if (!value || !isRecord(value)) return null;
const pollId =
readNestedString(value, ["clawdbotPollId"]) ??
readNestedString(value, ["moltbotPollId"]) ??
readNestedString(value, ["pollId"]) ??
readNestedString(value, ["clawdbot", "pollId"]) ??
readNestedString(value, ["clawdbot", "poll", "id"]) ??
readNestedString(value, ["data", "clawdbotPollId"]) ??
readNestedString(value, ["moltbot", "pollId"]) ??
readNestedString(value, ["moltbot", "poll", "id"]) ??
readNestedString(value, ["data", "moltbotPollId"]) ??
readNestedString(value, ["data", "pollId"]) ??
readNestedString(value, ["data", "clawdbot", "pollId"]);
readNestedString(value, ["data", "moltbot", "pollId"]);
if (!pollId) return null;
const directSelections = extractSelections(value.choices);
@@ -176,13 +176,13 @@ export function buildMSTeamsPollCard(params: {
type: "Action.Submit",
title: "Vote",
data: {
clawdbotPollId: pollId,
moltbotPollId: pollId,
},
msteams: {
type: "messageBack",
text: "clawdbot poll vote",
text: "moltbot poll vote",
displayText: "Vote recorded",
value: { clawdbotPollId: pollId },
value: { moltbotPollId: pollId },
},
},
],
+2 -2
View File
@@ -3,7 +3,7 @@ import {
createTypingCallbacks,
logTypingFailure,
resolveChannelMediaMaxBytes,
type ClawdbotConfig,
type MoltbotConfig,
type MSTeamsReplyStyle,
type RuntimeEnv,
} from "clawdbot/plugin-sdk";
@@ -24,7 +24,7 @@ import type { MSTeamsTurnContext } from "./sdk-types.js";
import { getMSTeamsRuntime } from "./runtime.js";
export function createMSTeamsReplyDispatcher(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
agentId: string;
runtime: RuntimeEnv;
log: MSTeamsMonitorLogger;
+2 -2
View File
@@ -1,4 +1,4 @@
import { resolveChannelMediaMaxBytes, type ClawdbotConfig, type PluginRuntime } from "clawdbot/plugin-sdk";
import { resolveChannelMediaMaxBytes, type MoltbotConfig, type PluginRuntime } from "clawdbot/plugin-sdk";
import type { MSTeamsAccessTokenProvider } from "./attachments/types.js";
import type {
MSTeamsConversationStore,
@@ -84,7 +84,7 @@ async function findConversationReference(recipient: {
}
export async function resolveMSTeamsSendContext(params: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
to: string;
}): Promise<MSTeamsProactiveContext> {
const msteamsCfg = params.cfg.channels?.msteams;
+4 -4
View File
@@ -1,5 +1,5 @@
import { loadWebMedia, resolveChannelMediaMaxBytes } from "clawdbot/plugin-sdk";
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import { createMSTeamsConversationStoreFs } from "./conversation-store-fs.js";
import {
classifyMSTeamsSendError,
@@ -21,7 +21,7 @@ import { resolveMSTeamsSendContext, type MSTeamsProactiveContext } from "./send-
export type SendMSTeamsMessageParams = {
/** Full config (for credentials) */
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
/** Conversation ID or user ID to send to */
to: string;
/** Message text */
@@ -48,7 +48,7 @@ const MSTEAMS_MAX_MEDIA_BYTES = 100 * 1024 * 1024;
export type SendMSTeamsPollParams = {
/** Full config (for credentials) */
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
/** Conversation ID or user ID to send to */
to: string;
/** Poll question */
@@ -67,7 +67,7 @@ export type SendMSTeamsPollResult = {
export type SendMSTeamsCardParams = {
/** Full config (for credentials) */
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
/** Conversation ID or user ID to send to */
to: string;
/** Adaptive Card JSON object */
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { nextcloudTalkPlugin } from "./src/channel.js";
@@ -9,7 +9,7 @@ const plugin = {
name: "Nextcloud Talk",
description: "Nextcloud Talk channel plugin",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setNextcloudTalkRuntime(api.runtime);
api.registerChannel({ plugin: nextcloudTalkPlugin });
},
+2 -2
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/nextcloud-talk",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot Nextcloud Talk channel plugin",
"clawdbot": {
"description": "Moltbot Nextcloud Talk channel plugin",
"moltbot": {
"extensions": [
"./index.ts"
],
+7 -7
View File
@@ -7,7 +7,7 @@ import {
normalizeAccountId,
setAccountEnabledInConfigSection,
type ChannelPlugin,
type ClawdbotConfig,
type MoltbotConfig,
type ChannelSetupInput,
} from "clawdbot/plugin-sdk";
@@ -173,7 +173,7 @@ export const nextcloudTalkPlugin: ChannelPlugin<ResolvedNextcloudTalkAccount> =
resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
applyAccountName: ({ cfg, accountId, name }) =>
applyAccountNameToChannelSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
channelKey: "nextcloud-talk",
accountId,
name,
@@ -194,7 +194,7 @@ export const nextcloudTalkPlugin: ChannelPlugin<ResolvedNextcloudTalkAccount> =
applyAccountConfig: ({ cfg, accountId, input }) => {
const setupInput = input as NextcloudSetupInput;
const namedConfig = applyAccountNameToChannelSection({
cfg: cfg as ClawdbotConfig,
cfg: cfg as MoltbotConfig,
channelKey: "nextcloud-talk",
accountId,
name: setupInput.name,
@@ -217,7 +217,7 @@ export const nextcloudTalkPlugin: ChannelPlugin<ResolvedNextcloudTalkAccount> =
: {}),
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
}
return {
...namedConfig,
@@ -241,7 +241,7 @@ export const nextcloudTalkPlugin: ChannelPlugin<ResolvedNextcloudTalkAccount> =
},
},
},
} as ClawdbotConfig;
} as MoltbotConfig;
},
},
outbound: {
@@ -323,7 +323,7 @@ export const nextcloudTalkPlugin: ChannelPlugin<ResolvedNextcloudTalkAccount> =
return { stop };
},
logoutAccount: async ({ accountId, cfg }) => {
const nextCfg = { ...cfg } as ClawdbotConfig;
const nextCfg = { ...cfg } as MoltbotConfig;
const nextSection = cfg.channels?.["nextcloud-talk"]
? { ...cfg.channels["nextcloud-talk"] }
: undefined;
@@ -377,7 +377,7 @@ export const nextcloudTalkPlugin: ChannelPlugin<ResolvedNextcloudTalkAccount> =
const nextChannels = { ...nextCfg.channels } as Record<string, unknown>;
delete nextChannels["nextcloud-talk"];
if (Object.keys(nextChannels).length > 0) {
nextCfg.channels = nextChannels as ClawdbotConfig["channels"];
nextCfg.channels = nextChannels as MoltbotConfig["channels"];
} else {
delete nextCfg.channels;
}
+7 -7
View File
@@ -1,7 +1,7 @@
import {
logInboundDrop,
resolveControlCommandGate,
type ClawdbotConfig,
type MoltbotConfig,
type RuntimeEnv,
} from "clawdbot/plugin-sdk";
@@ -114,7 +114,7 @@ export async function handleNextcloudTalkInbound(params: {
const effectiveGroupAllowFrom = [...baseGroupAllowFrom, ...storeAllowList].filter(Boolean);
const allowTextCommands = core.channel.commands.shouldHandleTextCommands({
cfg: config as ClawdbotConfig,
cfg: config as MoltbotConfig,
surface: CHANNEL_ID,
});
const useAccessGroups = config.commands?.useAccessGroups !== false;
@@ -125,7 +125,7 @@ export async function handleNextcloudTalkInbound(params: {
}).allowed;
const hasControlCommand = core.channel.text.hasControlCommand(
rawBody,
config as ClawdbotConfig,
config as MoltbotConfig,
);
const commandGate = resolveControlCommandGate({
useAccessGroups,
@@ -211,7 +211,7 @@ export async function handleNextcloudTalkInbound(params: {
}
const mentionRegexes = core.channel.mentions.buildMentionRegexes(
config as ClawdbotConfig,
config as MoltbotConfig,
);
const wasMentioned = mentionRegexes.length
? core.channel.mentions.matchesMentionPatterns(rawBody, mentionRegexes)
@@ -236,7 +236,7 @@ export async function handleNextcloudTalkInbound(params: {
}
const route = core.channel.routing.resolveAgentRoute({
cfg: config as ClawdbotConfig,
cfg: config as MoltbotConfig,
channel: CHANNEL_ID,
accountId: account.accountId,
peer: {
@@ -252,7 +252,7 @@ export async function handleNextcloudTalkInbound(params: {
agentId: route.agentId,
});
const envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(
config as ClawdbotConfig,
config as MoltbotConfig,
);
const previousTimestamp = core.channel.session.readSessionUpdatedAt({
storePath,
@@ -304,7 +304,7 @@ export async function handleNextcloudTalkInbound(params: {
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
ctx: ctxPayload,
cfg: config as ClawdbotConfig,
cfg: config as MoltbotConfig,
dispatcherOptions: {
deliver: async (payload) => {
await deliverNextcloudTalkReply({
+1 -1
View File
@@ -43,7 +43,7 @@ async function noteNextcloudTalkSecretHelp(prompter: WizardPrompter): Promise<vo
await prompter.note(
[
"1) SSH into your Nextcloud server",
'2) Run: ./occ talk:bot:install "Clawdbot" "<shared-secret>" "<webhook-url>" --feature reaction',
'2) Run: ./occ talk:bot:install "Moltbot" "<shared-secret>" "<webhook-url>" --feature reaction',
"3) Copy the shared secret you used in the command",
"4) Enable the bot in your Nextcloud Talk room settings",
"Tip: you can also set NEXTCLOUD_TALK_BOT_SECRET in your env.",
+4 -4
View File
@@ -3,22 +3,22 @@
## 2026.1.23
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.22
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.21
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.20
### Changes
- Version alignment with core Clawdbot release numbers.
- Version alignment with core Moltbot release numbers.
## 2026.1.19-1
+5 -5
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi, ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi, MoltbotConfig } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { nostrPlugin } from "./src/channel.js";
@@ -12,7 +12,7 @@ const plugin = {
name: "Nostr",
description: "Nostr DM channel plugin via NIP-04",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setNostrRuntime(api.runtime);
api.registerChannel({ plugin: nostrPlugin });
@@ -20,13 +20,13 @@ const plugin = {
const httpHandler = createNostrProfileHttpHandler({
getConfigProfile: (accountId: string) => {
const runtime = getNostrRuntime();
const cfg = runtime.config.loadConfig() as ClawdbotConfig;
const cfg = runtime.config.loadConfig() as MoltbotConfig;
const account = resolveNostrAccount({ cfg, accountId });
return account.profile;
},
updateConfigProfile: async (accountId: string, profile: NostrProfile) => {
const runtime = getNostrRuntime();
const cfg = runtime.config.loadConfig() as ClawdbotConfig;
const cfg = runtime.config.loadConfig() as MoltbotConfig;
// Build the config patch for channels.nostr.profile
const channels = (cfg.channels ?? {}) as Record<string, unknown>;
@@ -49,7 +49,7 @@ const plugin = {
},
getAccountInfo: (accountId: string) => {
const runtime = getNostrRuntime();
const cfg = runtime.config.loadConfig() as ClawdbotConfig;
const cfg = runtime.config.loadConfig() as MoltbotConfig;
const account = resolveNostrAccount({ cfg, accountId });
if (!account.configured || !account.publicKey) {
return null;
+3 -3
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/nostr",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot Nostr channel plugin for NIP-04 encrypted DMs",
"clawdbot": {
"description": "Moltbot Nostr channel plugin for NIP-04 encrypted DMs",
"moltbot": {
"extensions": [
"./index.ts"
],
@@ -24,7 +24,7 @@
}
},
"dependencies": {
"clawdbot": "workspace:*",
"moltbot": "workspace:*",
"nostr-tools": "^2.20.0",
"zod": "^4.3.6"
}
+1 -1
View File
@@ -221,7 +221,7 @@ export const nostrPlugin: ChannelPlugin<ResolvedNostrAccount> = {
onMessage: async (senderPubkey, text, reply) => {
ctx.log?.debug(`[${account.accountId}] DM from ${senderPubkey}: ${text.slice(0, 50)}...`);
// Forward to clawdbot's message pipeline
// Forward to moltbot's message pipeline
await runtime.channel.reply.handleInboundMessage({
channel: "nostr",
accountId: account.accountId,
@@ -14,7 +14,7 @@ import { setNostrRuntime } from "./runtime.js";
async function withTempStateDir<T>(fn: (dir: string) => Promise<T>) {
const previous = process.env.CLAWDBOT_STATE_DIR;
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-nostr-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-nostr-"));
process.env.CLAWDBOT_STATE_DIR = dir;
setNostrRuntime({
state: {
+4 -4
View File
@@ -1,4 +1,4 @@
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
import type { MoltbotConfig } from "clawdbot/plugin-sdk";
import { getPublicKeyFromPrivate } from "./nostr-bus.js";
import { DEFAULT_RELAYS } from "./nostr-bus.js";
import type { NostrProfile } from "./config-schema.js";
@@ -30,7 +30,7 @@ const DEFAULT_ACCOUNT_ID = "default";
/**
* List all configured Nostr account IDs
*/
export function listNostrAccountIds(cfg: ClawdbotConfig): string[] {
export function listNostrAccountIds(cfg: MoltbotConfig): string[] {
const nostrCfg = (cfg.channels as Record<string, unknown> | undefined)?.nostr as
| NostrAccountConfig
| undefined;
@@ -46,7 +46,7 @@ export function listNostrAccountIds(cfg: ClawdbotConfig): string[] {
/**
* Get the default account ID
*/
export function resolveDefaultNostrAccountId(cfg: ClawdbotConfig): string {
export function resolveDefaultNostrAccountId(cfg: MoltbotConfig): string {
const ids = listNostrAccountIds(cfg);
if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID;
return ids[0] ?? DEFAULT_ACCOUNT_ID;
@@ -56,7 +56,7 @@ export function resolveDefaultNostrAccountId(cfg: ClawdbotConfig): string {
* Resolve a Nostr account from config
*/
export function resolveNostrAccount(opts: {
cfg: ClawdbotConfig;
cfg: MoltbotConfig;
accountId?: string | null;
}): ResolvedNostrAccount {
const accountId = opts.accountId ?? DEFAULT_ACCOUNT_ID;
+2 -2
View File
@@ -1,5 +1,5 @@
import type { ClawdbotPluginApi } from "../../src/plugins/types.js";
import type { MoltbotPluginApi } from "../../src/plugins/types.js";
export default function register(_api: ClawdbotPluginApi) {
export default function register(_api: MoltbotPluginApi) {
// OpenProse is delivered via plugin-shipped skills.
}
+1 -1
View File
@@ -3,7 +3,7 @@
"version": "2026.1.26",
"type": "module",
"description": "OpenProse VM skill pack plugin (slash command + telemetry).",
"clawdbot": {
"moltbot": {
"extensions": [
"./index.ts"
]
+5 -5
View File
@@ -1,18 +1,18 @@
---
name: prose
description: OpenProse VM skill pack. Activate on any `prose` command, .prose files, or OpenProse mentions; orchestrates multi-agent workflows.
metadata: {"clawdbot":{"emoji":"🪶","homepage":"https://www.prose.md"}}
metadata: {"moltbot":{"emoji":"🪶","homepage":"https://www.prose.md"}}
---
# OpenProse Skill
OpenProse is a programming language for AI sessions. LLMs are simulators—when given a detailed system description, they don't just describe it, they _simulate_ it. The `prose.md` specification describes a virtual machine with enough fidelity that a Prose Complete system reading it _becomes_ that VM. Simulation with sufficient fidelity is implementation. **You are the Prose Complete system.**
## Clawdbot Runtime Mapping
## Moltbot Runtime Mapping
- **Task tool** in the upstream spec == Clawdbot `sessions_spawn`
- **File I/O** == Clawdbot `read`/`write`
- **Remote fetch** == Clawdbot `web_fetch` (or `exec` with curl when POST is required)
- **Task tool** in the upstream spec == Moltbot `sessions_spawn`
- **File I/O** == Moltbot `read`/`write`
- **Remote fetch** == Moltbot `web_fetch` (or `exec` with curl when POST is required)
## When to Activate
+4 -4
View File
@@ -18,11 +18,11 @@ see-also:
This document defines how to execute OpenProse programs. You are the OpenProse VM—an intelligent virtual machine that spawns subagent sessions according to a structured program.
## Clawdbot Runtime Mapping
## Moltbot Runtime Mapping
- **Task tool** in the upstream spec == Clawdbot `sessions_spawn`
- **File I/O** == Clawdbot `read`/`write`
- **Remote fetch** == Clawdbot `web_fetch` (or `exec` with curl when POST is required)
- **Task tool** in the upstream spec == Moltbot `sessions_spawn`
- **File I/O** == Moltbot `read`/`write`
- **Remote fetch** == Moltbot `web_fetch` (or `exec` with curl when POST is required)
## CLI Commands
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { signalPlugin } from "./src/channel.js";
@@ -9,7 +9,7 @@ const plugin = {
name: "Signal",
description: "Signal channel plugin",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setSignalRuntime(api.runtime);
api.registerChannel({ plugin: signalPlugin });
},
+2 -2
View File
@@ -2,8 +2,8 @@
"name": "@moltbot/signal",
"version": "2026.1.26",
"type": "module",
"description": "Clawdbot Signal channel plugin",
"clawdbot": {
"description": "Moltbot Signal channel plugin",
"moltbot": {
"extensions": [
"./index.ts"
]
+2 -2
View File
@@ -1,4 +1,4 @@
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import type { MoltbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
import { slackPlugin } from "./src/channel.js";
@@ -9,7 +9,7 @@ const plugin = {
name: "Slack",
description: "Slack channel plugin",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
register(api: MoltbotPluginApi) {
setSlackRuntime(api.runtime);
api.registerChannel({ plugin: slackPlugin });
},

Some files were not shown because too many files have changed in this diff Show More