wave-agent-sdk 0.7.2 → 0.8.1

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 +9 -79
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +85 -302
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -1
  7. package/dist/managers/aiManager.d.ts.map +1 -1
  8. package/dist/managers/aiManager.js +20 -13
  9. package/dist/managers/backgroundTaskManager.d.ts +1 -1
  10. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundTaskManager.js +1 -1
  12. package/dist/managers/{bashManager.d.ts → bangManager.d.ts} +4 -4
  13. package/dist/managers/{bashManager.d.ts.map → bangManager.d.ts.map} +1 -1
  14. package/dist/managers/{bashManager.js → bangManager.js} +5 -6
  15. package/dist/managers/hookManager.d.ts.map +1 -1
  16. package/dist/managers/hookManager.js +12 -3
  17. package/dist/managers/messageManager.d.ts +18 -6
  18. package/dist/managers/messageManager.d.ts.map +1 -1
  19. package/dist/managers/messageManager.js +42 -20
  20. package/dist/managers/permissionManager.d.ts +22 -1
  21. package/dist/managers/permissionManager.d.ts.map +1 -1
  22. package/dist/managers/permissionManager.js +106 -85
  23. package/dist/managers/planManager.d.ts +6 -0
  24. package/dist/managers/planManager.d.ts.map +1 -1
  25. package/dist/managers/planManager.js +21 -0
  26. package/dist/managers/skillManager.d.ts +7 -2
  27. package/dist/managers/skillManager.d.ts.map +1 -1
  28. package/dist/managers/skillManager.js +30 -10
  29. package/dist/managers/slashCommandManager.d.ts +7 -0
  30. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  31. package/dist/managers/slashCommandManager.js +59 -59
  32. package/dist/managers/subagentManager.d.ts +4 -0
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +47 -13
  35. package/dist/managers/toolManager.d.ts +7 -1
  36. package/dist/managers/toolManager.d.ts.map +1 -1
  37. package/dist/managers/toolManager.js +15 -2
  38. package/dist/prompts/index.d.ts +0 -4
  39. package/dist/prompts/index.d.ts.map +1 -1
  40. package/dist/prompts/index.js +0 -9
  41. package/dist/services/aiService.d.ts.map +1 -1
  42. package/dist/services/aiService.js +9 -9
  43. package/dist/services/configurationService.d.ts +2 -2
  44. package/dist/services/configurationService.d.ts.map +1 -1
  45. package/dist/services/configurationService.js +4 -4
  46. package/dist/services/hook.d.ts.map +1 -1
  47. package/dist/services/hook.js +6 -0
  48. package/dist/services/initializationService.d.ts +44 -0
  49. package/dist/services/initializationService.d.ts.map +1 -0
  50. package/dist/services/initializationService.js +170 -0
  51. package/dist/services/interactionService.d.ts +29 -0
  52. package/dist/services/interactionService.d.ts.map +1 -0
  53. package/dist/services/interactionService.js +97 -0
  54. package/dist/services/session.js +1 -1
  55. package/dist/services/taskManager.d.ts +5 -0
  56. package/dist/services/taskManager.d.ts.map +1 -1
  57. package/dist/services/taskManager.js +16 -2
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +7 -18
  60. package/dist/tools/editTool.js +1 -1
  61. package/dist/tools/exitPlanMode.js +1 -1
  62. package/dist/tools/globTool.d.ts.map +1 -1
  63. package/dist/tools/globTool.js +12 -2
  64. package/dist/tools/lspTool.d.ts +2 -0
  65. package/dist/tools/lspTool.d.ts.map +1 -1
  66. package/dist/tools/lspTool.js +144 -52
  67. package/dist/tools/skillTool.d.ts.map +1 -1
  68. package/dist/tools/skillTool.js +97 -2
  69. package/dist/tools/taskManagementTools.d.ts.map +1 -1
  70. package/dist/tools/taskManagementTools.js +23 -2
  71. package/dist/tools/taskTool.d.ts.map +1 -1
  72. package/dist/tools/taskTool.js +9 -15
  73. package/dist/tools/types.d.ts +1 -2
  74. package/dist/tools/types.d.ts.map +1 -1
  75. package/dist/tools/writeTool.js +1 -1
  76. package/dist/types/agent.d.ts +64 -0
  77. package/dist/types/agent.d.ts.map +1 -0
  78. package/dist/types/agent.js +1 -0
  79. package/dist/types/commands.d.ts +0 -4
  80. package/dist/types/commands.d.ts.map +1 -1
  81. package/dist/types/config.d.ts +1 -1
  82. package/dist/types/config.d.ts.map +1 -1
  83. package/dist/types/hooks.d.ts +3 -1
  84. package/dist/types/hooks.d.ts.map +1 -1
  85. package/dist/types/hooks.js +1 -0
  86. package/dist/types/index.d.ts +1 -0
  87. package/dist/types/index.d.ts.map +1 -1
  88. package/dist/types/index.js +1 -0
  89. package/dist/types/messaging.d.ts +3 -3
  90. package/dist/types/messaging.d.ts.map +1 -1
  91. package/dist/types/skills.d.ts +13 -0
  92. package/dist/types/skills.d.ts.map +1 -1
  93. package/dist/utils/commandArgumentParser.d.ts.map +1 -1
  94. package/dist/utils/commandArgumentParser.js +7 -0
  95. package/dist/utils/commandPathResolver.d.ts +3 -36
  96. package/dist/utils/commandPathResolver.d.ts.map +1 -1
  97. package/dist/utils/commandPathResolver.js +16 -93
  98. package/dist/utils/configValidator.d.ts +2 -2
  99. package/dist/utils/configValidator.d.ts.map +1 -1
  100. package/dist/utils/configValidator.js +4 -6
  101. package/dist/utils/containerSetup.d.ts +3 -4
  102. package/dist/utils/containerSetup.d.ts.map +1 -1
  103. package/dist/utils/containerSetup.js +14 -9
  104. package/dist/utils/customCommands.d.ts +2 -3
  105. package/dist/utils/customCommands.d.ts.map +1 -1
  106. package/dist/utils/customCommands.js +20 -60
  107. package/dist/utils/gitUtils.d.ts +25 -0
  108. package/dist/utils/gitUtils.d.ts.map +1 -1
  109. package/dist/utils/gitUtils.js +75 -0
  110. package/dist/utils/markdownParser.d.ts +4 -0
  111. package/dist/utils/markdownParser.d.ts.map +1 -1
  112. package/dist/utils/markdownParser.js +33 -0
  113. package/dist/utils/messageOperations.d.ts +16 -7
  114. package/dist/utils/messageOperations.d.ts.map +1 -1
  115. package/dist/utils/messageOperations.js +45 -20
  116. package/dist/utils/nameGenerator.d.ts +1 -1
  117. package/dist/utils/nameGenerator.d.ts.map +1 -1
  118. package/dist/utils/nameGenerator.js +10 -6
  119. package/dist/utils/skillParser.d.ts.map +1 -1
  120. package/dist/utils/skillParser.js +48 -0
  121. package/package.json +1 -1
  122. package/src/agent.ts +103 -458
  123. package/src/index.ts +2 -2
  124. package/src/managers/aiManager.ts +23 -17
  125. package/src/managers/backgroundTaskManager.ts +2 -2
  126. package/src/managers/{bashManager.ts → bangManager.ts} +11 -8
  127. package/src/managers/hookManager.ts +13 -3
  128. package/src/managers/messageManager.ts +55 -26
  129. package/src/managers/permissionManager.ts +121 -98
  130. package/src/managers/planManager.ts +26 -0
  131. package/src/managers/skillManager.ts +51 -14
  132. package/src/managers/slashCommandManager.ts +83 -73
  133. package/src/managers/subagentManager.ts +57 -13
  134. package/src/managers/toolManager.ts +22 -2
  135. package/src/prompts/index.ts +0 -15
  136. package/src/services/aiService.ts +12 -15
  137. package/src/services/configurationService.ts +4 -4
  138. package/src/services/hook.ts +7 -0
  139. package/src/services/initializationService.ts +291 -0
  140. package/src/services/interactionService.ts +171 -0
  141. package/src/services/session.ts +1 -1
  142. package/src/services/taskManager.ts +18 -2
  143. package/src/tools/bashTool.ts +8 -18
  144. package/src/tools/editTool.ts +1 -1
  145. package/src/tools/exitPlanMode.ts +1 -1
  146. package/src/tools/globTool.ts +15 -2
  147. package/src/tools/lsTool.ts +1 -1
  148. package/src/tools/lspTool.ts +184 -52
  149. package/src/tools/skillTool.ts +127 -2
  150. package/src/tools/taskManagementTools.ts +32 -2
  151. package/src/tools/taskTool.ts +13 -15
  152. package/src/tools/types.ts +1 -2
  153. package/src/tools/writeTool.ts +1 -1
  154. package/src/types/agent.ts +83 -0
  155. package/src/types/commands.ts +0 -6
  156. package/src/types/config.ts +1 -1
  157. package/src/types/hooks.ts +5 -1
  158. package/src/types/index.ts +1 -0
  159. package/src/types/messaging.ts +3 -3
  160. package/src/types/skills.ts +13 -0
  161. package/src/utils/commandArgumentParser.ts +8 -0
  162. package/src/utils/commandPathResolver.ts +14 -117
  163. package/src/utils/configValidator.ts +5 -9
  164. package/src/utils/containerSetup.ts +17 -14
  165. package/src/utils/customCommands.ts +20 -83
  166. package/src/utils/gitUtils.ts +75 -0
  167. package/src/utils/markdownParser.ts +47 -0
  168. package/src/utils/messageOperations.ts +58 -28
  169. package/src/utils/nameGenerator.ts +10 -6
  170. package/src/utils/skillParser.ts +52 -0
  171. package/dist/managers/backgroundBashManager.d.ts +0 -27
  172. package/dist/managers/backgroundBashManager.d.ts.map +0 -1
  173. package/dist/managers/backgroundBashManager.js +0 -169
  174. package/src/managers/backgroundBashManager.ts +0 -206
