mirror of https://github.com/openclaw/openclaw.git
fix(plugins): keep snapshot hook loads isolated
This commit is contained in:
parent
f849b8de97
commit
1b557ffe65
|
|
@ -2,6 +2,7 @@ import fs from "node:fs";
|
|||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterAll, afterEach, describe, expect, it } from "vitest";
|
||||
import { clearInternalHooks, getRegisteredEventKeys } from "../hooks/internal-hooks.js";
|
||||
import { emitDiagnosticEvent, resetDiagnosticEventsForTest } from "../infra/diagnostic-events.js";
|
||||
import { withEnv } from "../test-utils/env.js";
|
||||
import { clearPluginCommands, getPluginCommandSpecs } from "./command-registry-state.js";
|
||||
|
|
@ -1265,6 +1266,42 @@ module.exports = { id: "skipped-scoped-only", register() { throw new Error("skip
|
|||
clearPluginCommands();
|
||||
});
|
||||
|
||||
it("does not register internal hooks globally during non-activating loads", () => {
|
||||
useNoBundledPlugins();
|
||||
const plugin = writePlugin({
|
||||
id: "internal-hook-snapshot",
|
||||
filename: "internal-hook-snapshot.cjs",
|
||||
body: `module.exports = {
|
||||
id: "internal-hook-snapshot",
|
||||
register(api) {
|
||||
api.registerHook("gateway:startup", () => {}, { name: "snapshot-hook" });
|
||||
},
|
||||
};`,
|
||||
});
|
||||
|
||||
clearInternalHooks();
|
||||
const scoped = loadOpenClawPlugins({
|
||||
cache: false,
|
||||
activate: false,
|
||||
workspaceDir: plugin.dir,
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [plugin.file] },
|
||||
allow: ["internal-hook-snapshot"],
|
||||
},
|
||||
},
|
||||
onlyPluginIds: ["internal-hook-snapshot"],
|
||||
});
|
||||
|
||||
expect(scoped.plugins.find((entry) => entry.id === "internal-hook-snapshot")?.status).toBe(
|
||||
"loaded",
|
||||
);
|
||||
expect(scoped.hooks.map((entry) => entry.entry.hook.name)).toEqual(["snapshot-hook"]);
|
||||
expect(getRegisteredEventKeys()).toEqual([]);
|
||||
|
||||
clearInternalHooks();
|
||||
});
|
||||
|
||||
it("can scope bundled provider loads to deepseek without hanging", () => {
|
||||
if (prevBundledDir === undefined) {
|
||||
delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
|
||||
|
|
|
|||
|
|
@ -938,7 +938,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
|
|||
logger,
|
||||
runtime,
|
||||
coreGatewayHandlers: options.coreGatewayHandlers as Record<string, GatewayRequestHandler>,
|
||||
suppressGlobalCommands: !shouldActivate,
|
||||
activateGlobalSideEffects: shouldActivate,
|
||||
});
|
||||
|
||||
const discovery = discoverOpenClawPlugins({
|
||||
|
|
|
|||
|
|
@ -243,9 +243,9 @@ export type PluginRegistryParams = {
|
|||
logger: PluginLogger;
|
||||
coreGatewayHandlers?: GatewayRequestHandlers;
|
||||
runtime: PluginRuntime;
|
||||
// When true, skip writing to the global plugin command registry during register().
|
||||
// Used by non-activating snapshot loads to avoid leaking commands into the running gateway.
|
||||
suppressGlobalCommands?: boolean;
|
||||
// When false, keep registration local to the returned registry and avoid mutating
|
||||
// process-global command/hook state during non-activating snapshot loads.
|
||||
activateGlobalSideEffects?: boolean;
|
||||
};
|
||||
|
||||
type PluginTypedHookPolicy = {
|
||||
|
|
@ -376,7 +376,11 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
|
|||
});
|
||||
|
||||
const hookSystemEnabled = config?.hooks?.internal?.enabled !== false;
|
||||
if (!hookSystemEnabled || opts?.register === false) {
|
||||
if (
|
||||
!registryParams.activateGlobalSideEffects ||
|
||||
!hookSystemEnabled ||
|
||||
opts?.register === false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -812,7 +816,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
|
|||
// NOTE: cross-plugin duplicate command detection is intentionally skipped here because
|
||||
// snapshot registries are isolated and never write to the global command table. Conflicts
|
||||
// will surface when the plugin is loaded via the normal activation path at gateway startup.
|
||||
if (registryParams.suppressGlobalCommands) {
|
||||
if (!registryParams.activateGlobalSideEffects) {
|
||||
const validationError = validatePluginCommandDefinition(command);
|
||||
if (validationError) {
|
||||
pushDiagnostic({
|
||||
|
|
|
|||
Loading…
Reference in New Issue