fix(plugins): expose channel CLI metadata in discovery

This commit is contained in:
Gustavo Madeira Santana
2026-04-24 20:23:25 -04:00
parent 7ef4ecf499
commit 118813a412
5 changed files with 145 additions and 0 deletions

View File

@@ -69,6 +69,37 @@ describe("matrix plugin", () => {
expect(entry.setChannelRuntime).toEqual(expect.any(Function));
});
it("registers CLI metadata during discovery registration", () => {
const registerChannel = vi.fn();
const registerCli = vi.fn();
const registerGatewayMethod = vi.fn();
const api = createTestPluginApi({
id: "matrix",
name: "Matrix",
source: "test",
config: {},
runtime: {} as never,
registrationMode: "discovery",
registerChannel,
registerCli,
registerGatewayMethod,
});
entry.register(api);
expect(registerChannel).toHaveBeenCalledTimes(1);
expect(registerCli).toHaveBeenCalledWith(expect.any(Function), {
descriptors: [
{
name: "matrix",
description: "Manage Matrix accounts, verification, devices, and profile state",
hasSubcommands: true,
},
],
});
expect(registerGatewayMethod).not.toHaveBeenCalled();
});
it("registers subagent lifecycle hooks during full runtime registration", () => {
const on = vi.fn();
const registerGatewayMethod = vi.fn();

View File

@@ -488,6 +488,10 @@ export function defineBundledChannelEntry<TPlugin = ChannelPlugin>({
profile("bundled-register:registerChannel", () =>
api.registerChannel({ plugin: channelPlugin as ChannelPlugin }),
);
if (api.registrationMode === "discovery") {
profile("bundled-register:registerCliMetadata", () => registerCliMetadata?.(api));
return;
}
if (api.registrationMode !== "full") {
return;
}

View File

@@ -505,6 +505,10 @@ export function defineChannelPluginEntry<TPlugin>({
}
setRuntime?.(api.runtime);
api.registerChannel({ plugin: plugin as ChannelPlugin });
if (api.registrationMode === "discovery") {
registerCliMetadata?.(api);
return;
}
if (api.registrationMode !== "full") {
return;
}

View File

@@ -549,6 +549,108 @@ module.exports = {
);
});
it("collects channel CLI metadata during discovery plugin loads", () => {
useNoBundledPlugins();
const pluginDir = makeTempDir();
const modeMarker = path.join(pluginDir, "registration-mode.txt");
const fullMarker = path.join(pluginDir, "full-loaded.txt");
fs.writeFileSync(
path.join(pluginDir, "package.json"),
JSON.stringify(
{
name: "@openclaw/discovery-cli-metadata-channel",
openclaw: { extensions: ["./index.cjs"] },
},
null,
2,
),
"utf-8",
);
fs.writeFileSync(
path.join(pluginDir, "openclaw.plugin.json"),
JSON.stringify(
{
id: "discovery-cli-metadata-channel",
configSchema: EMPTY_PLUGIN_SCHEMA,
channels: ["discovery-cli-metadata-channel"],
},
null,
2,
),
"utf-8",
);
fs.writeFileSync(
path.join(pluginDir, "index.cjs"),
`${inlineChannelPluginEntryFactorySource()}
module.exports = {
...defineChannelPluginEntry({
id: "discovery-cli-metadata-channel",
name: "Discovery CLI Metadata Channel",
description: "discovery cli metadata channel",
plugin: {
id: "discovery-cli-metadata-channel",
meta: {
id: "discovery-cli-metadata-channel",
label: "Discovery CLI Metadata Channel",
selectionLabel: "Discovery CLI Metadata Channel",
docsPath: "/channels/discovery-cli-metadata-channel",
blurb: "discovery cli metadata channel",
},
capabilities: { chatTypes: ["direct"] },
config: {
listAccountIds: () => [],
resolveAccount: () => ({ accountId: "default" }),
},
outbound: { deliveryMode: "direct" },
},
registerCliMetadata(api) {
require("node:fs").writeFileSync(
${JSON.stringify(modeMarker)},
String(api.registrationMode),
"utf-8",
);
api.registerCli(() => {}, {
descriptors: [
{
name: "discovery-cli-metadata-channel",
description: "Discovery-load channel CLI metadata",
hasSubcommands: true,
},
],
});
},
registerFull() {
require("node:fs").writeFileSync(${JSON.stringify(fullMarker)}, "loaded", "utf-8");
},
}),
};`,
"utf-8",
);
const registry = loadOpenClawPlugins({
activate: false,
cache: false,
config: {
plugins: {
load: { paths: [pluginDir] },
allow: ["discovery-cli-metadata-channel"],
entries: {
"discovery-cli-metadata-channel": {
enabled: true,
},
},
},
},
});
expect(fs.readFileSync(modeMarker, "utf-8")).toBe("discovery");
expect(fs.existsSync(fullMarker)).toBe(false);
expect(registry.cliRegistrars.flatMap((entry) => entry.commands)).toContain(
"discovery-cli-metadata-channel",
);
});
it("rejects async plugin registration when collecting CLI metadata", async () => {
useNoBundledPlugins();
const plugin = writePlugin({

View File

@@ -57,6 +57,10 @@ export function inlineChannelPluginEntryFactorySource(): string {
}
options.setRuntime?.(api.runtime);
api.registerChannel({ plugin: options.plugin });
if (api.registrationMode === "discovery") {
options.registerCliMetadata?.(api);
return;
}
if (api.registrationMode !== "full") {
return;
}