wave-agent-sdk 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/dist/agent.d.ts +63 -9
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +103 -27
  4. package/dist/index.d.ts +3 -2
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +3 -3
  7. package/dist/managers/aiManager.d.ts +5 -2
  8. package/dist/managers/aiManager.d.ts.map +1 -1
  9. package/dist/managers/aiManager.js +121 -53
  10. package/dist/managers/backgroundBashManager.d.ts +1 -1
  11. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  12. package/dist/{hooks/manager.d.ts → managers/hookManager.d.ts} +26 -7
  13. package/dist/managers/hookManager.d.ts.map +1 -0
  14. package/dist/{hooks/manager.js → managers/hookManager.js} +108 -18
  15. package/dist/managers/mcpManager.d.ts +1 -1
  16. package/dist/managers/mcpManager.d.ts.map +1 -1
  17. package/dist/managers/mcpManager.js +5 -5
  18. package/dist/managers/messageManager.d.ts +29 -5
  19. package/dist/managers/messageManager.d.ts.map +1 -1
  20. package/dist/managers/messageManager.js +33 -12
  21. package/dist/managers/skillManager.d.ts +1 -1
  22. package/dist/managers/skillManager.d.ts.map +1 -1
  23. package/dist/managers/skillManager.js +3 -3
  24. package/dist/managers/slashCommandManager.d.ts +1 -1
  25. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  26. package/dist/managers/slashCommandManager.js +1 -1
  27. package/dist/managers/subagentManager.d.ts +9 -12
  28. package/dist/managers/subagentManager.d.ts.map +1 -1
  29. package/dist/managers/subagentManager.js +43 -45
  30. package/dist/managers/toolManager.d.ts +1 -1
  31. package/dist/managers/toolManager.d.ts.map +1 -1
  32. package/dist/services/aiService.d.ts +10 -2
  33. package/dist/services/aiService.d.ts.map +1 -1
  34. package/dist/services/aiService.js +25 -4
  35. package/dist/services/hook.d.ts +56 -0
  36. package/dist/services/hook.d.ts.map +1 -0
  37. package/dist/services/hook.js +276 -0
  38. package/dist/services/memory.js +3 -3
  39. package/dist/services/session.d.ts +65 -16
  40. package/dist/services/session.d.ts.map +1 -1
  41. package/dist/services/session.js +85 -34
  42. package/dist/tools/bashTool.js +2 -2
  43. package/dist/tools/deleteFileTool.js +1 -1
  44. package/dist/tools/editTool.js +1 -1
  45. package/dist/tools/multiEditTool.js +2 -2
  46. package/dist/tools/taskTool.d.ts.map +1 -1
  47. package/dist/tools/taskTool.js +7 -3
  48. package/dist/tools/writeTool.js +1 -1
  49. package/dist/types/commands.d.ts +24 -0
  50. package/dist/types/commands.d.ts.map +1 -0
  51. package/dist/types/commands.js +5 -0
  52. package/dist/types/config.d.ts +13 -0
  53. package/dist/types/config.d.ts.map +1 -0
  54. package/dist/types/config.js +5 -0
  55. package/dist/types/core.d.ts +38 -0
  56. package/dist/types/core.d.ts.map +1 -0
  57. package/dist/{types.js → types/core.js} +4 -13
  58. package/dist/{hooks/types.d.ts → types/hooks.d.ts} +2 -1
  59. package/dist/types/hooks.d.ts.map +1 -0
  60. package/dist/types/index.d.ts +20 -0
  61. package/dist/types/index.d.ts.map +1 -0
  62. package/dist/types/index.js +21 -0
  63. package/dist/types/mcp.d.ts +28 -0
  64. package/dist/types/mcp.d.ts.map +1 -0
  65. package/dist/types/mcp.js +5 -0
  66. package/dist/types/messaging.d.ts +80 -0
  67. package/dist/types/messaging.d.ts.map +1 -0
  68. package/dist/types/messaging.js +5 -0
  69. package/dist/types/processes.d.ts +17 -0
  70. package/dist/types/processes.d.ts.map +1 -0
  71. package/dist/types/processes.js +5 -0
  72. package/dist/types/skills.d.ts +78 -0
  73. package/dist/types/skills.d.ts.map +1 -0
  74. package/dist/types/skills.js +17 -0
  75. package/dist/utils/configResolver.d.ts +1 -1
  76. package/dist/utils/configResolver.d.ts.map +1 -1
  77. package/dist/utils/configResolver.js +1 -1
  78. package/dist/utils/configValidator.d.ts +1 -1
  79. package/dist/utils/configValidator.d.ts.map +1 -1
  80. package/dist/utils/configValidator.js +1 -1
  81. package/dist/utils/convertMessagesForAPI.d.ts +1 -1
  82. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
  83. package/dist/utils/customCommands.d.ts +1 -1
  84. package/dist/utils/customCommands.d.ts.map +1 -1
  85. package/dist/{hooks/matcher.d.ts → utils/hookMatcher.d.ts} +1 -1
  86. package/dist/utils/hookMatcher.d.ts.map +1 -0
  87. package/dist/utils/markdownParser.d.ts +1 -1
  88. package/dist/utils/markdownParser.d.ts.map +1 -1
  89. package/dist/utils/mcpUtils.d.ts +1 -1
  90. package/dist/utils/mcpUtils.d.ts.map +1 -1
  91. package/dist/utils/messageOperations.d.ts +7 -2
  92. package/dist/utils/messageOperations.d.ts.map +1 -1
  93. package/dist/utils/messageOperations.js +18 -1
  94. package/dist/utils/skillParser.d.ts +1 -1
  95. package/dist/utils/skillParser.d.ts.map +1 -1
  96. package/package.json +1 -1
  97. package/src/agent.ts +150 -50
  98. package/src/index.ts +3 -4
  99. package/src/managers/aiManager.ts +282 -164
  100. package/src/managers/backgroundBashManager.ts +1 -1
  101. package/src/{hooks/manager.ts → managers/hookManager.ts} +163 -28
  102. package/src/managers/mcpManager.ts +6 -6
  103. package/src/managers/messageManager.ts +69 -10
  104. package/src/managers/skillManager.ts +4 -4
  105. package/src/managers/slashCommandManager.ts +6 -2
  106. package/src/managers/subagentManager.ts +58 -53
  107. package/src/managers/toolManager.ts +1 -1
  108. package/src/services/aiService.ts +37 -7
  109. package/src/services/hook.ts +360 -0
  110. package/src/services/memory.ts +3 -3
  111. package/src/services/session.ts +99 -33
  112. package/src/tools/bashTool.ts +2 -2
  113. package/src/tools/deleteFileTool.ts +1 -1
  114. package/src/tools/editTool.ts +1 -1
  115. package/src/tools/multiEditTool.ts +2 -2
  116. package/src/tools/taskTool.ts +13 -5
  117. package/src/tools/writeTool.ts +1 -1
  118. package/src/types/commands.ts +26 -0
  119. package/src/types/config.ts +14 -0
  120. package/src/types/core.ts +49 -0
  121. package/src/{hooks/types.ts → types/hooks.ts} +1 -0
  122. package/src/types/index.ts +23 -0
  123. package/src/{types.ts → types/index.ts.backup} +13 -0
  124. package/src/types/mcp.ts +31 -0
  125. package/src/types/messaging.ts +103 -0
  126. package/src/types/processes.ts +18 -0
  127. package/src/types/skills.ts +91 -0
  128. package/src/utils/configResolver.ts +1 -1
  129. package/src/utils/configValidator.ts +5 -1
  130. package/src/utils/convertMessagesForAPI.ts +1 -1
  131. package/src/utils/customCommands.ts +1 -1
  132. package/src/utils/markdownParser.ts +1 -1
  133. package/src/utils/mcpUtils.ts +1 -1
  134. package/src/utils/messageOperations.ts +22 -1
  135. package/src/utils/skillParser.ts +1 -1
  136. package/dist/hooks/executor.d.ts +0 -56
  137. package/dist/hooks/executor.d.ts.map +0 -1
  138. package/dist/hooks/executor.js +0 -312
  139. package/dist/hooks/index.d.ts +0 -17
  140. package/dist/hooks/index.d.ts.map +0 -1
  141. package/dist/hooks/index.js +0 -14
  142. package/dist/hooks/manager.d.ts.map +0 -1
  143. package/dist/hooks/matcher.d.ts.map +0 -1
  144. package/dist/hooks/settings.d.ts +0 -46
  145. package/dist/hooks/settings.d.ts.map +0 -1
  146. package/dist/hooks/settings.js +0 -100
  147. package/dist/hooks/types.d.ts.map +0 -1
  148. package/dist/types.d.ts +0 -276
  149. package/dist/types.d.ts.map +0 -1
  150. package/src/hooks/executor.ts +0 -440
  151. package/src/hooks/index.ts +0 -52
  152. package/src/hooks/settings.ts +0 -129
  153. /package/dist/{hooks/types.js → types/hooks.js} +0 -0
  154. /package/dist/{hooks/matcher.js → utils/hookMatcher.js} +0 -0
  155. /package/src/{hooks/matcher.ts → utils/hookMatcher.ts} +0 -0
