wave-agent-sdk 1.0.4 → 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 (194) 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 +19 -9
  7. package/dist/managers/slashCommandManager.js +28 -0
  8. package/dist/managers/subagentManager.d.ts +0 -2
  9. package/dist/services/session.js +2 -9
  10. package/dist/telemetry/instrumentation.d.ts +1 -1
  11. package/dist/telemetry/instrumentation.js +57 -28
  12. package/dist/tools/bashTool.js +16 -6
  13. package/dist/tools/grepTool.js +11 -3
  14. package/dist/types/index.d.ts +3 -0
  15. package/dist/types/messaging.d.ts +2 -0
  16. package/dist/utils/containerSetup.js +0 -3
  17. package/dist/utils/messageOperations.d.ts +10 -1
  18. package/dist/utils/messageOperations.js +19 -1
  19. package/dist/utils/notificationXml.js +5 -0
  20. package/dist/utils/ripgrep.d.ts +4 -4
  21. package/dist/utils/ripgrep.js +4 -27
  22. package/package.json +20 -8
  23. package/bin/rg +0 -79
  24. package/dist/managers/forkedAgentManager.d.ts +0 -50
  25. package/dist/managers/forkedAgentManager.js +0 -130
  26. package/scripts/install_ripgrep.js +0 -111
  27. package/scripts/postinstall.js +0 -38
  28. package/src/agent.ts +0 -1271
  29. package/src/constants/subagents.ts +0 -4
  30. package/src/constants/toolLimits.ts +0 -15
  31. package/src/constants/tools.ts +0 -24
  32. package/src/core/plugin.ts +0 -237
  33. package/src/core/session.ts +0 -9
  34. package/src/index.ts +0 -38
  35. package/src/managers/MemoryRuleManager.ts +0 -198
  36. package/src/managers/aiManager.ts +0 -2429
  37. package/src/managers/backgroundTaskManager.ts +0 -480
  38. package/src/managers/bangManager.ts +0 -119
  39. package/src/managers/cronManager.ts +0 -401
  40. package/src/managers/foregroundTaskManager.ts +0 -30
  41. package/src/managers/forkedAgentManager.ts +0 -216
  42. package/src/managers/hookManager.ts +0 -1089
  43. package/src/managers/liveConfigManager.ts +0 -445
  44. package/src/managers/lspManager.ts +0 -470
  45. package/src/managers/mcpManager.ts +0 -1010
  46. package/src/managers/messageManager.ts +0 -1180
  47. package/src/managers/messageQueue.ts +0 -157
  48. package/src/managers/permissionManager.ts +0 -1140
  49. package/src/managers/planManager.ts +0 -112
  50. package/src/managers/pluginManager.ts +0 -330
  51. package/src/managers/pluginScopeManager.ts +0 -124
  52. package/src/managers/reversionManager.ts +0 -178
  53. package/src/managers/skillManager.ts +0 -578
  54. package/src/managers/slashCommandManager.ts +0 -564
  55. package/src/managers/subagentManager.ts +0 -915
  56. package/src/managers/toolManager.ts +0 -489
  57. package/src/managers/workflowManager.ts +0 -493
  58. package/src/prompts/autoMemory.ts +0 -33
  59. package/src/prompts/autoMemoryExtraction.ts +0 -146
  60. package/src/prompts/index.ts +0 -506
  61. package/src/prompts/planModeReminders.ts +0 -126
  62. package/src/services/GitService.ts +0 -131
  63. package/src/services/MarketplaceService.ts +0 -1052
  64. package/src/services/MemoryRuleService.ts +0 -71
  65. package/src/services/aiService.ts +0 -919
  66. package/src/services/authService.ts +0 -565
  67. package/src/services/autoMemoryService.ts +0 -280
  68. package/src/services/configurationService.ts +0 -1520
  69. package/src/services/fileWatcher.ts +0 -319
  70. package/src/services/hook.ts +0 -348
  71. package/src/services/initializationService.ts +0 -357
  72. package/src/services/interactionService.ts +0 -229
  73. package/src/services/jsonlHandler.ts +0 -295
  74. package/src/services/memory.ts +0 -234
  75. package/src/services/pluginLoader.ts +0 -252
  76. package/src/services/remoteSettingsService.ts +0 -366
  77. package/src/services/reversionService.ts +0 -122
  78. package/src/services/session.ts +0 -922
  79. package/src/services/taskManager.ts +0 -321
  80. package/src/telemetry/events.ts +0 -65
  81. package/src/telemetry/instrumentation.ts +0 -499
  82. package/src/telemetry/sessionTracing.ts +0 -348
  83. package/src/tools/agentTool.ts +0 -322
  84. package/src/tools/askUserQuestion.ts +0 -160
  85. package/src/tools/bashTool.ts +0 -621
  86. package/src/tools/buildTool.ts +0 -61
  87. package/src/tools/cronCreateTool.ts +0 -161
  88. package/src/tools/cronDeleteTool.ts +0 -51
  89. package/src/tools/cronListTool.ts +0 -47
  90. package/src/tools/editTool.ts +0 -313
  91. package/src/tools/enterPlanMode.ts +0 -124
  92. package/src/tools/enterWorktreeTool.ts +0 -190
  93. package/src/tools/exitPlanMode.ts +0 -139
  94. package/src/tools/exitWorktreeTool.ts +0 -236
  95. package/src/tools/globTool.ts +0 -167
  96. package/src/tools/grepTool.ts +0 -399
  97. package/src/tools/lspTool.ts +0 -883
  98. package/src/tools/readTool.ts +0 -426
  99. package/src/tools/skillTool.ts +0 -248
  100. package/src/tools/taskManagementTools.ts +0 -574
  101. package/src/tools/taskStopTool.ts +0 -78
  102. package/src/tools/types.ts +0 -137
  103. package/src/tools/webFetchTool.ts +0 -373
  104. package/src/tools/workflowTool.ts +0 -205
  105. package/src/tools/writeTool.ts +0 -267
  106. package/src/types/agent.ts +0 -128
  107. package/src/types/auth.ts +0 -19
  108. package/src/types/commands.ts +0 -30
  109. package/src/types/config.ts +0 -43
  110. package/src/types/configuration.ts +0 -168
  111. package/src/types/core.ts +0 -105
  112. package/src/types/cron.ts +0 -13
  113. package/src/types/environment.ts +0 -106
  114. package/src/types/fileSearch.ts +0 -4
  115. package/src/types/history.ts +0 -7
  116. package/src/types/hooks.ts +0 -256
  117. package/src/types/index.ts +0 -41
  118. package/src/types/lsp.ts +0 -98
  119. package/src/types/marketplace.ts +0 -71
  120. package/src/types/mcp.ts +0 -43
  121. package/src/types/memoryRule.ts +0 -31
  122. package/src/types/messaging.ts +0 -114
  123. package/src/types/permissions.ts +0 -80
  124. package/src/types/plugins.ts +0 -39
  125. package/src/types/processes.ts +0 -99
  126. package/src/types/reversion.ts +0 -29
  127. package/src/types/session.ts +0 -12
  128. package/src/types/skills.ts +0 -108
  129. package/src/types/tasks.ts +0 -13
  130. package/src/types/telemetry.ts +0 -98
  131. package/src/types/tools.ts +0 -44
  132. package/src/types/workflow.ts +0 -6
  133. package/src/utils/abortUtils.ts +0 -118
  134. package/src/utils/atomicWrite.ts +0 -61
  135. package/src/utils/bashParser.ts +0 -899
  136. package/src/utils/cacheControlUtils.ts +0 -426
  137. package/src/utils/commandArgumentParser.ts +0 -161
  138. package/src/utils/commandPathResolver.ts +0 -88
  139. package/src/utils/configPaths.ts +0 -220
  140. package/src/utils/configValidator.ts +0 -100
  141. package/src/utils/constants.ts +0 -39
  142. package/src/utils/container.ts +0 -92
  143. package/src/utils/containerSetup.ts +0 -371
  144. package/src/utils/convertMessagesForAPI.ts +0 -326
  145. package/src/utils/cronTasks.ts +0 -128
  146. package/src/utils/cronTasksLock.ts +0 -182
  147. package/src/utils/cronToHuman.ts +0 -99
  148. package/src/utils/customCommands.ts +0 -95
  149. package/src/utils/editUtils.ts +0 -20
  150. package/src/utils/fileFormat.ts +0 -40
  151. package/src/utils/fileSearch.ts +0 -151
  152. package/src/utils/fileUtils.ts +0 -223
  153. package/src/utils/gitUtils.ts +0 -315
  154. package/src/utils/globalLogger.ts +0 -128
  155. package/src/utils/groupMessagesByApiRound.ts +0 -121
  156. package/src/utils/hookMatcher.ts +0 -176
  157. package/src/utils/markdownParser.ts +0 -317
  158. package/src/utils/mcpUtils.ts +0 -138
  159. package/src/utils/messageOperations.ts +0 -641
  160. package/src/utils/modelCapabilities.ts +0 -30
  161. package/src/utils/nameGenerator.ts +0 -99
  162. package/src/utils/notificationXml.ts +0 -57
  163. package/src/utils/openaiClient.ts +0 -251
  164. package/src/utils/parseCronExpression.ts +0 -78
  165. package/src/utils/path.ts +0 -72
  166. package/src/utils/pathEncoder.ts +0 -400
  167. package/src/utils/pathSafety.ts +0 -40
  168. package/src/utils/promptHistory.ts +0 -168
  169. package/src/utils/ripgrep.ts +0 -35
  170. package/src/utils/shellResolver.ts +0 -190
  171. package/src/utils/skillParser.ts +0 -246
  172. package/src/utils/stringUtils.ts +0 -156
  173. package/src/utils/subagentParser.ts +0 -279
  174. package/src/utils/taskReminder.ts +0 -96
  175. package/src/utils/tokenCalculation.ts +0 -43
  176. package/src/utils/tokenEstimate.ts +0 -34
  177. package/src/utils/toolResultStorage.ts +0 -117
  178. package/src/utils/worktreeSession.ts +0 -26
  179. package/src/utils/worktreeUtils.ts +0 -786
  180. package/src/workflow/budgetTracker.ts +0 -34
  181. package/src/workflow/concurrencyLimiter.ts +0 -47
  182. package/src/workflow/journal.ts +0 -95
  183. package/src/workflow/progressReporter.ts +0 -141
  184. package/src/workflow/runState.ts +0 -65
  185. package/src/workflow/scriptRuntime.ts +0 -274
  186. package/src/workflow/structuredOutput.ts +0 -123
  187. package/src/workflow/types.ts +0 -101
  188. package/src/workflow/workflowApis.ts +0 -410
  189. package/vendor/ripgrep/linux-aarch64/rg +0 -0
  190. package/vendor/ripgrep/linux-x86_64/rg +0 -0
  191. package/vendor/ripgrep/macos-aarch64/rg +0 -0
  192. package/vendor/ripgrep/macos-x86_64/rg +0 -0
  193. package/vendor/ripgrep/windows-aarch64/rg.exe +0 -0
  194. 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
- }