@getpaseo/server 0.1.101 → 0.1.102

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 (141) hide show
  1. package/.env.example +8 -0
  2. package/dist/scripts/supervisor.js +26 -8
  3. package/dist/server/server/agent/activity-curator.d.ts +17 -0
  4. package/dist/server/server/agent/activity-curator.js +101 -24
  5. package/dist/server/server/agent/agent-manager.js +5 -1
  6. package/dist/server/server/agent/agent-sdk-types.d.ts +7 -2
  7. package/dist/server/server/agent/provider-registry.js +12 -11
  8. package/dist/server/server/agent/provider-snapshot-manager.d.ts +8 -1
  9. package/dist/server/server/agent/provider-snapshot-manager.js +78 -33
  10. package/dist/server/server/agent/providers/acp-agent.d.ts +13 -0
  11. package/dist/server/server/agent/providers/acp-agent.js +37 -1
  12. package/dist/server/server/agent/providers/claude/agent.js +51 -14
  13. package/dist/server/server/agent/providers/claude/query.d.ts +3 -0
  14. package/dist/server/server/agent/providers/claude/query.js +4 -2
  15. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +2 -1
  16. package/dist/server/server/agent/providers/generic-acp-agent.js +2 -1
  17. package/dist/server/server/agent/providers/kiro-acp-agent.d.ts +17 -0
  18. package/dist/server/server/agent/providers/kiro-acp-agent.js +78 -0
  19. package/dist/server/server/agent/providers/mock-load-test-agent.js +8 -0
  20. package/dist/server/server/agent/providers/opencode/paths.d.ts +2 -0
  21. package/dist/server/server/agent/providers/opencode/paths.js +7 -0
  22. package/dist/server/server/agent/providers/opencode/server-manager.d.ts +2 -0
  23. package/dist/server/server/agent/providers/opencode/server-manager.js +34 -5
  24. package/dist/server/server/agent/providers/opencode-agent.d.ts +4 -0
  25. package/dist/server/server/agent/providers/opencode-agent.js +14 -2
  26. package/dist/server/server/agent/providers/pi/agent.d.ts +3 -0
  27. package/dist/server/server/agent/providers/pi/agent.js +9 -3
  28. package/dist/server/server/agent/providers/provider-image-output.js +11 -6
  29. package/dist/server/server/agent/tools/paseo-tools.d.ts +1 -1
  30. package/dist/server/server/agent/tools/paseo-tools.js +0 -2
  31. package/dist/server/server/bootstrap.d.ts +7 -1
  32. package/dist/server/server/bootstrap.js +18 -0
  33. package/dist/server/server/config.d.ts +2 -0
  34. package/dist/server/server/config.js +57 -1
  35. package/dist/server/server/daemon-worker.js +19 -7
  36. package/dist/server/server/lifecycle-reasons.d.ts +4 -0
  37. package/dist/server/server/lifecycle-reasons.js +6 -0
  38. package/dist/server/server/persisted-config.d.ts +13 -2
  39. package/dist/server/server/persisted-config.js +30 -11
  40. package/dist/server/server/process-diagnostics.d.ts +17 -0
  41. package/dist/server/server/process-diagnostics.js +22 -0
  42. package/dist/server/server/relay-transport.js +1 -0
  43. package/dist/server/server/resolve-worktree-creation-intent.js +3 -1
  44. package/dist/server/server/session/daemon/daemon-self-update-session-controller.d.ts +32 -0
  45. package/dist/server/server/session/daemon/daemon-self-update-session-controller.js +88 -0
  46. package/dist/server/server/session/daemon/daemon-self-updater.d.ts +32 -0
  47. package/dist/server/server/session/daemon/daemon-self-updater.js +56 -0
  48. package/dist/server/server/session/daemon/daemon-session.d.ts +12 -0
  49. package/dist/server/server/session/daemon/daemon-session.js +12 -0
  50. package/dist/server/server/session/daemon/diagnostics.js +10 -0
  51. package/dist/server/server/session/daemon/install-origin.d.ts +7 -0
  52. package/dist/server/server/session/daemon/install-origin.js +64 -0
  53. package/dist/server/server/session/daemon/npm-global-cli.d.ts +29 -0
  54. package/dist/server/server/session/daemon/npm-global-cli.js +98 -0
  55. package/dist/server/server/session/provider/provider-catalog-session.js +8 -4
  56. package/dist/server/server/session.d.ts +5 -3
  57. package/dist/server/server/session.js +74 -32
  58. package/dist/server/server/speech/providers/openai/config.d.ts +0 -2
  59. package/dist/server/server/speech/providers/openai/config.js +71 -34
  60. package/dist/server/server/speech/providers/openai/runtime.js +4 -4
  61. package/dist/server/server/web-ui.d.ts +10 -0
  62. package/dist/server/server/web-ui.js +205 -0
  63. package/dist/server/server/websocket/runtime-metrics.d.ts +3 -0
  64. package/dist/server/server/websocket-server.d.ts +3 -0
  65. package/dist/server/server/websocket-server.js +190 -32
  66. package/dist/server/services/quota-fetcher/manifest.js +5 -0
  67. package/dist/server/services/quota-fetcher/providers/minimax.d.ts +29 -0
  68. package/dist/server/services/quota-fetcher/providers/minimax.js +227 -0
  69. package/dist/server/terminal/agent-hooks/agent-hook-installer.js +2 -2
  70. package/dist/server/utils/checkout-git.js +156 -3
  71. package/dist/server/utils/directory-suggestions.js +1 -4
  72. package/dist/server/utils/path.d.ts +2 -0
  73. package/dist/server/utils/path.js +13 -0
  74. package/dist/server/utils/worktree.d.ts +1 -0
  75. package/dist/server/utils/worktree.js +92 -11
  76. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css +1 -0
  77. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.br +0 -0
  78. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.gz +0 -0
  79. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5fa9347afb28c7d61bbf73684f3bdafa.js +1 -0
  80. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5fa9347afb28c7d61bbf73684f3bdafa.js.br +0 -0
  81. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5fa9347afb28c7d61bbf73684f3bdafa.js.gz +0 -0
  82. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-35159ed50cf218b741c5dab5a6f4a889.js +1 -0
  83. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-35159ed50cf218b741c5dab5a6f4a889.js.br +0 -0
  84. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-35159ed50cf218b741c5dab5a6f4a889.js.gz +0 -0
  85. package/dist/server/web-ui/_expo/static/js/web/index-cf63ba3f4de4164d2d9c3738e1b791b2.js +16157 -0
  86. package/dist/server/web-ui/_expo/static/js/web/index-cf63ba3f4de4164d2d9c3738e1b791b2.js.br +0 -0
  87. package/dist/server/web-ui/_expo/static/js/web/index-cf63ba3f4de4164d2d9c3738e1b791b2.js.gz +0 -0
  88. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-6a6cfdd9f06d4fd2b05adc1a8771c58c.js +1 -0
  89. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-6a6cfdd9f06d4fd2b05adc1a8771c58c.js.br +0 -0
  90. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-6a6cfdd9f06d4fd2b05adc1a8771c58c.js.gz +0 -0
  91. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b31888f9a7de4f0c52d6a58fcddbcb20.js +3 -0
  92. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b31888f9a7de4f0c52d6a58fcddbcb20.js.br +0 -0
  93. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b31888f9a7de4f0c52d6a58fcddbcb20.js.gz +0 -0
  94. package/dist/server/web-ui/apple-touch-icon.png +0 -0
  95. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png +0 -0
  96. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png +0 -0
  97. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png +0 -0
  98. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png +0 -0
  99. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png +0 -0
  100. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png +0 -0
  101. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png +0 -0
  102. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png +0 -0
  103. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png +0 -0
  104. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png +0 -0
  105. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png +0 -0
  106. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png +0 -0
  107. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png +0 -0
  108. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png +0 -0
  109. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png +0 -0
  110. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png +0 -0
  111. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png +0 -0
  112. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png +0 -0
  113. package/dist/server/web-ui/assets/assets/images/editor-apps/antigravity.6e91a685c33435e0b466a56db86cf141.png +0 -0
  114. package/dist/server/web-ui/assets/assets/images/editor-apps/cursor.c31d6bce4fe9aadc3fe59962f4c4fcf3.png +0 -0
  115. package/dist/server/web-ui/assets/assets/images/editor-apps/file-explorer.3e15e8f72c825c85ce336bcb0cdef776.png +0 -0
  116. package/dist/server/web-ui/assets/assets/images/editor-apps/finder.7f68fc2c475621a672e1be09309d5567.png +0 -0
  117. package/dist/server/web-ui/assets/assets/images/editor-apps/vscode.832bdb4c685d930f1c864c793703600b.png +0 -0
  118. package/dist/server/web-ui/assets/assets/images/editor-apps/webstorm.aa5dc2cd8c20cc0a155c4c5c5ab3c5f5.png +0 -0
  119. package/dist/server/web-ui/assets/assets/images/editor-apps/zed.f3a670b7f9aa226da4fe53fb86f1abbd.png +0 -0
  120. package/dist/server/web-ui/assets/assets/images/favicon-dark-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
  121. package/dist/server/web-ui/assets/assets/images/favicon-dark-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
  122. package/dist/server/web-ui/assets/assets/images/favicon-dark.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
  123. package/dist/server/web-ui/assets/assets/images/favicon-light-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
  124. package/dist/server/web-ui/assets/assets/images/favicon-light-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
  125. package/dist/server/web-ui/assets/assets/images/favicon-light.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
  126. package/dist/server/web-ui/assets/assets/images/notification-icon.3bf81d33ddbf380606bdd248ba83e158.png +0 -0
  127. package/dist/server/web-ui/favicon.ico +0 -0
  128. package/dist/server/web-ui/index.html +90 -0
  129. package/dist/server/web-ui/index.html.br +0 -0
  130. package/dist/server/web-ui/index.html.gz +0 -0
  131. package/dist/server/web-ui/manifest.json +27 -0
  132. package/dist/server/web-ui/manifest.json.br +0 -0
  133. package/dist/server/web-ui/manifest.json.gz +0 -0
  134. package/dist/server/web-ui/metadata.json +1 -0
  135. package/dist/server/web-ui/metadata.json.br +1 -0
  136. package/dist/server/web-ui/metadata.json.gz +0 -0
  137. package/dist/server/web-ui/pwa-icon-192.png +0 -0
  138. package/dist/server/web-ui/pwa-icon-512.png +0 -0
  139. package/dist/server/web-ui/robots.txt +2 -0
  140. package/dist/src/server/persisted-config.js +30 -11
  141. package/package.json +7 -7
