wave-agent-sdk 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/dist/agent.d.ts +23 -1
  2. package/dist/agent.js +34 -4
  3. package/dist/managers/aiManager.d.ts +36 -0
  4. package/dist/managers/aiManager.js +240 -8
  5. package/dist/managers/messageManager.d.ts +1 -3
  6. package/dist/managers/messageManager.js +13 -6
  7. package/dist/managers/slashCommandManager.js +28 -0
  8. package/dist/managers/subagentManager.d.ts +0 -2
  9. package/dist/telemetry/instrumentation.d.ts +1 -1
  10. package/dist/telemetry/instrumentation.js +57 -28
  11. package/dist/tools/bashTool.js +16 -6
  12. package/dist/tools/grepTool.js +11 -3
  13. package/dist/types/index.d.ts +3 -0
  14. package/dist/types/messaging.d.ts +2 -0
  15. package/dist/utils/containerSetup.js +0 -3
  16. package/dist/utils/messageOperations.d.ts +2 -1
  17. package/dist/utils/messageOperations.js +2 -1
  18. package/dist/utils/notificationXml.js +5 -0
  19. package/dist/utils/ripgrep.d.ts +4 -4
  20. package/dist/utils/ripgrep.js +4 -27
  21. package/package.json +20 -8
  22. package/bin/rg +0 -79
  23. package/dist/managers/forkedAgentManager.d.ts +0 -50
  24. package/dist/managers/forkedAgentManager.js +0 -130
  25. package/scripts/install_ripgrep.js +0 -111
  26. package/scripts/postinstall.js +0 -38
  27. package/src/agent.ts +0 -1271
  28. package/src/constants/subagents.ts +0 -4
  29. package/src/constants/toolLimits.ts +0 -15
  30. package/src/constants/tools.ts +0 -24
  31. package/src/core/plugin.ts +0 -237
  32. package/src/core/session.ts +0 -9
  33. package/src/index.ts +0 -38
  34. package/src/managers/MemoryRuleManager.ts +0 -198
  35. package/src/managers/aiManager.ts +0 -2429
  36. package/src/managers/backgroundTaskManager.ts +0 -480
  37. package/src/managers/bangManager.ts +0 -119
  38. package/src/managers/cronManager.ts +0 -401
  39. package/src/managers/foregroundTaskManager.ts +0 -30
  40. package/src/managers/forkedAgentManager.ts +0 -216
  41. package/src/managers/hookManager.ts +0 -1089
  42. package/src/managers/liveConfigManager.ts +0 -445
  43. package/src/managers/lspManager.ts +0 -470
  44. package/src/managers/mcpManager.ts +0 -1010
  45. package/src/managers/messageManager.ts +0 -1184
  46. package/src/managers/messageQueue.ts +0 -157
  47. package/src/managers/permissionManager.ts +0 -1140
  48. package/src/managers/planManager.ts +0 -112
  49. package/src/managers/pluginManager.ts +0 -330
  50. package/src/managers/pluginScopeManager.ts +0 -124
  51. package/src/managers/reversionManager.ts +0 -178
  52. package/src/managers/skillManager.ts +0 -578
  53. package/src/managers/slashCommandManager.ts +0 -564
  54. package/src/managers/subagentManager.ts +0 -915
  55. package/src/managers/toolManager.ts +0 -489
  56. package/src/managers/workflowManager.ts +0 -493
  57. package/src/prompts/autoMemory.ts +0 -33
  58. package/src/prompts/autoMemoryExtraction.ts +0 -146
  59. package/src/prompts/index.ts +0 -506
  60. package/src/prompts/planModeReminders.ts +0 -126
  61. package/src/services/GitService.ts +0 -131
  62. package/src/services/MarketplaceService.ts +0 -1052
  63. package/src/services/MemoryRuleService.ts +0 -71
  64. package/src/services/aiService.ts +0 -919
  65. package/src/services/authService.ts +0 -565
  66. package/src/services/autoMemoryService.ts +0 -280
  67. package/src/services/configurationService.ts +0 -1520
  68. package/src/services/fileWatcher.ts +0 -319
  69. package/src/services/hook.ts +0 -348
  70. package/src/services/initializationService.ts +0 -357
  71. package/src/services/interactionService.ts +0 -229
  72. package/src/services/jsonlHandler.ts +0 -295
  73. package/src/services/memory.ts +0 -234
  74. package/src/services/pluginLoader.ts +0 -252
  75. package/src/services/remoteSettingsService.ts +0 -366
  76. package/src/services/reversionService.ts +0 -122
  77. package/src/services/session.ts +0 -917
  78. package/src/services/taskManager.ts +0 -321
  79. package/src/telemetry/events.ts +0 -65
  80. package/src/telemetry/instrumentation.ts +0 -499
  81. package/src/telemetry/sessionTracing.ts +0 -348
  82. package/src/tools/agentTool.ts +0 -322
  83. package/src/tools/askUserQuestion.ts +0 -160
  84. package/src/tools/bashTool.ts +0 -621
  85. package/src/tools/buildTool.ts +0 -61
  86. package/src/tools/cronCreateTool.ts +0 -161
  87. package/src/tools/cronDeleteTool.ts +0 -51
  88. package/src/tools/cronListTool.ts +0 -47
  89. package/src/tools/editTool.ts +0 -313
  90. package/src/tools/enterPlanMode.ts +0 -124
  91. package/src/tools/enterWorktreeTool.ts +0 -190
  92. package/src/tools/exitPlanMode.ts +0 -139
  93. package/src/tools/exitWorktreeTool.ts +0 -236
  94. package/src/tools/globTool.ts +0 -167
  95. package/src/tools/grepTool.ts +0 -399
  96. package/src/tools/lspTool.ts +0 -883
  97. package/src/tools/readTool.ts +0 -426
  98. package/src/tools/skillTool.ts +0 -248
  99. package/src/tools/taskManagementTools.ts +0 -574
  100. package/src/tools/taskStopTool.ts +0 -78
  101. package/src/tools/types.ts +0 -137
  102. package/src/tools/webFetchTool.ts +0 -373
  103. package/src/tools/workflowTool.ts +0 -205
  104. package/src/tools/writeTool.ts +0 -267
  105. package/src/types/agent.ts +0 -128
  106. package/src/types/auth.ts +0 -19
  107. package/src/types/commands.ts +0 -30
  108. package/src/types/config.ts +0 -43
  109. package/src/types/configuration.ts +0 -168
  110. package/src/types/core.ts +0 -105
  111. package/src/types/cron.ts +0 -13
  112. package/src/types/environment.ts +0 -106
  113. package/src/types/fileSearch.ts +0 -4
  114. package/src/types/history.ts +0 -7
  115. package/src/types/hooks.ts +0 -256
  116. package/src/types/index.ts +0 -41
  117. package/src/types/lsp.ts +0 -98
  118. package/src/types/marketplace.ts +0 -71
  119. package/src/types/mcp.ts +0 -43
  120. package/src/types/memoryRule.ts +0 -31
  121. package/src/types/messaging.ts +0 -114
  122. package/src/types/permissions.ts +0 -80
  123. package/src/types/plugins.ts +0 -39
  124. package/src/types/processes.ts +0 -99
  125. package/src/types/reversion.ts +0 -29
  126. package/src/types/session.ts +0 -12
  127. package/src/types/skills.ts +0 -108
  128. package/src/types/tasks.ts +0 -13
  129. package/src/types/telemetry.ts +0 -98
  130. package/src/types/tools.ts +0 -44
  131. package/src/types/workflow.ts +0 -6
  132. package/src/utils/abortUtils.ts +0 -118
  133. package/src/utils/atomicWrite.ts +0 -61
  134. package/src/utils/bashParser.ts +0 -899
  135. package/src/utils/cacheControlUtils.ts +0 -426
  136. package/src/utils/commandArgumentParser.ts +0 -161
  137. package/src/utils/commandPathResolver.ts +0 -88
  138. package/src/utils/configPaths.ts +0 -220
  139. package/src/utils/configValidator.ts +0 -100
  140. package/src/utils/constants.ts +0 -39
  141. package/src/utils/container.ts +0 -92
  142. package/src/utils/containerSetup.ts +0 -371
  143. package/src/utils/convertMessagesForAPI.ts +0 -326
  144. package/src/utils/cronTasks.ts +0 -128
  145. package/src/utils/cronTasksLock.ts +0 -182
  146. package/src/utils/cronToHuman.ts +0 -99
  147. package/src/utils/customCommands.ts +0 -95
  148. package/src/utils/editUtils.ts +0 -20
  149. package/src/utils/fileFormat.ts +0 -40
  150. package/src/utils/fileSearch.ts +0 -151
  151. package/src/utils/fileUtils.ts +0 -223
  152. package/src/utils/gitUtils.ts +0 -315
  153. package/src/utils/globalLogger.ts +0 -128
  154. package/src/utils/groupMessagesByApiRound.ts +0 -121
  155. package/src/utils/hookMatcher.ts +0 -176
  156. package/src/utils/markdownParser.ts +0 -317
  157. package/src/utils/mcpUtils.ts +0 -138
  158. package/src/utils/messageOperations.ts +0 -659
  159. package/src/utils/modelCapabilities.ts +0 -30
  160. package/src/utils/nameGenerator.ts +0 -99
  161. package/src/utils/notificationXml.ts +0 -57
  162. package/src/utils/openaiClient.ts +0 -251
  163. package/src/utils/parseCronExpression.ts +0 -78
  164. package/src/utils/path.ts +0 -72
  165. package/src/utils/pathEncoder.ts +0 -400
  166. package/src/utils/pathSafety.ts +0 -40
  167. package/src/utils/promptHistory.ts +0 -168
  168. package/src/utils/ripgrep.ts +0 -35
  169. package/src/utils/shellResolver.ts +0 -190
  170. package/src/utils/skillParser.ts +0 -246
  171. package/src/utils/stringUtils.ts +0 -156
  172. package/src/utils/subagentParser.ts +0 -279
  173. package/src/utils/taskReminder.ts +0 -96
  174. package/src/utils/tokenCalculation.ts +0 -43
  175. package/src/utils/tokenEstimate.ts +0 -34
  176. package/src/utils/toolResultStorage.ts +0 -117
  177. package/src/utils/worktreeSession.ts +0 -26
  178. package/src/utils/worktreeUtils.ts +0 -786
  179. package/src/workflow/budgetTracker.ts +0 -34
  180. package/src/workflow/concurrencyLimiter.ts +0 -47
  181. package/src/workflow/journal.ts +0 -95
  182. package/src/workflow/progressReporter.ts +0 -141
  183. package/src/workflow/runState.ts +0 -65
  184. package/src/workflow/scriptRuntime.ts +0 -274
  185. package/src/workflow/structuredOutput.ts +0 -123
  186. package/src/workflow/types.ts +0 -101
  187. package/src/workflow/workflowApis.ts +0 -410
  188. package/vendor/ripgrep/linux-aarch64/rg +0 -0
  189. package/vendor/ripgrep/linux-x86_64/rg +0 -0
  190. package/vendor/ripgrep/macos-aarch64/rg +0 -0
  191. package/vendor/ripgrep/macos-x86_64/rg +0 -0
  192. package/vendor/ripgrep/windows-aarch64/rg.exe +0 -0
  193. package/vendor/ripgrep/windows-x86_64/rg.exe +0 -0
