wave-agent-sdk 0.6.4 → 0.7.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 (174) hide show
  1. package/dist/agent.d.ts +8 -0
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +49 -240
  4. package/dist/constants/tools.d.ts +0 -2
  5. package/dist/constants/tools.d.ts.map +1 -1
  6. package/dist/constants/tools.js +0 -2
  7. package/dist/core/plugin.d.ts +86 -0
  8. package/dist/core/plugin.d.ts.map +1 -0
  9. package/dist/core/plugin.js +164 -0
  10. package/dist/index.d.ts +1 -4
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1 -5
  13. package/dist/managers/MemoryRuleManager.d.ts +3 -1
  14. package/dist/managers/MemoryRuleManager.d.ts.map +1 -1
  15. package/dist/managers/MemoryRuleManager.js +2 -1
  16. package/dist/managers/aiManager.d.ts +13 -23
  17. package/dist/managers/aiManager.d.ts.map +1 -1
  18. package/dist/managers/aiManager.js +59 -32
  19. package/dist/managers/backgroundTaskManager.d.ts +3 -1
  20. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  21. package/dist/managers/backgroundTaskManager.js +2 -1
  22. package/dist/managers/bashManager.d.ts +4 -4
  23. package/dist/managers/bashManager.d.ts.map +1 -1
  24. package/dist/managers/bashManager.js +5 -2
  25. package/dist/managers/foregroundTaskManager.d.ts +3 -0
  26. package/dist/managers/foregroundTaskManager.d.ts.map +1 -1
  27. package/dist/managers/foregroundTaskManager.js +2 -1
  28. package/dist/managers/hookManager.d.ts +3 -3
  29. package/dist/managers/hookManager.d.ts.map +1 -1
  30. package/dist/managers/hookManager.js +20 -19
  31. package/dist/managers/liveConfigManager.d.ts +6 -13
  32. package/dist/managers/liveConfigManager.d.ts.map +1 -1
  33. package/dist/managers/liveConfigManager.js +50 -45
  34. package/dist/managers/lspManager.d.ts +4 -5
  35. package/dist/managers/lspManager.d.ts.map +1 -1
  36. package/dist/managers/lspManager.js +13 -12
  37. package/dist/managers/mcpManager.d.ts +3 -2
  38. package/dist/managers/mcpManager.d.ts.map +1 -1
  39. package/dist/managers/mcpManager.js +16 -15
  40. package/dist/managers/messageManager.d.ts +5 -7
  41. package/dist/managers/messageManager.d.ts.map +1 -1
  42. package/dist/managers/messageManager.js +12 -7
  43. package/dist/managers/permissionManager.d.ts +6 -4
  44. package/dist/managers/permissionManager.d.ts.map +1 -1
  45. package/dist/managers/permissionManager.js +39 -63
  46. package/dist/managers/planManager.d.ts +4 -6
  47. package/dist/managers/planManager.d.ts.map +1 -1
  48. package/dist/managers/planManager.js +18 -4
  49. package/dist/managers/pluginManager.d.ts +10 -22
  50. package/dist/managers/pluginManager.d.ts.map +1 -1
  51. package/dist/managers/pluginManager.js +27 -14
  52. package/dist/managers/reversionManager.d.ts +4 -3
  53. package/dist/managers/reversionManager.d.ts.map +1 -1
  54. package/dist/managers/reversionManager.js +5 -2
  55. package/dist/managers/skillManager.d.ts +3 -2
  56. package/dist/managers/skillManager.d.ts.map +1 -1
  57. package/dist/managers/skillManager.js +15 -14
  58. package/dist/managers/slashCommandManager.d.ts +9 -16
  59. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  60. package/dist/managers/slashCommandManager.js +21 -10
  61. package/dist/managers/subagentManager.d.ts +7 -17
  62. package/dist/managers/subagentManager.d.ts.map +1 -1
  63. package/dist/managers/subagentManager.js +41 -34
  64. package/dist/managers/toolManager.d.ts +15 -38
  65. package/dist/managers/toolManager.d.ts.map +1 -1
  66. package/dist/managers/toolManager.js +66 -56
  67. package/dist/prompts/index.d.ts +6 -3
  68. package/dist/prompts/index.d.ts.map +1 -1
  69. package/dist/prompts/index.js +8 -16
  70. package/dist/services/MarketplaceService.d.ts.map +1 -1
  71. package/dist/services/MarketplaceService.js +13 -0
  72. package/dist/services/aiService.d.ts +4 -0
  73. package/dist/services/aiService.d.ts.map +1 -1
  74. package/dist/services/aiService.js +47 -7
  75. package/dist/services/configurationService.d.ts.map +1 -1
  76. package/dist/services/configurationService.js +30 -11
  77. package/dist/services/taskManager.d.ts +3 -1
  78. package/dist/services/taskManager.d.ts.map +1 -1
  79. package/dist/services/taskManager.js +2 -1
  80. package/dist/tools/bashTool.js +2 -2
  81. package/dist/tools/editTool.d.ts.map +1 -1
  82. package/dist/tools/editTool.js +9 -1
  83. package/dist/tools/readTool.d.ts.map +1 -1
  84. package/dist/tools/readTool.js +2 -2
  85. package/dist/tools/skillTool.d.ts +2 -4
  86. package/dist/tools/skillTool.d.ts.map +1 -1
  87. package/dist/tools/skillTool.js +61 -61
  88. package/dist/tools/taskOutputTool.js +1 -1
  89. package/dist/tools/taskTool.d.ts +2 -4
  90. package/dist/tools/taskTool.d.ts.map +1 -1
  91. package/dist/tools/taskTool.js +192 -187
  92. package/dist/tools/types.d.ts +11 -1
  93. package/dist/tools/types.d.ts.map +1 -1
  94. package/dist/tools/writeTool.d.ts.map +1 -1
  95. package/dist/tools/writeTool.js +4 -2
  96. package/dist/types/marketplace.d.ts +8 -0
  97. package/dist/types/marketplace.d.ts.map +1 -1
  98. package/dist/types/permissions.d.ts +1 -1
  99. package/dist/types/permissions.d.ts.map +1 -1
  100. package/dist/types/permissions.js +1 -3
  101. package/dist/types/skills.d.ts +0 -2
  102. package/dist/types/skills.d.ts.map +1 -1
  103. package/dist/types/tools.d.ts +0 -15
  104. package/dist/types/tools.d.ts.map +1 -1
  105. package/dist/utils/container.d.ts +31 -0
  106. package/dist/utils/container.d.ts.map +1 -0
  107. package/dist/utils/container.js +79 -0
  108. package/dist/utils/containerSetup.d.ts +26 -0
  109. package/dist/utils/containerSetup.d.ts.map +1 -0
  110. package/dist/utils/containerSetup.js +165 -0
  111. package/dist/utils/editUtils.d.ts +0 -3
  112. package/dist/utils/editUtils.d.ts.map +1 -1
  113. package/dist/utils/editUtils.js +4 -3
  114. package/dist/utils/hookMatcher.d.ts +1 -1
  115. package/dist/utils/hookMatcher.d.ts.map +1 -1
  116. package/dist/utils/hookMatcher.js +2 -2
  117. package/dist/utils/openaiClient.js +2 -2
  118. package/dist/utils/stringUtils.d.ts +6 -0
  119. package/dist/utils/stringUtils.d.ts.map +1 -1
  120. package/dist/utils/stringUtils.js +8 -0
  121. package/package.json +1 -1
  122. package/src/agent.ts +60 -282
  123. package/src/constants/tools.ts +0 -2
  124. package/src/core/plugin.ts +224 -0
  125. package/src/index.ts +1 -6
  126. package/src/managers/MemoryRuleManager.ts +6 -1
  127. package/src/managers/aiManager.ts +83 -58
  128. package/src/managers/backgroundTaskManager.ts +5 -1
  129. package/src/managers/bashManager.ts +9 -4
  130. package/src/managers/foregroundTaskManager.ts +3 -0
  131. package/src/managers/hookManager.ts +21 -23
  132. package/src/managers/liveConfigManager.ts +57 -53
  133. package/src/managers/lspManager.ts +14 -19
  134. package/src/managers/mcpManager.ts +20 -20
  135. package/src/managers/messageManager.ts +19 -12
  136. package/src/managers/permissionManager.ts +45 -70
  137. package/src/managers/planManager.ts +26 -7
  138. package/src/managers/pluginManager.ts +37 -33
  139. package/src/managers/reversionManager.ts +5 -3
  140. package/src/managers/skillManager.ts +19 -20
  141. package/src/managers/slashCommandManager.ts +30 -25
  142. package/src/managers/subagentManager.ts +53 -53
  143. package/src/managers/toolManager.ts +91 -90
  144. package/src/prompts/index.ts +12 -24
  145. package/src/services/MarketplaceService.ts +13 -0
  146. package/src/services/aiService.ts +61 -15
  147. package/src/services/configurationService.ts +34 -13
  148. package/src/services/taskManager.ts +5 -1
  149. package/src/tools/bashTool.ts +2 -2
  150. package/src/tools/editTool.ts +9 -1
  151. package/src/tools/readTool.ts +2 -2
  152. package/src/tools/skillTool.ts +75 -71
  153. package/src/tools/taskOutputTool.ts +1 -1
  154. package/src/tools/taskTool.ts +224 -225
  155. package/src/tools/types.ts +12 -1
  156. package/src/tools/writeTool.ts +4 -2
  157. package/src/types/marketplace.ts +9 -0
  158. package/src/types/permissions.ts +0 -4
  159. package/src/types/skills.ts +0 -3
  160. package/src/types/tools.ts +0 -17
  161. package/src/utils/container.ts +92 -0
  162. package/src/utils/containerSetup.ts +256 -0
  163. package/src/utils/editUtils.ts +4 -3
  164. package/src/utils/hookMatcher.ts +2 -2
  165. package/src/utils/openaiClient.ts +2 -2
  166. package/src/utils/stringUtils.ts +9 -0
  167. package/dist/tools/deleteFileTool.d.ts +0 -6
  168. package/dist/tools/deleteFileTool.d.ts.map +0 -1
  169. package/dist/tools/deleteFileTool.js +0 -100
  170. package/dist/tools/multiEditTool.d.ts +0 -6
  171. package/dist/tools/multiEditTool.d.ts.map +0 -1
  172. package/dist/tools/multiEditTool.js +0 -246
  173. package/src/tools/deleteFileTool.ts +0 -127
  174. package/src/tools/multiEditTool.ts +0 -306
