@otto-code/server 0.5.0

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 (734) hide show
  1. package/.env.example +31 -0
  2. package/README.md +111 -0
  3. package/dist/scripts/dev-runner.js +37 -0
  4. package/dist/scripts/mcp-stdio-socket-bridge-cli.mjs +62 -0
  5. package/dist/scripts/supervisor-entrypoint.js +141 -0
  6. package/dist/scripts/supervisor-log-config.js +31 -0
  7. package/dist/scripts/supervisor.js +252 -0
  8. package/dist/server/executable-resolution/executable-resolution.d.ts +10 -0
  9. package/dist/server/executable-resolution/executable-resolution.js +118 -0
  10. package/dist/server/executable-resolution/windows.d.ts +18 -0
  11. package/dist/server/executable-resolution/windows.js +65 -0
  12. package/dist/server/server/agent/activity-curator.d.ts +28 -0
  13. package/dist/server/server/agent/activity-curator.js +227 -0
  14. package/dist/server/server/agent/agent-archive.d.ts +11 -0
  15. package/dist/server/server/agent/agent-archive.js +16 -0
  16. package/dist/server/server/agent/agent-loading.d.ts +14 -0
  17. package/dist/server/server/agent/agent-loading.js +54 -0
  18. package/dist/server/server/agent/agent-manager.d.ts +470 -0
  19. package/dist/server/server/agent/agent-manager.js +3049 -0
  20. package/dist/server/server/agent/agent-personalities.d.ts +59 -0
  21. package/dist/server/server/agent/agent-personalities.js +103 -0
  22. package/dist/server/server/agent/agent-projections.d.ts +35 -0
  23. package/dist/server/server/agent/agent-projections.js +488 -0
  24. package/dist/server/server/agent/agent-prompt.d.ts +76 -0
  25. package/dist/server/server/agent/agent-prompt.js +230 -0
  26. package/dist/server/server/agent/agent-response-loop.d.ts +72 -0
  27. package/dist/server/server/agent/agent-response-loop.js +333 -0
  28. package/dist/server/server/agent/agent-sdk-types.d.ts +736 -0
  29. package/dist/server/server/agent/agent-sdk-types.js +22 -0
  30. package/dist/server/server/agent/agent-storage.d.ts +147 -0
  31. package/dist/server/server/agent/agent-storage.js +326 -0
  32. package/dist/server/server/agent/agent-stream-coalescer.d.ts +41 -0
  33. package/dist/server/server/agent/agent-stream-coalescer.js +166 -0
  34. package/dist/server/server/agent/agent-timeline-store-types.d.ts +50 -0
  35. package/dist/server/server/agent/agent-timeline-store-types.js +2 -0
  36. package/dist/server/server/agent/agent-timeline-store.d.ts +27 -0
  37. package/dist/server/server/agent/agent-timeline-store.js +230 -0
  38. package/dist/server/server/agent/audio-utils.d.ts +3 -0
  39. package/dist/server/server/agent/audio-utils.js +19 -0
  40. package/dist/server/server/agent/create-agent/create.d.ts +91 -0
  41. package/dist/server/server/agent/create-agent/create.js +370 -0
  42. package/dist/server/server/agent/create-agent-lifecycle-dispatch.d.ts +54 -0
  43. package/dist/server/server/agent/create-agent-lifecycle-dispatch.js +152 -0
  44. package/dist/server/server/agent/create-agent-mode.d.ts +13 -0
  45. package/dist/server/server/agent/create-agent-mode.js +62 -0
  46. package/dist/server/server/agent/create-agent-title.d.ts +10 -0
  47. package/dist/server/server/agent/create-agent-title.js +34 -0
  48. package/dist/server/server/agent/dictation-debug.d.ts +13 -0
  49. package/dist/server/server/agent/dictation-debug.js +50 -0
  50. package/dist/server/server/agent/effort-levels.d.ts +2 -0
  51. package/dist/server/server/agent/effort-levels.js +7 -0
  52. package/dist/server/server/agent/foreground-run-state.d.ts +50 -0
  53. package/dist/server/server/agent/foreground-run-state.js +160 -0
  54. package/dist/server/server/agent/import-sessions.d.ts +47 -0
  55. package/dist/server/server/agent/import-sessions.js +145 -0
  56. package/dist/server/server/agent/lifecycle-command.d.ts +73 -0
  57. package/dist/server/server/agent/lifecycle-command.js +92 -0
  58. package/dist/server/server/agent/mcp-server.d.ts +5 -0
  59. package/dist/server/server/agent/mcp-server.js +66 -0
  60. package/dist/server/server/agent/mcp-shared.d.ts +192 -0
  61. package/dist/server/server/agent/mcp-shared.js +201 -0
  62. package/dist/server/server/agent/pcm16-resampler.d.ts +14 -0
  63. package/dist/server/server/agent/pcm16-resampler.js +63 -0
  64. package/dist/server/server/agent/permission-response.d.ts +15 -0
  65. package/dist/server/server/agent/permission-response.js +14 -0
  66. package/dist/server/server/agent/personality-stats-store.d.ts +23 -0
  67. package/dist/server/server/agent/personality-stats-store.js +65 -0
  68. package/dist/server/server/agent/prompt-attachments.d.ts +7 -0
  69. package/dist/server/server/agent/prompt-attachments.js +117 -0
  70. package/dist/server/server/agent/provider-history-timestamps.d.ts +2 -0
  71. package/dist/server/server/agent/provider-history-timestamps.js +16 -0
  72. package/dist/server/server/agent/provider-launch-config.d.ts +43 -0
  73. package/dist/server/server/agent/provider-launch-config.js +167 -0
  74. package/dist/server/server/agent/provider-notices.d.ts +3 -0
  75. package/dist/server/server/agent/provider-notices.js +5 -0
  76. package/dist/server/server/agent/provider-registry.d.ts +41 -0
  77. package/dist/server/server/agent/provider-registry.js +532 -0
  78. package/dist/server/server/agent/provider-session-import.d.ts +10 -0
  79. package/dist/server/server/agent/provider-session-import.js +49 -0
  80. package/dist/server/server/agent/provider-snapshot-manager.d.ts +142 -0
  81. package/dist/server/server/agent/provider-snapshot-manager.js +690 -0
  82. package/dist/server/server/agent/providers/acp-agent.d.ts +353 -0
  83. package/dist/server/server/agent/providers/acp-agent.js +2439 -0
  84. package/dist/server/server/agent/providers/claude/agent.d.ts +66 -0
  85. package/dist/server/server/agent/providers/claude/agent.js +4535 -0
  86. package/dist/server/server/agent/providers/claude/feature-definitions.d.ts +8 -0
  87. package/dist/server/server/agent/providers/claude/feature-definitions.js +24 -0
  88. package/dist/server/server/agent/providers/claude/model-manifest.d.ts +90 -0
  89. package/dist/server/server/agent/providers/claude/model-manifest.js +205 -0
  90. package/dist/server/server/agent/providers/claude/models.d.ts +11 -0
  91. package/dist/server/server/agent/providers/claude/models.js +97 -0
  92. package/dist/server/server/agent/providers/claude/partial-json.d.ts +5 -0
  93. package/dist/server/server/agent/providers/claude/partial-json.js +306 -0
  94. package/dist/server/server/agent/providers/claude/project-dir.d.ts +6 -0
  95. package/dist/server/server/agent/providers/claude/project-dir.js +57 -0
  96. package/dist/server/server/agent/providers/claude/query.d.ts +17 -0
  97. package/dist/server/server/agent/providers/claude/query.js +86 -0
  98. package/dist/server/server/agent/providers/claude/rewind.d.ts +30 -0
  99. package/dist/server/server/agent/providers/claude/rewind.js +30 -0
  100. package/dist/server/server/agent/providers/claude/sidechain-tracker.d.ts +22 -0
  101. package/dist/server/server/agent/providers/claude/sidechain-tracker.js +232 -0
  102. package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts +35 -0
  103. package/dist/server/server/agent/providers/claude/task-notification-tool-call.js +272 -0
  104. package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.d.ts +24 -0
  105. package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.js +23 -0
  106. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts +3 -0
  107. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +130 -0
  108. package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts +16 -0
  109. package/dist/server/server/agent/providers/claude/tool-call-mapper.js +129 -0
  110. package/dist/server/server/agent/providers/codex/app-server-transport.d.ts +90 -0
  111. package/dist/server/server/agent/providers/codex/app-server-transport.js +262 -0
  112. package/dist/server/server/agent/providers/codex/rewind.d.ts +21 -0
  113. package/dist/server/server/agent/providers/codex/rewind.js +46 -0
  114. package/dist/server/server/agent/providers/codex/test-utils/fake-app-server.d.ts +36 -0
  115. package/dist/server/server/agent/providers/codex/test-utils/fake-app-server.js +217 -0
  116. package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts +12 -0
  117. package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js +104 -0
  118. package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +24 -0
  119. package/dist/server/server/agent/providers/codex/tool-call-mapper.js +830 -0
  120. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +308 -0
  121. package/dist/server/server/agent/providers/codex-app-server-agent.js +4515 -0
  122. package/dist/server/server/agent/providers/codex-feature-definitions.d.ts +11 -0
  123. package/dist/server/server/agent/providers/codex-feature-definitions.js +45 -0
  124. package/dist/server/server/agent/providers/copilot-acp-agent.d.ts +26 -0
  125. package/dist/server/server/agent/providers/copilot-acp-agent.js +188 -0
  126. package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +15 -0
  127. package/dist/server/server/agent/providers/cursor-acp-agent.js +18 -0
  128. package/dist/server/server/agent/providers/diagnostic-utils.d.ts +36 -0
  129. package/dist/server/server/agent/providers/diagnostic-utils.js +355 -0
  130. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +42 -0
  131. package/dist/server/server/agent/providers/generic-acp-agent.js +160 -0
  132. package/dist/server/server/agent/providers/kiro-acp-agent.d.ts +17 -0
  133. package/dist/server/server/agent/providers/kiro-acp-agent.js +78 -0
  134. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +85 -0
  135. package/dist/server/server/agent/providers/mock-load-test-agent.js +1010 -0
  136. package/dist/server/server/agent/providers/mock-slow-provider.d.ts +14 -0
  137. package/dist/server/server/agent/providers/mock-slow-provider.js +39 -0
  138. package/dist/server/server/agent/providers/openai-compat-agent.d.ts +422 -0
  139. package/dist/server/server/agent/providers/openai-compat-agent.js +2536 -0
  140. package/dist/server/server/agent/providers/openai-compat-feature-definitions.d.ts +40 -0
  141. package/dist/server/server/agent/providers/openai-compat-feature-definitions.js +82 -0
  142. package/dist/server/server/agent/providers/openai-compat-mcp.d.ts +87 -0
  143. package/dist/server/server/agent/providers/openai-compat-mcp.js +353 -0
  144. package/dist/server/server/agent/providers/openai-compat-otto-tool-permissions.d.ts +29 -0
  145. package/dist/server/server/agent/providers/openai-compat-otto-tool-permissions.js +96 -0
  146. package/dist/server/server/agent/providers/openai-compat-tools.d.ts +69 -0
  147. package/dist/server/server/agent/providers/openai-compat-tools.js +1224 -0
  148. package/dist/server/server/agent/providers/opencode/paths.d.ts +2 -0
  149. package/dist/server/server/agent/providers/opencode/paths.js +7 -0
  150. package/dist/server/server/agent/providers/opencode/rewind.d.ts +18 -0
  151. package/dist/server/server/agent/providers/opencode/rewind.js +14 -0
  152. package/dist/server/server/agent/providers/opencode/server-manager.d.ts +91 -0
  153. package/dist/server/server/agent/providers/opencode/server-manager.js +425 -0
  154. package/dist/server/server/agent/providers/opencode/test-server-manager.d.ts +25 -0
  155. package/dist/server/server/agent/providers/opencode/test-server-manager.js +39 -0
  156. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-harness.d.ts +92 -0
  157. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-harness.js +260 -0
  158. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts +3 -0
  159. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +256 -0
  160. package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts +13 -0
  161. package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +53 -0
  162. package/dist/server/server/agent/providers/opencode-agent.d.ts +286 -0
  163. package/dist/server/server/agent/providers/opencode-agent.js +2830 -0
  164. package/dist/server/server/agent/providers/pi/agent.d.ts +132 -0
  165. package/dist/server/server/agent/providers/pi/agent.js +1649 -0
  166. package/dist/server/server/agent/providers/pi/cli-runtime.d.ts +21 -0
  167. package/dist/server/server/agent/providers/pi/cli-runtime.js +261 -0
  168. package/dist/server/server/agent/providers/pi/history-mapper.d.ts +9 -0
  169. package/dist/server/server/agent/providers/pi/history-mapper.js +140 -0
  170. package/dist/server/server/agent/providers/pi/rewind.d.ts +8 -0
  171. package/dist/server/server/agent/providers/pi/rewind.js +8 -0
  172. package/dist/server/server/agent/providers/pi/rpc-types.d.ts +208 -0
  173. package/dist/server/server/agent/providers/pi/rpc-types.js +2 -0
  174. package/dist/server/server/agent/providers/pi/runtime.d.ts +57 -0
  175. package/dist/server/server/agent/providers/pi/runtime.js +56 -0
  176. package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +16 -0
  177. package/dist/server/server/agent/providers/pi/session-descriptor.js +346 -0
  178. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +83 -0
  179. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +184 -0
  180. package/dist/server/server/agent/providers/pi/tool-call-mapper.d.ts +112 -0
  181. package/dist/server/server/agent/providers/pi/tool-call-mapper.js +284 -0
  182. package/dist/server/server/agent/providers/provider-image-output.d.ts +25 -0
  183. package/dist/server/server/agent/providers/provider-image-output.js +111 -0
  184. package/dist/server/server/agent/providers/provider-runner.d.ts +27 -0
  185. package/dist/server/server/agent/providers/provider-runner.js +81 -0
  186. package/dist/server/server/agent/providers/test-utils/session-stream-adapter.d.ts +3 -0
  187. package/dist/server/server/agent/providers/test-utils/session-stream-adapter.js +60 -0
  188. package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +884 -0
  189. package/dist/server/server/agent/providers/tool-call-detail-primitives.js +778 -0
  190. package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +25 -0
  191. package/dist/server/server/agent/providers/tool-call-mapper-utils.js +208 -0
  192. package/dist/server/server/agent/providers/trae-acp-agent.d.ts +15 -0
  193. package/dist/server/server/agent/providers/trae-acp-agent.js +18 -0
  194. package/dist/server/server/agent/recordings-debug.d.ts +3 -0
  195. package/dist/server/server/agent/recordings-debug.js +19 -0
  196. package/dist/server/server/agent/rewind/rewind.d.ts +10 -0
  197. package/dist/server/server/agent/rewind/rewind.js +29 -0
  198. package/dist/server/server/agent/rewind/test-rewind-session.d.ts +48 -0
  199. package/dist/server/server/agent/rewind/test-rewind-session.js +88 -0
  200. package/dist/server/server/agent/runtime-mcp-config.d.ts +14 -0
  201. package/dist/server/server/agent/runtime-mcp-config.js +53 -0
  202. package/dist/server/server/agent/structured-generation-providers.d.ts +29 -0
  203. package/dist/server/server/agent/structured-generation-providers.js +236 -0
  204. package/dist/server/server/agent/stt-debug.d.ts +10 -0
  205. package/dist/server/server/agent/stt-debug.js +33 -0
  206. package/dist/server/server/agent/stt-manager.d.ts +38 -0
  207. package/dist/server/server/agent/stt-manager.js +246 -0
  208. package/dist/server/server/agent/system-prompt.d.ts +2 -0
  209. package/dist/server/server/agent/system-prompt.js +8 -0
  210. package/dist/server/server/agent/timeline-append.d.ts +10 -0
  211. package/dist/server/server/agent/timeline-append.js +27 -0
  212. package/dist/server/server/agent/timeline-projection.d.ts +71 -0
  213. package/dist/server/server/agent/timeline-projection.js +373 -0
  214. package/dist/server/server/agent/tools/otto-tools.d.ts +80 -0
  215. package/dist/server/server/agent/tools/otto-tools.js +2912 -0
  216. package/dist/server/server/agent/tools/types.d.ts +36 -0
  217. package/dist/server/server/agent/tools/types.js +2 -0
  218. package/dist/server/server/agent/tts-debug.d.ts +8 -0
  219. package/dist/server/server/agent/tts-debug.js +24 -0
  220. package/dist/server/server/agent/tts-manager.d.ts +41 -0
  221. package/dist/server/server/agent/tts-manager.js +375 -0
  222. package/dist/server/server/agent-attention-policy.d.ts +29 -0
  223. package/dist/server/server/agent-attention-policy.js +36 -0
  224. package/dist/server/server/artifact/artifact-prompt.d.ts +2 -0
  225. package/dist/server/server/artifact/artifact-prompt.js +15 -0
  226. package/dist/server/server/artifact/artifact-service.d.ts +91 -0
  227. package/dist/server/server/artifact/artifact-service.js +419 -0
  228. package/dist/server/server/artifact/artifact-store.d.ts +24 -0
  229. package/dist/server/server/artifact/artifact-store.js +168 -0
  230. package/dist/server/server/artifact/artifact-watcher.d.ts +34 -0
  231. package/dist/server/server/artifact/artifact-watcher.js +146 -0
  232. package/dist/server/server/artifact/html-validator.d.ts +26 -0
  233. package/dist/server/server/artifact/html-validator.js +92 -0
  234. package/dist/server/server/atomic-file.d.ts +5 -0
  235. package/dist/server/server/atomic-file.js +19 -0
  236. package/dist/server/server/auth.d.ts +38 -0
  237. package/dist/server/server/auth.js +143 -0
  238. package/dist/server/server/auto-archive-on-merge/archive-if-safe.d.ts +40 -0
  239. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +92 -0
  240. package/dist/server/server/auto-archive-on-merge/index.d.ts +8 -0
  241. package/dist/server/server/auto-archive-on-merge/index.js +15 -0
  242. package/dist/server/server/bootstrap.d.ts +127 -0
  243. package/dist/server/server/bootstrap.js +1331 -0
  244. package/dist/server/server/browser-tools/broker.d.ts +45 -0
  245. package/dist/server/server/browser-tools/broker.js +390 -0
  246. package/dist/server/server/browser-tools/errors.d.ts +22 -0
  247. package/dist/server/server/browser-tools/errors.js +27 -0
  248. package/dist/server/server/browser-tools/policy.d.ts +10 -0
  249. package/dist/server/server/browser-tools/policy.js +16 -0
  250. package/dist/server/server/browser-tools/tools.d.ts +24 -0
  251. package/dist/server/server/browser-tools/tools.js +967 -0
  252. package/dist/server/server/chat/chat-mentions.d.ts +47 -0
  253. package/dist/server/server/chat/chat-mentions.js +113 -0
  254. package/dist/server/server/chat/chat-service.d.ts +78 -0
  255. package/dist/server/server/chat/chat-service.js +337 -0
  256. package/dist/server/server/checkout/status-projection.d.ts +19 -0
  257. package/dist/server/server/checkout/status-projection.js +117 -0
  258. package/dist/server/server/checkout-diff-manager.d.ts +41 -0
  259. package/dist/server/server/checkout-diff-manager.js +189 -0
  260. package/dist/server/server/checkout-git-utils.d.ts +11 -0
  261. package/dist/server/server/checkout-git-utils.js +34 -0
  262. package/dist/server/server/client-message-id.d.ts +3 -0
  263. package/dist/server/server/client-message-id.js +12 -0
  264. package/dist/server/server/config.d.ts +22 -0
  265. package/dist/server/server/config.js +330 -0
  266. package/dist/server/server/connection-offer.d.ts +20 -0
  267. package/dist/server/server/connection-offer.js +59 -0
  268. package/dist/server/server/daemon-config-store.d.ts +44 -0
  269. package/dist/server/server/daemon-config-store.js +530 -0
  270. package/dist/server/server/daemon-keypair.d.ts +8 -0
  271. package/dist/server/server/daemon-keypair.js +42 -0
  272. package/dist/server/server/daemon-version.d.ts +5 -0
  273. package/dist/server/server/daemon-version.js +22 -0
  274. package/dist/server/server/daemon-worker.d.ts +2 -0
  275. package/dist/server/server/daemon-worker.js +251 -0
  276. package/dist/server/server/dictation/dictation-stream-manager.d.ts +87 -0
  277. package/dist/server/server/dictation/dictation-stream-manager.js +572 -0
  278. package/dist/server/server/exports.d.ts +24 -0
  279. package/dist/server/server/exports.js +24 -0
  280. package/dist/server/server/file-download/token-store.d.ts +24 -0
  281. package/dist/server/server/file-download/token-store.js +40 -0
  282. package/dist/server/server/file-explorer/code-index.d.ts +28 -0
  283. package/dist/server/server/file-explorer/code-index.js +127 -0
  284. package/dist/server/server/file-explorer/file-search.d.ts +72 -0
  285. package/dist/server/server/file-explorer/file-search.js +297 -0
  286. package/dist/server/server/file-explorer/file-watcher.d.ts +40 -0
  287. package/dist/server/server/file-explorer/file-watcher.js +0 -0
  288. package/dist/server/server/file-explorer/gitignore.d.ts +39 -0
  289. package/dist/server/server/file-explorer/gitignore.js +191 -0
  290. package/dist/server/server/file-explorer/service.d.ts +103 -0
  291. package/dist/server/server/file-explorer/service.js +420 -0
  292. package/dist/server/server/file-upload/index.d.ts +27 -0
  293. package/dist/server/server/file-upload/index.js +158 -0
  294. package/dist/server/server/hostnames.d.ts +13 -0
  295. package/dist/server/server/hostnames.js +94 -0
  296. package/dist/server/server/json-utils.d.ts +11 -0
  297. package/dist/server/server/json-utils.js +45 -0
  298. package/dist/server/server/lifecycle-reasons.d.ts +4 -0
  299. package/dist/server/server/lifecycle-reasons.js +6 -0
  300. package/dist/server/server/logger.d.ts +29 -0
  301. package/dist/server/server/logger.js +125 -0
  302. package/dist/server/server/loop-service.d.ts +234 -0
  303. package/dist/server/server/loop-service.js +804 -0
  304. package/dist/server/server/managed-processes/managed-processes.d.ts +76 -0
  305. package/dist/server/server/managed-processes/managed-processes.js +326 -0
  306. package/dist/server/server/messages.d.ts +9 -0
  307. package/dist/server/server/messages.js +29 -0
  308. package/dist/server/server/migrations/backfill-workspace-id.migration.d.ts +9 -0
  309. package/dist/server/server/migrations/backfill-workspace-id.migration.js +64 -0
  310. package/dist/server/server/otto-env.d.ts +13 -0
  311. package/dist/server/server/otto-env.js +53 -0
  312. package/dist/server/server/otto-home.d.ts +2 -0
  313. package/dist/server/server/otto-home.js +19 -0
  314. package/dist/server/server/otto-worktree-service.d.ts +52 -0
  315. package/dist/server/server/otto-worktree-service.js +294 -0
  316. package/dist/server/server/package-version.d.ts +19 -0
  317. package/dist/server/server/package-version.js +60 -0
  318. package/dist/server/server/pagination/cursor.d.ts +16 -0
  319. package/dist/server/server/pagination/cursor.js +62 -0
  320. package/dist/server/server/pagination/sortable-pager.d.ts +24 -0
  321. package/dist/server/server/pagination/sortable-pager.js +68 -0
  322. package/dist/server/server/pairing-offer.d.ts +18 -0
  323. package/dist/server/server/pairing-offer.js +47 -0
  324. package/dist/server/server/pairing-qr.d.ts +7 -0
  325. package/dist/server/server/pairing-qr.js +45 -0
  326. package/dist/server/server/path-utils.d.ts +5 -0
  327. package/dist/server/server/path-utils.js +34 -0
  328. package/dist/server/server/persisted-config.d.ts +417 -0
  329. package/dist/server/server/persisted-config.js +471 -0
  330. package/dist/server/server/persistence-hooks.d.ts +31 -0
  331. package/dist/server/server/persistence-hooks.js +93 -0
  332. package/dist/server/server/pid-lock.d.ts +32 -0
  333. package/dist/server/server/pid-lock.js +170 -0
  334. package/dist/server/server/preview/dev-server-manager.d.ts +108 -0
  335. package/dist/server/server/preview/dev-server-manager.js +426 -0
  336. package/dist/server/server/preview/launch-config.d.ts +37 -0
  337. package/dist/server/server/preview/launch-config.js +63 -0
  338. package/dist/server/server/preview/preview-tools.d.ts +30 -0
  339. package/dist/server/server/preview/preview-tools.js +249 -0
  340. package/dist/server/server/private-files.d.ts +6 -0
  341. package/dist/server/server/private-files.js +37 -0
  342. package/dist/server/server/process-diagnostics.d.ts +17 -0
  343. package/dist/server/server/process-diagnostics.js +22 -0
  344. package/dist/server/server/push/notifications.d.ts +9 -0
  345. package/dist/server/server/push/notifications.js +15 -0
  346. package/dist/server/server/push/push-service.d.ts +20 -0
  347. package/dist/server/server/push/push-service.js +66 -0
  348. package/dist/server/server/push/token-store.d.ts +18 -0
  349. package/dist/server/server/push/token-store.js +68 -0
  350. package/dist/server/server/relay-transport.d.ts +31 -0
  351. package/dist/server/server/relay-transport.js +514 -0
  352. package/dist/server/server/resolve-workspace-id-for-path.d.ts +3 -0
  353. package/dist/server/server/resolve-workspace-id-for-path.js +41 -0
  354. package/dist/server/server/resolve-worktree-creation-intent.d.ts +32 -0
  355. package/dist/server/server/resolve-worktree-creation-intent.js +121 -0
  356. package/dist/server/server/schedule/cron.d.ts +4 -0
  357. package/dist/server/server/schedule/cron.js +81 -0
  358. package/dist/server/server/schedule/service.d.ts +89 -0
  359. package/dist/server/server/schedule/service.js +882 -0
  360. package/dist/server/server/schedule/store.d.ts +27 -0
  361. package/dist/server/server/schedule/store.js +190 -0
  362. package/dist/server/server/script-health-monitor.d.ts +39 -0
  363. package/dist/server/server/script-health-monitor.js +159 -0
  364. package/dist/server/server/script-proxy.d.ts +3 -0
  365. package/dist/server/server/script-proxy.js +2 -0
  366. package/dist/server/server/script-route-branch-handler.d.ts +10 -0
  367. package/dist/server/server/script-route-branch-handler.js +11 -0
  368. package/dist/server/server/script-status-projection.d.ts +36 -0
  369. package/dist/server/server/script-status-projection.js +200 -0
  370. package/dist/server/server/server-id.d.ts +17 -0
  371. package/dist/server/server/server-id.js +68 -0
  372. package/dist/server/server/service-proxy.d.ts +237 -0
  373. package/dist/server/server/service-proxy.js +714 -0
  374. package/dist/server/server/session/agent-config/agent-config-session.d.ts +59 -0
  375. package/dist/server/server/session/agent-config/agent-config-session.js +110 -0
  376. package/dist/server/server/session/agent-updates/agent-updates-service.d.ts +65 -0
  377. package/dist/server/server/session/agent-updates/agent-updates-service.js +232 -0
  378. package/dist/server/server/session/artifact/artifact-session.d.ts +45 -0
  379. package/dist/server/server/session/artifact/artifact-session.js +293 -0
  380. package/dist/server/server/session/chat/chat-schedule-loop-session.d.ts +120 -0
  381. package/dist/server/server/session/chat/chat-schedule-loop-session.js +489 -0
  382. package/dist/server/server/session/checkout/checkout-session.d.ts +146 -0
  383. package/dist/server/server/session/checkout/checkout-session.js +1000 -0
  384. package/dist/server/server/session/checkout/git-metadata-generator.d.ts +53 -0
  385. package/dist/server/server/session/checkout/git-metadata-generator.js +159 -0
  386. package/dist/server/server/session/daemon/daemon-self-update-session-controller.d.ts +32 -0
  387. package/dist/server/server/session/daemon/daemon-self-update-session-controller.js +88 -0
  388. package/dist/server/server/session/daemon/daemon-self-updater.d.ts +32 -0
  389. package/dist/server/server/session/daemon/daemon-self-updater.js +56 -0
  390. package/dist/server/server/session/daemon/daemon-session.d.ts +76 -0
  391. package/dist/server/server/session/daemon/daemon-session.js +148 -0
  392. package/dist/server/server/session/daemon/diagnostics.d.ts +41 -0
  393. package/dist/server/server/session/daemon/diagnostics.js +431 -0
  394. package/dist/server/server/session/daemon/install-origin.d.ts +7 -0
  395. package/dist/server/server/session/daemon/install-origin.js +64 -0
  396. package/dist/server/server/session/daemon/npm-global-cli.d.ts +29 -0
  397. package/dist/server/server/session/daemon/npm-global-cli.js +98 -0
  398. package/dist/server/server/session/files/workspace-files-session.d.ts +60 -0
  399. package/dist/server/server/session/files/workspace-files-session.js +518 -0
  400. package/dist/server/server/session/git-mutation/git-mutation-service.d.ts +34 -0
  401. package/dist/server/server/session/git-mutation/git-mutation-service.js +71 -0
  402. package/dist/server/server/session/project-config/project-config-session.d.ts +34 -0
  403. package/dist/server/server/session/project-config/project-config-session.js +125 -0
  404. package/dist/server/server/session/provider/provider-catalog-session.d.ts +74 -0
  405. package/dist/server/server/session/provider/provider-catalog-session.js +343 -0
  406. package/dist/server/server/session/voice/voice-session.d.ts +167 -0
  407. package/dist/server/server/session/voice/voice-session.js +912 -0
  408. package/dist/server/server/session/voice/voice-turn-controller.d.ts +38 -0
  409. package/dist/server/server/session/voice/voice-turn-controller.js +393 -0
  410. package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.d.ts +36 -0
  411. package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.js +134 -0
  412. package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.d.ts +34 -0
  413. package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.js +190 -0
  414. package/dist/server/server/session/workspace-scripts/workspace-scripts-service.d.ts +41 -0
  415. package/dist/server/server/session/workspace-scripts/workspace-scripts-service.js +100 -0
  416. package/dist/server/server/session.d.ts +450 -0
  417. package/dist/server/server/session.js +4763 -0
  418. package/dist/server/server/speech/audio.d.ts +10 -0
  419. package/dist/server/server/speech/audio.js +101 -0
  420. package/dist/server/server/speech/provider-resolver.d.ts +3 -0
  421. package/dist/server/server/speech/provider-resolver.js +7 -0
  422. package/dist/server/server/speech/providers/local/config.d.ts +30 -0
  423. package/dist/server/server/speech/providers/local/config.js +133 -0
  424. package/dist/server/server/speech/providers/local/models.d.ts +13 -0
  425. package/dist/server/server/speech/providers/local/models.js +21 -0
  426. package/dist/server/server/speech/providers/local/runtime.d.ts +31 -0
  427. package/dist/server/server/speech/providers/local/runtime.js +135 -0
  428. package/dist/server/server/speech/providers/local/sherpa/assets/silero_vad.onnx +0 -0
  429. package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts +109 -0
  430. package/dist/server/server/speech/providers/local/sherpa/model-catalog.js +129 -0
  431. package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts +16 -0
  432. package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +195 -0
  433. package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts +49 -0
  434. package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js +73 -0
  435. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts +9 -0
  436. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +107 -0
  437. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts +28 -0
  438. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +137 -0
  439. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts +21 -0
  440. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +133 -0
  441. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.d.ts +18 -0
  442. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.js +84 -0
  443. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts +24 -0
  444. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js +145 -0
  445. package/dist/server/server/speech/providers/local/sherpa/silero-vad-provider.d.ts +19 -0
  446. package/dist/server/server/speech/providers/local/sherpa/silero-vad-provider.js +49 -0
  447. package/dist/server/server/speech/providers/local/sherpa/silero-vad-session.d.ts +38 -0
  448. package/dist/server/server/speech/providers/local/sherpa/silero-vad-session.js +176 -0
  449. package/dist/server/server/speech/providers/local/sherpa/tts-voices.d.ts +10 -0
  450. package/dist/server/server/speech/providers/local/sherpa/tts-voices.js +86 -0
  451. package/dist/server/server/speech/providers/local/worker-bytes.d.ts +4 -0
  452. package/dist/server/server/speech/providers/local/worker-bytes.js +9 -0
  453. package/dist/server/server/speech/providers/local/worker-client.d.ts +93 -0
  454. package/dist/server/server/speech/providers/local/worker-client.js +591 -0
  455. package/dist/server/server/speech/providers/local/worker-process.d.ts +2 -0
  456. package/dist/server/server/speech/providers/local/worker-process.js +270 -0
  457. package/dist/server/server/speech/providers/local/worker-protocol.d.ts +96 -0
  458. package/dist/server/server/speech/providers/local/worker-protocol.js +2 -0
  459. package/dist/server/server/speech/providers/openai/config.d.ts +19 -0
  460. package/dist/server/server/speech/providers/openai/config.js +160 -0
  461. package/dist/server/server/speech/providers/openai/runtime.d.ts +29 -0
  462. package/dist/server/server/speech/providers/openai/runtime.js +102 -0
  463. package/dist/server/server/speech/providers/openai/stt.d.ts +23 -0
  464. package/dist/server/server/speech/providers/openai/stt.js +209 -0
  465. package/dist/server/server/speech/providers/openai/tts.d.ts +20 -0
  466. package/dist/server/server/speech/providers/openai/tts.js +70 -0
  467. package/dist/server/server/speech/speech-config-resolver.d.ts +11 -0
  468. package/dist/server/server/speech/speech-config-resolver.js +132 -0
  469. package/dist/server/server/speech/speech-provider.d.ts +71 -0
  470. package/dist/server/server/speech/speech-provider.js +2 -0
  471. package/dist/server/server/speech/speech-runtime.d.ts +67 -0
  472. package/dist/server/server/speech/speech-runtime.js +615 -0
  473. package/dist/server/server/speech/speech-settings-options.d.ts +14 -0
  474. package/dist/server/server/speech/speech-settings-options.js +73 -0
  475. package/dist/server/server/speech/speech-types.d.ts +22 -0
  476. package/dist/server/server/speech/speech-types.js +8 -0
  477. package/dist/server/server/speech/turn-detection-provider.d.ts +23 -0
  478. package/dist/server/server/speech/turn-detection-provider.js +2 -0
  479. package/dist/server/server/utils/diff-highlighter.d.ts +57 -0
  480. package/dist/server/server/utils/diff-highlighter.js +279 -0
  481. package/dist/server/server/voice-config.d.ts +15 -0
  482. package/dist/server/server/voice-config.js +54 -0
  483. package/dist/server/server/voice-permission-policy.d.ts +4 -0
  484. package/dist/server/server/voice-permission-policy.js +13 -0
  485. package/dist/server/server/voice-types.d.ts +12 -0
  486. package/dist/server/server/voice-types.js +2 -0
  487. package/dist/server/server/web-ui.d.ts +10 -0
  488. package/dist/server/server/web-ui.js +205 -0
  489. package/dist/server/server/websocket/runtime-metrics.d.ts +94 -0
  490. package/dist/server/server/websocket/runtime-metrics.js +148 -0
  491. package/dist/server/server/websocket-server.d.ts +187 -0
  492. package/dist/server/server/websocket-server.js +1766 -0
  493. package/dist/server/server/workspace-archive-service.d.ts +65 -0
  494. package/dist/server/server/workspace-archive-service.js +229 -0
  495. package/dist/server/server/workspace-auto-name.d.ts +55 -0
  496. package/dist/server/server/workspace-auto-name.js +128 -0
  497. package/dist/server/server/workspace-bootstrap-dedupe.d.ts +34 -0
  498. package/dist/server/server/workspace-bootstrap-dedupe.js +23 -0
  499. package/dist/server/server/workspace-directory.d.ts +93 -0
  500. package/dist/server/server/workspace-directory.js +422 -0
  501. package/dist/server/server/workspace-git-metadata.d.ts +24 -0
  502. package/dist/server/server/workspace-git-metadata.js +55 -0
  503. package/dist/server/server/workspace-git-service.d.ts +270 -0
  504. package/dist/server/server/workspace-git-service.js +1423 -0
  505. package/dist/server/server/workspace-reconciliation-service.d.ts +57 -0
  506. package/dist/server/server/workspace-reconciliation-service.js +278 -0
  507. package/dist/server/server/workspace-registry-bootstrap.d.ts +13 -0
  508. package/dist/server/server/workspace-registry-bootstrap.js +121 -0
  509. package/dist/server/server/workspace-registry-model.d.ts +55 -0
  510. package/dist/server/server/workspace-registry-model.js +190 -0
  511. package/dist/server/server/workspace-registry.d.ts +117 -0
  512. package/dist/server/server/workspace-registry.js +194 -0
  513. package/dist/server/server/workspace-script-runtime-store.d.ts +28 -0
  514. package/dist/server/server/workspace-script-runtime-store.js +78 -0
  515. package/dist/server/server/workspace-service-env.d.ts +18 -0
  516. package/dist/server/server/workspace-service-env.js +85 -0
  517. package/dist/server/server/workspace-service-port-registry.d.ts +19 -0
  518. package/dist/server/server/workspace-service-port-registry.js +59 -0
  519. package/dist/server/server/worktree/commands.d.ts +55 -0
  520. package/dist/server/server/worktree/commands.js +107 -0
  521. package/dist/server/server/worktree-bootstrap.d.ts +76 -0
  522. package/dist/server/server/worktree-bootstrap.js +720 -0
  523. package/dist/server/server/worktree-branch-name-generator.d.ts +35 -0
  524. package/dist/server/server/worktree-branch-name-generator.js +91 -0
  525. package/dist/server/server/worktree-core.d.ts +31 -0
  526. package/dist/server/server/worktree-core.js +105 -0
  527. package/dist/server/server/worktree-errors.d.ts +12 -0
  528. package/dist/server/server/worktree-errors.js +28 -0
  529. package/dist/server/server/worktree-session.d.ts +152 -0
  530. package/dist/server/server/worktree-session.js +466 -0
  531. package/dist/server/services/git-hosting/bitbucket-cloud-service.d.ts +24 -0
  532. package/dist/server/services/git-hosting/bitbucket-cloud-service.js +754 -0
  533. package/dist/server/services/git-hosting/github-hosting-service.d.ts +4 -0
  534. package/dist/server/services/git-hosting/github-hosting-service.js +11 -0
  535. package/dist/server/services/git-hosting/hosting-http-client.d.ts +20 -0
  536. package/dist/server/services/git-hosting/hosting-http-client.js +131 -0
  537. package/dist/server/services/git-hosting/request-cache.d.ts +20 -0
  538. package/dist/server/services/git-hosting/request-cache.js +68 -0
  539. package/dist/server/services/git-hosting/resolver.d.ts +32 -0
  540. package/dist/server/services/git-hosting/resolver.js +152 -0
  541. package/dist/server/services/git-hosting/router.d.ts +4 -0
  542. package/dist/server/services/git-hosting/router.js +105 -0
  543. package/dist/server/services/git-hosting/status-poller.d.ts +39 -0
  544. package/dist/server/services/git-hosting/status-poller.js +149 -0
  545. package/dist/server/services/git-hosting/types.d.ts +53 -0
  546. package/dist/server/services/git-hosting/types.js +75 -0
  547. package/dist/server/services/github-service.d.ts +339 -0
  548. package/dist/server/services/github-service.js +2109 -0
  549. package/dist/server/services/quota-fetcher/manifest.d.ts +4 -0
  550. package/dist/server/services/quota-fetcher/manifest.js +52 -0
  551. package/dist/server/services/quota-fetcher/provider.d.ts +17 -0
  552. package/dist/server/services/quota-fetcher/provider.js +2 -0
  553. package/dist/server/services/quota-fetcher/providers/claude.d.ts +26 -0
  554. package/dist/server/services/quota-fetcher/providers/claude.js +217 -0
  555. package/dist/server/services/quota-fetcher/providers/codex.d.ts +23 -0
  556. package/dist/server/services/quota-fetcher/providers/codex.js +211 -0
  557. package/dist/server/services/quota-fetcher/providers/copilot.d.ts +17 -0
  558. package/dist/server/services/quota-fetcher/providers/copilot.js +75 -0
  559. package/dist/server/services/quota-fetcher/providers/cursor.d.ts +17 -0
  560. package/dist/server/services/quota-fetcher/providers/cursor.js +123 -0
  561. package/dist/server/services/quota-fetcher/providers/grok.d.ts +18 -0
  562. package/dist/server/services/quota-fetcher/providers/grok.js +89 -0
  563. package/dist/server/services/quota-fetcher/providers/kimi.d.ts +20 -0
  564. package/dist/server/services/quota-fetcher/providers/kimi.js +89 -0
  565. package/dist/server/services/quota-fetcher/providers/minimax.d.ts +29 -0
  566. package/dist/server/services/quota-fetcher/providers/minimax.js +227 -0
  567. package/dist/server/services/quota-fetcher/providers/zai.d.ts +17 -0
  568. package/dist/server/services/quota-fetcher/providers/zai.js +58 -0
  569. package/dist/server/services/quota-fetcher/service.d.ts +28 -0
  570. package/dist/server/services/quota-fetcher/service.js +58 -0
  571. package/dist/server/services/quota-fetcher/usage.d.ts +22 -0
  572. package/dist/server/services/quota-fetcher/usage.js +49 -0
  573. package/dist/server/terminal/activity/terminal-activity-tracker.d.ts +20 -0
  574. package/dist/server/terminal/activity/terminal-activity-tracker.js +59 -0
  575. package/dist/server/terminal/agent-hooks/agent-hook-installer.d.ts +62 -0
  576. package/dist/server/terminal/agent-hooks/agent-hook-installer.js +117 -0
  577. package/dist/server/terminal/agent-hooks/claude/claude-settings.d.ts +7 -0
  578. package/dist/server/terminal/agent-hooks/claude/claude-settings.js +88 -0
  579. package/dist/server/terminal/agent-hooks/claude/claude.d.ts +4 -0
  580. package/dist/server/terminal/agent-hooks/claude/claude.js +47 -0
  581. package/dist/server/terminal/agent-hooks/codex/codex-settings.d.ts +7 -0
  582. package/dist/server/terminal/agent-hooks/codex/codex-settings.js +99 -0
  583. package/dist/server/terminal/agent-hooks/codex/codex.d.ts +4 -0
  584. package/dist/server/terminal/agent-hooks/codex/codex.js +30 -0
  585. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.d.ts +4 -0
  586. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.js +46 -0
  587. package/dist/server/terminal/agent-hooks/opencode/opencode.d.ts +3 -0
  588. package/dist/server/terminal/agent-hooks/opencode/opencode.js +23 -0
  589. package/dist/server/terminal/agent-hooks/provider-registry.d.ts +24 -0
  590. package/dist/server/terminal/agent-hooks/provider-registry.js +36 -0
  591. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.d.ts +10 -0
  592. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.js +26 -0
  593. package/dist/server/terminal/shell-integration/zsh/.zshenv +17 -0
  594. package/dist/server/terminal/shell-integration/zsh/otto-integration.zsh +32 -0
  595. package/dist/server/terminal/terminal-capture.d.ts +12 -0
  596. package/dist/server/terminal/terminal-capture.js +43 -0
  597. package/dist/server/terminal/terminal-manager-factory.d.ts +6 -0
  598. package/dist/server/terminal/terminal-manager-factory.js +5 -0
  599. package/dist/server/terminal/terminal-manager.d.ts +78 -0
  600. package/dist/server/terminal/terminal-manager.js +319 -0
  601. package/dist/server/terminal/terminal-output-coalescer.d.ts +34 -0
  602. package/dist/server/terminal/terminal-output-coalescer.js +73 -0
  603. package/dist/server/terminal/terminal-restore.d.ts +18 -0
  604. package/dist/server/terminal/terminal-restore.js +52 -0
  605. package/dist/server/terminal/terminal-session-controller.d.ts +85 -0
  606. package/dist/server/terminal/terminal-session-controller.js +819 -0
  607. package/dist/server/terminal/terminal-ts-loader.mjs +20 -0
  608. package/dist/server/terminal/terminal-worker-process.d.ts +2 -0
  609. package/dist/server/terminal/terminal-worker-process.js +304 -0
  610. package/dist/server/terminal/terminal-worker-protocol.d.ts +119 -0
  611. package/dist/server/terminal/terminal-worker-protocol.js +2 -0
  612. package/dist/server/terminal/terminal.d.ts +151 -0
  613. package/dist/server/terminal/terminal.js +1155 -0
  614. package/dist/server/terminal/worker-terminal-manager.d.ts +20 -0
  615. package/dist/server/terminal/worker-terminal-manager.js +688 -0
  616. package/dist/server/utils/build-metadata-prompt.d.ts +19 -0
  617. package/dist/server/utils/build-metadata-prompt.js +29 -0
  618. package/dist/server/utils/checkout-git.d.ts +253 -0
  619. package/dist/server/utils/checkout-git.js +2241 -0
  620. package/dist/server/utils/directory-suggestions.d.ts +26 -0
  621. package/dist/server/utils/directory-suggestions.js +830 -0
  622. package/dist/server/utils/git-rev-parse-path.d.ts +3 -0
  623. package/dist/server/utils/git-rev-parse-path.js +21 -0
  624. package/dist/server/utils/github-remote.d.ts +9 -0
  625. package/dist/server/utils/github-remote.js +62 -0
  626. package/dist/server/utils/otto-config-file.d.ts +30 -0
  627. package/dist/server/utils/otto-config-file.js +90 -0
  628. package/dist/server/utils/path.d.ts +18 -0
  629. package/dist/server/utils/path.js +123 -0
  630. package/dist/server/utils/project-icon.d.ts +39 -0
  631. package/dist/server/utils/project-icon.js +364 -0
  632. package/dist/server/utils/promise-timeout.d.ts +9 -0
  633. package/dist/server/utils/promise-timeout.js +25 -0
  634. package/dist/server/utils/run-git-command.d.ts +37 -0
  635. package/dist/server/utils/run-git-command.js +232 -0
  636. package/dist/server/utils/spawn.d.ts +25 -0
  637. package/dist/server/utils/spawn.js +59 -0
  638. package/dist/server/utils/string-command-shell.d.ts +13 -0
  639. package/dist/server/utils/string-command-shell.js +37 -0
  640. package/dist/server/utils/tree-kill.d.ts +18 -0
  641. package/dist/server/utils/tree-kill.js +77 -0
  642. package/dist/server/utils/windows-command.d.ts +15 -0
  643. package/dist/server/utils/windows-command.js +41 -0
  644. package/dist/server/utils/worktree-metadata.d.ts +39 -0
  645. package/dist/server/utils/worktree-metadata.js +174 -0
  646. package/dist/server/utils/worktree.d.ts +205 -0
  647. package/dist/server/utils/worktree.js +1120 -0
  648. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css +1 -0
  649. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.br +0 -0
  650. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.gz +0 -0
  651. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-a25c6055b348629689f75618db2c83e1.js +1 -0
  652. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-a25c6055b348629689f75618db2c83e1.js.br +0 -0
  653. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-a25c6055b348629689f75618db2c83e1.js.gz +0 -0
  654. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7dc26ea1611eb9d7c2971a6745e5bf5c.js +1 -0
  655. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7dc26ea1611eb9d7c2971a6745e5bf5c.js.br +0 -0
  656. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7dc26ea1611eb9d7c2971a6745e5bf5c.js.gz +0 -0
  657. package/dist/server/web-ui/_expo/static/js/web/index-ea91f496cee180fa5bf308c8cc177646.js +3199 -0
  658. package/dist/server/web-ui/_expo/static/js/web/index-ea91f496cee180fa5bf308c8cc177646.js.br +0 -0
  659. package/dist/server/web-ui/_expo/static/js/web/index-ea91f496cee180fa5bf308c8cc177646.js.gz +0 -0
  660. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-b6b853a967343babf305512fe8c5958c.js +1 -0
  661. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-b6b853a967343babf305512fe8c5958c.js.br +0 -0
  662. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-b6b853a967343babf305512fe8c5958c.js.gz +0 -0
  663. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-17223e158406802adc686d02d946573d.js +3 -0
  664. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-17223e158406802adc686d02d946573d.js.br +0 -0
  665. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-17223e158406802adc686d02d946573d.js.gz +0 -0
  666. package/dist/server/web-ui/apple-touch-icon.png +0 -0
  667. package/dist/server/web-ui/assets/__node_modules/@expo-google-fonts/inter/400Regular/Inter_400Regular.51b6ad87261f18b6433ec52871ddfabc.ttf +0 -0
  668. package/dist/server/web-ui/assets/__node_modules/@expo-google-fonts/jetbrains-mono/400Regular/JetBrainsMono_400Regular.a0147b5ab9e4946e81879aef45313def.ttf +0 -0
  669. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png +0 -0
  670. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png +0 -0
  671. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png +0 -0
  672. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png +0 -0
  673. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png +0 -0
  674. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png +0 -0
  675. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png +0 -0
  676. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png +0 -0
  677. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png +0 -0
  678. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png +0 -0
  679. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png +0 -0
  680. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png +0 -0
  681. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png +0 -0
  682. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png +0 -0
  683. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png +0 -0
  684. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png +0 -0
  685. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png +0 -0
  686. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png +0 -0
  687. package/dist/server/web-ui/assets/assets/images/editor-apps/antigravity.6e91a685c33435e0b466a56db86cf141.png +0 -0
  688. package/dist/server/web-ui/assets/assets/images/editor-apps/clion.baa1f4eb572e962a6117bdbee95749e4.png +0 -0
  689. package/dist/server/web-ui/assets/assets/images/editor-apps/cursor.c31d6bce4fe9aadc3fe59962f4c4fcf3.png +0 -0
  690. package/dist/server/web-ui/assets/assets/images/editor-apps/finder.7f68fc2c475621a672e1be09309d5567.png +0 -0
  691. package/dist/server/web-ui/assets/assets/images/editor-apps/goland.0796ab2b9be2637fd1cdcde891fad3ca.png +0 -0
  692. package/dist/server/web-ui/assets/assets/images/editor-apps/intellij-idea.33bc9ff9c0815d8ad43f618c8c244401.png +0 -0
  693. package/dist/server/web-ui/assets/assets/images/editor-apps/phpstorm.c60b33bc7a8309143d232e14b76554c5.png +0 -0
  694. package/dist/server/web-ui/assets/assets/images/editor-apps/pycharm.88f25ac484989c45c25323e0adccfa9f.png +0 -0
  695. package/dist/server/web-ui/assets/assets/images/editor-apps/rider.1a1091dc3a0ede0461f0aa38a54f080a.png +0 -0
  696. package/dist/server/web-ui/assets/assets/images/editor-apps/rubymine.0e5b66fd7d43f8cbac0f05bba97c9a21.png +0 -0
  697. package/dist/server/web-ui/assets/assets/images/editor-apps/rustrover.3590ef05482369f41d3484c90272570d.png +0 -0
  698. package/dist/server/web-ui/assets/assets/images/editor-apps/vscode.832bdb4c685d930f1c864c793703600b.png +0 -0
  699. package/dist/server/web-ui/assets/assets/images/editor-apps/webstorm.aa5dc2cd8c20cc0a155c4c5c5ab3c5f5.png +0 -0
  700. package/dist/server/web-ui/assets/assets/images/editor-apps/zed.f3a670b7f9aa226da4fe53fb86f1abbd.png +0 -0
  701. package/dist/server/web-ui/assets/assets/images/favicon-dark-attention.3b2c331d11122d8f743c73a5878593be.png +0 -0
  702. package/dist/server/web-ui/assets/assets/images/favicon-dark-running.6077c2ab71021b31c82a42e0b42ad837.png +0 -0
  703. package/dist/server/web-ui/assets/assets/images/favicon-dark.12984efe6d435a13794a74cd2f858dcd.png +0 -0
  704. package/dist/server/web-ui/assets/assets/images/favicon-light-attention.3b2c331d11122d8f743c73a5878593be.png +0 -0
  705. package/dist/server/web-ui/assets/assets/images/favicon-light-running.6077c2ab71021b31c82a42e0b42ad837.png +0 -0
  706. package/dist/server/web-ui/assets/assets/images/favicon-light.12984efe6d435a13794a74cd2f858dcd.png +0 -0
  707. package/dist/server/web-ui/assets/assets/images/notification-icon.2394c3b427c0f5ee2bb84864d8fb0f45.png +0 -0
  708. package/dist/server/web-ui/favicon.ico +0 -0
  709. package/dist/server/web-ui/index.html +147 -0
  710. package/dist/server/web-ui/index.html.br +0 -0
  711. package/dist/server/web-ui/index.html.gz +0 -0
  712. package/dist/server/web-ui/manifest.json +27 -0
  713. package/dist/server/web-ui/manifest.json.br +0 -0
  714. package/dist/server/web-ui/manifest.json.gz +0 -0
  715. package/dist/server/web-ui/metadata.json +1 -0
  716. package/dist/server/web-ui/metadata.json.br +1 -0
  717. package/dist/server/web-ui/metadata.json.gz +0 -0
  718. package/dist/server/web-ui/pwa-icon-192.png +0 -0
  719. package/dist/server/web-ui/pwa-icon-512.png +0 -0
  720. package/dist/server/web-ui/robots.txt +2 -0
  721. package/dist/src/executable-resolution/executable-resolution.js +118 -0
  722. package/dist/src/executable-resolution/windows.js +65 -0
  723. package/dist/src/server/agent/provider-launch-config.js +167 -0
  724. package/dist/src/server/otto-env.js +53 -0
  725. package/dist/src/server/otto-home.js +19 -0
  726. package/dist/src/server/persisted-config.js +471 -0
  727. package/dist/src/server/pid-lock.js +170 -0
  728. package/dist/src/server/private-files.js +37 -0
  729. package/dist/src/server/speech/providers/local/sherpa/sherpa-runtime-env.js +84 -0
  730. package/dist/src/terminal/shell-integration/zsh/.zshenv +17 -0
  731. package/dist/src/terminal/shell-integration/zsh/otto-integration.zsh +32 -0
  732. package/dist/src/utils/spawn.js +59 -0
  733. package/dist/src/utils/windows-command.js +41 -0
  734. package/package.json +118 -0
