wave-agent-sdk 0.0.7 → 0.0.10

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 (240) hide show
  1. package/dist/agent.d.ts +105 -24
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +438 -53
  4. package/dist/index.d.ts +4 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +4 -0
  7. package/dist/managers/aiManager.d.ts +18 -7
  8. package/dist/managers/aiManager.d.ts.map +1 -1
  9. package/dist/managers/aiManager.js +254 -142
  10. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundBashManager.js +11 -9
  12. package/dist/managers/hookManager.d.ts +6 -6
  13. package/dist/managers/hookManager.d.ts.map +1 -1
  14. package/dist/managers/hookManager.js +81 -39
  15. package/dist/managers/liveConfigManager.d.ts +95 -0
  16. package/dist/managers/liveConfigManager.d.ts.map +1 -0
  17. package/dist/managers/liveConfigManager.js +442 -0
  18. package/dist/managers/lspManager.d.ts +43 -0
  19. package/dist/managers/lspManager.d.ts.map +1 -0
  20. package/dist/managers/lspManager.js +326 -0
  21. package/dist/managers/messageManager.d.ts +41 -24
  22. package/dist/managers/messageManager.d.ts.map +1 -1
  23. package/dist/managers/messageManager.js +184 -73
  24. package/dist/managers/permissionManager.d.ts +66 -0
  25. package/dist/managers/permissionManager.d.ts.map +1 -0
  26. package/dist/managers/permissionManager.js +208 -0
  27. package/dist/managers/skillManager.d.ts +1 -0
  28. package/dist/managers/skillManager.d.ts.map +1 -1
  29. package/dist/managers/skillManager.js +2 -1
  30. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  31. package/dist/managers/slashCommandManager.js +4 -2
  32. package/dist/managers/subagentManager.d.ts +42 -6
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +213 -62
  35. package/dist/managers/toolManager.d.ts +38 -1
  36. package/dist/managers/toolManager.d.ts.map +1 -1
  37. package/dist/managers/toolManager.js +66 -2
  38. package/dist/services/aiService.d.ts +15 -5
  39. package/dist/services/aiService.d.ts.map +1 -1
  40. package/dist/services/aiService.js +446 -77
  41. package/dist/services/configurationService.d.ts +116 -0
  42. package/dist/services/configurationService.d.ts.map +1 -0
  43. package/dist/services/configurationService.js +585 -0
  44. package/dist/services/fileWatcher.d.ts +69 -0
  45. package/dist/services/fileWatcher.d.ts.map +1 -0
  46. package/dist/services/fileWatcher.js +212 -0
  47. package/dist/services/hook.d.ts +5 -40
  48. package/dist/services/hook.d.ts.map +1 -1
  49. package/dist/services/hook.js +47 -109
  50. package/dist/services/jsonlHandler.d.ts +71 -0
  51. package/dist/services/jsonlHandler.d.ts.map +1 -0
  52. package/dist/services/jsonlHandler.js +236 -0
  53. package/dist/services/memory.d.ts.map +1 -1
  54. package/dist/services/memory.js +33 -11
  55. package/dist/services/session.d.ts +116 -52
  56. package/dist/services/session.d.ts.map +1 -1
  57. package/dist/services/session.js +415 -143
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +77 -17
  60. package/dist/tools/deleteFileTool.d.ts.map +1 -1
  61. package/dist/tools/deleteFileTool.js +27 -1
  62. package/dist/tools/editTool.d.ts.map +1 -1
  63. package/dist/tools/editTool.js +33 -8
  64. package/dist/tools/lspTool.d.ts +6 -0
  65. package/dist/tools/lspTool.d.ts.map +1 -0
  66. package/dist/tools/lspTool.js +589 -0
  67. package/dist/tools/multiEditTool.d.ts.map +1 -1
  68. package/dist/tools/multiEditTool.js +30 -10
  69. package/dist/tools/readTool.d.ts.map +1 -1
  70. package/dist/tools/readTool.js +113 -3
  71. package/dist/tools/skillTool.js +2 -2
  72. package/dist/tools/todoWriteTool.d.ts.map +1 -1
  73. package/dist/tools/todoWriteTool.js +23 -0
  74. package/dist/tools/types.d.ts +11 -8
  75. package/dist/tools/types.d.ts.map +1 -1
  76. package/dist/tools/writeTool.d.ts.map +1 -1
  77. package/dist/tools/writeTool.js +30 -15
  78. package/dist/types/commands.d.ts +4 -1
  79. package/dist/types/commands.d.ts.map +1 -1
  80. package/dist/types/config.d.ts +4 -0
  81. package/dist/types/config.d.ts.map +1 -1
  82. package/dist/types/configuration.d.ts +69 -0
  83. package/dist/types/configuration.d.ts.map +1 -0
  84. package/dist/types/configuration.js +8 -0
  85. package/dist/types/core.d.ts +45 -0
  86. package/dist/types/core.d.ts.map +1 -1
  87. package/dist/types/environment.d.ts +83 -0
  88. package/dist/types/environment.d.ts.map +1 -0
  89. package/dist/types/environment.js +21 -0
  90. package/dist/types/fileSearch.d.ts +5 -0
  91. package/dist/types/fileSearch.d.ts.map +1 -0
  92. package/dist/types/fileSearch.js +1 -0
  93. package/dist/types/hooks.d.ts +18 -3
  94. package/dist/types/hooks.d.ts.map +1 -1
  95. package/dist/types/hooks.js +8 -8
  96. package/dist/types/index.d.ts +7 -0
  97. package/dist/types/index.d.ts.map +1 -1
  98. package/dist/types/index.js +7 -0
  99. package/dist/types/lsp.d.ts +90 -0
  100. package/dist/types/lsp.d.ts.map +1 -0
  101. package/dist/types/lsp.js +4 -0
  102. package/dist/types/messaging.d.ts +19 -12
  103. package/dist/types/messaging.d.ts.map +1 -1
  104. package/dist/types/permissions.d.ts +35 -0
  105. package/dist/types/permissions.d.ts.map +1 -0
  106. package/dist/types/permissions.js +12 -0
  107. package/dist/types/session.d.ts +15 -0
  108. package/dist/types/session.d.ts.map +1 -0
  109. package/dist/types/session.js +7 -0
  110. package/dist/types/skills.d.ts +1 -0
  111. package/dist/types/skills.d.ts.map +1 -1
  112. package/dist/types/tools.d.ts +35 -0
  113. package/dist/types/tools.d.ts.map +1 -0
  114. package/dist/types/tools.js +4 -0
  115. package/dist/utils/abortUtils.d.ts +34 -0
  116. package/dist/utils/abortUtils.d.ts.map +1 -0
  117. package/dist/utils/abortUtils.js +92 -0
  118. package/dist/utils/bashHistory.d.ts +4 -0
  119. package/dist/utils/bashHistory.d.ts.map +1 -1
  120. package/dist/utils/bashHistory.js +48 -30
  121. package/dist/utils/builtinSubagents.d.ts +7 -0
  122. package/dist/utils/builtinSubagents.d.ts.map +1 -0
  123. package/dist/utils/builtinSubagents.js +65 -0
  124. package/dist/utils/cacheControlUtils.d.ts +96 -0
  125. package/dist/utils/cacheControlUtils.d.ts.map +1 -0
  126. package/dist/utils/cacheControlUtils.js +324 -0
  127. package/dist/utils/commandPathResolver.d.ts +52 -0
  128. package/dist/utils/commandPathResolver.d.ts.map +1 -0
  129. package/dist/utils/commandPathResolver.js +145 -0
  130. package/dist/utils/configPaths.d.ts +85 -0
  131. package/dist/utils/configPaths.d.ts.map +1 -0
  132. package/dist/utils/configPaths.js +121 -0
  133. package/dist/utils/constants.d.ts +1 -13
  134. package/dist/utils/constants.d.ts.map +1 -1
  135. package/dist/utils/constants.js +2 -14
  136. package/dist/utils/convertMessagesForAPI.d.ts +2 -1
  137. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
  138. package/dist/utils/convertMessagesForAPI.js +39 -18
  139. package/dist/utils/customCommands.d.ts.map +1 -1
  140. package/dist/utils/customCommands.js +66 -21
  141. package/dist/utils/fileSearch.d.ts +14 -0
  142. package/dist/utils/fileSearch.d.ts.map +1 -0
  143. package/dist/utils/fileSearch.js +88 -0
  144. package/dist/utils/fileUtils.d.ts +27 -0
  145. package/dist/utils/fileUtils.d.ts.map +1 -0
  146. package/dist/utils/fileUtils.js +145 -0
  147. package/dist/utils/globalLogger.d.ts +88 -0
  148. package/dist/utils/globalLogger.d.ts.map +1 -0
  149. package/dist/utils/globalLogger.js +120 -0
  150. package/dist/utils/largeOutputHandler.d.ts +15 -0
  151. package/dist/utils/largeOutputHandler.d.ts.map +1 -0
  152. package/dist/utils/largeOutputHandler.js +40 -0
  153. package/dist/utils/markdownParser.d.ts.map +1 -1
  154. package/dist/utils/markdownParser.js +1 -17
  155. package/dist/utils/mcpUtils.d.ts.map +1 -1
  156. package/dist/utils/mcpUtils.js +25 -3
  157. package/dist/utils/messageOperations.d.ts +20 -18
  158. package/dist/utils/messageOperations.d.ts.map +1 -1
  159. package/dist/utils/messageOperations.js +30 -38
  160. package/dist/utils/pathEncoder.d.ts +108 -0
  161. package/dist/utils/pathEncoder.d.ts.map +1 -0
  162. package/dist/utils/pathEncoder.js +279 -0
  163. package/dist/utils/subagentParser.d.ts +2 -2
  164. package/dist/utils/subagentParser.d.ts.map +1 -1
  165. package/dist/utils/subagentParser.js +12 -8
  166. package/dist/utils/tokenCalculation.d.ts +26 -0
  167. package/dist/utils/tokenCalculation.d.ts.map +1 -0
  168. package/dist/utils/tokenCalculation.js +36 -0
  169. package/dist/utils/tokenEstimator.d.ts +39 -0
  170. package/dist/utils/tokenEstimator.d.ts.map +1 -0
  171. package/dist/utils/tokenEstimator.js +55 -0
  172. package/package.json +6 -6
  173. package/src/agent.ts +586 -78
  174. package/src/index.ts +4 -0
  175. package/src/managers/aiManager.ts +341 -192
  176. package/src/managers/backgroundBashManager.ts +11 -9
  177. package/src/managers/hookManager.ts +102 -54
  178. package/src/managers/liveConfigManager.ts +634 -0
  179. package/src/managers/lspManager.ts +434 -0
  180. package/src/managers/messageManager.ts +258 -121
  181. package/src/managers/permissionManager.ts +276 -0
  182. package/src/managers/skillManager.ts +3 -1
  183. package/src/managers/slashCommandManager.ts +5 -3
  184. package/src/managers/subagentManager.ts +295 -76
  185. package/src/managers/toolManager.ts +95 -3
  186. package/src/services/aiService.ts +656 -84
  187. package/src/services/configurationService.ts +762 -0
  188. package/src/services/fileWatcher.ts +300 -0
  189. package/src/services/hook.ts +54 -144
  190. package/src/services/jsonlHandler.ts +303 -0
  191. package/src/services/memory.ts +34 -11
  192. package/src/services/session.ts +522 -173
  193. package/src/tools/bashTool.ts +94 -20
  194. package/src/tools/deleteFileTool.ts +38 -1
  195. package/src/tools/editTool.ts +44 -9
  196. package/src/tools/lspTool.ts +760 -0
  197. package/src/tools/multiEditTool.ts +41 -11
  198. package/src/tools/readTool.ts +127 -3
  199. package/src/tools/skillTool.ts +2 -2
  200. package/src/tools/todoWriteTool.ts +33 -1
  201. package/src/tools/types.ts +15 -9
  202. package/src/tools/writeTool.ts +43 -16
  203. package/src/types/commands.ts +6 -1
  204. package/src/types/config.ts +5 -0
  205. package/src/types/configuration.ts +73 -0
  206. package/src/types/core.ts +55 -0
  207. package/src/types/environment.ts +104 -0
  208. package/src/types/fileSearch.ts +4 -0
  209. package/src/types/hooks.ts +32 -16
  210. package/src/types/index.ts +7 -0
  211. package/src/types/lsp.ts +96 -0
  212. package/src/types/messaging.ts +21 -14
  213. package/src/types/permissions.ts +48 -0
  214. package/src/types/session.ts +20 -0
  215. package/src/types/skills.ts +1 -0
  216. package/src/types/tools.ts +38 -0
  217. package/src/utils/abortUtils.ts +118 -0
  218. package/src/utils/bashHistory.ts +55 -31
  219. package/src/utils/builtinSubagents.ts +71 -0
  220. package/src/utils/cacheControlUtils.ts +475 -0
  221. package/src/utils/commandPathResolver.ts +189 -0
  222. package/src/utils/configPaths.ts +163 -0
  223. package/src/utils/constants.ts +2 -17
  224. package/src/utils/convertMessagesForAPI.ts +44 -18
  225. package/src/utils/customCommands.ts +90 -22
  226. package/src/utils/fileSearch.ts +107 -0
  227. package/src/utils/fileUtils.ts +160 -0
  228. package/src/utils/globalLogger.ts +128 -0
  229. package/src/utils/largeOutputHandler.ts +55 -0
  230. package/src/utils/markdownParser.ts +1 -19
  231. package/src/utils/mcpUtils.ts +34 -3
  232. package/src/utils/messageOperations.ts +47 -53
  233. package/src/utils/pathEncoder.ts +394 -0
  234. package/src/utils/subagentParser.ts +13 -9
  235. package/src/utils/tokenCalculation.ts +43 -0
  236. package/src/utils/tokenEstimator.ts +68 -0
  237. package/dist/utils/configResolver.d.ts +0 -38
  238. package/dist/utils/configResolver.d.ts.map +0 -1
  239. package/dist/utils/configResolver.js +0 -106
  240. package/src/utils/configResolver.ts +0 -142
