refactor: rename to openclaw

This commit is contained in:
Peter Steinberger
2026-01-30 03:15:10 +01:00
parent 4583f88626
commit 9a7160786a
2357 changed files with 16688 additions and 16788 deletions

View File

@@ -3,7 +3,7 @@ import path from "node:path";
import { fileURLToPath } from "node:url";
export function resolveBundledPluginsDir(): string | undefined {
const override = process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR?.trim();
const override = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR?.trim();
if (override) return override;
// bun --compile: ship a sibling `extensions/` next to the executable.

View File

@@ -7,7 +7,7 @@ const mocks = vi.hoisted(() => ({
}));
vi.mock("./loader.js", () => ({
loadMoltbotPlugins: () => ({
loadOpenClawPlugins: () => ({
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 { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { loadConfig } from "../config/config.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { loadMoltbotPlugins } from "./loader.js";
import { loadOpenClawPlugins } from "./loader.js";
import type { PluginLogger } from "./types.js";
const log = createSubsystemLogger("plugins");
export function registerPluginCliCommands(program: Command, cfg?: MoltbotConfig) {
export function registerPluginCliCommands(program: Command, cfg?: OpenClawConfig) {
const config = cfg ?? loadConfig();
const workspaceDir = resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config));
const logger: PluginLogger = {
@@ -18,7 +18,7 @@ export function registerPluginCliCommands(program: Command, cfg?: MoltbotConfig)
error: (msg: string) => log.error(msg),
debug: (msg: string) => log.debug(msg),
};
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
config,
workspaceDir,
logger,

View File

@@ -5,15 +5,15 @@
* These commands are processed before built-in commands and before agent invocation.
*/
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import type {
MoltbotPluginCommandDefinition,
OpenClawPluginCommandDefinition,
PluginCommandContext,
PluginCommandResult,
} from "./types.js";
import { logVerbose } from "../globals.js";
type RegisteredPluginCommand = MoltbotPluginCommandDefinition & {
type RegisteredPluginCommand = OpenClawPluginCommandDefinition & {
pluginId: string;
};
@@ -104,7 +104,7 @@ export type CommandRegistrationResult = {
*/
export function registerPluginCommand(
pluginId: string,
command: MoltbotPluginCommandDefinition,
command: OpenClawPluginCommandDefinition,
): 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: MoltbotConfig;
config: OpenClawConfig;
}): Promise<PluginCommandResult> {
const { command, args, senderId, channel, isAuthorizedSender, commandBody, config } = params;

View File

@@ -1,4 +1,4 @@
import type { MoltbotPluginConfigSchema } from "./types.js";
import type { OpenClawPluginConfigSchema } 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(): MoltbotPluginConfigSchema {
export function emptyPluginConfigSchema(): OpenClawPluginConfigSchema {
return {
safeParse(value: unknown): SafeParseResult {
if (value === undefined) return { success: true, data: undefined };

View File

@@ -1,4 +1,4 @@
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } 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?: MoltbotConfig["plugins"],
config?: OpenClawConfig["plugins"],
): NormalizedPluginsConfig => {
const memorySlot = normalizeSlotValue(config?.slots?.memory);
return {

View File

@@ -7,30 +7,30 @@ import { afterEach, describe, expect, it, vi } from "vitest";
const tempDirs: string[] = [];
function makeTempDir() {
const dir = path.join(os.tmpdir(), `moltbot-plugins-${randomUUID()}`);
const dir = path.join(os.tmpdir(), `openclaw-plugins-${randomUUID()}`);
fs.mkdirSync(dir, { recursive: true });
tempDirs.push(dir);
return dir;
}
async function withStateDir<T>(stateDir: string, fn: () => Promise<T>) {
const prev = process.env.CLAWDBOT_STATE_DIR;
const prevBundled = process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR;
process.env.CLAWDBOT_STATE_DIR = stateDir;
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const prev = process.env.OPENCLAW_STATE_DIR;
const prevBundled = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
process.env.OPENCLAW_STATE_DIR = stateDir;
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
vi.resetModules();
try {
return await fn();
} finally {
if (prev === undefined) {
delete process.env.CLAWDBOT_STATE_DIR;
delete process.env.OPENCLAW_STATE_DIR;
} else {
process.env.CLAWDBOT_STATE_DIR = prev;
process.env.OPENCLAW_STATE_DIR = prev;
}
if (prevBundled === undefined) {
delete process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR;
delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
} else {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = prevBundled;
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = prevBundled;
}
vi.resetModules();
}
@@ -46,7 +46,7 @@ afterEach(() => {
}
});
describe("discoverMoltbotPlugins", () => {
describe("discoverOpenClawPlugins", () => {
it("discovers global and workspace extensions", async () => {
const stateDir = makeTempDir();
const workspaceDir = path.join(stateDir, "workspace");
@@ -55,13 +55,13 @@ describe("discoverMoltbotPlugins", () => {
fs.mkdirSync(globalExt, { recursive: true });
fs.writeFileSync(path.join(globalExt, "alpha.ts"), "export default function () {}", "utf-8");
const workspaceExt = path.join(workspaceDir, ".clawdbot", "extensions");
const workspaceExt = path.join(workspaceDir, ".openclaw", "extensions");
fs.mkdirSync(workspaceExt, { recursive: true });
fs.writeFileSync(path.join(workspaceExt, "beta.ts"), "export default function () {}", "utf-8");
const { candidates } = await withStateDir(stateDir, async () => {
const { discoverMoltbotPlugins } = await import("./discovery.js");
return discoverMoltbotPlugins({ workspaceDir });
const { discoverOpenClawPlugins } = await import("./discovery.js");
return discoverOpenClawPlugins({ workspaceDir });
});
const ids = candidates.map((c) => c.idHint);
@@ -78,7 +78,7 @@ describe("discoverMoltbotPlugins", () => {
path.join(globalExt, "package.json"),
JSON.stringify({
name: "pack",
moltbot: { extensions: ["./src/one.ts", "./src/two.ts"] },
openclaw: { extensions: ["./src/one.ts", "./src/two.ts"] },
}),
"utf-8",
);
@@ -94,8 +94,8 @@ describe("discoverMoltbotPlugins", () => {
);
const { candidates } = await withStateDir(stateDir, async () => {
const { discoverMoltbotPlugins } = await import("./discovery.js");
return discoverMoltbotPlugins({});
const { discoverOpenClawPlugins } = await import("./discovery.js");
return discoverOpenClawPlugins({});
});
const ids = candidates.map((c) => c.idHint);
@@ -111,8 +111,8 @@ describe("discoverMoltbotPlugins", () => {
fs.writeFileSync(
path.join(globalExt, "package.json"),
JSON.stringify({
name: "@moltbot/voice-call",
moltbot: { extensions: ["./src/index.ts"] },
name: "@openclaw/voice-call",
openclaw: { extensions: ["./src/index.ts"] },
}),
"utf-8",
);
@@ -123,8 +123,8 @@ describe("discoverMoltbotPlugins", () => {
);
const { candidates } = await withStateDir(stateDir, async () => {
const { discoverMoltbotPlugins } = await import("./discovery.js");
return discoverMoltbotPlugins({});
const { discoverOpenClawPlugins } = await import("./discovery.js");
return discoverOpenClawPlugins({});
});
const ids = candidates.map((c) => c.idHint);
@@ -139,16 +139,16 @@ describe("discoverMoltbotPlugins", () => {
fs.writeFileSync(
path.join(packDir, "package.json"),
JSON.stringify({
name: "@moltbot/demo-plugin-dir",
moltbot: { extensions: ["./index.js"] },
name: "@openclaw/demo-plugin-dir",
openclaw: { extensions: ["./index.js"] },
}),
"utf-8",
);
fs.writeFileSync(path.join(packDir, "index.js"), "module.exports = {}", "utf-8");
const { candidates } = await withStateDir(stateDir, async () => {
const { discoverMoltbotPlugins } = await import("./discovery.js");
return discoverMoltbotPlugins({ extraPaths: [packDir] });
const { discoverOpenClawPlugins } = await import("./discovery.js");
return discoverOpenClawPlugins({ extraPaths: [packDir] });
});
const ids = candidates.map((c) => c.idHint);

View File

@@ -5,7 +5,7 @@ import { resolveConfigDir, resolveUserPath } from "../utils.js";
import { resolveBundledPluginsDir } from "./bundled-dir.js";
import {
getPackageManifestMetadata,
type MoltbotPackageManifest,
type OpenClawPackageManifest,
type PackageManifest,
} from "./manifest.js";
import type { PluginDiagnostic, PluginOrigin } from "./types.js";
@@ -22,7 +22,7 @@ export type PluginCandidate = {
packageVersion?: string;
packageDescription?: string;
packageDir?: string;
packageMoltbot?: MoltbotPackageManifest;
packageManifest?: OpenClawPackageManifest;
};
export type PluginDiscoveryResult = {
@@ -63,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: @moltbot/voice-call -> voice-call).
// package is scoped (example: @openclaw/voice-call -> voice-call).
const unscoped = rawPackageName.includes("/")
? (rawPackageName.split("/").pop() ?? rawPackageName)
: rawPackageName;
@@ -97,7 +97,7 @@ function addCandidate(params: {
packageVersion: manifest?.version?.trim() || undefined,
packageDescription: manifest?.description?.trim() || undefined,
packageDir: params.packageDir,
packageMoltbot: getPackageManifestMetadata(manifest ?? undefined),
packageManifest: getPackageManifestMetadata(manifest ?? undefined),
});
}
@@ -281,7 +281,7 @@ function discoverFromPath(params: {
}
}
export function discoverMoltbotPlugins(params: {
export function discoverOpenClawPlugins(params: {
workspaceDir?: string;
extraPaths?: string[];
}): PluginDiscoveryResult {
@@ -306,15 +306,17 @@ export function discoverMoltbotPlugins(params: {
}
if (workspaceDir) {
const workspaceRoot = resolveUserPath(workspaceDir);
const workspaceExt = path.join(workspaceRoot, ".clawdbot", "extensions");
discoverInDirectory({
dir: workspaceExt,
origin: "workspace",
workspaceDir: workspaceRoot,
candidates,
diagnostics,
seen,
});
const workspaceExtDirs = [path.join(workspaceRoot, ".openclaw", "extensions")];
for (const dir of workspaceExtDirs) {
discoverInDirectory({
dir,
origin: "workspace",
workspaceDir: workspaceRoot,
candidates,
diagnostics,
seen,
});
}
}
const globalDir = path.join(resolveConfigDir(), "extensions");

View File

@@ -1,12 +1,12 @@
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
export type PluginEnableResult = {
config: MoltbotConfig;
config: OpenClawConfig;
enabled: boolean;
reason?: string;
};
function ensureAllowlisted(cfg: MoltbotConfig, pluginId: string): MoltbotConfig {
function ensureAllowlisted(cfg: OpenClawConfig, pluginId: string): OpenClawConfig {
const allow = cfg.plugins?.allow;
if (!Array.isArray(allow) || allow.includes(pluginId)) return cfg;
return {
@@ -18,7 +18,7 @@ function ensureAllowlisted(cfg: MoltbotConfig, pluginId: string): MoltbotConfig
};
}
export function enablePluginInConfig(cfg: MoltbotConfig, pluginId: string): PluginEnableResult {
export function enablePluginInConfig(cfg: OpenClawConfig, pluginId: string): PluginEnableResult {
if (cfg.plugins?.enabled === false) {
return { config: cfg, enabled: false, reason: "plugins disabled" };
}
@@ -33,7 +33,7 @@ export function enablePluginInConfig(cfg: MoltbotConfig, pluginId: string): Plug
enabled: true,
},
};
let next: MoltbotConfig = {
let next: OpenClawConfig = {
...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(), `moltbot-plugin-install-${randomUUID()}`);
const dir = path.join(os.tmpdir(), `openclaw-plugin-install-${randomUUID()}`);
fs.mkdirSync(dir, { recursive: true });
tempDirs.push(dir);
return dir;
@@ -88,7 +88,7 @@ afterEach(() => {
});
describe("installPluginFromArchive", () => {
it("installs into ~/.clawdbot/extensions and uses unscoped id", async () => {
it("installs into ~/.openclaw/extensions and uses unscoped id", async () => {
const stateDir = makeTempDir();
const workDir = makeTempDir();
const pkgDir = path.join(workDir, "package");
@@ -96,9 +96,9 @@ describe("installPluginFromArchive", () => {
fs.writeFileSync(
path.join(pkgDir, "package.json"),
JSON.stringify({
name: "@moltbot/voice-call",
name: "@openclaw/voice-call",
version: "0.0.1",
moltbot: { extensions: ["./dist/index.js"] },
openclaw: { extensions: ["./dist/index.js"] },
}),
"utf-8",
);
@@ -129,9 +129,9 @@ describe("installPluginFromArchive", () => {
fs.writeFileSync(
path.join(pkgDir, "package.json"),
JSON.stringify({
name: "@moltbot/voice-call",
name: "@openclaw/voice-call",
version: "0.0.1",
moltbot: { extensions: ["./dist/index.js"] },
openclaw: { extensions: ["./dist/index.js"] },
}),
"utf-8",
);
@@ -163,9 +163,9 @@ describe("installPluginFromArchive", () => {
zip.file(
"package/package.json",
JSON.stringify({
name: "@moltbot/zipper",
name: "@openclaw/zipper",
version: "0.0.1",
moltbot: { extensions: ["./dist/index.js"] },
openclaw: { 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: "@moltbot/voice-call",
name: "@openclaw/voice-call",
version: "0.0.1",
moltbot: { extensions: ["./dist/index.js"] },
openclaw: { extensions: ["./dist/index.js"] },
}),
"utf-8",
);
@@ -210,9 +210,9 @@ describe("installPluginFromArchive", () => {
fs.writeFileSync(
path.join(pkgDir, "package.json"),
JSON.stringify({
name: "@moltbot/voice-call",
name: "@openclaw/voice-call",
version: "0.0.2",
moltbot: { extensions: ["./dist/index.js"] },
openclaw: { extensions: ["./dist/index.js"] },
}),
"utf-8",
);
@@ -244,14 +244,14 @@ describe("installPluginFromArchive", () => {
expect(manifest.version).toBe("0.0.2");
});
it("rejects packages without moltbot.extensions", async () => {
it("rejects packages without openclaw.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: "@moltbot/nope", version: "0.0.1" }),
JSON.stringify({ name: "@openclaw/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("moltbot.extensions");
expect(result.error).toContain("openclaw.extensions");
});
});

View File

@@ -1,7 +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 { MANIFEST_KEY } from "../compat/legacy-names.js";
import { runCommandWithTimeout } from "../process/exec.js";
import { CONFIG_DIR, resolveUserPath } from "../utils.js";
import {
@@ -21,9 +21,7 @@ type PackageManifest = {
name?: string;
version?: string;
dependencies?: Record<string, string>;
moltbot?: { extensions?: string[] };
[LEGACY_MANIFEST_KEY]?: { extensions?: string[] };
};
} & Partial<Record<typeof MANIFEST_KEY, { extensions?: string[] }>>;
export type InstallPluginResult =
| {
@@ -54,14 +52,14 @@ function safeFileName(input: string): string {
return safeDirName(input);
}
async function ensureMoltbotExtensions(manifest: PackageManifest) {
const extensions = manifest.moltbot?.extensions ?? manifest[LEGACY_MANIFEST_KEY]?.extensions;
async function ensureOpenClawExtensions(manifest: PackageManifest) {
const extensions = manifest[MANIFEST_KEY]?.extensions;
if (!Array.isArray(extensions)) {
throw new Error("package.json missing moltbot.extensions");
throw new Error("package.json missing openclaw.extensions");
}
const list = extensions.map((e) => (typeof e === "string" ? e.trim() : "")).filter(Boolean);
if (list.length === 0) {
throw new Error("package.json moltbot.extensions is empty");
throw new Error("package.json openclaw.extensions is empty");
}
return list;
}
@@ -101,7 +99,7 @@ async function installPluginFromPackageDir(params: {
let extensions: string[];
try {
extensions = await ensureMoltbotExtensions(manifest);
extensions = await ensureOpenClawExtensions(manifest);
} catch (err) {
return { ok: false, error: String(err) };
}
@@ -219,7 +217,7 @@ export async function installPluginFromArchive(params: {
return { ok: false, error: `unsupported archive: ${archivePath}` };
}
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-plugin-"));
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-plugin-"));
const extractDir = path.join(tmpDir, "extract");
await fs.mkdir(extractDir, { recursive: true });
@@ -352,7 +350,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(), "moltbot-npm-pack-"));
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-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 { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import type { PluginInstallRecord } from "../config/types.plugins.js";
export type PluginInstallUpdate = PluginInstallRecord & { pluginId: string };
export function recordPluginInstall(
cfg: MoltbotConfig,
cfg: OpenClawConfig,
update: PluginInstallUpdate,
): MoltbotConfig {
): OpenClawConfig {
const { pluginId, ...record } = update;
const installs = {
...cfg.plugins?.installs,

View File

@@ -4,16 +4,16 @@ import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { loadMoltbotPlugins } from "./loader.js";
import { loadOpenClawPlugins } from "./loader.js";
type TempPlugin = { dir: string; file: string; id: string };
const tempDirs: string[] = [];
const prevBundledDir = process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR;
const prevBundledDir = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
const EMPTY_PLUGIN_SCHEMA = { type: "object", additionalProperties: false, properties: {} };
function makeTempDir() {
const dir = path.join(os.tmpdir(), `moltbot-plugin-${randomUUID()}`);
const dir = path.join(os.tmpdir(), `openclaw-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, "moltbot.plugin.json"),
path.join(dir, "openclaw.plugin.json"),
JSON.stringify(
{
id: params.id,
@@ -53,13 +53,13 @@ afterEach(() => {
}
}
if (prevBundledDir === undefined) {
delete process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR;
delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
} else {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = prevBundledDir;
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = prevBundledDir;
}
});
describe("loadMoltbotPlugins", () => {
describe("loadOpenClawPlugins", () => {
it("disables bundled plugins by default", () => {
const bundledDir = makeTempDir();
writePlugin({
@@ -68,9 +68,9 @@ describe("loadMoltbotPlugins", () => {
dir: bundledDir,
filename: "bundled.ts",
});
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir;
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir;
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
config: {
plugins: {
@@ -82,7 +82,7 @@ describe("loadMoltbotPlugins", () => {
const bundled = registry.plugins.find((entry) => entry.id === "bundled");
expect(bundled?.status).toBe("disabled");
const enabledRegistry = loadMoltbotPlugins({
const enabledRegistry = loadOpenClawPlugins({
cache: false,
config: {
plugins: {
@@ -125,9 +125,9 @@ describe("loadMoltbotPlugins", () => {
dir: bundledDir,
filename: "telegram.ts",
});
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir;
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir;
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
config: {
plugins: {
@@ -152,9 +152,9 @@ describe("loadMoltbotPlugins", () => {
dir: bundledDir,
filename: "memory-core.ts",
});
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir;
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir;
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
config: {
plugins: {
@@ -177,10 +177,10 @@ describe("loadMoltbotPlugins", () => {
fs.writeFileSync(
path.join(pluginDir, "package.json"),
JSON.stringify({
name: "@moltbot/memory-core",
name: "@openclaw/memory-core",
version: "1.2.3",
description: "Memory plugin package",
moltbot: { extensions: ["./index.ts"] },
openclaw: { extensions: ["./index.ts"] },
}),
"utf-8",
);
@@ -191,9 +191,9 @@ describe("loadMoltbotPlugins", () => {
filename: "index.ts",
});
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir;
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir;
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
config: {
plugins: {
@@ -211,13 +211,13 @@ describe("loadMoltbotPlugins", () => {
expect(memory?.version).toBe("1.2.3");
});
it("loads plugins from config paths", () => {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const plugin = writePlugin({
id: "allowed",
body: `export default { id: "allowed", register(api) { api.registerGatewayMethod("allowed.ping", ({ respond }) => respond(true, { ok: true })); } };`,
});
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -234,13 +234,13 @@ describe("loadMoltbotPlugins", () => {
});
it("denylist disables plugins even if allowed", () => {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const plugin = writePlugin({
id: "blocked",
body: `export default { id: "blocked", register() {} };`,
});
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -257,13 +257,13 @@ describe("loadMoltbotPlugins", () => {
});
it("fails fast on invalid plugin config", () => {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const plugin = writePlugin({
id: "configurable",
body: `export default { id: "configurable", register() {} };`,
});
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -284,7 +284,7 @@ describe("loadMoltbotPlugins", () => {
});
it("registers channel plugins", () => {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const plugin = writePlugin({
id: "channel-demo",
body: `export default { id: "channel-demo", register(api) {
@@ -309,7 +309,7 @@ describe("loadMoltbotPlugins", () => {
} };`,
});
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -325,7 +325,7 @@ describe("loadMoltbotPlugins", () => {
});
it("registers http handlers", () => {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const plugin = writePlugin({
id: "http-demo",
body: `export default { id: "http-demo", register(api) {
@@ -333,7 +333,7 @@ describe("loadMoltbotPlugins", () => {
} };`,
});
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -351,7 +351,7 @@ describe("loadMoltbotPlugins", () => {
});
it("registers http routes", () => {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const plugin = writePlugin({
id: "http-route-demo",
body: `export default { id: "http-route-demo", register(api) {
@@ -359,7 +359,7 @@ describe("loadMoltbotPlugins", () => {
} };`,
});
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
@@ -378,13 +378,13 @@ describe("loadMoltbotPlugins", () => {
});
it("respects explicit disable in config", () => {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const plugin = writePlugin({
id: "config-disable",
body: `export default { id: "config-disable", register() {} };`,
});
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
config: {
plugins: {
@@ -401,7 +401,7 @@ describe("loadMoltbotPlugins", () => {
});
it("enforces memory slot selection", () => {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const memoryA = writePlugin({
id: "memory-a",
body: `export default { id: "memory-a", kind: "memory", register() {} };`,
@@ -411,7 +411,7 @@ describe("loadMoltbotPlugins", () => {
body: `export default { id: "memory-b", kind: "memory", register() {} };`,
});
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
config: {
plugins: {
@@ -428,13 +428,13 @@ describe("loadMoltbotPlugins", () => {
});
it("disables memory plugins when slot is none", () => {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const memory = writePlugin({
id: "memory-off",
body: `export default { id: "memory-off", kind: "memory", register() {} };`,
});
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
config: {
plugins: {
@@ -456,14 +456,14 @@ describe("loadMoltbotPlugins", () => {
dir: bundledDir,
filename: "shadow.js",
});
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir;
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir;
const override = writePlugin({
id: "shadow",
body: `export default { id: "shadow", register() {} };`,
});
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
cache: false,
config: {
plugins: {

View File

@@ -3,14 +3,13 @@ import path from "node:path";
import { fileURLToPath } from "node:url";
import { createJiti } from "jiti";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } 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 { discoverMoltbotPlugins } from "./discovery.js";
import { discoverOpenClawPlugins } from "./discovery.js";
import { loadPluginManifestRegistry } from "./manifest-registry.js";
import {
applyTestPluginDefaults,
normalizePluginsConfig,
resolveEnableState,
resolveMemorySlotDecision,
@@ -23,8 +22,8 @@ import { createPluginRuntime } from "./runtime/index.js";
import { setActivePluginRegistry } from "./runtime.js";
import { validateJsonSchemaValue } from "./schema-validator.js";
import type {
MoltbotPluginDefinition,
MoltbotPluginModule,
OpenClawPluginDefinition,
OpenClawPluginModule,
PluginDiagnostic,
PluginLogger,
} from "./types.js";
@@ -32,7 +31,7 @@ import type {
export type PluginLoadResult = PluginRegistry;
export type PluginLoadOptions = {
config?: MoltbotConfig;
config?: OpenClawConfig;
workspaceDir?: string;
logger?: PluginLogger;
coreGatewayHandlers?: Record<string, GatewayRequestHandler>;
@@ -99,8 +98,8 @@ function validatePluginConfig(params: {
}
function resolvePluginModuleExport(moduleExport: unknown): {
definition?: MoltbotPluginDefinition;
register?: MoltbotPluginDefinition["register"];
definition?: OpenClawPluginDefinition;
register?: OpenClawPluginDefinition["register"];
} {
const resolved =
moduleExport &&
@@ -110,11 +109,11 @@ function resolvePluginModuleExport(moduleExport: unknown): {
: moduleExport;
if (typeof resolved === "function") {
return {
register: resolved as MoltbotPluginDefinition["register"],
register: resolved as OpenClawPluginDefinition["register"],
};
}
if (resolved && typeof resolved === "object") {
const def = resolved as MoltbotPluginDefinition;
const def = resolved as OpenClawPluginDefinition;
const register = def.register ?? def.activate;
return { definition: def, register };
}
@@ -162,8 +161,8 @@ function pushDiagnostics(diagnostics: PluginDiagnostic[], append: PluginDiagnost
diagnostics.push(...append);
}
export function loadMoltbotPlugins(options: PluginLoadOptions = {}): PluginRegistry {
const cfg = applyTestPluginDefaults(options.config ?? {});
export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegistry {
const cfg = options.config ?? {};
const logger = options.logger ?? defaultLogger();
const validateOnly = options.mode === "validate";
const normalized = normalizePluginsConfig(cfg.plugins);
@@ -190,7 +189,7 @@ export function loadMoltbotPlugins(options: PluginLoadOptions = {}): PluginRegis
coreGatewayHandlers: options.coreGatewayHandlers as Record<string, GatewayRequestHandler>,
});
const discovery = discoverMoltbotPlugins({
const discovery = discoverOpenClawPlugins({
workspaceDir: options.workspaceDir,
extraPaths: normalized.loadPaths,
});
@@ -209,10 +208,7 @@ export function loadMoltbotPlugins(options: PluginLoadOptions = {}): PluginRegis
extensions: [".ts", ".tsx", ".mts", ".cts", ".mtsx", ".ctsx", ".js", ".mjs", ".cjs", ".json"],
...(pluginSdkAlias
? {
alias: {
"clawdbot/plugin-sdk": pluginSdkAlias,
"moltbot/plugin-sdk": pluginSdkAlias,
},
alias: { "openclaw/plugin-sdk": pluginSdkAlias },
}
: {}),
});
@@ -290,9 +286,9 @@ export function loadMoltbotPlugins(options: PluginLoadOptions = {}): PluginRegis
continue;
}
let mod: MoltbotPluginModule | null = null;
let mod: OpenClawPluginModule | null = null;
try {
mod = jiti(candidate.source) as MoltbotPluginModule;
mod = jiti(candidate.source) as OpenClawPluginModule;
} 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 { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { resolveUserPath } from "../utils.js";
import { normalizePluginsConfig, type NormalizedPluginsConfig } from "./config-state.js";
import { discoverMoltbotPlugins, type PluginCandidate } from "./discovery.js";
import { discoverOpenClawPlugins, type PluginCandidate } from "./discovery.js";
import { loadPluginManifest, type PluginManifest } from "./manifest.js";
import type { PluginConfigUiHint, PluginDiagnostic, PluginKind, PluginOrigin } from "./types.js";
@@ -36,7 +36,7 @@ const registryCache = new Map<string, { expiresAt: number; registry: PluginManif
const DEFAULT_MANIFEST_CACHE_MS = 200;
function resolveManifestCacheMs(env: NodeJS.ProcessEnv): number {
const raw = env.CLAWDBOT_PLUGIN_MANIFEST_CACHE_MS?.trim();
const raw = env.OPENCLAW_PLUGIN_MANIFEST_CACHE_MS?.trim();
if (raw === "" || raw === "0") return 0;
if (!raw) return DEFAULT_MANIFEST_CACHE_MS;
const parsed = Number.parseInt(raw, 10);
@@ -45,7 +45,7 @@ function resolveManifestCacheMs(env: NodeJS.ProcessEnv): number {
}
function shouldUseManifestCache(env: NodeJS.ProcessEnv): boolean {
const disabled = env.CLAWDBOT_DISABLE_PLUGIN_MANIFEST_CACHE?.trim();
const disabled = env.OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE?.trim();
if (disabled) return false;
return resolveManifestCacheMs(env) > 0;
}
@@ -100,7 +100,7 @@ function buildRecord(params: {
}
export function loadPluginManifestRegistry(params: {
config?: MoltbotConfig;
config?: OpenClawConfig;
workspaceDir?: string;
cache?: boolean;
env?: NodeJS.ProcessEnv;
@@ -122,7 +122,7 @@ export function loadPluginManifestRegistry(params: {
candidates: params.candidates,
diagnostics: params.diagnostics ?? [],
}
: discoverMoltbotPlugins({
: discoverOpenClawPlugins({
workspaceDir: params.workspaceDir,
extraPaths: normalized.loadPaths,
});

View File

@@ -1,14 +1,11 @@
import fs from "node:fs";
import path from "node:path";
import { LEGACY_MANIFEST_KEY, LEGACY_PLUGIN_MANIFEST_FILENAME } from "../compat/legacy-names.js";
import { MANIFEST_KEY } from "../compat/legacy-names.js";
import type { PluginConfigUiHint, PluginKind } from "./types.js";
export const PLUGIN_MANIFEST_FILENAME = "moltbot.plugin.json";
export const PLUGIN_MANIFEST_FILENAMES = [
PLUGIN_MANIFEST_FILENAME,
LEGACY_PLUGIN_MANIFEST_FILENAME,
] as const;
export const PLUGIN_MANIFEST_FILENAME = "openclaw.plugin.json";
export const PLUGIN_MANIFEST_FILENAMES = [PLUGIN_MANIFEST_FILENAME] as const;
export type PluginManifest = {
id: string;
@@ -102,7 +99,7 @@ export function loadPluginManifest(rootDir: string): PluginManifestLoadResult {
};
}
// package.json "moltbot" metadata (used for onboarding/catalog)
// package.json "openclaw" metadata (used for onboarding/catalog)
export type PluginPackageChannel = {
id?: string;
label?: string;
@@ -130,23 +127,23 @@ export type PluginPackageInstall = {
defaultChoice?: "npm" | "local";
};
export type MoltbotPackageManifest = {
export type OpenClawPackageManifest = {
extensions?: string[];
channel?: PluginPackageChannel;
install?: PluginPackageInstall;
};
export type ManifestKey = typeof MANIFEST_KEY;
export type PackageManifest = {
name?: string;
version?: string;
description?: string;
moltbot?: MoltbotPackageManifest;
[LEGACY_MANIFEST_KEY]?: MoltbotPackageManifest;
};
} & Partial<Record<ManifestKey, OpenClawPackageManifest>>;
export function getPackageManifestMetadata(
manifest: PackageManifest | undefined,
): MoltbotPackageManifest | undefined {
): OpenClawPackageManifest | undefined {
if (!manifest) return undefined;
return manifest.moltbot ?? manifest[LEGACY_MANIFEST_KEY];
return manifest[MANIFEST_KEY];
}

View File

@@ -1,5 +1,5 @@
import { createSubsystemLogger } from "../logging/subsystem.js";
import { loadMoltbotPlugins, type PluginLoadOptions } from "./loader.js";
import { loadOpenClawPlugins, 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 = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
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 {
MoltbotPluginApi,
MoltbotPluginChannelRegistration,
MoltbotPluginCliRegistrar,
MoltbotPluginCommandDefinition,
MoltbotPluginHttpHandler,
MoltbotPluginHttpRouteHandler,
MoltbotPluginHookOptions,
OpenClawPluginApi,
OpenClawPluginChannelRegistration,
OpenClawPluginCliRegistrar,
OpenClawPluginCommandDefinition,
OpenClawPluginHttpHandler,
OpenClawPluginHttpRouteHandler,
OpenClawPluginHookOptions,
ProviderPlugin,
MoltbotPluginService,
MoltbotPluginToolContext,
MoltbotPluginToolFactory,
OpenClawPluginService,
OpenClawPluginToolContext,
OpenClawPluginToolFactory,
PluginConfigUiHint,
PluginDiagnostic,
PluginLogger,
@@ -36,7 +36,7 @@ import { normalizePluginHttpPath } from "./http-path.js";
export type PluginToolRegistration = {
pluginId: string;
factory: MoltbotPluginToolFactory;
factory: OpenClawPluginToolFactory;
names: string[];
optional: boolean;
source: string;
@@ -44,21 +44,21 @@ export type PluginToolRegistration = {
export type PluginCliRegistration = {
pluginId: string;
register: MoltbotPluginCliRegistrar;
register: OpenClawPluginCliRegistrar;
commands: string[];
source: string;
};
export type PluginHttpRegistration = {
pluginId: string;
handler: MoltbotPluginHttpHandler;
handler: OpenClawPluginHttpHandler;
source: string;
};
export type PluginHttpRouteRegistration = {
pluginId?: string;
path: string;
handler: MoltbotPluginHttpRouteHandler;
handler: OpenClawPluginHttpRouteHandler;
source?: string;
};
@@ -84,13 +84,13 @@ export type PluginHookRegistration = {
export type PluginServiceRegistration = {
pluginId: string;
service: MoltbotPluginService;
service: OpenClawPluginService;
source: string;
};
export type PluginCommandRegistration = {
pluginId: string;
command: MoltbotPluginCommandDefinition;
command: OpenClawPluginCommandDefinition;
source: string;
};
@@ -167,13 +167,13 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
const registerTool = (
record: PluginRecord,
tool: AnyAgentTool | MoltbotPluginToolFactory,
tool: AnyAgentTool | OpenClawPluginToolFactory,
opts?: { name?: string; names?: string[]; optional?: boolean },
) => {
const names = opts?.names ?? (opts?.name ? [opts.name] : []);
const optional = opts?.optional === true;
const factory: MoltbotPluginToolFactory =
typeof tool === "function" ? tool : (_ctx: MoltbotPluginToolContext) => tool;
const factory: OpenClawPluginToolFactory =
typeof tool === "function" ? tool : (_ctx: OpenClawPluginToolContext) => 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: MoltbotPluginHookOptions | undefined,
config: MoltbotPluginApi["config"],
opts: OpenClawPluginHookOptions | undefined,
config: OpenClawPluginApi["config"],
) => {
const eventList = Array.isArray(events) ? events : [events];
const normalizedEvents = eventList.map((event) => event.trim()).filter(Boolean);
@@ -221,7 +221,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
...entry.hook,
name,
description,
source: "moltbot-plugin",
source: "openclaw-plugin",
pluginId: record.id,
},
metadata: {
@@ -233,7 +233,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
hook: {
name,
description,
source: "moltbot-plugin",
source: "openclaw-plugin",
pluginId: record.id,
filePath: record.source,
baseDir: path.dirname(record.source),
@@ -282,7 +282,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
record.gatewayMethods.push(trimmed);
};
const registerHttpHandler = (record: PluginRecord, handler: MoltbotPluginHttpHandler) => {
const registerHttpHandler = (record: PluginRecord, handler: OpenClawPluginHttpHandler) => {
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: MoltbotPluginHttpRouteHandler },
params: { path: string; handler: OpenClawPluginHttpRouteHandler },
) => {
const normalizedPath = normalizePluginHttpPath(params.path);
if (!normalizedPath) {
@@ -325,11 +325,11 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
const registerChannel = (
record: PluginRecord,
registration: MoltbotPluginChannelRegistration | ChannelPlugin,
registration: OpenClawPluginChannelRegistration | ChannelPlugin,
) => {
const normalized =
typeof (registration as MoltbotPluginChannelRegistration).plugin === "object"
? (registration as MoltbotPluginChannelRegistration)
typeof (registration as OpenClawPluginChannelRegistration).plugin === "object"
? (registration as OpenClawPluginChannelRegistration)
: { 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: MoltbotPluginCliRegistrar,
registrar: OpenClawPluginCliRegistrar,
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: MoltbotPluginService) => {
const registerService = (record: PluginRecord, service: OpenClawPluginService) => {
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: MoltbotPluginCommandDefinition) => {
const registerCommand = (record: PluginRecord, command: OpenClawPluginCommandDefinition) => {
const name = command.name.trim();
if (!name) {
pushDiagnostic({
@@ -464,10 +464,10 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
const createApi = (
record: PluginRecord,
params: {
config: MoltbotPluginApi["config"];
config: OpenClawPluginApi["config"];
pluginConfig?: Record<string, unknown>;
},
): MoltbotPluginApi => {
): OpenClawPluginApi => {
return {
id: record.id,
name: record.name,

View File

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

View File

@@ -1,4 +1,4 @@
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } 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: MoltbotConfig;
config: OpenClawConfig;
workspaceDir?: string;
}): Promise<PluginServicesHandle> {
const running: Array<{

View File

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

View File

@@ -1,4 +1,4 @@
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } 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: MoltbotConfig;
config: OpenClawConfig;
warnings: string[];
changed: boolean;
};
export function applyExclusiveSlotSelection(params: {
config: MoltbotConfig;
config: OpenClawConfig;
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 { loadMoltbotPlugins } from "./loader.js";
import { loadOpenClawPlugins } 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 = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
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(), `moltbot-plugin-tools-${randomUUID()}`);
const dir = path.join(os.tmpdir(), `openclaw-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, "moltbot.plugin.json"),
path.join(dir, "openclaw.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 { loadMoltbotPlugins } from "./loader.js";
import type { MoltbotPluginToolContext } from "./types.js";
import { loadOpenClawPlugins } from "./loader.js";
import type { OpenClawPluginToolContext } from "./types.js";
const log = createSubsystemLogger("plugins");
@@ -35,11 +35,11 @@ function isOptionalToolAllowed(params: {
}
export function resolvePluginTools(params: {
context: MoltbotPluginToolContext;
context: OpenClawPluginToolContext;
existingToolNames?: Set<string>;
toolAllowlist?: string[];
}): AnyAgentTool[] {
const registry = loadMoltbotPlugins({
const registry = loadOpenClawPlugins({
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 { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } 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 MoltbotPluginConfigSchema = {
export type OpenClawPluginConfigSchema = {
safeParse?: (value: unknown) => {
success: boolean;
data?: unknown;
@@ -55,8 +55,8 @@ export type MoltbotPluginConfigSchema = {
jsonSchema?: Record<string, unknown>;
};
export type MoltbotPluginToolContext = {
config?: MoltbotConfig;
export type OpenClawPluginToolContext = {
config?: OpenClawConfig;
workspaceDir?: string;
agentDir?: string;
agentId?: string;
@@ -66,17 +66,17 @@ export type MoltbotPluginToolContext = {
sandboxed?: boolean;
};
export type MoltbotPluginToolFactory = (
ctx: MoltbotPluginToolContext,
export type OpenClawPluginToolFactory = (
ctx: OpenClawPluginToolContext,
) => AnyAgentTool | AnyAgentTool[] | null | undefined;
export type MoltbotPluginToolOptions = {
export type OpenClawPluginToolOptions = {
name?: string;
names?: string[];
optional?: boolean;
};
export type MoltbotPluginHookOptions = {
export type OpenClawPluginHookOptions = {
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<MoltbotConfig>;
configPatch?: Partial<OpenClawConfig>;
defaultModel?: string;
notes?: string[];
};
export type ProviderAuthContext = {
config: MoltbotConfig;
config: OpenClawConfig;
agentDir?: string;
workspaceDir?: string;
prompter: WizardPrompter;
@@ -125,7 +125,7 @@ export type ProviderPlugin = {
refreshOAuth?: (cred: OAuthCredential) => Promise<OAuthCredential>;
};
export type MoltbotPluginGatewayMethod = {
export type OpenClawPluginGatewayMethod = {
method: string;
handler: GatewayRequestHandler;
};
@@ -148,8 +148,8 @@ export type PluginCommandContext = {
args?: string;
/** The full normalized command body */
commandBody: string;
/** Current moltbot configuration */
config: MoltbotConfig;
/** Current OpenClaw configuration */
config: OpenClawConfig;
};
/**
@@ -167,7 +167,7 @@ export type PluginCommandHandler = (
/**
* Definition for a plugin-registered command.
*/
export type MoltbotPluginCommandDefinition = {
export type OpenClawPluginCommandDefinition = {
/** Command name without leading slash (e.g., "tts") */
name: string;
/** Description shown in /help and command menus */
@@ -180,90 +180,90 @@ export type MoltbotPluginCommandDefinition = {
handler: PluginCommandHandler;
};
export type MoltbotPluginHttpHandler = (
export type OpenClawPluginHttpHandler = (
req: IncomingMessage,
res: ServerResponse,
) => Promise<boolean> | boolean;
export type MoltbotPluginHttpRouteHandler = (
export type OpenClawPluginHttpRouteHandler = (
req: IncomingMessage,
res: ServerResponse,
) => Promise<void> | void;
export type MoltbotPluginCliContext = {
export type OpenClawPluginCliContext = {
program: Command;
config: MoltbotConfig;
config: OpenClawConfig;
workspaceDir?: string;
logger: PluginLogger;
};
export type MoltbotPluginCliRegistrar = (ctx: MoltbotPluginCliContext) => void | Promise<void>;
export type OpenClawPluginCliRegistrar = (ctx: OpenClawPluginCliContext) => void | Promise<void>;
export type MoltbotPluginServiceContext = {
config: MoltbotConfig;
export type OpenClawPluginServiceContext = {
config: OpenClawConfig;
workspaceDir?: string;
stateDir: string;
logger: PluginLogger;
};
export type MoltbotPluginService = {
export type OpenClawPluginService = {
id: string;
start: (ctx: MoltbotPluginServiceContext) => void | Promise<void>;
stop?: (ctx: MoltbotPluginServiceContext) => void | Promise<void>;
start: (ctx: OpenClawPluginServiceContext) => void | Promise<void>;
stop?: (ctx: OpenClawPluginServiceContext) => void | Promise<void>;
};
export type MoltbotPluginChannelRegistration = {
export type OpenClawPluginChannelRegistration = {
plugin: ChannelPlugin;
dock?: ChannelDock;
};
export type MoltbotPluginDefinition = {
export type OpenClawPluginDefinition = {
id?: string;
name?: string;
description?: string;
version?: string;
kind?: PluginKind;
configSchema?: MoltbotPluginConfigSchema;
register?: (api: MoltbotPluginApi) => void | Promise<void>;
activate?: (api: MoltbotPluginApi) => void | Promise<void>;
configSchema?: OpenClawPluginConfigSchema;
register?: (api: OpenClawPluginApi) => void | Promise<void>;
activate?: (api: OpenClawPluginApi) => void | Promise<void>;
};
export type MoltbotPluginModule =
| MoltbotPluginDefinition
| ((api: MoltbotPluginApi) => void | Promise<void>);
export type OpenClawPluginModule =
| OpenClawPluginDefinition
| ((api: OpenClawPluginApi) => void | Promise<void>);
export type MoltbotPluginApi = {
export type OpenClawPluginApi = {
id: string;
name: string;
version?: string;
description?: string;
source: string;
config: MoltbotConfig;
config: OpenClawConfig;
pluginConfig?: Record<string, unknown>;
runtime: PluginRuntime;
logger: PluginLogger;
registerTool: (
tool: AnyAgentTool | MoltbotPluginToolFactory,
opts?: MoltbotPluginToolOptions,
tool: AnyAgentTool | OpenClawPluginToolFactory,
opts?: OpenClawPluginToolOptions,
) => void;
registerHook: (
events: string | string[],
handler: InternalHookHandler,
opts?: MoltbotPluginHookOptions,
opts?: OpenClawPluginHookOptions,
) => void;
registerHttpHandler: (handler: MoltbotPluginHttpHandler) => void;
registerHttpRoute: (params: { path: string; handler: MoltbotPluginHttpRouteHandler }) => void;
registerChannel: (registration: MoltbotPluginChannelRegistration | ChannelPlugin) => void;
registerHttpHandler: (handler: OpenClawPluginHttpHandler) => void;
registerHttpRoute: (params: { path: string; handler: OpenClawPluginHttpRouteHandler }) => void;
registerChannel: (registration: OpenClawPluginChannelRegistration | ChannelPlugin) => void;
registerGatewayMethod: (method: string, handler: GatewayRequestHandler) => void;
registerCli: (registrar: MoltbotPluginCliRegistrar, opts?: { commands?: string[] }) => void;
registerService: (service: MoltbotPluginService) => void;
registerCli: (registrar: OpenClawPluginCliRegistrar, opts?: { commands?: string[] }) => void;
registerService: (service: OpenClawPluginService) => 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: MoltbotPluginCommandDefinition) => void;
registerCommand: (command: OpenClawPluginCommandDefinition) => 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 { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import type { UpdateChannel } from "../infra/update-channels.js";
import { resolveUserPath } from "../utils.js";
import { discoverMoltbotPlugins } from "./discovery.js";
import { discoverOpenClawPlugins } 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: MoltbotConfig;
config: OpenClawConfig;
changed: boolean;
outcomes: PluginUpdateOutcome[];
};
@@ -38,7 +38,7 @@ export type PluginChannelSyncSummary = {
};
export type PluginChannelSyncResult = {
config: MoltbotConfig;
config: OpenClawConfig;
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 = discoverMoltbotPlugins({ workspaceDir: params.workspaceDir });
const discovery = discoverOpenClawPlugins({ 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.packageMoltbot?.install?.npmSpec?.trim() ||
candidate.packageManifest?.install?.npmSpec?.trim() ||
candidate.packageName?.trim() ||
undefined;
@@ -127,7 +127,7 @@ function buildLoadPathHelpers(existing: string[]) {
}
export async function updateNpmInstalledPlugins(params: {
config: MoltbotConfig;
config: OpenClawConfig;
logger?: PluginUpdateLogger;
pluginIds?: string[];
skipIds?: Set<string>;
@@ -290,7 +290,7 @@ export async function updateNpmInstalledPlugins(params: {
}
export async function syncPluginsForUpdateChannel(params: {
config: MoltbotConfig;
config: OpenClawConfig;
channel: UpdateChannel;
workspaceDir?: string;
logger?: PluginUpdateLogger;