mirror of https://github.com/openclaw/openclaw.git
fix(plugins): fall back to bundled plugin when npm spec resolves to non-OpenClaw package (#32019)
When `openclaw plugins install diffs` downloads the unrelated npm package `diffs@0.1.1` (which lacks `openclaw.extensions`), the install fails without trying the bundled `@openclaw/diffs` plugin. Two fixes: 1. Broaden the bundled-fallback trigger to also fire on "missing openclaw.extensions" errors (not just npm 404s) 2. Match bundled plugins by pluginId in addition to npmSpec so unscoped names like "diffs" resolve to `@openclaw/diffs` Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
089a8785b9
commit
da8a17d8de
|
|
@ -159,6 +159,19 @@ function isPackageNotFoundInstallError(message: string): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* True when npm downloaded a package successfully but it is not a valid
|
||||
* OpenClaw plugin (e.g. `diffs` resolves to the unrelated npm package
|
||||
* `diffs@0.1.1` instead of `@openclaw/diffs`).
|
||||
* See: https://github.com/openclaw/openclaw/issues/32019
|
||||
*/
|
||||
function isNotAnOpenClawPluginError(message: string): boolean {
|
||||
const lower = message.toLowerCase();
|
||||
return (
|
||||
lower.includes("missing openclaw.extensions") || lower.includes("openclaw.extensions is empty")
|
||||
);
|
||||
}
|
||||
|
||||
export function registerPluginsCli(program: Command) {
|
||||
const plugins = program
|
||||
.command("plugins")
|
||||
|
|
@ -625,7 +638,9 @@ export function registerPluginsCli(program: Command) {
|
|||
logger: createPluginInstallLogger(),
|
||||
});
|
||||
if (!result.ok) {
|
||||
const bundledFallback = isPackageNotFoundInstallError(result.error)
|
||||
const shouldTryBundledFallback =
|
||||
isPackageNotFoundInstallError(result.error) || isNotAnOpenClawPluginError(result.error);
|
||||
const bundledFallback = shouldTryBundledFallback
|
||||
? findBundledPluginByNpmSpec({ spec: raw })
|
||||
: undefined;
|
||||
if (!bundledFallback) {
|
||||
|
|
|
|||
|
|
@ -94,4 +94,26 @@ describe("bundled plugin sources", () => {
|
|||
expect(resolved?.localPath).toBe("/app/extensions/feishu");
|
||||
expect(missing).toBeUndefined();
|
||||
});
|
||||
|
||||
it("finds bundled source by plugin id when npm spec does not match (#32019)", () => {
|
||||
discoverOpenClawPluginsMock.mockReturnValue({
|
||||
candidates: [
|
||||
{
|
||||
origin: "bundled",
|
||||
rootDir: "/app/extensions/diffs",
|
||||
packageName: "@openclaw/diffs",
|
||||
packageManifest: {},
|
||||
},
|
||||
],
|
||||
diagnostics: [],
|
||||
});
|
||||
loadPluginManifestMock.mockReturnValue({ ok: true, manifest: { id: "diffs" } });
|
||||
|
||||
// Searching by unscoped name "diffs" should match by pluginId even though
|
||||
// the npmSpec is "@openclaw/diffs".
|
||||
const resolved = findBundledPluginByNpmSpec({ spec: "diffs" });
|
||||
|
||||
expect(resolved?.pluginId).toBe("diffs");
|
||||
expect(resolved?.localPath).toBe("/app/extensions/diffs");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -54,6 +54,13 @@ export function findBundledPluginByNpmSpec(params: {
|
|||
if (source.npmSpec === targetSpec) {
|
||||
return source;
|
||||
}
|
||||
// Also match by plugin id so that e.g. `openclaw plugins install diffs`
|
||||
// resolves to the bundled @openclaw/diffs plugin when the unscoped npm
|
||||
// package `diffs` is not a valid OpenClaw plugin.
|
||||
// See: https://github.com/openclaw/openclaw/issues/32019
|
||||
if (source.pluginId === targetSpec) {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue