Plugins: honor native command aliases at dispatch
This commit is contained in:
parent
095a9f6e1d
commit
f90d432de3
@ -212,6 +212,58 @@ describe("Discord native plugin command dispatch", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("round-trips Discord native aliases through the real plugin registry", async () => {
|
||||
const cfg = createConfig();
|
||||
const commandSpec: NativeCommandSpec = {
|
||||
name: "pairdiscord",
|
||||
description: "Pair",
|
||||
acceptsArgs: true,
|
||||
};
|
||||
const command = createDiscordNativeCommand({
|
||||
command: commandSpec,
|
||||
cfg,
|
||||
discordConfig: cfg.channels?.discord ?? {},
|
||||
accountId: "default",
|
||||
sessionPrefix: "discord:slash",
|
||||
ephemeralDefault: true,
|
||||
threadBindings: createNoopThreadBindingManager("default"),
|
||||
});
|
||||
const interaction = createInteraction();
|
||||
|
||||
expect(
|
||||
registerPluginCommand("demo-plugin", {
|
||||
name: "pair",
|
||||
nativeNames: {
|
||||
telegram: "pair_device",
|
||||
discord: "pairdiscord",
|
||||
},
|
||||
description: "Pair device",
|
||||
acceptsArgs: true,
|
||||
requireAuth: false,
|
||||
handler: async ({ args }) => ({ text: `paired:${args ?? ""}` }),
|
||||
}),
|
||||
).toEqual({ ok: true });
|
||||
|
||||
const dispatchSpy = vi
|
||||
.spyOn(dispatcherModule, "dispatchReplyWithDispatcher")
|
||||
.mockResolvedValue({} as never);
|
||||
|
||||
await (command as { run: (interaction: unknown) => Promise<void> }).run(
|
||||
Object.assign(interaction, {
|
||||
options: {
|
||||
getString: () => "now",
|
||||
getBoolean: () => null,
|
||||
getFocused: () => "",
|
||||
},
|
||||
}) as unknown,
|
||||
);
|
||||
|
||||
expect(dispatchSpy).not.toHaveBeenCalled();
|
||||
expect(interaction.reply).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ content: "paired:now" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("blocks unauthorized Discord senders before requireAuth:false plugin commands execute", async () => {
|
||||
const cfg = {
|
||||
commands: {
|
||||
|
||||
@ -147,6 +147,54 @@ describe("registerTelegramNativeCommands real plugin registry", () => {
|
||||
expect(sendMessage).not.toHaveBeenCalledWith(123, "Command not found.");
|
||||
});
|
||||
|
||||
it("round-trips Telegram native aliases through the real plugin registry", async () => {
|
||||
const { bot, commandHandlers, sendMessage, setMyCommands } = createCommandBot();
|
||||
|
||||
expect(
|
||||
registerPluginCommand("demo-plugin", {
|
||||
name: "pair",
|
||||
nativeNames: {
|
||||
telegram: "pair_device",
|
||||
discord: "pairdiscord",
|
||||
},
|
||||
description: "Pair device",
|
||||
acceptsArgs: true,
|
||||
requireAuth: false,
|
||||
handler: async ({ args }) => ({ text: `paired:${args ?? ""}` }),
|
||||
}),
|
||||
).toEqual({ ok: true });
|
||||
|
||||
registerTelegramNativeCommands({
|
||||
...buildParams({}),
|
||||
bot,
|
||||
});
|
||||
|
||||
const registeredCommands = await waitForRegisteredCommands(setMyCommands);
|
||||
expect(registeredCommands).toEqual(
|
||||
expect.arrayContaining([{ command: "pair_device", description: "Pair device" }]),
|
||||
);
|
||||
|
||||
const handler = commandHandlers.get("pair_device");
|
||||
expect(handler).toBeTruthy();
|
||||
|
||||
await handler?.({
|
||||
match: "now",
|
||||
message: {
|
||||
message_id: 2,
|
||||
date: Math.floor(Date.now() / 1000),
|
||||
chat: { id: 123, type: "private" },
|
||||
from: { id: 456, username: "alice" },
|
||||
},
|
||||
});
|
||||
|
||||
expect(deliveryMocks.deliverReplies).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
replies: [expect.objectContaining({ text: "paired:now" })],
|
||||
}),
|
||||
);
|
||||
expect(sendMessage).not.toHaveBeenCalledWith(123, "Command not found.");
|
||||
});
|
||||
|
||||
it("keeps real plugin command handlers available when native menu registration is disabled", () => {
|
||||
const { bot, commandHandlers, setMyCommands } = createCommandBot();
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
executePluginCommand,
|
||||
getPluginCommandSpecs,
|
||||
listPluginCommands,
|
||||
matchPluginCommand,
|
||||
registerPluginCommand,
|
||||
} from "./commands.js";
|
||||
import { setActivePluginRegistry } from "./runtime.js";
|
||||
@ -107,6 +108,29 @@ describe("registerPluginCommand", () => {
|
||||
expect(getPluginCommandSpecs("slack")).toEqual([]);
|
||||
});
|
||||
|
||||
it("matches provider-specific native aliases back to the canonical command", () => {
|
||||
const result = registerPluginCommand("demo-plugin", {
|
||||
name: "voice",
|
||||
nativeNames: {
|
||||
default: "talkvoice",
|
||||
discord: "discordvoice",
|
||||
},
|
||||
description: "Demo command",
|
||||
acceptsArgs: true,
|
||||
handler: async () => ({ text: "ok" }),
|
||||
});
|
||||
|
||||
expect(result).toEqual({ ok: true });
|
||||
expect(matchPluginCommand("/talkvoice now")).toMatchObject({
|
||||
command: expect.objectContaining({ name: "voice", pluginId: "demo-plugin" }),
|
||||
args: "now",
|
||||
});
|
||||
expect(matchPluginCommand("/discordvoice now")).toMatchObject({
|
||||
command: expect.objectContaining({ name: "voice", pluginId: "demo-plugin" }),
|
||||
args: "now",
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves Discord DM command bindings with the user target prefix intact", () => {
|
||||
expect(
|
||||
__testing.resolveBindingConversationFromCommand({
|
||||
|
||||
@ -219,7 +219,11 @@ export function matchPluginCommand(
|
||||
const args = spaceIndex === -1 ? undefined : trimmed.slice(spaceIndex + 1).trim();
|
||||
|
||||
const key = commandName.toLowerCase();
|
||||
const command = pluginCommands.get(key);
|
||||
const command =
|
||||
pluginCommands.get(key) ??
|
||||
Array.from(pluginCommands.values()).find((candidate) =>
|
||||
listPluginInvocationNames(candidate).includes(key),
|
||||
);
|
||||
|
||||
if (!command) {
|
||||
return null;
|
||||
@ -458,6 +462,24 @@ function resolvePluginNativeName(
|
||||
return command.name;
|
||||
}
|
||||
|
||||
function listPluginInvocationNames(command: OpenClawPluginCommandDefinition): string[] {
|
||||
const names = new Set<string>();
|
||||
const push = (value: string | undefined) => {
|
||||
const normalized = value?.trim().toLowerCase();
|
||||
if (!normalized) {
|
||||
return;
|
||||
}
|
||||
names.add(`/${normalized}`);
|
||||
};
|
||||
|
||||
push(command.name);
|
||||
push(command.nativeNames?.default);
|
||||
push(command.nativeNames?.telegram);
|
||||
push(command.nativeNames?.discord);
|
||||
|
||||
return [...names];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin command specs for native command registration (e.g., Telegram).
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user