summaryrefslogtreecommitdiff
path: root/packages/cli/src/services/CommandService.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cli/src/services/CommandService.ts')
-rw-r--r--packages/cli/src/services/CommandService.ts36
1 files changed, 28 insertions, 8 deletions
diff --git a/packages/cli/src/services/CommandService.ts b/packages/cli/src/services/CommandService.ts
index ef4f4d14..78e4817b 100644
--- a/packages/cli/src/services/CommandService.ts
+++ b/packages/cli/src/services/CommandService.ts
@@ -30,13 +30,17 @@ export class CommandService {
*
* This factory method orchestrates the entire command loading process. It
* runs all provided loaders in parallel, aggregates their results, handles
- * name conflicts by letting the last-loaded command win, and then returns a
+ * name conflicts for extension commands by renaming them, and then returns a
* fully constructed `CommandService` instance.
*
+ * Conflict resolution:
+ * - Extension commands that conflict with existing commands are renamed to
+ * `extensionName.commandName`
+ * - Non-extension commands (built-in, user, project) override earlier commands
+ * with the same name based on loader order
+ *
* @param loaders An array of objects that conform to the `ICommandLoader`
- * interface. The order of loaders is significant: if multiple loaders
- * provide a command with the same name, the command from the loader that
- * appears later in the array will take precedence.
+ * interface. Built-in commands should come first, followed by FileCommandLoader.
* @param signal An AbortSignal to cancel the loading process.
* @returns A promise that resolves to a new, fully initialized `CommandService` instance.
*/
@@ -57,12 +61,28 @@ export class CommandService {
}
}
- // De-duplicate commands using a Map. The last one found with a given name wins.
- // This creates a natural override system based on the order of the loaders
- // passed to the constructor.
const commandMap = new Map<string, SlashCommand>();
for (const cmd of allCommands) {
- commandMap.set(cmd.name, cmd);
+ let finalName = cmd.name;
+
+ // Extension commands get renamed if they conflict with existing commands
+ if (cmd.extensionName && commandMap.has(cmd.name)) {
+ let renamedName = `${cmd.extensionName}.${cmd.name}`;
+ let suffix = 1;
+
+ // Keep trying until we find a name that doesn't conflict
+ while (commandMap.has(renamedName)) {
+ renamedName = `${cmd.extensionName}.${cmd.name}${suffix}`;
+ suffix++;
+ }
+
+ finalName = renamedName;
+ }
+
+ commandMap.set(finalName, {
+ ...cmd,
+ name: finalName,
+ });
}
const finalCommands = Object.freeze(Array.from(commandMap.values()));