plugin-sdk: add channel subpaths and migrate bundled plugins

This commit is contained in:
Gustavo Madeira Santana
2026-03-03 22:07:03 -05:00
parent 1c200ca7ae
commit 1278ee9248
75 changed files with 808 additions and 174 deletions

View File

@@ -0,0 +1,50 @@
import fs from "node:fs";
import path from "node:path";
import { discoverOpenClawPlugins } from "../src/plugins/discovery.js";
const ROOT_IMPORT_PATTERNS = [
/\b(?:import|export)\b[\s\S]*?\bfrom\s+["']openclaw\/plugin-sdk["']/,
/\bimport\s+["']openclaw\/plugin-sdk["']/,
/\bimport\s*\(\s*["']openclaw\/plugin-sdk["']\s*\)/,
/\brequire\s*\(\s*["']openclaw\/plugin-sdk["']\s*\)/,
];
function hasMonolithicRootImport(content: string): boolean {
return ROOT_IMPORT_PATTERNS.some((pattern) => pattern.test(content));
}
function main() {
const discovery = discoverOpenClawPlugins({});
const bundledEntryFiles = [
...new Set(discovery.candidates.filter((c) => c.origin === "bundled").map((c) => c.source)),
];
const offenders: string[] = [];
for (const entryFile of bundledEntryFiles) {
let content = "";
try {
content = fs.readFileSync(entryFile, "utf8");
} catch {
continue;
}
if (hasMonolithicRootImport(content)) {
offenders.push(entryFile);
}
}
if (offenders.length > 0) {
console.error("Bundled plugin entrypoints must not import monolithic openclaw/plugin-sdk.");
for (const file of offenders.toSorted()) {
const relative = path.relative(process.cwd(), file) || file;
console.error(`- ${relative}`);
}
console.error("Use openclaw/plugin-sdk/<channel> for channel plugins or /core for others.");
process.exit(1);
}
console.log(
`OK: bundled entrypoints use scoped plugin-sdk subpaths (${bundledEntryFiles.length} checked).`,
);
}
main();

View File

@@ -41,6 +41,18 @@ const exportedNames = exportMatch[1]
const exportSet = new Set(exportedNames);
const requiredSubpathEntries = [
"core",
"telegram",
"discord",
"slack",
"signal",
"imessage",
"whatsapp",
"line",
"account-id",
];
// Critical functions that channel extension plugins import from openclaw/plugin-sdk.
// If any of these are missing, plugins will fail at runtime with:
// TypeError: (0 , _pluginSdk.<name>) is not a function
@@ -76,10 +88,25 @@ for (const name of requiredExports) {
}
}
for (const entry of requiredSubpathEntries) {
const jsPath = resolve(__dirname, "..", "dist", "plugin-sdk", `${entry}.js`);
const dtsPath = resolve(__dirname, "..", "dist", "plugin-sdk", `${entry}.d.ts`);
if (!existsSync(jsPath)) {
console.error(`MISSING SUBPATH JS: dist/plugin-sdk/${entry}.js`);
missing += 1;
}
if (!existsSync(dtsPath)) {
console.error(`MISSING SUBPATH DTS: dist/plugin-sdk/${entry}.d.ts`);
missing += 1;
}
}
if (missing > 0) {
console.error(`\nERROR: ${missing} required export(s) missing from dist/plugin-sdk/index.js.`);
console.error(
`\nERROR: ${missing} required plugin-sdk artifact(s) missing (named exports or subpath files).`,
);
console.error("This will break channel extension plugins at runtime.");
console.error("Check src/plugin-sdk/index.ts and rebuild.");
console.error("Check src/plugin-sdk/index.ts, subpath entries, and rebuild.");
process.exit(1);
}

View File

@@ -14,6 +14,22 @@ const requiredPathGroups = [
["dist/entry.js", "dist/entry.mjs"],
"dist/plugin-sdk/index.js",
"dist/plugin-sdk/index.d.ts",
"dist/plugin-sdk/core.js",
"dist/plugin-sdk/core.d.ts",
"dist/plugin-sdk/telegram.js",
"dist/plugin-sdk/telegram.d.ts",
"dist/plugin-sdk/discord.js",
"dist/plugin-sdk/discord.d.ts",
"dist/plugin-sdk/slack.js",
"dist/plugin-sdk/slack.d.ts",
"dist/plugin-sdk/signal.js",
"dist/plugin-sdk/signal.d.ts",
"dist/plugin-sdk/imessage.js",
"dist/plugin-sdk/imessage.d.ts",
"dist/plugin-sdk/whatsapp.js",
"dist/plugin-sdk/whatsapp.d.ts",
"dist/plugin-sdk/line.js",
"dist/plugin-sdk/line.d.ts",
"dist/build-info.json",
];
const forbiddenPrefixes = ["dist/OpenClaw.app/"];

View File

@@ -6,7 +6,18 @@ import path from "node:path";
//
// Our package export map points subpath `types` at `dist/plugin-sdk/<entry>.d.ts`, so we
// generate stable entry d.ts files that re-export the real declarations.
const entrypoints = ["index", "core", "telegram", "account-id"] as const;
const entrypoints = [
"index",
"core",
"telegram",
"discord",
"slack",
"signal",
"imessage",
"whatsapp",
"line",
"account-id",
] as const;
for (const entry of entrypoints) {
const out = path.join(process.cwd(), `dist/plugin-sdk/${entry}.d.ts`);
fs.mkdirSync(path.dirname(out), { recursive: true });