fix(plugins): resolve official plugin install aliases

Resolve bare official external plugin IDs through the official catalog before generic npm fallback, preserving explicit npm semantics and catalog integrity through the hook-pack fallback.\n\nFixes #76373.\n\nThanks @bek91 and @vincentkoc.
This commit is contained in:
Bek
2026-05-03 01:27:13 -04:00
committed by GitHub
parent f696be950b
commit 411df59916
6 changed files with 262 additions and 1 deletions

View File

@@ -21,6 +21,11 @@ import {
installPluginFromMarketplace,
resolveMarketplaceInstallShortcut,
} from "../plugins/marketplace.js";
import {
getOfficialExternalPluginCatalogEntry,
resolveOfficialExternalPluginId,
resolveOfficialExternalPluginInstall,
} from "../plugins/official-external-plugin-catalog.js";
import { tracePluginLifecyclePhaseAsync } from "../plugins/plugin-lifecycle-trace.js";
import { validateJsonSchemaValue } from "../plugins/schema-validator.js";
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
@@ -36,6 +41,7 @@ import {
import {
resolveBundledInstallPlanBeforeNpm,
resolveBundledInstallPlanForNpmFailure,
resolveOfficialExternalInstallPlanBeforeNpm,
} from "./plugin-install-plan.js";
import {
createHookPackInstallLogger,
@@ -231,11 +237,13 @@ async function tryInstallHookPackFromNpmSpec(params: {
installMode: "install" | "update";
spec: string;
pin?: boolean;
expectedIntegrity?: string;
runtime?: RuntimeEnv;
}): Promise<{ ok: true } | { ok: false; error: string }> {
const result = await installHooksFromNpmSpec({
spec: params.spec,
mode: params.installMode,
...(params.expectedIntegrity ? { expectedIntegrity: params.expectedIntegrity } : {}),
logger: createHookPackInstallLogger(params.runtime),
});
if (!result.ok) {
@@ -269,12 +277,16 @@ async function tryInstallPluginOrHookPackFromNpmSpec(params: {
safetyOverrides: InstallSafetyOverrides;
allowBundledFallback: boolean;
extensionsDir: string;
expectedPluginId?: string;
expectedIntegrity?: string;
runtime?: RuntimeEnv;
}): Promise<{ ok: true } | { ok: false }> {
const result = await installPluginFromNpmSpec({
...params.safetyOverrides,
mode: params.installMode,
spec: params.spec,
...(params.expectedPluginId ? { expectedPluginId: params.expectedPluginId } : {}),
...(params.expectedIntegrity ? { expectedIntegrity: params.expectedIntegrity } : {}),
extensionsDir: params.extensionsDir,
logger: createPluginInstallLogger(params.runtime),
});
@@ -305,6 +317,7 @@ async function tryInstallPluginOrHookPackFromNpmSpec(params: {
installMode: params.installMode,
spec: params.spec,
pin: params.pin,
expectedIntegrity: params.expectedIntegrity,
runtime: params.runtime,
});
if (hookFallback.ok) {
@@ -747,6 +760,41 @@ export async function runPluginInstallCommand(params: {
return;
}
const officialExternalPlan = resolveOfficialExternalInstallPlanBeforeNpm({
rawSpec: raw,
findOfficialExternalPlugin: (pluginId) => {
const entry = getOfficialExternalPluginCatalogEntry(pluginId);
const resolvedPluginId = entry ? resolveOfficialExternalPluginId(entry) : undefined;
const install = entry ? resolveOfficialExternalPluginInstall(entry) : null;
const npmSpec = install?.npmSpec;
return resolvedPluginId && npmSpec
? {
pluginId: resolvedPluginId,
npmSpec,
...(install.expectedIntegrity ? { expectedIntegrity: install.expectedIntegrity } : {}),
}
: undefined;
},
});
if (officialExternalPlan) {
const npmResult = await tryInstallPluginOrHookPackFromNpmSpec({
snapshot,
installMode,
spec: officialExternalPlan.npmSpec,
pin: opts.pin,
safetyOverrides,
allowBundledFallback: false,
extensionsDir,
expectedPluginId: officialExternalPlan.pluginId,
expectedIntegrity: officialExternalPlan.expectedIntegrity,
runtime,
});
if (!npmResult.ok) {
return runtime.exit(1);
}
return;
}
const clawhubSpec = parseClawHubPluginSpec(raw);
if (clawhubSpec) {
const result = await installPluginFromClawHub({