@@ -10,7 +10,7 @@ import {
10
10
  UserMessageParams,
11
11
  type AgentToolBlockUpdateParams,
12
12
  } from "../utils/messageOperations.js";
13
- import type { Logger, Message, Usage, SlashCommand } from "../types/index.js";
13
+ import type { Message, Usage, SlashCommand } from "../types/index.js";
14
14
  import { join } from "path";
15
15
  import {
16
16
  appendMessages,
@@ -23,6 +23,8 @@ import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
23
23
  import type { MemoryRuleManager } from "./MemoryRuleManager.js";
24
24
  import { pathEncoder } from "../utils/pathEncoder.js";
25
25
 
26
+ import { Container } from "../utils/container.js";
27
+
26
28
  export interface MessageManagerCallbacks {
27
29
  onMessagesChange?: (messages: Message[]) => void;
28
30
  onSessionIdChange?: (sessionId: string) => void;
@@ -59,13 +61,13 @@ export interface MessageManagerCallbacks {
59
61
  ) => void;
60
62
  }
61
63
 
64
+ import { logger } from "../utils/globalLogger.js";
65
+
62
66
  export interface MessageManagerOptions {
63
67
  callbacks: MessageManagerCallbacks;
64
68
  workdir: string;
65
- logger?: Logger;
66
69
  sessionType?: "main" | "subagent";
67
70
  subagentType?: string;
68
- memoryRuleManager?: MemoryRuleManager;
69
71
  }
70
72
 
71
73
  export class MessageManager {
@@ -77,16 +79,17 @@ export class MessageManager {
77
79
  private latestTotalTokens: number;
78
80
  private workdir: string;
79
81
  private encodedWorkdir: string; // Cached encoded workdir
80
- private logger?: Logger; // Add optional logger property
81
82
  private callbacks: MessageManagerCallbacks;
82
83
  private transcriptPath: string; // Cached transcript path
83
84
  private savedMessageCount: number; // Track how many messages have been saved to prevent duplication
84
85
  private filesInContext: Set<string> = new Set(); // Track files mentioned in the conversation
85
- private memoryRuleManager?: MemoryRuleManager;
86
86
  private sessionType: "main" | "subagent";
87
87
  private subagentType?: string;
88
88
 
89
- constructor(options: MessageManagerOptions) {
89
+ constructor(
90
+ private container: Container,
91
+ options: MessageManagerOptions,
92
+ ) {
90
93
  this.sessionId = generateSessionId();
91
94
  this.rootSessionId = this.sessionId;
92
95
  this.messages = [];
@@ -94,16 +97,20 @@ export class MessageManager {
94
97
  this.workdir = options.workdir;
95
98
  this.encodedWorkdir = pathEncoder.encodeSync(this.workdir); // Cache encoded workdir
96
99
  this.callbacks = options.callbacks;
97
- this.logger = options.logger;
98
100
  this.savedMessageCount = 0; // Initialize saved message count tracker
99
101
  this.sessionType = options.sessionType || "main";
100
102
  this.subagentType = options.subagentType;
101
- this.memoryRuleManager = options.memoryRuleManager;
102
103
 
103
104
  // Compute and cache the transcript path
104
105
  this.transcriptPath = this.computeTranscriptPath();
105
106
  }
106
107
 
108
+ private get memoryRuleManager(): MemoryRuleManager | undefined {
109
+ return this.container.has("MemoryRuleManager")
110
+ ? this.container.get<MemoryRuleManager>("MemoryRuleManager")
111
+ : undefined;
112
+ }
113
+
107
114
  // Getter methods
108
115
  public getSessionId(): string {
109
116
  return this.sessionId;
@@ -155,7 +162,7 @@ export class MessageManager {
155
162
  const filesInContext = this.getFilesInContext();
156
163
  const activeRules = this.memoryRuleManager.getActiveRules(filesInContext);
157
164
  if (activeRules.length > 0) {
158
- this.logger?.debug(
165
+ logger?.debug(
159
166
  `Active modular rules (${activeRules.length}): ${activeRules.map((r) => r.id).join(", ")}`,
160
167
  );
161
168
  if (combined) {
@@ -200,7 +207,7 @@ export class MessageManager {
200
207
  try {
201
208
  await createSession(this.sessionId, this.workdir, this.sessionType);
202
209
  } catch (error) {
203
- this.logger?.error("Failed to create session:", error);
210
+ logger?.error("Failed to create session:", error);
204
211
  }
205
212
  }
206
213
 
@@ -242,7 +249,7 @@ export class MessageManager {
242
249
  // Update the saved message count
243
250
  this.savedMessageCount = this.messages.length;
244
251
  } catch (error) {
245
- this.logger?.error("Failed to save session:", error);
252
+ logger?.error("Failed to save session:", error);
246
253
  }
247
254
  }
248
255
 
@@ -741,7 +748,7 @@ export class MessageManager {
741
748
 
742
749
  await writeFile(this.transcriptPath, content, "utf8");
743
750
  } catch (error) {
744
- this.logger?.error("Failed to rewrite session file:", error);
751
+ logger?.error("Failed to rewrite session file:", error);
745
752
  }
746
753
  }
747
754
 
@@ -27,18 +27,17 @@ import { isPathInside } from "../utils/pathSafety.js";
27
27
  import {
28
28
  BASH_TOOL_NAME,
29
29
  EDIT_TOOL_NAME,
30
- MULTI_EDIT_TOOL_NAME,
31
- DELETE_FILE_TOOL_NAME,
32
30
  WRITE_TOOL_NAME,
33
31
  READ_TOOL_NAME,
34
32
  LS_TOOL_NAME,
35
33
  } from "../constants/tools.js";
34
+ import { Container } from "../utils/container.js";
36
35
 
37
36
  const SAFE_COMMANDS = ["cd", "ls", "pwd", "true", "false"];
38
37
 
38
+ import { logger } from "../utils/globalLogger.js";
39
+
39
40
  export interface PermissionManagerOptions {
40
- /** Logger for debugging permission decisions */
41
- logger?: Logger;
42
41
  /** Configured default permission mode from settings */
43
42
  configuredDefaultMode?: PermissionMode;
44
43
  /** Allowed rules from settings */
@@ -51,10 +50,11 @@ export interface PermissionManagerOptions {
51
50
  workdir?: string;
52
51
  /** Path to the current plan file */
53
52
  planFilePath?: string;
53
+ /** Optional logger */
54
+ logger?: Logger;
54
55
  }
55
56
 
56
57
  export class PermissionManager {
57
- private logger?: Logger;
58
58
  private configuredDefaultMode?: PermissionMode;
59
59
  private allowedRules: string[] = [];
60
60
  private deniedRules: string[] = [];
@@ -63,14 +63,18 @@ export class PermissionManager {
63
63
  private workdir?: string;
64
64
  private planFilePath?: string;
65
65
  private onConfiguredDefaultModeChange?: (mode: PermissionMode) => void;
66
+ private _logger?: Logger;
66
67
 
67
- constructor(options: PermissionManagerOptions = {}) {
68
- this.logger = options.logger;
68
+ constructor(
69
+ private container: Container,
70
+ options: PermissionManagerOptions = {},
71
+ ) {
69
72
  this.configuredDefaultMode = options.configuredDefaultMode;
70
73
  this.allowedRules = options.allowedRules || [];
71
74
  this.deniedRules = options.deniedRules || [];
72
75
  this.workdir = options.workdir;
73
76
  this.planFilePath = options.planFilePath;
77
+ this._logger = options.logger;
74
78
  this.updateAdditionalDirectories(options.additionalDirectories || []);
75
79
  }
76
80
 
@@ -89,7 +93,7 @@ export class PermissionManager {
89
93
  updateConfiguredDefaultMode(defaultMode?: PermissionMode): void {
90
94
  const oldEffectiveMode = this.getCurrentEffectiveMode();
91
95
 
92
- this.logger?.debug("Updating configured default permission mode", {
96
+ logger?.debug("Updating configured default permission mode", {
93
97
  previous: this.configuredDefaultMode,
94
98
  new: defaultMode,
95
99
  });
@@ -100,7 +104,7 @@ export class PermissionManager {
100
104
  oldEffectiveMode !== newEffectiveMode &&
101
105
  this.onConfiguredDefaultModeChange
102
106
  ) {
103
- this.logger?.debug(
107
+ logger?.debug(
104
108
  "Effective permission mode changed due to configuration update",
105
109
  {
106
110
  oldMode: oldEffectiveMode,
@@ -122,7 +126,7 @@ export class PermissionManager {
122
126
  * Update the allowed rules (e.g., when configuration reloads)
123
127
  */
124
128
  updateAllowedRules(rules: string[]): void {
125
- this.logger?.debug("Updating allowed permission rules", {
129
+ logger?.debug("Updating allowed permission rules", {
126
130
  count: rules.length,
127
131
  });
128
132
  this.allowedRules = rules;
@@ -132,7 +136,7 @@ export class PermissionManager {
132
136
  * Update the denied rules (e.g., when configuration reloads)
133
137
  */
134
138
  updateDeniedRules(rules: string[]): void {
135
- this.logger?.debug("Updating denied permission rules", {
139
+ logger?.debug("Updating denied permission rules", {
136
140
  count: rules.length,
137
141
  });
138
142
  this.deniedRules = rules;
@@ -142,7 +146,7 @@ export class PermissionManager {
142
146
  * Add temporary rules for the current session
143
147
  */
144
148
  public addTemporaryRules(rules: string[]): void {
145
- this.logger?.debug("Adding temporary permission rules", {
149
+ logger?.debug("Adding temporary permission rules", {
146
150
  count: rules.length,
147
151
  rules,
148
152
  });
@@ -153,7 +157,7 @@ export class PermissionManager {
153
157
  * Clear all temporary rules
154
158
  */
155
159
  public clearTemporaryRules(): void {
156
- this.logger?.debug("Clearing temporary permission rules");
160
+ logger?.debug("Clearing temporary permission rules");
157
161
  this.temporaryRules = [];
158
162
  }
159
163
 
@@ -161,7 +165,7 @@ export class PermissionManager {
161
165
  * Update the additional directories (e.g., when configuration reloads)
162
166
  */
163
167
  updateAdditionalDirectories(directories: string[]): void {
164
- this.logger?.debug("Updating additional directories", {
168
+ logger?.debug("Updating additional directories", {
165
169
  count: directories.length,
166
170
  });
167
171
  this.additionalDirectories = directories.map((dir) => {
@@ -176,7 +180,7 @@ export class PermissionManager {
176
180
  * Update the working directory
177
181
  */
178
182
  updateWorkdir(workdir: string): void {
179
- this.logger?.debug("Updating working directory", {
183
+ logger?.debug("Updating working directory", {
180
184
  workdir,
181
185
  });
182
186
  this.workdir = workdir;
@@ -186,7 +190,7 @@ export class PermissionManager {
186
190
  * Set the current plan file path
187
191
  */
188
192
  public setPlanFilePath(path: string | undefined): void {
189
- this.logger?.debug("Setting plan file path", { path });
193
+ logger?.debug("Setting plan file path", { path });
190
194
  this.planFilePath = path;
191
195
  }
192
196
 
@@ -224,7 +228,7 @@ export class PermissionManager {
224
228
  }
225
229
  }
226
230
 
227
- this.logger?.debug("Path is outside Safe Zone", {
231
+ logger?.debug("Path is outside Safe Zone", {
228
232
  absolutePath,
229
233
  workdir: effectiveWorkdir,
230
234
  additionalDirectories: this.additionalDirectories,
@@ -248,7 +252,7 @@ export class PermissionManager {
248
252
  ): PermissionMode {
249
253
  // CLI override takes highest precedence
250
254
  if (cliPermissionMode !== undefined) {
251
- this.logger?.debug("Using CLI permission mode override", {
255
+ logger?.debug("Using CLI permission mode override", {
252
256
  cliMode: cliPermissionMode,
253
257
  configuredDefault: this.configuredDefaultMode,
254
258
  });
@@ -257,14 +261,14 @@ export class PermissionManager {
257
261
 
258
262
  // Use configured default mode if available
259
263
  if (this.configuredDefaultMode !== undefined) {
260
- this.logger?.debug("Using configured default permission mode", {
264
+ logger?.debug("Using configured default permission mode", {
261
265
  configuredDefault: this.configuredDefaultMode,
262
266
  });
263
267
  return this.configuredDefaultMode;
264
268
  }
265
269
 
266
270
  // Fall back to system default
267
- this.logger?.debug("Using system default permission mode");
271
+ logger?.debug("Using system default permission mode");
268
272
  return "default";
269
273
  }
270
274
 
@@ -275,7 +279,7 @@ export class PermissionManager {
275
279
  async checkPermission(
276
280
  context: ToolPermissionContext,
277
281
  ): Promise<PermissionDecision> {
278
- this.logger?.debug("Checking permission for tool", {
282
+ logger?.debug("Checking permission for tool", {
279
283
  toolName: context.toolName,
280
284
  permissionMode: context.permissionMode,
281
285
  hasCallback: !!context.canUseToolCallback,
@@ -284,7 +288,7 @@ export class PermissionManager {
284
288
  // 0. Check denied rules first - Deny always takes precedence
285
289
  for (const rule of this.deniedRules) {
286
290
  if (this.matchesRule(context, rule)) {
287
- this.logger?.warn("Permission denied by rule", {
291
+ logger?.warn("Permission denied by rule", {
288
292
  toolName: context.toolName,
289
293
  rule,
290
294
  });
@@ -297,24 +301,18 @@ export class PermissionManager {
297
301
 
298
302
  // 1. If bypassPermissions mode, always allow
299
303
  if (context.permissionMode === "bypassPermissions") {
300
- this.logger?.debug("Permission bypassed for tool", {
304
+ logger?.debug("Permission bypassed for tool", {
301
305
  toolName: context.toolName,
302
306
  });
303
307
  return { behavior: "allow" };
304
308
  }
305
309
 
306
- // 1.1 If acceptEdits mode, allow Edit, MultiEdit, Delete, Write
310
+ // 1.1 If acceptEdits mode, allow Edit, Write
307
311
  if (context.permissionMode === "acceptEdits") {
308
- const autoAcceptedTools = [
309
- EDIT_TOOL_NAME,
310
- MULTI_EDIT_TOOL_NAME,
311
- DELETE_FILE_TOOL_NAME,
312
- WRITE_TOOL_NAME,
313
- ];
312
+ const autoAcceptedTools = [EDIT_TOOL_NAME, WRITE_TOOL_NAME];
314
313
  if (autoAcceptedTools.includes(context.toolName)) {
315
314
  // Enforce Safe Zone for file operations
316
- const targetPath = (context.toolInput?.file_path ||
317
- context.toolInput?.target_file) as string | undefined;
315
+ const targetPath = context.toolInput?.file_path as string | undefined;
318
316
  const workdir = context.toolInput?.workdir as string | undefined;
319
317
 
320
318
  if (targetPath) {
@@ -323,7 +321,7 @@ export class PermissionManager {
323
321
  workdir,
324
322
  );
325
323
  if (!isInside) {
326
- this.logger?.info(
324
+ logger?.info(
327
325
  "File operation outside the Safe Zone in acceptEdits mode, falling back to manual confirmation",
328
326
  {
329
327
  toolName: context.toolName,
@@ -333,7 +331,7 @@ export class PermissionManager {
333
331
  );
334
332
  // Fall through to normal permission check flow to trigger confirmation prompt
335
333
  } else {
336
- this.logger?.debug(
334
+ logger?.debug(
337
335
  "Permission automatically accepted for tool in acceptEdits mode",
338
336
  {
339
337
  toolName: context.toolName,
@@ -347,7 +345,7 @@ export class PermissionManager {
347
345
 
348
346
  // 1.2 Check if tool call is allowed by persistent or temporary rules
349
347
  if (this.isAllowedByRule(context)) {
350
- this.logger?.debug("Permission allowed by persistent rule", {
348
+ logger?.debug("Permission allowed by persistent rule", {
351
349
  toolName: context.toolName,
352
350
  });
353
351
  return { behavior: "allow" };
@@ -355,29 +353,16 @@ export class PermissionManager {
355
353
 
356
354
  // 1.3 If plan mode, allow Read-only tools and Edit/Write for plan file
357
355
  if (context.permissionMode === "plan") {
358
- const writeTools = [
359
- EDIT_TOOL_NAME,
360
- MULTI_EDIT_TOOL_NAME,
361
- WRITE_TOOL_NAME,
362
- DELETE_FILE_TOOL_NAME,
363
- ];
364
- if (context.toolName === DELETE_FILE_TOOL_NAME) {
365
- return {
366
- behavior: "deny",
367
- message: "Delete operations are not allowed in plan mode.",
368
- };
369
- }
370
-
356
+ const writeTools = [EDIT_TOOL_NAME, WRITE_TOOL_NAME];
371
357
  if (writeTools.includes(context.toolName)) {
372
- const targetPath = (context.toolInput?.file_path ||
373
- context.toolInput?.target_file) as string | undefined;
358
+ const targetPath = context.toolInput?.file_path as string | undefined;
374
359
 
375
360
  if (this.planFilePath && targetPath) {
376
361
  const absoluteTargetPath = path.resolve(targetPath);
377
362
  const absolutePlanPath = path.resolve(this.planFilePath);
378
363
 
379
364
  if (absoluteTargetPath === absolutePlanPath) {
380
- this.logger?.debug("Allowing write to plan file in plan mode", {
365
+ logger?.debug("Allowing write to plan file in plan mode", {
381
366
  toolName: context.toolName,
382
367
  targetPath,
383
368
  });
@@ -394,7 +379,7 @@ export class PermissionManager {
394
379
 
395
380
  // 2. If not a restricted tool, always allow
396
381
  if (!this.isRestrictedTool(context.toolName)) {
397
- this.logger?.debug("Tool is not restricted, allowing", {
382
+ logger?.debug("Tool is not restricted, allowing", {
398
383
  toolName: context.toolName,
399
384
  });
400
385
  return { behavior: "allow" };
@@ -403,11 +388,11 @@ export class PermissionManager {
403
388
  // 3. If custom callback provided, call it and return result
404
389
  if (context.canUseToolCallback) {
405
390
  try {
406
- this.logger?.debug("Calling custom permission callback for tool", {
391
+ logger?.debug("Calling custom permission callback for tool", {
407
392
  toolName: context.toolName,
408
393
  });
409
394
  const decision = await context.canUseToolCallback(context);
410
- this.logger?.debug("Custom callback returned decision", {
395
+ logger?.debug("Custom callback returned decision", {
411
396
  toolName: context.toolName,
412
397
  decision,
413
398
  });
@@ -415,7 +400,7 @@ export class PermissionManager {
415
400
  } catch (error) {
416
401
  const errorMessage =
417
402
  error instanceof Error ? error.message : String(error);
418
- this.logger?.error("Error in permission callback", {
403
+ logger?.error("Error in permission callback", {
419
404
  toolName: context.toolName,
420
405
  error: errorMessage,
421
406
  });
@@ -428,7 +413,7 @@ export class PermissionManager {
428
413
 
429
414
  // 4. For default mode on restricted tools without callback, integrate with CLI confirmation
430
415
  // Note: CLI confirmation integration will be implemented in Phase 2
431
- this.logger?.warn(
416
+ logger?.warn(
432
417
  "No permission callback provided for restricted tool in default mode",
433
418
  {
434
419
  toolName: context.toolName,
@@ -447,7 +432,7 @@ export class PermissionManager {
447
432
  const isRestricted = (RESTRICTED_TOOLS as readonly string[]).includes(
448
433
  toolName,
449
434
  );
450
- this.logger?.debug("Checking if tool is restricted", {
435
+ logger?.debug("Checking if tool is restricted", {
451
436
  toolName,
452
437
  isRestricted,
453
438
  });
@@ -483,16 +468,9 @@ export class PermissionManager {
483
468
  };
484
469
 
485
470
  // Set hidePersistentOption for out-of-bounds file operations
486
- const fileTools = [
487
- EDIT_TOOL_NAME,
488
- MULTI_EDIT_TOOL_NAME,
489
- DELETE_FILE_TOOL_NAME,
490
- WRITE_TOOL_NAME,
491
- ];
471
+ const fileTools = [EDIT_TOOL_NAME, WRITE_TOOL_NAME];
492
472
  if (fileTools.includes(toolName)) {
493
- const targetPath = (toolInput?.file_path || toolInput?.target_file) as
494
- | string
495
- | undefined;
473
+ const targetPath = toolInput?.file_path as string | undefined;
496
474
  const workdir = toolInput?.workdir as string | undefined;
497
475
 
498
476
  if (targetPath) {
@@ -543,7 +521,7 @@ export class PermissionManager {
543
521
  }
544
522
  }
545
523
 
546
- this.logger?.debug("Created permission context", {
524
+ logger?.debug("Created permission context", {
547
525
  toolName,
548
526
  permissionMode,
549
527
  hasCallback: !!callback,
@@ -593,13 +571,10 @@ export class PermissionManager {
593
571
  READ_TOOL_NAME,
594
572
  WRITE_TOOL_NAME,
595
573
  EDIT_TOOL_NAME,
596
- MULTI_EDIT_TOOL_NAME,
597
- DELETE_FILE_TOOL_NAME,
598
574
  LS_TOOL_NAME,
599
575
  ];
600
576
  if (pathTools.includes(toolName)) {
601
577
  const targetPath = (context.toolInput?.file_path ||
602
- context.toolInput?.target_file ||
603
578
  context.toolInput?.path) as string | undefined;
604
579
 
605
580
  if (targetPath) {
@@ -2,15 +2,19 @@ import path from "node:path";
2
2
  import fs from "node:fs/promises";
3
3
  import os from "node:os";
4
4
  import { generateRandomName } from "../utils/nameGenerator.js";
5
- import type { Logger } from "../types/core.js";
5
+
6
+ import { Container } from "../utils/container.js";
6
7
 
7
8
  /**
8
9
  * Manages plan files for plan mode
9
10
  */
11
+ import { logger } from "../utils/globalLogger.js";
12
+
10
13
  export class PlanManager {
11
14
  private planDir: string;
15
+ private currentPlanFilePath: string | null = null;
12
16
 
13
- constructor(private logger?: Logger) {
17
+ constructor(private container: Container) {
14
18
  this.planDir = path.join(os.homedir(), ".wave", "plans");
15
19
  }
16
20
 
@@ -24,15 +28,30 @@ export class PlanManager {
24
28
  try {
25
29
  await fs.mkdir(this.planDir, { recursive: true });
26
30
  } catch (error) {
27
- this.logger?.error(
28
- `Failed to create plan directory: ${this.planDir}`,
29
- error,
30
- );
31
+ logger?.error(`Failed to create plan directory: ${this.planDir}`, error);
31
32
  throw error;
32
33
  }
33
34
  const name = generateRandomName(seed);
34
35
  const filePath = path.join(this.planDir, `${name}.md`);
35
- this.logger?.info(`Generated plan file path: ${filePath}`);
36
+
37
+ if (this.currentPlanFilePath !== filePath) {
38
+ try {
39
+ await fs.unlink(filePath);
40
+ } catch (error) {
41
+ if (
42
+ error instanceof Error &&
43
+ (error as Error & { code?: string }).code !== "ENOENT"
44
+ ) {
45
+ logger?.error(
46
+ `Failed to remove existing plan file: ${filePath}`,
47
+ error,
48
+ );
49
+ }
50
+ }
51
+ this.currentPlanFilePath = filePath;
52
+ }
53
+
54
+ logger?.info(`Generated plan file path: ${filePath}`);
36
55
  return { path: filePath, name };
37
56
  }
38
57
 
@@ -1,4 +1,5 @@
1
- import { Plugin, PluginConfig, Logger } from "../types/index.js";
1
+ import { logger } from "../utils/globalLogger.js";
2
+ import { Plugin, PluginConfig } from "../types/index.js";
2
3
  import { PluginLoader } from "../services/pluginLoader.js";
3
4
  import * as path from "path";
4
5
  import { SkillManager } from "./skillManager.js";
@@ -8,41 +9,48 @@ import { McpManager } from "./mcpManager.js";
8
9
  import { SlashCommandManager } from "./slashCommandManager.js";
9
10
  import { MarketplaceService } from "../services/MarketplaceService.js";
10
11
  import { ConfigurationService } from "../services/configurationService.js";
12
+ import { Container } from "../utils/container.js";
11
13
 
12
14
  export interface PluginManagerOptions {
13
15
  workdir: string;
14
- logger?: Logger;
15
- skillManager?: SkillManager;
16
- hookManager?: HookManager;
17
- lspManager?: LspManager;
18
- mcpManager?: McpManager;
19
- slashCommandManager?: SlashCommandManager;
20
16
  enabledPlugins?: Record<string, boolean>;
21
- configurationService?: ConfigurationService;
22
17
  }
23
18
 
24
19
  export class PluginManager {
25
20
  private plugins = new Map<string, Plugin>();
26
21
  private workdir: string;
27
- private logger?: Logger;
28
- private skillManager?: SkillManager;
29
- private hookManager?: HookManager;
30
- private lspManager?: LspManager;
31
- private mcpManager?: McpManager;
32
- private slashCommandManager?: SlashCommandManager;
33
22
  private enabledPlugins: Record<string, boolean>;
34
- private configurationService?: ConfigurationService;
35
23
 
36
- constructor(options: PluginManagerOptions) {
24
+ constructor(
25
+ private container: Container,
26
+ options: PluginManagerOptions,
27
+ ) {
37
28
  this.workdir = options.workdir;
38
- this.logger = options.logger;
39
- this.skillManager = options.skillManager;
40
- this.hookManager = options.hookManager;
41
- this.lspManager = options.lspManager;
42
- this.mcpManager = options.mcpManager;
43
- this.slashCommandManager = options.slashCommandManager;
44
29
  this.enabledPlugins = options.enabledPlugins || {};
45
- this.configurationService = options.configurationService;
30
+ }
31
+
32
+ private get skillManager(): SkillManager | undefined {
33
+ return this.container.get<SkillManager>("SkillManager");
34
+ }
35
+
36
+ private get hookManager(): HookManager | undefined {
37
+ return this.container.get<HookManager>("HookManager");
38
+ }
39
+
40
+ private get lspManager(): LspManager | undefined {
41
+ return this.container.get<LspManager>("LspManager");
42
+ }
43
+
44
+ private get mcpManager(): McpManager | undefined {
45
+ return this.container.get<McpManager>("McpManager");
46
+ }
47
+
48
+ private get slashCommandManager(): SlashCommandManager | undefined {
49
+ return this.container.get<SlashCommandManager>("SlashCommandManager");
50
+ }
51
+
52
+ private get configurationService(): ConfigurationService | undefined {
53
+ return this.container.get<ConfigurationService>("ConfigurationService");
46
54
  }
47
55
 
48
56
  /**
@@ -70,15 +78,13 @@ export class PluginManager {
70
78
  for (const p of installedRegistry.plugins) {
71
79
  const pluginId = `${p.name}@${p.marketplace}`;
72
80
  if (this.enabledPlugins[pluginId] !== true) {
73
- this.logger?.info(
74
- `Plugin ${pluginId} is not enabled via configuration`,
75
- );
81
+ logger?.info(`Plugin ${pluginId} is not enabled via configuration`);
76
82
  continue;
77
83
  }
78
84
  await this.loadSinglePlugin(p.cachePath);
79
85
  }
80
86
  } catch (error) {
81
- this.logger?.error("Failed to load installed plugins:", error);
87
+ logger?.error("Failed to load installed plugins:", error);
82
88
  }
83
89
  }
84
90
 
@@ -91,9 +97,7 @@ export class PluginManager {
91
97
 
92
98
  if (this.plugins.has(manifest.name)) {
93
99
  // If already loaded (e.g. via explicit config), skip
94
- this.logger?.warn(
95
- `Plugin with name '${manifest.name}' is already loaded`,
96
- );
100
+ logger?.warn(`Plugin with name '${manifest.name}' is already loaded`);
97
101
  return;
98
102
  }
99
103
 
@@ -138,9 +142,9 @@ export class PluginManager {
138
142
  }
139
143
 
140
144
  this.plugins.set(manifest.name, plugin);
141
- this.logger?.info(`Loaded plugin: ${manifest.name} v${manifest.version}`);
145
+ logger?.info(`Loaded plugin: ${manifest.name} v${manifest.version}`);
142
146
  } catch (error) {
143
- this.logger?.error(`Failed to load plugin from ${absolutePath}`, error);
147
+ logger?.error(`Failed to load plugin from ${absolutePath}`, error);
144
148
  }
145
149
  }
146
150
 
@@ -152,7 +156,7 @@ export class PluginManager {
152
156
  // Load plugins from configuration (e.g. --plugin-dir) first to give them higher priority
153
157
  for (const config of configs) {
154
158
  if (config.type !== "local") {
155
- this.logger?.warn(`Unsupported plugin type: ${config.type}`);
159
+ logger?.warn(`Unsupported plugin type: ${config.type}`);
156
160
  continue;
157
161
  }
158
162
 
@@ -1,13 +1,15 @@
1
1
  import fs from "fs/promises";
2
2
  import { FileSnapshot } from "../types/reversion.js";
3
3
  import { ReversionService } from "../services/reversionService.js";
4
+ import { Container } from "../utils/container.js";
4
5
 
5
6
  export class ReversionManager {
6
7
  private buffer: Map<string, FileSnapshot> = new Map();
7
- private reversionService: ReversionService;
8
8
 
9
- constructor(reversionService: ReversionService) {
10
- this.reversionService = reversionService;
9
+ constructor(private container: Container) {}
10
+
11
+ private get reversionService(): ReversionService {
12
+ return this.container.get<ReversionService>("ReversionService")!;
11
13
  }
12
14
 
13
15
  /**