@@ -0,0 +1,2439 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import path from "node:path";
5
+ import { Readable, Writable } from "node:stream";
6
+ import { terminateWithTreeKill } from "../../../utils/tree-kill.js";
7
+ import { ClientSideConnection, PROTOCOL_VERSION, } from "@agentclientprotocol/sdk";
8
+ import { getAgentStreamEventTurnId, } from "../agent-sdk-types.js";
9
+ import { importSessionFromPersistence } from "../provider-session-import.js";
10
+ import { checkProviderLaunchAvailable, createProviderEnvSpec, resolveProviderLaunch, } from "../provider-launch-config.js";
11
+ import { renderPromptAttachmentAsText } from "../prompt-attachments.js";
12
+ import { appendOrReplaceGrowingAssistantMessage, runProviderTurn } from "./provider-runner.js";
13
+ import { buildStringCommandShellInvocation, createStringCommandShellEnvOverlay, } from "../../../utils/string-command-shell.js";
14
+ import { spawnProcess } from "../../../utils/spawn.js";
15
+ import { toDiagnosticErrorMessage, truncateForDiagnostic, } from "./diagnostic-utils.js";
16
+ import { withTimeout } from "../../../utils/promise-timeout.js";
17
+ function assertChildWithPipes(child) {
18
+ if (!child.stdin || !child.stdout || !child.stderr) {
19
+ throw new Error("Child process did not expose stdio pipes");
20
+ }
21
+ }
22
+ function isRecord(value) {
23
+ return value != null && typeof value === "object" && !Array.isArray(value);
24
+ }
25
+ function isACPError(value) {
26
+ return isRecord(value) && typeof value.message === "string" && typeof value.code === "number";
27
+ }
28
+ function extractACPErrorDataMessage(data) {
29
+ if (!isRecord(data)) {
30
+ return null;
31
+ }
32
+ for (const key of ["details", "errorMessage", "message", "detail", "title"]) {
33
+ const value = data[key];
34
+ if (typeof value === "string" && value.trim()) {
35
+ return value.trim();
36
+ }
37
+ }
38
+ return extractACPErrorDataMessage(data.error);
39
+ }
40
+ export function summarizeACPRequestError(error) {
41
+ // Promise rejections are untyped, but the ACP SDK rejects JSON-RPC failures as response.error.
42
+ if (isACPError(error)) {
43
+ const code = String(error.code);
44
+ const detail = extractACPErrorDataMessage(error.data);
45
+ const message = detail && detail !== error.message ? `${error.message}: ${detail}` : error.message;
46
+ const data = error.data === undefined ? "" : ` | data=${JSON.stringify(error.data)}`;
47
+ return {
48
+ message,
49
+ code,
50
+ diagnostic: `${message} | code=${code}${data}`,
51
+ };
52
+ }
53
+ if (error instanceof Error) {
54
+ return { message: error.message };
55
+ }
56
+ return { message: String(error) };
57
+ }
58
+ function toACPRequestError(error) {
59
+ if (!isACPError(error)) {
60
+ return error instanceof Error ? error : new Error(String(error));
61
+ }
62
+ const summary = summarizeACPRequestError(error);
63
+ const next = new Error(summary.message);
64
+ next.name = "ACPRequestError";
65
+ return next;
66
+ }
67
+ function resolveTerminalCommand(command, args) {
68
+ if (args && args.length > 0) {
69
+ return { command, args };
70
+ }
71
+ if (!/\s/.test(command.trim())) {
72
+ return { command, args: [] };
73
+ }
74
+ const shell = buildStringCommandShellInvocation({ command, windowsShell: "cmd" });
75
+ return { command: shell.shell, args: shell.args, shell: false };
76
+ }
77
+ function formatDurationMs(startedAt) {
78
+ return `${Math.max(0, Date.now() - startedAt)}ms`;
79
+ }
80
+ function pushACPStderrRow(rows, stderrChunks) {
81
+ const stderr = stderrChunks.join("").trim();
82
+ if (!stderr) {
83
+ return;
84
+ }
85
+ rows.push({
86
+ label: "ACP stderr",
87
+ value: truncateForDiagnostic(stderr),
88
+ });
89
+ }
90
+ export const DEFAULT_ACP_CAPABILITIES = {
91
+ supportsStreaming: true,
92
+ supportsSessionPersistence: true,
93
+ // ACP agents can list prior sessions via `session/list`. The runtime probe in
94
+ // listImportableSessions returns nothing for agents that don't advertise the
95
+ // capability, so enabling this here only makes the daemon query them.
96
+ supportsSessionListing: true,
97
+ supportsDynamicModes: true,
98
+ supportsMcpServers: true,
99
+ supportsReasoningStream: true,
100
+ supportsToolInvocations: true,
101
+ supportsRewindConversation: false,
102
+ supportsRewindFiles: false,
103
+ supportsRewindBoth: false,
104
+ };
105
+ const ACP_CLIENT_CAPABILITIES = {
106
+ fs: {
107
+ readTextFile: true,
108
+ writeTextFile: true,
109
+ },
110
+ terminal: true,
111
+ };
112
+ // Suppress interactive auth side-effects (e.g. Gemini CLI opening a Google
113
+ // sign-in URL in the browser) when probing an ACP agent for models/modes.
114
+ // NO_BROWSER is honored by Gemini CLI; other ACP agents ignore it.
115
+ const PROBE_ENV = { NO_BROWSER: "true" };
116
+ const ACP_CATALOG_TIMEOUT_MS = 60000;
117
+ const ACP_DIAGNOSTIC_PHASE_TIMEOUT_MS = 20000;
118
+ function summarizeMalformedACPStdoutError(error) {
119
+ return {
120
+ type: error instanceof Error ? error.name : typeof error,
121
+ message: "ACP stdout line was not valid JSON",
122
+ };
123
+ }
124
+ function normalizeACPIncomingMessage(message) {
125
+ if ("id" in message &&
126
+ !("method" in message) &&
127
+ typeof message.id === "string" &&
128
+ /^\d+$/.test(message.id)) {
129
+ const numericId = Number(message.id);
130
+ if (Number.isSafeInteger(numericId)) {
131
+ return {
132
+ ...message,
133
+ // COMPAT(deepseek-tui-acp-id): added v0.1.78, remove after 2026-11-19
134
+ // once the ACP SDK accepts stringified numeric response IDs.
135
+ id: numericId,
136
+ };
137
+ }
138
+ }
139
+ return message;
140
+ }
141
+ export function createLoggedNdJsonStream(output, input, options) {
142
+ const textEncoder = new TextEncoder();
143
+ const textDecoder = new TextDecoder();
144
+ const readable = new ReadableStream({
145
+ async start(controller) {
146
+ let content = "";
147
+ const reader = input.getReader();
148
+ try {
149
+ while (true) {
150
+ const { value, done } = await reader.read();
151
+ if (done) {
152
+ break;
153
+ }
154
+ if (!value) {
155
+ continue;
156
+ }
157
+ content += textDecoder.decode(value, { stream: true });
158
+ const lines = content.split("\n");
159
+ content = lines.pop() || "";
160
+ for (const line of lines) {
161
+ const trimmedLine = line.trim();
162
+ if (!trimmedLine) {
163
+ continue;
164
+ }
165
+ try {
166
+ const message = JSON.parse(trimmedLine);
167
+ controller.enqueue(normalizeACPIncomingMessage(message));
168
+ }
169
+ catch (error) {
170
+ options.logger.warn({
171
+ err: summarizeMalformedACPStdoutError(error),
172
+ provider: options.provider,
173
+ }, "ACP agent emitted non-JSON stdout; ignoring line");
174
+ }
175
+ }
176
+ }
177
+ }
178
+ finally {
179
+ reader.releaseLock();
180
+ controller.close();
181
+ }
182
+ },
183
+ });
184
+ const writable = new WritableStream({
185
+ async write(message) {
186
+ const writer = output.getWriter();
187
+ try {
188
+ await writer.write(textEncoder.encode(`${JSON.stringify(message)}\n`));
189
+ }
190
+ finally {
191
+ writer.releaseLock();
192
+ }
193
+ },
194
+ });
195
+ return { readable, writable };
196
+ }
197
+ export function mapACPUsage(usage) {
198
+ if (!usage) {
199
+ return undefined;
200
+ }
201
+ return {
202
+ inputTokens: usage.inputTokens ?? undefined,
203
+ outputTokens: usage.outputTokens ?? undefined,
204
+ cachedInputTokens: usage.cachedReadTokens ?? undefined,
205
+ };
206
+ }
207
+ export function resolveACPModeSelection({ modeId, availableModes, configOptions, }) {
208
+ const configOption = findSelectConfigOption({ configOptions, category: "mode" });
209
+ return {
210
+ availableMode: availableModes.find((mode) => mode.id === modeId) ?? null,
211
+ configOption,
212
+ configChoice: findSelectConfigChoice({ option: configOption, value: modeId }),
213
+ hasAvailableModes: availableModes.length > 0,
214
+ };
215
+ }
216
+ export function resolveACPModelSelection({ modelId, availableModels, configOptions, }) {
217
+ const configOption = findSelectConfigOption({ configOptions, category: "model" });
218
+ return {
219
+ availableModel: availableModels?.find((model) => model.modelId === modelId) ?? null,
220
+ configOption,
221
+ configChoice: findSelectConfigChoice({ option: configOption, value: modelId }),
222
+ hasAvailableModels: Boolean(availableModels?.length),
223
+ };
224
+ }
225
+ export function deriveModesFromACP(fallbackModes, modeState, configOptions) {
226
+ if (modeState?.availableModes?.length) {
227
+ return {
228
+ modes: modeState.availableModes.map((mode) => ({
229
+ id: mode.id,
230
+ label: mode.name,
231
+ description: mode.description ?? undefined,
232
+ })),
233
+ currentModeId: modeState.currentModeId ?? null,
234
+ };
235
+ }
236
+ const modeOption = findSelectConfigOption({ configOptions, category: "mode" });
237
+ if (modeOption) {
238
+ const flatOptions = flattenSelectOptions(modeOption.options);
239
+ return {
240
+ modes: flatOptions.map((option) => ({
241
+ id: option.value,
242
+ label: option.name,
243
+ description: option.description ?? undefined,
244
+ })),
245
+ currentModeId: modeOption.currentValue,
246
+ };
247
+ }
248
+ return {
249
+ modes: fallbackModes,
250
+ currentModeId: null,
251
+ };
252
+ }
253
+ export function deriveModelDefinitionsFromACP(provider, models, configOptions) {
254
+ const thinkingOptions = deriveSelectorOptions(configOptions, "thought_level");
255
+ const defaultThinkingOptionId = thinkingOptions.find((option) => option.isDefault)?.id ?? null;
256
+ if (models?.availableModels?.length) {
257
+ return models.availableModels.map((model) => ({
258
+ provider,
259
+ id: model.modelId,
260
+ label: model.name,
261
+ description: model.description ?? undefined,
262
+ isDefault: model.modelId === models.currentModelId,
263
+ thinkingOptions: thinkingOptions.length > 0 ? thinkingOptions : undefined,
264
+ defaultThinkingOptionId: defaultThinkingOptionId ?? undefined,
265
+ }));
266
+ }
267
+ const modelOptions = deriveSelectorOptions(configOptions, "model");
268
+ return modelOptions.map((option) => ({
269
+ provider,
270
+ id: option.id,
271
+ label: option.label,
272
+ description: option.description,
273
+ isDefault: option.isDefault,
274
+ thinkingOptions: thinkingOptions.length > 0 ? thinkingOptions : undefined,
275
+ defaultThinkingOptionId: defaultThinkingOptionId ?? undefined,
276
+ metadata: option.metadata,
277
+ }));
278
+ }
279
+ export function deriveFeaturesFromACP(configOptions, featureOptions) {
280
+ return featureOptions.flatMap((featureOption) => {
281
+ const option = findSelectConfigFeatureOption(configOptions, featureOption);
282
+ if (!option) {
283
+ return [];
284
+ }
285
+ return [
286
+ {
287
+ type: "select",
288
+ id: featureOption.id,
289
+ label: featureOption.label,
290
+ description: featureOption.description,
291
+ tooltip: featureOption.tooltip,
292
+ icon: featureOption.icon,
293
+ value: option.currentValue ?? null,
294
+ options: deriveConfigFeatureSelectOptions(option, featureOption),
295
+ },
296
+ ];
297
+ });
298
+ }
299
+ export class ACPAgentClient {
300
+ constructor(options) {
301
+ this.provider = options.provider;
302
+ this.terminateProcess = options.terminateProcess ?? terminateWithTreeKill;
303
+ this.capabilities = options.capabilities ?? DEFAULT_ACP_CAPABILITIES;
304
+ this.logger = options.logger.child({
305
+ module: "agent",
306
+ provider: options.provider,
307
+ });
308
+ this.runtimeSettings = options.runtimeSettings;
309
+ this.defaultCommand = options.defaultCommand;
310
+ this.defaultModes = options.defaultModes ?? [];
311
+ this.modelTransformer = options.modelTransformer;
312
+ this.sessionResponseTransformer = options.sessionResponseTransformer;
313
+ this.configOptionsTransformer = options.configOptionsTransformer;
314
+ this.configFeatureOptions = options.configFeatureOptions ?? [];
315
+ this.modeIdTransformer = options.modeIdTransformer;
316
+ this.toolSnapshotTransformer = options.toolSnapshotTransformer;
317
+ this.providerModeWriter = options.providerModeWriter;
318
+ this.beforeModeWriter = options.beforeModeWriter;
319
+ this.thinkingOptionWriter = options.thinkingOptionWriter;
320
+ this.waitForInitialCommands = options.waitForInitialCommands ?? false;
321
+ this.initialCommandsWaitTimeoutMs = options.initialCommandsWaitTimeoutMs ?? 1500;
322
+ this.extensionCommandsParser = options.extensionCommandsParser;
323
+ }
324
+ async createSession(config, launchContext) {
325
+ this.assertProvider(config);
326
+ const session = new ACPAgentSession({ ...config, provider: this.provider }, {
327
+ provider: this.provider,
328
+ logger: this.logger,
329
+ runtimeSettings: this.runtimeSettings,
330
+ defaultCommand: this.defaultCommand,
331
+ defaultModes: this.defaultModes,
332
+ modelTransformer: this.modelTransformer,
333
+ sessionResponseTransformer: this.sessionResponseTransformer,
334
+ configOptionsTransformer: this.configOptionsTransformer,
335
+ configFeatureOptions: this.configFeatureOptions,
336
+ modeIdTransformer: this.modeIdTransformer,
337
+ toolSnapshotTransformer: this.toolSnapshotTransformer,
338
+ providerModeWriter: this.providerModeWriter,
339
+ beforeModeWriter: this.beforeModeWriter,
340
+ thinkingOptionWriter: this.thinkingOptionWriter,
341
+ capabilities: this.capabilities,
342
+ agentId: launchContext?.agentId,
343
+ launchEnv: launchContext?.env,
344
+ extensionCommandsParser: this.extensionCommandsParser,
345
+ waitForInitialCommands: this.waitForInitialCommands,
346
+ initialCommandsWaitTimeoutMs: this.initialCommandsWaitTimeoutMs,
347
+ });
348
+ await session.initializeNewSession();
349
+ return session;
350
+ }
351
+ async resumeSession(handle, overrides, launchContext) {
352
+ if (handle.provider !== this.provider) {
353
+ throw new Error(`Cannot resume ${handle.provider} handle with ${this.provider} provider`);
354
+ }
355
+ const storedConfig = coerceSessionConfigMetadata(handle.metadata);
356
+ const cwd = overrides?.cwd ?? storedConfig.cwd;
357
+ if (!cwd) {
358
+ throw new Error(`${this.provider} resume requires the original working directory`);
359
+ }
360
+ const mergedConfig = {
361
+ ...storedConfig,
362
+ ...overrides,
363
+ provider: this.provider,
364
+ cwd,
365
+ };
366
+ const session = new ACPAgentSession(mergedConfig, {
367
+ provider: this.provider,
368
+ logger: this.logger,
369
+ runtimeSettings: this.runtimeSettings,
370
+ defaultCommand: this.defaultCommand,
371
+ defaultModes: this.defaultModes,
372
+ modelTransformer: this.modelTransformer,
373
+ sessionResponseTransformer: this.sessionResponseTransformer,
374
+ configOptionsTransformer: this.configOptionsTransformer,
375
+ configFeatureOptions: this.configFeatureOptions,
376
+ modeIdTransformer: this.modeIdTransformer,
377
+ toolSnapshotTransformer: this.toolSnapshotTransformer,
378
+ providerModeWriter: this.providerModeWriter,
379
+ beforeModeWriter: this.beforeModeWriter,
380
+ thinkingOptionWriter: this.thinkingOptionWriter,
381
+ capabilities: this.capabilities,
382
+ handle,
383
+ agentId: launchContext?.agentId,
384
+ launchEnv: launchContext?.env,
385
+ extensionCommandsParser: this.extensionCommandsParser,
386
+ waitForInitialCommands: this.waitForInitialCommands,
387
+ initialCommandsWaitTimeoutMs: this.initialCommandsWaitTimeoutMs,
388
+ });
389
+ await session.initializeResumedSession();
390
+ return session;
391
+ }
392
+ async fetchCatalog(options) {
393
+ const cwd = options.scope === "global" ? homedir() : options.cwd;
394
+ const timeoutMs = options.timeoutMs ?? ACP_CATALOG_TIMEOUT_MS;
395
+ let probe = null;
396
+ try {
397
+ const catalogProbe = (async () => {
398
+ const initializedProbe = await this.spawnProcess(PROBE_ENV, {
399
+ initializeTimeoutMs: timeoutMs,
400
+ onSpawned: (spawned) => {
401
+ probe = spawned;
402
+ },
403
+ });
404
+ probe = initializedProbe;
405
+ const response = await this.runACPRequest(() => initializedProbe.connection.newSession({
406
+ cwd,
407
+ mcpServers: [],
408
+ }));
409
+ const transformed = this.transformSessionResponse(response);
410
+ const models = deriveModelDefinitionsFromACP(this.provider, transformed.models, transformed.configOptions);
411
+ const modeInfo = deriveModesFromACP(this.defaultModes, transformed.modes, transformed.configOptions);
412
+ return {
413
+ models: this.modelTransformer ? this.modelTransformer(models) : models,
414
+ modes: modeInfo.modes,
415
+ };
416
+ })();
417
+ return await withTimeout(catalogProbe, timeoutMs, `ACP catalog probe timed out after ${timeoutMs}ms`);
418
+ }
419
+ finally {
420
+ if (probe) {
421
+ await this.closeProbe(probe);
422
+ }
423
+ }
424
+ }
425
+ async listFeatures(config) {
426
+ if (this.configFeatureOptions.length === 0) {
427
+ return [];
428
+ }
429
+ this.assertProvider(config);
430
+ const probe = await this.spawnProcess(PROBE_ENV);
431
+ try {
432
+ const response = await this.runACPRequest(() => probe.connection.newSession({
433
+ cwd: config.cwd,
434
+ mcpServers: [],
435
+ }));
436
+ const transformed = this.transformSessionResponse(response);
437
+ return deriveFeaturesFromACP(transformed.configOptions, this.configFeatureOptions);
438
+ }
439
+ finally {
440
+ await this.closeProbe(probe);
441
+ }
442
+ }
443
+ async listImportableSessions(options) {
444
+ const probe = await this.spawnProcess(PROBE_ENV);
445
+ try {
446
+ if (!probe.initialize.agentCapabilities?.sessionCapabilities?.list) {
447
+ return [];
448
+ }
449
+ const sessions = [];
450
+ let cursor;
451
+ for (;;) {
452
+ const page = await this.runACPRequest(() => probe.connection.listSessions({
453
+ ...(cursor ? { cursor } : {}),
454
+ // Filter by working directory at the source. Without this the agent
455
+ // returns globally-recent sessions, which the `limit` below can
456
+ // truncate before the current directory's sessions are reached.
457
+ ...(options?.cwd ? { cwd: options.cwd } : {}),
458
+ }));
459
+ for (const session of page.sessions) {
460
+ sessions.push({
461
+ providerHandleId: session.sessionId,
462
+ cwd: session.cwd,
463
+ title: session.title ?? null,
464
+ firstPromptPreview: null,
465
+ lastPromptPreview: null,
466
+ lastActivityAt: session.updatedAt ? new Date(session.updatedAt) : new Date(0),
467
+ });
468
+ }
469
+ cursor = page.nextCursor ?? null;
470
+ if (!cursor)
471
+ break;
472
+ if (options?.limit && sessions.length >= options.limit)
473
+ break;
474
+ }
475
+ return typeof options?.limit === "number" ? sessions.slice(0, options.limit) : sessions;
476
+ }
477
+ finally {
478
+ await this.closeProbe(probe);
479
+ }
480
+ }
481
+ async importSession(input, context) {
482
+ return importSessionFromPersistence({
483
+ provider: this.provider,
484
+ request: input,
485
+ context,
486
+ resumeSession: this.resumeSession.bind(this),
487
+ });
488
+ }
489
+ async isAvailable() {
490
+ try {
491
+ await this.resolveLaunchCommand();
492
+ return true;
493
+ }
494
+ catch {
495
+ return false;
496
+ }
497
+ }
498
+ async spawnProcess(launchEnv, options) {
499
+ const transport = await this.spawnTransport(launchEnv);
500
+ const probe = {
501
+ child: transport.child,
502
+ connection: transport.connection,
503
+ stderrChunks: transport.stderrChunks,
504
+ };
505
+ options?.onSpawned?.(probe);
506
+ try {
507
+ const initialize = await this.initializeTransport(transport, options?.initializeTimeoutMs);
508
+ const initializedProbe = {
509
+ ...probe,
510
+ initialize,
511
+ };
512
+ probe.initialize = initialize;
513
+ return initializedProbe;
514
+ }
515
+ catch (error) {
516
+ await terminateChildProcess(transport.child, 2000, this.terminateProcess);
517
+ throw error;
518
+ }
519
+ }
520
+ async spawnTransport(launchEnv) {
521
+ const { command, args } = await this.resolveLaunchCommand();
522
+ const child = spawnProcess(command, args, {
523
+ cwd: process.cwd(),
524
+ ...createProviderEnvSpec({
525
+ runtimeSettings: this.runtimeSettings,
526
+ overlays: [launchEnv],
527
+ }),
528
+ stdio: ["pipe", "pipe", "pipe"],
529
+ });
530
+ assertChildWithPipes(child);
531
+ const stderrChunks = [];
532
+ child.stderr.on("data", (chunk) => {
533
+ stderrChunks.push(chunk.toString());
534
+ });
535
+ const spawnErrorPromise = new Promise((_, reject) => {
536
+ child.once("error", (error) => {
537
+ const stderr = stderrChunks.join("").trim();
538
+ reject(new Error(stderr ? `${String(error)}\n${stderr}` : String(error)));
539
+ });
540
+ });
541
+ const spawnReadyPromise = new Promise((resolve) => {
542
+ child.once("spawn", () => {
543
+ resolve();
544
+ });
545
+ });
546
+ const stream = createLoggedNdJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout), { logger: this.logger, provider: this.provider });
547
+ const connection = new ClientSideConnection(() => this.buildProbeClient(), stream);
548
+ return {
549
+ child,
550
+ connection,
551
+ stderrChunks,
552
+ spawnReady: spawnReadyPromise,
553
+ spawnError: spawnErrorPromise,
554
+ };
555
+ }
556
+ async initializeTransport(transport, initializeTimeoutMs) {
557
+ let timeout = null;
558
+ const initializeTimeoutPromise = initializeTimeoutMs
559
+ ? new Promise((_, reject) => {
560
+ timeout = setTimeout(() => {
561
+ reject(new Error(`ACP initialize timed out after ${initializeTimeoutMs}ms`));
562
+ }, initializeTimeoutMs);
563
+ })
564
+ : null;
565
+ try {
566
+ return await this.runACPRequest(() => Promise.race([
567
+ transport.connection.initialize({
568
+ protocolVersion: PROTOCOL_VERSION,
569
+ clientCapabilities: ACP_CLIENT_CAPABILITIES,
570
+ clientInfo: { name: "Otto", version: "dev" },
571
+ }),
572
+ transport.spawnError,
573
+ ...(initializeTimeoutPromise ? [initializeTimeoutPromise] : []),
574
+ ]));
575
+ }
576
+ finally {
577
+ if (timeout) {
578
+ clearTimeout(timeout);
579
+ }
580
+ }
581
+ }
582
+ buildProbeClient() {
583
+ return {
584
+ async requestPermission() {
585
+ return { outcome: { outcome: "cancelled" } };
586
+ },
587
+ async sessionUpdate() { },
588
+ async readTextFile(params) {
589
+ const content = await fs.readFile(params.path, "utf8");
590
+ return { content };
591
+ },
592
+ async writeTextFile(params) {
593
+ await fs.mkdir(path.dirname(params.path), { recursive: true });
594
+ await fs.writeFile(params.path, params.content, "utf8");
595
+ return {};
596
+ },
597
+ async createTerminal() {
598
+ throw new Error("ACP model probe does not support terminal execution");
599
+ },
600
+ };
601
+ }
602
+ async closeProbe(probe) {
603
+ try {
604
+ if (probe.initialize?.agentCapabilities?.sessionCapabilities?.close) {
605
+ // No active session to close here; ignore capability.
606
+ }
607
+ }
608
+ finally {
609
+ await terminateChildProcess(probe.child, 2000, this.terminateProcess);
610
+ }
611
+ }
612
+ async runACPRequest(request) {
613
+ try {
614
+ return await request();
615
+ }
616
+ catch (error) {
617
+ throw toACPRequestError(error);
618
+ }
619
+ }
620
+ async buildACPProbeDiagnosticRows(options = {}) {
621
+ const rows = [];
622
+ const phaseTimeoutMs = options.phaseTimeoutMs ?? ACP_DIAGNOSTIC_PHASE_TIMEOUT_MS;
623
+ const cwd = options.cwd ?? homedir();
624
+ let transport = null;
625
+ try {
626
+ const spawnStartedAt = Date.now();
627
+ try {
628
+ transport = await this.spawnTransport(PROBE_ENV);
629
+ await withTimeout(Promise.race([transport.spawnReady, transport.spawnError]), phaseTimeoutMs, `ACP spawn timed out after ${phaseTimeoutMs}ms`);
630
+ rows.push({
631
+ label: "ACP spawn",
632
+ value: `ok (${formatDurationMs(spawnStartedAt)})`,
633
+ });
634
+ }
635
+ catch (error) {
636
+ rows.push({
637
+ label: "ACP spawn",
638
+ value: `error: ${toDiagnosticErrorMessage(error)}`,
639
+ });
640
+ return rows;
641
+ }
642
+ const activeTransport = transport;
643
+ const initializeStartedAt = Date.now();
644
+ try {
645
+ await this.initializeTransport(activeTransport, phaseTimeoutMs);
646
+ rows.push({
647
+ label: "ACP initialize",
648
+ value: `ok (${formatDurationMs(initializeStartedAt)})`,
649
+ });
650
+ }
651
+ catch (error) {
652
+ rows.push({
653
+ label: "ACP initialize",
654
+ value: `error: ${toDiagnosticErrorMessage(error)}`,
655
+ });
656
+ pushACPStderrRow(rows, activeTransport.stderrChunks);
657
+ return rows;
658
+ }
659
+ const sessionStartedAt = Date.now();
660
+ try {
661
+ const response = await withTimeout(this.runACPRequest(() => activeTransport.connection.newSession({
662
+ cwd,
663
+ mcpServers: [],
664
+ })), phaseTimeoutMs, `ACP session/new timed out after ${phaseTimeoutMs}ms`);
665
+ const transformed = this.transformSessionResponse(response);
666
+ const models = deriveModelDefinitionsFromACP(this.provider, transformed.models, transformed.configOptions);
667
+ const modeInfo = deriveModesFromACP(this.defaultModes, transformed.modes, transformed.configOptions);
668
+ rows.push({
669
+ label: "ACP session/new",
670
+ value: `ok (${formatDurationMs(sessionStartedAt)}; models=${models.length}; modes=${modeInfo.modes.length})`,
671
+ });
672
+ }
673
+ catch (error) {
674
+ rows.push({
675
+ label: "ACP session/new",
676
+ value: `error: ${toDiagnosticErrorMessage(error)}`,
677
+ });
678
+ pushACPStderrRow(rows, activeTransport.stderrChunks);
679
+ return rows;
680
+ }
681
+ pushACPStderrRow(rows, activeTransport.stderrChunks);
682
+ return rows;
683
+ }
684
+ finally {
685
+ if (transport) {
686
+ const cleanupStartedAt = Date.now();
687
+ try {
688
+ await terminateChildProcess(transport.child, 2000, this.terminateProcess);
689
+ rows.push({
690
+ label: "ACP cleanup",
691
+ value: `ok (${formatDurationMs(cleanupStartedAt)})`,
692
+ });
693
+ }
694
+ catch (error) {
695
+ rows.push({
696
+ label: "ACP cleanup",
697
+ value: `error: ${toDiagnosticErrorMessage(error)}`,
698
+ });
699
+ }
700
+ }
701
+ }
702
+ }
703
+ async resolveLaunchCommand() {
704
+ const prefix = await resolveProviderLaunch({
705
+ commandConfig: this.runtimeSettings?.command,
706
+ defaultBinary: this.defaultCommand[0],
707
+ });
708
+ const availability = await checkProviderLaunchAvailable(prefix);
709
+ if (!availability.available) {
710
+ throw new Error(`${this.provider} command '${this.defaultCommand[0]}' not found`);
711
+ }
712
+ return {
713
+ command: prefix.command,
714
+ args: [...prefix.args, ...this.defaultCommand.slice(1)],
715
+ };
716
+ }
717
+ assertProvider(config) {
718
+ if (config.provider !== this.provider) {
719
+ throw new Error(`Expected ${this.provider} config, received ${config.provider}`);
720
+ }
721
+ }
722
+ transformSessionResponse(response) {
723
+ const transformed = this.sessionResponseTransformer
724
+ ? this.sessionResponseTransformer(response)
725
+ : response;
726
+ if (!this.configOptionsTransformer || !transformed.configOptions) {
727
+ return transformed;
728
+ }
729
+ return {
730
+ ...transformed,
731
+ configOptions: this.configOptionsTransformer(transformed.configOptions),
732
+ };
733
+ }
734
+ }
735
+ export class ACPAgentSession {
736
+ constructor(config, options) {
737
+ this.subscribers = new Set();
738
+ this.pendingPermissions = new Map();
739
+ this.messageAssemblies = new Map();
740
+ this.submittedUserMessageIds = new Set();
741
+ this.activeSubmittedUserMessage = null;
742
+ this.toolCalls = new Map();
743
+ this.terminalEntries = new Map();
744
+ this.persistedHistory = [];
745
+ this.child = null;
746
+ this.connection = null;
747
+ this.agentCapabilities = null;
748
+ this.sessionId = null;
749
+ this.currentMode = null;
750
+ this.currentModel = null;
751
+ this.availableModels = null;
752
+ this.thinkingOptionId = null;
753
+ this.currentTitle = null;
754
+ this.lastActivityAt = null;
755
+ this.configOptions = [];
756
+ this.cachedCommands = [];
757
+ this.commandsReadyDeferred = null;
758
+ this.commandsReadySettled = false;
759
+ this.activeForegroundTurnId = null;
760
+ this.closed = false;
761
+ this.historyPending = false;
762
+ this.replayingHistory = false;
763
+ this.bootstrapThreadEventPending = false;
764
+ this.provider = options.provider;
765
+ this.terminateProcess = options.terminateProcess ?? terminateWithTreeKill;
766
+ this.capabilities = options.capabilities;
767
+ this.logger = options.logger.child({ module: "agent", provider: options.provider });
768
+ this.runtimeSettings = options.runtimeSettings;
769
+ this.defaultCommand = options.defaultCommand;
770
+ this.defaultModes = options.defaultModes;
771
+ this.modelTransformer = options.modelTransformer;
772
+ this.sessionResponseTransformer = options.sessionResponseTransformer;
773
+ this.configOptionsTransformer = options.configOptionsTransformer;
774
+ this.configFeatureOptions = options.configFeatureOptions ?? [];
775
+ this.modeIdTransformer = options.modeIdTransformer;
776
+ this.toolSnapshotTransformer = options.toolSnapshotTransformer;
777
+ this.providerModeWriter = options.providerModeWriter;
778
+ this.beforeModeWriter = options.beforeModeWriter;
779
+ this.thinkingOptionWriter = options.thinkingOptionWriter;
780
+ this.availableModes = options.defaultModes;
781
+ this.agentId = options.agentId;
782
+ this.launchEnv = options.launchEnv;
783
+ this.initialHandle = options.handle;
784
+ this.config = { ...config, provider: options.provider };
785
+ this.currentMode = config.modeId ?? null;
786
+ this.currentModel = config.model ?? null;
787
+ this.thinkingOptionId = config.thinkingOptionId ?? null;
788
+ this.currentTitle = config.title ?? null;
789
+ this.waitForInitialCommands = options.waitForInitialCommands ?? false;
790
+ this.initialCommandsWaitTimeoutMs = options.initialCommandsWaitTimeoutMs ?? 1500;
791
+ this.extensionCommandsParser = options.extensionCommandsParser;
792
+ }
793
+ get id() {
794
+ return this.sessionId;
795
+ }
796
+ async initializeNewSession() {
797
+ const spawned = await this.spawnProcess();
798
+ this.child = spawned.child;
799
+ this.connection = spawned.connection;
800
+ this.agentCapabilities = spawned.initialize.agentCapabilities ?? null;
801
+ const response = await this.runACPRequest(() => this.connection.newSession({
802
+ cwd: this.config.cwd,
803
+ mcpServers: this.acpMcpServers(),
804
+ }));
805
+ this.sessionId = response.sessionId;
806
+ this.bootstrapThreadEventPending = true;
807
+ this.applySessionState(response);
808
+ await this.applyConfiguredOverrides();
809
+ }
810
+ /**
811
+ * IMPORTANT: Some ACP providers (e.g., Devin CLI) require all three params
812
+ * (sessionId, cwd, mcpServers) to be present in session/load or
813
+ * unstable_resumeSession — even when mcpServers is an empty array — and
814
+ * return "Invalid params" if any are omitted. Never drop cwd or mcpServers
815
+ * from these calls regardless of capabilities.
816
+ */
817
+ async initializeResumedSession() {
818
+ const handle = this.initialHandle;
819
+ if (!handle) {
820
+ throw new Error("Resume requested without persistence handle");
821
+ }
822
+ const spawned = await this.spawnProcess();
823
+ this.child = spawned.child;
824
+ this.connection = spawned.connection;
825
+ this.agentCapabilities = spawned.initialize.agentCapabilities ?? null;
826
+ this.sessionId = handle.sessionId;
827
+ this.bootstrapThreadEventPending = true;
828
+ const sessionCapabilities = this.agentCapabilities?.sessionCapabilities;
829
+ if (this.agentCapabilities?.loadSession) {
830
+ this.replayingHistory = true;
831
+ const response = await this.runACPRequest(() => this.connection.loadSession({
832
+ sessionId: handle.sessionId,
833
+ cwd: this.config.cwd,
834
+ mcpServers: this.acpMcpServers(),
835
+ }));
836
+ this.replayingHistory = false;
837
+ this.historyPending = this.persistedHistory.length > 0;
838
+ this.applySessionState(response);
839
+ }
840
+ else if (sessionCapabilities?.resume) {
841
+ const response = await this.runACPRequest(() => this.connection.unstable_resumeSession({
842
+ sessionId: handle.sessionId,
843
+ cwd: this.config.cwd,
844
+ mcpServers: this.acpMcpServers(),
845
+ }));
846
+ this.applySessionState(response);
847
+ }
848
+ else {
849
+ throw new Error(`${this.provider} does not support ACP session resume`);
850
+ }
851
+ await this.applyConfiguredOverrides();
852
+ }
853
+ async run(prompt, options) {
854
+ const result = await runProviderTurn({
855
+ prompt,
856
+ runOptions: options,
857
+ startTurn: (p, o) => this.startTurn(p, o),
858
+ subscribe: (callback) => this.subscribe(callback),
859
+ getSessionId: () => this.sessionId ?? "",
860
+ reduceFinalText: appendOrReplaceGrowingAssistantMessage,
861
+ });
862
+ if (!this.sessionId) {
863
+ throw new Error("ACP session did not expose a session id");
864
+ }
865
+ return result;
866
+ }
867
+ async startTurn(prompt, options) {
868
+ if (this.closed) {
869
+ throw new Error(`${this.provider} session is closed`);
870
+ }
871
+ if (!this.connection || !this.sessionId) {
872
+ throw new Error(`${this.provider} session is not initialized`);
873
+ }
874
+ if (this.activeForegroundTurnId) {
875
+ throw new Error("A foreground turn is already active");
876
+ }
877
+ const turnId = randomUUID();
878
+ const messageId = options?.messageId ?? randomUUID();
879
+ this.activeForegroundTurnId = turnId;
880
+ this.activeSubmittedUserMessage = null;
881
+ this.emitBootstrapThreadEvent();
882
+ this.pushEvent({ type: "turn_started", provider: this.provider, turnId });
883
+ this.emitSubmittedUserMessage(prompt, messageId, turnId);
884
+ void this.connection
885
+ .prompt({
886
+ sessionId: this.sessionId,
887
+ messageId,
888
+ prompt: toACPContentBlocks(prompt),
889
+ })
890
+ .then((response) => {
891
+ this.handlePromptResponse(response, turnId);
892
+ return;
893
+ })
894
+ .catch((error) => {
895
+ const summary = summarizeACPRequestError(error);
896
+ this.finishTurn({
897
+ type: "turn_failed",
898
+ provider: this.provider,
899
+ error: summary.message,
900
+ code: summary.code,
901
+ diagnostic: this.collectDiagnostic(summary.diagnostic ?? summary.message),
902
+ turnId,
903
+ });
904
+ });
905
+ return { turnId };
906
+ }
907
+ subscribe(callback) {
908
+ this.subscribers.add(callback);
909
+ if (this.sessionId) {
910
+ callback({
911
+ type: "thread_started",
912
+ provider: this.provider,
913
+ sessionId: this.sessionId,
914
+ });
915
+ }
916
+ return () => {
917
+ this.subscribers.delete(callback);
918
+ };
919
+ }
920
+ async *streamHistory() {
921
+ if (!this.historyPending || this.persistedHistory.length === 0) {
922
+ return;
923
+ }
924
+ const history = [...this.persistedHistory];
925
+ this.persistedHistory.length = 0;
926
+ this.historyPending = false;
927
+ for (const item of history) {
928
+ yield { type: "timeline", provider: this.provider, item };
929
+ }
930
+ }
931
+ async getRuntimeInfo() {
932
+ return this.runtimeInfo();
933
+ }
934
+ async getAvailableModes() {
935
+ return [...this.availableModes];
936
+ }
937
+ async getCurrentMode() {
938
+ return this.currentMode;
939
+ }
940
+ get features() {
941
+ return deriveFeaturesFromACP(this.configOptions, this.configFeatureOptions);
942
+ }
943
+ ensureCommandsReadyDeferred() {
944
+ if (this.commandsReadyDeferred || this.commandsReadySettled || this.cachedCommands.length > 0) {
945
+ return;
946
+ }
947
+ let resolve;
948
+ const promise = new Promise((r) => {
949
+ resolve = r;
950
+ });
951
+ this.commandsReadyDeferred = { promise, resolve };
952
+ }
953
+ settleCommandsReady() {
954
+ if (this.commandsReadySettled) {
955
+ return;
956
+ }
957
+ this.commandsReadySettled = true;
958
+ this.commandsReadyDeferred?.resolve();
959
+ this.commandsReadyDeferred = null;
960
+ }
961
+ async waitForCommandsReady() {
962
+ const deferred = this.commandsReadyDeferred;
963
+ if (!deferred) {
964
+ return;
965
+ }
966
+ let timer = null;
967
+ try {
968
+ await Promise.race([
969
+ deferred.promise,
970
+ new Promise((resolve) => {
971
+ timer = setTimeout(resolve, this.initialCommandsWaitTimeoutMs);
972
+ }),
973
+ ]);
974
+ }
975
+ finally {
976
+ if (timer) {
977
+ clearTimeout(timer);
978
+ }
979
+ }
980
+ }
981
+ async listCommands() {
982
+ if (this.cachedCommands.length > 0) {
983
+ return this.cachedCommands;
984
+ }
985
+ if (!this.waitForInitialCommands || this.closed) {
986
+ return this.cachedCommands;
987
+ }
988
+ this.ensureCommandsReadyDeferred();
989
+ await this.waitForCommandsReady();
990
+ this.settleCommandsReady();
991
+ return this.cachedCommands;
992
+ }
993
+ async setMode(modeId) {
994
+ if (!this.connection || !this.sessionId) {
995
+ throw new Error("ACP session not initialized");
996
+ }
997
+ const selection = resolveACPModeSelection({
998
+ modeId,
999
+ availableModes: this.availableModes,
1000
+ configOptions: this.configOptions,
1001
+ });
1002
+ await this.setModeWithSelection({ modeId, selection });
1003
+ }
1004
+ // Mode/model selection updates stay after ACP RPC success; this intentionally diverges from Zed's optimistic rollback path (acp.rs:3080-3104).
1005
+ async setModeWithSelection({ modeId, selection, }) {
1006
+ if (!this.connection || !this.sessionId) {
1007
+ throw new Error("ACP session not initialized");
1008
+ }
1009
+ const context = this.createProviderModeWriterContext(modeId, selection);
1010
+ const providerResult = this.providerModeWriter
1011
+ ? await this.providerModeWriter(context)
1012
+ : { handled: false };
1013
+ if (providerResult.handled) {
1014
+ this.currentMode = providerResult.currentModeId ?? modeId;
1015
+ if (providerResult.configOptions) {
1016
+ this.configOptions = this.transformConfigOptions(providerResult.configOptions);
1017
+ }
1018
+ this.availableModes = deriveModesFromACP(this.defaultModes, null, this.configOptions).modes;
1019
+ this.pushEvent({
1020
+ type: "mode_changed",
1021
+ provider: this.provider,
1022
+ currentModeId: this.currentMode,
1023
+ availableModes: [...this.availableModes],
1024
+ });
1025
+ return;
1026
+ }
1027
+ if (selection.hasAvailableModes) {
1028
+ if (!selection.availableMode) {
1029
+ this.warnInvalidSelection(modeId, `is not valid ${this.provider} mode. Available options: ${this.availableModes
1030
+ .map((mode) => mode.id)
1031
+ .join(", ")}`);
1032
+ return;
1033
+ }
1034
+ }
1035
+ else {
1036
+ const modeOption = selection.configOption;
1037
+ if (!modeOption) {
1038
+ throw new Error(`${this.provider} does not expose ACP mode switching`);
1039
+ }
1040
+ if (!selection.configChoice) {
1041
+ this.warnInvalidSelection(modeId, `is not valid ${this.provider} mode config option. Available options: ${flattenSelectOptions(modeOption.options)
1042
+ .map((option) => option.value)
1043
+ .join(", ")}`);
1044
+ return;
1045
+ }
1046
+ }
1047
+ if (this.beforeModeWriter) {
1048
+ const beforeResult = await this.beforeModeWriter(context);
1049
+ if (beforeResult?.configOptions) {
1050
+ this.configOptions = this.transformConfigOptions(beforeResult.configOptions);
1051
+ }
1052
+ }
1053
+ if (selection.hasAvailableModes) {
1054
+ await this.connection.setSessionMode({ sessionId: this.sessionId, modeId });
1055
+ this.currentMode = modeId;
1056
+ this.pushEvent({
1057
+ type: "mode_changed",
1058
+ provider: this.provider,
1059
+ currentModeId: this.currentMode,
1060
+ availableModes: [...this.availableModes],
1061
+ });
1062
+ return;
1063
+ }
1064
+ const modeOption = selection.configOption;
1065
+ if (!modeOption) {
1066
+ throw new Error(`${this.provider} does not expose ACP mode switching`);
1067
+ }
1068
+ const response = await this.connection.setSessionConfigOption({
1069
+ sessionId: this.sessionId,
1070
+ configId: modeOption.id,
1071
+ value: modeId,
1072
+ });
1073
+ this.currentMode = this.applyConfigOptionResponse({
1074
+ response,
1075
+ configId: modeOption.id,
1076
+ category: "mode",
1077
+ requestedValue: modeId,
1078
+ label: "mode",
1079
+ });
1080
+ this.availableModes = deriveModesFromACP(this.defaultModes, null, this.configOptions).modes;
1081
+ this.pushEvent({
1082
+ type: "mode_changed",
1083
+ provider: this.provider,
1084
+ currentModeId: this.currentMode,
1085
+ availableModes: [...this.availableModes],
1086
+ });
1087
+ }
1088
+ createProviderModeWriterContext(requestedModeId, selection) {
1089
+ if (!this.connection || !this.sessionId) {
1090
+ throw new Error("ACP session not initialized");
1091
+ }
1092
+ return {
1093
+ connection: this.connection,
1094
+ sessionId: this.sessionId,
1095
+ requestedModeId,
1096
+ currentModeId: this.currentMode,
1097
+ selection,
1098
+ configOptions: this.configOptions,
1099
+ logger: this.logger,
1100
+ };
1101
+ }
1102
+ async setModel(modelId) {
1103
+ if (!this.connection || !this.sessionId) {
1104
+ throw new Error("ACP session not initialized");
1105
+ }
1106
+ if (!modelId) {
1107
+ this.currentModel = null;
1108
+ return;
1109
+ }
1110
+ const selection = resolveACPModelSelection({
1111
+ modelId,
1112
+ availableModels: this.availableModels,
1113
+ configOptions: this.configOptions,
1114
+ });
1115
+ await this.setModelWithSelection({ modelId, selection });
1116
+ }
1117
+ async setModelWithSelection({ modelId, selection, }) {
1118
+ if (!this.connection || !this.sessionId) {
1119
+ throw new Error("ACP session not initialized");
1120
+ }
1121
+ if (selection.hasAvailableModels) {
1122
+ if (!selection.availableModel) {
1123
+ this.warnInvalidSelection(modelId, `is not a valid ${this.provider} model. Available options: ${this.availableModels
1124
+ ?.map((model) => model.modelId)
1125
+ .join(", ")}`);
1126
+ return;
1127
+ }
1128
+ if (typeof this.connection.unstable_setSessionModel !== "function") {
1129
+ throw new Error(this.modelSelectionUnavailableMessage());
1130
+ }
1131
+ try {
1132
+ await this.connection.unstable_setSessionModel({
1133
+ sessionId: this.sessionId,
1134
+ modelId,
1135
+ });
1136
+ this.currentModel = modelId;
1137
+ this.pushEvent({
1138
+ type: "model_changed",
1139
+ provider: this.provider,
1140
+ runtimeInfo: this.runtimeInfo(),
1141
+ });
1142
+ return;
1143
+ }
1144
+ catch {
1145
+ // Fall through to config option path.
1146
+ }
1147
+ }
1148
+ const modelOption = selection.configOption;
1149
+ if (!modelOption) {
1150
+ throw new Error(this.modelSelectionUnavailableMessage());
1151
+ }
1152
+ if (!selection.configChoice) {
1153
+ this.warnInvalidSelection(modelId, `is not a valid ${this.provider} model config option. Available options: ${flattenSelectOptions(modelOption.options)
1154
+ .map((option) => option.value)
1155
+ .join(", ")}`);
1156
+ return;
1157
+ }
1158
+ const response = await this.connection.setSessionConfigOption({
1159
+ sessionId: this.sessionId,
1160
+ configId: modelOption.id,
1161
+ value: modelId,
1162
+ });
1163
+ this.currentModel = this.applyConfigOptionResponse({
1164
+ response,
1165
+ configId: modelOption.id,
1166
+ category: "model",
1167
+ requestedValue: modelId,
1168
+ label: "model",
1169
+ });
1170
+ this.pushEvent({
1171
+ type: "model_changed",
1172
+ provider: this.provider,
1173
+ runtimeInfo: this.runtimeInfo(),
1174
+ });
1175
+ }
1176
+ async setThinkingOption(thinkingOptionId) {
1177
+ if (!this.connection || !this.sessionId) {
1178
+ throw new Error("ACP session not initialized");
1179
+ }
1180
+ if (!thinkingOptionId) {
1181
+ this.thinkingOptionId = null;
1182
+ return;
1183
+ }
1184
+ if (this.thinkingOptionWriter) {
1185
+ await this.thinkingOptionWriter(this.connection, this.sessionId, thinkingOptionId);
1186
+ this.thinkingOptionId = thinkingOptionId;
1187
+ this.pushEvent({
1188
+ type: "thinking_option_changed",
1189
+ provider: this.provider,
1190
+ thinkingOptionId: this.thinkingOptionId,
1191
+ });
1192
+ return;
1193
+ }
1194
+ const option = findSelectConfigOption({
1195
+ configOptions: this.configOptions,
1196
+ category: "thought_level",
1197
+ });
1198
+ if (!option) {
1199
+ throw new Error(`${this.provider} does not expose ACP thought-level selection`);
1200
+ }
1201
+ const response = await this.connection.setSessionConfigOption({
1202
+ sessionId: this.sessionId,
1203
+ configId: option.id,
1204
+ value: thinkingOptionId,
1205
+ });
1206
+ this.thinkingOptionId = this.applyConfigOptionResponse({
1207
+ response,
1208
+ configId: option.id,
1209
+ category: "thought_level",
1210
+ requestedValue: thinkingOptionId,
1211
+ label: "thought-level",
1212
+ });
1213
+ this.pushEvent({
1214
+ type: "thinking_option_changed",
1215
+ provider: this.provider,
1216
+ thinkingOptionId: this.thinkingOptionId,
1217
+ });
1218
+ }
1219
+ async setFeature(featureId, value) {
1220
+ if (!this.connection || !this.sessionId) {
1221
+ throw new Error("ACP session not initialized");
1222
+ }
1223
+ const featureOption = this.configFeatureOptions.find((option) => option.id === featureId);
1224
+ if (!featureOption) {
1225
+ throw new Error(`Unknown ${this.provider} feature: ${featureId}`);
1226
+ }
1227
+ const option = findSelectConfigFeatureOption(this.configOptions, featureOption);
1228
+ if (!option) {
1229
+ throw new Error(`${this.provider} does not expose ACP feature '${featureId}'`);
1230
+ }
1231
+ const requestedValue = normalizeConfigFeatureValue(value);
1232
+ const choice = findSelectConfigChoice({ option, value: requestedValue });
1233
+ if (!choice) {
1234
+ throw new Error(`${this.provider} feature '${featureId}' does not include option '${requestedValue}'`);
1235
+ }
1236
+ const response = await this.connection.setSessionConfigOption({
1237
+ sessionId: this.sessionId,
1238
+ configId: option.id,
1239
+ value: requestedValue,
1240
+ });
1241
+ const currentValue = this.applyConfigOptionResponse({
1242
+ response,
1243
+ configId: option.id,
1244
+ category: featureOption.category,
1245
+ requestedValue,
1246
+ label: featureOption.label,
1247
+ });
1248
+ this.config.featureValues = { ...this.config.featureValues, [featureId]: currentValue };
1249
+ }
1250
+ applyConfigOptionResponse({ response, configId, category, requestedValue, label, }) {
1251
+ this.configOptions = this.transformConfigOptions(response.configOptions);
1252
+ const responseOption = findSelectConfigOption({
1253
+ configOptions: this.configOptions,
1254
+ category,
1255
+ id: configId,
1256
+ });
1257
+ if (responseOption?.currentValue != null) {
1258
+ return responseOption.currentValue;
1259
+ }
1260
+ this.logger.warn({ configId, value: requestedValue }, `ACP setSessionConfigOption response did not include the requested ${label} option currentValue; using requested value`);
1261
+ return requestedValue;
1262
+ }
1263
+ getPendingPermissions() {
1264
+ return Array.from(this.pendingPermissions.values(), (entry) => entry.request);
1265
+ }
1266
+ async respondToPermission(requestId, response) {
1267
+ const pending = this.pendingPermissions.get(requestId);
1268
+ if (!pending) {
1269
+ throw new Error(`No pending permission request with id '${requestId}'`);
1270
+ }
1271
+ this.pendingPermissions.delete(requestId);
1272
+ const selectedOption = selectPermissionOption(pending.options, response);
1273
+ pending.resolve(selectedOption
1274
+ ? {
1275
+ outcome: {
1276
+ outcome: "selected",
1277
+ optionId: selectedOption.optionId,
1278
+ },
1279
+ }
1280
+ : { outcome: { outcome: "cancelled" } });
1281
+ this.pushEvent({
1282
+ type: "permission_resolved",
1283
+ provider: this.provider,
1284
+ requestId,
1285
+ resolution: response,
1286
+ turnId: pending.turnId ?? undefined,
1287
+ });
1288
+ if (response.behavior === "deny" && response.interrupt && this.connection && this.sessionId) {
1289
+ await this.connection.cancel({ sessionId: this.sessionId });
1290
+ }
1291
+ }
1292
+ describePersistence() {
1293
+ if (!this.sessionId) {
1294
+ return null;
1295
+ }
1296
+ return {
1297
+ provider: this.provider,
1298
+ sessionId: this.sessionId,
1299
+ nativeHandle: this.sessionId,
1300
+ metadata: {
1301
+ ...this.config,
1302
+ title: this.currentTitle,
1303
+ },
1304
+ };
1305
+ }
1306
+ async interrupt() {
1307
+ if (!this.connection || !this.sessionId) {
1308
+ return;
1309
+ }
1310
+ for (const pending of this.pendingPermissions.values()) {
1311
+ pending.resolve({ outcome: { outcome: "cancelled" } });
1312
+ }
1313
+ this.pendingPermissions.clear();
1314
+ if (this.activeForegroundTurnId) {
1315
+ await this.connection.cancel({ sessionId: this.sessionId });
1316
+ }
1317
+ }
1318
+ async close() {
1319
+ if (this.closed) {
1320
+ return;
1321
+ }
1322
+ this.closed = true;
1323
+ this.settleCommandsReady();
1324
+ for (const pending of this.pendingPermissions.values()) {
1325
+ pending.resolve({ outcome: { outcome: "cancelled" } });
1326
+ }
1327
+ this.pendingPermissions.clear();
1328
+ if (this.connection && this.sessionId) {
1329
+ try {
1330
+ if (this.activeForegroundTurnId) {
1331
+ await this.connection.cancel({ sessionId: this.sessionId });
1332
+ }
1333
+ }
1334
+ catch { }
1335
+ try {
1336
+ if (this.agentCapabilities?.sessionCapabilities?.close) {
1337
+ await this.connection.unstable_closeSession({ sessionId: this.sessionId });
1338
+ }
1339
+ }
1340
+ catch (error) {
1341
+ this.logger.debug({ err: error }, "ACP closeSession failed during shutdown");
1342
+ }
1343
+ }
1344
+ const terminalTerminations = Array.from(this.terminalEntries.values(), (terminal) => this.terminateProcess(terminal.child, {
1345
+ gracefulTimeoutMs: 2000,
1346
+ forceTimeoutMs: 2000,
1347
+ }));
1348
+ await Promise.all(terminalTerminations);
1349
+ this.terminalEntries.clear();
1350
+ if (this.child) {
1351
+ await this.terminateProcess(this.child, { gracefulTimeoutMs: 2000, forceTimeoutMs: 2000 });
1352
+ }
1353
+ this.subscribers.clear();
1354
+ this.connection = null;
1355
+ this.child = null;
1356
+ this.activeForegroundTurnId = null;
1357
+ }
1358
+ async requestPermission(params) {
1359
+ // Match Zed acp.rs:3189-3220: generic ACP permission requests stay pure pass-through.
1360
+ const requestId = randomUUID();
1361
+ let toolSnapshot = this.toolCalls.get(params.toolCall.toolCallId) ??
1362
+ mergeToolSnapshot(params.toolCall.toolCallId, params.toolCall);
1363
+ if (this.toolSnapshotTransformer) {
1364
+ toolSnapshot = this.toolSnapshotTransformer(toolSnapshot);
1365
+ }
1366
+ const request = mapPermissionRequest(this.provider, requestId, params, toolSnapshot);
1367
+ const promise = new Promise((resolve, reject) => {
1368
+ this.pendingPermissions.set(requestId, {
1369
+ request,
1370
+ options: params.options,
1371
+ resolve,
1372
+ reject,
1373
+ turnId: this.activeForegroundTurnId,
1374
+ });
1375
+ });
1376
+ this.pushEvent({
1377
+ type: "permission_requested",
1378
+ provider: this.provider,
1379
+ request,
1380
+ turnId: this.activeForegroundTurnId ?? undefined,
1381
+ });
1382
+ return promise;
1383
+ }
1384
+ async sessionUpdate(params) {
1385
+ this.logger.trace({
1386
+ agentId: this.agentId,
1387
+ provider: this.provider,
1388
+ sessionId: params.sessionId,
1389
+ rawEvent: params,
1390
+ }, "provider.acp.raw_event");
1391
+ if (params.sessionId !== this.sessionId) {
1392
+ return;
1393
+ }
1394
+ const events = this.translateSessionUpdate(params.update);
1395
+ this.logger.trace({
1396
+ agentId: this.agentId,
1397
+ provider: this.provider,
1398
+ sessionId: this.sessionId,
1399
+ turnId: this.activeForegroundTurnId ?? undefined,
1400
+ rawEvent: params,
1401
+ events,
1402
+ }, "provider.acp.parsed_event");
1403
+ if (this.replayingHistory) {
1404
+ for (const event of events) {
1405
+ if (event.type === "timeline") {
1406
+ this.persistedHistory.push(event.item);
1407
+ }
1408
+ }
1409
+ return;
1410
+ }
1411
+ for (const event of events) {
1412
+ this.pushEvent(event);
1413
+ }
1414
+ }
1415
+ async extNotification(method, params) {
1416
+ this.logger.trace({
1417
+ agentId: this.agentId,
1418
+ provider: this.provider,
1419
+ sessionId: typeof params.sessionId === "string" ? params.sessionId : undefined,
1420
+ method,
1421
+ rawEvent: params,
1422
+ }, "provider.acp.extension_notification");
1423
+ const parsedCommands = this.extensionCommandsParser?.(method, params);
1424
+ if (parsedCommands) {
1425
+ this.applyResolvedCommands(parsedCommands, {
1426
+ sessionId: typeof params.sessionId === "string" ? params.sessionId : undefined,
1427
+ });
1428
+ }
1429
+ }
1430
+ // Cache an asynchronously-delivered slash-command batch and unblock any
1431
+ // listCommands() call that is waiting on the initial batch. Used when a
1432
+ // provider supplies an extensionCommandsParser whose result arrives after
1433
+ // session/new (e.g. via a vendor extension notification). The ready gate is
1434
+ // always settled — even for an empty batch — so a provider that legitimately
1435
+ // reports no commands does not leave listCommands() blocked for the full
1436
+ // initial-commands timeout. An optional sessionId scopes the batch to this
1437
+ // session; notifications addressed to a different session are ignored.
1438
+ applyResolvedCommands(commands, options) {
1439
+ if (options?.sessionId !== undefined &&
1440
+ this.sessionId !== null &&
1441
+ options.sessionId !== this.sessionId) {
1442
+ return;
1443
+ }
1444
+ if (commands.length > 0) {
1445
+ this.cachedCommands = commands;
1446
+ }
1447
+ this.settleCommandsReady();
1448
+ }
1449
+ async readTextFile(params) {
1450
+ const raw = await fs.readFile(params.path, "utf8");
1451
+ if (!params.line && !params.limit) {
1452
+ return { content: raw };
1453
+ }
1454
+ const lines = raw.split(/\r?\n/);
1455
+ const start = Math.max((params.line ?? 1) - 1, 0);
1456
+ const end = params.limit ? start + params.limit : undefined;
1457
+ return { content: lines.slice(start, end).join("\n") };
1458
+ }
1459
+ async writeTextFile(params) {
1460
+ await fs.mkdir(path.dirname(params.path), { recursive: true });
1461
+ await fs.writeFile(params.path, params.content, "utf8");
1462
+ return {};
1463
+ }
1464
+ async createTerminal(params) {
1465
+ const terminalId = randomUUID();
1466
+ const env = Object.fromEntries((params.env ?? []).map((entry) => [entry.name, entry.value]));
1467
+ const terminalCommand = resolveTerminalCommand(params.command, params.args);
1468
+ const commandEnvOverlays = terminalCommand.shell === false ? [env, createStringCommandShellEnvOverlay()] : [env];
1469
+ const child = spawnProcess(terminalCommand.command, terminalCommand.args, {
1470
+ cwd: params.cwd ?? this.config.cwd,
1471
+ ...createProviderEnvSpec({
1472
+ runtimeSettings: this.runtimeSettings,
1473
+ overlays: commandEnvOverlays,
1474
+ }),
1475
+ shell: terminalCommand.shell,
1476
+ stdio: ["ignore", "pipe", "pipe"],
1477
+ });
1478
+ let resolveExit;
1479
+ let rejectExit;
1480
+ const waitForExit = new Promise((resolve, reject) => {
1481
+ resolveExit = resolve;
1482
+ rejectExit = reject;
1483
+ });
1484
+ waitForExit.catch(() => undefined);
1485
+ const entry = {
1486
+ id: terminalId,
1487
+ child,
1488
+ output: "",
1489
+ truncated: false,
1490
+ outputByteLimit: params.outputByteLimit ?? null,
1491
+ exit: null,
1492
+ waitForExit,
1493
+ resolveExit,
1494
+ rejectExit,
1495
+ };
1496
+ child.stdout.on("data", (chunk) => appendTerminalOutput(entry, chunk.toString()));
1497
+ child.stderr.on("data", (chunk) => appendTerminalOutput(entry, chunk.toString()));
1498
+ child.once("error", (error) => {
1499
+ const spawnError = error instanceof Error ? error : new Error(String(error));
1500
+ appendTerminalOutput(entry, `${spawnError.message}\n`);
1501
+ rejectExit(spawnError);
1502
+ });
1503
+ child.once("exit", (code, signal) => {
1504
+ const exit = { exitCode: code, signal };
1505
+ entry.exit = exit;
1506
+ resolveExit(exit);
1507
+ });
1508
+ this.terminalEntries.set(terminalId, entry);
1509
+ return { terminalId };
1510
+ }
1511
+ async terminalOutput(params) {
1512
+ const entry = this.getTerminalEntry(params.terminalId);
1513
+ return {
1514
+ output: entry.output,
1515
+ truncated: entry.truncated,
1516
+ exitStatus: entry.exit ?? undefined,
1517
+ };
1518
+ }
1519
+ async waitForTerminalExit(params) {
1520
+ const entry = this.getTerminalEntry(params.terminalId);
1521
+ return entry.waitForExit;
1522
+ }
1523
+ async releaseTerminal(params) {
1524
+ const entry = this.getTerminalEntry(params.terminalId);
1525
+ if (!entry.exit) {
1526
+ await this.terminateProcess(entry.child, { gracefulTimeoutMs: 2000, forceTimeoutMs: 2000 });
1527
+ }
1528
+ this.terminalEntries.delete(params.terminalId);
1529
+ }
1530
+ async killTerminal(params) {
1531
+ const entry = this.getTerminalEntry(params.terminalId);
1532
+ if (!entry.exit) {
1533
+ await this.terminateProcess(entry.child, { gracefulTimeoutMs: 2000, forceTimeoutMs: 2000 });
1534
+ }
1535
+ return {};
1536
+ }
1537
+ async spawnProcess() {
1538
+ const prefix = await resolveProviderLaunch({
1539
+ commandConfig: this.runtimeSettings?.command,
1540
+ defaultBinary: this.defaultCommand[0],
1541
+ });
1542
+ const availability = await checkProviderLaunchAvailable(prefix);
1543
+ if (!availability.available) {
1544
+ throw new Error(`${this.provider} command '${this.defaultCommand[0]}' not found`);
1545
+ }
1546
+ const command = prefix.command;
1547
+ const args = [...prefix.args, ...this.defaultCommand.slice(1)];
1548
+ const child = spawnProcess(command, args, {
1549
+ cwd: this.config.cwd,
1550
+ ...createProviderEnvSpec({
1551
+ runtimeSettings: this.runtimeSettings,
1552
+ overlays: [this.launchEnv],
1553
+ }),
1554
+ stdio: ["pipe", "pipe", "pipe"],
1555
+ });
1556
+ assertChildWithPipes(child);
1557
+ const stderrChunks = [];
1558
+ child.stderr.on("data", (chunk) => {
1559
+ stderrChunks.push(chunk.toString());
1560
+ });
1561
+ child.once("exit", (code, signal) => {
1562
+ if (this.closed) {
1563
+ return;
1564
+ }
1565
+ if (this.activeForegroundTurnId) {
1566
+ this.synthesizeCanceledToolCalls();
1567
+ this.finishTurn({
1568
+ type: "turn_failed",
1569
+ provider: this.provider,
1570
+ error: `ACP agent exited unexpectedly (${code ?? "null"}${signal ? `, ${signal}` : ""})`,
1571
+ diagnostic: stderrChunks.join("").trim() || undefined,
1572
+ turnId: this.activeForegroundTurnId,
1573
+ });
1574
+ }
1575
+ });
1576
+ const stream = createLoggedNdJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout), { logger: this.logger, provider: this.provider });
1577
+ const connection = new ClientSideConnection(() => this, stream);
1578
+ const initialize = await this.runACPRequest(() => connection.initialize({
1579
+ protocolVersion: PROTOCOL_VERSION,
1580
+ clientCapabilities: ACP_CLIENT_CAPABILITIES,
1581
+ clientInfo: { name: "Otto", version: "dev" },
1582
+ }));
1583
+ return { child, connection, initialize };
1584
+ }
1585
+ async runACPRequest(request) {
1586
+ try {
1587
+ return await request();
1588
+ }
1589
+ catch (error) {
1590
+ throw toACPRequestError(error);
1591
+ }
1592
+ }
1593
+ acpMcpServers() {
1594
+ return this.capabilities.supportsMcpServers ? normalizeMcpServers(this.config.mcpServers) : [];
1595
+ }
1596
+ applySessionState(response) {
1597
+ const transformed = this.sessionResponseTransformer
1598
+ ? this.sessionResponseTransformer(response)
1599
+ : response;
1600
+ this.configOptions = this.transformConfigOptions(transformed.configOptions ?? []);
1601
+ const modeInfo = deriveModesFromACP(this.defaultModes, transformed.modes, this.configOptions);
1602
+ this.availableModes = modeInfo.modes;
1603
+ this.currentMode = modeInfo.currentModeId ?? this.currentMode;
1604
+ this.availableModels = transformed.models?.availableModels ?? null;
1605
+ this.currentModel =
1606
+ transformed.models?.currentModelId ?? deriveCurrentConfigValue(this.configOptions, "model");
1607
+ this.thinkingOptionId =
1608
+ deriveCurrentConfigValue(this.configOptions, "thought_level") ?? this.thinkingOptionId;
1609
+ }
1610
+ transformConfigOptions(configOptions) {
1611
+ return this.configOptionsTransformer
1612
+ ? this.configOptionsTransformer(configOptions)
1613
+ : configOptions;
1614
+ }
1615
+ transformModeId(modeId) {
1616
+ return this.modeIdTransformer ? this.modeIdTransformer(modeId) : modeId;
1617
+ }
1618
+ async applyConfiguredOverrides() {
1619
+ const configuredModeId = this.config.modeId;
1620
+ if (configuredModeId && configuredModeId !== this.currentMode) {
1621
+ const selection = resolveACPModeSelection({
1622
+ modeId: configuredModeId,
1623
+ availableModes: this.availableModes,
1624
+ configOptions: this.configOptions,
1625
+ });
1626
+ await this.setModeWithSelection({ modeId: configuredModeId, selection });
1627
+ }
1628
+ const configuredModelId = this.config.model;
1629
+ if (configuredModelId && configuredModelId !== this.currentModel) {
1630
+ const selection = resolveACPModelSelection({
1631
+ modelId: configuredModelId,
1632
+ availableModels: this.availableModels,
1633
+ configOptions: this.configOptions,
1634
+ });
1635
+ try {
1636
+ await this.setModelWithSelection({ modelId: configuredModelId, selection });
1637
+ }
1638
+ catch (error) {
1639
+ if (!this.isModelSelectionUnavailableError(error)) {
1640
+ throw error;
1641
+ }
1642
+ this.logger.warn({ value: configuredModelId }, `${this.provider} does not expose ACP model selection; using provider default model`);
1643
+ }
1644
+ }
1645
+ if (this.config.thinkingOptionId && this.config.thinkingOptionId !== this.thinkingOptionId) {
1646
+ await this.setThinkingOption(this.config.thinkingOptionId);
1647
+ }
1648
+ const configuredFeatureValues = this.config.featureValues ?? {};
1649
+ for (const featureOption of this.configFeatureOptions) {
1650
+ if (!Object.prototype.hasOwnProperty.call(configuredFeatureValues, featureOption.id)) {
1651
+ continue;
1652
+ }
1653
+ await this.setFeature(featureOption.id, configuredFeatureValues[featureOption.id]);
1654
+ }
1655
+ }
1656
+ warnInvalidSelection(value, message) {
1657
+ this.logger.warn({ value }, message);
1658
+ }
1659
+ modelSelectionUnavailableMessage() {
1660
+ return `${this.provider} does not expose ACP model selection`;
1661
+ }
1662
+ isModelSelectionUnavailableError(error) {
1663
+ return error instanceof Error && error.message === this.modelSelectionUnavailableMessage();
1664
+ }
1665
+ translateSessionUpdate(update) {
1666
+ switch (update.sessionUpdate) {
1667
+ case "user_message_chunk": {
1668
+ const item = this.createMessageTimelineItem("user_message", update);
1669
+ if (!item) {
1670
+ return [];
1671
+ }
1672
+ if (item.type !== "user_message") {
1673
+ return [this.wrapTimeline(item)];
1674
+ }
1675
+ if (this.isSubmittedUserMessageEcho(item)) {
1676
+ return [];
1677
+ }
1678
+ return [this.wrapTimeline(item)];
1679
+ }
1680
+ case "agent_message_chunk": {
1681
+ const item = this.createMessageTimelineItem("assistant_message", update);
1682
+ return item ? [this.wrapTimeline(item)] : [];
1683
+ }
1684
+ case "agent_thought_chunk": {
1685
+ const item = this.createMessageTimelineItem("reasoning", update);
1686
+ return item ? [this.wrapTimeline(item)] : [];
1687
+ }
1688
+ case "tool_call":
1689
+ return this.handleToolCallUpdate(update.toolCallId, update, undefined);
1690
+ case "tool_call_update":
1691
+ return this.handleToolCallUpdate(update.toolCallId, update, this.toolCalls.get(update.toolCallId));
1692
+ case "plan":
1693
+ return [this.wrapTimeline(mapPlanToTimeline(update))];
1694
+ case "current_mode_update":
1695
+ this.handleCurrentModeUpdate(update);
1696
+ return [
1697
+ {
1698
+ type: "mode_changed",
1699
+ provider: this.provider,
1700
+ currentModeId: this.currentMode,
1701
+ availableModes: [...this.availableModes],
1702
+ },
1703
+ ];
1704
+ case "config_option_update":
1705
+ return this.handleConfigOptionUpdate(update);
1706
+ case "session_info_update":
1707
+ this.handleSessionInfoUpdate(update);
1708
+ return [];
1709
+ case "usage_update":
1710
+ this.handleUsageUpdate(update);
1711
+ return [];
1712
+ case "available_commands_update":
1713
+ this.cachedCommands = update.availableCommands.map((command) => ({
1714
+ name: command.name,
1715
+ description: command.description,
1716
+ argumentHint: "",
1717
+ kind: "command",
1718
+ }));
1719
+ this.settleCommandsReady();
1720
+ return [];
1721
+ default:
1722
+ return [];
1723
+ }
1724
+ }
1725
+ handleToolCallUpdate(toolCallId, update, previous) {
1726
+ let snapshot = mergeToolSnapshot(toolCallId, update, previous);
1727
+ if (this.toolSnapshotTransformer) {
1728
+ snapshot = this.toolSnapshotTransformer(snapshot);
1729
+ }
1730
+ this.toolCalls.set(toolCallId, snapshot);
1731
+ return [this.wrapTimeline(mapToolSnapshotToTimeline(snapshot, this.terminalEntries))];
1732
+ }
1733
+ createMessageTimelineItem(type, update) {
1734
+ const chunkText = contentBlockToText(update.content);
1735
+ if (!chunkText) {
1736
+ return null;
1737
+ }
1738
+ const key = this.messageAssemblyKey(type, update.messageId);
1739
+ const state = this.messageAssemblies.get(key) ?? { text: "" };
1740
+ state.text += chunkText;
1741
+ this.messageAssemblies.set(key, state);
1742
+ if (type === "user_message") {
1743
+ return { type: "user_message", text: state.text, messageId: update.messageId ?? undefined };
1744
+ }
1745
+ if (type === "assistant_message") {
1746
+ return { type: "assistant_message", text: chunkText };
1747
+ }
1748
+ return { type: "reasoning", text: chunkText };
1749
+ }
1750
+ messageAssemblyKey(type, messageId) {
1751
+ const fallbackId = type === "user_message" ? (this.activeForegroundTurnId ?? "default") : "default";
1752
+ return `${type}:${messageId ?? fallbackId}`;
1753
+ }
1754
+ handleCurrentModeUpdate(update) {
1755
+ this.currentMode = this.transformModeId(update.currentModeId);
1756
+ }
1757
+ handleConfigOptionUpdate(update) {
1758
+ this.configOptions = this.transformConfigOptions(update.configOptions);
1759
+ const modeInfo = deriveModesFromACP(this.defaultModes, null, this.configOptions);
1760
+ const nextMode = modeInfo.currentModeId;
1761
+ const nextModel = deriveCurrentConfigValue(this.configOptions, "model");
1762
+ const nextThinkingOptionId = deriveCurrentConfigValue(this.configOptions, "thought_level");
1763
+ this.availableModes = modeInfo.modes;
1764
+ this.currentMode = nextMode ?? this.currentMode;
1765
+ this.currentModel = nextModel ?? this.currentModel;
1766
+ this.thinkingOptionId = nextThinkingOptionId ?? this.thinkingOptionId;
1767
+ const events = [];
1768
+ if (nextMode !== null) {
1769
+ events.push({
1770
+ type: "mode_changed",
1771
+ provider: this.provider,
1772
+ currentModeId: this.currentMode,
1773
+ availableModes: [...this.availableModes],
1774
+ });
1775
+ }
1776
+ if (nextModel !== null) {
1777
+ events.push({
1778
+ type: "model_changed",
1779
+ provider: this.provider,
1780
+ runtimeInfo: this.runtimeInfo(),
1781
+ });
1782
+ }
1783
+ if (nextThinkingOptionId !== null) {
1784
+ events.push({
1785
+ type: "thinking_option_changed",
1786
+ provider: this.provider,
1787
+ thinkingOptionId: this.thinkingOptionId,
1788
+ });
1789
+ }
1790
+ return events;
1791
+ }
1792
+ handleSessionInfoUpdate(update) {
1793
+ if ("title" in update) {
1794
+ this.currentTitle = update.title ?? null;
1795
+ }
1796
+ if ("updatedAt" in update) {
1797
+ this.lastActivityAt = update.updatedAt ?? null;
1798
+ }
1799
+ }
1800
+ handleUsageUpdate(update) {
1801
+ void update;
1802
+ }
1803
+ handlePromptResponse(response, turnId) {
1804
+ this.currentTurnUsage = mapACPUsage(response.usage) ?? this.currentTurnUsage;
1805
+ switch (response.stopReason) {
1806
+ case "cancelled":
1807
+ this.synthesizeCanceledToolCalls();
1808
+ this.finishTurn({
1809
+ type: "turn_canceled",
1810
+ provider: this.provider,
1811
+ reason: "Interrupted",
1812
+ turnId,
1813
+ });
1814
+ break;
1815
+ case "end_turn":
1816
+ case "max_tokens":
1817
+ case "max_turn_requests":
1818
+ case "refusal":
1819
+ default:
1820
+ this.finishTurn({
1821
+ type: "turn_completed",
1822
+ provider: this.provider,
1823
+ usage: this.currentTurnUsage,
1824
+ turnId,
1825
+ });
1826
+ break;
1827
+ }
1828
+ }
1829
+ wrapTimeline(item) {
1830
+ return {
1831
+ type: "timeline",
1832
+ provider: this.provider,
1833
+ item,
1834
+ turnId: this.activeForegroundTurnId ?? undefined,
1835
+ };
1836
+ }
1837
+ pushEvent(event) {
1838
+ this.logger.trace({
1839
+ agentId: this.agentId,
1840
+ provider: this.provider,
1841
+ sessionId: this.sessionId,
1842
+ turnId: getAgentStreamEventTurnId(event) ?? this.activeForegroundTurnId ?? undefined,
1843
+ event,
1844
+ }, "provider.acp.event_emit");
1845
+ for (const subscriber of this.subscribers) {
1846
+ subscriber(event);
1847
+ }
1848
+ }
1849
+ emitSubmittedUserMessage(prompt, messageId, turnId) {
1850
+ const text = extractPromptText(prompt);
1851
+ if (text.trim().length === 0) {
1852
+ return;
1853
+ }
1854
+ this.submittedUserMessageIds.add(messageId);
1855
+ this.activeSubmittedUserMessage = { messageId, text, turnId };
1856
+ this.pushEvent({
1857
+ type: "timeline",
1858
+ provider: this.provider,
1859
+ turnId,
1860
+ item: { type: "user_message", text, messageId },
1861
+ });
1862
+ }
1863
+ runtimeInfo() {
1864
+ return {
1865
+ provider: this.provider,
1866
+ sessionId: this.sessionId,
1867
+ model: this.currentModel,
1868
+ thinkingOptionId: this.thinkingOptionId,
1869
+ modeId: this.currentMode,
1870
+ extra: {
1871
+ title: this.currentTitle,
1872
+ updatedAt: this.lastActivityAt,
1873
+ },
1874
+ };
1875
+ }
1876
+ finishTurn(event) {
1877
+ this.activeForegroundTurnId = null;
1878
+ if (this.activeSubmittedUserMessage?.turnId === event.turnId) {
1879
+ this.activeSubmittedUserMessage = null;
1880
+ }
1881
+ this.pushEvent(event);
1882
+ }
1883
+ isSubmittedUserMessageEcho(item) {
1884
+ const active = this.activeSubmittedUserMessage;
1885
+ if (!active || active.turnId !== this.activeForegroundTurnId) {
1886
+ return false;
1887
+ }
1888
+ if (item.messageId) {
1889
+ if (this.submittedUserMessageIds.has(item.messageId)) {
1890
+ return true;
1891
+ }
1892
+ }
1893
+ return active.text.startsWith(item.text);
1894
+ }
1895
+ emitBootstrapThreadEvent() {
1896
+ if (!this.bootstrapThreadEventPending || !this.sessionId) {
1897
+ return;
1898
+ }
1899
+ this.bootstrapThreadEventPending = false;
1900
+ this.pushEvent({
1901
+ type: "thread_started",
1902
+ provider: this.provider,
1903
+ sessionId: this.sessionId,
1904
+ });
1905
+ }
1906
+ synthesizeCanceledToolCalls() {
1907
+ for (const snapshot of this.toolCalls.values()) {
1908
+ const mapped = mapToolSnapshotToTimeline(snapshot, this.terminalEntries);
1909
+ if (mapped.status === "running") {
1910
+ this.pushEvent(this.wrapTimeline({
1911
+ ...mapped,
1912
+ status: "canceled",
1913
+ error: null,
1914
+ }));
1915
+ }
1916
+ }
1917
+ }
1918
+ collectDiagnostic(message) {
1919
+ const parts = [message];
1920
+ if (this.child?.exitCode != null) {
1921
+ parts.push(`exitCode=${this.child.exitCode}`);
1922
+ }
1923
+ if (this.child?.signalCode) {
1924
+ parts.push(`signal=${this.child.signalCode}`);
1925
+ }
1926
+ return parts.length > 0 ? parts.join(" | ") : undefined;
1927
+ }
1928
+ getTerminalEntry(terminalId) {
1929
+ const entry = this.terminalEntries.get(terminalId);
1930
+ if (!entry) {
1931
+ throw new Error(`Unknown terminal '${terminalId}'`);
1932
+ }
1933
+ return entry;
1934
+ }
1935
+ }
1936
+ function findSelectConfigOption({ configOptions, category, id, }) {
1937
+ const option = configOptions?.find((entry) => entry.type === "select" && entry.category === category && (!id || entry.id === id));
1938
+ return option ?? null;
1939
+ }
1940
+ function findSelectConfigFeatureOption(configOptions, featureOption) {
1941
+ const option = configOptions?.find((entry) => entry.type === "select" &&
1942
+ entry.id === featureOption.configId &&
1943
+ entry.category === featureOption.category);
1944
+ return option ?? null;
1945
+ }
1946
+ function findSelectConfigChoice({ option, value, }) {
1947
+ if (!option) {
1948
+ return null;
1949
+ }
1950
+ return flattenSelectOptions(option.options).find((choice) => choice.value === value) ?? null;
1951
+ }
1952
+ function flattenSelectOptions(options) {
1953
+ const flattened = [];
1954
+ for (const option of options) {
1955
+ if ("value" in option) {
1956
+ flattened.push(option);
1957
+ continue;
1958
+ }
1959
+ for (const groupOption of option.options) {
1960
+ flattened.push({ ...groupOption, group: option.group });
1961
+ }
1962
+ }
1963
+ return flattened;
1964
+ }
1965
+ function deriveConfigFeatureSelectOptions(option, featureOption) {
1966
+ return flattenSelectOptions(option.options).map((choice) => ({
1967
+ id: choice.value,
1968
+ label: normalizeConfigFeatureOptionLabel(choice, featureOption),
1969
+ description: choice.description ?? undefined,
1970
+ isDefault: choice.value === option.currentValue,
1971
+ metadata: choice.group ? { group: choice.group } : undefined,
1972
+ }));
1973
+ }
1974
+ function normalizeConfigFeatureOptionLabel(choice, featureOption) {
1975
+ const name = choice.name.trim();
1976
+ if (name) {
1977
+ return name;
1978
+ }
1979
+ if (choice.value === "" && featureOption.emptyOptionLabel) {
1980
+ return featureOption.emptyOptionLabel;
1981
+ }
1982
+ return choice.value;
1983
+ }
1984
+ function normalizeConfigFeatureValue(value) {
1985
+ if (typeof value === "string") {
1986
+ return value;
1987
+ }
1988
+ if (value === null) {
1989
+ return "";
1990
+ }
1991
+ throw new Error(`ACP feature value must be a string`);
1992
+ }
1993
+ function deriveSelectorOptions(configOptions, category) {
1994
+ const option = findSelectConfigOption({ configOptions, category });
1995
+ if (!option) {
1996
+ return [];
1997
+ }
1998
+ return flattenSelectOptions(option.options).map((value) => ({
1999
+ id: value.value,
2000
+ label: value.name,
2001
+ description: value.description ?? undefined,
2002
+ isDefault: value.value === option.currentValue,
2003
+ metadata: value.group ? { group: value.group } : undefined,
2004
+ }));
2005
+ }
2006
+ function deriveCurrentConfigValue(configOptions, category) {
2007
+ const option = configOptions?.find((entry) => entry.type === "select" && entry.category === category);
2008
+ return option?.currentValue ?? null;
2009
+ }
2010
+ function normalizeMcpServers(servers) {
2011
+ if (!servers) {
2012
+ return [];
2013
+ }
2014
+ return Object.entries(servers).map(([name, config]) => {
2015
+ if (config.type === "stdio") {
2016
+ return {
2017
+ name,
2018
+ command: config.command,
2019
+ args: config.args ?? [],
2020
+ env: Object.entries(config.env ?? {}).map(([envName, value]) => ({
2021
+ name: envName,
2022
+ value,
2023
+ })),
2024
+ };
2025
+ }
2026
+ if (config.type === "http") {
2027
+ return {
2028
+ type: "http",
2029
+ name,
2030
+ url: config.url,
2031
+ headers: Object.entries(config.headers ?? {}).map(([headerName, value]) => ({
2032
+ name: headerName,
2033
+ value,
2034
+ })),
2035
+ };
2036
+ }
2037
+ return {
2038
+ type: "sse",
2039
+ name,
2040
+ url: config.url,
2041
+ headers: Object.entries(config.headers ?? {}).map(([headerName, value]) => ({
2042
+ name: headerName,
2043
+ value,
2044
+ })),
2045
+ };
2046
+ });
2047
+ }
2048
+ function toACPContentBlocks(prompt) {
2049
+ if (typeof prompt === "string") {
2050
+ return [{ type: "text", text: prompt }];
2051
+ }
2052
+ const contentBlocks = [];
2053
+ for (const block of prompt) {
2054
+ switch (block.type) {
2055
+ case "text":
2056
+ contentBlocks.push({ type: "text", text: block.text });
2057
+ break;
2058
+ case "image":
2059
+ contentBlocks.push({ type: "image", data: block.data, mimeType: block.mimeType });
2060
+ break;
2061
+ default:
2062
+ contentBlocks.push({ type: "text", text: renderPromptAttachmentAsText(block) });
2063
+ break;
2064
+ }
2065
+ }
2066
+ return contentBlocks;
2067
+ }
2068
+ function extractPromptText(prompt) {
2069
+ if (typeof prompt === "string") {
2070
+ return prompt;
2071
+ }
2072
+ return prompt
2073
+ .filter((block) => block.type === "text")
2074
+ .map((block) => block.text)
2075
+ .join("");
2076
+ }
2077
+ function contentBlockToText(content) {
2078
+ switch (content.type) {
2079
+ case "text":
2080
+ return content.text;
2081
+ case "resource_link":
2082
+ return content.title ?? content.uri;
2083
+ case "resource":
2084
+ return "text" in content.resource
2085
+ ? content.resource.text
2086
+ : `[resource:${content.resource.mimeType ?? "binary"}]`;
2087
+ case "image":
2088
+ return "[image]";
2089
+ case "audio":
2090
+ return "[audio]";
2091
+ default:
2092
+ return "";
2093
+ }
2094
+ }
2095
+ function coalesceDefined(next, previous, fallback) {
2096
+ if (next !== undefined) {
2097
+ return next;
2098
+ }
2099
+ if (previous !== undefined) {
2100
+ return previous;
2101
+ }
2102
+ return fallback;
2103
+ }
2104
+ function mergeToolSnapshot(toolCallId, update, previous) {
2105
+ return {
2106
+ toolCallId,
2107
+ title: update.title ?? previous?.title ?? toolCallId,
2108
+ kind: update.kind ?? previous?.kind ?? null,
2109
+ status: update.status ?? previous?.status ?? null,
2110
+ content: coalesceDefined(update.content, previous?.content, null),
2111
+ locations: coalesceDefined(update.locations, previous?.locations, null),
2112
+ rawInput: update.rawInput !== undefined ? update.rawInput : previous?.rawInput,
2113
+ rawOutput: update.rawOutput !== undefined ? update.rawOutput : previous?.rawOutput,
2114
+ };
2115
+ }
2116
+ function mapPlanToTimeline(plan) {
2117
+ return {
2118
+ type: "todo",
2119
+ items: plan.entries.map((entry) => ({
2120
+ text: entry.content,
2121
+ completed: entry.status === "completed",
2122
+ })),
2123
+ };
2124
+ }
2125
+ function mapToolSnapshotToTimeline(snapshot, terminals) {
2126
+ const status = mapToolStatus(snapshot.status);
2127
+ const detail = mapToolDetail(snapshot, terminals);
2128
+ const base = {
2129
+ type: "tool_call",
2130
+ callId: snapshot.toolCallId,
2131
+ name: snapshot.kind ?? snapshot.title,
2132
+ detail,
2133
+ metadata: {
2134
+ kind: snapshot.kind ?? undefined,
2135
+ title: snapshot.title,
2136
+ },
2137
+ };
2138
+ if (status === "failed") {
2139
+ return {
2140
+ ...base,
2141
+ status: "failed",
2142
+ error: { message: readErrorMessage(snapshot.rawOutput) },
2143
+ };
2144
+ }
2145
+ if (status === "completed") {
2146
+ return {
2147
+ ...base,
2148
+ status: "completed",
2149
+ error: null,
2150
+ };
2151
+ }
2152
+ return {
2153
+ ...base,
2154
+ status: "running",
2155
+ error: null,
2156
+ };
2157
+ }
2158
+ function mapToolStatus(status) {
2159
+ switch (status) {
2160
+ case "completed":
2161
+ return "completed";
2162
+ case "failed":
2163
+ return "failed";
2164
+ case "pending":
2165
+ case "in_progress":
2166
+ default:
2167
+ return "running";
2168
+ }
2169
+ }
2170
+ function mapToolDetail(snapshot, terminals) {
2171
+ const context = {
2172
+ snapshot,
2173
+ firstLocation: snapshot.locations?.[0]?.path,
2174
+ textContent: extractToolText(snapshot.content),
2175
+ diffContent: extractDiffContent(snapshot.content),
2176
+ terminalContent: extractTerminalContent(snapshot.content, terminals),
2177
+ rawInput: readRecord(snapshot.rawInput),
2178
+ rawOutput: readRecord(snapshot.rawOutput),
2179
+ };
2180
+ switch (snapshot.kind) {
2181
+ case "read":
2182
+ return buildReadToolDetail(context);
2183
+ case "edit":
2184
+ case "delete":
2185
+ return buildEditToolDetail(context);
2186
+ case "search":
2187
+ return buildSearchAcpToolDetail(context);
2188
+ case "execute":
2189
+ return buildShellToolDetail(context);
2190
+ case "fetch":
2191
+ return buildFetchToolDetail(context);
2192
+ case "think":
2193
+ return {
2194
+ type: "plain_text",
2195
+ label: snapshot.title,
2196
+ icon: "brain",
2197
+ text: context.textContent ?? stringifyUnknown(snapshot.rawOutput),
2198
+ };
2199
+ case "switch_mode":
2200
+ return {
2201
+ type: "plain_text",
2202
+ label: snapshot.title,
2203
+ icon: "sparkles",
2204
+ text: context.textContent ?? stringifyUnknown(snapshot.rawInput),
2205
+ };
2206
+ default:
2207
+ return buildDefaultToolDetail(context);
2208
+ }
2209
+ }
2210
+ function buildReadToolDetail(context) {
2211
+ const { snapshot, firstLocation, textContent, rawInput, rawOutput } = context;
2212
+ return {
2213
+ type: "read",
2214
+ filePath: firstLocation ?? readString(rawInput, ["path", "filePath", "file"]) ?? snapshot.title,
2215
+ content: textContent ?? readString(rawOutput, ["content", "text"]),
2216
+ offset: readNumber(rawInput, ["offset", "line"]),
2217
+ limit: readNumber(rawInput, ["limit"]),
2218
+ };
2219
+ }
2220
+ function buildEditToolDetail(context) {
2221
+ const { snapshot, firstLocation, textContent, diffContent, rawInput } = context;
2222
+ return {
2223
+ type: "edit",
2224
+ filePath: firstLocation ?? readString(rawInput, ["path", "filePath", "file"]) ?? snapshot.title,
2225
+ oldString: diffContent?.oldText ?? readString(rawInput, ["oldText", "oldString"]),
2226
+ newString: snapshot.kind === "delete"
2227
+ ? ""
2228
+ : (diffContent?.newText ?? readString(rawInput, ["newText", "newString"])),
2229
+ unifiedDiff: textContent ?? undefined,
2230
+ };
2231
+ }
2232
+ function buildSearchAcpToolDetail(context) {
2233
+ const { snapshot, textContent, rawInput, rawOutput } = context;
2234
+ return {
2235
+ type: "search",
2236
+ query: readString(rawInput, ["query", "pattern"]) ?? snapshot.title,
2237
+ toolName: "search",
2238
+ content: textContent ?? readString(rawOutput, ["content", "text"]),
2239
+ filePaths: snapshot.locations?.map((location) => location.path),
2240
+ };
2241
+ }
2242
+ function buildShellToolDetail(context) {
2243
+ const { snapshot, textContent, terminalContent, rawInput, rawOutput } = context;
2244
+ return {
2245
+ type: "shell",
2246
+ command: terminalContent?.command ??
2247
+ buildShellCommand(rawInput) ??
2248
+ readString(rawInput, ["command"]) ??
2249
+ snapshot.title,
2250
+ cwd: terminalContent?.cwd ?? readString(rawInput, ["cwd"]),
2251
+ output: terminalContent?.output ?? textContent ?? readString(rawOutput, ["output", "text"]),
2252
+ exitCode: terminalContent?.exitCode ?? readNumber(rawOutput, ["exitCode"]),
2253
+ };
2254
+ }
2255
+ function buildFetchToolDetail(context) {
2256
+ const { snapshot, textContent, rawInput, rawOutput } = context;
2257
+ return {
2258
+ type: "fetch",
2259
+ url: readString(rawInput, ["url"]) ?? snapshot.title,
2260
+ prompt: readString(rawInput, ["prompt"]),
2261
+ result: textContent ?? readString(rawOutput, ["result", "text", "content"]),
2262
+ code: readNumber(rawOutput, ["status", "code"]),
2263
+ };
2264
+ }
2265
+ function buildDefaultToolDetail(context) {
2266
+ const { snapshot, textContent, terminalContent } = context;
2267
+ if (terminalContent) {
2268
+ return {
2269
+ type: "shell",
2270
+ command: terminalContent.command ?? snapshot.title,
2271
+ cwd: terminalContent.cwd,
2272
+ output: terminalContent.output,
2273
+ exitCode: terminalContent.exitCode,
2274
+ };
2275
+ }
2276
+ if (textContent) {
2277
+ return {
2278
+ type: "plain_text",
2279
+ label: snapshot.title,
2280
+ text: textContent,
2281
+ icon: "wrench",
2282
+ };
2283
+ }
2284
+ return {
2285
+ type: "unknown",
2286
+ input: snapshot.rawInput ?? null,
2287
+ output: snapshot.rawOutput ?? null,
2288
+ };
2289
+ }
2290
+ function extractToolText(content) {
2291
+ if (!content) {
2292
+ return undefined;
2293
+ }
2294
+ const parts = [];
2295
+ for (const item of content) {
2296
+ if (item.type === "content") {
2297
+ const text = contentBlockToText(item.content);
2298
+ if (text) {
2299
+ parts.push(text);
2300
+ }
2301
+ }
2302
+ }
2303
+ return parts.length > 0 ? parts.join("\n") : undefined;
2304
+ }
2305
+ function extractDiffContent(content) {
2306
+ const diff = content?.find((item) => item.type === "diff");
2307
+ return diff ? { oldText: diff.oldText ?? undefined, newText: diff.newText } : null;
2308
+ }
2309
+ function extractTerminalContent(content, terminals) {
2310
+ const terminal = content?.find((item) => item.type === "terminal");
2311
+ if (!terminal) {
2312
+ return undefined;
2313
+ }
2314
+ const entry = terminals.get(terminal.terminalId);
2315
+ if (!entry) {
2316
+ return undefined;
2317
+ }
2318
+ return {
2319
+ output: entry.output,
2320
+ exitCode: entry.exit?.exitCode ?? null,
2321
+ };
2322
+ }
2323
+ function mapPermissionRequest(provider, requestId, params, snapshot) {
2324
+ const kind = snapshot.kind === "switch_mode" ? "mode" : "tool";
2325
+ return {
2326
+ id: requestId,
2327
+ provider,
2328
+ name: snapshot.kind ?? snapshot.title,
2329
+ kind,
2330
+ title: params.toolCall.title ?? snapshot.title,
2331
+ detail: mapToolDetail(snapshot, new Map()),
2332
+ metadata: {
2333
+ toolCallId: params.toolCall.toolCallId,
2334
+ rawRequest: params,
2335
+ options: params.options,
2336
+ },
2337
+ };
2338
+ }
2339
+ function selectPermissionOption(options, response) {
2340
+ const order = response.behavior === "allow"
2341
+ ? ["allow_once", "allow_always"]
2342
+ : ["reject_once", "reject_always"];
2343
+ for (const kind of order) {
2344
+ const match = options.find((option) => option.kind === kind);
2345
+ if (match) {
2346
+ return match;
2347
+ }
2348
+ }
2349
+ return null;
2350
+ }
2351
+ function appendTerminalOutput(entry, chunk) {
2352
+ entry.output += chunk;
2353
+ const limit = entry.outputByteLimit;
2354
+ if (!limit) {
2355
+ return;
2356
+ }
2357
+ while (Buffer.byteLength(entry.output, "utf8") > limit && entry.output.length > 0) {
2358
+ entry.output = entry.output.slice(1);
2359
+ entry.truncated = true;
2360
+ }
2361
+ }
2362
+ function readRecord(value) {
2363
+ return isRecord(value) ? value : null;
2364
+ }
2365
+ function readString(record, keys) {
2366
+ if (!record) {
2367
+ return undefined;
2368
+ }
2369
+ for (const key of keys) {
2370
+ const value = record[key];
2371
+ if (typeof value === "string" && value.trim().length > 0) {
2372
+ return value;
2373
+ }
2374
+ }
2375
+ return undefined;
2376
+ }
2377
+ function readNumber(record, keys) {
2378
+ if (!record) {
2379
+ return undefined;
2380
+ }
2381
+ for (const key of keys) {
2382
+ const value = record[key];
2383
+ if (typeof value === "number" && Number.isFinite(value)) {
2384
+ return value;
2385
+ }
2386
+ }
2387
+ return undefined;
2388
+ }
2389
+ function buildShellCommand(record) {
2390
+ if (!record) {
2391
+ return undefined;
2392
+ }
2393
+ const command = readString(record, ["command"]);
2394
+ const args = Array.isArray(record["args"])
2395
+ ? record["args"].filter((value) => typeof value === "string")
2396
+ : [];
2397
+ if (!command) {
2398
+ return undefined;
2399
+ }
2400
+ return args.length > 0 ? `${command} ${args.join(" ")}` : command;
2401
+ }
2402
+ function readErrorMessage(value) {
2403
+ if (typeof value === "string") {
2404
+ return value;
2405
+ }
2406
+ const record = readRecord(value);
2407
+ return readString(record, ["message", "error"]) ?? "Tool call failed";
2408
+ }
2409
+ function stringifyUnknown(value) {
2410
+ if (value == null) {
2411
+ return undefined;
2412
+ }
2413
+ if (typeof value === "string") {
2414
+ return value;
2415
+ }
2416
+ try {
2417
+ return JSON.stringify(value);
2418
+ }
2419
+ catch {
2420
+ return typeof value === "bigint" ? String(value) : "[unserializable]";
2421
+ }
2422
+ }
2423
+ function coerceSessionConfigMetadata(metadata) {
2424
+ if (!metadata || typeof metadata !== "object") {
2425
+ return {};
2426
+ }
2427
+ return metadata;
2428
+ }
2429
+ async function terminateChildProcess(child, timeoutMs, terminate) {
2430
+ try {
2431
+ await terminate(child, { gracefulTimeoutMs: timeoutMs, forceTimeoutMs: timeoutMs });
2432
+ }
2433
+ finally {
2434
+ child.stdin.destroy();
2435
+ child.stdout.destroy();
2436
+ child.stderr.destroy();
2437
+ }
2438
+ }
2439
+ //# sourceMappingURL=acp-agent.js.map