diff --git a/src/tools/slashcommand/command-discovery.test.ts b/src/tools/slashcommand/command-discovery.test.ts index 1ebf65c97..232515a33 100644 --- a/src/tools/slashcommand/command-discovery.test.ts +++ b/src/tools/slashcommand/command-discovery.test.ts @@ -204,4 +204,35 @@ Use ancestor command. expect(ancestorCommand?.scope).toBe("opencode-project") expect(ancestorCommand?.content).toContain("Use ancestor command.") }) + + it("deduplicates same-named opencode commands while keeping the higher-priority alias", () => { + const commandsRoot = join(projectDir, ".opencode") + const singularDir = join(commandsRoot, "command") + const pluralDir = join(commandsRoot, "commands") + + mkdirSync(singularDir, { recursive: true }) + mkdirSync(pluralDir, { recursive: true }) + writeFileSync( + join(singularDir, "duplicate.md"), + `--- +description: Singular duplicate command +--- +Use singular command. +`, + ) + writeFileSync( + join(pluralDir, "duplicate.md"), + `--- +description: Plural duplicate command +--- +Use plural command. +`, + ) + + const commands = discoverCommandsSync(projectDir) + const duplicates = commands.filter((command) => command.name === "duplicate") + + expect(duplicates).toHaveLength(1) + expect(duplicates[0]?.content).toContain("Use plural command.") + }) }) diff --git a/src/tools/slashcommand/command-discovery.ts b/src/tools/slashcommand/command-discovery.ts index ad8e23130..7567e74dd 100644 --- a/src/tools/slashcommand/command-discovery.ts +++ b/src/tools/slashcommand/command-discovery.ts @@ -76,6 +76,22 @@ function discoverPluginCommands(options?: CommandDiscoveryOptions): CommandInfo[ })) } +function deduplicateCommandInfosByName(commands: CommandInfo[]): CommandInfo[] { + const seen = new Set() + const deduplicatedCommands: CommandInfo[] = [] + + for (const command of commands) { + if (seen.has(command.name)) { + continue + } + + seen.add(command.name) + deduplicatedCommands.push(command) + } + + return deduplicatedCommands +} + export function discoverCommandsSync( directory?: string, options?: CommandDiscoveryOptions, @@ -110,12 +126,12 @@ export function discoverCommandsSync( scope: "builtin", })) - return [ + return deduplicateCommandInfosByName([ ...projectCommands, ...userCommands, ...opencodeProjectCommands, ...opencodeGlobalCommands, ...builtinCommands, ...pluginCommands, - ] + ]) }