@@ -16,6 +16,7 @@ export declare function createLoggedNdJsonStream(output: NodeWritableStream, inp
16
16
  logger: Logger;
17
17
  provider: string;
18
18
  }): ACPStream;
19
+ export type ACPExtensionCommandsParser = (method: string, params: Record<string, unknown>) => AgentSlashCommand[] | null;
19
20
  interface ACPAgentClientOptions {
20
21
  provider: string;
21
22
  logger: Logger;
@@ -32,6 +33,7 @@ interface ACPAgentClientOptions {
32
33
  beforeModeWriter?: (context: ACPProviderModeWriterContext) => Promise<ACPBeforeModeWriteResult>;
33
34
  thinkingOptionWriter?: (connection: ClientSideConnection, sessionId: string, thinkingOptionId: string) => Promise<void>;
34
35
  capabilities?: AgentCapabilityFlags;
36
+ extensionCommandsParser?: ACPExtensionCommandsParser;
35
37
  waitForInitialCommands?: boolean;
36
38
  initialCommandsWaitTimeoutMs?: number;
37
39
  terminateProcess?: ProcessTerminator;
@@ -52,6 +54,7 @@ interface ACPAgentSessionOptions {
52
54
  beforeModeWriter?: (context: ACPProviderModeWriterContext) => Promise<ACPBeforeModeWriteResult>;
53
55
  thinkingOptionWriter?: (connection: ClientSideConnection, sessionId: string, thinkingOptionId: string) => Promise<void>;
54
56
  capabilities: AgentCapabilityFlags;
57
+ extensionCommandsParser?: ACPExtensionCommandsParser;
55
58
  handle?: AgentPersistenceHandle;
56
59
  agentId?: string;
57
60
  launchEnv?: Record<string, string>;
@@ -177,6 +180,7 @@ export declare class ACPAgentClient implements AgentClient {
177
180
  private readonly thinkingOptionWriter?;
178
181
  private readonly waitForInitialCommands;
179
182
  private readonly initialCommandsWaitTimeoutMs;
183
+ private readonly extensionCommandsParser?;
180
184
  protected readonly terminateProcess: ProcessTerminator;
181
185
  constructor(options: ACPAgentClientOptions);
182
186
  createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext): Promise<AgentSession>;
@@ -251,6 +255,7 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
251
255
  private commandsReadySettled;
252
256
  private waitForInitialCommands;
253
257
  private initialCommandsWaitTimeoutMs;
258
+ private readonly extensionCommandsParser?;
254
259
  private currentTurnUsage;
255
260
  private activeForegroundTurnId;
256
261
  private closed;
@@ -261,6 +266,13 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
261
266
  constructor(config: AgentSessionConfig, options: ACPAgentSessionOptions);
262
267
  get id(): string | null;
263
268
  initializeNewSession(): Promise<void>;
269
+ /**
270
+ * IMPORTANT: Some ACP providers (e.g., Devin CLI) require all three params
271
+ * (sessionId, cwd, mcpServers) to be present in session/load or
272
+ * unstable_resumeSession — even when mcpServers is an empty array — and
273
+ * return "Invalid params" if any are omitted. Never drop cwd or mcpServers
274
+ * from these calls regardless of capabilities.
275
+ */
264
276
  initializeResumedSession(): Promise<void>;
265
277
  run(prompt: AgentPromptInput, options?: AgentRunOptions): Promise<AgentRunResult>;
266
278
  startTurn(prompt: AgentPromptInput, options?: AgentRunOptions): Promise<{
@@ -292,6 +304,7 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
292
304
  requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse>;
293
305
  sessionUpdate(params: SessionNotification): Promise<void>;
294
306
  extNotification(method: string, params: Record<string, unknown>): Promise<void>;
307
+ private applyResolvedCommands;
295
308
  readTextFile(params: ReadTextFileRequest): Promise<{
296
309
  content: string;
297
310
  }>;
@@ -318,6 +318,7 @@ export class ACPAgentClient {
318
318
  this.thinkingOptionWriter = options.thinkingOptionWriter;
319
319
  this.waitForInitialCommands = options.waitForInitialCommands ?? false;
320
320
  this.initialCommandsWaitTimeoutMs = options.initialCommandsWaitTimeoutMs ?? 1500;
321
+ this.extensionCommandsParser = options.extensionCommandsParser;
321
322
  }
322
323
  async createSession(config, launchContext) {
323
324
  this.assertProvider(config);
@@ -339,6 +340,7 @@ export class ACPAgentClient {
339
340
  capabilities: this.capabilities,
340
341
  agentId: launchContext?.agentId,
341
342
  launchEnv: launchContext?.env,
343
+ extensionCommandsParser: this.extensionCommandsParser,
342
344
  waitForInitialCommands: this.waitForInitialCommands,
343
345
  initialCommandsWaitTimeoutMs: this.initialCommandsWaitTimeoutMs,
344
346
  });
@@ -379,6 +381,7 @@ export class ACPAgentClient {
379
381
  handle,
380
382
  agentId: launchContext?.agentId,
381
383
  launchEnv: launchContext?.env,
384
+ extensionCommandsParser: this.extensionCommandsParser,
382
385
  waitForInitialCommands: this.waitForInitialCommands,
383
386
  initialCommandsWaitTimeoutMs: this.initialCommandsWaitTimeoutMs,
384
387
  });
@@ -386,7 +389,7 @@ export class ACPAgentClient {
386
389
  return session;
387
390
  }
388
391
  async fetchCatalog(options) {
389
- const { cwd } = options;
392
+ const cwd = options.scope === "global" ? homedir() : options.cwd;
390
393
  const timeoutMs = options.timeoutMs ?? ACP_CATALOG_TIMEOUT_MS;
391
394
  let probe = null;
392
395
  try {
@@ -784,6 +787,7 @@ export class ACPAgentSession {
784
787
  this.currentTitle = config.title ?? null;
785
788
  this.waitForInitialCommands = options.waitForInitialCommands ?? false;
786
789
  this.initialCommandsWaitTimeoutMs = options.initialCommandsWaitTimeoutMs ?? 1500;
790
+ this.extensionCommandsParser = options.extensionCommandsParser;
787
791
  }
788
792
  get id() {
789
793
  return this.sessionId;
@@ -802,6 +806,13 @@ export class ACPAgentSession {
802
806
  this.applySessionState(response);
803
807
  await this.applyConfiguredOverrides();
804
808
  }
809
+ /**
810
+ * IMPORTANT: Some ACP providers (e.g., Devin CLI) require all three params
811
+ * (sessionId, cwd, mcpServers) to be present in session/load or
812
+ * unstable_resumeSession — even when mcpServers is an empty array — and
813
+ * return "Invalid params" if any are omitted. Never drop cwd or mcpServers
814
+ * from these calls regardless of capabilities.
815
+ */
805
816
  async initializeResumedSession() {
806
817
  const handle = this.initialHandle;
807
818
  if (!handle) {
@@ -1408,6 +1419,31 @@ export class ACPAgentSession {
1408
1419
  method,
1409
1420
  rawEvent: params,
1410
1421
  }, "provider.acp.extension_notification");
1422
+ const parsedCommands = this.extensionCommandsParser?.(method, params);
1423
+ if (parsedCommands) {
1424
+ this.applyResolvedCommands(parsedCommands, {
1425
+ sessionId: typeof params.sessionId === "string" ? params.sessionId : undefined,
1426
+ });
1427
+ }
1428
+ }
1429
+ // Cache an asynchronously-delivered slash-command batch and unblock any
1430
+ // listCommands() call that is waiting on the initial batch. Used when a
1431
+ // provider supplies an extensionCommandsParser whose result arrives after
1432
+ // session/new (e.g. via a vendor extension notification). The ready gate is
1433
+ // always settled — even for an empty batch — so a provider that legitimately
1434
+ // reports no commands does not leave listCommands() blocked for the full
1435
+ // initial-commands timeout. An optional sessionId scopes the batch to this
1436
+ // session; notifications addressed to a different session are ignored.
1437
+ applyResolvedCommands(commands, options) {
1438
+ if (options?.sessionId !== undefined &&
1439
+ this.sessionId !== null &&
1440
+ options.sessionId !== this.sessionId) {
1441
+ return;
1442
+ }
1443
+ if (commands.length > 0) {
1444
+ this.cachedCommands = commands;
1445
+ }
1446
+ this.settleCommandsReady();
1411
1447
  }
1412
1448
  async readTextFile(params) {
1413
1449
  const raw = await fs.readFile(params.path, "utf8");
@@ -22,6 +22,7 @@ import { getAgentStreamEventTurnId, } from "../../agent-sdk-types.js";
22
22
  import { importSessionFromPersistence } from "../../provider-session-import.js";
23
23
  import { checkProviderLaunchAvailable, createProviderEnv, createProviderEnvSpec, resolveProviderLaunch, } from "../../provider-launch-config.js";
24
24
  import { withTimeout } from "../../../../utils/promise-timeout.js";
25
+ import { terminateWithTreeKill } from "../../../../utils/tree-kill.js";
25
26
  import { execCommand } from "../../../../utils/spawn.js";
26
27
  import { composeSystemPromptParts } from "../../system-prompt.js";
27
28
  const fsPromises = promises;
@@ -1289,6 +1290,13 @@ function readLegacyResultUsageTokens(usage) {
1289
1290
  function isClaudeSubagentToolName(name) {
1290
1291
  return name === "Task" || name === "Agent";
1291
1292
  }
1293
+ function readClaudeParentToolUseId(message) {
1294
+ if (!("parent_tool_use_id" in message)) {
1295
+ return null;
1296
+ }
1297
+ const parentToolUseId = message.parent_tool_use_id;
1298
+ return typeof parentToolUseId === "string" && parentToolUseId.length > 0 ? parentToolUseId : null;
1299
+ }
1292
1300
  class ClaudeContextUsageState {
1293
1301
  constructor(initialContextWindowMaxTokens) {
1294
1302
  this.completedResultTurns = 0;
@@ -1414,6 +1422,7 @@ class ClaudeAgentSession {
1414
1422
  this.provider = "claude";
1415
1423
  this.capabilities = CLAUDE_CAPABILITIES;
1416
1424
  this.query = null;
1425
+ this.childProcess = null;
1417
1426
  this.input = null;
1418
1427
  this.planResumeMode = null;
1419
1428
  this.availableModes = DEFAULT_MODES;
@@ -1887,6 +1896,19 @@ class ClaudeAgentSession {
1887
1896
  await this.awaitWithTimeout(this.query?.return?.(), "close query return");
1888
1897
  this.query = null;
1889
1898
  this.input = null;
1899
+ // Terminate the entire process tree (claude + MCP children) to prevent
1900
+ // orphan accumulation. The SDK's internal cleanup may only kill the
1901
+ // direct child process.
1902
+ if (this.childProcess) {
1903
+ const result = await terminateWithTreeKill(this.childProcess, {
1904
+ gracefulTimeoutMs: 2000,
1905
+ forceTimeoutMs: 2000,
1906
+ });
1907
+ if (result === "kill-timeout") {
1908
+ this.logger.warn({ pid: this.childProcess.pid, agentId: this.agentId }, "Claude process tree did not report exit after SIGKILL");
1909
+ }
1910
+ this.childProcess = null;
1911
+ }
1890
1912
  if (this.persistSession === false && this.claudeSessionId) {
1891
1913
  // Claude Code currently ignores --no-session-persistence outside --print mode
1892
1914
  // (see `claude --help`), so the SDK's persistSession=false is silently dropped
@@ -2225,6 +2247,18 @@ class ClaudeAgentSession {
2225
2247
  catch {
2226
2248
  /* ignore */
2227
2249
  }
2250
+ // Tree-kill the old process tree now that the SDK has cleaned up.
2251
+ // If we skip this, MCP children of the previous claude process can
2252
+ // survive as orphans when the session spawns a replacement query.
2253
+ if (this.childProcess) {
2254
+ await terminateWithTreeKill(this.childProcess, {
2255
+ gracefulTimeoutMs: 2000,
2256
+ forceTimeoutMs: 2000,
2257
+ }).catch(() => {
2258
+ /* process may already be dead */
2259
+ });
2260
+ this.childProcess = null;
2261
+ }
2228
2262
  }
2229
2263
  // Preserve claudeSessionId across query recreation so buildOptions() passes
2230
2264
  // resume: sessionId and the new query continues the existing conversation.
@@ -2237,6 +2271,9 @@ class ClaudeAgentSession {
2237
2271
  runtimeSettings: this.runtimeSettings,
2238
2272
  launchEnv: this.launchEnv,
2239
2273
  queryFactory: this.queryFactory,
2274
+ onChildProcess: (child) => {
2275
+ this.childProcess = child;
2276
+ },
2240
2277
  });
2241
2278
  const fastMode = this.resolveFastModeSetting();
2242
2279
  if (fastMode !== null) {
@@ -2809,17 +2846,19 @@ class ClaudeAgentSession {
2809
2846
  suppressAssistantText: true,
2810
2847
  suppressReasoning: true,
2811
2848
  });
2812
- const assistantTimelineEvents = this.timelineAssembler
2813
- .consume({
2814
- message,
2815
- runId: turnId,
2816
- messageIdHint,
2817
- })
2818
- .map((item) => ({
2819
- type: "timeline",
2820
- item,
2821
- provider: "claude",
2822
- }));
2849
+ const assistantTimelineEvents = readClaudeParentToolUseId(message)
2850
+ ? []
2851
+ : this.timelineAssembler
2852
+ .consume({
2853
+ message,
2854
+ runId: turnId,
2855
+ messageIdHint,
2856
+ })
2857
+ .map((item) => ({
2858
+ type: "timeline",
2859
+ item,
2860
+ provider: "claude",
2861
+ }));
2823
2862
  return [...messageEvents, ...assistantTimelineEvents];
2824
2863
  }
2825
2864
  async handleMissingResumedConversation(message, activeQuery) {
@@ -2867,9 +2906,7 @@ class ClaudeAgentSession {
2867
2906
  }
2868
2907
  }
2869
2908
  translateMessageToEvents(message, options) {
2870
- const parentToolUseId = "parent_tool_use_id" in message
2871
- ? message.parent_tool_use_id
2872
- : null;
2909
+ const parentToolUseId = readClaudeParentToolUseId(message);
2873
2910
  if (parentToolUseId) {
2874
2911
  return this.sidechainTracker.handleMessage(message, parentToolUseId);
2875
2912
  }
@@ -1,3 +1,4 @@
1
+ import { type ChildProcess } from "node:child_process";
1
2
  import { query, type Options, type Query } from "@anthropic-ai/claude-agent-sdk";
2
3
  import { type ProviderRuntimeSettings } from "../../provider-launch-config.js";
3
4
  export type ClaudeOptions = Options;
@@ -9,6 +10,8 @@ export interface ClaudeQueryContext {
9
10
  runtimeSettings?: ProviderRuntimeSettings;
10
11
  launchEnv?: Record<string, string>;
11
12
  queryFactory?: ClaudeQueryFactory;
13
+ /** Called with the spawned child process so the caller can tree-kill it on close. */
14
+ onChildProcess?: (child: ChildProcess) => void;
12
15
  }
13
16
  export declare function claudeQuery(input: ClaudeQueryInput, context?: ClaudeQueryContext): Query;
14
17
  //# sourceMappingURL=query.d.ts.map
@@ -24,7 +24,8 @@ function resolveClaudeSpawnCommand(spawnOptions, runtimeSettings) {
24
24
  args: [...commandConfig.argv.slice(1), ...spawnOptions.args],
25
25
  };
26
26
  }
27
- function applyRuntimeSettingsToClaudeOptions(options, runtimeSettings, launchEnv) {
27
+ function applyRuntimeSettingsToClaudeOptions(options, context) {
28
+ const { runtimeSettings, launchEnv, onChildProcess } = context;
28
29
  return {
29
30
  ...options,
30
31
  spawnClaudeCodeProcess: (spawnOptions) => {
@@ -62,6 +63,7 @@ function applyRuntimeSettingsToClaudeOptions(options, runtimeSettings, launchEnv
62
63
  // The command is always a resolved binary path, so shell routing is unnecessary.
63
64
  shell: false,
64
65
  });
66
+ onChildProcess?.(child);
65
67
  if (typeof options.stderr === "function") {
66
68
  child.stderr?.on("data", (chunk) => {
67
69
  options.stderr?.(chunk.toString());
@@ -78,7 +80,7 @@ export function claudeQuery(input, context = {}) {
78
80
  const launchQuery = context.queryFactory ?? query;
79
81
  return launchQuery({
80
82
  ...input,
81
- options: applyRuntimeSettingsToClaudeOptions(input.options, context.runtimeSettings, context.launchEnv),
83
+ options: applyRuntimeSettingsToClaudeOptions(input.options, context),
82
84
  });
83
85
  }
84
86
  //# sourceMappingURL=query.js.map
@@ -1,6 +1,6 @@
1
1
  import type { Logger } from "pino";
2
2
  import { z } from "zod";
3
- import { ACPAgentClient } from "./acp-agent.js";
3
+ import { ACPAgentClient, type ACPExtensionCommandsParser } from "./acp-agent.js";
4
4
  export declare const GenericACPProviderParamsSchema: z.ZodObject<{
5
5
  supportsMcpServers: z.ZodOptional<z.ZodBoolean>;
6
6
  }, z.core.$loose>;
@@ -14,6 +14,7 @@ interface GenericACPAgentClientOptions {
14
14
  waitForInitialCommands?: boolean;
15
15
  initialCommandsWaitTimeoutMs?: number;
16
16
  diagnosticPhaseTimeoutMs?: number;
17
+ extensionCommandsParser?: ACPExtensionCommandsParser;
17
18
  }
18
19
  export declare class GenericACPAgentClient extends ACPAgentClient {
19
20
  private readonly command;
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { checkProviderLaunchAvailable, resolveProviderLaunch } from "../provider-launch-config.js";
3
- import { ACPAgentClient, DEFAULT_ACP_CAPABILITIES } from "./acp-agent.js";
3
+ import { ACPAgentClient, DEFAULT_ACP_CAPABILITIES, } from "./acp-agent.js";
4
4
  import { buildBinaryDiagnosticRows, formatProviderDiagnostic, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
5
5
  export const GenericACPProviderParamsSchema = z
6
6
  .object({
@@ -19,6 +19,7 @@ export class GenericACPAgentClient extends ACPAgentClient {
19
19
  capabilities: buildGenericACPCapabilities(options),
20
20
  waitForInitialCommands: options.waitForInitialCommands,
21
21
  initialCommandsWaitTimeoutMs: options.initialCommandsWaitTimeoutMs,
22
+ extensionCommandsParser: options.extensionCommandsParser,
22
23
  });
23
24
  this.command = options.command;
24
25
  this.providerId = options.providerId;
@@ -0,0 +1,17 @@
1
+ import type { Logger } from "pino";
2
+ import type { ACPExtensionCommandsParser } from "./acp-agent.js";
3
+ import { GenericACPAgentClient } from "./generic-acp-agent.js";
4
+ interface KiroACPAgentClientOptions {
5
+ logger: Logger;
6
+ command: [string, ...string[]];
7
+ env?: Record<string, string>;
8
+ providerId?: string;
9
+ label?: string;
10
+ providerParams?: unknown;
11
+ }
12
+ export declare const parseKiroExtensionCommands: ACPExtensionCommandsParser;
13
+ export declare class KiroACPAgentClient extends GenericACPAgentClient {
14
+ constructor(options: KiroACPAgentClientOptions);
15
+ }
16
+ export {};
17
+ //# sourceMappingURL=kiro-acp-agent.d.ts.map
@@ -0,0 +1,78 @@
1
+ import { GenericACPAgentClient } from "./generic-acp-agent.js";
2
+ // Kiro CLI publishes its slash commands and skills asynchronously through the
3
+ // `_kiro.dev/commands/available` extension notification shortly after
4
+ // `session/new` resolves. Wait for that first batch so listCommands() doesn't
5
+ // resolve to an empty list before Kiro has reported its commands.
6
+ const KIRO_INITIAL_COMMANDS_WAIT_TIMEOUT_MS = 10000;
7
+ // ACP extension method (per the `_`-prefixed vendor namespace convention) that
8
+ // Kiro CLI uses to publish its slash commands and skills after session/new.
9
+ const KIRO_COMMANDS_AVAILABLE_METHOD = "_kiro.dev/commands/available";
10
+ function isRecord(value) {
11
+ return value != null && typeof value === "object" && !Array.isArray(value);
12
+ }
13
+ // Maps a `_kiro.dev/commands/available` payload onto Paseo slash commands.
14
+ // Kiro reports built-in slash commands under `commands` (names arrive with a
15
+ // leading "/", e.g. "/agent") and skills/prompts under `prompts` (names without
16
+ // a slash, tagged with a `skill:` serverName). Paseo stores command names
17
+ // without the leading slash — the composer prepends it on insertion.
18
+ function mapKiroAvailableCommands(params) {
19
+ const result = [];
20
+ const seen = new Set();
21
+ const pushEntry = (entry) => {
22
+ if (!isRecord(entry)) {
23
+ return;
24
+ }
25
+ const rawName = typeof entry.name === "string" ? entry.name.trim() : "";
26
+ const name = rawName.replace(/^\/+/, "");
27
+ if (!name || seen.has(name)) {
28
+ return;
29
+ }
30
+ seen.add(name);
31
+ const description = typeof entry.description === "string" ? entry.description : "";
32
+ const meta = isRecord(entry.meta) ? entry.meta : null;
33
+ const argumentHint = meta && typeof meta.hint === "string" ? meta.hint : "";
34
+ const serverName = typeof entry.serverName === "string" ? entry.serverName : "";
35
+ const kind = serverName.startsWith("skill:") ? "skill" : "command";
36
+ result.push({ name, description, argumentHint, kind });
37
+ };
38
+ if (Array.isArray(params.commands)) {
39
+ for (const entry of params.commands) {
40
+ pushEntry(entry);
41
+ }
42
+ }
43
+ if (Array.isArray(params.prompts)) {
44
+ for (const entry of params.prompts) {
45
+ pushEntry(entry);
46
+ }
47
+ }
48
+ return result;
49
+ }
50
+ // Provider-specific parser injected into the generic ACP session via the
51
+ // `extensionCommandsParser` option (mirrors how Cursor/Copilot inject their
52
+ // behavior through constructor options). Kiro advertises its slash commands and
53
+ // skills through the `_kiro.dev/commands/available` extension notification
54
+ // instead of the standard `available_commands_update` session update; this
55
+ // recognizes that one method and returns the parsed commands (possibly empty),
56
+ // or null for any other notification so the base session ignores it.
57
+ export const parseKiroExtensionCommands = (method, params) => {
58
+ if (method !== KIRO_COMMANDS_AVAILABLE_METHOD) {
59
+ return null;
60
+ }
61
+ return mapKiroAvailableCommands(params);
62
+ };
63
+ export class KiroACPAgentClient extends GenericACPAgentClient {
64
+ constructor(options) {
65
+ super({
66
+ logger: options.logger,
67
+ command: options.command,
68
+ env: options.env,
69
+ providerId: options.providerId,
70
+ label: options.label,
71
+ providerParams: options.providerParams,
72
+ waitForInitialCommands: true,
73
+ initialCommandsWaitTimeoutMs: KIRO_INITIAL_COMMANDS_WAIT_TIMEOUT_MS,
74
+ extensionCommandsParser: parseKiroExtensionCommands,
75
+ });
76
+ }
77
+ }
78
+ //# sourceMappingURL=kiro-acp-agent.js.map
@@ -439,12 +439,14 @@ export class MockLoadTestAgentSession {
439
439
  }
440
440
  const profile = resolveModelProfile(this.modelId);
441
441
  const turnId = randomUUID();
442
+ const assistantMessageId = randomUUID();
442
443
  let resolve;
443
444
  const completed = new Promise((promiseResolve) => {
444
445
  resolve = promiseResolve;
445
446
  });
446
447
  const turn = {
447
448
  turnId,
449
+ assistantMessageId,
448
450
  prompt,
449
451
  startedAt: Date.now(),
450
452
  cycle: 0,
@@ -655,6 +657,7 @@ export class MockLoadTestAgentSession {
655
657
  this.emitTimeline(turn.turnId, {
656
658
  type: "assistant_message",
657
659
  text: finalText,
660
+ messageId: turn.assistantMessageId,
658
661
  });
659
662
  this.activeTurn = null;
660
663
  this.emit({
@@ -669,6 +672,7 @@ export class MockLoadTestAgentSession {
669
672
  {
670
673
  type: "assistant_message",
671
674
  text: finalText,
675
+ messageId: turn.assistantMessageId,
672
676
  },
673
677
  ],
674
678
  canceled: false,
@@ -768,6 +772,7 @@ export class MockLoadTestAgentSession {
768
772
  ? {
769
773
  type: "assistant_message",
770
774
  text: `stress-update-${index}`,
775
+ messageId: turn.assistantMessageId,
771
776
  }
772
777
  : {
773
778
  type: "todo",
@@ -834,6 +839,7 @@ export class MockLoadTestAgentSession {
834
839
  this.emitTimeline(turn.turnId, {
835
840
  type: "assistant_message",
836
841
  text: `data:image/png;base64,${payload}`,
842
+ messageId: turn.assistantMessageId,
837
843
  });
838
844
  }
839
845
  this.activeTurn = null;
@@ -892,6 +898,7 @@ export class MockLoadTestAgentSession {
892
898
  this.emitTimeline(turn.turnId, {
893
899
  type: "assistant_message",
894
900
  text: event.text,
901
+ messageId: turn.assistantMessageId,
895
902
  });
896
903
  return;
897
904
  }
@@ -933,6 +940,7 @@ export class MockLoadTestAgentSession {
933
940
  this.emitTimeline(turn.turnId, {
934
941
  type: "assistant_message",
935
942
  text: "\n\n_(end of synthetic stream)_\n",
943
+ messageId: turn.assistantMessageId,
936
944
  });
937
945
  this.finishTurnWithText(turn, "Synthetic load test complete");
938
946
  }
@@ -0,0 +1,2 @@
1
+ export declare function resolveOpenCodeHomeDir(env?: NodeJS.ProcessEnv): string;
2
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1,7 @@
1
+ import path from "node:path";
2
+ import { resolvePaseoHome } from "../../../paseo-home.js";
3
+ const OPENCODE_HOME_DIRNAME = "opencode-home";
4
+ export function resolveOpenCodeHomeDir(env = process.env) {
5
+ return path.join(resolvePaseoHome(env), OPENCODE_HOME_DIRNAME);
6
+ }
7
+ //# sourceMappingURL=paths.js.map
@@ -46,6 +46,7 @@ export interface OpenCodeServerManagerOptions {
46
46
  terminateProcess?: ProcessTerminator;
47
47
  portAllocator?: OpenCodePortAllocator;
48
48
  resolveCommandPrefix?: OpenCodeCommandPrefixResolver;
49
+ resolveHomeDir?: () => string;
49
50
  spawnServerProcess?: OpenCodeServerProcessSpawner;
50
51
  }
51
52
  export declare class OpenCodeServerManager implements OpenCodeServerManagerLike {
@@ -62,6 +63,7 @@ export declare class OpenCodeServerManager implements OpenCodeServerManagerLike
62
63
  private readonly terminateProcess;
63
64
  private readonly portAllocator;
64
65
  private readonly resolveCommandPrefix;
66
+ private readonly resolveHomeDir;
65
67
  private readonly spawnServerProcess;
66
68
  constructor(options: OpenCodeServerManagerOptions);
67
69
  static getInstance(logger: Logger, runtimeSettings?: ProviderRuntimeSettings, options?: Omit<OpenCodeServerManagerOptions, "logger" | "runtimeSettings">): OpenCodeServerManager;
@@ -1,9 +1,12 @@
1
+ import { mkdirSync } from "node:fs";
2
+ import { stat } from "node:fs/promises";
1
3
  import net from "node:net";
2
- import os from "node:os";
4
+ import path from "node:path";
3
5
  import { findExecutable } from "../../../../executable-resolution/executable-resolution.js";
4
6
  import { spawnProcess } from "../../../../utils/spawn.js";
5
7
  import { terminateWithTreeKill } from "../../../../utils/tree-kill.js";
6
8
  import { createProviderEnvSpec, resolveProviderCommandPrefix, } from "../../provider-launch-config.js";
9
+ import { resolveOpenCodeHomeDir } from "./paths.js";
7
10
  const OPENCODE_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT_MS = 5000;
8
11
  const OPENCODE_SERVER_FORCE_SHUTDOWN_TIMEOUT_MS = 1000;
9
12
  export class OpenCodeServerManager {
@@ -21,6 +24,7 @@ export class OpenCodeServerManager {
21
24
  this.resolveCommandPrefix =
22
25
  options.resolveCommandPrefix ??
23
26
  (() => resolveProviderCommandPrefix(this.runtimeSettings?.command, resolveOpenCodeBinary));
27
+ this.resolveHomeDir = options.resolveHomeDir ?? resolveOpenCodeHomeDir;
24
28
  this.spawnServerProcess = options.spawnServerProcess ?? spawnProcess;
25
29
  }
26
30
  static getInstance(logger, runtimeSettings, options = {}) {
@@ -164,7 +168,11 @@ export class OpenCodeServerManager {
164
168
  const url = `http://127.0.0.1:${port}`;
165
169
  const launchPrefix = await this.resolveCommandPrefix();
166
170
  const serverArgs = [...launchPrefix.args, "serve", "--port", String(port)];
167
- const serverCwd = os.homedir();
171
+ // Use a neutral OpenCode home as the server cwd. Launching from the user's
172
+ // home directory causes OpenCode to treat it as the default workspace and
173
+ // index the entire home tree.
174
+ const serverCwd = this.resolveHomeDir();
175
+ mkdirSync(serverCwd, { recursive: true });
168
176
  const serverProcess = this.spawnServerProcess(launchPrefix.command, serverArgs, {
169
177
  cwd: serverCwd,
170
178
  detached: process.platform !== "win32",
@@ -371,10 +379,31 @@ OpenCodeServerManager.instance = null;
371
379
  OpenCodeServerManager.exitHandlerRegistered = false;
372
380
  async function resolveOpenCodeBinary() {
373
381
  const found = await findExecutable("opencode");
374
- if (found) {
375
- return found;
382
+ if (!found) {
383
+ throw new Error("OpenCode binary not found. Install OpenCode (https://github.com/opencode-ai/opencode) and ensure it is available in your shell PATH.");
384
+ }
385
+ if (process.platform === "win32" && path.extname(found).toLowerCase() === ".cmd") {
386
+ // Global npm: <prefix>/opencode.cmd → <prefix>/node_modules/opencode-ai/bin/opencode.exe
387
+ const globalCandidate = path.join(path.dirname(found), "node_modules", "opencode-ai", "bin", "opencode.exe");
388
+ if (await pathExists(globalCandidate))
389
+ return globalCandidate;
390
+ // Local/pnpm: <project>/node_modules/.bin/opencode.cmd → <project>/node_modules/opencode-ai/bin/opencode.exe
391
+ const localCandidate = path.join(path.dirname(found), "..", "opencode-ai", "bin", "opencode.exe");
392
+ if (await pathExists(localCandidate))
393
+ return localCandidate;
394
+ console.warn("[opencode-server] Found opencode.cmd but could not resolve the real opencode.exe. " +
395
+ "The process may not be properly terminated on exit. Path: %s", found);
396
+ }
397
+ return found;
398
+ }
399
+ async function pathExists(filePath) {
400
+ try {
401
+ await stat(filePath);
402
+ return true;
403
+ }
404
+ catch {
405
+ return false;
376
406
  }
377
- throw new Error("OpenCode binary not found. Install OpenCode (https://github.com/opencode-ai/opencode) and ensure it is available in your shell PATH.");
378
407
  }
379
408
  function findAvailablePort() {
380
409
  return new Promise((resolve, reject) => {
@@ -4,6 +4,7 @@ import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOpt
4
4
  import { isDefaultAgentCreateConfigUnattended } from "../create-agent-mode.js";
5
5
  import { type ProviderRuntimeSettings } from "../provider-launch-config.js";
6
6
  import { type OpenCodeServerManagerLike } from "./opencode/server-manager.js";
7
+ import { resolveOpenCodeHomeDir } from "./opencode/paths.js";
7
8
  import type { ManagedProcessRegistry } from "../../managed-processes/managed-processes.js";
8
9
  declare function resolveOpenCodeCreateConfig(input: ResolveAgentCreateConfigInput): ResolveAgentCreateConfigResult;
9
10
  declare function isOpenCodeCreateConfigUnattended(input: Parameters<typeof isDefaultAgentCreateConfigUnattended>[0]): boolean;
@@ -100,11 +101,13 @@ export declare const __openCodeInternals: {
100
101
  resolveOpenCodeSelectedModelContextWindow: typeof resolveOpenCodeSelectedModelContextWindow;
101
102
  isSelectableOpenCodeAgent: typeof isSelectableOpenCodeAgent;
102
103
  mapOpenCodeAgentToMode: typeof mapOpenCodeAgentToMode;
104
+ resolveOpenCodeHomeDir: typeof resolveOpenCodeHomeDir;
103
105
  readonly OpenCodeAgentSession: typeof OpenCodeAgentSession;
104
106
  };
105
107
  interface OpenCodeAgentClientDeps {
106
108
  serverManager?: OpenCodeServerManagerLike;
107
109
  createClient?: OpenCodeClientFactory;
110
+ resolveHomeDir?: () => string;
108
111
  managedProcesses?: ManagedProcessRegistry;
109
112
  }
110
113
  type OpenCodeClientFactory = (options: {
@@ -118,6 +121,7 @@ export declare class OpenCodeAgentClient implements AgentClient {
118
121
  readonly isCreateConfigUnattended: typeof isOpenCodeCreateConfigUnattended;
119
122
  private readonly serverManager;
120
123
  private readonly createOpenCodeClient;
124
+ private readonly resolveHomeDir;
121
125
  private readonly logger;
122
126
  private readonly runtimeSettings?;
123
127
  private readonly modelContextWindows;