wave-agent-sdk 1.0.5 → 1.0.7

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