@@ -1,4 +1,6 @@
1
1
  import { spawn } from "child_process";
2
+ import { logger } from "../utils/globalLogger.js";
3
+ import { stripAnsiColors } from "../utils/stringUtils.js";
2
4
  import type { BackgroundShell } from "../types/index.js";
3
5
 
4
6
  export interface BackgroundBashManagerCallbacks {
@@ -62,12 +64,12 @@ export class BackgroundBashManager {
62
64
  }
63
65
 
64
66
  child.stdout?.on("data", (data) => {
65
- shell.stdout += data.toString();
67
+ shell.stdout += stripAnsiColors(data.toString());
66
68
  this.notifyShellsChange();
67
69
  });
68
70
 
69
71
  child.stderr?.on("data", (data) => {
70
- shell.stderr += data.toString();
72
+ shell.stderr += stripAnsiColors(data.toString());
71
73
  this.notifyShellsChange();
72
74
  });
73
75
 
@@ -86,7 +88,7 @@ export class BackgroundBashManager {
86
88
  clearTimeout(timeoutHandle);
87
89
  }
88
90
  shell.status = "completed";
89
- shell.stderr += `\nProcess error: ${error.message}`;
91
+ shell.stderr += `\nProcess error: ${stripAnsiColors(error.message)}`;
90
92
  shell.exitCode = 1;
91
93
  shell.runtime = Date.now() - startTime;
92
94
  this.notifyShellsChange();
@@ -127,8 +129,8 @@ export class BackgroundBashManager {
127
129
  .split("\n")
128
130
  .filter((line) => regex.test(line))
129
131
  .join("\n");
130
- } catch {
131
- // logger.warn(`Invalid filter regex: ${filter}`, error);
132
+ } catch (error) {
133
+ logger.warn(`Invalid filter regex: ${filter}`, error);
132
134
  }
133
135
  }