@@ -17,11 +17,15 @@ import {
17
17
  HookConfigurationError,
18
18
  isValidHookEvent,
19
19
  isValidHookEventConfig,
20
- } from "./types.js";
21
- import { type IHookMatcher, HookMatcher } from "./matcher.js";
22
- import { type IHookExecutor, HookExecutor } from "./executor.js";
23
- import { loadMergedHooksConfig } from "./settings.js";
24
- import type { Logger } from "../types.js";
20
+ } from "../types/hooks.js";
21
+ import { type IHookMatcher, HookMatcher } from "../utils/hookMatcher.js";
22
+ import {
23
+ executeCommand,
24
+ isCommandSafe,
25
+ loadMergedHooksConfig,
26
+ } from "../services/hook.js";
27
+ import type { Logger } from "../types/index.js";
28
+ import type { MessageManager } from "./messageManager.js";
25
29
 
26
30
  export interface IHookManager {
27
31
  // Load configuration from settings
@@ -52,22 +56,16 @@ export interface IHookManager {
52
56
  export class HookManager implements IHookManager {
53
57
  private configuration: PartialHookConfiguration | undefined;
54
58
  private readonly matcher: IHookMatcher;
55
- private readonly executor: IHookExecutor;
56
59
  private readonly logger?: Logger;
57
60
  private readonly workdir: string;
58
61
 
59
62
  constructor(
60
63
  workdir: string,
61
64
  matcher: IHookMatcher = new HookMatcher(),
62
- executor?: IHookExecutor,
63
65
  logger?: Logger,
64
66
  ) {
65
67
  this.workdir = workdir;
66
68
  this.matcher = matcher;
67
- // Create executor with logger if provided, or use passed executor, or create default
68
- this.executor = logger
69
- ? new HookExecutor(logger)
70
- : executor || new HookExecutor();
71
69
  this.logger = logger;
72
70
  }
73
71
 
@@ -112,19 +110,21 @@ export class HookManager implements IHookManager {
112
110
  this.logger?.debug(`[HookManager] Loading configuration...`);
113
111
  const mergedConfig = loadMergedHooksConfig(this.workdir);
114
112
  this.logger?.debug(`[HookManager] Merged config result:`, mergedConfig);
115
- this.configuration = mergedConfig;
116
-
117
- // Validate the loaded configuration
118
- const validation = this.validatePartialConfiguration(mergedConfig);
119
- if (!validation.valid) {
120
- throw new HookConfigurationError(
121
- "filesystem settings",
122
- validation.errors,
123
- );
113
+ this.configuration = mergedConfig || undefined;
114
+
115
+ // Validate the loaded configuration if it exists
116
+ if (mergedConfig) {
117
+ const validation = this.validatePartialConfiguration(mergedConfig);
118
+ if (!validation.valid) {
119
+ throw new HookConfigurationError(
120
+ "filesystem settings",
121
+ validation.errors,
122
+ );
123
+ }
124
124
  }
125
125
 
126
126
  this.logger?.debug(
127
- `[HookManager] Configuration loaded successfully with ${Object.keys(mergedConfig).length} event types`,
127
+ `[HookManager] Configuration loaded successfully with ${Object.keys(mergedConfig || {}).length} event types`,
128
128
  );
129
129
  } catch (error) {
130
130
  // If loading fails, start with undefined configuration (no hooks)
@@ -174,7 +174,9 @@ export class HookManager implements IHookManager {
174
174
 
175
175
  const eventConfigs = this.configuration[event];
176
176
  if (!eventConfigs || eventConfigs.length === 0) {
177
- this.logger?.debug(`[HookManager] No hooks configured for ${event} event`);
177
+ this.logger?.debug(
178
+ `[HookManager] No hooks configured for ${event} event`,
179
+ );
178
180
  return [];
179
181
  }
180
182
 
@@ -217,10 +219,7 @@ export class HookManager implements IHookManager {
217
219
  `[HookManager] Executing command ${commandIndex + 1}/${config.hooks.length} in configuration ${configIndex + 1}`,
218
220
  );
219
221
 
220
- const result = await this.executor.executeCommand(
221
- hookCommand.command,
222
- context,
223
- );
222
+ const result = await executeCommand(hookCommand.command, context);
224
223
  results.push(result);
225
224
 
226
225
  // Report individual command result
@@ -261,11 +260,147 @@ export class HookManager implements IHookManager {
261
260
  results,
262
261
  totalDuration,
263
262
  );
264
- this.logger?.info(`[HookManager] ${event} execution summary: ${summary}`);
263
+ this.logger?.debug(`[HookManager] ${event} execution summary: ${summary}`);
265
264
 
266
265
  return results;
267
266
  }
268
267
 
268
+ /**
269
+ * Process hook execution results and determine appropriate actions
270
+ * based on exit codes and hook event type
271
+ */
272
+ processHookResults(
273
+ event: HookEvent,
274
+ results: HookExecutionResult[],
275
+ messageManager?: MessageManager,
276
+ toolId?: string,
277
+ originalToolResult?: string,
278
+ ): {
279
+ shouldBlock: boolean;
280
+ errorMessage?: string;
281
+ } {
282
+ if (!messageManager || results.length === 0) {
283
+ return { shouldBlock: false };
284
+ }
285
+
286
+ // First pass: Check for any blocking errors (exit code 2)
287
+ // Blocking errors take precedence and stop all processing
288
+ for (const result of results) {
289
+ if (result.exitCode === 2) {
290
+ // Handle blocking error immediately and return
291
+ return this.handleBlockingError(
292
+ event,
293
+ result,
294
+ messageManager,
295
+ toolId,
296
+ originalToolResult,
297
+ );
298
+ }
299
+ }
300
+
301
+ // Second pass: Process all non-blocking results
302
+ for (const result of results) {
303
+ if (result.exitCode === undefined) {
304
+ continue; // Skip results without exit codes
305
+ }
306
+
307
+ // Handle exit code interpretation
308
+ if (result.exitCode === 0) {
309
+ // Success case - handle stdout based on hook type
310
+ this.handleHookSuccess(event, result, messageManager);
311
+ } else {
312
+ // Non-blocking error case (any exit code except 0 and 2)
313
+ this.handleNonBlockingError(result, messageManager);
314
+ }
315
+ }
316
+
317
+ return { shouldBlock: false };
318
+ }
319
+
320
+ /**
321
+ * Handle successful hook execution (exit code 0)
322
+ */
323
+ private handleHookSuccess(
324
+ event: HookEvent,
325
+ result: HookExecutionResult,
326
+ messageManager: MessageManager,
327
+ ): void {
328
+ if (event === "UserPromptSubmit" && result.stdout?.trim()) {
329
+ // Inject stdout as user message context for UserPromptSubmit
330
+ messageManager.addUserMessage(result.stdout.trim());
331
+ }
332
+ // For other hook types (PreToolUse, PostToolUse, Stop), ignore stdout
333
+ }
334
+
335
+ /**
336
+ * Handle blocking error (exit code 2) - behavior varies by hook type
337
+ */
338
+ private handleBlockingError(
339
+ event: HookEvent,
340
+ result: HookExecutionResult,
341
+ messageManager: MessageManager,
342
+ toolId?: string,
343
+ originalToolResult?: string,
344
+ ): {
345
+ shouldBlock: boolean;
346
+ errorMessage?: string;
347
+ } {
348
+ const errorMessage = result.stderr?.trim() || "Hook execution failed";
349
+
350
+ switch (event) {
351
+ case "UserPromptSubmit":
352
+ // Block prompt processing, show error to user, erase prompt
353
+ messageManager.addErrorBlock(errorMessage);
354
+ messageManager.removeLastUserMessage();
355
+ return {
356
+ shouldBlock: true,
357
+ errorMessage,
358
+ };
359
+
360
+ case "PreToolUse":
361
+ // Block tool execution and show error to Wave Agent via tool block
362
+ if (toolId) {
363
+ messageManager.updateToolBlock({
364
+ toolId,
365
+ result: errorMessage,
366
+ success: false,
367
+ error: "Hook blocked tool execution",
368
+ });
369
+ }
370
+ return { shouldBlock: true };
371
+
372
+ case "PostToolUse":
373
+ // Show error to Wave Agent via tool block, execution continues
374
+ if (toolId && originalToolResult !== undefined) {
375
+ messageManager.updateToolBlock({
376
+ toolId,
377
+ result: `${originalToolResult}\n\nHook feedback: ${errorMessage}`,
378
+ success: false,
379
+ });
380
+ }
381
+ return { shouldBlock: false };
382
+
383
+ case "Stop":
384
+ // Show error to Wave Agent via user message and block stopping to continue conversation
385
+ messageManager.addUserMessage(errorMessage);
386
+ return { shouldBlock: true, errorMessage };
387
+
388
+ default:
389
+ return { shouldBlock: false };
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Handle non-blocking error (other exit codes)
395
+ */
396
+ private handleNonBlockingError(
397
+ result: HookExecutionResult,
398
+ messageManager: MessageManager,
399
+ ): void {
400
+ const errorMessage = result.stderr?.trim() || "Hook execution failed";
401
+ messageManager.addErrorBlock(errorMessage);
402
+ }
403
+
269
404
  /**
270
405
  * Check if hooks are configured for an event/tool combination
271
406
  */
@@ -554,7 +689,7 @@ export class HookManager implements IHookManager {
554
689
 
555
690
  // Validate commands
556
691
  config.hooks.forEach((hookCommand, cmdIndex) => {
557
- if (!this.executor.isCommandSafe(hookCommand.command)) {
692
+ if (!isCommandSafe(hookCommand.command)) {
558
693
  errors.push(
559
694
  `${prefix}.hooks[${cmdIndex}]: Command may be unsafe: ${hookCommand.command}`,
560
695
  );
@@ -11,7 +11,7 @@ import type {
11
11
  McpConfig,
12
12
  McpTool,
13
13
  McpServerStatus,
14
- } from "../types.js";
14
+ } from "../types/index.js";
15
15
 
16
16
  interface McpConnection {
17
17
  client: Client;
@@ -53,7 +53,7 @@ export class McpManager {
53
53
  this.workdir = workdir;
54
54
 
55
55
  if (autoConnect) {
56
- this.logger?.info("Initializing MCP servers...");
56
+ this.logger?.debug("Initializing MCP servers...");
57
57
 
58
58
  // Ensure MCP configuration is loaded
59
59
  const config = await this.ensureConfigLoaded();
@@ -63,10 +63,10 @@ export class McpManager {
63
63
  const connectionPromises = Object.keys(config.mcpServers).map(
64
64
  async (serverName) => {
65
65
  try {
66
- this.logger?.info(`Connecting to MCP server: ${serverName}`);
66
+ this.logger?.debug(`Connecting to MCP server: ${serverName}`);
67
67
  const success = await this.connectServer(serverName);
68
68
  if (success) {
69
- this.logger?.info(
69
+ this.logger?.debug(
70
70
  `Successfully connected to MCP server: ${serverName}`,
71
71
  );
72
72
  } else {
@@ -86,7 +86,7 @@ export class McpManager {
86
86
  await Promise.all(connectionPromises);
87
87
  }
88
88
 
89
- this.logger?.info("MCP servers initialization completed");
89
+ this.logger?.debug("MCP servers initialization completed");
90
90
  // Trigger state change callback after initialization
91
91
  this.callbacks.onServersChange?.(this.getAllServers());
92
92
  }
@@ -255,7 +255,7 @@ export class McpManager {
255
255
  };
256
256
 
257
257
  transport.onclose = () => {
258
- this.logger?.info(`MCP Server ${name} transport closed`);
258
+ this.logger?.debug(`MCP Server ${name} transport closed`);
259
259
  this.connections.delete(name);
260
260
  this.updateServerStatus(name, {
261
261
  status: "disconnected",
@@ -12,11 +12,12 @@ import {
12
12
  completeCommandInMessage,
13
13
  addSubagentBlockToMessage,
14
14
  updateSubagentBlockInMessage,
15
+ removeLastUserMessage,
15
16
  type AddSubagentBlockParams,
16
17
  type UpdateSubagentBlockParams,
17
18
  type AgentToolBlockUpdateParams,
18
19
  } from "../utils/messageOperations.js";
19
- import type { Logger, Message } from "../types.js";
20
+ import type { Logger, Message, Usage } from "../types/index.js";
20
21
  import {
21
22
  cleanupExpiredSessions,
22
23
  getLatestSession,
@@ -32,6 +33,7 @@ export interface MessageManagerCallbacks {
32
33
  onSessionIdChange?: (sessionId: string) => void;
33
34
  onLatestTotalTokensChange?: (latestTotalTokens: number) => void;
34
35
  onUserInputHistoryChange?: (history: string[]) => void;
36
+ onUsagesChange?: (usages: Usage[]) => void;
35
37
  // Incremental callback
36
38
  onUserMessageAdded?: (
37
39
  content: string,
@@ -63,14 +65,32 @@ export interface MessageManagerCallbacks {
63
65
  onUpdateCommandOutputMessage?: (command: string, output: string) => void;
64
66
  onCompleteCommandMessage?: (command: string, exitCode: number) => void;
65
67
  // Subagent callbacks
66
- onSubAgentBlockAdded?: (subagentId: string) => void;
67
- onSubAgentBlockUpdated?: (subagentId: string, messages: Message[]) => void;
68
+ onSubAgentBlockAdded?: (
69
+ subagentId: string,
70
+ parameters: {
71
+ description: string;
72
+ prompt: string;
73
+ subagent_type: string;
74
+ },
75
+ ) => void;
76
+ onSubAgentBlockUpdated?: (
77
+ subagentId: string,
78
+ messages: Message[],
79
+ status: "active" | "completed" | "error" | "aborted",
80
+ ) => void;
68
81
  }
69
82
 
70
83
  export interface MessageManagerOptions {
71
84
  callbacks: MessageManagerCallbacks;
72
85
  workdir: string;
73
86
  logger?: Logger;
87
+
88
+ // New: Optional session directory override
89
+ /**
90
+ * Custom session directory path
91
+ * @default join(homedir(), ".wave", "sessions")
92
+ */
93
+ sessionDir?: string;
74
94
  }
75
95
 
76
96
  export class MessageManager {
@@ -83,6 +103,7 @@ export class MessageManager {
83
103
  private workdir: string;
84
104
  private logger?: Logger; // Add optional logger property
85
105
  private callbacks: MessageManagerCallbacks;
106
+ private sessionDir?: string; // Add session directory property
86
107
 
87
108
  constructor(options: MessageManagerOptions) {
88
109
  this.sessionId = randomUUID();
@@ -93,6 +114,7 @@ export class MessageManager {
93
114
  this.workdir = options.workdir;
94
115
  this.callbacks = options.callbacks;
95
116
  this.logger = options.logger;
117
+ this.sessionDir = options.sessionDir;
96
118
  }
97
119
 
98
120
  // Getter methods
@@ -113,7 +135,7 @@ export class MessageManager {
113
135
  }
114
136
 
115
137
  public getTranscriptPath(): string {
116
- return getSessionFilePath(this.sessionId);
138
+ return getSessionFilePath(this.sessionId, this.sessionDir);
117
139
  }
118
140
 
119
141
  // Setter methods, will trigger callbacks
@@ -140,6 +162,7 @@ export class MessageManager {
140
162
  this.workdir,
141
163
  this.latestTotalTokens,
142
164
  this.sessionStartTime,
165
+ this.sessionDir,
143
166
  );
144
167
  } catch (error) {
145
168
  this.logger?.error("Failed to save session:", error);
@@ -155,9 +178,9 @@ export class MessageManager {
155
178
  ): Promise<void> {
156
179
  // Clean up expired sessions first
157
180
  try {
158
- await cleanupExpiredSessions(this.workdir);
181
+ await cleanupExpiredSessions(this.workdir, this.sessionDir);
159
182
  } catch (error) {
160
- console.warn("Failed to cleanup expired sessions:", error);
183
+ this.logger?.warn("Failed to cleanup expired sessions:", error);
161
184
  }
162
185
 
163
186
  if (!restoreSessionId && !continueLastSession) {
@@ -168,13 +191,16 @@ export class MessageManager {
168
191
  let sessionToRestore: SessionData | null = null;
169
192
 
170
193
  if (restoreSessionId) {
171
- sessionToRestore = await loadSession(restoreSessionId);
194
+ sessionToRestore = await loadSession(restoreSessionId, this.sessionDir);
172
195
  if (!sessionToRestore) {
173
196
  console.error(`Session not found: ${restoreSessionId}`);
174
197
  process.exit(1);
175
198
  }
176
199
  } else if (continueLastSession) {
177
- sessionToRestore = await getLatestSession(this.workdir);
200
+ sessionToRestore = await getLatestSession(
201
+ this.workdir,
202
+ this.sessionDir,
203
+ );
178
204
  if (!sessionToRestore) {
179
205
  console.error(
180
206
  `No previous session found for workdir: ${this.workdir}`,
@@ -290,11 +316,13 @@ export class MessageManager {
290
316
  public addAssistantMessage(
291
317
  content?: string,
292
318
  toolCalls?: ChatCompletionMessageFunctionToolCall[],
319
+ usage?: Usage,
293
320
  ): void {
294
321
  const newMessages = addAssistantMessageToMessages(
295
322
  this.messages,
296
323
  content,
297
324
  toolCalls,
325
+ usage,
298
326
  );
299
327
  this.setMessages(newMessages);
300
328
  this.callbacks.onAssistantMessageAdded?.(content, toolCalls);
@@ -432,6 +460,11 @@ export class MessageManager {
432
460
  subagentName: string,
433
461
  status: "active" | "completed" | "error" = "active",
434
462
  subagentMessages: Message[] = [],
463
+ parameters: {
464
+ description: string;
465
+ prompt: string;
466
+ subagent_type: string;
467
+ },
435
468
  ): void {
436
469
  const params: AddSubagentBlockParams = {
437
470
  messages: this.messages,
@@ -442,7 +475,7 @@ export class MessageManager {
442
475
  };
443
476
  const updatedMessages = addSubagentBlockToMessage(params);
444
477
  this.setMessages(updatedMessages);
445
- this.callbacks.onSubAgentBlockAdded?.(params.subagentId);
478
+ this.callbacks.onSubAgentBlockAdded?.(params.subagentId, parameters);
446
479
  }
447
480
 
448
481
  public updateSubagentBlock(
@@ -464,6 +497,32 @@ export class MessageManager {
464
497
  status: updates.status || "active",
465
498
  subagentMessages: updates.messages || [],
466
499
  };
467
- this.callbacks.onSubAgentBlockUpdated?.(params.subagentId, params.messages);
500
+ this.callbacks.onSubAgentBlockUpdated?.(
501
+ params.subagentId,
502
+ params.messages,
503
+ params.status,
504
+ );
505
+ }
506
+
507
+ /**
508
+ * Trigger usage change callback with all usage data from assistant messages
509
+ */
510
+ public triggerUsageChange(): void {
511
+ const usages: Usage[] = [];
512
+ for (const message of this.messages) {
513
+ if (message.role === "assistant" && message.usage) {
514
+ usages.push(message.usage);
515
+ }
516
+ }
517
+ this.callbacks.onUsagesChange?.(usages);
518
+ }
519
+
520
+ /**
521
+ * Remove the last user message from the conversation
522
+ * Used for hook error handling when the user prompt needs to be erased
523
+ */
524
+ public removeLastUserMessage(): void {
525
+ const newMessages = removeLastUserMessage(this.messages);
526
+ this.setMessages(newMessages);
468
527
  }
469
528
  }
@@ -10,7 +10,7 @@ import type {
10
10
  SkillToolArgs,
11
11
  SkillInvocationContext,
12
12
  Logger,
13
- } from "../types.js";
13
+ } from "../types/index.js";
14
14
  import { parseSkillFile, formatSkillError } from "../utils/skillParser.js";
15
15
 
16
16
  /**
@@ -36,7 +36,7 @@ export class SkillManager {
36
36
  * Initialize the skill manager by discovering available skills
37
37
  */
38
38
  async initialize(): Promise<void> {
39
- this.logger?.info("Initializing SkillManager...");
39
+ this.logger?.debug("Initializing SkillManager...");
40
40
 
41
41
  try {
42
42
  // Clear existing data before discovery
@@ -66,7 +66,7 @@ export class SkillManager {
66
66
  }
67
67
 
68
68
  this.initialized = true;
69
- this.logger?.info(
69
+ this.logger?.debug(
70
70
  `SkillManager initialized with ${this.skillMetadata.size} skills`,
71
71
  );
72
72
  } catch (error) {
@@ -247,7 +247,7 @@ export class SkillManager {
247
247
  ): Promise<{ content: string; context?: SkillInvocationContext }> {
248
248
  const { skill_name } = args;
249
249
 
250
- this.logger?.info(`Invoking skill: ${skill_name}`);
250
+ this.logger?.debug(`Invoking skill: ${skill_name}`);
251
251
 
252
252
  try {
253
253
  // Load the skill
@@ -1,6 +1,10 @@
1
1
  import type { MessageManager } from "./messageManager.js";
2
2
  import type { AIManager } from "./aiManager.js";
3
- import type { SlashCommand, CustomSlashCommand, Logger } from "../types.js";
3
+ import type {
4
+ SlashCommand,
5
+ CustomSlashCommand,
6
+ Logger,
7
+ } from "../types/index.js";
4
8
  import { loadCustomSlashCommands } from "../utils/customCommands.js";
5
9
 
6
10
  import {
@@ -92,7 +96,7 @@ export class SlashCommandManager {
92
96
  });
93
97
  }
94
98
 
95
- this.logger?.info(`Loaded ${customCommands.length} custom commands`);
99
+ this.logger?.debug(`Loaded ${customCommands.length} custom commands`);
96
100
  } catch (error) {
97
101
  this.logger?.warn("Failed to load custom commands:", error);
98
102
  }