@@ -1,357 +0,0 @@
1
- import { handleSessionRestoration } from "./session.js";
2
- import { setGlobalLogger } from "../utils/globalLogger.js";
3
- import { LspManager } from "../managers/lspManager.js";
4
- import { USER_MEMORY_FILE } from "../utils/constants.js";
5
- import type {
6
- Message,
7
- Logger,
8
- AgentOptions,
9
- ILspManager,
10
- } from "../types/index.js";
11
- import type { SkillManager } from "../managers/skillManager.js";
12
- import type { SubagentManager } from "../managers/subagentManager.js";
13
- import type { Container } from "../utils/container.js";
14
- import type { ToolManager } from "../managers/toolManager.js";
15
- import type { PluginManager } from "../managers/pluginManager.js";
16
- import type { SlashCommandManager } from "../managers/slashCommandManager.js";
17
- import type { McpManager } from "../managers/mcpManager.js";
18
- import type { ConfigurationService } from "./configurationService.js";
19
- import type { HookManager } from "../managers/hookManager.js";
20
- import type { MessageManager } from "../managers/messageManager.js";
21
- import type { MemoryRuleManager } from "../managers/MemoryRuleManager.js";
22
- import type { LiveConfigManager } from "../managers/liveConfigManager.js";
23
- import type { TaskManager } from "./taskManager.js";
24
- import type { PermissionManager } from "../managers/permissionManager.js";
25
- import { remoteSettingsService } from "./remoteSettingsService.js";
26
-
27
- export interface InitializationContext {
28
- skillManager: SkillManager;
29
- subagentManager: SubagentManager;
30
- container: Container;
31
- toolManager: ToolManager;
32
- pluginManager: PluginManager;
33
- options: AgentOptions;
34
- slashCommandManager: SlashCommandManager;
35
- logger?: Logger;
36
- mcpManager: McpManager;
37
- workdir: string;
38
- lspManager: ILspManager;
39
- configurationService: ConfigurationService;
40
- hookManager: HookManager;
41
- messageManager: MessageManager;
42
- memoryRuleManager: MemoryRuleManager;
43
- liveConfigManager: LiveConfigManager;
44
- taskManager: TaskManager;
45
- resolveAndValidateConfig: () => void;
46
- }
47
-
48
- export class InitializationService {
49
- public static async initialize(
50
- context: InitializationContext,
51
- options?: {
52
- restoreSessionId?: string;
53
- continueLastSession?: boolean;
54
- messages?: Message[];
55
- },
56
- ): Promise<void> {
57
- const {
58
- skillManager,
59
- subagentManager,
60
- container,
61
- toolManager,
62
- pluginManager,
63
- options: agentOptions,
64
- slashCommandManager,
65
- logger,
66
- mcpManager,
67
- workdir,
68
- lspManager,
69
- configurationService,
70
- hookManager,
71
- messageManager,
72
- memoryRuleManager,
73
- liveConfigManager,
74
- taskManager,
75
- resolveAndValidateConfig,
76
- } = context;
77
-
78
- const startTime = performance.now();
79
-
80
- // Set global logger early so managers can use it during initialization
81
- setGlobalLogger(logger || null);
82
-
83
- // Initialize managers first
84
- try {
85
- const phaseStart = performance.now();
86
- // Initialize SkillManager
87
- await skillManager.initialize();
88
-
89
- // Initialize SubagentManager (load and cache configurations)
90
- await subagentManager.initialize();
91
-
92
- // Register managers in container for tool access
93
- container.register("SubagentManager", subagentManager);
94
- container.register("SkillManager", skillManager);
95
-
96
- // Initialize built-in tools
97
- toolManager.initializeBuiltInTools();
98
-
99
- // Initialize plugins
100
- await pluginManager.loadPlugins(agentOptions.plugins || []);
101
-
102
- // Register skill commands
103
- slashCommandManager.registerSkillCommands(
104
- skillManager.getAvailableSkills(),
105
- );
106
- logger?.debug(
107
- `Initialization Phase [Managers and Tools] took ${(performance.now() - phaseStart).toFixed(2)}ms`,
108
- );
109
- } catch (error) {
110
- logger?.error("Failed to initialize managers and tools:", error);
111
- // Don't throw error to prevent app startup failure
112
- }
113
-
114
- // Initialize MCP servers with auto-connect
115
- try {
116
- const phaseStart = performance.now();
117
- await mcpManager.initialize(workdir, true);
118
- if (lspManager instanceof LspManager) {
119
- await lspManager.initialize(workdir);
120
- }
121
- logger?.debug(
122
- `Initialization Phase [MCP and LSP] took ${(performance.now() - phaseStart).toFixed(2)}ms`,
123
- );
124
- } catch (error) {
125
- logger?.error("Failed to initialize MCP servers:", error);
126
- // Don't throw error to prevent app startup failure
127
- }
128
-
129
- // Load remote settings disk cache synchronously.
130
- // Must happen BEFORE loadMergedConfiguration so cached managed settings
131
- // (env, model, disallowedTools) are merged into the config. Settings `env`
132
- // is stored in the per-session env snapshot (NOT process.env), except
133
- // WAVE_SERVER_URL which is mirrored to process.env so the network fetch
134
- // (below) can read it via authService.getServerUrl(); no race.
135
- try {
136
- const phaseStart = performance.now();
137
- await remoteSettingsService.initialize();
138
- logger?.debug(
139
- `Initialization Phase [Remote Settings Cache] took ${(performance.now() - phaseStart).toFixed(2)}ms`,
140
- );
141
- } catch (error) {
142
- logger?.error("Failed to initialize remote settings:", error);
143
- // Don't throw error to prevent app startup failure - continue without remote settings
144
- }
145
-
146
- // Initialize hooks configuration
147
- try {
148
- const phaseStart = performance.now();
149
- // Load hooks configuration using ConfigurationService
150
- const configResult =
151
- await configurationService.loadMergedConfiguration(workdir);
152
-
153
- hookManager.loadConfigurationFromWaveConfig(configResult.configuration);
154
-
155
- // Update plugin manager with enabled plugins configuration
156
- if (configResult.configuration?.enabledPlugins) {
157
- pluginManager.updateEnabledPlugins(
158
- configResult.configuration.enabledPlugins,
159
- );
160
- }
161
-
162
- // Initialize permission manager with loaded rules
163
- if (configResult.configuration?.permissions) {
164
- const permissionManager =
165
- context.container.get<PermissionManager>("PermissionManager");
166
- if (permissionManager) {
167
- if (configResult.configuration.permissions.allow) {
168
- permissionManager.updateAllowedRules(
169
- configResult.configuration.permissions.allow,
170
- );
171
- }
172
- if (configResult.configuration.permissions.deny) {
173
- permissionManager.updateDeniedRules(
174
- configResult.configuration.permissions.deny,
175
- );
176
- }
177
- if (configResult.configuration.permissions.permissionMode) {
178
- permissionManager.updateConfiguredPermissionMode(
179
- configResult.configuration.permissions.permissionMode,
180
- );
181
- }
182
- if (configResult.configuration.permissions.additionalDirectories) {
183
- permissionManager.updateAdditionalDirectories(
184
- configResult.configuration.permissions.additionalDirectories,
185
- );
186
- }
187
- }
188
- }
189
- logger?.debug(
190
- `Initialization Phase [Hooks Configuration] took ${(performance.now() - phaseStart).toFixed(2)}ms`,
191
- );
192
- } catch (error) {
193
- logger?.error("Failed to initialize hooks system:", error);
194
- // Don't throw error to prevent app startup failure
195
- }
196
-
197
- // Start remote settings network fetch + polling now that the config is
198
- // merged. Settings `env` WAVE_SERVER_URL was mirrored to process.env by
199
- // loadMergedConfiguration → setEnvironmentVars, so the fetch reads it via
200
- // authService.getServerUrl(); fire-and-forget, failures fall back to the
201
- // cached/merged settings.
202
- remoteSettingsService.startBackgroundFetch();
203
-
204
- // Execute SessionStart hooks
205
- try {
206
- const phaseStart = performance.now();
207
- const sessionStartResult = await hookManager.executeSessionStartHooks(
208
- "startup",
209
- messageManager.getSessionId(),
210
- messageManager.getTranscriptPath(),
211
- );
212
-
213
- // Inject additionalContext as a meta user message (matches Claude Code)
214
- if (sessionStartResult.additionalContext) {
215
- messageManager.addUserMessage({
216
- content: `<system-reminder>\nSessionStart hook additional context: ${sessionStartResult.additionalContext}\n</system-reminder>`,
217
- isMeta: true,
218
- });
219
- }
220
-
221
- // Inject initialUserMessage as a meta user message
222
- if (sessionStartResult.initialUserMessage) {
223
- messageManager.addUserMessage({
224
- content: sessionStartResult.initialUserMessage,
225
- isMeta: true,
226
- });
227
- }
228
-
229
- logger?.debug(
230
- `Initialization Phase [SessionStart Hooks] took ${(performance.now() - phaseStart).toFixed(2)}ms`,
231
- );
232
- } catch (error) {
233
- logger?.warn("SessionStart hooks execution failed:", error);
234
- }
235
-
236
- // Trigger WorktreeCreate hook if this is a new worktree
237
- if (agentOptions.isNewWorktree && hookManager) {
238
- try {
239
- logger?.info(
240
- `Triggering WorktreeCreate hook for ${agentOptions.worktreeName}...`,
241
- );
242
- const hookResults = await hookManager.executeHooks("WorktreeCreate", {
243
- event: "WorktreeCreate",
244
- projectDir: workdir,
245
- timestamp: new Date(),
246
- sessionId: messageManager.getSessionId(),
247
- transcriptPath: messageManager.getTranscriptPath(),
248
- cwd: workdir,
249
- worktreeName: agentOptions.worktreeName,
250
- env: Object.fromEntries(
251
- Object.entries(configurationService.getMergedEnv()).filter(
252
- (e) => e[1] !== undefined,
253
- ),
254
- ) as Record<string, string>,
255
- });
256
-
257
- // Process hook results
258
- hookManager.processHookResults(
259
- "WorktreeCreate",
260
- hookResults,
261
- messageManager,
262
- );
263
- } catch (error) {
264
- logger?.warn("WorktreeCreate hooks execution failed:", error);
265
- }
266
- }
267
-
268
- // Resolve and validate configuration after loading settings.json
269
- resolveAndValidateConfig();
270
-
271
- // Initialize auto-memory directory
272
- try {
273
- const phaseStart = performance.now();
274
- if (configurationService.resolveAutoMemoryEnabled()) {
275
- const memoryService =
276
- container.get<import("./memory.js").MemoryService>("MemoryService");
277
- if (memoryService) {
278
- await memoryService.ensureAutoMemoryDirectory(workdir);
279
- const permissionManager =
280
- container.get<PermissionManager>("PermissionManager");
281
- if (permissionManager) {
282
- const autoMemoryDir = memoryService.getAutoMemoryDirectory(workdir);
283
- permissionManager.addSystemAdditionalDirectory(autoMemoryDir);
284
- permissionManager.addSystemAdditionalDirectory(USER_MEMORY_FILE);
285
- }
286
- }
287
- }
288
- logger?.debug(
289
- `Initialization Phase [Auto-memory Initialization] took ${(performance.now() - phaseStart).toFixed(2)}ms`,
290
- );
291
- } catch (error) {
292
- logger?.error("Failed to initialize auto-memory directory:", error);
293
- }
294
-
295
- // Discover modular memory rules
296
- try {
297
- const phaseStart = performance.now();
298
- await memoryRuleManager.discoverRules();
299
- logger?.debug(
300
- `Initialization Phase [Memory Rules Discovery] took ${(performance.now() - phaseStart).toFixed(2)}ms`,
301
- );
302
- } catch (error) {
303
- logger?.error("Failed to discover memory rules:", error);
304
- }
305
-
306
- // Initialize live configuration reload
307
- try {
308
- const phaseStart = performance.now();
309
- await liveConfigManager.initialize();
310
- logger?.debug(
311
- `Initialization Phase [Live Config Initialization] took ${(performance.now() - phaseStart).toFixed(2)}ms`,
312
- );
313
- } catch (error) {
314
- logger?.error("Failed to initialize live configuration reload:", error);
315
- // Don't throw error to prevent app startup failure - continue without live reload
316
- }
317
-
318
- // Memory is lazy-cached on first getCombinedMemoryContent call
319
- // No explicit loading needed during initialization
320
-
321
- // Handle session restoration or set provided messages
322
- const sessionPhaseStart = performance.now();
323
- if (options?.messages) {
324
- // If messages are provided, use them directly (useful for testing)
325
- messageManager.setMessages(options.messages);
326
- // Rebuild usage array from restored messages
327
- messageManager.rebuildUsageFromMessages(options.messages);
328
- } else {
329
- // Otherwise, handle session restoration
330
- const sessionToRestore = await handleSessionRestoration(
331
- options?.restoreSessionId,
332
- options?.continueLastSession,
333
- messageManager.getWorkdir(),
334
- );
335
- // Rebuild usage array from restored messages
336
- messageManager.rebuildUsageFromMessages(sessionToRestore?.messages || []);
337
-
338
- if (sessionToRestore) {
339
- messageManager.initializeFromSession(sessionToRestore);
340
-
341
- // Update task manager with the root session ID to ensure continuity across compactions
342
- taskManager.setTaskListId(sessionToRestore.id);
343
-
344
- // After session is initialized, load tasks for the session
345
- const tasks = await taskManager.listTasks();
346
- agentOptions.callbacks?.onTasksChange?.(tasks);
347
- }
348
- }
349
- logger?.debug(
350
- `Initialization Phase [Session Restoration] took ${(performance.now() - sessionPhaseStart).toFixed(2)}ms`,
351
- );
352
-
353
- logger?.debug(
354
- `Total Initialization took ${(performance.now() - startTime).toFixed(2)}ms`,
355
- );
356
- }
357
- }
@@ -1,229 +0,0 @@
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
- logger,
37
- aiManager,
38
- } = context;
39
-
40
- try {
41
- // Handle slash command - check if it's a slash command (starts with /)
42
- if (content.startsWith("/")) {
43
- const command = content.trim();
44
- if (!command || command === "/") return;
45
-
46
- // Parse and validate slash command
47
- const { isValid, commandId, args } =
48
- slashCommandManager.parseAndValidateSlashCommand(command);
49
-
50
- if (isValid && commandId !== undefined) {
51
- // Execute valid slash command
52
- // Note: executeCommand sets isLoading early (e.g., custom commands set it
53
- // before bash execution). sendAIMessage() no longer guards against isLoading,
54
- // so callers can safely set it early without blocking subsequent AI calls.
55
- await slashCommandManager.executeCommand(commandId, args);
56
-
57
- return;
58
- }
59
-
60
- // If command doesn't exist, continue as normal message processing
61
- // Don't add to history, let normal message processing logic below handle it
62
- }
63
-
64
- // Handle normal AI message
65
- // Add user message first, will automatically sync to UI
66
- messageManager.addUserMessage({
67
- content,
68
- images: images?.map((img) => ({
69
- path: img.path,
70
- mimeType: img.mimeType,
71
- })),
72
- });
73
-
74
- // Reserve loading state synchronously before any async work (hooks).
75
- // This closes the race window where a concurrent notification/message
76
- // could see isLoading=false during the await below and start a second
77
- // sendAIMessage. sendAIMessage's generation guard is the backstop, but
78
- // reserving here prevents the race at its source.
79
- aiManager.setIsLoading(true);
80
-
81
- // Execute UserPromptSubmit hooks after adding the user message
82
- if (hookManager) {
83
- try {
84
- const hookResults = await hookManager.executeHooks(
85
- "UserPromptSubmit",
86
- {
87
- event: "UserPromptSubmit",
88
- projectDir: workdir,
89
- timestamp: new Date(),
90
- // UserPromptSubmit doesn't need toolName
91
- sessionId: messageManager.getSessionId(),
92
- transcriptPath: messageManager.getTranscriptPath(),
93
- cwd: workdir,
94
- userPrompt: content,
95
- env: Object.fromEntries(
96
- Object.entries(
97
- context.configurationService.getMergedEnv(),
98
- ).filter((e) => e[1] !== undefined),
99
- ) as Record<string, string>, // Include environment variables
100
- },
101
- );
102
-
103
- // Process hook results and determine if we should continue
104
- const processResult = hookManager.processHookResults(
105
- "UserPromptSubmit",
106
- hookResults,
107
- messageManager,
108
- );
109
-
110
- // If hook processing indicates we should block (exit code 2), stop here
111
- if (processResult.shouldBlock) {
112
- logger?.info(
113
- "UserPromptSubmit hook blocked prompt processing with error:",
114
- processResult.errorMessage,
115
- );
116
- // Release the loading state we reserved above
117
- aiManager.setIsLoading(false);
118
- return; // Don't send to AI
119
- }
120
- } catch (error) {
121
- logger?.warn("UserPromptSubmit hooks execution failed:", error);
122
- // Continue processing even if hooks fail
123
- }
124
- }
125
-
126
- // Send AI message
127
- await aiManager.sendAIMessage();
128
- } catch (error) {
129
- console.error("Failed to add user message:", error);
130
- // Ensure loading state is released on error
131
- aiManager.setIsLoading(false);
132
- // Loading state will be automatically updated by the useEffect that watches messages
133
- }
134
- }
135
-
136
- public static async restoreSession(
137
- context: InteractionContext,
138
- sessionId: string,
139
- ): Promise<void> {
140
- const {
141
- messageManager,
142
- hookManager,
143
- logger,
144
- subagentManager,
145
- taskManager,
146
- options,
147
- abortMessage,
148
- } = context;
149
-
150
- // 1. Validation
151
- if (!sessionId || sessionId === messageManager.getSessionId()) {
152
- return; // No-op if session ID is invalid or already current
153
- }
154
-
155
- // 2. Auto-save current session
156
- try {
157
- await messageManager.saveSession();
158
- } catch (error) {
159
- logger?.warn("Failed to save current session before restore:", error);
160
- // Continue with restoration even if save fails
161
- }
162
-
163
- // 3. Run SessionEnd hooks for the current session (cleanup before switching)
164
- const currentSessionId = messageManager.getSessionId();
165
- const currentTranscriptPath = messageManager.getTranscriptPath();
166
- if (hookManager) {
167
- try {
168
- await hookManager.executeSessionEndHooks(
169
- "resume",
170
- currentSessionId,
171
- currentTranscriptPath,
172
- );
173
- } catch (error) {
174
- logger?.warn(
175
- `SessionEnd hooks on restore failed: ${(error as Error).message}`,
176
- );
177
- }
178
- }
179
-
180
- // 4. Load target session
181
- const sessionData = await loadSessionFromJsonl(
182
- sessionId,
183
- messageManager.getWorkdir(),
184
- );
185
- if (!sessionData) {
186
- throw new Error(`Session not found: ${sessionId}`);
187
- }
188
-
189
- // 5. Clean current state
190
- abortMessage(); // Abort any running operations
191
- subagentManager.cleanup(); // Clean up active subagents
192
-
193
- // 6. Rebuild usage (in correct order)
194
- messageManager.rebuildUsageFromMessages(sessionData.messages);
195
-
196
- // 7. Initialize session state last
197
- messageManager.initializeFromSession(sessionData);
198
-
199
- // 8. Run SessionStart hooks for the restored session and inject additional
200
- // context as a meta user message (matches Claude Code's resume behavior:
201
- // SessionEnd then SessionStart, hook messages appended to the conversation)
202
- if (hookManager) {
203
- try {
204
- const sessionStartResult = await hookManager.executeSessionStartHooks(
205
- "resume",
206
- sessionData.id,
207
- messageManager.getTranscriptPath(),
208
- );
209
- if (sessionStartResult.additionalContext) {
210
- messageManager.addUserMessage({
211
- content: `<system-reminder>\nSessionStart hook additional context: ${sessionStartResult.additionalContext}\n</system-reminder>`,
212
- isMeta: true,
213
- });
214
- }
215
- } catch (error) {
216
- logger?.warn(
217
- `SessionStart hooks on restore failed: ${(error as Error).message}`,
218
- );
219
- }
220
- }
221
-
222
- // Update task manager with the root session ID to ensure continuity across compactions
223
- taskManager.setTaskListId(sessionData.id);
224
-
225
- // 9. Load tasks for the restored session
226
- const tasks = await taskManager.listTasks();
227
- options.callbacks?.onTasksChange?.(tasks);
228
- }
229
- }