wave-agent-sdk 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) 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 +57 -45
  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 +6 -6
  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/lspTool.d.ts +2 -0
  63. package/dist/tools/lspTool.d.ts.map +1 -1
  64. package/dist/tools/lspTool.js +144 -52
  65. package/dist/tools/skillTool.d.ts.map +1 -1
  66. package/dist/tools/skillTool.js +97 -2
  67. package/dist/tools/taskManagementTools.d.ts.map +1 -1
  68. package/dist/tools/taskManagementTools.js +23 -2
  69. package/dist/tools/taskTool.d.ts.map +1 -1
  70. package/dist/tools/taskTool.js +9 -15
  71. package/dist/tools/types.d.ts +1 -2
  72. package/dist/tools/types.d.ts.map +1 -1
  73. package/dist/tools/writeTool.js +1 -1
  74. package/dist/types/agent.d.ts +64 -0
  75. package/dist/types/agent.d.ts.map +1 -0
  76. package/dist/types/agent.js +1 -0
  77. package/dist/types/commands.d.ts +0 -4
  78. package/dist/types/commands.d.ts.map +1 -1
  79. package/dist/types/config.d.ts +1 -1
  80. package/dist/types/config.d.ts.map +1 -1
  81. package/dist/types/hooks.d.ts +3 -1
  82. package/dist/types/hooks.d.ts.map +1 -1
  83. package/dist/types/hooks.js +1 -0
  84. package/dist/types/index.d.ts +1 -0
  85. package/dist/types/index.d.ts.map +1 -1
  86. package/dist/types/index.js +1 -0
  87. package/dist/types/messaging.d.ts +3 -3
  88. package/dist/types/messaging.d.ts.map +1 -1
  89. package/dist/types/skills.d.ts +13 -0
  90. package/dist/types/skills.d.ts.map +1 -1
  91. package/dist/utils/commandPathResolver.d.ts +3 -36
  92. package/dist/utils/commandPathResolver.d.ts.map +1 -1
  93. package/dist/utils/commandPathResolver.js +16 -93
  94. package/dist/utils/configValidator.d.ts +2 -2
  95. package/dist/utils/configValidator.d.ts.map +1 -1
  96. package/dist/utils/configValidator.js +4 -6
  97. package/dist/utils/containerSetup.d.ts +3 -4
  98. package/dist/utils/containerSetup.d.ts.map +1 -1
  99. package/dist/utils/containerSetup.js +14 -9
  100. package/dist/utils/customCommands.d.ts +2 -3
  101. package/dist/utils/customCommands.d.ts.map +1 -1
  102. package/dist/utils/customCommands.js +20 -60
  103. package/dist/utils/gitUtils.d.ts +25 -0
  104. package/dist/utils/gitUtils.d.ts.map +1 -1
  105. package/dist/utils/gitUtils.js +75 -0
  106. package/dist/utils/markdownParser.d.ts +4 -0
  107. package/dist/utils/markdownParser.d.ts.map +1 -1
  108. package/dist/utils/markdownParser.js +33 -0
  109. package/dist/utils/messageOperations.d.ts +16 -7
  110. package/dist/utils/messageOperations.d.ts.map +1 -1
  111. package/dist/utils/messageOperations.js +45 -20
  112. package/dist/utils/nameGenerator.d.ts +1 -1
  113. package/dist/utils/nameGenerator.d.ts.map +1 -1
  114. package/dist/utils/nameGenerator.js +10 -6
  115. package/dist/utils/skillParser.d.ts.map +1 -1
  116. package/dist/utils/skillParser.js +48 -0
  117. package/package.json +1 -1
  118. package/src/agent.ts +103 -458
  119. package/src/index.ts +2 -2
  120. package/src/managers/aiManager.ts +23 -17
  121. package/src/managers/backgroundTaskManager.ts +2 -2
  122. package/src/managers/{bashManager.ts → bangManager.ts} +11 -8
  123. package/src/managers/hookManager.ts +13 -3
  124. package/src/managers/messageManager.ts +55 -26
  125. package/src/managers/permissionManager.ts +121 -98
  126. package/src/managers/planManager.ts +26 -0
  127. package/src/managers/skillManager.ts +51 -14
  128. package/src/managers/slashCommandManager.ts +75 -55
  129. package/src/managers/subagentManager.ts +57 -13
  130. package/src/managers/toolManager.ts +22 -2
  131. package/src/prompts/index.ts +0 -15
  132. package/src/services/aiService.ts +9 -12
  133. package/src/services/configurationService.ts +4 -4
  134. package/src/services/hook.ts +7 -0
  135. package/src/services/initializationService.ts +291 -0
  136. package/src/services/interactionService.ts +171 -0
  137. package/src/services/session.ts +1 -1
  138. package/src/services/taskManager.ts +18 -2
  139. package/src/tools/bashTool.ts +8 -18
  140. package/src/tools/editTool.ts +1 -1
  141. package/src/tools/exitPlanMode.ts +1 -1
  142. package/src/tools/lsTool.ts +1 -1
  143. package/src/tools/lspTool.ts +184 -52
  144. package/src/tools/skillTool.ts +127 -2
  145. package/src/tools/taskManagementTools.ts +32 -2
  146. package/src/tools/taskTool.ts +13 -15
  147. package/src/tools/types.ts +1 -2
  148. package/src/tools/writeTool.ts +1 -1
  149. package/src/types/agent.ts +83 -0
  150. package/src/types/commands.ts +0 -6
  151. package/src/types/config.ts +1 -1
  152. package/src/types/hooks.ts +5 -1
  153. package/src/types/index.ts +1 -0
  154. package/src/types/messaging.ts +3 -3
  155. package/src/types/skills.ts +13 -0
  156. package/src/utils/commandPathResolver.ts +14 -117
  157. package/src/utils/configValidator.ts +5 -9
  158. package/src/utils/containerSetup.ts +17 -14
  159. package/src/utils/customCommands.ts +20 -83
  160. package/src/utils/gitUtils.ts +75 -0
  161. package/src/utils/markdownParser.ts +47 -0
  162. package/src/utils/messageOperations.ts +58 -28
  163. package/src/utils/nameGenerator.ts +10 -6
  164. package/src/utils/skillParser.ts +52 -0
  165. package/dist/managers/backgroundBashManager.d.ts +0 -27
  166. package/dist/managers/backgroundBashManager.d.ts.map +0 -1
  167. package/dist/managers/backgroundBashManager.js +0 -169
  168. package/src/managers/backgroundBashManager.ts +0 -206
