wave-agent-sdk 0.2.1 → 0.5.0

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 +66 -20
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +156 -83
  4. package/dist/constants/prompts.d.ts +7 -2
  5. package/dist/constants/prompts.d.ts.map +1 -1
  6. package/dist/constants/prompts.js +41 -5
  7. package/dist/constants/tools.d.ts +2 -2
  8. package/dist/constants/tools.js +2 -2
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/managers/MemoryRuleManager.d.ts.map +1 -1
  13. package/dist/managers/MemoryRuleManager.js +16 -2
  14. package/dist/managers/aiManager.d.ts +14 -4
  15. package/dist/managers/aiManager.d.ts.map +1 -1
  16. package/dist/managers/aiManager.js +61 -9
  17. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  18. package/dist/managers/backgroundBashManager.js +1 -0
  19. package/dist/managers/backgroundTaskManager.d.ts +35 -0
  20. package/dist/managers/backgroundTaskManager.d.ts.map +1 -0
  21. package/dist/managers/backgroundTaskManager.js +249 -0
  22. package/dist/managers/bashManager.d.ts.map +1 -1
  23. package/dist/managers/bashManager.js +0 -3
  24. package/dist/managers/foregroundTaskManager.d.ts +9 -0
  25. package/dist/managers/foregroundTaskManager.d.ts.map +1 -0
  26. package/dist/managers/foregroundTaskManager.js +20 -0
  27. package/dist/managers/liveConfigManager.d.ts +1 -1
  28. package/dist/managers/liveConfigManager.d.ts.map +1 -1
  29. package/dist/managers/lspManager.d.ts.map +1 -1
  30. package/dist/managers/lspManager.js +3 -1
  31. package/dist/managers/messageManager.d.ts +34 -4
  32. package/dist/managers/messageManager.d.ts.map +1 -1
  33. package/dist/managers/messageManager.js +104 -13
  34. package/dist/managers/permissionManager.d.ts.map +1 -1
  35. package/dist/managers/permissionManager.js +11 -13
  36. package/dist/managers/pluginManager.d.ts.map +1 -1
  37. package/dist/managers/pluginManager.js +3 -2
  38. package/dist/managers/pluginScopeManager.d.ts +13 -2
  39. package/dist/managers/pluginScopeManager.d.ts.map +1 -1
  40. package/dist/managers/pluginScopeManager.js +38 -0
  41. package/dist/managers/reversionManager.d.ts +39 -0
  42. package/dist/managers/reversionManager.d.ts.map +1 -0
  43. package/dist/managers/reversionManager.js +118 -0
  44. package/dist/managers/slashCommandManager.d.ts +4 -1
  45. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  46. package/dist/managers/slashCommandManager.js +16 -6
  47. package/dist/managers/subagentManager.d.ts +13 -2
  48. package/dist/managers/subagentManager.d.ts.map +1 -1
  49. package/dist/managers/subagentManager.js +144 -35
  50. package/dist/managers/toolManager.d.ts +11 -1
  51. package/dist/managers/toolManager.d.ts.map +1 -1
  52. package/dist/managers/toolManager.js +11 -3
  53. package/dist/services/GitService.d.ts.map +1 -1
  54. package/dist/services/GitService.js +6 -2
  55. package/dist/services/MarketplaceService.d.ts +14 -1
  56. package/dist/services/MarketplaceService.d.ts.map +1 -1
  57. package/dist/services/MarketplaceService.js +72 -4
  58. package/dist/services/MemoryRuleService.d.ts +1 -1
  59. package/dist/services/MemoryRuleService.d.ts.map +1 -1
  60. package/dist/services/MemoryRuleService.js +13 -2
  61. package/dist/services/aiService.js +1 -1
  62. package/dist/services/configurationService.d.ts +18 -2
  63. package/dist/services/configurationService.d.ts.map +1 -1
  64. package/dist/services/configurationService.js +62 -0
  65. package/dist/services/fileWatcher.d.ts +0 -5
  66. package/dist/services/fileWatcher.d.ts.map +1 -1
  67. package/dist/services/fileWatcher.js +0 -11
  68. package/dist/services/memory.js +1 -1
  69. package/dist/services/pluginLoader.d.ts.map +1 -1
  70. package/dist/services/pluginLoader.js +6 -1
  71. package/dist/services/reversionService.d.ts +24 -0
  72. package/dist/services/reversionService.d.ts.map +1 -0
  73. package/dist/services/reversionService.js +76 -0
  74. package/dist/services/session.d.ts +7 -0
  75. package/dist/services/session.d.ts.map +1 -1
  76. package/dist/services/session.js +126 -3
  77. package/dist/tools/bashTool.d.ts +0 -8
  78. package/dist/tools/bashTool.d.ts.map +1 -1
  79. package/dist/tools/bashTool.js +52 -174
  80. package/dist/tools/deleteFileTool.d.ts.map +1 -1
  81. package/dist/tools/deleteFileTool.js +9 -0
  82. package/dist/tools/editTool.d.ts.map +1 -1
  83. package/dist/tools/editTool.js +15 -4
  84. package/dist/tools/multiEditTool.d.ts.map +1 -1
  85. package/dist/tools/multiEditTool.js +16 -5
  86. package/dist/tools/taskOutputTool.d.ts +3 -0
  87. package/dist/tools/taskOutputTool.d.ts.map +1 -0
  88. package/dist/tools/taskOutputTool.js +149 -0
  89. package/dist/tools/taskStopTool.d.ts +3 -0
  90. package/dist/tools/taskStopTool.d.ts.map +1 -0
  91. package/dist/tools/taskStopTool.js +65 -0
  92. package/dist/tools/taskTool.d.ts.map +1 -1
  93. package/dist/tools/taskTool.js +105 -63
  94. package/dist/tools/types.d.ts +7 -0
  95. package/dist/tools/types.d.ts.map +1 -1
  96. package/dist/tools/writeTool.d.ts.map +1 -1
  97. package/dist/tools/writeTool.js +9 -0
  98. package/dist/types/commands.d.ts +1 -0
  99. package/dist/types/commands.d.ts.map +1 -1
  100. package/dist/types/configuration.d.ts +3 -0
  101. package/dist/types/configuration.d.ts.map +1 -1
  102. package/dist/types/environment.d.ts +2 -1
  103. package/dist/types/environment.d.ts.map +1 -1
  104. package/dist/types/environment.js +0 -6
  105. package/dist/types/history.d.ts +5 -0
  106. package/dist/types/history.d.ts.map +1 -0
  107. package/dist/types/history.js +1 -0
  108. package/dist/types/index.d.ts +1 -0
  109. package/dist/types/index.d.ts.map +1 -1
  110. package/dist/types/index.js +1 -0
  111. package/dist/types/marketplace.d.ts +4 -0
  112. package/dist/types/marketplace.d.ts.map +1 -1
  113. package/dist/types/messaging.d.ts +7 -1
  114. package/dist/types/messaging.d.ts.map +1 -1
  115. package/dist/types/processes.d.ts +24 -4
  116. package/dist/types/processes.d.ts.map +1 -1
  117. package/dist/types/reversion.d.ts +29 -0
  118. package/dist/types/reversion.d.ts.map +1 -0
  119. package/dist/types/reversion.js +1 -0
  120. package/dist/utils/builtinSubagents.d.ts.map +1 -1
  121. package/dist/utils/builtinSubagents.js +16 -0
  122. package/dist/utils/constants.d.ts +2 -2
  123. package/dist/utils/constants.d.ts.map +1 -1
  124. package/dist/utils/constants.js +2 -2
  125. package/dist/utils/editUtils.d.ts +4 -9
  126. package/dist/utils/editUtils.d.ts.map +1 -1
  127. package/dist/utils/editUtils.js +54 -55
  128. package/dist/utils/messageOperations.d.ts +3 -1
  129. package/dist/utils/messageOperations.d.ts.map +1 -1
  130. package/dist/utils/messageOperations.js +8 -1
  131. package/dist/utils/openaiClient.d.ts.map +1 -1
  132. package/dist/utils/openaiClient.js +56 -26
  133. package/dist/utils/promptHistory.d.ts +20 -0
  134. package/dist/utils/promptHistory.d.ts.map +1 -0
  135. package/dist/utils/promptHistory.js +117 -0
  136. package/package.json +5 -3
  137. package/src/agent.ts +193 -109
  138. package/src/constants/prompts.ts +45 -5
  139. package/src/constants/tools.ts +2 -2
  140. package/src/index.ts +1 -1
  141. package/src/managers/MemoryRuleManager.ts +18 -2
  142. package/src/managers/aiManager.ts +87 -18
  143. package/src/managers/backgroundBashManager.ts +1 -0
  144. package/src/managers/backgroundTaskManager.ts +306 -0
  145. package/src/managers/bashManager.ts +0 -4
  146. package/src/managers/foregroundTaskManager.ts +26 -0
  147. package/src/managers/liveConfigManager.ts +2 -1
  148. package/src/managers/lspManager.ts +3 -1
  149. package/src/managers/messageManager.ts +136 -18
  150. package/src/managers/permissionManager.ts +11 -13
  151. package/src/managers/pluginManager.ts +4 -3
  152. package/src/managers/pluginScopeManager.ts +57 -8
  153. package/src/managers/reversionManager.ts +152 -0
  154. package/src/managers/slashCommandManager.ts +30 -7
  155. package/src/managers/subagentManager.ts +176 -31
  156. package/src/managers/toolManager.ts +23 -4
  157. package/src/services/GitService.ts +6 -2
  158. package/src/services/MarketplaceService.ts +100 -4
  159. package/src/services/MemoryRuleService.ts +18 -6
  160. package/src/services/aiService.ts +1 -1
  161. package/src/services/configurationService.ts +79 -1
  162. package/src/services/fileWatcher.ts +0 -13
  163. package/src/services/memory.ts +1 -1
  164. package/src/services/pluginLoader.ts +7 -1
  165. package/src/services/reversionService.ts +94 -0
  166. package/src/services/session.ts +161 -3
  167. package/src/tools/bashTool.ts +73 -200
  168. package/src/tools/deleteFileTool.ts +15 -0
  169. package/src/tools/editTool.ts +20 -10
  170. package/src/tools/multiEditTool.ts +21 -11
  171. package/src/tools/taskOutputTool.ts +174 -0
  172. package/src/tools/taskStopTool.ts +72 -0
  173. package/src/tools/taskTool.ts +130 -74
  174. package/src/tools/types.ts +7 -0
  175. package/src/tools/writeTool.ts +14 -0
  176. package/src/types/commands.ts +3 -0
  177. package/src/types/configuration.ts +4 -0
  178. package/src/types/environment.ts +3 -1
  179. package/src/types/history.ts +4 -0
  180. package/src/types/index.ts +1 -0
  181. package/src/types/marketplace.ts +5 -0
  182. package/src/types/messaging.ts +9 -1
  183. package/src/types/processes.ts +33 -4
  184. package/src/types/reversion.ts +29 -0
  185. package/src/utils/builtinSubagents.ts +18 -0
  186. package/src/utils/constants.ts +2 -2
  187. package/src/utils/editUtils.ts +66 -58
  188. package/src/utils/messageOperations.ts +10 -0
  189. package/src/utils/openaiClient.ts +69 -35
  190. package/src/utils/promptHistory.ts +133 -0
  191. package/dist/utils/bashHistory.d.ts +0 -50
  192. package/dist/utils/bashHistory.d.ts.map +0 -1
  193. package/dist/utils/bashHistory.js +0 -256
  194. package/src/utils/bashHistory.ts +0 -320