package/src/agent.ts CHANGED
@@ -1,32 +1,23 @@
1
1
  import { ForegroundTaskManager } from "./managers/foregroundTaskManager.js";
2
- import {
3
- MessageManager,
4
- type MessageManagerCallbacks,
5
- } from "./managers/messageManager.js";
2
+ import { MessageManager } from "./managers/messageManager.js";
6
3
  import { AIManager } from "./managers/aiManager.js";
7
4
  import { ToolManager } from "./managers/toolManager.js";
8
- import {
9
- SubagentManager,
10
- type SubagentManagerCallbacks,
11
- } from "./managers/subagentManager.js";
12
- import { McpManager, type McpManagerCallbacks } from "./managers/mcpManager.js";
5
+ import { SubagentManager } from "./managers/subagentManager.js";
6
+ import { McpManager } from "./managers/mcpManager.js";
13
7
  import { LspManager } from "./managers/lspManager.js";
14
- import { BashManager } from "./managers/bashManager.js";
15
- import {
16
- BackgroundTaskManager,
17
- type BackgroundTaskManagerCallbacks,
18
- } from "./managers/backgroundTaskManager.js";
8
+ import { BangManager } from "./managers/bangManager.js";
9
+ import { BackgroundTaskManager } from "./managers/backgroundTaskManager.js";
19
10
  import { SlashCommandManager } from "./managers/slashCommandManager.js";
