fix(coding-agent): preserved claude root command precedence

Ordered recursively discovered Claude command files so root basename commands stay ahead of nested basename duplicates while nested files still get namespace aliases.\n\nFixes #1523
This commit is contained in:
roboomp
2026-05-30 03:23:04 +00:00
parent 270f72ac71
commit bd3bb3ec28
2 changed files with 34 additions and 8 deletions
+15 -8
View File
@@ -269,20 +269,27 @@ function readClaudeCommandToggles(): { enableUser: boolean; enableProject: boole
}
}
function getClaudeCommandNamespaceAlias(commandsDir: string, filePath: string): string | null {
const relativeName = path.relative(commandsDir, filePath).replace(/\.md$/, "");
if (!/[\\/]/.test(relativeName)) return null;
return relativeName.replace(/[\\/]+/g, ":");
function getClaudeRelativeCommandName(commandsDir: string, filePath: string): string {
return path.relative(commandsDir, filePath).replace(/\.md$/, "");
}
function addClaudeCommandNamespaceAliases(commands: SlashCommand[], commandsDir: string): SlashCommand[] {
const rootCommands: SlashCommand[] = [];
const nestedCommands: SlashCommand[] = [];
const aliases: SlashCommand[] = [];
for (const command of commands) {
const alias = getClaudeCommandNamespaceAlias(commandsDir, command.path);
if (alias === null) continue;
aliases.push({ ...command, name: alias });
const relativeName = getClaudeRelativeCommandName(commandsDir, command.path);
if (!/[\\/]/.test(relativeName)) {
rootCommands.push(command);
continue;
}
nestedCommands.push(command);
aliases.push({ ...command, name: relativeName.replace(/[\\/]+/g, ":") });
}
return aliases.length === 0 ? commands : [...commands, ...aliases];
return nestedCommands.length === 0 ? commands : [...rootCommands, ...nestedCommands, ...aliases];
}
async function loadSlashCommands(ctx: LoadContext): Promise<LoadResult<SlashCommand>> {
@@ -60,4 +60,23 @@ describe("Claude Code slash command discovery", () => {
expect(names).toContain("audit");
expect(names).toContain("team:audit");
});
test("keeps root commands ahead of nested basename duplicates", async () => {
const rootApply = path.join(project, ".claude", "commands", "apply.md");
const nestedApply = path.join(project, ".claude", "commands", "agent", "apply.md");
await writeFile(rootApply, "Root apply prompt\n");
await writeFile(nestedApply, "Nested apply prompt\n");
const result = await loadCapability<SlashCommand>(slashCommandCapability.id, {
cwd: project,
providers: ["claude"],
});
const apply = result.items.find(command => command.name === "apply");
const agentApply = result.items.find(command => command.name === "agent:apply");
expect(result.warnings).toEqual([]);
expect(apply?.path).toBe(rootApply);
expect(apply?.content).toBe("Root apply prompt\n");
expect(agentApply?.path).toBe(nestedApply);
expect(agentApply?.content).toBe("Nested apply prompt\n");
});
});