| |
| |
| |
| |
| |
|
|
| import { debugLogger, coreEvents } from '@google/gemini-cli-core'; |
| import type { SlashCommand } from '../ui/commands/types.js'; |
| import type { ICommandLoader, CommandConflict } from './types.js'; |
| import { SlashCommandResolver } from './SlashCommandResolver.js'; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export class CommandService { |
| |
| |
| |
| |
| |
| private constructor( |
| private readonly commands: readonly SlashCommand[], |
| private readonly conflicts: readonly CommandConflict[], |
| ) {} |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static async create( |
| loaders: ICommandLoader[], |
| signal: AbortSignal, |
| ): Promise<CommandService> { |
| const allCommands = await this.loadAllCommands(loaders, signal); |
| const { finalCommands, conflicts } = |
| SlashCommandResolver.resolve(allCommands); |
|
|
| if (conflicts.length > 0) { |
| this.emitConflictEvents(conflicts); |
| } |
|
|
| return new CommandService( |
| Object.freeze(finalCommands), |
| Object.freeze(conflicts), |
| ); |
| } |
|
|
| |
| |
| |
| private static async loadAllCommands( |
| loaders: ICommandLoader[], |
| signal: AbortSignal, |
| ): Promise<SlashCommand[]> { |
| const results = await Promise.allSettled( |
| loaders.map((loader) => loader.loadCommands(signal)), |
| ); |
|
|
| const commands: SlashCommand[] = []; |
| for (const result of results) { |
| if (result.status === 'fulfilled') { |
| commands.push(...result.value); |
| } else { |
| debugLogger.debug('A command loader failed:', result.reason); |
| } |
| } |
| return commands; |
| } |
|
|
| |
| |
| |
| private static emitConflictEvents(conflicts: CommandConflict[]): void { |
| coreEvents.emitSlashCommandConflicts( |
| conflicts.flatMap((c) => |
| c.losers.map((l) => ({ |
| name: c.name, |
| renamedTo: l.renamedTo, |
| loserExtensionName: l.command.extensionName, |
| winnerExtensionName: l.reason.extensionName, |
| loserMcpServerName: l.command.mcpServerName, |
| winnerMcpServerName: l.reason.mcpServerName, |
| loserKind: l.command.kind, |
| winnerKind: l.reason.kind, |
| })), |
| ), |
| ); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| getCommands(): readonly SlashCommand[] { |
| return this.commands; |
| } |
|
|
| |
| |
| |
| |
| |
| getConflicts(): readonly CommandConflict[] { |
| return this.conflicts; |
| } |
| } |
|
|