refactor: rename clawdbot to moltbot with legacy compat

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

View File

@@ -7,7 +7,7 @@ const mocks = vi.hoisted(() => ({
}));
vi.mock("./loader.js", () => ({
loadClawdbotPlugins: () => ({
loadMoltbotPlugins: () => ({
cliRegistrars: [
{
pluginId: "memory-core",

View File

@@ -1,15 +1,15 @@
import type { Command } from "commander";
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import { loadConfig } from "../config/config.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { loadClawdbotPlugins } from "./loader.js";
import { loadMoltbotPlugins } from "./loader.js";
import type { PluginLogger } from "./types.js";
const log = createSubsystemLogger("plugins");
export function registerPluginCliCommands(program: Command, cfg?: ClawdbotConfig) {
export function registerPluginCliCommands(program: Command, cfg?: MoltbotConfig) {
const config = cfg ?? loadConfig();
const workspaceDir = resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config));
const logger: PluginLogger = {
@@ -18,7 +18,7 @@ export function registerPluginCliCommands(program: Command, cfg?: ClawdbotConfig
error: (msg: string) => log.error(msg),
debug: (msg: string) => log.debug(msg),
};
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
config,
workspaceDir,
logger,

View File

@@ -5,15 +5,15 @@
* These commands are processed before built-in commands and before agent invocation.
*/
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type {
ClawdbotPluginCommandDefinition,
MoltbotPluginCommandDefinition,
PluginCommandContext,
PluginCommandResult,
} from "./types.js";
import { logVerbose } from "../globals.js";
type RegisteredPluginCommand = ClawdbotPluginCommandDefinition & {
type RegisteredPluginCommand = MoltbotPluginCommandDefinition & {
pluginId: string;
};
@@ -104,7 +104,7 @@ export type CommandRegistrationResult = {
*/
export function registerPluginCommand(
pluginId: string,
command: ClawdbotPluginCommandDefinition,
command: MoltbotPluginCommandDefinition,
): CommandRegistrationResult {
// Prevent registration while commands are being processed
if (registryLocked) {
@@ -221,7 +221,7 @@ export async function executePluginCommand(params: {
channel: string;
isAuthorizedSender: boolean;
commandBody: string;
config: ClawdbotConfig;
config: MoltbotConfig;
}): Promise<PluginCommandResult> {
const { command, args, senderId, channel, isAuthorizedSender, commandBody, config } = params;

View File

@@ -1,4 +1,4 @@
import type { ClawdbotPluginConfigSchema } from "./types.js";
import type { MoltbotPluginConfigSchema } from "./types.js";
type Issue = { path: Array<string | number>; message: string };
@@ -10,7 +10,7 @@ function error(message: string): SafeParseResult {
return { success: false, error: { issues: [{ path: [], message }] } };
}
export function emptyPluginConfigSchema(): ClawdbotPluginConfigSchema {
export function emptyPluginConfigSchema(): MoltbotPluginConfigSchema {
return {
safeParse(value: unknown): SafeParseResult {
if (value === undefined) return { success: true, data: undefined };

View File

@@ -1,4 +1,4 @@
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import { defaultSlotIdForKey } from "./slots.js";
import type { PluginRecord } from "./registry.js";
@@ -49,7 +49,7 @@ const normalizePluginEntries = (entries: unknown): NormalizedPluginsConfig["entr
};
export const normalizePluginsConfig = (
config?: ClawdbotConfig["plugins"],
config?: MoltbotConfig["plugins"],
): NormalizedPluginsConfig => {
const memorySlot = normalizeSlotValue(config?.slots?.memory);
return {

View File

@@ -7,7 +7,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
const tempDirs: string[] = [];
function makeTempDir() {
const dir = path.join(os.tmpdir(), `clawdbot-plugins-${randomUUID()}`);
const dir = path.join(os.tmpdir(), `moltbot-plugins-${randomUUID()}`);
fs.mkdirSync(dir, { recursive: true });
tempDirs.push(dir);
return dir;
@@ -46,7 +46,7 @@ afterEach(() => {
}
});
describe("discoverClawdbotPlugins", () => {
describe("discoverMoltbotPlugins", () => {
it("discovers global and workspace extensions", async () => {
const stateDir = makeTempDir();
const workspaceDir = path.join(stateDir, "workspace");
@@ -60,8 +60,8 @@ describe("discoverClawdbotPlugins", () => {
fs.writeFileSync(path.join(workspaceExt, "beta.ts"), "export default function () {}", "utf-8");
const { candidates } = await withStateDir(stateDir, async () => {
const { discoverClawdbotPlugins } = await import("./discovery.js");
return discoverClawdbotPlugins({ workspaceDir });
const { discoverMoltbotPlugins } = await import("./discovery.js");
return discoverMoltbotPlugins({ workspaceDir });
});
const ids = candidates.map((c) => c.idHint);
@@ -78,7 +78,7 @@ describe("discoverClawdbotPlugins", () => {
path.join(globalExt, "package.json"),
JSON.stringify({
name: "pack",
clawdbot: { extensions: ["./src/one.ts", "./src/two.ts"] },
moltbot: { extensions: ["./src/one.ts", "./src/two.ts"] },
}),
"utf-8",
);
@@ -94,8 +94,8 @@ describe("discoverClawdbotPlugins", () => {
);
const { candidates } = await withStateDir(stateDir, async () => {
const { discoverClawdbotPlugins } = await import("./discovery.js");
return discoverClawdbotPlugins({});
const { discoverMoltbotPlugins } = await import("./discovery.js");
return discoverMoltbotPlugins({});
});
const ids = candidates.map((c) => c.idHint);
@@ -111,8 +111,8 @@ describe("discoverClawdbotPlugins", () => {
fs.writeFileSync(
path.join(globalExt, "package.json"),
JSON.stringify({
name: "@clawdbot/voice-call",
clawdbot: { extensions: ["./src/index.ts"] },
name: "@moltbot/voice-call",
moltbot: { extensions: ["./src/index.ts"] },
}),
"utf-8",
);
@@ -123,8 +123,8 @@ describe("discoverClawdbotPlugins", () => {
);
const { candidates } = await withStateDir(stateDir, async () => {
const { discoverClawdbotPlugins } = await import("./discovery.js");
return discoverClawdbotPlugins({});
const { discoverMoltbotPlugins } = await import("./discovery.js");
return discoverMoltbotPlugins({});
});
const ids = candidates.map((c) => c.idHint);
@@ -139,16 +139,16 @@ describe("discoverClawdbotPlugins", () => {
fs.writeFileSync(
path.join(packDir, "package.json"),
JSON.stringify({
name: "@clawdbot/demo-plugin-dir",
clawdbot: { extensions: ["./index.js"] },
name: "@moltbot/demo-plugin-dir",
moltbot: { extensions: ["./index.js"] },
}),
"utf-8",
);
fs.writeFileSync(path.join(packDir, "index.js"), "module.exports = {}", "utf-8");
const { candidates } = await withStateDir(stateDir, async () => {
const { discoverClawdbotPlugins } = await import("./discovery.js");
return discoverClawdbotPlugins({ extraPaths: [packDir] });
const { discoverMoltbotPlugins } = await import("./discovery.js");
return discoverMoltbotPlugins({ extraPaths: [packDir] });
});
const ids = candidates.map((c) => c.idHint);

View File

@@ -3,7 +3,11 @@ import path from "node:path";
import { resolveConfigDir, resolveUserPath } from "../utils.js";
import { resolveBundledPluginsDir } from "./bundled-dir.js";
import type { ClawdbotPackageManifest, PackageManifest } from "./manifest.js";
import {
getPackageManifestMetadata,
type MoltbotPackageManifest,
type PackageManifest,
} from "./manifest.js";
import type { PluginDiagnostic, PluginOrigin } from "./types.js";
const EXTENSION_EXTS = new Set([".ts", ".js", ".mts", ".cts", ".mjs", ".cjs"]);
@@ -18,7 +22,7 @@ export type PluginCandidate = {
packageVersion?: string;
packageDescription?: string;
packageDir?: string;
packageClawdbot?: ClawdbotPackageManifest;
packageMoltbot?: MoltbotPackageManifest;
};
export type PluginDiscoveryResult = {
@@ -44,7 +48,7 @@ function readPackageManifest(dir: string): PackageManifest | null {
}
function resolvePackageExtensions(manifest: PackageManifest): string[] {
const raw = manifest.clawdbot?.extensions;
const raw = getPackageManifestMetadata(manifest)?.extensions;
if (!Array.isArray(raw)) return [];
return raw.map((entry) => (typeof entry === "string" ? entry.trim() : "")).filter(Boolean);
}
@@ -59,7 +63,7 @@ function deriveIdHint(params: {
if (!rawPackageName) return base;
// Prefer the unscoped name so config keys stay stable even when the npm
// package is scoped (example: @clawdbot/voice-call -> voice-call).
// package is scoped (example: @moltbot/voice-call -> voice-call).
const unscoped = rawPackageName.includes("/")
? (rawPackageName.split("/").pop() ?? rawPackageName)
: rawPackageName;
@@ -93,7 +97,7 @@ function addCandidate(params: {
packageVersion: manifest?.version?.trim() || undefined,
packageDescription: manifest?.description?.trim() || undefined,
packageDir: params.packageDir,
packageClawdbot: manifest?.clawdbot,
packageMoltbot: getPackageManifestMetadata(manifest ?? undefined),
});
}
@@ -277,7 +281,7 @@ function discoverFromPath(params: {
}
}
export function discoverClawdbotPlugins(params: {
export function discoverMoltbotPlugins(params: {
workspaceDir?: string;
extraPaths?: string[];
}): PluginDiscoveryResult {

View File

@@ -1,12 +1,12 @@
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
export type PluginEnableResult = {
config: ClawdbotConfig;
config: MoltbotConfig;
enabled: boolean;
reason?: string;
};
function ensureAllowlisted(cfg: ClawdbotConfig, pluginId: string): ClawdbotConfig {
function ensureAllowlisted(cfg: MoltbotConfig, pluginId: string): MoltbotConfig {
const allow = cfg.plugins?.allow;
if (!Array.isArray(allow) || allow.includes(pluginId)) return cfg;
return {
@@ -18,7 +18,7 @@ function ensureAllowlisted(cfg: ClawdbotConfig, pluginId: string): ClawdbotConfi
};
}
export function enablePluginInConfig(cfg: ClawdbotConfig, pluginId: string): PluginEnableResult {
export function enablePluginInConfig(cfg: MoltbotConfig, pluginId: string): PluginEnableResult {
if (cfg.plugins?.enabled === false) {
return { config: cfg, enabled: false, reason: "plugins disabled" };
}
@@ -33,7 +33,7 @@ export function enablePluginInConfig(cfg: ClawdbotConfig, pluginId: string): Plu
enabled: true,
},
};
let next: ClawdbotConfig = {
let next: MoltbotConfig = {
...cfg,
plugins: {
...cfg.plugins,

View File

@@ -9,7 +9,7 @@ import { afterEach, describe, expect, it } from "vitest";
const tempDirs: string[] = [];
function makeTempDir() {
const dir = path.join(os.tmpdir(), `clawdbot-plugin-install-${randomUUID()}`);
const dir = path.join(os.tmpdir(), `moltbot-plugin-install-${randomUUID()}`);
fs.mkdirSync(dir, { recursive: true });
tempDirs.push(dir);
return dir;
@@ -96,9 +96,9 @@ describe("installPluginFromArchive", () => {
fs.writeFileSync(
path.join(pkgDir, "package.json"),
JSON.stringify({
name: "@clawdbot/voice-call",
name: "@moltbot/voice-call",
version: "0.0.1",
clawdbot: { extensions: ["./dist/index.js"] },
moltbot: { extensions: ["./dist/index.js"] },
}),
"utf-8",
);
@@ -129,9 +129,9 @@ describe("installPluginFromArchive", () => {
fs.writeFileSync(
path.join(pkgDir, "package.json"),
JSON.stringify({
name: "@clawdbot/voice-call",
name: "@moltbot/voice-call",
version: "0.0.1",
clawdbot: { extensions: ["./dist/index.js"] },
moltbot: { extensions: ["./dist/index.js"] },
}),
"utf-8",
);
@@ -163,9 +163,9 @@ describe("installPluginFromArchive", () => {
zip.file(
"package/package.json",
JSON.stringify({
name: "@clawdbot/zipper",
name: "@moltbot/zipper",
version: "0.0.1",
clawdbot: { extensions: ["./dist/index.js"] },
moltbot: { extensions: ["./dist/index.js"] },
}),
);
zip.file("package/dist/index.js", "export {};");
@@ -192,9 +192,9 @@ describe("installPluginFromArchive", () => {
fs.writeFileSync(
path.join(pkgDir, "package.json"),
JSON.stringify({
name: "@clawdbot/voice-call",
name: "@moltbot/voice-call",
version: "0.0.1",
clawdbot: { extensions: ["./dist/index.js"] },
moltbot: { extensions: ["./dist/index.js"] },
}),
"utf-8",
);
@@ -210,9 +210,9 @@ describe("installPluginFromArchive", () => {
fs.writeFileSync(
path.join(pkgDir, "package.json"),
JSON.stringify({
name: "@clawdbot/voice-call",
name: "@moltbot/voice-call",
version: "0.0.2",
clawdbot: { extensions: ["./dist/index.js"] },
moltbot: { extensions: ["./dist/index.js"] },
}),
"utf-8",
);
@@ -244,14 +244,14 @@ describe("installPluginFromArchive", () => {
expect(manifest.version).toBe("0.0.2");
});
it("rejects packages without clawdbot.extensions", async () => {
it("rejects packages without moltbot.extensions", async () => {
const stateDir = makeTempDir();
const workDir = makeTempDir();
const pkgDir = path.join(workDir, "package");
fs.mkdirSync(pkgDir, { recursive: true });
fs.writeFileSync(
path.join(pkgDir, "package.json"),
JSON.stringify({ name: "@clawdbot/nope", version: "0.0.1" }),
JSON.stringify({ name: "@moltbot/nope", version: "0.0.1" }),
"utf-8",
);
@@ -266,6 +266,6 @@ describe("installPluginFromArchive", () => {
const result = await installPluginFromArchive({ archivePath, extensionsDir });
expect(result.ok).toBe(false);
if (result.ok) return;
expect(result.error).toContain("clawdbot.extensions");
expect(result.error).toContain("moltbot.extensions");
});
});

View File

@@ -1,6 +1,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { LEGACY_MANIFEST_KEY } from "../compat/legacy-names.js";
import { runCommandWithTimeout } from "../process/exec.js";
import { CONFIG_DIR, resolveUserPath } from "../utils.js";
import {
@@ -20,7 +21,8 @@ type PackageManifest = {
name?: string;
version?: string;
dependencies?: Record<string, string>;
clawdbot?: { extensions?: string[] };
moltbot?: { extensions?: string[] };
[LEGACY_MANIFEST_KEY]?: { extensions?: string[] };
};
export type InstallPluginResult =
@@ -52,14 +54,14 @@ function safeFileName(input: string): string {
return safeDirName(input);
}
async function ensureClawdbotExtensions(manifest: PackageManifest) {
const extensions = manifest.clawdbot?.extensions;
async function ensureMoltbotExtensions(manifest: PackageManifest) {
const extensions = manifest.moltbot?.extensions ?? manifest[LEGACY_MANIFEST_KEY]?.extensions;
if (!Array.isArray(extensions)) {
throw new Error("package.json missing clawdbot.extensions");
throw new Error("package.json missing moltbot.extensions");
}
const list = extensions.map((e) => (typeof e === "string" ? e.trim() : "")).filter(Boolean);
if (list.length === 0) {
throw new Error("package.json clawdbot.extensions is empty");
throw new Error("package.json moltbot.extensions is empty");
}
return list;
}
@@ -99,7 +101,7 @@ async function installPluginFromPackageDir(params: {
let extensions: string[];
try {
extensions = await ensureClawdbotExtensions(manifest);
extensions = await ensureMoltbotExtensions(manifest);
} catch (err) {
return { ok: false, error: String(err) };
}
@@ -217,7 +219,7 @@ export async function installPluginFromArchive(params: {
return { ok: false, error: `unsupported archive: ${archivePath}` };
}
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-plugin-"));
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-plugin-"));
const extractDir = path.join(tmpDir, "extract");
await fs.mkdir(extractDir, { recursive: true });
@@ -350,7 +352,7 @@ export async function installPluginFromNpmSpec(params: {
const spec = params.spec.trim();
if (!spec) return { ok: false, error: "missing npm spec" };
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-npm-pack-"));
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-npm-pack-"));
logger.info?.(`Downloading ${spec}`);
const res = await runCommandWithTimeout(["npm", "pack", spec], {
timeoutMs: Math.max(timeoutMs, 300_000),

View File

@@ -1,12 +1,12 @@
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { PluginInstallRecord } from "../config/types.plugins.js";
export type PluginInstallUpdate = PluginInstallRecord & { pluginId: string };
export function recordPluginInstall(
cfg: ClawdbotConfig,
cfg: MoltbotConfig,
update: PluginInstallUpdate,
): ClawdbotConfig {
): MoltbotConfig {
const { pluginId, ...record } = update;
const installs = {
...cfg.plugins?.installs,

View File

@@ -4,7 +4,7 @@ import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { loadClawdbotPlugins } from "./loader.js";
import { loadMoltbotPlugins } from "./loader.js";
type TempPlugin = { dir: string; file: string; id: string };
@@ -13,7 +13,7 @@ const prevBundledDir = process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR;
const EMPTY_PLUGIN_SCHEMA = { type: "object", additionalProperties: false, properties: {} };
function makeTempDir() {
const dir = path.join(os.tmpdir(), `clawdbot-plugin-${randomUUID()}`);
const dir = path.join(os.tmpdir(), `moltbot-plugin-${randomUUID()}`);
fs.mkdirSync(dir, { recursive: true });
tempDirs.push(dir);
return dir;
@@ -30,7 +30,7 @@ function writePlugin(params: {
const file = path.join(dir, filename);
fs.writeFileSync(file, params.body, "utf-8");
fs.writeFileSync(
path.join(dir, "clawdbot.plugin.json"),
path.join(dir, "moltbot.plugin.json"),
JSON.stringify(
{
id: params.id,
@@ -59,7 +59,7 @@ afterEach(() => {
}
});
describe("loadClawdbotPlugins", () => {
describe("loadMoltbotPlugins", () => {
it("disables bundled plugins by default", () => {
const bundledDir = makeTempDir();
writePlugin({
@@ -70,7 +70,7 @@ describe("loadClawdbotPlugins", () => {
});
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir;
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
config: {
plugins: {
@@ -82,7 +82,7 @@ describe("loadClawdbotPlugins", () => {
const bundled = registry.plugins.find((entry) => entry.id === "bundled");
expect(bundled?.status).toBe("disabled");
const enabledRegistry = loadClawdbotPlugins({
const enabledRegistry = loadMoltbotPlugins({
cache: false,
config: {
plugins: {
@@ -127,7 +127,7 @@ describe("loadClawdbotPlugins", () => {
});
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir;
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
config: {
plugins: {
@@ -154,7 +154,7 @@ describe("loadClawdbotPlugins", () => {
});
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir;
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
config: {
plugins: {
@@ -177,10 +177,10 @@ describe("loadClawdbotPlugins", () => {
fs.writeFileSync(
path.join(pluginDir, "package.json"),
JSON.stringify({
name: "@clawdbot/memory-core",
name: "@moltbot/memory-core",
version: "1.2.3",
description: "Memory plugin package",
clawdbot: { extensions: ["./index.ts"] },
moltbot: { extensions: ["./index.ts"] },
}),
"utf-8",
);
@@ -193,7 +193,7 @@ describe("loadClawdbotPlugins", () => {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir;
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
config: {
plugins: {
@@ -217,7 +217,7 @@ describe("loadClawdbotPlugins", () => {
body: `export default { id: "allowed", register(api) { api.registerGatewayMethod("allowed.ping", ({ respond }) => respond(true, { ok: true })); } };`,
});
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -240,7 +240,7 @@ describe("loadClawdbotPlugins", () => {
body: `export default { id: "blocked", register() {} };`,
});
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -263,7 +263,7 @@ describe("loadClawdbotPlugins", () => {
body: `export default { id: "configurable", register() {} };`,
});
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -309,7 +309,7 @@ describe("loadClawdbotPlugins", () => {
} };`,
});
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -333,7 +333,7 @@ describe("loadClawdbotPlugins", () => {
} };`,
});
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -359,7 +359,7 @@ describe("loadClawdbotPlugins", () => {
} };`,
});
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -384,7 +384,7 @@ describe("loadClawdbotPlugins", () => {
body: `export default { id: "config-disable", register() {} };`,
});
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
config: {
plugins: {
@@ -411,7 +411,7 @@ describe("loadClawdbotPlugins", () => {
body: `export default { id: "memory-b", kind: "memory", register() {} };`,
});
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
config: {
plugins: {
@@ -434,7 +434,7 @@ describe("loadClawdbotPlugins", () => {
body: `export default { id: "memory-off", kind: "memory", register() {} };`,
});
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
config: {
plugins: {
@@ -463,7 +463,7 @@ describe("loadClawdbotPlugins", () => {
body: `export default { id: "shadow", register() {} };`,
});
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
cache: false,
config: {
plugins: {

View File

@@ -3,11 +3,11 @@ import path from "node:path";
import { fileURLToPath } from "node:url";
import { createJiti } from "jiti";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { GatewayRequestHandler } from "../gateway/server-methods/types.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { resolveUserPath } from "../utils.js";
import { discoverClawdbotPlugins } from "./discovery.js";
import { discoverMoltbotPlugins } from "./discovery.js";
import { loadPluginManifestRegistry } from "./manifest-registry.js";
import {
normalizePluginsConfig,
@@ -22,8 +22,8 @@ import { createPluginRuntime } from "./runtime/index.js";
import { setActivePluginRegistry } from "./runtime.js";
import { validateJsonSchemaValue } from "./schema-validator.js";
import type {
ClawdbotPluginDefinition,
ClawdbotPluginModule,
MoltbotPluginDefinition,
MoltbotPluginModule,
PluginDiagnostic,
PluginLogger,
} from "./types.js";
@@ -31,7 +31,7 @@ import type {
export type PluginLoadResult = PluginRegistry;
export type PluginLoadOptions = {
config?: ClawdbotConfig;
config?: MoltbotConfig;
workspaceDir?: string;
logger?: PluginLogger;
coreGatewayHandlers?: Record<string, GatewayRequestHandler>;
@@ -98,8 +98,8 @@ function validatePluginConfig(params: {
}
function resolvePluginModuleExport(moduleExport: unknown): {
definition?: ClawdbotPluginDefinition;
register?: ClawdbotPluginDefinition["register"];
definition?: MoltbotPluginDefinition;
register?: MoltbotPluginDefinition["register"];
} {
const resolved =
moduleExport &&
@@ -109,11 +109,11 @@ function resolvePluginModuleExport(moduleExport: unknown): {
: moduleExport;
if (typeof resolved === "function") {
return {
register: resolved as ClawdbotPluginDefinition["register"],
register: resolved as MoltbotPluginDefinition["register"],
};
}
if (resolved && typeof resolved === "object") {
const def = resolved as ClawdbotPluginDefinition;
const def = resolved as MoltbotPluginDefinition;
const register = def.register ?? def.activate;
return { definition: def, register };
}
@@ -161,7 +161,7 @@ function pushDiagnostics(diagnostics: PluginDiagnostic[], append: PluginDiagnost
diagnostics.push(...append);
}
export function loadClawdbotPlugins(options: PluginLoadOptions = {}): PluginRegistry {
export function loadMoltbotPlugins(options: PluginLoadOptions = {}): PluginRegistry {
const cfg = options.config ?? {};
const logger = options.logger ?? defaultLogger();
const validateOnly = options.mode === "validate";
@@ -189,7 +189,7 @@ export function loadClawdbotPlugins(options: PluginLoadOptions = {}): PluginRegi
coreGatewayHandlers: options.coreGatewayHandlers as Record<string, GatewayRequestHandler>,
});
const discovery = discoverClawdbotPlugins({
const discovery = discoverMoltbotPlugins({
workspaceDir: options.workspaceDir,
extraPaths: normalized.loadPaths,
});
@@ -289,9 +289,9 @@ export function loadClawdbotPlugins(options: PluginLoadOptions = {}): PluginRegi
continue;
}
let mod: ClawdbotPluginModule | null = null;
let mod: MoltbotPluginModule | null = null;
try {
mod = jiti(candidate.source) as ClawdbotPluginModule;
mod = jiti(candidate.source) as MoltbotPluginModule;
} catch (err) {
logger.error(`[plugins] ${record.id} failed to load from ${record.source}: ${String(err)}`);
record.status = "error";

View File

@@ -1,9 +1,9 @@
import fs from "node:fs";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import { resolveUserPath } from "../utils.js";
import { normalizePluginsConfig, type NormalizedPluginsConfig } from "./config-state.js";
import { discoverClawdbotPlugins, type PluginCandidate } from "./discovery.js";
import { discoverMoltbotPlugins, type PluginCandidate } from "./discovery.js";
import { loadPluginManifest, type PluginManifest } from "./manifest.js";
import type { PluginConfigUiHint, PluginDiagnostic, PluginKind, PluginOrigin } from "./types.js";
@@ -100,7 +100,7 @@ function buildRecord(params: {
}
export function loadPluginManifestRegistry(params: {
config?: ClawdbotConfig;
config?: MoltbotConfig;
workspaceDir?: string;
cache?: boolean;
env?: NodeJS.ProcessEnv;
@@ -122,7 +122,7 @@ export function loadPluginManifestRegistry(params: {
candidates: params.candidates,
diagnostics: params.diagnostics ?? [],
}
: discoverClawdbotPlugins({
: discoverMoltbotPlugins({
workspaceDir: params.workspaceDir,
extraPaths: normalized.loadPaths,
});

View File

@@ -1,9 +1,14 @@
import fs from "node:fs";
import path from "node:path";
import { LEGACY_MANIFEST_KEY, LEGACY_PLUGIN_MANIFEST_FILENAME } from "../compat/legacy-names.js";
import type { PluginConfigUiHint, PluginKind } from "./types.js";
export const PLUGIN_MANIFEST_FILENAME = "clawdbot.plugin.json";
export const PLUGIN_MANIFEST_FILENAME = "moltbot.plugin.json";
export const PLUGIN_MANIFEST_FILENAMES = [
PLUGIN_MANIFEST_FILENAME,
LEGACY_PLUGIN_MANIFEST_FILENAME,
] as const;
export type PluginManifest = {
id: string;
@@ -32,6 +37,10 @@ function isRecord(value: unknown): value is Record<string, unknown> {
}
export function resolvePluginManifestPath(rootDir: string): string {
for (const filename of PLUGIN_MANIFEST_FILENAMES) {
const candidate = path.join(rootDir, filename);
if (fs.existsSync(candidate)) return candidate;
}
return path.join(rootDir, PLUGIN_MANIFEST_FILENAME);
}
@@ -93,7 +102,7 @@ export function loadPluginManifest(rootDir: string): PluginManifestLoadResult {
};
}
// package.json "clawdbot" metadata (used for onboarding/catalog)
// package.json "moltbot" metadata (used for onboarding/catalog)
export type PluginPackageChannel = {
id?: string;
label?: string;
@@ -121,7 +130,7 @@ export type PluginPackageInstall = {
defaultChoice?: "npm" | "local";
};
export type ClawdbotPackageManifest = {
export type MoltbotPackageManifest = {
extensions?: string[];
channel?: PluginPackageChannel;
install?: PluginPackageInstall;
@@ -131,5 +140,13 @@ export type PackageManifest = {
name?: string;
version?: string;
description?: string;
clawdbot?: ClawdbotPackageManifest;
moltbot?: MoltbotPackageManifest;
[LEGACY_MANIFEST_KEY]?: MoltbotPackageManifest;
};
export function getPackageManifestMetadata(
manifest: PackageManifest | undefined,
): MoltbotPackageManifest | undefined {
if (!manifest) return undefined;
return manifest.moltbot ?? manifest[LEGACY_MANIFEST_KEY];
}

View File

@@ -1,5 +1,5 @@
import { createSubsystemLogger } from "../logging/subsystem.js";
import { loadClawdbotPlugins, type PluginLoadOptions } from "./loader.js";
import { loadMoltbotPlugins, type PluginLoadOptions } from "./loader.js";
import type { ProviderPlugin } from "./types.js";
const log = createSubsystemLogger("plugins");
@@ -8,7 +8,7 @@ export function resolvePluginProviders(params: {
config?: PluginLoadOptions["config"];
workspaceDir?: string;
}): ProviderPlugin[] {
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
config: params.config,
workspaceDir: params.workspaceDir,
logger: {

View File

@@ -8,17 +8,17 @@ import type {
import { registerInternalHook } from "../hooks/internal-hooks.js";
import { resolveUserPath } from "../utils.js";
import type {
ClawdbotPluginApi,
ClawdbotPluginChannelRegistration,
ClawdbotPluginCliRegistrar,
ClawdbotPluginCommandDefinition,
ClawdbotPluginHttpHandler,
ClawdbotPluginHttpRouteHandler,
ClawdbotPluginHookOptions,
MoltbotPluginApi,
MoltbotPluginChannelRegistration,
MoltbotPluginCliRegistrar,
MoltbotPluginCommandDefinition,
MoltbotPluginHttpHandler,
MoltbotPluginHttpRouteHandler,
MoltbotPluginHookOptions,
ProviderPlugin,
ClawdbotPluginService,
ClawdbotPluginToolContext,
ClawdbotPluginToolFactory,
MoltbotPluginService,
MoltbotPluginToolContext,
MoltbotPluginToolFactory,
PluginConfigUiHint,
PluginDiagnostic,
PluginLogger,
@@ -36,7 +36,7 @@ import { normalizePluginHttpPath } from "./http-path.js";
export type PluginToolRegistration = {
pluginId: string;
factory: ClawdbotPluginToolFactory;
factory: MoltbotPluginToolFactory;
names: string[];
optional: boolean;
source: string;
@@ -44,21 +44,21 @@ export type PluginToolRegistration = {
export type PluginCliRegistration = {
pluginId: string;
register: ClawdbotPluginCliRegistrar;
register: MoltbotPluginCliRegistrar;
commands: string[];
source: string;
};
export type PluginHttpRegistration = {
pluginId: string;
handler: ClawdbotPluginHttpHandler;
handler: MoltbotPluginHttpHandler;
source: string;
};
export type PluginHttpRouteRegistration = {
pluginId?: string;
path: string;
handler: ClawdbotPluginHttpRouteHandler;
handler: MoltbotPluginHttpRouteHandler;
source?: string;
};
@@ -84,13 +84,13 @@ export type PluginHookRegistration = {
export type PluginServiceRegistration = {
pluginId: string;
service: ClawdbotPluginService;
service: MoltbotPluginService;
source: string;
};
export type PluginCommandRegistration = {
pluginId: string;
command: ClawdbotPluginCommandDefinition;
command: MoltbotPluginCommandDefinition;
source: string;
};
@@ -167,13 +167,13 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
const registerTool = (
record: PluginRecord,
tool: AnyAgentTool | ClawdbotPluginToolFactory,
tool: AnyAgentTool | MoltbotPluginToolFactory,
opts?: { name?: string; names?: string[]; optional?: boolean },
) => {
const names = opts?.names ?? (opts?.name ? [opts.name] : []);
const optional = opts?.optional === true;
const factory: ClawdbotPluginToolFactory =
typeof tool === "function" ? tool : (_ctx: ClawdbotPluginToolContext) => tool;
const factory: MoltbotPluginToolFactory =
typeof tool === "function" ? tool : (_ctx: MoltbotPluginToolContext) => tool;
if (typeof tool !== "function") {
names.push(tool.name);
@@ -196,8 +196,8 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
record: PluginRecord,
events: string | string[],
handler: Parameters<typeof registerInternalHook>[1],
opts: ClawdbotPluginHookOptions | undefined,
config: ClawdbotPluginApi["config"],
opts: MoltbotPluginHookOptions | undefined,
config: MoltbotPluginApi["config"],
) => {
const eventList = Array.isArray(events) ? events : [events];
const normalizedEvents = eventList.map((event) => event.trim()).filter(Boolean);
@@ -221,11 +221,11 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
...entry.hook,
name,
description,
source: "clawdbot-plugin",
source: "moltbot-plugin",
pluginId: record.id,
},
clawdbot: {
...entry.clawdbot,
metadata: {
...entry.metadata,
events: normalizedEvents,
},
}
@@ -233,14 +233,14 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
hook: {
name,
description,
source: "clawdbot-plugin",
source: "moltbot-plugin",
pluginId: record.id,
filePath: record.source,
baseDir: path.dirname(record.source),
handlerPath: record.source,
},
frontmatter: {},
clawdbot: { events: normalizedEvents },
metadata: { events: normalizedEvents },
invocation: { enabled: true },
};
@@ -282,7 +282,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
record.gatewayMethods.push(trimmed);
};
const registerHttpHandler = (record: PluginRecord, handler: ClawdbotPluginHttpHandler) => {
const registerHttpHandler = (record: PluginRecord, handler: MoltbotPluginHttpHandler) => {
record.httpHandlers += 1;
registry.httpHandlers.push({
pluginId: record.id,
@@ -293,7 +293,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
const registerHttpRoute = (
record: PluginRecord,
params: { path: string; handler: ClawdbotPluginHttpRouteHandler },
params: { path: string; handler: MoltbotPluginHttpRouteHandler },
) => {
const normalizedPath = normalizePluginHttpPath(params.path);
if (!normalizedPath) {
@@ -325,11 +325,11 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
const registerChannel = (
record: PluginRecord,
registration: ClawdbotPluginChannelRegistration | ChannelPlugin,
registration: MoltbotPluginChannelRegistration | ChannelPlugin,
) => {
const normalized =
typeof (registration as ClawdbotPluginChannelRegistration).plugin === "object"
? (registration as ClawdbotPluginChannelRegistration)
typeof (registration as MoltbotPluginChannelRegistration).plugin === "object"
? (registration as MoltbotPluginChannelRegistration)
: { plugin: registration as ChannelPlugin };
const plugin = normalized.plugin;
const id = typeof plugin?.id === "string" ? plugin.id.trim() : String(plugin?.id ?? "").trim();
@@ -382,7 +382,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
const registerCli = (
record: PluginRecord,
registrar: ClawdbotPluginCliRegistrar,
registrar: MoltbotPluginCliRegistrar,
opts?: { commands?: string[] },
) => {
const commands = (opts?.commands ?? []).map((cmd) => cmd.trim()).filter(Boolean);
@@ -395,7 +395,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
});
};
const registerService = (record: PluginRecord, service: ClawdbotPluginService) => {
const registerService = (record: PluginRecord, service: MoltbotPluginService) => {
const id = service.id.trim();
if (!id) return;
record.services.push(id);
@@ -406,7 +406,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
});
};
const registerCommand = (record: PluginRecord, command: ClawdbotPluginCommandDefinition) => {
const registerCommand = (record: PluginRecord, command: MoltbotPluginCommandDefinition) => {
const name = command.name.trim();
if (!name) {
pushDiagnostic({
@@ -464,10 +464,10 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
const createApi = (
record: PluginRecord,
params: {
config: ClawdbotPluginApi["config"];
config: MoltbotPluginApi["config"];
pluginConfig?: Record<string, unknown>;
},
): ClawdbotPluginApi => {
): MoltbotPluginApi => {
return {
id: record.id,
name: record.name,

View File

@@ -16,7 +16,7 @@ const createEmptyRegistry = (): PluginRegistry => ({
diagnostics: [],
});
const REGISTRY_STATE = Symbol.for("clawdbot.pluginRegistryState");
const REGISTRY_STATE = Symbol.for("moltbot.pluginRegistryState");
type RegistryState = {
registry: PluginRegistry | null;

View File

@@ -1,5 +1,5 @@
import type { ClawdbotConfig } from "../config/config.js";
import { STATE_DIR_CLAWDBOT } from "../config/paths.js";
import type { MoltbotConfig } from "../config/config.js";
import { STATE_DIR } from "../config/paths.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import type { PluginRegistry } from "./registry.js";
@@ -11,7 +11,7 @@ export type PluginServicesHandle = {
export async function startPluginServices(params: {
registry: PluginRegistry;
config: ClawdbotConfig;
config: MoltbotConfig;
workspaceDir?: string;
}): Promise<PluginServicesHandle> {
const running: Array<{
@@ -25,7 +25,7 @@ export async function startPluginServices(params: {
await service.start({
config: params.config,
workspaceDir: params.workspaceDir,
stateDir: STATE_DIR_CLAWDBOT,
stateDir: STATE_DIR,
logger: {
info: (msg) => log.info(msg),
warn: (msg) => log.warn(msg),
@@ -40,7 +40,7 @@ export async function startPluginServices(params: {
service.stop?.({
config: params.config,
workspaceDir: params.workspaceDir,
stateDir: STATE_DIR_CLAWDBOT,
stateDir: STATE_DIR,
logger: {
info: (msg) => log.info(msg),
warn: (msg) => log.warn(msg),

View File

@@ -1,11 +1,11 @@
import { describe, expect, it } from "vitest";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import { applyExclusiveSlotSelection } from "./slots.js";
describe("applyExclusiveSlotSelection", () => {
it("selects the slot and disables other entries for the same kind", () => {
const config: ClawdbotConfig = {
const config: MoltbotConfig = {
plugins: {
slots: { memory: "memory-core" },
entries: {
@@ -37,7 +37,7 @@ describe("applyExclusiveSlotSelection", () => {
});
it("does nothing when the slot already matches", () => {
const config: ClawdbotConfig = {
const config: MoltbotConfig = {
plugins: {
slots: { memory: "memory" },
entries: {
@@ -59,7 +59,7 @@ describe("applyExclusiveSlotSelection", () => {
});
it("warns when the slot falls back to a default", () => {
const config: ClawdbotConfig = {
const config: MoltbotConfig = {
plugins: {
entries: {
memory: { enabled: true },
@@ -81,7 +81,7 @@ describe("applyExclusiveSlotSelection", () => {
});
it("skips changes when no exclusive slot applies", () => {
const config: ClawdbotConfig = {};
const config: MoltbotConfig = {};
const result = applyExclusiveSlotSelection({
config,
selectedId: "custom",

View File

@@ -1,4 +1,4 @@
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { PluginSlotsConfig } from "../config/types.plugins.js";
import type { PluginKind } from "./types.js";
@@ -27,13 +27,13 @@ export function defaultSlotIdForKey(slotKey: PluginSlotKey): string {
}
export type SlotSelectionResult = {
config: ClawdbotConfig;
config: MoltbotConfig;
warnings: string[];
changed: boolean;
};
export function applyExclusiveSlotSelection(params: {
config: ClawdbotConfig;
config: MoltbotConfig;
selectedId: string;
selectedKind?: PluginKind;
registry?: { plugins: SlotPluginRecord[] };

View File

@@ -2,7 +2,7 @@ import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent
import { resolveDefaultAgentWorkspaceDir } from "../agents/workspace.js";
import { loadConfig } from "../config/config.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { loadClawdbotPlugins } from "./loader.js";
import { loadMoltbotPlugins } from "./loader.js";
import type { PluginRegistry } from "./registry.js";
export type PluginStatusReport = PluginRegistry & {
@@ -21,7 +21,7 @@ export function buildPluginStatusReport(params?: {
: (resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)) ??
resolveDefaultAgentWorkspaceDir());
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
config,
workspaceDir,
logger: {

View File

@@ -13,7 +13,7 @@ const tempDirs: string[] = [];
const EMPTY_PLUGIN_SCHEMA = { type: "object", additionalProperties: false, properties: {} };
function makeTempDir() {
const dir = path.join(os.tmpdir(), `clawdbot-plugin-tools-${randomUUID()}`);
const dir = path.join(os.tmpdir(), `moltbot-plugin-tools-${randomUUID()}`);
fs.mkdirSync(dir, { recursive: true });
tempDirs.push(dir);
return dir;
@@ -24,7 +24,7 @@ function writePlugin(params: { id: string; body: string }): TempPlugin {
const file = path.join(dir, `${params.id}.js`);
fs.writeFileSync(file, params.body, "utf-8");
fs.writeFileSync(
path.join(dir, "clawdbot.plugin.json"),
path.join(dir, "moltbot.plugin.json"),
JSON.stringify(
{
id: params.id,

View File

@@ -1,8 +1,8 @@
import type { AnyAgentTool } from "../agents/tools/common.js";
import { normalizeToolName } from "../agents/tool-policy.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { loadClawdbotPlugins } from "./loader.js";
import type { ClawdbotPluginToolContext } from "./types.js";
import { loadMoltbotPlugins } from "./loader.js";
import type { MoltbotPluginToolContext } from "./types.js";
const log = createSubsystemLogger("plugins");
@@ -35,11 +35,11 @@ function isOptionalToolAllowed(params: {
}
export function resolvePluginTools(params: {
context: ClawdbotPluginToolContext;
context: MoltbotPluginToolContext;
existingToolNames?: Set<string>;
toolAllowlist?: string[];
}): AnyAgentTool[] {
const registry = loadClawdbotPlugins({
const registry = loadMoltbotPlugins({
config: params.context.config,
workspaceDir: params.context.workspaceDir,
logger: {

View File

@@ -7,7 +7,7 @@ import type { AuthProfileCredential, OAuthCredential } from "../agents/auth-prof
import type { AnyAgentTool } from "../agents/tools/common.js";
import type { ChannelDock } from "../channels/dock.js";
import type { ChannelPlugin } from "../channels/plugins/types.js";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { InternalHookHandler } from "../hooks/internal-hooks.js";
import type { HookEntry } from "../hooks/types.js";
import type { ModelProviderConfig } from "../config/types.js";
@@ -41,7 +41,7 @@ export type PluginConfigValidation =
| { ok: true; value?: unknown }
| { ok: false; errors: string[] };
export type ClawdbotPluginConfigSchema = {
export type MoltbotPluginConfigSchema = {
safeParse?: (value: unknown) => {
success: boolean;
data?: unknown;
@@ -55,8 +55,8 @@ export type ClawdbotPluginConfigSchema = {
jsonSchema?: Record<string, unknown>;
};
export type ClawdbotPluginToolContext = {
config?: ClawdbotConfig;
export type MoltbotPluginToolContext = {
config?: MoltbotConfig;
workspaceDir?: string;
agentDir?: string;
agentId?: string;
@@ -66,17 +66,17 @@ export type ClawdbotPluginToolContext = {
sandboxed?: boolean;
};
export type ClawdbotPluginToolFactory = (
ctx: ClawdbotPluginToolContext,
export type MoltbotPluginToolFactory = (
ctx: MoltbotPluginToolContext,
) => AnyAgentTool | AnyAgentTool[] | null | undefined;
export type ClawdbotPluginToolOptions = {
export type MoltbotPluginToolOptions = {
name?: string;
names?: string[];
optional?: boolean;
};
export type ClawdbotPluginHookOptions = {
export type MoltbotPluginHookOptions = {
entry?: HookEntry;
name?: string;
description?: string;
@@ -87,13 +87,13 @@ export type ProviderAuthKind = "oauth" | "api_key" | "token" | "device_code" | "
export type ProviderAuthResult = {
profiles: Array<{ profileId: string; credential: AuthProfileCredential }>;
configPatch?: Partial<ClawdbotConfig>;
configPatch?: Partial<MoltbotConfig>;
defaultModel?: string;
notes?: string[];
};
export type ProviderAuthContext = {
config: ClawdbotConfig;
config: MoltbotConfig;
agentDir?: string;
workspaceDir?: string;
prompter: WizardPrompter;
@@ -125,7 +125,7 @@ export type ProviderPlugin = {
refreshOAuth?: (cred: OAuthCredential) => Promise<OAuthCredential>;
};
export type ClawdbotPluginGatewayMethod = {
export type MoltbotPluginGatewayMethod = {
method: string;
handler: GatewayRequestHandler;
};
@@ -148,8 +148,8 @@ export type PluginCommandContext = {
args?: string;
/** The full normalized command body */
commandBody: string;
/** Current clawdbot configuration */
config: ClawdbotConfig;
/** Current moltbot configuration */
config: MoltbotConfig;
};
/**
@@ -167,7 +167,7 @@ export type PluginCommandHandler = (
/**
* Definition for a plugin-registered command.
*/
export type ClawdbotPluginCommandDefinition = {
export type MoltbotPluginCommandDefinition = {
/** Command name without leading slash (e.g., "tts") */
name: string;
/** Description shown in /help and command menus */
@@ -180,90 +180,90 @@ export type ClawdbotPluginCommandDefinition = {
handler: PluginCommandHandler;
};
export type ClawdbotPluginHttpHandler = (
export type MoltbotPluginHttpHandler = (
req: IncomingMessage,
res: ServerResponse,
) => Promise<boolean> | boolean;
export type ClawdbotPluginHttpRouteHandler = (
export type MoltbotPluginHttpRouteHandler = (
req: IncomingMessage,
res: ServerResponse,
) => Promise<void> | void;
export type ClawdbotPluginCliContext = {
export type MoltbotPluginCliContext = {
program: Command;
config: ClawdbotConfig;
config: MoltbotConfig;
workspaceDir?: string;
logger: PluginLogger;
};
export type ClawdbotPluginCliRegistrar = (ctx: ClawdbotPluginCliContext) => void | Promise<void>;
export type MoltbotPluginCliRegistrar = (ctx: MoltbotPluginCliContext) => void | Promise<void>;
export type ClawdbotPluginServiceContext = {
config: ClawdbotConfig;
export type MoltbotPluginServiceContext = {
config: MoltbotConfig;
workspaceDir?: string;
stateDir: string;
logger: PluginLogger;
};
export type ClawdbotPluginService = {
export type MoltbotPluginService = {
id: string;
start: (ctx: ClawdbotPluginServiceContext) => void | Promise<void>;
stop?: (ctx: ClawdbotPluginServiceContext) => void | Promise<void>;
start: (ctx: MoltbotPluginServiceContext) => void | Promise<void>;
stop?: (ctx: MoltbotPluginServiceContext) => void | Promise<void>;
};
export type ClawdbotPluginChannelRegistration = {
export type MoltbotPluginChannelRegistration = {
plugin: ChannelPlugin;
dock?: ChannelDock;
};
export type ClawdbotPluginDefinition = {
export type MoltbotPluginDefinition = {
id?: string;
name?: string;
description?: string;
version?: string;
kind?: PluginKind;
configSchema?: ClawdbotPluginConfigSchema;
register?: (api: ClawdbotPluginApi) => void | Promise<void>;
activate?: (api: ClawdbotPluginApi) => void | Promise<void>;
configSchema?: MoltbotPluginConfigSchema;
register?: (api: MoltbotPluginApi) => void | Promise<void>;
activate?: (api: MoltbotPluginApi) => void | Promise<void>;
};
export type ClawdbotPluginModule =
| ClawdbotPluginDefinition
| ((api: ClawdbotPluginApi) => void | Promise<void>);
export type MoltbotPluginModule =
| MoltbotPluginDefinition
| ((api: MoltbotPluginApi) => void | Promise<void>);
export type ClawdbotPluginApi = {
export type MoltbotPluginApi = {
id: string;
name: string;
version?: string;
description?: string;
source: string;
config: ClawdbotConfig;
config: MoltbotConfig;
pluginConfig?: Record<string, unknown>;
runtime: PluginRuntime;
logger: PluginLogger;
registerTool: (
tool: AnyAgentTool | ClawdbotPluginToolFactory,
opts?: ClawdbotPluginToolOptions,
tool: AnyAgentTool | MoltbotPluginToolFactory,
opts?: MoltbotPluginToolOptions,
) => void;
registerHook: (
events: string | string[],
handler: InternalHookHandler,
opts?: ClawdbotPluginHookOptions,
opts?: MoltbotPluginHookOptions,
) => void;
registerHttpHandler: (handler: ClawdbotPluginHttpHandler) => void;
registerHttpRoute: (params: { path: string; handler: ClawdbotPluginHttpRouteHandler }) => void;
registerChannel: (registration: ClawdbotPluginChannelRegistration | ChannelPlugin) => void;
registerHttpHandler: (handler: MoltbotPluginHttpHandler) => void;
registerHttpRoute: (params: { path: string; handler: MoltbotPluginHttpRouteHandler }) => void;
registerChannel: (registration: MoltbotPluginChannelRegistration | ChannelPlugin) => void;
registerGatewayMethod: (method: string, handler: GatewayRequestHandler) => void;
registerCli: (registrar: ClawdbotPluginCliRegistrar, opts?: { commands?: string[] }) => void;
registerService: (service: ClawdbotPluginService) => void;
registerCli: (registrar: MoltbotPluginCliRegistrar, opts?: { commands?: string[] }) => void;
registerService: (service: MoltbotPluginService) => void;
registerProvider: (provider: ProviderPlugin) => void;
/**
* Register a custom command that bypasses the LLM agent.
* Plugin commands are processed before built-in commands and before agent invocation.
* Use this for simple state-toggling or status commands that don't need AI reasoning.
*/
registerCommand: (command: ClawdbotPluginCommandDefinition) => void;
registerCommand: (command: MoltbotPluginCommandDefinition) => void;
resolvePath: (input: string) => string;
/** Register a lifecycle hook handler */
on: <K extends PluginHookName>(

View File

@@ -1,9 +1,9 @@
import fs from "node:fs/promises";
import type { ClawdbotConfig } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { UpdateChannel } from "../infra/update-channels.js";
import { resolveUserPath } from "../utils.js";
import { discoverClawdbotPlugins } from "./discovery.js";
import { discoverMoltbotPlugins } from "./discovery.js";
import { installPluginFromNpmSpec, resolvePluginInstallDir } from "./install.js";
import { recordPluginInstall } from "./installs.js";
import { loadPluginManifest } from "./manifest.js";
@@ -25,7 +25,7 @@ export type PluginUpdateOutcome = {
};
export type PluginUpdateSummary = {
config: ClawdbotConfig;
config: MoltbotConfig;
changed: boolean;
outcomes: PluginUpdateOutcome[];
};
@@ -38,7 +38,7 @@ export type PluginChannelSyncSummary = {
};
export type PluginChannelSyncResult = {
config: ClawdbotConfig;
config: MoltbotConfig;
changed: boolean;
summary: PluginChannelSyncSummary;
};
@@ -62,7 +62,7 @@ async function readInstalledPackageVersion(dir: string): Promise<string | undefi
function resolveBundledPluginSources(params: {
workspaceDir?: string;
}): Map<string, BundledPluginSource> {
const discovery = discoverClawdbotPlugins({ workspaceDir: params.workspaceDir });
const discovery = discoverMoltbotPlugins({ workspaceDir: params.workspaceDir });
const bundled = new Map<string, BundledPluginSource>();
for (const candidate of discovery.candidates) {
@@ -73,7 +73,7 @@ function resolveBundledPluginSources(params: {
if (bundled.has(pluginId)) continue;
const npmSpec =
candidate.packageClawdbot?.install?.npmSpec?.trim() ||
candidate.packageMoltbot?.install?.npmSpec?.trim() ||
candidate.packageName?.trim() ||
undefined;
@@ -127,7 +127,7 @@ function buildLoadPathHelpers(existing: string[]) {
}
export async function updateNpmInstalledPlugins(params: {
config: ClawdbotConfig;
config: MoltbotConfig;
logger?: PluginUpdateLogger;
pluginIds?: string[];
skipIds?: Set<string>;
@@ -290,7 +290,7 @@ export async function updateNpmInstalledPlugins(params: {
}
export async function syncPluginsForUpdateChannel(params: {
config: ClawdbotConfig;
config: MoltbotConfig;
channel: UpdateChannel;
workspaceDir?: string;
logger?: PluginUpdateLogger;