@@ -0,0 +1,291 @@
1
+ import path from "path";
2
+ import * as fs from "fs/promises";
3
+ import os from "os";
4
+ import { handleSessionRestoration } from "./session.js";
5
+ import { setGlobalLogger } from "../utils/globalLogger.js";
6
+ import { LspManager } from "../managers/lspManager.js";
7
+ import type {
8
+ Message,
9
+ Logger,
10
+ AgentOptions,
11
+ ILspManager,
12
+ } from "../types/index.js";
13
+ import type { SkillManager } from "../managers/skillManager.js";
14
+ import type { SubagentManager } from "../managers/subagentManager.js";
15
+ import type { Container } from "../utils/container.js";
16
+ import type { ToolManager } from "../managers/toolManager.js";
17
+ import type { PluginManager } from "../managers/pluginManager.js";
18
+ import type { SlashCommandManager } from "../managers/slashCommandManager.js";
19
+ import type { McpManager } from "../managers/mcpManager.js";
20
+ import type { ConfigurationService } from "./configurationService.js";
21
+ import type { HookManager } from "../managers/hookManager.js";
22
+ import type { MessageManager } from "../managers/messageManager.js";
23
+ import type { MemoryRuleManager } from "../managers/MemoryRuleManager.js";
24
+ import type { LiveConfigManager } from "../managers/liveConfigManager.js";
25
+ import type { TaskManager } from "./taskManager.js";
26
+ import type { PermissionManager } from "../managers/permissionManager.js";
27
+
28
+ export interface InitializationContext {
29
+ skillManager: SkillManager;
30
+ subagentManager: SubagentManager;
31
+ container: Container;
32
+ toolManager: ToolManager;
33
+ pluginManager: PluginManager;
34
+ options: AgentOptions;
35
+ slashCommandManager: SlashCommandManager;
36
+ logger?: Logger;
37
+ mcpManager: McpManager;
38
+ workdir: string;
39
+ lspManager: ILspManager;
40
+ configurationService: ConfigurationService;
41
+ hookManager: HookManager;
42
+ messageManager: MessageManager;
43
+ memoryRuleManager: MemoryRuleManager;
44
+ liveConfigManager: LiveConfigManager;
45
+ taskManager: TaskManager;
46
+ setProjectMemory: (content: string) => void;
47
+ setUserMemory: (content: string) => void;
48
+ resolveAndValidateConfig: () => void;
49
+ }
50
+
51
+ export class InitializationService {
52
+ public static async initialize(
53
+ context: InitializationContext,
54
+ options?: {
55
+ restoreSessionId?: string;
56
+ continueLastSession?: boolean;
57
+ messages?: Message[];
58
+ },
59
+ ): Promise<void> {
60
+ const {
61
+ skillManager,
62
+ subagentManager,
63
+ container,
64
+ toolManager,
65
+ pluginManager,
66
+ options: agentOptions,
67
+ slashCommandManager,
68
+ logger,
69
+ mcpManager,
70
+ workdir,
71
+ lspManager,
72
+ configurationService,
73
+ hookManager,
74
+ messageManager,
75
+ memoryRuleManager,
76
+ liveConfigManager,
77
+ taskManager,
78
+ setProjectMemory,
79
+ setUserMemory,
80
+ resolveAndValidateConfig,
81
+ } = context;
82
+
83
+ // Initialize managers first
84
+ try {
85
+ // Initialize SkillManager
86
+ await skillManager.initialize();
87
+
88
+ // Initialize SubagentManager (load and cache configurations)
89
+ await subagentManager.initialize();
90
+
91
+ // Register managers in container for tool access
92
+ container.register("SubagentManager", subagentManager);
93
+ container.register("SkillManager", skillManager);
94
+
95
+ // Initialize built-in tools
96
+ toolManager.initializeBuiltInTools();
97
+
98
+ // Initialize plugins
99
+ await pluginManager.loadPlugins(agentOptions.plugins || []);
100
+
101
+ // Register skill commands
102
+ slashCommandManager.registerSkillCommands(
103
+ skillManager.getAvailableSkills(),
104
+ );
105
+ } catch (error) {
106
+ logger?.error("Failed to initialize managers and tools:", error);
107
+ // Don't throw error to prevent app startup failure
108
+ }
109
+
110
+ // Initialize MCP servers with auto-connect
111
+ try {
112
+ await mcpManager.initialize(workdir, true);
113
+ if (lspManager instanceof LspManager) {
114
+ await lspManager.initialize(workdir);
115
+ }
116
+ } catch (error) {
117
+ logger?.error("Failed to initialize MCP servers:", error);
118
+ // Don't throw error to prevent app startup failure
119
+ }
120
+
121
+ // Initialize hooks configuration
122
+ try {
123
+ // Load hooks configuration using ConfigurationService
124
+ logger?.debug("Loading hooks configuration...");
125
+ const configResult =
126
+ await configurationService.loadMergedConfiguration(workdir);
127
+
128
+ hookManager.loadConfigurationFromWaveConfig(configResult.configuration);
129
+
130
+ // Update plugin manager with enabled plugins configuration
131
+ if (configResult.configuration?.enabledPlugins) {
132
+ pluginManager.updateEnabledPlugins(
133
+ configResult.configuration.enabledPlugins,
134
+ );
135
+ }
136
+
137
+ // Initialize permission manager with loaded rules
138
+ if (configResult.configuration?.permissions) {
139
+ const permissionManager =
140
+ context.container.get<PermissionManager>("PermissionManager");
141
+ if (permissionManager) {
142
+ if (configResult.configuration.permissions.allow) {
143
+ permissionManager.updateAllowedRules(
144
+ configResult.configuration.permissions.allow,
145
+ );
146
+ }
147
+ if (configResult.configuration.permissions.deny) {
148
+ permissionManager.updateDeniedRules(
149
+ configResult.configuration.permissions.deny,
150
+ );
151
+ }
152
+ if (configResult.configuration.permissions.defaultMode) {
153
+ permissionManager.updateConfiguredDefaultMode(
154
+ configResult.configuration.permissions.defaultMode,
155
+ );
156
+ }
157
+ }
158
+ }
159
+
160
+ logger?.debug("Hooks system initialized successfully");
161
+ } catch (error) {
162
+ logger?.error("Failed to initialize hooks system:", error);
163
+ // Don't throw error to prevent app startup failure
164
+ }
165
+
166
+ // Trigger WorktreeCreate hook if this is a new worktree
167
+ if (agentOptions.isNewWorktree && hookManager) {
168
+ try {
169
+ logger?.info(
170
+ `Triggering WorktreeCreate hook for ${agentOptions.worktreeName}...`,
171
+ );
172
+ const hookResults = await hookManager.executeHooks("WorktreeCreate", {
173
+ event: "WorktreeCreate",
174
+ projectDir: workdir,
175
+ timestamp: new Date(),
176
+ sessionId: messageManager.getSessionId(),
177
+ transcriptPath: messageManager.getTranscriptPath(),
178
+ cwd: workdir,
179
+ worktreeName: agentOptions.worktreeName,
180
+ env: configurationService.getEnvironmentVars(),
181
+ });
182
+
183
+ // Process hook results
184
+ hookManager.processHookResults(
185
+ "WorktreeCreate",
186
+ hookResults,
187
+ messageManager,
188
+ );
189
+ } catch (error) {
190
+ logger?.warn("WorktreeCreate hooks execution failed:", error);
191
+ }
192
+ }
193
+
194
+ // Resolve and validate configuration after loading settings.json
195
+ resolveAndValidateConfig();
196
+
197
+ // Set global logger for SDK-wide access before discovering rules
198
+ setGlobalLogger(logger || null);
199
+
200
+ // Discover modular memory rules
201
+ try {
202
+ await memoryRuleManager.discoverRules();
203
+ } catch (error) {
204
+ logger?.error("Failed to discover memory rules:", error);
205
+ }
206
+
207
+ // Initialize live configuration reload
208
+ try {
209
+ logger?.debug("Initializing live configuration reload...");
210
+ await liveConfigManager.initialize();
211
+ logger?.debug("Live configuration reload initialized successfully");
212
+ } catch (error) {
213
+ logger?.error("Failed to initialize live configuration reload:", error);
214
+ // Don't throw error to prevent app startup failure - continue without live reload
215
+ }
216
+
217
+ // Load memory files during initialization
218
+ try {
219
+ logger?.debug("Loading memory files...");
220
+
221
+ // Load project memory from AGENTS.md (bypass memory store for direct file access)
222
+ try {
223
+ const projectMemoryPath = path.join(workdir, "AGENTS.md");
224
+ const projectMemoryContent = await fs.readFile(
225
+ projectMemoryPath,
226
+ "utf-8",
227
+ );
228
+ setProjectMemory(projectMemoryContent);
229
+ logger?.debug("Project memory loaded successfully");
230
+ } catch (error) {
231
+ setProjectMemory("");
232
+ logger?.debug(
233
+ "Project memory file not found or unreadable, using empty content:",
234
+ error instanceof Error ? error.message : String(error),
235
+ );
236
+ }
237
+
238
+ // Load user memory (bypass memory store for direct file access)
239
+ try {
240
+ const userMemoryPath = path.join(os.homedir(), ".wave", "AGENTS.md");
241
+ const userMemoryContent = await fs.readFile(userMemoryPath, "utf-8");
242
+ setUserMemory(userMemoryContent);
243
+ logger?.debug("User memory loaded successfully");
244
+ } catch (error) {
245
+ setUserMemory("");
246
+ logger?.debug(
247
+ "User memory file not found or unreadable, using empty content:",
248
+ error instanceof Error ? error.message : String(error),
249
+ );
250
+ }
251
+
252
+ logger?.debug("Memory initialization completed");
253
+ } catch (error) {
254
+ // Ensure memory is always initialized even if loading fails
255
+ setProjectMemory("");
256
+ setUserMemory("");
257
+ logger?.error("Failed to load memory files:", error);
258
+ // Don't throw error to prevent app startup failure
259
+ }
260
+
261
+ // Handle session restoration or set provided messages
262
+ if (options?.messages) {
263
+ // If messages are provided, use them directly (useful for testing)
264
+ messageManager.setMessages(options.messages);
265
+ // Rebuild usage array from restored messages
266
+ messageManager.rebuildUsageFromMessages(options.messages);
267
+ } else {
268
+ // Otherwise, handle session restoration
269
+ const sessionToRestore = await handleSessionRestoration(
270
+ options?.restoreSessionId,
271
+ options?.continueLastSession,
272
+ messageManager.getWorkdir(),
273
+ );
274
+ // Rebuild usage array from restored messages
275
+ messageManager.rebuildUsageFromMessages(sessionToRestore?.messages || []);
276
+
277
+ if (sessionToRestore) {
278
+ messageManager.initializeFromSession(sessionToRestore);
279
+
280
+ // Update task manager with the root session ID to ensure continuity across compressions
281
+ taskManager.setTaskListId(
282
+ sessionToRestore.rootSessionId || sessionToRestore.id,
283
+ );
284
+
285
+ // After session is initialized, load tasks for the session
286
+ const tasks = await taskManager.listTasks();
287
+ agentOptions.callbacks?.onTasksChange?.(tasks);
288
+ }
289
+ }
290
+ }
291
+ }
@@ -0,0 +1,171 @@
1
+ import { loadSessionFromJsonl } from "./session.js";
2
+ import type { Logger, AgentOptions } from "../types/index.js";
3
+ import type { MessageManager } from "../managers/messageManager.js";
4
+ import type { SlashCommandManager } from "../managers/slashCommandManager.js";
5
+ import type { HookManager } from "../managers/hookManager.js";
6
+ import type { ConfigurationService } from "./configurationService.js";
7
+ import type { AIManager } from "../managers/aiManager.js";
8
+ import type { SubagentManager } from "../managers/subagentManager.js";
9
+ import type { TaskManager } from "./taskManager.js";
10
+
11
+ export interface InteractionContext {
12
+ messageManager: MessageManager;
13
+ slashCommandManager: SlashCommandManager;
14
+ hookManager: HookManager;
15
+ workdir: string;
16
+ configurationService: ConfigurationService;
17
+ logger?: Logger;
18
+ aiManager: AIManager;
19
+ subagentManager: SubagentManager;
20
+ taskManager: TaskManager;
21
+ options: AgentOptions;
22
+ abortMessage: () => void;
23
+ }
24
+
25
+ export class InteractionService {
26
+ public static async sendMessage(
27
+ context: InteractionContext,
28
+ content: string,
29
+ images?: Array<{ path: string; mimeType: string }>,
30
+ ): Promise<void> {
31
+ const {
32
+ messageManager,
33
+ slashCommandManager,
34
+ hookManager,
35
+ workdir,
36
+ configurationService,
37
+ logger,
38
+ aiManager,
39
+ } = context;
40
+
41
+ try {
42
+ // Handle slash command - check if it's a slash command (starts with /)
43
+ if (content.startsWith("/")) {
44
+ const command = content.trim();
45
+ if (!command || command === "/") return;
46
+
47
+ // Parse and validate slash command
48
+ const { isValid, commandId, args } =
49
+ slashCommandManager.parseAndValidateSlashCommand(command);
50
+
51
+ if (isValid && commandId !== undefined) {
52
+ // Execute valid slash command
53
+ await slashCommandManager.executeCommand(commandId, args);
54
+
55
+ return;
56
+ }
57
+
58
+ // If command doesn't exist, continue as normal message processing
59
+ // Don't add to history, let normal message processing logic below handle it
60
+ }
61
+
62
+ // Handle normal AI message
63
+ // Add user message first, will automatically sync to UI
64
+ messageManager.addUserMessage({
65
+ content,
66
+ images: images?.map((img) => ({
67
+ path: img.path,
68
+ mimeType: img.mimeType,
69
+ })),
70
+ });
71
+
72
+ // Execute UserPromptSubmit hooks after adding the user message
73
+ if (hookManager) {
74
+ try {
75
+ const hookResults = await hookManager.executeHooks(
76
+ "UserPromptSubmit",
77
+ {
78
+ event: "UserPromptSubmit",
79
+ projectDir: workdir,
80
+ timestamp: new Date(),
81
+ // UserPromptSubmit doesn't need toolName
82
+ sessionId: messageManager.getSessionId(),
83
+ transcriptPath: messageManager.getTranscriptPath(),
84
+ cwd: workdir,
85
+ userPrompt: content,
86
+ env: configurationService.getEnvironmentVars(), // Include configuration environment variables
87
+ },
88
+ );
89
+
90
+ // Process hook results and determine if we should continue
91
+ const processResult = hookManager.processHookResults(
92
+ "UserPromptSubmit",
93
+ hookResults,
94
+ messageManager,
95
+ );
96
+
97
+ // If hook processing indicates we should block (exit code 2), stop here
98
+ if (processResult.shouldBlock) {
99
+ logger?.info(
100
+ "UserPromptSubmit hook blocked prompt processing with error:",
101
+ processResult.errorMessage,
102
+ );
103
+ return; // Don't send to AI
104
+ }
105
+ } catch (error) {
106
+ logger?.warn("UserPromptSubmit hooks execution failed:", error);
107
+ // Continue processing even if hooks fail
108
+ }
109
+ }
110
+
111
+ // Send AI message
112
+ await aiManager.sendAIMessage();
113
+ } catch (error) {
114
+ console.error("Failed to add user message:", error);
115
+ // Loading state will be automatically updated by the useEffect that watches messages
116
+ }
117
+ }
118
+
119
+ public static async restoreSession(
120
+ context: InteractionContext,
121
+ sessionId: string,
122
+ ): Promise<void> {
123
+ const {
124
+ messageManager,
125
+ logger,
126
+ subagentManager,
127
+ taskManager,
128
+ options,
129
+ abortMessage,
130
+ } = context;
131
+
132
+ // 1. Validation
133
+ if (!sessionId || sessionId === messageManager.getSessionId()) {
134
+ return; // No-op if session ID is invalid or already current
135
+ }
136
+
137
+ // 2. Auto-save current session
138
+ try {
139
+ await messageManager.saveSession();
140
+ } catch (error) {
141
+ logger?.warn("Failed to save current session before restore:", error);
142
+ // Continue with restoration even if save fails
143
+ }
144
+
145
+ // 3. Load target session
146
+ const sessionData = await loadSessionFromJsonl(
147
+ sessionId,
148
+ messageManager.getWorkdir(),
149
+ );
150
+ if (!sessionData) {
151
+ throw new Error(`Session not found: ${sessionId}`);
152
+ }
153
+
154
+ // 4. Clean current state
155
+ abortMessage(); // Abort any running operations
156
+ subagentManager.cleanup(); // Clean up active subagents
157
+
158
+ // 5. Rebuild usage (in correct order)
159
+ messageManager.rebuildUsageFromMessages(sessionData.messages);
160
+
161
+ // 6. Initialize session state last
162
+ messageManager.initializeFromSession(sessionData);
163
+
164
+ // Update task manager with the root session ID to ensure continuity across compressions
165
+ taskManager.setTaskListId(sessionData.rootSessionId || sessionData.id);
166
+
167
+ // 7. Load tasks for the restored session
168
+ const tasks = await taskManager.listTasks();
169
+ options.callbacks?.onTasksChange?.(tasks);
170
+ }
171
+ }
@@ -768,7 +768,7 @@ export async function getFirstMessageContent(
768
768
  }
