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
@@ -14,6 +14,34 @@ export class SlashCommandManager {
14
14
  }
15
15
  initialize() {
16
16
  this.loadCustomCommands();
17
+ // Builtin /subtask: manual fork subagent (aligned with Claude Code's
18
+ // /subtask — inherits the parent's full context, runs in the background,
19
+ // result returns to the main conversation via a task notification).
20
+ this.registerCommand({
21
+ id: "subtask",
22
+ name: "subtask",
23
+ description: "Start a fork subagent with the current conversation context in the background",
24
+ handler: async (args, signal) => {
25
+ const taskDescription = args?.trim();
26
+ if (!taskDescription) {
27
+ this.messageManager.addErrorBlock("Usage: /subtask <task description>");
28
+ return;
29
+ }
30
+ try {
31
+ // The fork snapshots its context synchronously on entry, so the
32
+ // transcript echo below never duplicates the prompt inside the fork.
33
+ await this.aiManager.runForkSubagent(taskDescription, { description: taskDescription }, signal);
34
+ this.messageManager.addUserMessage({
35
+ content: `/subtask ${taskDescription}`,
36
+ });
37
+ }
38
+ catch (error) {
39
+ this.aiManager.setIsLoading(false);
40
+ logger?.error("Failed to execute /subtask:", error);
41
+ this.messageManager.addErrorBlock(`Failed to execute /subtask: ${error instanceof Error ? error.message : String(error)}`);
42
+ }
43
+ },
44
+ });
17
45
  // Listen for skill refreshes and update skill commands
18
46
  const skillManager = this.container.get("SkillManager");
19
47
  if (skillManager) {
@@ -19,7 +19,6 @@ export interface SubagentManagerCallbacks {
19
19
  subagentId: string;
20
20
  messageId: string;
21
21
  chunk: string;
22
- accumulated: string;
23
22
  stage: "streaming" | "end";
24
23
  }) => void;
25
24
  /** Triggered during subagent reasoning streaming updates */
@@ -27,7 +26,6 @@ export interface SubagentManagerCallbacks {
27
26
  subagentId: string;
28
27
  messageId: string;
29
28
  chunk: string;
30
- accumulated: string;
31
29
  stage: "streaming" | "end";
32
30
  }) => void;
33
31
  /** Triggered when subagent tool block is updated */
@@ -1,7 +1,6 @@
1
1
  import { ChatCompletionMessageToolCall } from "openai/resources";
2
2
  import { ChatCompletionMessageParam, ChatCompletionFunctionTool } from "openai/resources.js";
3
- import type { GatewayConfig, ModelConfig } from "../types/index.js";
4
- import { type ClaudeUsage } from "../utils/cacheControlUtils.js";
3
+ import type { GatewayConfig, ModelConfig, Usage } from "../types/index.js";
5
4
  import { type SystemPromptBlock } from "../prompts/index.js";
6
5
  /**
7
6
  * Resets the rate limiter state. Primarily used for testing.
@@ -40,7 +39,7 @@ export interface CallAgentResult {
40
39
  content?: string;
41
40
  tool_calls?: ChatCompletionMessageToolCall[];
42
41
  reasoning_content?: string;
43
- usage?: ClaudeUsage;
42
+ usage?: Usage;
44
43
  finish_reason?: "stop" | "length" | "tool_calls" | "content_filter" | "function_call" | null;
45
44
  response_headers?: Record<string, string>;
46
45
  additionalFields?: Record<string, unknown>;
@@ -202,17 +202,9 @@ export async function callAgent(options) {
202
202
  });
203
203
  const finalMessage = response.choices[0]?.message;
204
204
  const finishReason = response.choices[0]?.finish_reason || null;
205
- let totalUsage = response.usage
206
- ? {
207
- prompt_tokens: response.usage.prompt_tokens,
208
- completion_tokens: response.usage.completion_tokens,
209
- total_tokens: response.usage.total_tokens,
210
- }
205
+ const totalUsage = response.usage
206
+ ? extendUsageWithCacheMetrics(response.usage)
211
207
  : undefined;
212
- // Extend usage with cache metrics (Claude top-level + OpenAI prompt_tokens_details)
213
- if (totalUsage && response.usage) {
214
- totalUsage = extendUsageWithCacheMetrics(totalUsage, response.usage);
215
- }
216
208
  const result = {};
217
209
  if (finalMessage) {
218
210
  const { content: finalContent, tool_calls: finalToolCalls, reasoning_content: finalReasoningContent, ...otherFields } = finalMessage;
@@ -353,14 +345,8 @@ async function processStreamingResponse(stream, onContentUpdate, onToolUpdate, o
353
345
  }
354
346
  // Check for usage information in any chunk
355
347
  if (chunk.usage) {
356
- let chunkUsage = {
357
- prompt_tokens: chunk.usage.prompt_tokens,
358
- completion_tokens: chunk.usage.completion_tokens,
359
- total_tokens: chunk.usage.total_tokens,
360
- };
361
- // Extend usage with cache metrics (Claude top-level + OpenAI prompt_tokens_details)
362
- chunkUsage = extendUsageWithCacheMetrics(chunkUsage, chunk.usage);
363
- usage = chunkUsage;
348
+ // Extend usage with cache metrics from OpenAI prompt_tokens_details
349
+ usage = extendUsageWithCacheMetrics(chunk.usage);
364
350
  }
365
351
  // Check for finish_reason in the choice
366
352
  const choice = chunk.choices?.[0];
@@ -196,6 +196,13 @@ export declare function mergeEnvironmentConfig(userEnv: Record<string, string> |
196
196
  * Supports both hooks and environment variables with proper validation
197
197
  */
198
198
  export declare function loadWaveConfigFromFile(filePath: string): WaveConfiguration | null;
199
+ /**
200
+ * Load the user-level (~/.wave/settings.json) `env` block only — no workdir
201
+ * dependency. Used at daemon startup to apply WAVE_SERVER_URL before any agent
202
+ * initializes: auth queries (getAuthStatus) can run before the first agent,
203
+ * and AuthService falls back to the default URL otherwise.
204
+ */
205
+ export declare function loadUserConfigEnv(): Record<string, string>;
199
206
  /**
200
207
  * Load and merge Wave configuration from both user and project sources
201
208
  * Project configuration takes precedence over user configuration
@@ -1079,6 +1079,16 @@ export function loadWaveConfigFromFile(filePath) {
1079
1079
  throw error;
1080
1080
  }
1081
1081
  }
1082
+ /**
1083
+ * Load the user-level (~/.wave/settings.json) `env` block only — no workdir
1084
+ * dependency. Used at daemon startup to apply WAVE_SERVER_URL before any agent
1085
+ * initializes: auth queries (getAuthStatus) can run before the first agent,
1086
+ * and AuthService falls back to the default URL otherwise.
1087
+ */
1088
+ export function loadUserConfigEnv() {
1089
+ const config = loadWaveConfigFromFile(getUserConfigPaths()[0]);
1090
+ return config?.env ?? {};
1091
+ }
1082
1092
  /**
1083
1093
  * Load and merge Wave configuration from both user and project sources
1084
1094
  * Project configuration takes precedence over user configuration
@@ -5,7 +5,7 @@
5
5
  * and graceful shutdown for Wave's OpenTelemetry integration.
6
6
  */
7
7
  import type { TelemetryConfig } from "../types/telemetry.js";
8
- import type { SpanExporter, ReadableSpan } from "@opentelemetry/sdk-trace-node";
8
+ import type { SpanExporter, ReadableSpan } from "@opentelemetry/sdk-trace-base";
9
9
  import type { LogRecordExporter, ReadableLogRecord } from "@opentelemetry/sdk-logs";
10
10
  /**
11
11
  * Resolve the full TelemetryConfig from env vars + settings.json.
@@ -8,13 +8,17 @@ import { logger } from "../utils/globalLogger.js";
8
8
  import * as fs from "node:fs";
9
9
  import { AuthService, getOrCreateAnonymousId, } from "../services/authService.js";
10
10
  // Lazy-loaded OTEL modules — only imported when telemetry is initialized
11
- let sdkNode;
11
+ let sdkTraceBase;
12
+ let otelResources;
12
13
  let api;
14
+ let apiLogs;
13
15
  let sdkLogs;
14
16
  let exporterTraceOtlpHttp;
15
17
  let exporterLogsOtlpHttp;
16
- /** Internal SDK instance */
17
- let otelSdk;
18
+ /** Internal trace provider instance */
19
+ let tracerProvider;
20
+ /** Internal log provider instance */
21
+ let loggerProvider;
18
22
  /** Whether telemetry has been initialized */
19
23
  let initialized = false;
20
24
  /** Current resolved config */
@@ -34,14 +38,23 @@ function resolveTelemetryFilePath() {
34
38
  async function loadOTELModules() {
35
39
  if (api)
36
40
  return; // Already loaded
37
- [sdkNode, api, sdkLogs, exporterTraceOtlpHttp, exporterLogsOtlpHttp] =
38
- await Promise.all([
39
- import("@opentelemetry/sdk-node"),
40
- import("@opentelemetry/api"),
41
- import("@opentelemetry/sdk-logs"),
42
- import("@opentelemetry/exporter-trace-otlp-http"),
43
- import("@opentelemetry/exporter-logs-otlp-http"),
44
- ]);
41
+ [
42
+ sdkTraceBase,
43
+ otelResources,
44
+ api,
45
+ apiLogs,
46
+ sdkLogs,
47
+ exporterTraceOtlpHttp,
48
+ exporterLogsOtlpHttp,
49
+ ] = await Promise.all([
50
+ import("@opentelemetry/sdk-trace-base"),
51
+ import("@opentelemetry/resources"),
52
+ import("@opentelemetry/api"),
53
+ import("@opentelemetry/api-logs"),
54
+ import("@opentelemetry/sdk-logs"),
55
+ import("@opentelemetry/exporter-trace-otlp-http"),
56
+ import("@opentelemetry/exporter-logs-otlp-http"),
57
+ ]);
45
58
  }
46
59
  /**
47
60
  * Resolve the exporter target from environment variable or config.
@@ -281,33 +294,43 @@ export async function initializeTelemetry(config) {
281
294
  return;
282
295
  }
283
296
  const { tracesExporter, logsExporter } = currentConfig;
284
- // Build resource attributes using new API (sdk-node 0.217+)
285
- const { resources } = sdkNode;
286
- const resource = resources.defaultResource().merge(resources.resourceFromAttributes({
297
+ // Build resource attributes (lightweight assembly: sdk-trace-base + resources)
298
+ const resource = otelResources.defaultResource().merge(otelResources.resourceFromAttributes({
287
299
  "service.name": "wave",
288
300
  "service.version": process.env.npm_package_version || "unknown",
289
301
  "os.type": process.platform,
290
302
  "host.arch": process.arch,
291
303
  }));
292
- // Configure trace provider
293
- const nodeSdkOptions = { resource };
304
+ const spanProcessors = [];
294
305
  if (tracesExporter === "otlp" && currentConfig.endpoint) {
295
- nodeSdkOptions.traceExporter = createOTLPTraceExporter(currentConfig);
306
+ spanProcessors.push(new sdkTraceBase.BatchSpanProcessor(createOTLPTraceExporter(currentConfig)));
296
307
  }
297
308
  else if (tracesExporter === "jsonl") {
298
- nodeSdkOptions.traceExporter = new JsonlSpanExporter();
309
+ spanProcessors.push(new sdkTraceBase.BatchSpanProcessor(new JsonlSpanExporter()));
299
310
  }
300
- // Configure logs provider
311
+ const logProcessors = [];
301
312
  if (logsExporter === "otlp" && currentConfig.endpoint) {
302
- nodeSdkOptions.logRecordProcessor = new sdkLogs.BatchLogRecordProcessor(createOTLPLogExporter(currentConfig));
313
+ logProcessors.push(new sdkLogs.BatchLogRecordProcessor(createOTLPLogExporter(currentConfig)));
303
314
  }
304
315
  else if (logsExporter === "jsonl") {
305
- nodeSdkOptions.logRecordProcessor = new sdkLogs.BatchLogRecordProcessor(new JsonlLogExporter());
316
+ logProcessors.push(new sdkLogs.BatchLogRecordProcessor(new JsonlLogExporter()));
306
317
  }
307
- // Only initialize SDK if at least one exporter is configured
308
- if (nodeSdkOptions.traceExporter || nodeSdkOptions.logRecordProcessor) {
309
- otelSdk = new sdkNode.NodeSDK(nodeSdkOptions);
310
- await otelSdk.start();
318
+ // Only initialize providers if at least one exporter is configured
319
+ if (spanProcessors.length > 0 || logProcessors.length > 0) {
320
+ if (spanProcessors.length > 0) {
321
+ tracerProvider = new sdkTraceBase.BasicTracerProvider({
322
+ resource,
323
+ spanProcessors,
324
+ });
325
+ api.trace.setGlobalTracerProvider(tracerProvider);
326
+ }
327
+ if (logProcessors.length > 0) {
328
+ loggerProvider = new sdkLogs.LoggerProvider({
329
+ resource,
330
+ processors: logProcessors,
331
+ });
332
+ apiLogs.logs.setGlobalLoggerProvider(loggerProvider);
333
+ }
311
334
  initialized = true;
312
335
  logger?.info("OpenTelemetry initialized", {
313
336
  tracesExporter,
@@ -329,7 +352,7 @@ export async function initializeTelemetry(config) {
329
352
  * Respects shutdownTimeoutMs config.
330
353
  */
331
354
  export async function shutdownTelemetry() {
332
- if (!otelSdk || !initialized) {
355
+ if (!tracerProvider && !loggerProvider) {
333
356
  return;
334
357
  }
335
358
  try {
@@ -337,14 +360,20 @@ export async function shutdownTelemetry() {
337
360
  const timeoutPromise = new Promise((_, reject) => {
338
361
  setTimeout(() => reject(new Error("Telemetry shutdown timed out")), timeout);
339
362
  });
340
- await Promise.race([otelSdk.shutdown(), timeoutPromise]);
363
+ const shutdowns = [];
364
+ if (tracerProvider)
365
+ shutdowns.push(tracerProvider.shutdown());
366
+ if (loggerProvider)
367
+ shutdowns.push(loggerProvider.shutdown());
368
+ await Promise.race([Promise.all(shutdowns), timeoutPromise]);
341
369
  logger?.debug("OpenTelemetry shut down successfully");
342
370
  }
343
371
  catch (error) {
344
372
  logger?.warn("OpenTelemetry shutdown failed:", error);
345
373
  }
346
374
  finally {
347
- otelSdk = undefined;
375
+ tracerProvider = undefined;
376
+ loggerProvider = undefined;
348
377
  initialized = false;
349
378
  currentConfig = undefined;
350
379
  }
@@ -152,6 +152,13 @@ The working directory persists between commands. Try to maintain your current wo
152
152
  error: "Command parameter is required and must be a string",
153
153
  };
154
154
  }
155
+ // If the session cwd was auto-recovered (e.g. the previous worktree
156
+ // directory was removed manually via `git worktree remove`), surface
157
+ // the notice in this tool's result so the model is aware of the switch.
158
+ const cwdRecovery = context.aiManager?.consumeCwdRecovery?.();
159
+ const recoveryNotice = cwdRecovery
160
+ ? `Note: working directory ${cwdRecovery.from} no longer exists; session working directory recovered to ${cwdRecovery.to}.\n`
161
+ : "";
155
162
  // Resolve shell path: on Windows, use Git Bash; on macOS/Linux, use bash or zsh
156
163
  const shellPath = resolveShellPath();
157
164
  if (!shellPath) {
@@ -221,7 +228,7 @@ The working directory persists between commands. Try to maintain your current wo
221
228
  ].join("\n");
222
229
  return {
223
230
  success: true,
224
- content: backgroundMsg,
231
+ content: recoveryNotice + backgroundMsg,
225
232
  shortResult: `Background process ${taskId} started${outputPath ? ` → ${outputPath}` : ""}`,
226
233
  };
227
234
  }
@@ -387,9 +394,11 @@ The working directory persists between commands. Try to maintain your current wo
387
394
  const processedOutput = processToolResult(outputBuffer + (errorBuffer ? "\n" + errorBuffer : ""), BASH_MAX_OUTPUT_CHARS, "bash");
388
395
  resolve({
389
396
  success: false,
390
- content: processedOutput
391
- ? `${processedOutput}\n\n${reason}`
392
- : reason,
397
+ content: recoveryNotice
398
+ ? recoveryNotice + (processedOutput || reason)
399
+ : processedOutput
400
+ ? `${processedOutput}\n\n${reason}`
401
+ : reason,
393
402
  error: reason,
394
403
  });
395
404
  }
