wave-agent-sdk 1.0.5 → 1.0.7

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