File size: 4,395 Bytes
fc93158 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | #!/usr/bin/env node
/**
* Verifies that critical plugin-sdk exports are present in the compiled dist output.
* Regression guard for #27569 where isDangerousNameMatchingEnabled was missing
* from the compiled output, breaking channel extension plugins at runtime.
*
* Run after `pnpm build` to catch missing exports before release.
*/
import { readFileSync, existsSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const distFile = resolve(__dirname, "..", "dist", "plugin-sdk", "index.js");
if (!existsSync(distFile)) {
console.error("ERROR: dist/plugin-sdk/index.js not found. Run `pnpm build` first.");
process.exit(1);
}
const content = readFileSync(distFile, "utf-8");
// Extract the final export statement from the compiled output.
// tsdown/rolldown emits a single `export { ... }` at the end of the file.
const exportMatch = content.match(/export\s*\{([^}]+)\}\s*;?\s*$/);
if (!exportMatch) {
console.error("ERROR: Could not find export statement in dist/plugin-sdk/index.js");
process.exit(1);
}
const exportedNames = exportMatch[1]
.split(",")
.map((s) => {
// Handle `foo as bar` aliases — the exported name is the `bar` part
const parts = s.trim().split(/\s+as\s+/);
return (parts[parts.length - 1] || "").trim();
})
.filter(Boolean);
const exportSet = new Set(exportedNames);
const requiredSubpathEntries = [
"core",
"compat",
"telegram",
"discord",
"slack",
"signal",
"imessage",
"whatsapp",
"line",
"msteams",
"acpx",
"bluebubbles",
"copilot-proxy",
"device-pair",
"diagnostics-otel",
"diffs",
"feishu",
"google-gemini-cli-auth",
"googlechat",
"irc",
"llm-task",
"lobster",
"matrix",
"mattermost",
"memory-core",
"memory-lancedb",
"minimax-portal-auth",
"nextcloud-talk",
"nostr",
"open-prose",
"phone-control",
"qwen-portal-auth",
"synology-chat",
"talk-voice",
"test-utils",
"thread-ownership",
"tlon",
"twitch",
"voice-call",
"zalo",
"zalouser",
"account-id",
"keyed-async-queue",
];
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
const requiredExports = [
"isDangerousNameMatchingEnabled",
"createAccountListHelpers",
"buildAgentMediaPayload",
"createReplyPrefixOptions",
"createTypingCallbacks",
"logInboundDrop",
"logTypingFailure",
"buildPendingHistoryContextFromMap",
"clearHistoryEntriesIfEnabled",
"recordPendingHistoryEntryIfEnabled",
"resolveControlCommandGate",
"resolveDmGroupAccessWithLists",
"resolveAllowlistProviderRuntimeGroupPolicy",
"resolveDefaultGroupPolicy",
"resolveChannelMediaMaxBytes",
"warnMissingProviderGroupPolicyFallbackOnce",
"emptyPluginConfigSchema",
"normalizePluginHttpPath",
"registerPluginHttpRoute",
"DEFAULT_ACCOUNT_ID",
"DEFAULT_GROUP_HISTORY_LIMIT",
];
let missing = 0;
for (const name of requiredExports) {
if (!exportSet.has(name)) {
console.error(`MISSING EXPORT: ${name}`);
missing += 1;
}
}
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;
}
}
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).`,
);
console.error("This will break channel extension plugins at runtime.");
console.error("Check src/plugin-sdk/index.ts, subpath entries, and rebuild.");
process.exit(1);
}
console.log(`OK: All ${requiredExports.length} required plugin-sdk exports verified.`);
|