@@ -460,7 +469,8 @@ The working directory persists between commands. Try to maintain your current wo
460
469
  const exitCode = code ?? 0;
461
470
  const combinedOutput = outputBuffer + (errorBuffer ? "\n" + errorBuffer : "");
462
471
  // Prepend CWD change message to output if present
463
- const finalOutput = (cwdMessage ? cwdMessage + "\n" : "") +
472
+ const finalOutput = recoveryNotice +
473
+ (cwdMessage ? cwdMessage + "\n" : "") +
464
474
  (combinedOutput || `Command executed with exit code: ${exitCode}`);
465
475
  const content = processToolResult(finalOutput, BASH_MAX_OUTPUT_CHARS, "bash");
466
476
  const lines = combinedOutput.trim().split("\n");
@@ -490,7 +500,7 @@ The working directory persists between commands. Try to maintain your current wo
490
500
  resolve({
491
501
  success: false,
492
502
  content: "",
493
- error: `Failed to execute command: ${error.message}`,
503
+ error: `${recoveryNotice}Failed to execute command: ${error.message}`.trim(),
494
504
  });
495
505
  }
496
506
  });
@@ -131,6 +131,13 @@ export const grepTool = {
131
131
  }
132
132
  try {
133
133
  const workdir = context.workdir;
134
+ // If the session cwd was auto-recovered (e.g. the previous worktree
135
+ // directory was removed manually via `git worktree remove`), surface
136
+ // the notice in this tool's result so the model is aware of the switch.
137
+ const cwdRecovery = context.aiManager?.consumeCwdRecovery?.();
138
+ const recoveryNotice = cwdRecovery
139
+ ? `Note: working directory ${cwdRecovery.from} no longer exists; session working directory recovered to ${cwdRecovery.to}.\n`
140
+ : "";
134
141
  const rgArgs = [
135
142
  "--color=never",
136
143
  "--max-columns=500",
@@ -207,7 +214,7 @@ export const grepTool = {
207
214
  return {
208
215
  success: false,
209
216
  content: "",
210
- error: `ripgrep failed: ${result.stderr}`,
217
+ error: `${recoveryNotice}ripgrep failed: ${result.stderr}`.trim(),
211
218
  };
212
219
  }
213
220
  if (result.exitCode !== 0 && result.exitCode !== 1) {
@@ -217,7 +224,8 @@ export const grepTool = {
217
224
  if (!output) {
218
225
  return {
219
226
  success: true,
220
- content: "No matches found. Suggestion: specify the 'path' field to search in ignored or other directories (e.g., 'node_modules'), as the default search path is the current working directory and respects .gitignore.",
227
+ content: recoveryNotice +
228
+ "No matches found. Suggestion: specify the 'path' field to search in ignored or other directories (e.g., 'node_modules'), as the default search path is the current working directory and respects .gitignore.",
221
229
  shortResult: "No matches found",
222
230
  metadata: {
223
231
  numMatches: 0,
@@ -256,7 +264,7 @@ export const grepTool = {
256
264
  }
257
265
  return {
258
266
  success: true,
259
- content: finalOutput,
267
+ content: recoveryNotice + finalOutput,
260
268
  shortResult,
261
269
  metadata: {
262
270
  numMatches: totalMatches,
@@ -2,7 +2,6 @@
2
2
  * Core foundational types used across multiple domains
3
3
  * Dependencies: None (foundation layer)
4
4
  */
5
- import type { CompletionUsage } from "openai/resources";
6
5
  /**
7
6
  * Logger interface definition
8
7
  * Compatible with OpenAI package Logger interface
@@ -15,7 +14,7 @@ export interface Logger {
15
14
  }
16
15
  /**
17
16
  * Usage statistics for AI operations
18
- * Extends OpenAI's Usage format with additional tracking fields
17
+ * Extends OpenAI's Usage format with normalized cache fields
19
18
  */
20
19
  export interface Usage {
21
20
  prompt_tokens: number;
@@ -25,38 +24,6 @@ export interface Usage {
25
24
  operation_type?: "agent" | "compact";
26
25
  cache_read_input_tokens?: number;
27
26
  cache_creation_input_tokens?: number;
28
- cache_creation?: {
29
- ephemeral_5m_input_tokens: number;
30
- ephemeral_1h_input_tokens: number;
31
- };
32
- }
33
- /**
34
- * Enhanced usage metrics including Claude cache information
35
- * Backward compatible with standard OpenAI CompletionUsage
36
- */
37
- export interface ClaudeUsage extends CompletionUsage {
38
- prompt_tokens: number;
39
- completion_tokens: number;
40
- total_tokens: number;
41
- /**
42
- * Number of tokens read from existing cache
43
- * Indicates cost savings from cache hits
44
- */
45
- cache_read_input_tokens?: number;
46
- /**
47
- * Number of tokens used to create new cache entries
48
- * Investment in future cache hits
49
- */
50
- cache_creation_input_tokens?: number;
51
- /**
52
- * Detailed breakdown of cache creation by duration
53
- */
54
- cache_creation?: {
55
- /** Tokens cached for 5 minute duration */
56
- ephemeral_5m_input_tokens: number;
57
- /** Tokens cached for 1 hour duration */
58
- ephemeral_1h_input_tokens: number;
59
- };
60
27
  }
61
28
  /**
62
29
  * Represents a diff change for tool parameter-based diff display
@@ -35,3 +35,7 @@ export * from "./cron.js";
35
35
  export * from "./telemetry.js";
36
36
  export * from "./auth.js";
37
37
  export * from "./workflow.js";
38
+ export type { SessionMetadata, SessionData } from "../services/session.js";
39
+ export type { ToolBlockUpdateCallbackParams } from "../utils/messageOperations.js";
40
+ export type { QueuedMessage } from "../managers/messageQueue.js";
41
+ export type { SubagentConfiguration } from "../utils/subagentParser.js";
@@ -88,4 +88,6 @@ export interface TaskNotificationBlock {
88
88
  status: "completed" | "failed" | "killed" | "aborted";
89
89
  summary: string;
90
90
  outputFile?: string;
91
+ /** Full final response of the task (e.g. a fork subagent's result). */
92
+ result?: string;
91
93
  }
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import type { ChatCompletionMessageParam, ChatCompletionContentPart, ChatCompletionContentPartText, CompletionUsage } from "openai/resources";
9
9
  import type { ModelCapabilities } from "../types/config.js";
10
+ import type { Usage } from "../types/core.js";
10
11
  /**
11
12
  * Cache control directive for Claude models
12
13
  */
@@ -28,22 +29,6 @@ export interface ClaudeChatCompletionContentPartText extends ChatCompletionConte
28
29
  export interface ExtendedPromptTokensDetails extends CompletionUsage.PromptTokensDetails {
29
30
  cache_creation_input_tokens?: number;
30
31
  }
31
- /**
32
- * Enhanced usage metrics including cache information
33
- * Supports both Claude-specific top-level fields and OpenAI-standard prompt_tokens_details
34
- */
35
- export interface ClaudeUsage extends CompletionUsage {
36
- prompt_tokens: number;
37
- completion_tokens: number;
38
- total_tokens: number;
39
- cache_read_input_tokens?: number;
40
- cache_creation_input_tokens?: number;
41
- cache_creation?: {
42
- ephemeral_5m_input_tokens: number;
43
- ephemeral_1h_input_tokens: number;
44
- };
45
- prompt_tokens_details?: ExtendedPromptTokensDetails;
46
- }
47
32
  /**
48
33
  * Validates cache control structure
49
34
  * @param control - Object to validate
@@ -85,16 +70,9 @@ export declare function countContentBlocks(messages: ChatCompletionMessageParam[
85
70
  export declare function transformMessagesForExplicitCache(messages: ChatCompletionMessageParam[], capabilities?: ModelCapabilities): ChatCompletionMessageParam[];
86
71
  /**
87
72
  * Extends standard usage with cache metrics
88
- * Extracts cache tokens from both Claude-specific top-level fields and
89
- * OpenAI-standard prompt_tokens_details (used by Gemini, DeepSeek, etc.)
90
- * @param standardUsage - OpenAI usage response
91
- * @param cacheMetrics - Additional cache metrics from the API response
73
+ * Extracts cache tokens from OpenAI-standard prompt_tokens_details
74
+ * (cached_tokens and the gateway-provided cache_creation_input_tokens)
75
+ * @param usage - OpenAI usage response
92
76
  * @returns Extended usage with cache information
93
77
  */
94
- export declare function extendUsageWithCacheMetrics(standardUsage: CompletionUsage, cacheMetrics?: Partial<ClaudeUsage>): ClaudeUsage;
95
- /**
96
- * Validates Claude usage structure
97
- * @param usage - Usage object to validate
98
- * @returns True if usage structure is valid
99
- */
100
- export declare function isValidClaudeUsage(usage: unknown): usage is ClaudeUsage;
78
+ export declare function extendUsageWithCacheMetrics(usage: CompletionUsage): Usage;
@@ -207,84 +207,23 @@ export function transformMessagesForExplicitCache(messages, capabilities) {
207
207
  }
208
208
  /**
209
209
  * Extends standard usage with cache metrics
210
- * Extracts cache tokens from both Claude-specific top-level fields and
211
- * OpenAI-standard prompt_tokens_details (used by Gemini, DeepSeek, etc.)
212
- * @param standardUsage - OpenAI usage response
213
- * @param cacheMetrics - Additional cache metrics from the API response
210
+ * Extracts cache tokens from OpenAI-standard prompt_tokens_details
211
+ * (cached_tokens and the gateway-provided cache_creation_input_tokens)
212
+ * @param usage - OpenAI usage response
214
213
  * @returns Extended usage with cache information
215
214
  */
216
- export function extendUsageWithCacheMetrics(standardUsage, cacheMetrics) {
215
+ export function extendUsageWithCacheMetrics(usage) {
217
216
  const baseUsage = {
218
- prompt_tokens: standardUsage.prompt_tokens,
219
- completion_tokens: standardUsage.completion_tokens,
220
- total_tokens: standardUsage.total_tokens,
217
+ prompt_tokens: usage.prompt_tokens,
218
+ completion_tokens: usage.completion_tokens,
219
+ total_tokens: usage.total_tokens,
221
220
  };
222
- if (!cacheMetrics) {
223
- return baseUsage;
221
+ const details = usage.prompt_tokens_details;
222
+ if (details?.cached_tokens != null) {
223
+ baseUsage.cache_read_input_tokens = details.cached_tokens;
224
224
  }
225
- // Extract cache_read_input_tokens from Claude top-level field
226
- if (typeof cacheMetrics.cache_read_input_tokens === "number") {
227
- baseUsage.cache_read_input_tokens = cacheMetrics.cache_read_input_tokens;
228
- }
229
- // Fallback to prompt_tokens_details.cached_tokens (OpenAI standard)
230
- else if (cacheMetrics.prompt_tokens_details?.cached_tokens != null) {
231
- baseUsage.cache_read_input_tokens =
232
- cacheMetrics.prompt_tokens_details.cached_tokens;
233
- }
234
- // Extract cache_creation_input_tokens from Claude top-level field
235
- if (typeof cacheMetrics.cache_creation_input_tokens === "number") {
236
- baseUsage.cache_creation_input_tokens =
237
- cacheMetrics.cache_creation_input_tokens;
238
- }
239
- // Fallback to prompt_tokens_details.cache_creation_input_tokens
240
- else if (cacheMetrics.prompt_tokens_details?.cache_creation_input_tokens != null) {
241
- baseUsage.cache_creation_input_tokens =
242
- cacheMetrics.prompt_tokens_details.cache_creation_input_tokens;
243
- }
244
- // Extract cache_creation breakdown (Claude-specific)
245
- if (cacheMetrics.cache_creation &&
246
- typeof cacheMetrics.cache_creation.ephemeral_5m_input_tokens === "number" &&
247
- typeof cacheMetrics.cache_creation.ephemeral_1h_input_tokens === "number") {
248
- baseUsage.cache_creation = {
249
- ephemeral_5m_input_tokens: cacheMetrics.cache_creation.ephemeral_5m_input_tokens,
250
- ephemeral_1h_input_tokens: cacheMetrics.cache_creation.ephemeral_1h_input_tokens,
251
- };
225
+ if (details?.cache_creation_input_tokens != null) {
226
+ baseUsage.cache_creation_input_tokens = details.cache_creation_input_tokens;
252
227
  }
253
228
  return baseUsage;
254
229
  }
255
- /**
256
- * Validates Claude usage structure
257
- * @param usage - Usage object to validate
258
- * @returns True if usage structure is valid
259
- */
260
- export function isValidClaudeUsage(usage) {
261
- if (!usage || typeof usage !== "object") {
262
- return false;
263
- }
264
- const usageObj = usage;
265
- // Check required standard fields
266
- const hasStandardFields = typeof usageObj.prompt_tokens === "number" &&
267
- typeof usageObj.completion_tokens === "number" &&
268
- typeof usageObj.total_tokens === "number";
269
- if (!hasStandardFields) {
270
- return false;
271
- }
272
- // Check optional cache fields
273
- const hasCacheFields = (usageObj.cache_read_input_tokens === undefined ||
274
- typeof usageObj.cache_read_input_tokens === "number") &&
275
- (usageObj.cache_creation_input_tokens === undefined ||
276
- typeof usageObj.cache_creation_input_tokens === "number");
277
- if (!hasCacheFields) {
278
- return false;
279
- }
280
- // Check cache_creation object if present
281
- if (usageObj.cache_creation !== undefined) {
282
- const cacheCreation = usageObj.cache_creation;
283
- if (typeof cacheCreation !== "object" ||
284
- typeof cacheCreation.ephemeral_5m_input_tokens !== "number" ||
285
- typeof cacheCreation.ephemeral_1h_input_tokens !== "number") {
286
- return false;
287
- }
288
- }
289
- return true;
290
- }
@@ -20,7 +20,6 @@ import { WorkflowManager } from "../managers/workflowManager.js";
20
20
  import { MemoryRuleManager } from "../managers/MemoryRuleManager.js";
21
21
  import { ReversionManager } from "../managers/reversionManager.js";
22
22
  import { SubagentManager } from "../managers/subagentManager.js";
23
- import { ForkedAgentManager } from "../managers/forkedAgentManager.js";
24
23
  import { LiveConfigManager } from "../managers/liveConfigManager.js";
25
24
  import { ReversionService } from "../services/reversionService.js";
26
25
  import { cleanupMetaOnlySessions } from "../services/session.js";
@@ -245,8 +244,6 @@ export function setupAgentContainer(setupOptions) {
245
244
  stream,
246
245
  });
247
246
  container.register("SubagentManager", subagentManager);
248
- const forkedAgentManager = new ForkedAgentManager(container);
249
- container.register("ForkedAgentManager", forkedAgentManager);
250
247
  const aiManager = new AIManager(container, {
251
248
  callbacks: {
252
249
  ...callbacks,
@@ -132,5 +132,6 @@ export interface AddNotificationMessageParams {
132
132
  status: "completed" | "failed" | "killed" | "aborted";
133
133
  summary: string;
134
134
  outputFile?: string;
135
+ result?: string;
135
136
  }
136
- export declare const addNotificationMessageToMessages: ({ messages, taskId, taskType, status, summary, outputFile, }: AddNotificationMessageParams) => Message[];
137
+ export declare const addNotificationMessageToMessages: ({ messages, taskId, taskType, status, summary, outputFile, result, }: AddNotificationMessageParams) => Message[];