|
4 | 4 | *--------------------------------------------------------------------------------------------*/ |
5 | 5 |
|
6 | 6 | import * as vscode from 'vscode'; |
7 | | -import { CancellationToken } from 'vscode'; |
| 7 | +import { ILogService } from '../../../../platform/log/common/logService'; |
| 8 | +import { CancellationToken } from '../../../../util/vs/base/common/cancellation'; |
| 9 | +import { Disposable } from '../../../../util/vs/base/common/lifecycle'; |
8 | 10 | import { createDecorator, IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation'; |
9 | 11 | import { getClaudeSlashCommandRegistry, IClaudeSlashCommandHandler } from './slashCommands/claudeSlashCommandRegistry'; |
10 | 12 |
|
@@ -41,16 +43,17 @@ export interface IClaudeSlashCommandService { |
41 | 43 |
|
42 | 44 | export const IClaudeSlashCommandService = createDecorator<IClaudeSlashCommandService>('claudeSlashCommandService'); |
43 | 45 |
|
44 | | -export class ClaudeSlashCommandService implements IClaudeSlashCommandService { |
| 46 | +export class ClaudeSlashCommandService extends Disposable implements IClaudeSlashCommandService { |
45 | 47 | readonly _serviceBrand: undefined; |
46 | 48 |
|
47 | 49 | private _handlerCache = new Map<string, IClaudeSlashCommandHandler>(); |
48 | | - private _commandDisposables: vscode.Disposable[] = []; |
49 | 50 | private _initialized = false; |
50 | 51 |
|
51 | 52 | constructor( |
52 | 53 | @IInstantiationService private readonly instantiationService: IInstantiationService, |
| 54 | + @ILogService private readonly logService: ILogService, |
53 | 55 | ) { |
| 56 | + super(); |
54 | 57 | // Initialize eagerly to register VS Code commands at startup |
55 | 58 | this._ensureInitialized(); |
56 | 59 | } |
@@ -95,28 +98,23 @@ export class ClaudeSlashCommandService implements IClaudeSlashCommandService { |
95 | 98 | const ctors = getClaudeSlashCommandRegistry(); |
96 | 99 | for (const ctor of ctors) { |
97 | 100 | const handler = this.instantiationService.createInstance(ctor); |
98 | | - this._handlerCache.set(handler.commandName.toLowerCase(), handler); |
| 101 | + const commandKey = handler.commandName.toLowerCase(); |
| 102 | + // This shouldn't happen unless we accidentally register duplicates |
| 103 | + if (this._handlerCache.has(commandKey)) { |
| 104 | + this.logService.warn(`Duplicate Claude slash command name "${handler.commandName}" detected. Ignoring handler ${ctor.name || 'unknown constructor'}.`); |
| 105 | + continue; |
| 106 | + } |
| 107 | + this._handlerCache.set(commandKey, handler); |
99 | 108 |
|
100 | 109 | // Register VS Code command if commandId is provided |
101 | 110 | if (handler.commandId) { |
102 | | - const disposable = vscode.commands.registerCommand(handler.commandId, () => { |
103 | | - // Invoke with no args, no stream (Command Palette mode), and a cancellation token |
104 | | - const tokenSource = new vscode.CancellationTokenSource(); |
105 | | - handler.handle('', undefined, tokenSource.token).catch(err => { |
106 | | - vscode.window.showErrorMessage(`Command failed: ${err.message || err}`); |
107 | | - }); |
108 | | - }); |
109 | | - this._commandDisposables.push(disposable); |
| 111 | + this._register(vscode.commands.registerCommand(handler.commandId, () => { |
| 112 | + // Invoke with no args and no stream (Command Palette mode) |
| 113 | + return handler.handle('', undefined, CancellationToken.None); |
| 114 | + })); |
110 | 115 | } |
111 | 116 | } |
112 | 117 |
|
113 | 118 | this._initialized = true; |
114 | 119 | } |
115 | | - |
116 | | - dispose(): void { |
117 | | - for (const disposable of this._commandDisposables) { |
118 | | - disposable.dispose(); |
119 | | - } |
120 | | - this._commandDisposables = []; |
121 | | - } |
122 | 120 | } |
0 commit comments