wave-agent-sdk 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/dist/agent.d.ts +23 -1
  2. package/dist/agent.js +34 -4
  3. package/dist/managers/aiManager.d.ts +36 -0
  4. package/dist/managers/aiManager.js +240 -8
  5. package/dist/managers/messageManager.d.ts +1 -3
  6. package/dist/managers/messageManager.js +13 -6
  7. package/dist/managers/slashCommandManager.js +28 -0
  8. package/dist/managers/subagentManager.d.ts +0 -2
  9. package/dist/telemetry/instrumentation.d.ts +1 -1
  10. package/dist/telemetry/instrumentation.js +57 -28
  11. package/dist/tools/bashTool.js +16 -6
  12. package/dist/tools/grepTool.js +11 -3
  13. package/dist/types/index.d.ts +3 -0
  14. package/dist/types/messaging.d.ts +2 -0
  15. package/dist/utils/containerSetup.js +0 -3
  16. package/dist/utils/messageOperations.d.ts +2 -1
  17. package/dist/utils/messageOperations.js +2 -1
  18. package/dist/utils/notificationXml.js +5 -0
  19. package/dist/utils/ripgrep.d.ts +4 -4
  20. package/dist/utils/ripgrep.js +4 -27
  21. package/package.json +20 -8
  22. package/bin/rg +0 -79
  23. package/dist/managers/forkedAgentManager.d.ts +0 -50
  24. package/dist/managers/forkedAgentManager.js +0 -130
  25. package/scripts/install_ripgrep.js +0 -111
  26. package/scripts/postinstall.js +0 -38
  27. package/src/agent.ts +0 -1271
  28. package/src/constants/subagents.ts +0 -4
  29. package/src/constants/toolLimits.ts +0 -15
  30. package/src/constants/tools.ts +0 -24
  31. package/src/core/plugin.ts +0 -237
  32. package/src/core/session.ts +0 -9
  33. package/src/index.ts +0 -38
  34. package/src/managers/MemoryRuleManager.ts +0 -198
  35. package/src/managers/aiManager.ts +0 -2429
  36. package/src/managers/backgroundTaskManager.ts +0 -480
  37. package/src/managers/bangManager.ts +0 -119
  38. package/src/managers/cronManager.ts +0 -401
  39. package/src/managers/foregroundTaskManager.ts +0 -30
  40. package/src/managers/forkedAgentManager.ts +0 -216
  41. package/src/managers/hookManager.ts +0 -1089
  42. package/src/managers/liveConfigManager.ts +0 -445
  43. package/src/managers/lspManager.ts +0 -470
  44. package/src/managers/mcpManager.ts +0 -1010
  45. package/src/managers/messageManager.ts +0 -1184
  46. package/src/managers/messageQueue.ts +0 -157
  47. package/src/managers/permissionManager.ts +0 -1140
  48. package/src/managers/planManager.ts +0 -112
  49. package/src/managers/pluginManager.ts +0 -330
  50. package/src/managers/pluginScopeManager.ts +0 -124
  51. package/src/managers/reversionManager.ts +0 -178
  52. package/src/managers/skillManager.ts +0 -578
  53. package/src/managers/slashCommandManager.ts +0 -564
  54. package/src/managers/subagentManager.ts +0 -915
  55. package/src/managers/toolManager.ts +0 -489
  56. package/src/managers/workflowManager.ts +0 -493
  57. package/src/prompts/autoMemory.ts +0 -33
  58. package/src/prompts/autoMemoryExtraction.ts +0 -146
  59. package/src/prompts/index.ts +0 -506
  60. package/src/prompts/planModeReminders.ts +0 -126
  61. package/src/services/GitService.ts +0 -131
  62. package/src/services/MarketplaceService.ts +0 -1052
  63. package/src/services/MemoryRuleService.ts +0 -71
  64. package/src/services/aiService.ts +0 -919
  65. package/src/services/authService.ts +0 -565
  66. package/src/services/autoMemoryService.ts +0 -280
  67. package/src/services/configurationService.ts +0 -1520
  68. package/src/services/fileWatcher.ts +0 -319
  69. package/src/services/hook.ts +0 -348
  70. package/src/services/initializationService.ts +0 -357
  71. package/src/services/interactionService.ts +0 -229
  72. package/src/services/jsonlHandler.ts +0 -295
  73. package/src/services/memory.ts +0 -234
  74. package/src/services/pluginLoader.ts +0 -252
  75. package/src/services/remoteSettingsService.ts +0 -366
  76. package/src/services/reversionService.ts +0 -122
  77. package/src/services/session.ts +0 -917
  78. package/src/services/taskManager.ts +0 -321
  79. package/src/telemetry/events.ts +0 -65
  80. package/src/telemetry/instrumentation.ts +0 -499
  81. package/src/telemetry/sessionTracing.ts +0 -348
  82. package/src/tools/agentTool.ts +0 -322
  83. package/src/tools/askUserQuestion.ts +0 -160
  84. package/src/tools/bashTool.ts +0 -621
  85. package/src/tools/buildTool.ts +0 -61
  86. package/src/tools/cronCreateTool.ts +0 -161
  87. package/src/tools/cronDeleteTool.ts +0 -51
  88. package/src/tools/cronListTool.ts +0 -47
  89. package/src/tools/editTool.ts +0 -313
  90. package/src/tools/enterPlanMode.ts +0 -124
  91. package/src/tools/enterWorktreeTool.ts +0 -190
  92. package/src/tools/exitPlanMode.ts +0 -139
  93. package/src/tools/exitWorktreeTool.ts +0 -236
  94. package/src/tools/globTool.ts +0 -167
  95. package/src/tools/grepTool.ts +0 -399
  96. package/src/tools/lspTool.ts +0 -883
  97. package/src/tools/readTool.ts +0 -426
  98. package/src/tools/skillTool.ts +0 -248
  99. package/src/tools/taskManagementTools.ts +0 -574
  100. package/src/tools/taskStopTool.ts +0 -78
  101. package/src/tools/types.ts +0 -137
  102. package/src/tools/webFetchTool.ts +0 -373
  103. package/src/tools/workflowTool.ts +0 -205
  104. package/src/tools/writeTool.ts +0 -267
  105. package/src/types/agent.ts +0 -128
  106. package/src/types/auth.ts +0 -19
  107. package/src/types/commands.ts +0 -30
  108. package/src/types/config.ts +0 -43
  109. package/src/types/configuration.ts +0 -168
  110. package/src/types/core.ts +0 -105
  111. package/src/types/cron.ts +0 -13
  112. package/src/types/environment.ts +0 -106
  113. package/src/types/fileSearch.ts +0 -4
  114. package/src/types/history.ts +0 -7
  115. package/src/types/hooks.ts +0 -256
  116. package/src/types/index.ts +0 -41
  117. package/src/types/lsp.ts +0 -98
  118. package/src/types/marketplace.ts +0 -71
  119. package/src/types/mcp.ts +0 -43
  120. package/src/types/memoryRule.ts +0 -31
  121. package/src/types/messaging.ts +0 -114
  122. package/src/types/permissions.ts +0 -80
  123. package/src/types/plugins.ts +0 -39
  124. package/src/types/processes.ts +0 -99
  125. package/src/types/reversion.ts +0 -29
  126. package/src/types/session.ts +0 -12
  127. package/src/types/skills.ts +0 -108
  128. package/src/types/tasks.ts +0 -13
  129. package/src/types/telemetry.ts +0 -98
  130. package/src/types/tools.ts +0 -44
  131. package/src/types/workflow.ts +0 -6
  132. package/src/utils/abortUtils.ts +0 -118
  133. package/src/utils/atomicWrite.ts +0 -61
  134. package/src/utils/bashParser.ts +0 -899
  135. package/src/utils/cacheControlUtils.ts +0 -426
  136. package/src/utils/commandArgumentParser.ts +0 -161
  137. package/src/utils/commandPathResolver.ts +0 -88
  138. package/src/utils/configPaths.ts +0 -220
  139. package/src/utils/configValidator.ts +0 -100
  140. package/src/utils/constants.ts +0 -39
  141. package/src/utils/container.ts +0 -92
  142. package/src/utils/containerSetup.ts +0 -371
  143. package/src/utils/convertMessagesForAPI.ts +0 -326
  144. package/src/utils/cronTasks.ts +0 -128
  145. package/src/utils/cronTasksLock.ts +0 -182
  146. package/src/utils/cronToHuman.ts +0 -99
  147. package/src/utils/customCommands.ts +0 -95
  148. package/src/utils/editUtils.ts +0 -20
  149. package/src/utils/fileFormat.ts +0 -40
  150. package/src/utils/fileSearch.ts +0 -151
  151. package/src/utils/fileUtils.ts +0 -223
  152. package/src/utils/gitUtils.ts +0 -315
  153. package/src/utils/globalLogger.ts +0 -128
  154. package/src/utils/groupMessagesByApiRound.ts +0 -121
  155. package/src/utils/hookMatcher.ts +0 -176
  156. package/src/utils/markdownParser.ts +0 -317
  157. package/src/utils/mcpUtils.ts +0 -138
  158. package/src/utils/messageOperations.ts +0 -659
  159. package/src/utils/modelCapabilities.ts +0 -30
  160. package/src/utils/nameGenerator.ts +0 -99
  161. package/src/utils/notificationXml.ts +0 -57
  162. package/src/utils/openaiClient.ts +0 -251
  163. package/src/utils/parseCronExpression.ts +0 -78
  164. package/src/utils/path.ts +0 -72
  165. package/src/utils/pathEncoder.ts +0 -400
  166. package/src/utils/pathSafety.ts +0 -40
  167. package/src/utils/promptHistory.ts +0 -168
  168. package/src/utils/ripgrep.ts +0 -35
  169. package/src/utils/shellResolver.ts +0 -190
  170. package/src/utils/skillParser.ts +0 -246
  171. package/src/utils/stringUtils.ts +0 -156
  172. package/src/utils/subagentParser.ts +0 -279
  173. package/src/utils/taskReminder.ts +0 -96
  174. package/src/utils/tokenCalculation.ts +0 -43
  175. package/src/utils/tokenEstimate.ts +0 -34
  176. package/src/utils/toolResultStorage.ts +0 -117
  177. package/src/utils/worktreeSession.ts +0 -26
  178. package/src/utils/worktreeUtils.ts +0 -786
  179. package/src/workflow/budgetTracker.ts +0 -34
  180. package/src/workflow/concurrencyLimiter.ts +0 -47
  181. package/src/workflow/journal.ts +0 -95
  182. package/src/workflow/progressReporter.ts +0 -141
  183. package/src/workflow/runState.ts +0 -65
  184. package/src/workflow/scriptRuntime.ts +0 -274
  185. package/src/workflow/structuredOutput.ts +0 -123
  186. package/src/workflow/types.ts +0 -101
  187. package/src/workflow/workflowApis.ts +0 -410
  188. package/vendor/ripgrep/linux-aarch64/rg +0 -0
  189. package/vendor/ripgrep/linux-x86_64/rg +0 -0
  190. package/vendor/ripgrep/macos-aarch64/rg +0 -0
  191. package/vendor/ripgrep/macos-x86_64/rg +0 -0
  192. package/vendor/ripgrep/windows-aarch64/rg.exe +0 -0
  193. package/vendor/ripgrep/windows-x86_64/rg.exe +0 -0
