mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 13:26:04 -06:00
fix(plugins): register static node-host commands without activation (#127043)
The node host resolves its plugin registry via loadPluginRegistryHandle (activate:false). Since #117587 static definition.nodeHostCommands only registered under runFullActivationOnlyRegistrations, so headless nodes silently lost browser.proxy (and the browser/file caps), breaking the meeting-bot chain with 'No connected Google Meet-capable node with browser proxy'. Register node-host commands in every load mode; each command keeps its own isAvailable gate. reload and security audit collectors stay activation-only.
This commit is contained in:
committed by
GitHub
parent
4343b38ce7
commit
781ded80d6
@@ -507,13 +507,17 @@ export function loadRuntimePluginCandidate(params: {
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Node-host commands register in every load mode: the node host resolves its
|
||||
// registry without activation (loadPluginRegistryHandle), and each command is
|
||||
// already availability-gated per invocation. Gating them on full activation
|
||||
// silently strips static registrations like browser.proxy from headless nodes.
|
||||
for (const nodeHostCommand of definition?.nodeHostCommands ?? []) {
|
||||
params.registryBuilder.registerNodeHostCommand(record, nodeHostCommand);
|
||||
}
|
||||
if (registrationPlan.runFullActivationOnlyRegistrations) {
|
||||
if (definition?.reload) {
|
||||
params.registryBuilder.registerReload(record, definition.reload);
|
||||
}
|
||||
for (const nodeHostCommand of definition?.nodeHostCommands ?? []) {
|
||||
params.registryBuilder.registerNodeHostCommand(record, nodeHostCommand);
|
||||
}
|
||||
for (const collector of definition?.securityAuditCollectors ?? []) {
|
||||
params.registryBuilder.registerSecurityAuditCollector(record, collector);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/** Verifies static plugin nodeHostCommands survive non-activating registry loads (node-host path). */
|
||||
import { afterAll, afterEach, expect, it } from "vitest";
|
||||
import {
|
||||
cleanupPluginLoaderFixturesForTest,
|
||||
loadOpenClawPlugins,
|
||||
resetPluginLoaderTestStateForTest,
|
||||
useNoBundledPlugins,
|
||||
writePlugin,
|
||||
} from "./loader.test-fixtures.js";
|
||||
|
||||
afterEach(resetPluginLoaderTestStateForTest);
|
||||
afterAll(cleanupPluginLoaderFixturesForTest);
|
||||
|
||||
// The node host resolves its registry via loadPluginRegistryHandle (activate:false).
|
||||
// Static nodeHostCommands (e.g. the browser plugin's browser.proxy) must register
|
||||
// there too, or headless meeting/browser nodes silently lose their surface.
|
||||
it("registers static nodeHostCommands without activation", () => {
|
||||
useNoBundledPlugins();
|
||||
const plugin = writePlugin({
|
||||
id: "node-surface",
|
||||
body: `module.exports = {
|
||||
id: "node-surface",
|
||||
nodeHostCommands: [{
|
||||
command: "nodesurface.proxy",
|
||||
cap: "node-surface",
|
||||
handle: async () => "ok",
|
||||
}],
|
||||
register() {},
|
||||
};`,
|
||||
});
|
||||
|
||||
const registry = loadOpenClawPlugins({
|
||||
cache: false,
|
||||
activate: false,
|
||||
workspaceDir: plugin.dir,
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [plugin.file] },
|
||||
allow: [plugin.id],
|
||||
},
|
||||
},
|
||||
onlyPluginIds: [plugin.id],
|
||||
});
|
||||
|
||||
expect(registry.plugins.find((entry) => entry.id === plugin.id)?.status).toBe("loaded");
|
||||
expect(registry.nodeHostCommands.map((entry) => entry.command.command)).toContain(
|
||||
"nodesurface.proxy",
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user