134
136
 
@@ -159,8 +161,8 @@ export class BackgroundBashManager {
159
161
  ) {
160
162
  try {
161
163
  process.kill(-shell.process.pid, "SIGKILL");
162
- } catch {
163
- // logger.error("Failed to force kill process:", error);
164
+ } catch (error) {
165
+ logger.error("Failed to force kill process:", error);
164
166
  }
165
167
  }
166
168
  }, 1000);
@@ -183,8 +185,8 @@ export class BackgroundBashManager {
183
185
  shell.runtime = Date.now() - shell.startTime;
184
186
  this.notifyShellsChange();
185
187
  return true;
186
- } catch {
187
- // logger.error("Failed to kill child process:", directKillError);
188
+ } catch (directKillError) {
189
+ logger.error("Failed to kill child process:", directKillError);
188
190
  return false;
189
191
  }
190
192
  }
@@ -8,7 +8,7 @@
8
8
  import {
9
9
  type HookEvent,
10
10
  type HookEventConfig,
11
- type HookConfiguration,
11
+ type WaveConfiguration,
12
12
  type PartialHookConfiguration,
13
13
  type HookExecutionContext,
14
14
  type ExtendedHookExecutionContext,
@@ -19,11 +19,7 @@ import {
19
19
  isValidHookEventConfig,
20
20
  } from "../types/hooks.js";
21
21
  import { HookMatcher } from "../utils/hookMatcher.js";
22
- import {
23
- executeCommand,
24
- isCommandSafe,
25
- loadMergedHooksConfig,
26
- } from "../services/hook.js";
22
+ import { executeCommand, isCommandSafe } from "../services/hook.js";
27
23
  import type { Logger } from "../types/index.js";
28
24
  import { MessageSource } from "../types/index.js";
29
25
  import type { MessageManager } from "./messageManager.js";
@@ -77,41 +73,41 @@ export class HookManager {
77
73
  }
78
74
 
79
75
  /**
80
- * Load configuration from filesystem settings
81
- * Automatically loads and merges user and project hooks configuration
76
+ * Load hooks configuration from a pre-loaded WaveConfiguration
77
+ * Configuration loading is now handled by ConfigurationService
82
78
  */
83
- loadConfigurationFromSettings(): void {
79
+ loadConfigurationFromWaveConfig(waveConfig: WaveConfiguration | null): void {
84
80
  try {
85
- this.logger?.debug(`[HookManager] Loading configuration...`);
86
- const mergedConfig = loadMergedHooksConfig(this.workdir);
87
- this.logger?.debug(`[HookManager] Merged config result:`, mergedConfig);
88
- this.configuration = mergedConfig || undefined;
81
+ this.logger?.debug(
82
+ `[HookManager] Loading hooks configuration from pre-loaded config...`,
83
+ );
84
+
85
+ this.configuration = waveConfig?.hooks || undefined;
89
86
 
90
87
  // Validate the loaded configuration if it exists
91
- if (mergedConfig) {
92
- const validation = this.validatePartialConfiguration(mergedConfig);
88
+ if (waveConfig?.hooks) {
89
+ const validation = this.validatePartialConfiguration(waveConfig.hooks);
93
90
  if (!validation.valid) {
94
91
  throw new HookConfigurationError(
95
- "filesystem settings",
92
+ "provided configuration",
96
93
  validation.errors,
97
94
  );
98
95
  }
99
96
  }
100
97
 
101
98
  this.logger?.debug(
102
- `[HookManager] Configuration loaded successfully with ${Object.keys(mergedConfig || {}).length} event types`,
99
+ `[HookManager] Hooks configuration loaded successfully with ${Object.keys(waveConfig?.hooks || {}).length} event types`,
103
100
  );
104
101
  } catch (error) {
105
102
  // If loading fails, start with undefined configuration (no hooks)
106
103
  this.configuration = undefined;
107
104
 
108
- // Re-throw configuration errors, but handle file system errors gracefully
105
+ // Re-throw configuration errors, but handle other errors gracefully
109
106
  if (error instanceof HookConfigurationError) {
110
107
  throw error;
111
108
  } else {
112
109
  this.logger?.warn(
113
- "Failed to load hooks configuration from settings:",
114
- error,
110
+ `[HookManager] Failed to load configuration, continuing with no hooks: ${(error as Error).message}`,
115
111
  );
116
112
  }
117
113
  }
@@ -194,7 +190,11 @@ export class HookManager {
194
190
  `[HookManager] Executing command ${commandIndex + 1}/${config.hooks.length} in configuration ${configIndex + 1}`,
195
191
  );
196
192
 
197
- const result = await executeCommand(hookCommand.command, context);
193
+ const result = await executeCommand(
194
+ hookCommand.command,
195
+ context,
196
+ undefined,
197
+ );
198
198
  results.push(result);
199
199
 
200
200
  // Report individual command result
@@ -203,7 +203,7 @@ export class HookManager {
203
203
  `[HookManager] Command ${commandIndex + 1} completed successfully in ${result.duration}ms`,
204
204
  );
205
205
  } else {
206
- this.logger?.warn(
206
+ this.logger?.debug(
207
207
  `[HookManager] Command ${commandIndex + 1} failed in ${result.duration}ms (exit code: ${result.exitCode}, timed out: ${result.timedOut})`,
208
208
  );
209
209
  }
@@ -344,6 +344,7 @@ export class HookManager {
344
344
  result: errorMessage,
345
345
  success: false,
346
346
  error: "Hook blocked tool execution",
347
+ stage: "end", // Hook blocking results in end stage with error
347
348
  });
348
349
  }
349
350
  return { shouldBlock: true };
@@ -364,6 +365,19 @@ export class HookManager {
364
365
  });
365
366
  return { shouldBlock: true, errorMessage };
366
367
 
368
+ case "Notification":
369
+ // For notification hooks with exit code 2, only show stderr in error block
370
+ messageManager.addErrorBlock(errorMessage);
371
+ return { shouldBlock: false };
372
+
373
+ case "SubagentStop":
374
+ // Similar to Stop, show error and allow blocking
375
+ messageManager.addUserMessage({
376
+ content: errorMessage,
377
+ source: MessageSource.HOOK,
378
+ });
379
+ return { shouldBlock: true, errorMessage };
380
+
367
381
  default:
368
382
  return { shouldBlock: false };
369
383
  }
