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:
@@ -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");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user