769
769
 
770
770
  const commandBlock = message.blocks.find(
771
- (block) => block.type === "command_output",
771
+ (block) => block.type === "bang",
772
772
  );
773
773
  if (commandBlock && "command" in commandBlock) {
774
774
  return commandBlock.command;
@@ -5,6 +5,7 @@ import { EventEmitter } from "events";
5
5
  import { Task } from "../types/tasks.js";
6
6
  import { logger } from "../utils/globalLogger.js";
7
7
  import { Container } from "../utils/container.js";
8
+ import type { MessageManager } from "../managers/messageManager.js";
8
9
 
9
10
  export class TaskManager extends EventEmitter {
10
11
  private readonly baseDir: string;
@@ -27,6 +28,21 @@ export class TaskManager extends EventEmitter {
27
28
  this.taskListId = taskListId;
28
29
  }
29
30
 
31
+ /**
32
+ * Syncs the task list ID with the current session's root session ID.
33
+ * This is typically called when the session is cleared or compressed.
34
+ */
35
+ public async syncWithSession(): Promise<void> {
36
+ const messageManager = this.container.get<MessageManager>("MessageManager");
37
+ if (!messageManager) return;
38
+
39
+ const rootSessionId = messageManager.getRootSessionId();
40
+ if (this.taskListId !== rootSessionId && !process.env.WAVE_TASK_LIST_ID) {
41
+ this.setTaskListId(rootSessionId);
42
+ await this.refreshTasks();
43
+ }
44
+ }
45
+
30
46
  private getSessionDir(): string {
31
47
  return join(this.baseDir, this.taskListId);
32
48
  }
@@ -110,7 +126,7 @@ export class TaskManager extends EventEmitter {
110
126
  const content = JSON.stringify(fullTask, null, 2);
111
127
  await fs.writeFile(taskPath, content, "utf8");
112
128
  this.emit("tasksChange", this.taskListId);
113
- logger.info(`Task ${taskId} created in task list ${this.taskListId}`);
129
+ logger.debug(`Task ${taskId} created in task list ${this.taskListId}`);
114
130
  return taskId;
115
131
  });
116
132
  }
