Plugins: add root-alias shim and cache/docs updates

This commit is contained in:
Gustavo Madeira Santana
2026-03-04 01:19:17 -05:00
parent 646817dd80
commit 802b9f6b19
21 changed files with 576 additions and 21 deletions

View File

@@ -13,14 +13,68 @@ function hasMonolithicRootImport(content: string): boolean {
return ROOT_IMPORT_PATTERNS.some((pattern) => pattern.test(content));
}
function isSourceFile(filePath: string): boolean {
if (filePath.endsWith(".d.ts")) {
return false;
}
return /\.(?:[cm]?ts|[cm]?js|tsx|jsx)$/u.test(filePath);
}
function collectPluginSourceFiles(rootDir: string): string[] {
const srcDir = path.join(rootDir, "src");
if (!fs.existsSync(srcDir)) {
return [];
}
const files: string[] = [];
const stack: string[] = [srcDir];
while (stack.length > 0) {
const current = stack.pop();
if (!current) {
continue;
}
let entries: fs.Dirent[] = [];
try {
entries = fs.readdirSync(current, { withFileTypes: true });
} catch {
continue;
}
for (const entry of entries) {
const fullPath = path.join(current, entry.name);
if (entry.isDirectory()) {
if (
entry.name === "node_modules" ||
entry.name === "dist" ||
entry.name === ".git" ||
entry.name === "coverage"
) {
continue;
}
stack.push(fullPath);
continue;
}
if (entry.isFile() && isSourceFile(fullPath)) {
files.push(fullPath);
}
}
}
return files;
}
function main() {
const discovery = discoverOpenClawPlugins({});
const bundledEntryFiles = [
...new Set(discovery.candidates.filter((c) => c.origin === "bundled").map((c) => c.source)),
];
const bundledCandidates = discovery.candidates.filter((c) => c.origin === "bundled");
const filesToCheck = new Set<string>();
for (const candidate of bundledCandidates) {
filesToCheck.add(candidate.source);
for (const srcFile of collectPluginSourceFiles(candidate.rootDir)) {
filesToCheck.add(srcFile);
}
}
const offenders: string[] = [];
for (const entryFile of bundledEntryFiles) {
for (const entryFile of filesToCheck) {
let content = "";
try {
content = fs.readFileSync(entryFile, "utf8");
@@ -33,17 +87,19 @@ function main() {
}
if (offenders.length > 0) {
console.error("Bundled plugin entrypoints must not import monolithic openclaw/plugin-sdk.");
console.error("Bundled plugin source files 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.");
console.error(
"Use openclaw/plugin-sdk/<channel> for channel plugins, /core for startup surfaces, or /compat for broader internals.",
);
process.exit(1);
}
console.log(
`OK: bundled entrypoints use scoped plugin-sdk subpaths (${bundledEntryFiles.length} checked).`,
`OK: bundled plugin source files use scoped plugin-sdk subpaths (${filesToCheck.size} checked).`,
);
}

View File

@@ -43,6 +43,7 @@ const exportSet = new Set(exportedNames);
const requiredSubpathEntries = [
"core",
"compat",
"telegram",
"discord",
"slack",
@@ -53,6 +54,8 @@ const requiredSubpathEntries = [
"account-id",
];
const requiredRuntimeShimEntries = ["root-alias.cjs"];
// 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
@@ -101,6 +104,14 @@ for (const entry of requiredSubpathEntries) {
}
}
for (const entry of requiredRuntimeShimEntries) {
const shimPath = resolve(__dirname, "..", "dist", "plugin-sdk", entry);
if (!existsSync(shimPath)) {
console.error(`MISSING RUNTIME SHIM: dist/plugin-sdk/${entry}`);
missing += 1;
}
}
if (missing > 0) {
console.error(
`\nERROR: ${missing} required plugin-sdk artifact(s) missing (named exports or subpath files).`,

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env node
import { copyFileSync, mkdirSync } from "node:fs";
import { dirname, resolve } from "node:path";
const source = resolve("src/plugin-sdk/root-alias.cjs");
const target = resolve("dist/plugin-sdk/root-alias.cjs");
mkdirSync(dirname(target), { recursive: true });
copyFileSync(source, target);

View File

@@ -16,6 +16,9 @@ const requiredPathGroups = [
"dist/plugin-sdk/index.d.ts",
"dist/plugin-sdk/core.js",
"dist/plugin-sdk/core.d.ts",
"dist/plugin-sdk/root-alias.cjs",
"dist/plugin-sdk/compat.js",
"dist/plugin-sdk/compat.d.ts",
"dist/plugin-sdk/telegram.js",
"dist/plugin-sdk/telegram.d.ts",
"dist/plugin-sdk/discord.js",

View File

@@ -9,6 +9,7 @@ import path from "node:path";
const entrypoints = [
"index",
"core",
"compat",
"telegram",
"discord",
"slack",