@@ -1,564 +0,0 @@
1
- import type { MessageManager } from "./messageManager.js";
2
- import type { AIManager } from "./aiManager.js";
3
- import type { SlashCommand, CustomSlashCommand } from "../types/index.js";
4
- import { loadCustomSlashCommands } from "../utils/customCommands.js";
5
-
6
- import {
7
- substituteCommandParameters,
8
- parseSlashCommandInput,
9
- hasParameterPlaceholders,
10
- } from "../utils/commandArgumentParser.js";
11
- import { Container } from "../utils/container.js";
12
- import {
13
- parseBashCommands,
14
- replaceBashCommandsWithOutput,
15
- executeBashCommands,
16
- } from "../utils/markdownParser.js";
17
- import {
18
- countToolBlocks,
19
- formatToolTokenSummary,
20
- } from "../utils/messageOperations.js";
21
- import type { SkillManager } from "./skillManager.js";
22
- import type { SkillMetadata } from "../types/skills.js";
23
- import type { SubagentManager } from "./subagentManager.js";
24
- import { logger } from "../utils/globalLogger.js";
25
-
26
- export interface SlashCommandManagerOptions {
27
- workdir: string;
28
- }
29
-
30
- export class SlashCommandManager {
31
- private commands = new Map<string, SlashCommand>();
32
- private customCommands = new Map<string, CustomSlashCommand>();
33
- private skillCommandIds = new Set<string>();
34
- private workdir: string;
35
- private currentCommandAbortController: AbortController | null = null;
36
-
37
- constructor(
38
- private container: Container,
39
- options: SlashCommandManagerOptions,
40
- ) {
41
- this.workdir = options.workdir;
42
- }
43
-
44
- public initialize(): void {
45
- this.loadCustomCommands();
46
-
47
- // Listen for skill refreshes and update skill commands
48
- const skillManager = this.container.get<SkillManager>("SkillManager");
49
- if (skillManager) {
50
- skillManager.on("refreshed", (skills: SkillMetadata[]) => {
51
- this.registerSkillCommands(skills);
52
- });
53
- }
54
- }
55
-
56
- private get messageManager(): MessageManager {
57
- return this.container.get<MessageManager>("MessageManager")!;
58
- }
59
-
60
- private get aiManager(): AIManager {
61
- return this.container.get<AIManager>("AIManager")!;
62
- }
63
-
64
- private get skillManager(): SkillManager {
65
- return this.container.get<SkillManager>("SkillManager")!;
66
- }
67
-
68
- private get subagentManager(): SubagentManager {
69
- return this.container.get<SubagentManager>("SubagentManager")!;
70
- }
71
-
72
- /**
73
- * Load custom commands from filesystem
74
- */
75
- private loadCustomCommands(): void {
76
- try {
77
- const customCommands = loadCustomSlashCommands(this.workdir);
78
-
79
- for (const command of customCommands) {
80
- this.customCommands.set(command.id, command);
81
-
82
- // Generate description: prioritize custom description, otherwise use default description
83
- const description =
84
- command.description ||
85
- `Custom command: ${command.name}${hasParameterPlaceholders(command.content) ? " (supports parameters)" : ""}`;
86
-
87
- // Register as a regular command with a handler that executes the custom command
88
- this.registerCommand({
89
- id: command.id,
90
- name: command.name,
91
- description,
92
- handler: async (args?: string) => {
93
- // Substitute parameters in the command content
94
- let processedContent = command.content;
95
-
96
- if (args) {
97
- processedContent = substituteCommandParameters(
98
- processedContent,
99
- args,
100
- );
101
- }
102
-
103
- await this.executeCustomCommandInMainAgent(
104
- command.name,
105
- processedContent,
106
- command.config,
107
- );
108
- },
109
- });
110
- }
111
-
112
- logger?.debug(`Loaded ${customCommands.length} custom commands`);
113
- } catch (error) {
114
- logger?.warn("Failed to load custom commands:", error);
115
- }
116
- }
117
-
118
- /**
119
- * Register skills as slash commands
120
- */
121
- public registerSkillCommands(skills: SkillMetadata[]): void {
122
- // Clear existing skill commands
123
- for (const commandId of this.skillCommandIds) {
124
- this.unregisterCommand(commandId);
125
- }
126
- this.skillCommandIds.clear();
127
-
128
- for (const skill of skills) {
129
- if (skill.userInvocable === false) {
130
- continue;
131
- }
132
- const commandId = skill.name;
133
- this.skillCommandIds.add(commandId);
134
-
135
- this.registerCommand({
136
- id: commandId,
137
- name: skill.name,
138
- description: `Skill: ${skill.description}`,
139
- handler: async (args?: string, signal?: AbortSignal) => {
140
- try {
141
- // 1. Prepare skill content immediately
142
- const prepared = await this.skillManager.prepareSkill({
143
- skill_name: skill.name,
144
- args,
145
- });
146
-
147
- if (!prepared.skill) {
148
- // If skill not found or invalid, add error
149
- this.messageManager.addErrorBlock(prepared.content);
150
- return;
151
- }
152
-
153
- if (skill.context === "fork") {
154
- // Forked skill execution: add user message with text + tool block
155
- const messageId = this.messageManager.addUserMessage({
156
- content: `/${skill.name}${args ? ` ${args}` : ""}`,
157
- customCommandContent: prepared.content,
158
- });
159
-
160
- const toolBlockId = this.messageManager.addToolBlockToMessage(
161
- messageId,
162
- {
163
- name: skill.name,
164
- parameters: prepared.content,
165
- stage: "running",
166
- },
167
- );
168
-
169
- // Forked skill execution
170
- const subagentConfigs =
171
- await this.subagentManager.loadConfigurations();
172
- const subagentType = skill.agent || "general-purpose";
173
- const config = subagentConfigs.find(
174
- (c) => c.name === subagentType,
175
- );
176
- if (!config) {
177
- throw new Error(
178
- `Subagent configuration for ${subagentType} not found`,
179
- );
180
- }
181
-
182
- try {
183
- const instance = await this.subagentManager.createInstance(
184
- config,
185
- {
186
- description: skill.description,
187
- prompt: prepared.content,
188
- subagent_type: subagentType,
189
- model: skill.model,
190
- },
191
- false,
192
- () => {
193
- // Update the tool block with progress
194
- const subagent = this.subagentManager.getInstance(
195
- instance.subagentId,
196
- );
197
- if (subagent) {
198
- const messages = subagent.messages;
199
- const tokens =
200
- subagent.messageManager.getLatestTotalTokens();
201
- const usedTools = subagent.usedTools;
202
-
203
- const toolCount = countToolBlocks(messages);
204
- const summary = formatToolTokenSummary(toolCount, tokens);
205
-
206
- const getDisplayParam = (t: {
207
- name: string;
208
- parameters: string;
209
- compactParams?: string;
210
- stage?: string;
211
- }) => {
212
- if (
213
- (t.stage === "end" || t.stage === "running") &&
214
- t.compactParams
215
- ) {
216
- return t.compactParams;
217
- }
218
- const flat = t.parameters.replace(/\n/g, "\\n");
219
- return flat.length > 30 ? `…${flat.slice(-30)}` : flat;
220
- };
221
-
222
- let shortResult = "";
223
- if (toolCount > 2) {
224
- shortResult += "... ";
225
- }
226
- shortResult += summary;
227
- if (usedTools.length > 0) {
228
- shortResult +=
229
- "\n" +
230
- usedTools
231
- .map((t) => `${t.name} ${getDisplayParam(t)}`)
232
- .join("\n");
233
- }
234
-
235
- this.messageManager.updateToolBlock({
236
- id: toolBlockId,
237
- messageId,
238
- shortResult,
239
- });
240
- }
241
- },
242
- );
243
-
244
- // Show loading while subagent runs
245
- this.aiManager.setIsLoading(true);
246
- try {
247
- const result = await this.subagentManager.executeAgent(
248
- instance,
249
- prepared.content,
250
- signal,
251
- );
252
-
253
- // Update the ToolBlock with final result
254
- this.messageManager.updateToolBlock({
255
- id: toolBlockId,
256
- messageId,
257
- result,
258
- stage: "end",
259
- success: true,
260
- });
261
-
262
- // Trigger AI to process the tool result
263
- await this.aiManager.sendAIMessage();
264
- } finally {
265
- this.subagentManager.cleanupInstance(instance.subagentId);
266
- }
267
- } catch (error) {
268
- // Update the ToolBlock with error
269
- this.messageManager.updateToolBlock({
270
- id: toolBlockId,
271
- messageId,
272
- stage: "end",
273
- success: false,
274
- error: error instanceof Error ? error.message : String(error),
275
- });
276
- throw error; // Re-throw to be caught by outer catch for logging/error block
277
- }
278
- return;
279
- }
280
-
281
- // Non-forked skill: execute and trigger AI response
282
- this.aiManager.setIsLoading(true);
283
- const result = await this.skillManager.executeSkill({
284
- skill_name: skill.name,
285
- args,
286
- });
287
-
288
- // Add user message with the processed content
289
- this.messageManager.addUserMessage({
290
- content: `/${skill.name}${args ? ` ${args}` : ""}`,
291
- customCommandContent: result.content,
292
- });
293
-
294
- // Trigger AI response
295
- await this.aiManager.sendAIMessage({
296
- model: skill.model,
297
- allowedRules: result.allowedTools,
298
- });
299
- } catch (error) {
300
- this.aiManager.setIsLoading(false);
301
-
302
- logger?.error(error);
303
- this.messageManager.addErrorBlock(
304
- `Failed to execute skill command '${skill.name}': ${
305
- error instanceof Error ? error.message : String(error)
306
- }`,
307
- );
308
- }
309
- },
310
- });
311
- }
312
-
313
- logger?.debug(`Registered ${skills.length} skill commands`);
314
- }
315
-
316
- /**
317
- * Register commands from a plugin with namespacing
318
- */
319
- public registerPluginCommands(
320
- pluginName: string,
321
- commands: CustomSlashCommand[],
322
- ): void {
323
- for (const command of commands) {
324
- const namespacedId = `${pluginName}:${command.id}`;
325
- const namespacedName = `${pluginName}:${command.name}`;
326
-
327
- this.customCommands.set(namespacedId, command);
328
-
329
- // Generate description: prioritize custom description, otherwise use default description
330
- const description =
331
- command.description ||
332
- `Plugin command: ${namespacedName}${hasParameterPlaceholders(command.content) ? " (supports parameters)" : ""}`;
333
-
334
- this.registerCommand({
335
- id: namespacedId,
336
- name: namespacedName,
337
- description,
338
- handler: async (args?: string) => {
339
- // Substitute parameters in the command content
340
- let processedContent = command.content;
341
-
342
- if (args) {
343
- processedContent = substituteCommandParameters(
344
- processedContent,
345
- args,
346
- );
347
- }
348
-
349
- await this.executeCustomCommandInMainAgent(
350
- namespacedName,
351
- processedContent,
352
- command.config,
353
- args,
354
- );
355
- },
356
- });
357
- }
358
-
359
- logger?.debug(
360
- `Registered ${commands.length} commands from plugin '${pluginName}'`,
361
- );
362
- }
363
-
364
- /**
365
- * Reload custom commands (useful for development)
366
- */
367
- public reloadCustomCommands(): void {
368
- // Clear existing custom commands
369
- for (const commandId of this.customCommands.keys()) {
370
- this.unregisterCommand(commandId);
371
- }
372
- this.customCommands.clear();
373
-
374
- // Reload
375
- this.loadCustomCommands();
376
- }
377
-
378
- /**
379
- * Register new command
380
- */
381
- public registerCommand(command: SlashCommand): void {
382
- this.commands.set(command.id, command);
383
- }
384
-
385
- /**
386
- * Unregister command
387
- */
388
- private unregisterCommand(commandId: string): boolean {
389
- return this.commands.delete(commandId);
390
- }
391
-
392
- /**
393
- * Get all available commands
394
- */
395
- public getCommands(): SlashCommand[] {
396
- return Array.from(this.commands.values());
397
- }
398
-
399
- /**
400
- * Get command by ID
401
- */
402
- public getCommand(commandId: string): SlashCommand | undefined {
403
- return this.commands.get(commandId);
404
- }
405
-
406
- /**
407
- * Execute command
408
- */
409
- public async executeCommand(
410
- commandId: string,
411
- args?: string,
412
- ): Promise<boolean> {
413
- const command = this.commands.get(commandId);
414
- if (!command) {
415
- return false;
416
- }
417
-
418
- // Abort any previous command if it's still running
419
- this.currentCommandAbortController?.abort();
420
- this.currentCommandAbortController = new AbortController();
421
-
422
- try {
423
- await command.handler(args, this.currentCommandAbortController.signal);
424
- return true;
425
- } catch (error) {
426
- if (error instanceof Error && error.name === "AbortError") {
427
- logger?.debug(`Slash command ${commandId} was aborted`);
428
- } else {
429
- console.error(`Failed to execute slash command ${commandId}:`, error);
430
- }
431
- return false;
432
- } finally {
433
- this.currentCommandAbortController = null;
434
- // FR-013: Ensure slash commands are persisted to the session file
435
- await this.messageManager.saveSession();
436
- }
437
- }
438
-
439
- /**
440
- * Parse and validate a slash command input
441
- * Returns whether the command is valid along with parsed commandId and args
442
- */
443
- public parseAndValidateSlashCommand(input: string): {
444
- isValid: boolean;
445
- commandId?: string;
446
- args?: string;
447
- } {
448
- try {
449
- const { command: commandId, args } = parseSlashCommandInput(input);
450
- const isValid = this.hasCommand(commandId);
451
- return {
452
- isValid,
453
- commandId: isValid ? commandId : undefined,
454
- args: isValid ? args || undefined : undefined, // Convert empty string to undefined
455
- };
456
- } catch (error) {
457
- console.error(`Failed to parse slash command input "${input}":`, error);
458
- return { isValid: false };
459
- }
460
- }
461
-
462
- /**
463
- * Check if command exists
464
- */
465
- public hasCommand(commandId: string): boolean {
466
- return this.commands.has(commandId);
467
- }
468
-
469
- /**
470
- * Check if a slash command should bypass the message queue when AI is busy.
471
- * Returns true for commands marked as immediate (boolean or function).
472
- */
473
- public isImmediateCommand(input: string): boolean {
474
- const { command: commandId, args } = parseSlashCommandInput(input);
475
- const command = this.commands.get(commandId);
476
- if (!command?.immediate) return false;
477
- if (typeof command.immediate === "boolean") return command.immediate;
478
- return command.immediate(args);
479
- }
480
-
481
- /**
482
- * Get custom command details
483
- */
484
- public getCustomCommand(commandId: string): CustomSlashCommand | undefined {
485
- return this.customCommands.get(commandId);
486
- }
487
-
488
- /**
489
- * Get all custom commands
490
- */
491
- public getCustomCommands(): CustomSlashCommand[] {
492
- return Array.from(this.customCommands.values());
493
- }
494
-
495
- /**
496
- * Execute custom command in main agent instead of sub-agent
497
- */
498
- private async executeCustomCommandInMainAgent(
499
- commandName: string,
500
- content: string,
501
- config?: { model?: string; allowedTools?: string[] },
502
- args?: string,
503
- ): Promise<void> {
504
- try {
505
- // Set loading early so UI shows feedback during bash execution
506
- this.aiManager.setIsLoading(true);
507
-
508
- // Parse bash commands from the content
509
- const { commands, processedContent } = parseBashCommands(content);
510
-
511
- // Add user message immediately so text block shows before bash execution
512
- const messageId = this.messageManager.addUserMessage({
513
- content: `/${commandName}${args ? ` ${args}` : ""}`,
514
- customCommandContent: processedContent,
515
- });
516
-
517
- // Execute bash commands and update the message if any exist
518
- if (commands.length > 0) {
519
- const bashResults = await executeBashCommands(commands, this.workdir);
520
- const finalContent = replaceBashCommandsWithOutput(
521
- processedContent,
522
- bashResults,
523
- );
524
-
525
- // Update the user message with the bash-processed content
526
- this.messageManager.updateUserMessage(messageId, {
527
- customCommandContent: finalContent,
528
- });
529
- }
530
-
531
- // Execute the AI conversation with custom configuration
532
- await this.aiManager.sendAIMessage({
533
- model: config?.model,
534
- allowedRules: config?.allowedTools,
535
- });
536
- } catch (error) {
537
- this.aiManager.setIsLoading(false);
538
-
539
- logger?.error(
540
- `Failed to execute custom command '${commandName}':`,
541
- error,
542
- );
543
-
544
- // Add error to message manager
545
- this.messageManager.addErrorBlock(
546
- `Failed to execute custom command '${commandName}': ${
547
- error instanceof Error ? error.message : String(error)
548
- }`,
549
- );
550
- }
551
- }
552
-
553
- /**
554
- * Interrupt the currently executing slash command
555
- */
556
- public abortCurrentCommand(): void {
557
- // Abort the AI manager if it's running
558
- this.aiManager.abortAIMessage();
559
-
560
- // Abort the current slash command handler
561
- this.currentCommandAbortController?.abort();
562
- this.currentCommandAbortController = null;
563
- }
564
- }