@@ -141,7 +157,7 @@ export class TaskManager extends EventEmitter {
141
157
  const content = JSON.stringify(task, null, 2);
142
158
  await fs.writeFile(taskPath, content, "utf8");
143
159
  this.emit("tasksChange", this.taskListId);
144
- logger.info(`Task ${task.id} updated in task list ${this.taskListId}`);
160
+ logger.debug(`Task ${task.id} updated in task list ${this.taskListId}`);
145
161
  });
146
162
  }
147
163
 
@@ -153,7 +153,7 @@ Usage notes:
153
153
  return {
154
154
  success: false,
155
155
  content: "",
156
- error: `${BASH_TOOL_NAME} operation denied, reason: ${permissionResult.message || "No reason provided"}`,
156
+ error: `${BASH_TOOL_NAME} operation denied by user, reason: ${permissionResult.message || "No reason provided"}`,
157
157
  };
158
158
  }
159
159
  } catch {
@@ -197,24 +197,9 @@ Usage notes:
197
197
 
198
198
  let outputBuffer = "";
199
199
  let errorBuffer = "";
200
- let shortResultBuffer = "";
201
200
  let isAborted = false;
202
201
  let isBackgrounded = false;
203
202
 
204
- const updateShortResult = (chunk: string) => {
205
- if (!chunk) return;
206
- shortResultBuffer += chunk;
207
- if (shortResultBuffer.length > MAX_OUTPUT_LENGTH) {
208
- shortResultBuffer = shortResultBuffer.slice(-MAX_OUTPUT_LENGTH);
209
- }
210
- const lastLines = shortResultBuffer
211
- .trim()
212
- .split("\n")
213
- .slice(-3)
214
- .join("\n");
215
- context.onShortResultUpdate?.(lastLines || "");
216
- };
217
-
218
203
  const foregroundTaskId = `bash_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
219
204
 
220
205
  // Register as foreground task
@@ -324,7 +309,6 @@ Usage notes:
324
309
  if (!isAborted && !isBackgrounded && !runInBackground) {
325
310
  const chunk = stripAnsiColors(data.toString());
326
311
  outputBuffer += chunk;
327
- updateShortResult(chunk);
328
312
  }
329
313
  });
330
314
 
@@ -332,7 +316,6 @@ Usage notes:
332
316
  if (!isAborted && !isBackgrounded && !runInBackground) {
333
317
  const chunk = stripAnsiColors(data.toString());
334
318
  errorBuffer += chunk;
335
- updateShortResult(chunk);
336
319
  }
337
320
  });
338
321
 
@@ -361,9 +344,16 @@ Usage notes:
361
344
  "\n\n... (output truncated)"
362
345
  : finalOutput;
363
346
 
347
+ const shortResult = combinedOutput
348
+ .trim()
349
+ .split("\n")
350
+ .slice(-3)
351
+ .join("\n");
352
+
364
353
  resolve({
365
354
  success: exitCode === 0,
366
355
  content,
356
+ shortResult: shortResult || undefined,
367
357
  error:
368
358
  exitCode !== 0
369
359
  ? `Command failed with exit code: ${exitCode}`
@@ -182,7 +182,7 @@ Usage:
182
182
  return {
183
183
  success: false,
184
184
  content: "",
185
- error: `${EDIT_TOOL_NAME} operation denied, reason: ${permissionResult.message || "No reason provided"}`,
185
+ error: `${EDIT_TOOL_NAME} operation denied by user, reason: ${permissionResult.message || "No reason provided"}`,
186
186
  };
187
187
  }
188
188
  } catch {
@@ -93,7 +93,7 @@ Ensure your plan is complete and unambiguous:
93
93
  if (permissionResult.behavior === "deny") {
94
94
  return {
95
95
  success: false,
96
- content: `User feedback: ${permissionResult.message || "Plan rejected by user"}. Please update your proposal accordingly.`,
96
+ content: `Please update your proposal based on the following user feedback: ${permissionResult.message || "Plan rejected by user"}`,
97
97
  error: permissionResult.message ? undefined : "Plan rejected by user",
98
98
  };
99
99
  }
@@ -2,7 +2,7 @@ import * as fs from "fs";
2
2
  import * as path from "path";
3
3
  import { minimatch } from "minimatch";
4
4
  import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
5
- import { isBinary, getDisplayPath } from "@/utils/path.js";
5
+ import { isBinary, getDisplayPath } from "../utils/path.js";
6
6
  import {
7
7
  LS_TOOL_NAME,
8
8
  GLOB_TOOL_NAME,