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.
- package/dist/agent.d.ts +63 -9
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +103 -27
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/managers/aiManager.d.ts +5 -2
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +121 -53
- package/dist/managers/backgroundBashManager.d.ts +1 -1
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/{hooks/manager.d.ts → managers/hookManager.d.ts} +26 -7
- package/dist/managers/hookManager.d.ts.map +1 -0
- package/dist/{hooks/manager.js → managers/hookManager.js} +108 -18
- package/dist/managers/mcpManager.d.ts +1 -1
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/mcpManager.js +5 -5
- package/dist/managers/messageManager.d.ts +29 -5
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +33 -12
- package/dist/managers/skillManager.d.ts +1 -1
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +3 -3
- package/dist/managers/slashCommandManager.d.ts +1 -1
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +1 -1
- package/dist/managers/subagentManager.d.ts +9 -12
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +43 -45
- package/dist/managers/toolManager.d.ts +1 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/services/aiService.d.ts +10 -2
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +25 -4
- package/dist/services/hook.d.ts +56 -0
- package/dist/services/hook.d.ts.map +1 -0
- package/dist/services/hook.js +276 -0
- package/dist/services/memory.js +3 -3
- package/dist/services/session.d.ts +65 -16
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +85 -34
- package/dist/tools/bashTool.js +2 -2
- package/dist/tools/deleteFileTool.js +1 -1
- package/dist/tools/editTool.js +1 -1
- package/dist/tools/multiEditTool.js +2 -2
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +7 -3
- package/dist/tools/writeTool.js +1 -1
- package/dist/types/commands.d.ts +24 -0
- package/dist/types/commands.d.ts.map +1 -0
- package/dist/types/commands.js +5 -0
- package/dist/types/config.d.ts +13 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +5 -0
- package/dist/types/core.d.ts +38 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/{types.js → types/core.js} +4 -13
- package/dist/{hooks/types.d.ts → types/hooks.d.ts} +2 -1
- package/dist/types/hooks.d.ts.map +1 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +21 -0
- package/dist/types/mcp.d.ts +28 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +5 -0
- package/dist/types/messaging.d.ts +80 -0
- package/dist/types/messaging.d.ts.map +1 -0
- package/dist/types/messaging.js +5 -0
- package/dist/types/processes.d.ts +17 -0
- package/dist/types/processes.d.ts.map +1 -0
- package/dist/types/processes.js +5 -0
- package/dist/types/skills.d.ts +78 -0
- package/dist/types/skills.d.ts.map +1 -0
- package/dist/types/skills.js +17 -0
- package/dist/utils/configResolver.d.ts +1 -1
- package/dist/utils/configResolver.d.ts.map +1 -1
- package/dist/utils/configResolver.js +1 -1
- package/dist/utils/configValidator.d.ts +1 -1
- package/dist/utils/configValidator.d.ts.map +1 -1
- package/dist/utils/configValidator.js +1 -1
- package/dist/utils/convertMessagesForAPI.d.ts +1 -1
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/customCommands.d.ts +1 -1
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/{hooks/matcher.d.ts → utils/hookMatcher.d.ts} +1 -1
- package/dist/utils/hookMatcher.d.ts.map +1 -0
- package/dist/utils/markdownParser.d.ts +1 -1
- package/dist/utils/markdownParser.d.ts.map +1 -1
- package/dist/utils/mcpUtils.d.ts +1 -1
- package/dist/utils/mcpUtils.d.ts.map +1 -1
- package/dist/utils/messageOperations.d.ts +7 -2
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +18 -1
- package/dist/utils/skillParser.d.ts +1 -1
- package/dist/utils/skillParser.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agent.ts +150 -50
- package/src/index.ts +3 -4
- package/src/managers/aiManager.ts +282 -164
- package/src/managers/backgroundBashManager.ts +1 -1
- package/src/{hooks/manager.ts → managers/hookManager.ts} +163 -28
- package/src/managers/mcpManager.ts +6 -6
- package/src/managers/messageManager.ts +69 -10
- package/src/managers/skillManager.ts +4 -4
- package/src/managers/slashCommandManager.ts +6 -2
- package/src/managers/subagentManager.ts +58 -53
- package/src/managers/toolManager.ts +1 -1
- package/src/services/aiService.ts +37 -7
- package/src/services/hook.ts +360 -0
- package/src/services/memory.ts +3 -3
- package/src/services/session.ts +99 -33
- package/src/tools/bashTool.ts +2 -2
- package/src/tools/deleteFileTool.ts +1 -1
- package/src/tools/editTool.ts +1 -1
- package/src/tools/multiEditTool.ts +2 -2
- package/src/tools/taskTool.ts +13 -5
- package/src/tools/writeTool.ts +1 -1
- package/src/types/commands.ts +26 -0
- package/src/types/config.ts +14 -0
- package/src/types/core.ts +49 -0
- package/src/{hooks/types.ts → types/hooks.ts} +1 -0
- package/src/types/index.ts +23 -0
- package/src/{types.ts → types/index.ts.backup} +13 -0
- package/src/types/mcp.ts +31 -0
- package/src/types/messaging.ts +103 -0
- package/src/types/processes.ts +18 -0
- package/src/types/skills.ts +91 -0
- package/src/utils/configResolver.ts +1 -1
- package/src/utils/configValidator.ts +5 -1
- package/src/utils/convertMessagesForAPI.ts +1 -1
- package/src/utils/customCommands.ts +1 -1
- package/src/utils/markdownParser.ts +1 -1
- package/src/utils/mcpUtils.ts +1 -1
- package/src/utils/messageOperations.ts +22 -1
- package/src/utils/skillParser.ts +1 -1
- package/dist/hooks/executor.d.ts +0 -56
- package/dist/hooks/executor.d.ts.map +0 -1
- package/dist/hooks/executor.js +0 -312
- package/dist/hooks/index.d.ts +0 -17
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js +0 -14
- package/dist/hooks/manager.d.ts.map +0 -1
- package/dist/hooks/matcher.d.ts.map +0 -1
- package/dist/hooks/settings.d.ts +0 -46
- package/dist/hooks/settings.d.ts.map +0 -1
- package/dist/hooks/settings.js +0 -100
- package/dist/hooks/types.d.ts.map +0 -1
- package/dist/types.d.ts +0 -276
- package/dist/types.d.ts.map +0 -1
- package/src/hooks/executor.ts +0 -440
- package/src/hooks/index.ts +0 -52
- package/src/hooks/settings.ts +0 -129
- /package/dist/{hooks/types.js → types/hooks.js} +0 -0
- /package/dist/{hooks/matcher.js → utils/hookMatcher.js} +0 -0
- /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 "
|
|
21
|
-
import { type IHookMatcher, HookMatcher } from "
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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(
|
|
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
|
|
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?.
|
|
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 (!
|
|
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?.
|
|
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?.
|
|
66
|
+
this.logger?.debug(`Connecting to MCP server: ${serverName}`);
|
|
67
67
|
const success = await this.connectServer(serverName);
|
|
68
68
|
if (success) {
|
|
69
|
-
this.logger?.
|
|
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?.
|
|
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?.
|
|
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?: (
|
|
67
|
-
|
|
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
|
-
|
|
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(
|
|
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?.(
|
|
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?.
|
|
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?.
|
|
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?.
|
|
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 {
|
|
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?.
|
|
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
|
}
|