package/src/agent.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { ForegroundTaskManager } from "./managers/foregroundTaskManager.js";
1
2
  import {
2
3
  MessageManager,
3
4
  type MessageManagerCallbacks,
@@ -13,12 +14,14 @@ import { McpManager, type McpManagerCallbacks } from "./managers/mcpManager.js";
13
14
  import { LspManager } from "./managers/lspManager.js";
14
15
  import { BashManager } from "./managers/bashManager.js";
15
16
  import {
16
- BackgroundBashManager,
17
- type BackgroundBashManagerCallbacks,
18
- } from "./managers/backgroundBashManager.js";
17
+ BackgroundTaskManager,
18
+ type BackgroundTaskManagerCallbacks,
19
+ } from "./managers/backgroundTaskManager.js";
19
20
  import { SlashCommandManager } from "./managers/slashCommandManager.js";
20
21
  import { PluginManager } from "./managers/pluginManager.js";
21
22
  import { HookManager } from "./managers/hookManager.js";
23
+ import { ReversionManager } from "./managers/reversionManager.js";
24
+ import { ReversionService } from "./services/reversionService.js";
22
25
  import { PermissionManager } from "./managers/permissionManager.js";
23
26
  import { PlanManager } from "./managers/planManager.js";
24
27
  import type {
@@ -36,6 +39,8 @@ import type {
36
39
  Usage,
37
40
  PermissionMode,
38
41
  PermissionCallback,
42
+ BackgroundTask,
43
+ ForegroundTask,
39
44
  } from "./types/index.js";
40
45
  import { MemoryRuleManager } from "./managers/MemoryRuleManager.js";
41
46
  import { LiveConfigManager } from "./managers/liveConfigManager.js";
@@ -70,6 +75,8 @@ export interface AgentOptions {
70
75
  fastModel?: string;
71
76
  maxInputTokens?: number;
72
77
  maxTokens?: number;
78
+ /** Preferred language for agent communication */
79
+ language?: string;
73
80
 
74
81
  // Existing options (preserved)
75
82
  callbacks?: AgentCallbacks;
@@ -96,10 +103,12 @@ export interface AgentOptions {
96
103
 
97
104
  export interface AgentCallbacks
98
105
  extends MessageManagerCallbacks,
99
- BackgroundBashManagerCallbacks,
106
+ BackgroundTaskManagerCallbacks,
100
107
  McpManagerCallbacks,
101
108
  SubagentManagerCallbacks {
109
+ onTasksChange?: (tasks: BackgroundTask[]) => void;
102
110
  onPermissionModeChange?: (mode: PermissionMode) => void;
111
+ onBackgroundCurrentTask?: () => void;
103
112
  }
104
113
 
105
114
  export class Agent {
@@ -107,7 +116,7 @@ export class Agent {
107
116
  private aiManager: AIManager;
108
117
 
109
118
  private bashManager: BashManager | null = null;
110
- private backgroundBashManager: BackgroundBashManager;
119
+ private backgroundTaskManager: BackgroundTaskManager;
111
120
  private logger?: Logger; // Add optional logger property
112
121
  private toolManager: ToolManager; // Add tool registry instance
113
122
  private mcpManager: McpManager; // Add MCP manager instance
@@ -119,8 +128,10 @@ export class Agent {
119
128
  private pluginManager: PluginManager; // Add plugin manager instance
120
129
  private skillManager: SkillManager; // Add skill manager instance
121
130
  private hookManager: HookManager; // Add hooks manager instance
131
+ private reversionManager: ReversionManager;
122
132
  private memoryRuleManager: MemoryRuleManager; // Add memory rule manager instance
123
133
  private liveConfigManager: LiveConfigManager; // Add live configuration manager
134
+ private foregroundTaskManager: ForegroundTaskManager;
124
135
  private configurationService: ConfigurationService; // Add configuration service
125
136
  private workdir: string; // Working directory
126
137
  private systemPrompt?: string; // Custom system prompt
@@ -160,44 +171,8 @@ export class Agent {
160
171
  );
161
172
  }
162
173
 
163
- /**
164
- * Update agent configuration dynamically
165
- *
166
- * @param config - Configuration updates for gateway, model, and token limit
167
- */
168
- public updateConfig(config: {
169
- gateway?: Partial<GatewayConfig>;
170
- model?: Partial<ModelConfig>;
171
- maxInputTokens?: number;
172
- maxTokens?: number;
173
- }): void {
174
- if (config.gateway) {
175
- this.options.apiKey = config.gateway.apiKey ?? this.options.apiKey;
176
- this.options.baseURL = config.gateway.baseURL ?? this.options.baseURL;
177
- this.options.defaultHeaders =
178
- config.gateway.defaultHeaders ?? this.options.defaultHeaders;
179
- this.options.fetchOptions =
180
- config.gateway.fetchOptions ?? this.options.fetchOptions;
181
- this.options.fetch = config.gateway.fetch ?? this.options.fetch;
182
- }
183
-
184
- if (config.model) {
185
- this.options.agentModel =
186
- config.model.agentModel ?? this.options.agentModel;
187
- this.options.fastModel = config.model.fastModel ?? this.options.fastModel;
188
- this.options.maxTokens = config.model.maxTokens ?? this.options.maxTokens;
189
- }
190
-
191
- if (config.maxInputTokens !== undefined) {
192
- this.options.maxInputTokens = config.maxInputTokens;
193
- }
194
-
195
- if (config.maxTokens !== undefined) {
196
- this.options.maxTokens = config.maxTokens;
197
- }
198
-
199
- // Re-validate configuration after update
200
- this.resolveAndValidateConfig();
174
+ public getLanguage(): string | undefined {
175
+ return this.configurationService.resolveLanguage(this.options.language);
201
176
  }
202
177
 
203
178
  /**
@@ -231,8 +206,15 @@ export class Agent {
231
206
  // Store options for dynamic configuration resolution
232
207
  this.options = options;
233
208
 
234
- this.backgroundBashManager = new BackgroundBashManager({
235
- callbacks,
209
+ this.foregroundTaskManager = new ForegroundTaskManager();
210
+
211
+ this.backgroundTaskManager = new BackgroundTaskManager({
212
+ callbacks: {
213
+ ...callbacks,
214
+ onTasksChange: (tasks) => {
215
+ callbacks.onTasksChange?.(tasks);
216
+ },
217
+ },
236
218
  workdir: this.workdir,
237
219
  });
238
220
  this.mcpManager = new McpManager({ callbacks, logger: this.logger }); // Initialize MCP manager
@@ -261,17 +243,23 @@ export class Agent {
261
243
  workdir: this.workdir,
262
244
  });
263
245
 
246
+ // Initialize memory rule manager
247
+ this.memoryRuleManager = new MemoryRuleManager({
248
+ workdir: this.workdir,
249
+ });
250
+
264
251
  // Initialize MessageManager
265
252
  this.messageManager = new MessageManager({
266
253
  callbacks,
267
254
  workdir: this.workdir,
268
255
  logger: this.logger,
256
+ memoryRuleManager: this.memoryRuleManager,
269
257
  });
270
258
 
271
- // Initialize memory rule manager
272
- this.memoryRuleManager = new MemoryRuleManager({
273
- workdir: this.workdir,
274
- });
259
+ // Initialize ReversionManager
260
+ this.reversionManager = new ReversionManager(
261
+ new ReversionService(this.messageManager.getTranscriptPath()),
262
+ );
275
263
 
276
264
  // Create a wrapper for canUseTool that triggers notification hooks
277
265
  const canUseToolWithNotification: PermissionCallback | undefined =
@@ -321,8 +309,11 @@ export class Agent {
321
309
  lspManager: this.lspManager,
322
310
  logger: this.logger,
323
311
  permissionManager: this.permissionManager,
312
+ reversionManager: this.reversionManager,
324
313
  permissionMode: options.permissionMode, // Let PermissionManager handle defaultMode resolution
325
314
  canUseToolCallback: canUseToolWithNotification,
315
+ backgroundTaskManager: this.backgroundTaskManager,
316
+ foregroundTaskManager: this.foregroundTaskManager,
326
317
  }); // Initialize tool registry with permission support
327
318
  this.liveConfigManager = new LiveConfigManager({
328
319
  workdir: this.workdir,
@@ -353,8 +344,11 @@ export class Agent {
353
344
  getGatewayConfig: () => this.getGatewayConfig(),
354
345
  getModelConfig: () => this.getModelConfig(),
355
346
  getMaxInputTokens: () => this.getMaxInputTokens(),
347
+ getLanguage: () => this.getLanguage(),
356
348
  hookManager: this.hookManager,
357
349
  onUsageAdded: (usage) => this.addUsage(usage),
350
+ backgroundTaskManager: this.backgroundTaskManager,
351
+ memoryRuleManager: this.memoryRuleManager,
358
352
  });
359
353
 
360
354
  // Initialize AI manager with resolved configuration
@@ -362,7 +356,7 @@ export class Agent {
362
356
  messageManager: this.messageManager,
363
357
  toolManager: this.toolManager,
364
358
  logger: this.logger,
365
- backgroundBashManager: this.backgroundBashManager,
359
+ backgroundTaskManager: this.backgroundTaskManager,
366
360
  hookManager: this.hookManager,
367
361
  permissionManager: this.permissionManager,
368
362
  callbacks: {
@@ -374,9 +368,11 @@ export class Agent {
374
368
  workdir: this.workdir,
375
369
  systemPrompt: this.systemPrompt,
376
370
  stream: this.stream, // Pass streaming mode flag
371
+ reversionManager: this.reversionManager,
377
372
  getGatewayConfig: () => this.getGatewayConfig(),
378
373
  getModelConfig: () => this.getModelConfig(),
379
374
  getMaxInputTokens: () => this.getMaxInputTokens(),
375
+ getLanguage: () => this.getLanguage(),
380
376
  getEnvironmentVars: () => this.configurationService.getEnvironmentVars(), // Provide access to configuration environment variables
381
377
  });
382
378
 
@@ -384,6 +380,7 @@ export class Agent {
384
380
  this.slashCommandManager = new SlashCommandManager({
385
381
  messageManager: this.messageManager,
386
382
  aiManager: this.aiManager,
383
+ backgroundTaskManager: this.backgroundTaskManager,
387
384
  workdir: this.workdir,
388
385
  logger: this.logger,
389
386
  });
@@ -478,29 +475,8 @@ export class Agent {
478
475
  }
479
476
 
480
477
  /** Get combined memory content (project + user + modular rules) */
481
- public get combinedMemory(): string {
482
- let combined = "";
483
- if (this._projectMemoryContent.trim()) {
484
- combined += this._projectMemoryContent;
485
- }
486
- if (this._userMemoryContent.trim()) {
487
- if (combined) {
488
- combined += "\n\n";
489
- }
490
- combined += this._userMemoryContent;
491
- }
492
-
493
- // Add modular memory rules
494
- const filesInContext = this.messageManager.getFilesInContext();
495
- const activeRules = this.memoryRuleManager.getActiveRules(filesInContext);
496
- if (activeRules.length > 0) {
497
- if (combined) {
498
- combined += "\n\n";
499
- }
500
- combined += activeRules.map((r) => r.content).join("\n\n");
501
- }
502
-
503
- return combined;
478
+ public async getCombinedMemory(): Promise<string> {
479
+ return this.messageManager.getCombinedMemory();
504
480
  }
505
481
 
506
482
  /** Get AI loading status */
@@ -523,12 +499,25 @@ export class Agent {
523
499
  id: string,
524
500
  filter?: string,
525
501
  ): { stdout: string; stderr: string; status: string } | null {
526
- return this.backgroundBashManager.getOutput(id, filter);
502
+ return this.backgroundTaskManager.getOutput(id, filter);
527
503
  }
528
504
 
529
505
  /** Kill background bash shell */
530
506
  public killBackgroundShell(id: string): boolean {
531
- return this.backgroundBashManager.killShell(id);
507
+ return this.backgroundTaskManager.stopTask(id);
508
+ }
509
+
510
+ /** Get background task output */
511
+ public getBackgroundTaskOutput(
512
+ id: string,
513
+ filter?: string,
514
+ ): { stdout: string; stderr: string; status: string } | null {
515
+ return this.backgroundTaskManager.getOutput(id, filter);
516
+ }
517
+
518
+ /** Stop background task */
519
+ public stopBackgroundTask(id: string): boolean {
520
+ return this.backgroundTaskManager.stopTask(id);
532
521
  }
533
522
 
534
523
  /**
@@ -667,6 +656,9 @@ export class Agent {
667
656
  // Resolve and validate configuration after loading settings.json
668
657
  this.resolveAndValidateConfig();
669
658
 
659
+ // Set global logger for SDK-wide access before discovering rules
660
+ setGlobalLogger(this.logger || null);
661
+
670
662
  // Discover modular memory rules
671
663
  try {
672
664
  await this.memoryRuleManager.discoverRules();
@@ -674,9 +666,6 @@ export class Agent {
674
666
  this.logger?.error("Failed to discover memory rules:", error);
675
667
  }
676
668
 
677
- // Set global logger for SDK-wide access after validation
678
- setGlobalLogger(this.logger || null);
679
-
680
669
  // Initialize live configuration reload
681
670
  try {
682
671
  this.logger?.debug("Initializing live configuration reload...");
@@ -955,14 +944,42 @@ export class Agent {
955
944
  this.slashCommandManager.abortCurrentCommand();
956
945
  }
957
946
 
947
+ /**
948
+ * Register a foreground task that can be backgrounded
949
+ */
950
+ public registerForegroundTask(task: ForegroundTask): void {
951
+ this.foregroundTaskManager.registerForegroundTask(task);
952
+ }
953
+
954
+ /**
955
+ * Unregister a foreground task
956
+ */
957
+ public unregisterForegroundTask(id: string): void {
958
+ this.foregroundTaskManager.unregisterForegroundTask(id);
959
+ }
960
+
961
+ /**
962
+ * Background the current foreground task
963
+ */
964
+ public async backgroundCurrentTask(): Promise<void> {
965
+ await this.foregroundTaskManager.backgroundCurrentTask();
966
+ this.options.callbacks?.onBackgroundCurrentTask?.();
967
+
968
+ // If there was no foreground task (e.g. a tool that doesn't register one),
969
+ // or even if there was, we should stop the AI recursion loop.
970
+ if (!this.foregroundTaskManager.hasActiveTasks()) {
971
+ this.aiManager.abortRecursion();
972
+ }
973
+ }
974
+
958
975
  /** Destroy managers, clean up resources */
959
976
  public async destroy(): Promise<void> {
960
977
  await this.messageManager.saveSession();
961
978
  this.abortAIMessage(); // This will abort tools including Task tool (subagents)
962
979
  this.abortBashCommand();
963
980
  this.abortSlashCommand();
964
- // Cleanup background bash manager
965
- this.backgroundBashManager.cleanup();
981
+ // Cleanup background task manager
982
+ this.backgroundTaskManager.cleanup();
966
983
  // Cleanup MCP connections
967
984
  await this.mcpManager.cleanup();
968
985
  // Cleanup LSP connections
@@ -983,6 +1000,23 @@ export class Agent {
983
1000
  // Cleanup memory store
984
1001
  }
985
1002
 
1003
+ /**
1004
+ * Get a subagent instance by its ID
1005
+ * @param subagentId - The ID of the subagent instance
1006
+ */
1007
+ public getSubagentInstance(
1008
+ subagentId: string,
1009
+ ): import("./managers/subagentManager.js").SubagentInstance | null {
1010
+ return this.subagentManager.getInstance(subagentId);
1011
+ }
1012
+
1013
+ /**
1014
+ * Trigger the rewind UI callback
1015
+ */
1016
+ public triggerShowRewind(): void {
1017
+ this.messageManager.triggerShowRewind();
1018
+ }
1019
+
986
1020
  /**
987
1021
  * Send a message to the AI agent with optional images
988
1022
  *
@@ -1122,12 +1156,18 @@ export class Agent {
1122
1156
  const typeLabel = type === "project" ? "Project Memory" : "User Memory";
1123
1157
  const storagePath = "AGENTS.md";
1124
1158
 
1125
- this.messageManager.addMemoryBlock(
1126
- `${typeLabel}: ${memoryText}`,
1127
- true,
1128
- type,
1129
- storagePath,
1130
- );
1159
+ const messages = this.messageManager.getMessages();
1160
+ const lastMessage = messages[messages.length - 1];
1161
+ if (lastMessage && lastMessage.role === "assistant") {
1162
+ lastMessage.blocks.push({
1163
+ type: "memory",
1164
+ content: `${typeLabel}: ${memoryText}`,
1165
+ isSuccess: true,
1166
+ memoryType: type,
1167
+ storagePath,
1168
+ });
1169
+ this.messageManager.setMessages(messages);
1170
+ }
1131
1171
  } catch (error) {
1132
1172
  // Add failed MemoryBlock to the last assistant message
1133
1173
  const memoryText = message.substring(1).trim();
@@ -1136,12 +1176,18 @@ export class Agent {
1136
1176
  const errorMessage =
1137
1177
  error instanceof Error ? error.message : String(error);
1138
1178
 
1139
- this.messageManager.addMemoryBlock(
1140
- `${typeLabel}: ${memoryText} - Error: ${errorMessage}`,
1141
- false,
1142
- type,
1143
- storagePath,
1144
- );
1179
+ const messages = this.messageManager.getMessages();
1180
+ const lastMessage = messages[messages.length - 1];
1181
+ if (lastMessage && lastMessage.role === "assistant") {
1182
+ lastMessage.blocks.push({
1183
+ type: "memory",
1184
+ content: `${typeLabel}: ${memoryText} - Error: ${errorMessage}`,
1185
+ isSuccess: false,
1186
+ memoryType: type,
1187
+ storagePath,
1188
+ });
1189
+ this.messageManager.setMessages(messages);
1190
+ }
1145
1191
  }
1146
1192
  }
1147
1193
 
@@ -1189,6 +1235,13 @@ export class Agent {
1189
1235
  return this.slashCommandManager.getCustomCommands();
1190
1236
  }
1191
1237
 
1238
+ /**
1239
+ * Register a custom slash command
1240
+ */
1241
+ public registerSlashCommand(command: SlashCommand): void {
1242
+ this.slashCommandManager.registerCommand(command);
1243
+ }
1244
+
1192
1245
  /**
1193
1246
  * Get the current permission mode
1194
1247
  */
@@ -1210,30 +1263,41 @@ export class Agent {
1210
1263
  }
1211
1264
 
1212
1265
  /**
1213
- * Handle plan mode transition, generating or clearing plan file path
1214
- * @param mode - The current effective permission mode
1266
+ * Truncate history to a specific index and revert file changes.
1267
+ * @param index - The index of the user message to truncate to.
1215
1268
  */
1216
- private handlePlanModeTransition(mode: PermissionMode): void {
1217
- if (mode === "plan") {
1218
- this.planManager
1219
- .getOrGeneratePlanFilePath()
1220
- .then(({ path }) => {
1221
- this.logger?.debug("Plan file path generated", { path });
1222
- this.permissionManager.setPlanFilePath(path);
1223
- })
1224
- .catch((error) => {
1225
- this.logger?.error("Failed to generate plan file path", error);
1226
- });
1227
- } else {
1228
- this.permissionManager.setPlanFilePath(undefined);
1229
- }
1269
+ public async truncateHistory(index: number): Promise<void> {
1270
+ await this.messageManager.truncateHistory(index, this.reversionManager);
1271
+ }
1272
+
1273
+ /**
1274
+ * Get the current plan file path (for testing and UI)
1275
+ */
1276
+ public getPlanFilePath(): string | undefined {
1277
+ return this.permissionManager.getPlanFilePath();
1278
+ }
1279
+
1280
+ /**
1281
+ * Get all currently allowed rules (for testing and UI)
1282
+ */
1283
+ public getAllowedRules(): string[] {
1284
+ return this.permissionManager.getAllowedRules();
1285
+ }
1286
+
1287
+ /**
1288
+ * Check permission for a tool call (for testing)
1289
+ */
1290
+ public async checkPermission(
1291
+ context: import("./types/permissions.js").ToolPermissionContext,
1292
+ ): Promise<import("./types/permissions.js").PermissionDecision> {
1293
+ return this.permissionManager.checkPermission(context);
1230
1294
  }
1231
1295
 
1232
1296
  /**
1233
1297
  * Add a persistent permission rule
1234
1298
  * @param rule - The rule to add (e.g., "Bash(ls)")
1235
1299
  */
1236
- private async addPermissionRule(rule: string): Promise<void> {
1300
+ public async addPermissionRule(rule: string): Promise<void> {
1237
1301
  // 1. Expand rule if it's a Bash command
1238
1302
  let rulesToAdd = [rule];
1239
1303
  const bashMatch = rule.match(/^Bash\((.*)\)$/);
@@ -1266,4 +1330,24 @@ export class Agent {
1266
1330
  }
1267
1331
  }
1268
1332
  }
1333
+
1334
+ /**
1335
+ * Handle plan mode transition, generating or clearing plan file path
1336
+ * @param mode - The current effective permission mode
1337
+ */
1338
+ private handlePlanModeTransition(mode: PermissionMode): void {
1339
+ if (mode === "plan") {
1340
+ this.planManager
1341
+ .getOrGeneratePlanFilePath()
1342
+ .then(({ path }) => {
1343
+ this.logger?.debug("Plan file path generated", { path });
1344
+ this.permissionManager.setPlanFilePath(path);
1345
+ })
1346
+ .catch((error) => {
1347
+ this.logger?.error("Failed to generate plan file path", error);
1348
+ });
1349
+ } else {
1350
+ this.permissionManager.setPlanFilePath(undefined);
1351
+ }
1352
+ }
1269
1353
  }
@@ -44,8 +44,11 @@ export const SUBAGENT_POLICY = `
44
44
  - You should proactively use the ${TASK_TOOL_NAME} tool with specialized agents when the task at hand matches the agent's description.
45
45
  - VERY IMPORTANT: When exploring the codebase to gather context or to answer a question that is not a needle query for a specific file/class/function, it is CRITICAL that you use the ${TASK_TOOL_NAME} tool with subagent_type=Explore instead of running search commands directly.`;
46
46
 
47
- export const FILE_TOOL_POLICY = `
48
- - Use specialized tools instead of bash commands when possible, as this provides a better user experience. For file operations, use dedicated tools: ${READ_TOOL_NAME} for reading files instead of cat/head/tail, ${EDIT_TOOL_NAME}/${MULTI_EDIT_TOOL_NAME} for editing instead of sed/awk, ${WRITE_TOOL_NAME} for creating files instead of cat with heredoc or echo redirection, and ${LS_TOOL_NAME}/${GLOB_TOOL_NAME}/${GREP_TOOL_NAME} for searching and listing files instead of find/ls/grep.`;
47
+ export const FILE_TOOL_POLICY_PREFIX = `\n- Use specialized tools instead of bash commands when possible, as this provides a better user experience. For file operations, use dedicated tools:`;
48
+ export const READ_FILE_POLICY = ` ${READ_TOOL_NAME} for reading files instead of cat/head/tail`;
49
+ export const EDIT_FILE_POLICY = ` ${EDIT_TOOL_NAME}/${MULTI_EDIT_TOOL_NAME} for editing instead of sed/awk`;
50
+ export const WRITE_FILE_POLICY = ` ${WRITE_TOOL_NAME} for creating files instead of cat with heredoc or echo redirection`;
51
+ export const SEARCH_FILE_POLICY = ` ${LS_TOOL_NAME}/${GLOB_TOOL_NAME}/${GREP_TOOL_NAME} for searching and listing files instead of find/ls/grep`;
49
52
 
50
53
  export const BASH_POLICY = `
51
54
  - Reserve bash tools exclusively for actual system commands and terminal operations that require shell execution. NEVER use bash echo or other command-line tools to communicate thoughts, explanations, or instructions to the user. Output all communication directly in your response text instead.
@@ -53,7 +56,24 @@ export const BASH_POLICY = `
53
56
 
54
57
  export const DEFAULT_SYSTEM_PROMPT = BASE_SYSTEM_PROMPT;
55
58
 
56
- export const INIT_PROMPT = `Please analyze this codebase and create a AGENTS.md file, which will be given to future instances of Wave Code to operate in this repository.
59
+ export const GENERAL_PURPOSE_SYSTEM_PROMPT = `You are an agent. Given the user's message, you should use the tools available to complete the task. Do what has been asked; nothing more, nothing less. When you complete the task simply respond with a detailed writeup.
60
+
61
+ Your strengths:
62
+ - Searching for code, configurations, and patterns across large codebases
63
+ - Analyzing multiple files to understand system architecture
64
+ - Investigating complex questions that require exploring many files
65
+ - Performing multi-step research tasks
66
+
67
+ Guidelines:
68
+ - For file searches: Use Grep or Glob when you need to search broadly. Use Read when you know the specific file path.
69
+ - For analysis: Start broad and narrow down. Use multiple search strategies if the first doesn't yield results.
70
+ - Be thorough: Check multiple locations, consider different naming conventions, look for related files.
71
+ - NEVER create files unless they're absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one.
72
+ - NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested.
73
+ - In your final response always share relevant file names and code snippets. Any file paths you return in your response MUST be absolute. Do NOT use relative paths.
74
+ - For clear communication, avoid using emojis.`;
75
+
76
+ export const INIT_PROMPT = `Please analyze this codebase and create a AGENTS.md file, which will be given to future instances of Agent to operate in this repository.
57
77
 
58
78
  What to add:
59
79
  1. Commands that will be commonly used, such as how to build, lint, and run tests. Include the necessary commands to develop in this codebase, such as how to run a single test.
@@ -72,7 +92,7 @@ Usage notes:
72
92
  \`\`\`
73
93
  # AGENTS.md
74
94
 
75
- This file provides guidance to Wave Code when working with code in this repository.
95
+ This file provides guidance to Agent when working with code in this repository.
76
96
  \`\`\``;
77
97
 
78
98
  export function buildSystemPrompt(
@@ -104,7 +124,27 @@ export function buildSystemPrompt(
104
124
  toolNames.has(GLOB_TOOL_NAME) ||
105
125
  toolNames.has(GREP_TOOL_NAME)
106
126
  ) {
107
- prompt += FILE_TOOL_POLICY;
127
+ const parts: string[] = [];
128
+ if (toolNames.has(READ_TOOL_NAME)) {
129
+ parts.push(READ_FILE_POLICY);
130
+ }
131
+ if (toolNames.has(EDIT_TOOL_NAME) || toolNames.has(MULTI_EDIT_TOOL_NAME)) {
132
+ parts.push(EDIT_FILE_POLICY);
133
+ }
134
+ if (toolNames.has(WRITE_TOOL_NAME)) {
135
+ parts.push(WRITE_FILE_POLICY);
136
+ }
137
+ if (
138
+ toolNames.has(LS_TOOL_NAME) ||
139
+ toolNames.has(GLOB_TOOL_NAME) ||
140
+ toolNames.has(GREP_TOOL_NAME)
141
+ ) {
142
+ parts.push(SEARCH_FILE_POLICY);
143
+ }
144
+
145
+ if (parts.length > 0) {
146
+ prompt += FILE_TOOL_POLICY_PREFIX + parts.join(",") + ".";
147
+ }
108
148
  }
109
149
 
110
150
  if (toolNames.has(BASH_TOOL_NAME)) {
@@ -1,7 +1,7 @@
1
1
  export const ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion";
2
2
  export const BASH_TOOL_NAME = "Bash";
3
- export const BASH_OUTPUT_TOOL_NAME = "BashOutput";
4
- export const KILL_BASH_TOOL_NAME = "KillBash";
3
+ export const TASK_OUTPUT_TOOL_NAME = "TaskOutput";
4
+ export const TASK_STOP_TOOL_NAME = "TaskStop";
5
5
  export const DELETE_FILE_TOOL_NAME = "Delete";
6
6
  export const EDIT_TOOL_NAME = "Edit";
7
7
  export const EXIT_PLAN_MODE_TOOL_NAME = "ExitPlanMode";
package/src/index.ts CHANGED
@@ -18,7 +18,6 @@ export * from "./managers/pluginScopeManager.js";
18
18
  export * from "./agent.js";
19
19
 
20
20
  // Export all utilities
21
- export * from "./utils/bashHistory.js";
22
21
  export * from "./utils/bashParser.js";
23
22
  export * from "./utils/convertMessagesForAPI.js";
24
23
  export * from "./utils/fileFilter.js";
@@ -27,6 +26,7 @@ export * from "./utils/globalLogger.js";
27
26
  export * from "./utils/mcpUtils.js";
28
27
  export * from "./utils/messageOperations.js";
29
28
  export * from "./utils/path.js";
29
+ export * from "./utils/promptHistory.js";
30
30
  export * from "./utils/stringUtils.js";
31
31
  export * from "./utils/customCommands.js";
32
32
  export * from "./utils/hookMatcher.js";
@@ -37,6 +37,10 @@ export class MemoryRuleManager {
37
37
  const projectRulesDir = path.join(this.workdir, ".wave", "rules");
38
38
  const userRulesDir = path.join(os.homedir(), ".wave", "rules");
39
39
 
40
+ logger.debug(`Scanning for modular memory rules...`);
41
+ logger.debug(` User rules directory: ${userRulesDir}`);
42
+ logger.debug(` Project rules directory: ${projectRulesDir}`);
43
+
40
44
  const newRules: Record<string, MemoryRule> = {};
41
45
 
42
46
  // Discover user rules first, then project rules so project rules can override if needed
@@ -45,7 +49,18 @@ export class MemoryRuleManager {
45
49
  await this.scanDirectory(projectRulesDir, "project", newRules);
46
50
 
47
51
  this.state.rules = newRules;
48
- logger.debug(`Discovered ${Object.keys(newRules).length} memory rules`);
52
+ const ruleCount = Object.keys(newRules).length;
53
+ logger.debug(`Discovered ${ruleCount} modular memory rules`);
54
+
55
+ if (ruleCount > 0) {
56
+ logger.debug("Loaded memory rules:");
57
+ for (const [id, rule] of Object.entries(newRules)) {
58
+ const pathInfo = rule.metadata.paths
59
+ ? `paths: ${JSON.stringify(rule.metadata.paths)}`
60
+ : "global (no path restriction)";
61
+ logger.debug(` - ${id} (${rule.source}): ${pathInfo}`);
62
+ }
63
+ }
49
64
  }
50
65
 
51
66
  private async scanDirectory(
@@ -121,6 +136,7 @@ export class MemoryRuleManager {
121
136
  const relativeId = path.relative(rulesRoot, filePath);
122
137
  rule.id = relativeId;
123
138
  registry[rule.id] = rule;
139
+ logger.debug(`Loaded memory rule: ${relativeId} from ${filePath}`);
124
140
  } catch (error) {
125
141
  logger.error(`Failed to parse memory rule at ${filePath}:`, error);
126
142
  }
@@ -132,7 +148,7 @@ export class MemoryRuleManager {
132
148
  getActiveRules(filesInContext: string[]): MemoryRule[] {
133
149
  const activeRules: MemoryRule[] = [];
134
150
  for (const rule of Object.values(this.state.rules)) {
135
- if (this.service.isRuleActive(rule, filesInContext)) {
151
+ if (this.service.isRuleActive(rule, filesInContext, this.workdir)) {
136
152
  activeRules.push(rule);
137
153
  }
138
154
  }