diff --git a/extensions/telegram/src/bot-native-command-builtins.ts b/extensions/telegram/src/bot-native-command-builtins.ts index b59c9321b4b9..64320bce1514 100644 --- a/extensions/telegram/src/bot-native-command-builtins.ts +++ b/extensions/telegram/src/bot-native-command-builtins.ts @@ -253,7 +253,11 @@ export async function executeTelegramBuiltinCommand( if (!dispatch) { return false; } - const commandDefinition = findCommandByNativeName(params.commandName, "telegram"); + // Loaded-registry lookup only: Telegram defines no resolveNativeCommandName + // hook, and the bundled fallback would jiti-load the plugin source in dev/test. + const commandDefinition = findCommandByNativeName(params.commandName, "telegram", { + includeBundledChannelFallback: false, + }); const commandArgs = commandDefinition ? parseCommandArgs(commandDefinition, params.rawText) : params.rawText diff --git a/extensions/telegram/src/bot-native-commands.test.ts b/extensions/telegram/src/bot-native-commands.test.ts index 09e997f3331e..067ebcb875f1 100644 --- a/extensions/telegram/src/bot-native-commands.test.ts +++ b/extensions/telegram/src/bot-native-commands.test.ts @@ -184,6 +184,7 @@ describe("registerTelegramNativeCommands", () => { const native = listNativeCommandSpecsForConfig(cfg, { skillCommands, provider: "telegram", + includeBundledChannelFallback: false, }).map((command) => ({ command: normalizeTelegramCommandName(command.name), description: command.description, @@ -239,7 +240,11 @@ describe("registerTelegramNativeCommands", () => { "Telegram menu pressure omitted per-skill commands; removing per-skill commands and keeping /skill.", ); const expectedTotalCommands = - customCommands.length + listNativeCommandSpecsForConfig(cfg, { provider: "telegram" }).length; + customCommands.length + + listNativeCommandSpecsForConfig(cfg, { + provider: "telegram", + includeBundledChannelFallback: false, + }).length; expect(runtimeLog).toHaveBeenCalledWith( `Telegram limits bots to 100 commands. ${expectedTotalCommands} configured; registering first 100. Use channels.telegram.commands.native: false to disable, or reduce plugin/skill/custom commands.`, ); diff --git a/extensions/telegram/src/bot-native-commands.ts b/extensions/telegram/src/bot-native-commands.ts index 3f181e629e12..39d7a88162a6 100644 --- a/extensions/telegram/src/bot-native-commands.ts +++ b/extensions/telegram/src/bot-native-commands.ts @@ -104,12 +104,19 @@ export const registerTelegramNativeCommands = ({ : []; const pluginCommandRuntime = createPluginCommandRuntime(); const pluginCommandSpecs = pluginCommandRuntime.listNativeCandidates("telegram"); + // Telegram is the channel here: resolve native names from the loaded registry + // only. The bundled fallback would jiti-load this whole plugin from source in + // dev/test checkouts (minutes of transpile) to call a hook Telegram never defines. const nativeCommands = nativeEnabled - ? listNativeCommandSpecsForConfig(cfg, { skillCommands, provider: "telegram" }) + ? listNativeCommandSpecsForConfig(cfg, { + skillCommands, + provider: "telegram", + includeBundledChannelFallback: false, + }) : []; const reservedCommands = new Set( - listNativeCommandSpecs({ provider: "telegram" }).map((command) => - normalizeTelegramCommandName(command.name), + listNativeCommandSpecs({ provider: "telegram", includeBundledChannelFallback: false }).map( + (command) => normalizeTelegramCommandName(command.name), ), ); for (const command of skillCommands) { @@ -131,7 +138,10 @@ export const registerTelegramNativeCommands = ({ runtime.error?.(danger(issue)); } const firstSkillCommandIndex = nativeEnabled - ? listNativeCommandSpecsForConfig(cfg, { provider: "telegram" }).length + ? listNativeCommandSpecsForConfig(cfg, { + provider: "telegram", + includeBundledChannelFallback: false, + }).length : 0; const nativeMenuCommands = nativeCommands .map((command, index): TelegramMenuCommand | null => { @@ -171,8 +181,13 @@ export const registerTelegramNativeCommands = ({ "Telegram menu pressure omitted per-skill commands; removing per-skill commands and keeping /skill.", ); } - const loginCommand = listNativeCommandSpecsForConfig(cfg, { provider: "telegram" }).find( - (command) => findCommandByNativeName(command.name, "telegram")?.key === "login", + const loginCommand = listNativeCommandSpecsForConfig(cfg, { + provider: "telegram", + includeBundledChannelFallback: false, + }).find( + (command) => + findCommandByNativeName(command.name, "telegram", { includeBundledChannelFallback: false }) + ?.key === "login", ); const nativeCommandsToHandle = nativeEnabled ? nativeCommands @@ -264,7 +279,10 @@ export const registerTelegramNativeCommands = ({ ); }); } - if (findCommandByNativeName(command.name, "telegram")?.key === "login") { + if ( + findCommandByNativeName(command.name, "telegram", { includeBundledChannelFallback: false }) + ?.key === "login" + ) { handleLoginCallback = handleNativeCommand; } } @@ -300,7 +318,7 @@ export const registerTelegramNativeCommands = ({ .split("@", 1)[0] ?.toLowerCase(); const commandDefinition = commandName - ? findCommandByNativeName(commandName, "telegram") + ? findCommandByNativeName(commandName, "telegram", { includeBundledChannelFallback: false }) : undefined; if (commandDefinition?.key !== "login") { return { handled: false, clearButtons: false }; diff --git a/src/auto-reply/commands-registry.ts b/src/auto-reply/commands-registry.ts index 51d50ab6cc9f..01d3153ade36 100644 --- a/src/auto-reply/commands-registry.ts +++ b/src/auto-reply/commands-registry.ts @@ -79,9 +79,13 @@ function resolveNativeName( ); } -function toNativeCommandSpec(command: ChatCommandDefinition, provider?: string): NativeCommandSpec { +function toNativeCommandSpec( + command: ChatCommandDefinition, + provider?: string, + options?: NativeCommandProviderLookupOptions, +): NativeCommandSpec { const spec: NativeCommandSpec = { - name: resolveNativeName(command, provider) ?? command.key, + name: resolveNativeName(command, provider, options) ?? command.key, description: command.description, acceptsArgs: Boolean(command.acceptsArgs), args: command.args, @@ -92,8 +96,12 @@ function toNativeCommandSpec(command: ChatCommandDefinition, provider?: string): return spec; } -function resolveNativeNames(command: ChatCommandDefinition, provider?: string): string[] { - const primary = resolveNativeName(command, provider); +function resolveNativeNames( + command: ChatCommandDefinition, + provider?: string, + options?: NativeCommandProviderLookupOptions, +): string[] { + const primary = resolveNativeName(command, provider, options); return [primary, ...(command.nativeAliases ?? [])].filter((name): name is string => Boolean(name), ); @@ -115,6 +123,7 @@ function supportsNativeProvider(command: ChatCommandDefinition, provider?: strin function listNativeSpecsFromCommands( commands: ChatCommandDefinition[], provider?: string, + options?: NativeCommandProviderLookupOptions, ): NativeCommandSpec[] { return commands .filter( @@ -122,8 +131,8 @@ function listNativeSpecsFromCommands( command.scope !== "text" && command.nativeName && supportsNativeProvider(command, provider), ) .flatMap((command) => { - const spec = toNativeCommandSpec(command, provider); - return resolveNativeNames(command, provider).map((name, index) => { + const spec = toNativeCommandSpec(command, provider, options); + return resolveNativeNames(command, provider, options).map((name, index) => { const nativeSpec: NativeCommandSpec = { name, description: spec.description, @@ -145,22 +154,32 @@ function listNativeSpecsFromCommands( } /** Lists native command specs registered for a provider, including skill commands. */ -export function listNativeCommandSpecs(params?: { - skillCommands?: SkillCommandSpec[]; - provider?: string; -}): NativeCommandSpec[] { +export function listNativeCommandSpecs( + params?: { + skillCommands?: SkillCommandSpec[]; + provider?: string; + } & NativeCommandProviderLookupOptions, +): NativeCommandSpec[] { return listNativeSpecsFromCommands( listChatCommands({ skillCommands: params?.skillCommands }), params?.provider, + params, ); } /** Lists native command specs that are enabled for the provided config. */ export function listNativeCommandSpecsForConfig( cfg: OpenClawConfig, - params?: { skillCommands?: SkillCommandSpec[]; provider?: string }, + params?: { + skillCommands?: SkillCommandSpec[]; + provider?: string; + } & NativeCommandProviderLookupOptions, ): NativeCommandSpec[] { - return listNativeSpecsFromCommands(listChatCommandsForConfig(cfg, params), params?.provider); + return listNativeSpecsFromCommands( + listChatCommandsForConfig(cfg, params), + params?.provider, + params, + ); } export function mergeNativeCommandSpecs(params: {