@@ -395,46 +409,62 @@ export class HookManager {
395
409
  }
396
410
 
397
411
  /**
398
- * Validate hook configuration structure and content
412
+ * Validate Wave configuration structure and content
399
413
  */
400
- validateConfiguration(config: HookConfiguration): ValidationResult {
414
+ validateConfiguration(config: WaveConfiguration): ValidationResult {
401
415
  const errors: string[] = [];
402
416
 
403
417
  if (!config || typeof config !== "object") {
404
418
  return { valid: false, errors: ["Configuration must be an object"] };
405
419
  }
406
420
 
407
- if (!config.hooks || typeof config.hooks !== "object") {
408
- return {
409
- valid: false,
410
- errors: ["Configuration must have a hooks property"],
411
- };
412
- }
421
+ // Validate hooks if present
422
+ if (config.hooks) {
423
+ if (typeof config.hooks !== "object") {
424
+ errors.push("hooks property must be an object");
425
+ } else {
426
+ // Validate each hook event
427
+ for (const [eventName, eventConfigs] of Object.entries(config.hooks)) {
428
+ // Validate event name
429
+ if (!isValidHookEvent(eventName)) {
430
+ errors.push(`Invalid hook event: ${eventName}`);
431
+ continue;
432
+ }
413
433
 
414
- // Validate each hook event
415
- for (const [eventName, eventConfigs] of Object.entries(config.hooks)) {
416
- // Validate event name
417
- if (!isValidHookEvent(eventName)) {
418
- errors.push(`Invalid hook event: ${eventName}`);
419
- continue;
420
- }
434
+ // Validate event configurations
435
+ if (!Array.isArray(eventConfigs)) {
436
+ errors.push(
437
+ `Hook event ${eventName} must be an array of configurations`,
438
+ );
439
+ continue;
440
+ }
421
441
 
422
- // Validate event configurations
423
- if (!Array.isArray(eventConfigs)) {
424
- errors.push(
425
- `Hook event ${eventName} must be an array of configurations`,
426
- );
427
- continue;
442
+ eventConfigs.forEach((eventConfig, index) => {
443
+ const configErrors = this.validateEventConfig(
444
+ eventName as HookEvent,
445
+ eventConfig,
446
+ index,
447
+ );
448
+ errors.push(...configErrors);
449
+ });
450
+ }
428
451
  }
452
+ }
429
453
 
430
- eventConfigs.forEach((eventConfig, index) => {
431
- const configErrors = this.validateEventConfig(
432
- eventName as HookEvent,
433
- eventConfig,
434
- index,
435
- );
436
- errors.push(...configErrors);
437
- });
454
+ // Validate environment variables if present
455
+ if (config.env) {
456
+ if (typeof config.env !== "object" || Array.isArray(config.env)) {
457
+ errors.push("env property must be an object");
458
+ } else {
459
+ for (const [key, value] of Object.entries(config.env)) {
460
+ if (typeof key !== "string" || key.trim() === "") {
461
+ errors.push(`Invalid environment variable key: ${key}`);
462
+ }
463
+ if (typeof value !== "string") {
464
+ errors.push(`Environment variable ${key} must have a string value`);
465
+ }
466
+ }
467
+ }
438
468
  }
439
469
 
440
470
  return {
@@ -544,7 +574,10 @@ export class HookManager {
544
574
 
545
575
  // Validate non-tool events don't have unexpected tool names
546
576
  if (
547
- (event === "UserPromptSubmit" || event === "Stop") &&
577
+ (event === "UserPromptSubmit" ||
578
+ event === "Stop" ||
579
+ event === "Notification" ||
580
+ event === "SubagentStop") &&
548
581
  context.toolName !== undefined
549
582
  ) {
550
583
  this.logger?.warn(
@@ -616,7 +649,12 @@ export class HookManager {
616
649
  toolName?: string,
617
650
  ): boolean {
618
651
  // For events that don't use matchers, config always applies
619
- if (event === "UserPromptSubmit" || event === "Stop") {
652
+ if (
653
+ event === "UserPromptSubmit" ||
654
+ event === "Stop" ||
655
+ event === "Notification" ||
656
+ event === "SubagentStop"
657
+ ) {
620
658
  return true;
621
659
  }
622
660
 
@@ -662,7 +700,13 @@ export class HookManager {
662
700
  }
663
701
 
664
702
  // Validate that non-tool events don't have matchers
665
- if ((event === "UserPromptSubmit" || event === "Stop") && config.matcher) {
703
+ if (
704
+ (event === "UserPromptSubmit" ||
705
+ event === "Stop" ||
706
+ event === "Notification" ||
707
+ event === "SubagentStop") &&
708
+ config.matcher
709
+ ) {
666
710
  errors.push(`${prefix}: Event ${event} should not have a matcher`);
667
711
  }
668
712
 
@@ -697,6 +741,8 @@ export class HookManager {
697
741
  PostToolUse: 0,
698
742
  UserPromptSubmit: 0,
699
743
  Stop: 0,
744
+ SubagentStop: 0,
745
+ Notification: 0,
700
746
  },
701
747
  };
702
748
  }
@@ -706,6 +752,8 @@ export class HookManager {
706
752
  PostToolUse: 0,
707
753
  UserPromptSubmit: 0,
708
754
  Stop: 0,
755
+ SubagentStop: 0,
756
+ Notification: 0,
709
757
  };
710
758
 
711
759
  let totalConfigs = 0;