mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
fix(packaging): recognize owner-restricted plugin aliases
This commit is contained in:
@@ -33,7 +33,7 @@ export type PluginNpmRuntimeBuildPlan = {
|
||||
};
|
||||
/** Resolve the package-local runtime build plan for one publishable plugin package. */
|
||||
export function resolvePluginNpmRuntimeBuildPlan(params: unknown): PluginNpmRuntimeBuildPlan | null;
|
||||
/** List built host SDK imports that are absent from the OpenClaw package exports. */
|
||||
/** List built host SDK imports unavailable through package exports or owner-restricted aliases. */
|
||||
export function listMissingPluginNpmRuntimeHostExports(plan: PluginNpmRuntimeBuildPlan): string[];
|
||||
/** Build package-local runtime files and static assets for one plugin package. */
|
||||
export function buildPluginNpmRuntime(params: unknown): Promise<
|
||||
|
||||
@@ -93,6 +93,10 @@ function createNeverBundleDependencyMatcher(packageJson) {
|
||||
|
||||
const HOST_PLUGIN_SDK_IMPORT_RE =
|
||||
/(?:\bfrom\s+|\bimport\s*(?:\(\s*)?|\b(?:require|_+require\d*)\(\s*)["'](openclaw\/plugin-sdk\/[^"']+)["']/gu;
|
||||
const OWNER_RESTRICTED_HOST_IMPORTS_BY_PACKAGE_NAME = new Map([
|
||||
["@openclaw/codex", new Set(["openclaw/plugin-sdk/agent-harness-tool-authority-runtime"])],
|
||||
["@openclaw/copilot", new Set(["openclaw/plugin-sdk/agent-harness-tool-authority-runtime"])],
|
||||
]);
|
||||
|
||||
function listRuntimeJavaScriptFiles(rootDir) {
|
||||
if (!fs.existsSync(rootDir)) {
|
||||
@@ -111,8 +115,8 @@ function listRuntimeJavaScriptFiles(rootDir) {
|
||||
}
|
||||
|
||||
/**
|
||||
* List host SDK imports emitted by a built plugin runtime but absent from package exports.
|
||||
* @param {{ repoRoot: string; outDir: string }} plan
|
||||
* List host SDK imports emitted by a built plugin runtime but unavailable to its package owner.
|
||||
* @param {{ repoRoot: string; outDir: string; packageJson?: { name?: unknown } }} plan
|
||||
*/
|
||||
export function listMissingPluginNpmRuntimeHostExports(plan) {
|
||||
const hostImports = new Set();
|
||||
@@ -131,8 +135,16 @@ export function listMissingPluginNpmRuntimeHostExports(plan) {
|
||||
|
||||
const hostPackageJson = readJsonFile(path.join(plan.repoRoot, "package.json"));
|
||||
const hostExports = new Set(Object.keys(hostPackageJson.exports ?? {}));
|
||||
const packageName =
|
||||
typeof plan.packageJson?.name === "string" ? plan.packageJson.name.trim() : "";
|
||||
const ownerRestrictedHostImports =
|
||||
OWNER_RESTRICTED_HOST_IMPORTS_BY_PACKAGE_NAME.get(packageName) ?? new Set();
|
||||
return [...hostImports]
|
||||
.filter((specifier) => !hostExports.has(specifier.replace(/^openclaw/u, ".")))
|
||||
.filter(
|
||||
(specifier) =>
|
||||
!hostExports.has(specifier.replace(/^openclaw/u, ".")) &&
|
||||
!ownerRestrictedHostImports.has(specifier),
|
||||
)
|
||||
.toSorted((left, right) => left.localeCompare(right));
|
||||
}
|
||||
|
||||
|
||||
@@ -240,16 +240,19 @@ describe("plugin npm runtime build planning", () => {
|
||||
expect(plan.runtimeBuildOutputs).toContain("./dist/setup-api.js");
|
||||
});
|
||||
|
||||
it("keeps published Codex runtime imports resolvable from the host package", async () => {
|
||||
const result = await buildPluginNpmRuntime({
|
||||
repoRoot,
|
||||
packageDir: "extensions/codex",
|
||||
logLevel: "silent",
|
||||
});
|
||||
const plan = expectPluginNpmRuntimeBuildPlan(result);
|
||||
it.each(["codex", "copilot"])(
|
||||
"keeps published %s runtime imports resolvable from the host package",
|
||||
async (pluginId) => {
|
||||
const result = await buildPluginNpmRuntime({
|
||||
repoRoot,
|
||||
packageDir: `extensions/${pluginId}`,
|
||||
logLevel: "silent",
|
||||
});
|
||||
const plan = expectPluginNpmRuntimeBuildPlan(result);
|
||||
|
||||
expect(listMissingPluginNpmRuntimeHostExports(plan)).toEqual([]);
|
||||
});
|
||||
expect(listMissingPluginNpmRuntimeHostExports(plan)).toEqual([]);
|
||||
},
|
||||
);
|
||||
|
||||
it("detects unresolved side-effect host imports in built plugin runtimes", () => {
|
||||
const outDir = tempDirs.make("openclaw-plugin-runtime-host-import-");
|
||||
@@ -275,6 +278,45 @@ describe("plugin npm runtime build planning", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("allows private harness authority imports only for their official package owners", () => {
|
||||
const outDir = tempDirs.make("openclaw-plugin-runtime-private-owner-import-");
|
||||
writeFileSync(
|
||||
path.join(outDir, "index.js"),
|
||||
[
|
||||
'import "openclaw/plugin-sdk/agent-harness-tool-authority-runtime";',
|
||||
'import "openclaw/plugin-sdk/not-owner-restricted";',
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
const plan = expectPluginNpmRuntimeBuildPlan(
|
||||
resolvePluginNpmRuntimeBuildPlan({
|
||||
repoRoot,
|
||||
packageDir: path.join(repoRoot, "extensions", "codex"),
|
||||
}),
|
||||
);
|
||||
|
||||
expect(listMissingPluginNpmRuntimeHostExports({ ...plan, outDir })).toEqual([
|
||||
"openclaw/plugin-sdk/not-owner-restricted",
|
||||
]);
|
||||
expect(
|
||||
listMissingPluginNpmRuntimeHostExports({
|
||||
...plan,
|
||||
outDir,
|
||||
packageJson: { ...plan.packageJson, name: "@openclaw/copilot" },
|
||||
}),
|
||||
).toEqual(["openclaw/plugin-sdk/not-owner-restricted"]);
|
||||
expect(
|
||||
listMissingPluginNpmRuntimeHostExports({
|
||||
...plan,
|
||||
outDir,
|
||||
packageJson: { ...plan.packageJson, name: "@openclaw/demo" },
|
||||
}),
|
||||
).toEqual([
|
||||
"openclaw/plugin-sdk/agent-harness-tool-authority-runtime",
|
||||
"openclaw/plugin-sdk/not-owner-restricted",
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not require host metadata when the runtime has no host imports", () => {
|
||||
const syntheticRepoRoot = tempDirs.make("openclaw-plugin-runtime-synthetic-repo-");
|
||||
const outDir = tempDirs.make("openclaw-plugin-runtime-no-host-import-");
|
||||
|
||||
Reference in New Issue
Block a user