wave-agent-sdk 1.0.4 → 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 (194) 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 +19 -9
  7. package/dist/managers/slashCommandManager.js +28 -0
  8. package/dist/managers/subagentManager.d.ts +0 -2
  9. package/dist/services/session.js +2 -9
  10. package/dist/telemetry/instrumentation.d.ts +1 -1
  11. package/dist/telemetry/instrumentation.js +57 -28
  12. package/dist/tools/bashTool.js +16 -6
  13. package/dist/tools/grepTool.js +11 -3
  14. package/dist/types/index.d.ts +3 -0
  15. package/dist/types/messaging.d.ts +2 -0
  16. package/dist/utils/containerSetup.js +0 -3
  17. package/dist/utils/messageOperations.d.ts +10 -1
  18. package/dist/utils/messageOperations.js +19 -1
  19. package/dist/utils/notificationXml.js +5 -0
  20. package/dist/utils/ripgrep.d.ts +4 -4
  21. package/dist/utils/ripgrep.js +4 -27
  22. package/package.json +20 -8
  23. package/bin/rg +0 -79
  24. package/dist/managers/forkedAgentManager.d.ts +0 -50
  25. package/dist/managers/forkedAgentManager.js +0 -130
  26. package/scripts/install_ripgrep.js +0 -111
  27. package/scripts/postinstall.js +0 -38
  28. package/src/agent.ts +0 -1271
  29. package/src/constants/subagents.ts +0 -4
  30. package/src/constants/toolLimits.ts +0 -15
  31. package/src/constants/tools.ts +0 -24
  32. package/src/core/plugin.ts +0 -237
  33. package/src/core/session.ts +0 -9
  34. package/src/index.ts +0 -38
  35. package/src/managers/MemoryRuleManager.ts +0 -198
  36. package/src/managers/aiManager.ts +0 -2429
  37. package/src/managers/backgroundTaskManager.ts +0 -480
  38. package/src/managers/bangManager.ts +0 -119
  39. package/src/managers/cronManager.ts +0 -401
  40. package/src/managers/foregroundTaskManager.ts +0 -30
  41. package/src/managers/forkedAgentManager.ts +0 -216
  42. package/src/managers/hookManager.ts +0 -1089
  43. package/src/managers/liveConfigManager.ts +0 -445
  44. package/src/managers/lspManager.ts +0 -470
  45. package/src/managers/mcpManager.ts +0 -1010
  46. package/src/managers/messageManager.ts +0 -1180
  47. package/src/managers/messageQueue.ts +0 -157
  48. package/src/managers/permissionManager.ts +0 -1140
  49. package/src/managers/planManager.ts +0 -112
  50. package/src/managers/pluginManager.ts +0 -330
  51. package/src/managers/pluginScopeManager.ts +0 -124
  52. package/src/managers/reversionManager.ts +0 -178
  53. package/src/managers/skillManager.ts +0 -578
  54. package/src/managers/slashCommandManager.ts +0 -564
  55. package/src/managers/subagentManager.ts +0 -915
  56. package/src/managers/toolManager.ts +0 -489
  57. package/src/managers/workflowManager.ts +0 -493
  58. package/src/prompts/autoMemory.ts +0 -33
  59. package/src/prompts/autoMemoryExtraction.ts +0 -146
  60. package/src/prompts/index.ts +0 -506
  61. package/src/prompts/planModeReminders.ts +0 -126
  62. package/src/services/GitService.ts +0 -131
  63. package/src/services/MarketplaceService.ts +0 -1052
  64. package/src/services/MemoryRuleService.ts +0 -71
  65. package/src/services/aiService.ts +0 -919
  66. package/src/services/authService.ts +0 -565
  67. package/src/services/autoMemoryService.ts +0 -280
  68. package/src/services/configurationService.ts +0 -1520
  69. package/src/services/fileWatcher.ts +0 -319
  70. package/src/services/hook.ts +0 -348
  71. package/src/services/initializationService.ts +0 -357
  72. package/src/services/interactionService.ts +0 -229
  73. package/src/services/jsonlHandler.ts +0 -295
  74. package/src/services/memory.ts +0 -234
  75. package/src/services/pluginLoader.ts +0 -252
  76. package/src/services/remoteSettingsService.ts +0 -366
  77. package/src/services/reversionService.ts +0 -122
  78. package/src/services/session.ts +0 -922
  79. package/src/services/taskManager.ts +0 -321
  80. package/src/telemetry/events.ts +0 -65
  81. package/src/telemetry/instrumentation.ts +0 -499
  82. package/src/telemetry/sessionTracing.ts +0 -348
  83. package/src/tools/agentTool.ts +0 -322
  84. package/src/tools/askUserQuestion.ts +0 -160
  85. package/src/tools/bashTool.ts +0 -621
  86. package/src/tools/buildTool.ts +0 -61
  87. package/src/tools/cronCreateTool.ts +0 -161
  88. package/src/tools/cronDeleteTool.ts +0 -51
  89. package/src/tools/cronListTool.ts +0 -47
  90. package/src/tools/editTool.ts +0 -313
  91. package/src/tools/enterPlanMode.ts +0 -124
  92. package/src/tools/enterWorktreeTool.ts +0 -190
  93. package/src/tools/exitPlanMode.ts +0 -139
  94. package/src/tools/exitWorktreeTool.ts +0 -236
  95. package/src/tools/globTool.ts +0 -167
  96. package/src/tools/grepTool.ts +0 -399
  97. package/src/tools/lspTool.ts +0 -883
  98. package/src/tools/readTool.ts +0 -426
  99. package/src/tools/skillTool.ts +0 -248
  100. package/src/tools/taskManagementTools.ts +0 -574
  101. package/src/tools/taskStopTool.ts +0 -78
  102. package/src/tools/types.ts +0 -137
  103. package/src/tools/webFetchTool.ts +0 -373
  104. package/src/tools/workflowTool.ts +0 -205
  105. package/src/tools/writeTool.ts +0 -267
  106. package/src/types/agent.ts +0 -128
  107. package/src/types/auth.ts +0 -19
  108. package/src/types/commands.ts +0 -30
  109. package/src/types/config.ts +0 -43
  110. package/src/types/configuration.ts +0 -168
  111. package/src/types/core.ts +0 -105
  112. package/src/types/cron.ts +0 -13
  113. package/src/types/environment.ts +0 -106
  114. package/src/types/fileSearch.ts +0 -4
  115. package/src/types/history.ts +0 -7
  116. package/src/types/hooks.ts +0 -256
  117. package/src/types/index.ts +0 -41
  118. package/src/types/lsp.ts +0 -98
  119. package/src/types/marketplace.ts +0 -71
  120. package/src/types/mcp.ts +0 -43
  121. package/src/types/memoryRule.ts +0 -31
  122. package/src/types/messaging.ts +0 -114
  123. package/src/types/permissions.ts +0 -80
  124. package/src/types/plugins.ts +0 -39
  125. package/src/types/processes.ts +0 -99
  126. package/src/types/reversion.ts +0 -29
  127. package/src/types/session.ts +0 -12
  128. package/src/types/skills.ts +0 -108
  129. package/src/types/tasks.ts +0 -13
  130. package/src/types/telemetry.ts +0 -98
  131. package/src/types/tools.ts +0 -44
  132. package/src/types/workflow.ts +0 -6
  133. package/src/utils/abortUtils.ts +0 -118
  134. package/src/utils/atomicWrite.ts +0 -61
  135. package/src/utils/bashParser.ts +0 -899
  136. package/src/utils/cacheControlUtils.ts +0 -426
  137. package/src/utils/commandArgumentParser.ts +0 -161
  138. package/src/utils/commandPathResolver.ts +0 -88
  139. package/src/utils/configPaths.ts +0 -220
  140. package/src/utils/configValidator.ts +0 -100
  141. package/src/utils/constants.ts +0 -39
  142. package/src/utils/container.ts +0 -92
  143. package/src/utils/containerSetup.ts +0 -371
  144. package/src/utils/convertMessagesForAPI.ts +0 -326
  145. package/src/utils/cronTasks.ts +0 -128
  146. package/src/utils/cronTasksLock.ts +0 -182
  147. package/src/utils/cronToHuman.ts +0 -99
  148. package/src/utils/customCommands.ts +0 -95
  149. package/src/utils/editUtils.ts +0 -20
  150. package/src/utils/fileFormat.ts +0 -40
  151. package/src/utils/fileSearch.ts +0 -151
  152. package/src/utils/fileUtils.ts +0 -223
  153. package/src/utils/gitUtils.ts +0 -315
  154. package/src/utils/globalLogger.ts +0 -128
  155. package/src/utils/groupMessagesByApiRound.ts +0 -121
  156. package/src/utils/hookMatcher.ts +0 -176
  157. package/src/utils/markdownParser.ts +0 -317
  158. package/src/utils/mcpUtils.ts +0 -138
  159. package/src/utils/messageOperations.ts +0 -641
  160. package/src/utils/modelCapabilities.ts +0 -30
  161. package/src/utils/nameGenerator.ts +0 -99
  162. package/src/utils/notificationXml.ts +0 -57
  163. package/src/utils/openaiClient.ts +0 -251
  164. package/src/utils/parseCronExpression.ts +0 -78
  165. package/src/utils/path.ts +0 -72
  166. package/src/utils/pathEncoder.ts +0 -400
  167. package/src/utils/pathSafety.ts +0 -40
  168. package/src/utils/promptHistory.ts +0 -168
  169. package/src/utils/ripgrep.ts +0 -35
  170. package/src/utils/shellResolver.ts +0 -190
  171. package/src/utils/skillParser.ts +0 -246
  172. package/src/utils/stringUtils.ts +0 -156
  173. package/src/utils/subagentParser.ts +0 -279
  174. package/src/utils/taskReminder.ts +0 -96
  175. package/src/utils/tokenCalculation.ts +0 -43
  176. package/src/utils/tokenEstimate.ts +0 -34
  177. package/src/utils/toolResultStorage.ts +0 -117
  178. package/src/utils/worktreeSession.ts +0 -26
  179. package/src/utils/worktreeUtils.ts +0 -786
  180. package/src/workflow/budgetTracker.ts +0 -34
  181. package/src/workflow/concurrencyLimiter.ts +0 -47
  182. package/src/workflow/journal.ts +0 -95
  183. package/src/workflow/progressReporter.ts +0 -141
  184. package/src/workflow/runState.ts +0 -65
  185. package/src/workflow/scriptRuntime.ts +0 -274
  186. package/src/workflow/structuredOutput.ts +0 -123
  187. package/src/workflow/types.ts +0 -101
  188. package/src/workflow/workflowApis.ts +0 -410
  189. package/vendor/ripgrep/linux-aarch64/rg +0 -0
  190. package/vendor/ripgrep/linux-x86_64/rg +0 -0
  191. package/vendor/ripgrep/macos-aarch64/rg +0 -0
  192. package/vendor/ripgrep/macos-x86_64/rg +0 -0
  193. package/vendor/ripgrep/windows-aarch64/rg.exe +0 -0
  194. 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
- }