fix(regression): scope plugin registry reuse by gateway methods

This commit is contained in:
Tak Hoffman
2026-03-27 23:21:51 -05:00
parent 158e7c517e
commit c0d4c07b88
2 changed files with 35 additions and 1 deletions

View File

@@ -3593,6 +3593,35 @@ describe("getCompatibleActivePluginRegistry", () => {
expect(getCompatibleActivePluginRegistry()).toBe(registry);
});
it("does not reuse the active registry when core gateway method names differ", () => {
const registry = createEmptyPluginRegistry();
const loadOptions = {
config: {
plugins: {
allow: ["demo"],
load: { paths: ["/tmp/demo.js"] },
},
},
workspaceDir: "/tmp/workspace-a",
coreGatewayHandlers: {
"sessions.get": () => undefined,
},
};
const { cacheKey } = resolvePluginLoadCacheContext(loadOptions);
setActivePluginRegistry(registry, cacheKey);
expect(getCompatibleActivePluginRegistry(loadOptions)).toBe(registry);
expect(
getCompatibleActivePluginRegistry({
...loadOptions,
coreGatewayHandlers: {
"sessions.get": () => undefined,
"sessions.list": () => undefined,
},
}),
).toBeUndefined();
});
});
describe("resolveRuntimePluginRegistry", () => {

View File

@@ -202,6 +202,7 @@ function buildCacheKey(params: {
preferSetupRuntimeForChannelPlugins?: boolean;
runtimeSubagentMode?: "default" | "explicit" | "gateway-bindable";
pluginSdkResolution?: PluginSdkResolutionPreference;
coreGatewayMethodNames?: string[];
}): string {
const { roots, loadPaths } = resolvePluginCacheInputs({
workspaceDir: params.workspaceDir,
@@ -228,11 +229,12 @@ function buildCacheKey(params: {
const setupOnlyKey = params.includeSetupOnlyChannelPlugins === true ? "setup-only" : "runtime";
const startupChannelMode =
params.preferSetupRuntimeForChannelPlugins === true ? "prefer-setup" : "full";
const gatewayMethodsKey = JSON.stringify(params.coreGatewayMethodNames ?? []);
return `${roots.workspace ?? ""}::${roots.global ?? ""}::${roots.stock ?? ""}::${JSON.stringify({
...params.plugins,
installs,
loadPaths,
})}::${scopeKey}::${setupOnlyKey}::${startupChannelMode}::${params.runtimeSubagentMode ?? "default"}::${params.pluginSdkResolution ?? "auto"}`;
})}::${scopeKey}::${setupOnlyKey}::${startupChannelMode}::${params.runtimeSubagentMode ?? "default"}::${params.pluginSdkResolution ?? "auto"}::${gatewayMethodsKey}`;
}
function normalizeScopedPluginIds(ids?: string[]): string[] | undefined {
@@ -263,6 +265,7 @@ function hasExplicitCompatibilityInputs(options: PluginLoadOptions): boolean {
options.onlyPluginIds?.length ||
options.runtimeOptions !== undefined ||
options.pluginSdkResolution !== undefined ||
options.coreGatewayHandlers !== undefined ||
options.includeSetupOnlyChannelPlugins === true ||
options.preferSetupRuntimeForChannelPlugins === true,
);
@@ -275,6 +278,7 @@ export function resolvePluginLoadCacheContext(options: PluginLoadOptions = {}) {
const onlyPluginIds = normalizeScopedPluginIds(options.onlyPluginIds);
const includeSetupOnlyChannelPlugins = options.includeSetupOnlyChannelPlugins === true;
const preferSetupRuntimeForChannelPlugins = options.preferSetupRuntimeForChannelPlugins === true;
const coreGatewayMethodNames = Object.keys(options.coreGatewayHandlers ?? {}).toSorted();
const cacheKey = buildCacheKey({
workspaceDir: options.workspaceDir,
plugins: normalized,
@@ -285,6 +289,7 @@ export function resolvePluginLoadCacheContext(options: PluginLoadOptions = {}) {
preferSetupRuntimeForChannelPlugins,
runtimeSubagentMode: resolveRuntimeSubagentMode(options.runtimeOptions),
pluginSdkResolution: options.pluginSdkResolution,
coreGatewayMethodNames,
});
return {
env,