20
11
  import { PluginManager } from "./managers/pluginManager.js";
21
12
  import { HookManager } from "./managers/hookManager.js";
22
13
  import { ReversionManager } from "./managers/reversionManager.js";
23
14
  import { PermissionManager } from "./managers/permissionManager.js";
24
15
  import { PlanManager } from "./managers/planManager.js";
25
- import type {
16
+ import {
26
17
  SlashCommand,
27
18
  CustomSlashCommand,
28
19
  ILspManager,
29
- PluginConfig,
20
+ AgentOptions,
30
21
  } from "./types/index.js";
31
22
  import type {
32
23
  Message,
@@ -36,8 +27,6 @@ import type {
36
27
  ModelConfig,
37
28
  Usage,
38
29
  PermissionMode,
39
- PermissionCallback,
40
- BackgroundTask,
41
30
  ForegroundTask,
42
31
  } from "./types/index.js";
43
32
  import { MemoryRuleManager } from "./managers/MemoryRuleManager.js";
@@ -45,90 +34,17 @@ import { LiveConfigManager } from "./managers/liveConfigManager.js";
45
34
  import { configValidator } from "./utils/configValidator.js";
46
35
  import { SkillManager } from "./managers/skillManager.js";
47
36
  import { TaskManager } from "./services/taskManager.js";
48
- import {
49
- loadSessionFromJsonl,
50
- handleSessionRestoration,
51
- } from "./services/session.js";
52
- import { setGlobalLogger } from "./utils/globalLogger.js";
37
+ import { InitializationService } from "./services/initializationService.js";
38
+ import { InteractionService } from "./services/interactionService.js";
53
39
  import { ConfigurationService } from "./services/configurationService.js";
54
- import * as fs from "fs/promises";
55
- import path from "path";
56
- import os from "os";
57
- import { ClientOptions } from "openai";
58
-
59
40
  import { Container } from "./utils/container.js";
60
41
  import { setupAgentContainer } from "./utils/containerSetup.js";
61
42
 
62
- /**
63
- * Configuration options for Agent instances
64
- *
65
- * IMPORTANT: This interface is used by both Agent constructor and Agent.create()
66
- * Any changes to this interface must be compatible with both methods.
67
- */
68
- export interface AgentOptions {
69
- // Optional configuration with environment fallbacks
70
- apiKey?: string;
71
- baseURL?: string;
72
- defaultHeaders?: Record<string, string>;
73
- fetchOptions?: ClientOptions["fetchOptions"];
74
- fetch?: ClientOptions["fetch"];
75
- agentModel?: string;
76
- fastModel?: string;
77
- maxInputTokens?: number;
78
- maxTokens?: number;
79
- /** Preferred language for agent communication */
80
- language?: string;
81
-
82
- // Existing options (preserved)
83
- callbacks?: AgentCallbacks;
84
- restoreSessionId?: string;
85
- continueLastSession?: boolean;
86
- logger?: Logger;
87
- /**Add optional initial messages parameter for testing convenience */
88
- messages?: Message[];
89
- /**Working directory - if not specified, use process.cwd() */
90
- workdir?: string;
91
- /**Optional custom system prompt - if provided, replaces default system prompt */
92
- systemPrompt?: string;
93
- /**Permission mode - defaults to "default" */
94
- permissionMode?: PermissionMode;
95
- /**Custom permission callback */
96
- canUseTool?: PermissionCallback;
97
- /**Whether to use streaming mode for AI responses - defaults to true */
98
- stream?: boolean;
99
- /**Optional custom LSP manager - if not provided, a standalone one will be created */
100
- lspManager?: ILspManager;
101
- /**Optional local plugins to load */
102
- plugins?: PluginConfig[];
103
- /**
104
- * Optional list of tool names to enable.
105
- * - undefined: Enable all built-in tools and plugins (default).
106
- * - []: Disable all tools.
107
- * - string[]: Enable only the tools with the specified names.
108
- */
109
- tools?: string[];
110
- }
111
-
112
- export interface AgentCallbacks
113
- extends MessageManagerCallbacks,
114
- BackgroundTaskManagerCallbacks,
115
- McpManagerCallbacks,
116
- SubagentManagerCallbacks {
117
- onTasksChange?: (tasks: BackgroundTask[]) => void;
118
- onSessionTasksChange?: (tasks: import("./types/tasks.js").Task[]) => void;
119
- onPermissionModeChange?: (mode: PermissionMode) => void;
120
- onSubagentLatestTotalTokensChange?: (
121
- subagentId: string,
122
- tokens: number,
123
- ) => void;
124
- onBackgroundCurrentTask?: () => void;
125
- }
126
-
127
43
  export class Agent {
128
44
  private messageManager: MessageManager;
129
45
  private aiManager: AIManager;
130
46
 
131
- private bashManager: BashManager | null = null;
47
+ private bangManager: BangManager | null = null;
132
48
  private backgroundTaskManager: BackgroundTaskManager;
133
49
  private logger?: Logger; // Add optional logger property
134
50
  private toolManager: ToolManager; // Add tool registry instance
@@ -150,7 +66,6 @@ export class Agent {
150
66
  private configurationService: ConfigurationService; // Add configuration service
151
67
  private workdir: string; // Working directory
152
68
  private systemPrompt?: string; // Custom system prompt
153
- private _usages: Usage[] = []; // Usage tracking array
154
69
  private stream: boolean; // Streaming mode flag
155
70
 
156
71
  // Configuration options storage for dynamic resolution
@@ -173,7 +88,7 @@ export class Agent {
173
88
 
174
89
  public getModelConfig(): ModelConfig {
175
90
  return this.configurationService.resolveModelConfig(
176
- this.options.agentModel,
91
+ this.options.model,
177
92
  this.options.fastModel,
178
93
  this.options.maxTokens,
179
94
  this.getPermissionMode(),
@@ -221,26 +136,23 @@ export class Agent {
221
136
  configurationService: this.configurationService,
222
137
  systemPrompt: this.systemPrompt,
223
138
  stream: this.stream,
224
- onSessionIdChange: () => {
225
- this.taskManager.setTaskListId(this.messageManager.getRootSessionId());
226
- },
227
- onSessionTasksChange: (tasks) => {
228
- this.options.callbacks?.onSessionTasksChange?.(tasks);
229
- },
230
139
  onTasksChange: (tasks) => {
231
140
  this.options.callbacks?.onTasksChange?.(tasks);
232
141
  },
142
+ onBackgroundTasksChange: (tasks) => {
143
+ this.options.callbacks?.onBackgroundTasksChange?.(tasks);
144
+ },
233
145
  onPermissionModeChange: (mode) => {
234
146
  this.options.callbacks?.onPermissionModeChange?.(mode);
235
147
  },
236
148
  handlePlanModeTransition: (mode) => {
237
- this.handlePlanModeTransition(mode);
149
+ this.planManager.handlePlanModeTransition(mode);
238
150
  },
239
151
  setPermissionMode: (mode) => {
240
152
  this.setPermissionMode(mode);
241
153
  },
242
154
  addPermissionRule: (rule) => this.addPermissionRule(rule),
243
- addUsage: (usage) => this.addUsage(usage),
155
+ addUsage: (usage) => this.messageManager.addUsage(usage),
244
156
  getGatewayConfig: () => this.getGatewayConfig(),
245
157
  getModelConfig: () => this.getModelConfig(),
246
158
  getMaxInputTokens: () => this.getMaxInputTokens(),
@@ -266,7 +178,7 @@ export class Agent {
266
178
  this.aiManager = this.container.get("AIManager")!;
267
179
  this.slashCommandManager = this.container.get("SlashCommandManager")!;
268
180
  this.pluginManager = this.container.get("PluginManager")!;
269
- this.bashManager = this.container.get("BashManager")!;
181
+ this.bangManager = this.container.get("BangManager")!;
270
182
 
271
183
  // Set initial permission mode if provided
272
184
  if (options.permissionMode) {
@@ -284,37 +196,13 @@ export class Agent {
284
196
  }
285
197
 
286
198
  public get usages(): Usage[] {
287
- return [...this._usages]; // Return copy to prevent external modification
199
+ return this.messageManager.getUsages();
288
200
  }
289
201
 
290
202
  public get sessionFilePath(): string {
291
203
  return this.messageManager.getTranscriptPath();
292
204
  }
293
205
 
294
- /**
295
- * Rebuild usage array from messages containing usage metadata
296
- * Called during session restoration to reconstruct usage tracking
297
- */
298
- private rebuildUsageFromMessages(messages: Message[]): void {
299
- this._usages = [];
300
- messages.forEach((message) => {
301
- if (message.role === "assistant" && message.usage) {
302
- this._usages.push(message.usage);
303
- }
304
- });
305
- // Trigger callback after rebuilding usage array
306
- this.messageManager.triggerUsageChange();
307
- }
308
-
309
- /**
310
- * Add usage data to the tracking array and trigger callbacks
311
- * @param usage Usage data from AI operations
312
- */
313
- private addUsage(usage: Usage): void {
314
- this._usages.push(usage);
315
- this.messageManager.triggerUsageChange();
316
- }
317
-
318
206
  public get latestTotalTokens(): number {
319
207
  return this.messageManager.getlatestTotalTokens();
320
208
  }
@@ -351,7 +239,7 @@ export class Agent {
351
239
 
352
240
  /** Get bash command execution status */
353
241
  public get isCommandRunning(): boolean {
354
- return this.bashManager?.isCommandRunning ?? false;
242
+ return this.bangManager?.isCommandRunning ?? false;
355
243
  }
356
244
 
357
245
  /** Get background bash shell output */
@@ -446,7 +334,7 @@ export class Agent {
446
334
  configValidator.validateGatewayConfig(gatewayConfig);
447
335
  configValidator.validateMaxInputTokens(maxInputTokens);
448
336
  configValidator.validateModelConfig(
449
- modelConfig.agentModel,
337
+ modelConfig.model,
450
338
  modelConfig.fastModel,
451
339
  );
452
340
  }
@@ -457,160 +345,35 @@ export class Agent {
457
345
  continueLastSession?: boolean;
458
346
  messages?: Message[];
459
347
  }): Promise<void> {
460
- // Initialize managers first
461
- try {
462
- // Initialize SkillManager
463
- await this.skillManager.initialize();
464
-
465
- // Initialize SubagentManager (load and cache configurations)
466
- await this.subagentManager.initialize();
467
-
468
- // Register managers in container for tool access
469
- this.container.register("SubagentManager", this.subagentManager);
470
- this.container.register("SkillManager", this.skillManager);
471
-
472
- // Initialize built-in tools
473
- this.toolManager.initializeBuiltInTools();
474
-
475
- // Initialize plugins
476
- await this.pluginManager.loadPlugins(this.options.plugins || []);
477
- } catch (error) {
478
- this.logger?.error("Failed to initialize managers and tools:", error);
479
- // Don't throw error to prevent app startup failure
480
- }
481
-
482
- // Initialize MCP servers with auto-connect
483
- try {
484
- await this.mcpManager.initialize(this.workdir, true);
485
- if (this.lspManager instanceof LspManager) {
486
- await this.lspManager.initialize(this.workdir);
487
- }
488
- } catch (error) {
489
- this.logger?.error("Failed to initialize MCP servers:", error);
490
- // Don't throw error to prevent app startup failure
491
- }
492
-
493
- // Initialize hooks configuration
494
- try {
495
- // Load hooks configuration using ConfigurationService
496
- this.logger?.debug("Loading hooks configuration...");
497
- const configResult =
498
- await this.configurationService.loadMergedConfiguration(this.workdir);
499
-
500
- this.hookManager.loadConfigurationFromWaveConfig(
501
- configResult.configuration,
502
- );
503
-
504
- // Update plugin manager with enabled plugins configuration
505
- if (configResult.configuration?.enabledPlugins) {
506
- this.pluginManager.updateEnabledPlugins(
507
- configResult.configuration.enabledPlugins,
508
- );
509
- }
510
-
511
- this.logger?.debug("Hooks system initialized successfully");
512
- } catch (error) {
513
- this.logger?.error("Failed to initialize hooks system:", error);
514
- // Don't throw error to prevent app startup failure
515
- }
516
-
517
- // Resolve and validate configuration after loading settings.json
518
- this.resolveAndValidateConfig();
519
-
520
- // Set global logger for SDK-wide access before discovering rules
521
- setGlobalLogger(this.logger || null);
522
-
523
- // Discover modular memory rules
524
- try {
525
- await this.memoryRuleManager.discoverRules();
526
- } catch (error) {
527
- this.logger?.error("Failed to discover memory rules:", error);
528
- }
529
-
530
- // Initialize live configuration reload
531
- try {
532
- this.logger?.debug("Initializing live configuration reload...");
533
- await this.liveConfigManager.initialize();
534
- this.logger?.debug("Live configuration reload initialized successfully");
535
- } catch (error) {
536
- this.logger?.error(
537
- "Failed to initialize live configuration reload:",
538
- error,
539
- );
540
- // Don't throw error to prevent app startup failure - continue without live reload
541
- }
542
-
543
- // Load memory files during initialization
544
- try {
545
- this.logger?.debug("Loading memory files...");
546
-
547
- // Load project memory from AGENTS.md (bypass memory store for direct file access)
548
- try {
549
- const projectMemoryPath = path.join(this.workdir, "AGENTS.md");
550
- this._projectMemoryContent = await fs.readFile(
551
- projectMemoryPath,
552
- "utf-8",
553
- );
554
- this.logger?.debug("Project memory loaded successfully");
555
- } catch (error) {
556
- this._projectMemoryContent = "";
557
- this.logger?.debug(
558
- "Project memory file not found or unreadable, using empty content:",
559
- error instanceof Error ? error.message : String(error),
560
- );
561
- }
562
-
563
- // Load user memory (bypass memory store for direct file access)
564
- try {
565
- const userMemoryPath = path.join(os.homedir(), ".wave", "AGENTS.md");
566
- this._userMemoryContent = await fs.readFile(userMemoryPath, "utf-8");
567
- this.logger?.debug("User memory loaded successfully");
568
- } catch (error) {
569
- this._userMemoryContent = "";
570
- this.logger?.debug(
571
- "User memory file not found or unreadable, using empty content:",
572
- error instanceof Error ? error.message : String(error),
573
- );
574
- }
575
-
576
- this.logger?.debug("Memory initialization completed");
577
- } catch (error) {
578
- // Ensure memory is always initialized even if loading fails
579
- this._projectMemoryContent = "";
580
- this._userMemoryContent = "";
581
- this.logger?.error("Failed to load memory files:", error);
582
- // Don't throw error to prevent app startup failure
583
- }
584
-
585
- // Handle session restoration or set provided messages
586
- if (options?.messages) {
587
- // If messages are provided, use them directly (useful for testing)
588
- this.messageManager.setMessages(options.messages);
589
- // Rebuild usage array from restored messages
590
- this.rebuildUsageFromMessages(options.messages);
591
- } else {
592
- // Otherwise, handle session restoration
593
- const sessionToRestore = await handleSessionRestoration(
594
- options?.restoreSessionId,
595
- options?.continueLastSession,
596
- this.messageManager.getWorkdir(),
597
- );
598
- // Rebuild usage array from restored messages
599
- this.rebuildUsageFromMessages(sessionToRestore?.messages || []);
600
-
601
- if (sessionToRestore) {
602
- this.messageManager.initializeFromSession(sessionToRestore);
603
-
604
- // Update task manager with the root session ID to ensure continuity across compressions
605
- this.taskManager.setTaskListId(
606
- sessionToRestore.rootSessionId || sessionToRestore.id,
607
- );
608
-
609
- // After session is initialized, load tasks for the session
610
- const tasks = await this.taskManager.listTasks();
611
- this.options.callbacks?.onSessionTasksChange?.(tasks);
612
- }
613
- }
348
+ await InitializationService.initialize(
349
+ {
350
+ skillManager: this.skillManager,
351
+ subagentManager: this.subagentManager,
352
+ container: this.container,
353
+ toolManager: this.toolManager,
354
+ pluginManager: this.pluginManager,
355
+ options: this.options,
356
+ slashCommandManager: this.slashCommandManager,
357
+ logger: this.logger,
358
+ mcpManager: this.mcpManager,
359
+ workdir: this.workdir,
360
+ lspManager: this.lspManager,
361
+ configurationService: this.configurationService,
362
+ hookManager: this.hookManager,
363
+ messageManager: this.messageManager,
364
+ memoryRuleManager: this.memoryRuleManager,
365
+ liveConfigManager: this.liveConfigManager,
366
+ taskManager: this.taskManager,
367
+ setProjectMemory: (content) => {
368
+ this._projectMemoryContent = content;
369
+ },
370
+ setUserMemory: (content) => {
371
+ this._userMemoryContent = content;
372
+ },
373
+ resolveAndValidateConfig: () => this.resolveAndValidateConfig(),
374
+ },
375
+ options,
376
+ );
614
377
  }
615
378
 
616
379
  /**
@@ -618,47 +381,22 @@ export class Agent {
618
381
  * @param sessionId - The ID of the session to restore
619
382
  */
620
383
  public async restoreSession(sessionId: string): Promise<void> {
621
- // 1. Validation
622
- if (!sessionId || sessionId === this.sessionId) {
623
- return; // No-op if session ID is invalid or already current
624
- }
625
-
626
- // 2. Auto-save current session
627
- try {
628
- await this.messageManager.saveSession();
629
- } catch (error) {
630
- this.logger?.warn(
631
- "Failed to save current session before restore:",
632
- error,
633
- );
634
- // Continue with restoration even if save fails
635
- }
636
-
637
- // 3. Load target session
638
- const sessionData = await loadSessionFromJsonl(
384
+ await InteractionService.restoreSession(
385
+ {
386
+ messageManager: this.messageManager,
387
+ slashCommandManager: this.slashCommandManager,
388
+ hookManager: this.hookManager,
389
+ workdir: this.workdir,
390
+ configurationService: this.configurationService,
391
+ logger: this.logger,
392
+ aiManager: this.aiManager,
393
+ subagentManager: this.subagentManager,
394
+ taskManager: this.taskManager,
395
+ options: this.options,
396
+ abortMessage: () => this.abortMessage(),
397
+ },
639
398
  sessionId,
640
- this.messageManager.getWorkdir(),
641
399
  );
642
- if (!sessionData) {
643
- throw new Error(`Session not found: ${sessionId}`);
644
- }
645
-
646
- // 4. Clean current state
647
- this.abortMessage(); // Abort any running operations
648
- this.subagentManager.cleanup(); // Clean up active subagents
649
-
650
- // 5. Rebuild usage (in correct order)
651
- this.rebuildUsageFromMessages(sessionData.messages);
652
-
653
- // 6. Initialize session state last
654
- this.messageManager.initializeFromSession(sessionData);
655
-
656
- // Update task manager with the root session ID to ensure continuity across compressions
657
- this.taskManager.setTaskListId(sessionData.rootSessionId || sessionData.id);
658
-
659
- // 7. Load tasks for the restored session
660
- const tasks = await this.taskManager.listTasks();
661
- this.options.callbacks?.onSessionTasksChange?.(tasks);
662
400
  }
663
401
 
664
402
  public abortAIMessage(): void {
@@ -667,7 +405,7 @@ export class Agent {
667
405
 
668
406
  /** Execute bash command */
669
407
  public async executeBashCommand(command: string): Promise<void> {
670
- await this.bashManager?.executeCommand(command);
408
+ await this.bangManager?.executeCommand(command);
671
409
  }
672
410
 
673
411
  public clearMessages(): void {
@@ -683,7 +421,7 @@ export class Agent {
683
421
 
684
422
  /** Interrupt bash command execution */
685
423
  public abortBashCommand(): void {
686
- this.bashManager?.abortCommand();
424
+ this.bangManager?.abortCommand();
687
425
  }
688
426
 
689
427
  /** Interrupt slash command execution */
@@ -788,82 +526,23 @@ export class Agent {
788
526
  content: string,
789
527
  images?: Array<{ path: string; mimeType: string }>,
790
528
  ): Promise<void> {
791
- try {
792
- // Handle slash command - check if it's a slash command (starts with /)
793
- if (content.startsWith("/")) {
794
- const command = content.trim();
795
- if (!command || command === "/") return;
796
-
797
- // Parse and validate slash command
798
- const { isValid, commandId, args } =
799
- this.slashCommandManager.parseAndValidateSlashCommand(command);
800
-
801
- if (isValid && commandId !== undefined) {
802
- // Execute valid slash command
803
- await this.slashCommandManager.executeCommand(commandId, args);
804
-
805
- return;
806
- }
807
-
808
- // If command doesn't exist, continue as normal message processing
809
- // Don't add to history, let normal message processing logic below handle it
810
- }
811
-
812
- // Handle normal AI message
813
- // Add user message first, will automatically sync to UI
814
- this.messageManager.addUserMessage({
815
- content,
816
- images: images?.map((img) => ({
817
- path: img.path,
818
- mimeType: img.mimeType,
819
- })),
820
- });
821
-
822
- // Execute UserPromptSubmit hooks after adding the user message
823
- if (this.hookManager) {
824
- try {
825
- const hookResults = await this.hookManager.executeHooks(
826
- "UserPromptSubmit",
827
- {
828
- event: "UserPromptSubmit",
829
- projectDir: this.workdir,
830
- timestamp: new Date(),
831
- // UserPromptSubmit doesn't need toolName
832
- sessionId: this.sessionId,
833
- transcriptPath: this.messageManager.getTranscriptPath(),
834
- cwd: this.workdir,
835
- userPrompt: content,
836
- env: this.configurationService.getEnvironmentVars(), // Include configuration environment variables
837
- },
838
- );
839
-
840
- // Process hook results and determine if we should continue
841
- const processResult = this.hookManager.processHookResults(
842
- "UserPromptSubmit",
843
- hookResults,
844
- this.messageManager,
845
- );
846
-
847
- // If hook processing indicates we should block (exit code 2), stop here
848
- if (processResult.shouldBlock) {
849
- this.logger?.info(
850
- "UserPromptSubmit hook blocked prompt processing with error:",
851
- processResult.errorMessage,
852
- );
853
- return; // Don't send to AI
854
- }
855
- } catch (error) {
856
- this.logger?.warn("UserPromptSubmit hooks execution failed:", error);
857
- // Continue processing even if hooks fail
858
- }
859
- }
860
-
861
- // Send AI message
862
- await this.aiManager.sendAIMessage();
863
- } catch (error) {
864
- console.error("Failed to add user message:", error);
865
- // Loading state will be automatically updated by the useEffect that watches messages
866
- }
529
+ await InteractionService.sendMessage(
530
+ {
531
+ messageManager: this.messageManager,
532
+ slashCommandManager: this.slashCommandManager,
533
+ hookManager: this.hookManager,
534
+ workdir: this.workdir,
535
+ configurationService: this.configurationService,
536
+ logger: this.logger,
537
+ aiManager: this.aiManager,
538
+ subagentManager: this.subagentManager,
539
+ taskManager: this.taskManager,
540
+ options: this.options,
541
+ abortMessage: () => this.abortMessage(),
542
+ },
543
+ content,
544
+ images,
545
+ );
867
546
  }
868
547
 
869
548
  // ========== MCP Management Methods ==========
@@ -896,8 +575,12 @@ export class Agent {
896
575
  }
897
576
 
898
577
  /** Reload custom commands */
899
- public reloadCustomCommands(): void {
578
+ public async reloadCustomCommands(): Promise<void> {
579
+ await this.skillManager.initialize();
900
580
  this.slashCommandManager.reloadCustomCommands();
581
+ this.slashCommandManager.registerSkillCommands(
582
+ this.skillManager.getAvailableSkills(),
583
+ );
901
584
  }
902
585
 
903
586
  /** Get custom command details */
@@ -932,7 +615,7 @@ export class Agent {
932
615
  this.logger?.debug("Setting permission mode", { mode });
933
616
  this.toolManager.setPermissionMode(mode);
934
617
 
935
- this.handlePlanModeTransition(mode);
618
+ this.planManager.handlePlanModeTransition(mode);
936
619
 
937
620
  this.options.callbacks?.onPermissionModeChange?.(mode);
938
621
  }
@@ -944,7 +627,9 @@ export class Agent {
944
627
  public async truncateHistory(index: number): Promise<void> {
945
628
  await this.messageManager.truncateHistory(index, this.reversionManager);
946
629
  // After truncating history, the task list might have changed, so refresh it.
947
- await this.taskManager.refreshTasks();
630
+ // We explicitly load tasks and trigger the callback to ensure UI updates immediately and in order.
631
+ const tasks = await this.taskManager.listTasks();
632
+ this.options.callbacks?.onTasksChange?.(tasks);
948
633
  }
949
634
 
950
635
  /**
@@ -965,9 +650,19 @@ export class Agent {
965
650
  }
966
651
 
967
652
  /**
968
- * Get all currently allowed rules (for testing and UI)
653
+ * Get all currently allowed rules (user-defined and default)
969
654
  */
970
655
  public getAllowedRules(): string[] {
656
+ return [
657
+ ...this.permissionManager.getAllowedRules(),
658
+ ...this.permissionManager.getDefaultAllowedRules(),
659
+ ];
660
+ }
661
+
662
+ /**
663
+ * Get only user-defined allowed rules
664
+ */
665
+ public getUserAllowedRules(): string[] {
971
666
  return this.permissionManager.getAllowedRules();
972
667
  }
973
668
 
@@ -985,57 +680,7 @@ export class Agent {
985
680
  * @param rule - The rule to add (e.g., "Bash(ls)")
986
681
  */
987
682
  public async addPermissionRule(rule: string): Promise<void> {
988
- // 1. Expand rule if it's a Bash command
989
- let rulesToAdd = [rule];
990
- const bashMatch = rule.match(/^Bash\((.*)\)$/);
991
- if (bashMatch) {
992
- const command = bashMatch[1];
993
- rulesToAdd = this.permissionManager.expandBashRule(command, this.workdir);
994
- }
995
-
996
- for (const ruleToAdd of rulesToAdd) {
997
- // 2. Update PermissionManager state
998
- const currentRules = this.permissionManager.getAllowedRules();
999
- if (!currentRules.includes(ruleToAdd)) {
1000
- this.permissionManager.updateAllowedRules([...currentRules, ruleToAdd]);
1001
-
1002
- // 3. Persist to settings.local.json
1003
- try {
1004
- await this.configurationService.addAllowedRule(
1005
- this.workdir,
1006
- ruleToAdd,
1007
- );
1008
- this.logger?.debug("Persistent permission rule added", {
1009
- rule: ruleToAdd,
1010
- });
1011
- } catch (error) {
1012
- this.logger?.error("Failed to persist permission rule", {
1013
- rule: ruleToAdd,
1014
- error: error instanceof Error ? error.message : String(error),
1015
- });
1016
- }
1017
- }
1018
- }
1019
- }
1020
-
1021
- /**
1022
- * Handle plan mode transition, generating or clearing plan file path
1023
- * @param mode - The current effective permission mode
1024
- */
1025
- private handlePlanModeTransition(mode: PermissionMode): void {
1026
- if (mode === "plan") {
1027
- this.planManager
1028
- .getOrGeneratePlanFilePath(this.messageManager.getRootSessionId())
1029
- .then(({ path }) => {
1030
- this.logger?.debug("Plan file path generated", { path });
1031
- this.permissionManager.setPlanFilePath(path);
1032
- })
1033
- .catch((error) => {
1034
- this.logger?.error("Failed to generate plan file path", error);
1035
- });
1036
- } else {
1037
- this.permissionManager.setPlanFilePath(undefined);
1038
- }
683
+ await this.permissionManager.addPermissionRule(rule);
1039
684
  }
1040
685
 
1041
686
  /**