fix: openclaw module loading (#993)
Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Haze <hazeone@users.noreply.github.com>
This commit is contained in:
127
scripts/openclaw-self-import-patch.mjs
Normal file
127
scripts/openclaw-self-import-patch.mjs
Normal file
@@ -0,0 +1,127 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
export const OPENCLAW_PLUGIN_SDK_PREFIX = 'openclaw/plugin-sdk/';
|
||||
|
||||
const OPENCLAW_PLUGIN_SDK_SPECIFIER_RE = /(["'])openclaw\/plugin-sdk\/([^"'\r\n]+)\1/g;
|
||||
|
||||
function assertSafePluginSdkSubpath(subpath) {
|
||||
if (!subpath || subpath.startsWith('/') || subpath.startsWith('\\')) {
|
||||
throw new Error(`Invalid OpenClaw plugin-sdk import subpath: ${JSON.stringify(subpath)}`);
|
||||
}
|
||||
|
||||
const parts = subpath.split(/[\\/]+/);
|
||||
if (parts.some((part) => !part || part === '.' || part === '..')) {
|
||||
throw new Error(`Invalid OpenClaw plugin-sdk import subpath: ${JSON.stringify(subpath)}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function toImportSpecifier(relativePath) {
|
||||
const normalized = relativePath.split(path.sep).join('/');
|
||||
if (normalized.startsWith('./') || normalized.startsWith('../')) {
|
||||
return normalized;
|
||||
}
|
||||
return `./${normalized}`;
|
||||
}
|
||||
|
||||
export function resolvePluginSdkTarget(distDir, subpath) {
|
||||
assertSafePluginSdkSubpath(subpath);
|
||||
|
||||
const targetSubpath = subpath.endsWith('.js') ? subpath : `${subpath}.js`;
|
||||
return path.join(distDir, 'plugin-sdk', ...targetSubpath.split(/[\\/]+/));
|
||||
}
|
||||
|
||||
export function rewriteOpenClawPluginSdkSpecifiers(content, options) {
|
||||
const { filePath, distDir } = options;
|
||||
let replacements = 0;
|
||||
|
||||
const nextContent = content.replace(
|
||||
OPENCLAW_PLUGIN_SDK_SPECIFIER_RE,
|
||||
(match, quote, subpath) => {
|
||||
const target = resolvePluginSdkTarget(distDir, subpath);
|
||||
if (!fs.existsSync(target)) {
|
||||
throw new Error(
|
||||
`Cannot rewrite ${match} in ${filePath}: missing bundled SDK target ${target}`,
|
||||
);
|
||||
}
|
||||
|
||||
replacements++;
|
||||
const relativePath = path.relative(path.dirname(filePath), target);
|
||||
return `${quote}${toImportSpecifier(relativePath)}${quote}`;
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
content: nextContent,
|
||||
replacements,
|
||||
};
|
||||
}
|
||||
|
||||
function listJavaScriptFiles(rootDir) {
|
||||
const files = [];
|
||||
const stack = [rootDir];
|
||||
|
||||
while (stack.length > 0) {
|
||||
const current = stack.pop();
|
||||
let entries;
|
||||
try {
|
||||
entries = fs.readdirSync(current, { withFileTypes: true });
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(current, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
stack.push(fullPath);
|
||||
continue;
|
||||
}
|
||||
if (entry.isFile() && entry.name.endsWith('.js')) {
|
||||
files.push(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
export function patchExtensionOpenClawSelfImports(outputDir) {
|
||||
const distDir = path.join(outputDir, 'dist');
|
||||
const extensionsDir = path.join(distDir, 'extensions');
|
||||
if (!fs.existsSync(extensionsDir)) {
|
||||
return {
|
||||
filesScanned: 0,
|
||||
filesPatched: 0,
|
||||
specifiersPatched: 0,
|
||||
};
|
||||
}
|
||||
|
||||
let filesScanned = 0;
|
||||
let filesPatched = 0;
|
||||
let specifiersPatched = 0;
|
||||
|
||||
for (const filePath of listJavaScriptFiles(extensionsDir)) {
|
||||
filesScanned++;
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
if (!content.includes(OPENCLAW_PLUGIN_SDK_PREFIX)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const result = rewriteOpenClawPluginSdkSpecifiers(content, {
|
||||
filePath,
|
||||
distDir,
|
||||
});
|
||||
|
||||
if (result.replacements > 0 && result.content !== content) {
|
||||
fs.writeFileSync(filePath, result.content, 'utf8');
|
||||
filesPatched++;
|
||||
specifiersPatched += result.replacements;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
filesScanned,
|
||||
filesPatched,
|
||||
specifiersPatched,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user