@camerontaylor/paseo-server 0.8.0-fork.1

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 (928) 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 +160 -0
  6. package/dist/scripts/supervisor-log-config.js +31 -0
  7. package/dist/scripts/supervisor.js +313 -0
  8. package/dist/server/executable-resolution/executable-resolution.d.ts +10 -0
  9. package/dist/server/executable-resolution/executable-resolution.js +121 -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 +40 -0
  13. package/dist/server/server/agent/activity-curator.js +243 -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-configuration-validator.d.ts +18 -0
  17. package/dist/server/server/agent/agent-configuration-validator.js +42 -0
  18. package/dist/server/server/agent/agent-loading.d.ts +17 -0
  19. package/dist/server/server/agent/agent-loading.js +88 -0
  20. package/dist/server/server/agent/agent-manager.d.ts +555 -0
  21. package/dist/server/server/agent/agent-manager.js +3930 -0
  22. package/dist/server/server/agent/agent-owner.d.ts +12 -0
  23. package/dist/server/server/agent/agent-owner.js +12 -0
  24. package/dist/server/server/agent/agent-projections.d.ts +26 -0
  25. package/dist/server/server/agent/agent-projections.js +414 -0
  26. package/dist/server/server/agent/agent-prompt.d.ts +91 -0
  27. package/dist/server/server/agent/agent-prompt.js +359 -0
  28. package/dist/server/server/agent/agent-response-loop.d.ts +72 -0
  29. package/dist/server/server/agent/agent-response-loop.js +336 -0
  30. package/dist/server/server/agent/agent-run-state.d.ts +76 -0
  31. package/dist/server/server/agent/agent-run-state.js +212 -0
  32. package/dist/server/server/agent/agent-sdk-types.d.ts +742 -0
  33. package/dist/server/server/agent/agent-sdk-types.js +25 -0
  34. package/dist/server/server/agent/agent-storage.d.ts +148 -0
  35. package/dist/server/server/agent/agent-storage.js +401 -0
  36. package/dist/server/server/agent/agent-stream-coalescer.d.ts +43 -0
  37. package/dist/server/server/agent/agent-stream-coalescer.js +187 -0
  38. package/dist/server/server/agent/agent-timeline-content.d.ts +6 -0
  39. package/dist/server/server/agent/agent-timeline-content.js +62 -0
  40. package/dist/server/server/agent/agent-timeline-store-types.d.ts +54 -0
  41. package/dist/server/server/agent/agent-timeline-store-types.js +2 -0
  42. package/dist/server/server/agent/agent-timeline-store.d.ts +31 -0
  43. package/dist/server/server/agent/agent-timeline-store.js +249 -0
  44. package/dist/server/server/agent/audio-utils.d.ts +3 -0
  45. package/dist/server/server/agent/audio-utils.js +19 -0
  46. package/dist/server/server/agent/create-agent/create.d.ts +102 -0
  47. package/dist/server/server/agent/create-agent/create.js +362 -0
  48. package/dist/server/server/agent/create-agent/intent.d.ts +25 -0
  49. package/dist/server/server/agent/create-agent/intent.js +30 -0
  50. package/dist/server/server/agent/create-agent-lifecycle-dispatch.d.ts +65 -0
  51. package/dist/server/server/agent/create-agent-lifecycle-dispatch.js +166 -0
  52. package/dist/server/server/agent/create-agent-mode.d.ts +13 -0
  53. package/dist/server/server/agent/create-agent-mode.js +65 -0
  54. package/dist/server/server/agent/create-agent-title.d.ts +10 -0
  55. package/dist/server/server/agent/create-agent-title.js +34 -0
  56. package/dist/server/server/agent/dictation-debug.d.ts +13 -0
  57. package/dist/server/server/agent/dictation-debug.js +50 -0
  58. package/dist/server/server/agent/import-sessions.d.ts +57 -0
  59. package/dist/server/server/agent/import-sessions.js +240 -0
  60. package/dist/server/server/agent/lifecycle-command.d.ts +73 -0
  61. package/dist/server/server/agent/lifecycle-command.js +99 -0
  62. package/dist/server/server/agent/mcp-server.d.ts +5 -0
  63. package/dist/server/server/agent/mcp-server.js +31 -0
  64. package/dist/server/server/agent/mcp-shared.d.ts +181 -0
  65. package/dist/server/server/agent/mcp-shared.js +199 -0
  66. package/dist/server/server/agent/mutable-provider-config-owner.d.ts +8 -0
  67. package/dist/server/server/agent/mutable-provider-config-owner.js +35 -0
  68. package/dist/server/server/agent/paseo-tool-policy.d.ts +9 -0
  69. package/dist/server/server/agent/paseo-tool-policy.js +16 -0
  70. package/dist/server/server/agent/pcm16-resampler.d.ts +14 -0
  71. package/dist/server/server/agent/pcm16-resampler.js +63 -0
  72. package/dist/server/server/agent/permission-response.d.ts +15 -0
  73. package/dist/server/server/agent/permission-response.js +14 -0
  74. package/dist/server/server/agent/plugin-provider.d.ts +16 -0
  75. package/dist/server/server/agent/plugin-provider.js +1356 -0
  76. package/dist/server/server/agent/prompt-attachments.d.ts +12 -0
  77. package/dist/server/server/agent/prompt-attachments.js +182 -0
  78. package/dist/server/server/agent/provider-history-timestamps.d.ts +2 -0
  79. package/dist/server/server/agent/provider-history-timestamps.js +16 -0
  80. package/dist/server/server/agent/provider-launch-config.d.ts +43 -0
  81. package/dist/server/server/agent/provider-launch-config.js +167 -0
  82. package/dist/server/server/agent/provider-notices.d.ts +4 -0
  83. package/dist/server/server/agent/provider-notices.js +9 -0
  84. package/dist/server/server/agent/provider-options.d.ts +19 -0
  85. package/dist/server/server/agent/provider-options.js +53 -0
  86. package/dist/server/server/agent/provider-refresh-deadline.d.ts +11 -0
  87. package/dist/server/server/agent/provider-refresh-deadline.js +65 -0
  88. package/dist/server/server/agent/provider-registry.d.ts +72 -0
  89. package/dist/server/server/agent/provider-registry.js +604 -0
  90. package/dist/server/server/agent/provider-runtime.d.ts +16 -0
  91. package/dist/server/server/agent/provider-runtime.js +35 -0
  92. package/dist/server/server/agent/provider-session-import.d.ts +10 -0
  93. package/dist/server/server/agent/provider-session-import.js +55 -0
  94. package/dist/server/server/agent/provider-snapshot-manager.d.ts +166 -0
  95. package/dist/server/server/agent/provider-snapshot-manager.js +843 -0
  96. package/dist/server/server/agent/provider-subagents/store.d.ts +68 -0
  97. package/dist/server/server/agent/provider-subagents/store.js +111 -0
  98. package/dist/server/server/agent/providers/acp-agent.d.ts +703 -0
  99. package/dist/server/server/agent/providers/acp-agent.js +3412 -0
  100. package/dist/server/server/agent/providers/claude/agent.d.ts +74 -0
  101. package/dist/server/server/agent/providers/claude/agent.js +5236 -0
  102. package/dist/server/server/agent/providers/claude/feature-definitions.d.ts +8 -0
  103. package/dist/server/server/agent/providers/claude/feature-definitions.js +24 -0
  104. package/dist/server/server/agent/providers/claude/hooks.d.ts +12 -0
  105. package/dist/server/server/agent/providers/claude/hooks.js +20 -0
  106. package/dist/server/server/agent/providers/claude/model-manifest.d.ts +147 -0
  107. package/dist/server/server/agent/providers/claude/model-manifest.js +342 -0
  108. package/dist/server/server/agent/providers/claude/models.d.ts +28 -0
  109. package/dist/server/server/agent/providers/claude/models.js +141 -0
  110. package/dist/server/server/agent/providers/claude/options.d.ts +85 -0
  111. package/dist/server/server/agent/providers/claude/options.js +93 -0
  112. package/dist/server/server/agent/providers/claude/partial-json.d.ts +5 -0
  113. package/dist/server/server/agent/providers/claude/partial-json.js +306 -0
  114. package/dist/server/server/agent/providers/claude/project-dir.d.ts +6 -0
  115. package/dist/server/server/agent/providers/claude/project-dir.js +57 -0
  116. package/dist/server/server/agent/providers/claude/query.d.ts +17 -0
  117. package/dist/server/server/agent/providers/claude/query.js +86 -0
  118. package/dist/server/server/agent/providers/claude/rewind.d.ts +30 -0
  119. package/dist/server/server/agent/providers/claude/rewind.js +30 -0
  120. package/dist/server/server/agent/providers/claude/side-question.d.ts +16 -0
  121. package/dist/server/server/agent/providers/claude/side-question.js +57 -0
  122. package/dist/server/server/agent/providers/claude/sidechain-tracker.d.ts +35 -0
  123. package/dist/server/server/agent/providers/claude/sidechain-tracker.js +392 -0
  124. package/dist/server/server/agent/providers/claude/subagents/live-source.d.ts +161 -0
  125. package/dist/server/server/agent/providers/claude/subagents/live-source.js +415 -0
  126. package/dist/server/server/agent/providers/claude/subagents/observation.d.ts +53 -0
  127. package/dist/server/server/agent/providers/claude/subagents/observation.js +57 -0
  128. package/dist/server/server/agent/providers/claude/subagents/presentation.d.ts +12 -0
  129. package/dist/server/server/agent/providers/claude/subagents/presentation.js +41 -0
  130. package/dist/server/server/agent/providers/claude/subagents/replay-source.d.ts +70 -0
  131. package/dist/server/server/agent/providers/claude/subagents/replay-source.js +305 -0
  132. package/dist/server/server/agent/providers/claude/subagents/workflow-output.d.ts +4 -0
  133. package/dist/server/server/agent/providers/claude/subagents/workflow-output.js +86 -0
  134. package/dist/server/server/agent/providers/claude/subagents/workflow-replay-source.d.ts +38 -0
  135. package/dist/server/server/agent/providers/claude/subagents/workflow-replay-source.js +225 -0
  136. package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts +37 -0
  137. package/dist/server/server/agent/providers/claude/task-notification-tool-call.js +296 -0
  138. package/dist/server/server/agent/providers/claude/task-state.d.ts +18 -0
  139. package/dist/server/server/agent/providers/claude/task-state.js +185 -0
  140. package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.d.ts +24 -0
  141. package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.js +23 -0
  142. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts +3 -0
  143. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +130 -0
  144. package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts +16 -0
  145. package/dist/server/server/agent/providers/claude/tool-call-mapper.js +129 -0
  146. package/dist/server/server/agent/providers/codex/app-server-transport.d.ts +101 -0
  147. package/dist/server/server/agent/providers/codex/app-server-transport.js +290 -0
  148. package/dist/server/server/agent/providers/codex/async-questions.d.ts +18 -0
  149. package/dist/server/server/agent/providers/codex/async-questions.js +135 -0
  150. package/dist/server/server/agent/providers/codex/options.d.ts +59 -0
  151. package/dist/server/server/agent/providers/codex/options.js +82 -0
  152. package/dist/server/server/agent/providers/codex/rewind.d.ts +24 -0
  153. package/dist/server/server/agent/providers/codex/rewind.js +77 -0
  154. package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts +12 -0
  155. package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js +104 -0
  156. package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +24 -0
  157. package/dist/server/server/agent/providers/codex/tool-call-mapper.js +909 -0
  158. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +384 -0
  159. package/dist/server/server/agent/providers/codex-app-server-agent.js +5877 -0
  160. package/dist/server/server/agent/providers/codex-feature-definitions.d.ts +11 -0
  161. package/dist/server/server/agent/providers/codex-feature-definitions.js +55 -0
  162. package/dist/server/server/agent/providers/copilot-acp-agent.d.ts +26 -0
  163. package/dist/server/server/agent/providers/copilot-acp-agent.js +187 -0
  164. package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +17 -0
  165. package/dist/server/server/agent/providers/cursor-acp-agent.js +31 -0
  166. package/dist/server/server/agent/providers/diagnostic-utils.d.ts +36 -0
  167. package/dist/server/server/agent/providers/diagnostic-utils.js +356 -0
  168. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +55 -0
  169. package/dist/server/server/agent/providers/generic-acp-agent.js +178 -0
  170. package/dist/server/server/agent/providers/gjc-acp-agent.d.ts +155 -0
  171. package/dist/server/server/agent/providers/gjc-acp-agent.js +588 -0
  172. package/dist/server/server/agent/providers/jsonl-frame-decoder.d.ts +17 -0
  173. package/dist/server/server/agent/providers/jsonl-frame-decoder.js +149 -0
  174. package/dist/server/server/agent/providers/jsonl-rpc-process.d.ts +63 -0
  175. package/dist/server/server/agent/providers/jsonl-rpc-process.js +207 -0
  176. package/dist/server/server/agent/providers/kimi-acp-agent.d.ts +35 -0
  177. package/dist/server/server/agent/providers/kimi-acp-agent.js +65 -0
  178. package/dist/server/server/agent/providers/kiro-acp-agent.d.ts +17 -0
  179. package/dist/server/server/agent/providers/kiro-acp-agent.js +78 -0
  180. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +111 -0
  181. package/dist/server/server/agent/providers/mock-load-test-agent.js +1340 -0
  182. package/dist/server/server/agent/providers/mock-slow-provider.d.ts +14 -0
  183. package/dist/server/server/agent/providers/mock-slow-provider.js +40 -0
  184. package/dist/server/server/agent/providers/omp/advisor-message.d.ts +11 -0
  185. package/dist/server/server/agent/providers/omp/advisor-message.js +80 -0
  186. package/dist/server/server/agent/providers/omp/agent.d.ts +178 -0
  187. package/dist/server/server/agent/providers/omp/agent.js +1952 -0
  188. package/dist/server/server/agent/providers/omp/cli-runtime.d.ts +22 -0
  189. package/dist/server/server/agent/providers/omp/cli-runtime.js +208 -0
  190. package/dist/server/server/agent/providers/omp/commands.d.ts +8 -0
  191. package/dist/server/server/agent/providers/omp/commands.js +62 -0
  192. package/dist/server/server/agent/providers/omp/custom-message.d.ts +7 -0
  193. package/dist/server/server/agent/providers/omp/custom-message.js +4 -0
  194. package/dist/server/server/agent/providers/omp/event-mapper.d.ts +13 -0
  195. package/dist/server/server/agent/providers/omp/event-mapper.js +267 -0
  196. package/dist/server/server/agent/providers/omp/history-hooks.d.ts +3 -0
  197. package/dist/server/server/agent/providers/omp/history-hooks.js +13 -0
  198. package/dist/server/server/agent/providers/omp/history.d.ts +19 -0
  199. package/dist/server/server/agent/providers/omp/history.js +306 -0
  200. package/dist/server/server/agent/providers/omp/host-tools.d.ts +14 -0
  201. package/dist/server/server/agent/providers/omp/host-tools.js +196 -0
  202. package/dist/server/server/agent/providers/omp/map-omp-model.d.ts +11 -0
  203. package/dist/server/server/agent/providers/omp/map-omp-model.js +67 -0
  204. package/dist/server/server/agent/providers/omp/message-history.d.ts +38 -0
  205. package/dist/server/server/agent/providers/omp/message-history.js +216 -0
  206. package/dist/server/server/agent/providers/omp/protocol-session.d.ts +13 -0
  207. package/dist/server/server/agent/providers/omp/protocol-session.js +39 -0
  208. package/dist/server/server/agent/providers/omp/provider-config.d.ts +43 -0
  209. package/dist/server/server/agent/providers/omp/provider-config.js +120 -0
  210. package/dist/server/server/agent/providers/omp/rpc-types.d.ts +2040 -0
  211. package/dist/server/server/agent/providers/omp/rpc-types.js +551 -0
  212. package/dist/server/server/agent/providers/omp/rpc-ui-permission-mapper.d.ts +24 -0
  213. package/dist/server/server/agent/providers/omp/rpc-ui-permission-mapper.js +156 -0
  214. package/dist/server/server/agent/providers/omp/runtime.d.ts +85 -0
  215. package/dist/server/server/agent/providers/omp/runtime.js +62 -0
  216. package/dist/server/server/agent/providers/omp/session-descriptor.d.ts +16 -0
  217. package/dist/server/server/agent/providers/omp/session-descriptor.js +389 -0
  218. package/dist/server/server/agent/providers/omp/subagent-card-tracker.d.ts +33 -0
  219. package/dist/server/server/agent/providers/omp/subagent-card-tracker.js +264 -0
  220. package/dist/server/server/agent/providers/omp/subagent-index.d.ts +13 -0
  221. package/dist/server/server/agent/providers/omp/subagent-index.js +111 -0
  222. package/dist/server/server/agent/providers/omp/subagent-title.d.ts +2 -0
  223. package/dist/server/server/agent/providers/omp/subagent-title.js +14 -0
  224. package/dist/server/server/agent/providers/omp/system-notice.d.ts +8 -0
  225. package/dist/server/server/agent/providers/omp/system-notice.js +68 -0
  226. package/dist/server/server/agent/providers/omp/todo-mapper.d.ts +9 -0
  227. package/dist/server/server/agent/providers/omp/todo-mapper.js +52 -0
  228. package/dist/server/server/agent/providers/omp/tool-call-detail.d.ts +110 -0
  229. package/dist/server/server/agent/providers/omp/tool-call-detail.js +288 -0
  230. package/dist/server/server/agent/providers/omp/tool-call-id.d.ts +4 -0
  231. package/dist/server/server/agent/providers/omp/tool-call-id.js +34 -0
  232. package/dist/server/server/agent/providers/omp/tool-call-mapper.d.ts +7 -0
  233. package/dist/server/server/agent/providers/omp/tool-call-mapper.js +98 -0
  234. package/dist/server/server/agent/providers/omp/usage-poller.d.ts +32 -0
  235. package/dist/server/server/agent/providers/omp/usage-poller.js +141 -0
  236. package/dist/server/server/agent/providers/opencode/bridge-plugin.bundle.mjs +14678 -0
  237. package/dist/server/server/agent/providers/opencode/bridge.d.ts +39 -0
  238. package/dist/server/server/agent/providers/opencode/bridge.js +249 -0
  239. package/dist/server/server/agent/providers/opencode/event-consumer.d.ts +60 -0
  240. package/dist/server/server/agent/providers/opencode/event-consumer.js +221 -0
  241. package/dist/server/server/agent/providers/opencode/options.d.ts +156 -0
  242. package/dist/server/server/agent/providers/opencode/options.js +62 -0
  243. package/dist/server/server/agent/providers/opencode/paths.d.ts +2 -0
  244. package/dist/server/server/agent/providers/opencode/paths.js +7 -0
  245. package/dist/server/server/agent/providers/opencode/rewind.d.ts +18 -0
  246. package/dist/server/server/agent/providers/opencode/rewind.js +14 -0
  247. package/dist/server/server/agent/providers/opencode/server-manager.d.ts +101 -0
  248. package/dist/server/server/agent/providers/opencode/server-manager.js +513 -0
  249. package/dist/server/server/agent/providers/opencode/side-question.d.ts +78 -0
  250. package/dist/server/server/agent/providers/opencode/side-question.js +172 -0
  251. package/dist/server/server/agent/providers/opencode/subagent-presentation.d.ts +36 -0
  252. package/dist/server/server/agent/providers/opencode/subagent-presentation.js +62 -0
  253. package/dist/server/server/agent/providers/opencode/test-server-manager.d.ts +22 -0
  254. package/dist/server/server/agent/providers/opencode/test-server-manager.js +43 -0
  255. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts +3 -0
  256. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +256 -0
  257. package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts +13 -0
  258. package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +53 -0
  259. package/dist/server/server/agent/providers/opencode-agent.d.ts +393 -0
  260. package/dist/server/server/agent/providers/opencode-agent.js +4106 -0
  261. package/dist/server/server/agent/providers/pi/agent.d.ts +164 -0
  262. package/dist/server/server/agent/providers/pi/agent.js +2236 -0
  263. package/dist/server/server/agent/providers/pi/cli-runtime.d.ts +21 -0
  264. package/dist/server/server/agent/providers/pi/cli-runtime.js +177 -0
  265. package/dist/server/server/agent/providers/pi/history-mapper.d.ts +36 -0
  266. package/dist/server/server/agent/providers/pi/history-mapper.js +212 -0
  267. package/dist/server/server/agent/providers/pi/rewind.d.ts +8 -0
  268. package/dist/server/server/agent/providers/pi/rewind.js +8 -0
  269. package/dist/server/server/agent/providers/pi/rpc-types.d.ts +252 -0
  270. package/dist/server/server/agent/providers/pi/rpc-types.js +2 -0
  271. package/dist/server/server/agent/providers/pi/runtime.d.ts +77 -0
  272. package/dist/server/server/agent/providers/pi/runtime.js +65 -0
  273. package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +16 -0
  274. package/dist/server/server/agent/providers/pi/session-descriptor.js +355 -0
  275. package/dist/server/server/agent/providers/pi/tool-call-mapper.d.ts +113 -0
  276. package/dist/server/server/agent/providers/pi/tool-call-mapper.js +340 -0
  277. package/dist/server/server/agent/providers/pi/usage-poller.d.ts +32 -0
  278. package/dist/server/server/agent/providers/pi/usage-poller.js +141 -0
  279. package/dist/server/server/agent/providers/provider-image-output.d.ts +25 -0
  280. package/dist/server/server/agent/providers/provider-image-output.js +165 -0
  281. package/dist/server/server/agent/providers/provider-runner.d.ts +27 -0
  282. package/dist/server/server/agent/providers/provider-runner.js +81 -0
  283. package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +884 -0
  284. package/dist/server/server/agent/providers/tool-call-detail-primitives.js +778 -0
  285. package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +25 -0
  286. package/dist/server/server/agent/providers/tool-call-mapper-utils.js +208 -0
  287. package/dist/server/server/agent/providers/trae-acp-agent.d.ts +15 -0
  288. package/dist/server/server/agent/providers/trae-acp-agent.js +18 -0
  289. package/dist/server/server/agent/recordings-debug.d.ts +3 -0
  290. package/dist/server/server/agent/recordings-debug.js +19 -0
  291. package/dist/server/server/agent/rewind/rewind.d.ts +10 -0
  292. package/dist/server/server/agent/rewind/rewind.js +29 -0
  293. package/dist/server/server/agent/rewind/test-rewind-session.d.ts +48 -0
  294. package/dist/server/server/agent/rewind/test-rewind-session.js +88 -0
  295. package/dist/server/server/agent/runtime-mcp-config.d.ts +14 -0
  296. package/dist/server/server/agent/runtime-mcp-config.js +53 -0
  297. package/dist/server/server/agent/side-conversations/store.d.ts +33 -0
  298. package/dist/server/server/agent/side-conversations/store.js +62 -0
  299. package/dist/server/server/agent/stale-provider-session-error.d.ts +6 -0
  300. package/dist/server/server/agent/stale-provider-session-error.js +11 -0
  301. package/dist/server/server/agent/structured-generation-providers.d.ts +29 -0
  302. package/dist/server/server/agent/structured-generation-providers.js +193 -0
  303. package/dist/server/server/agent/stt-debug.d.ts +10 -0
  304. package/dist/server/server/agent/stt-debug.js +33 -0
  305. package/dist/server/server/agent/stt-manager.d.ts +38 -0
  306. package/dist/server/server/agent/stt-manager.js +246 -0
  307. package/dist/server/server/agent/system-prompt.d.ts +2 -0
  308. package/dist/server/server/agent/system-prompt.js +8 -0
  309. package/dist/server/server/agent/timeline-append.d.ts +10 -0
  310. package/dist/server/server/agent/timeline-append.js +27 -0
  311. package/dist/server/server/agent/timeline-page-bounds.d.ts +19 -0
  312. package/dist/server/server/agent/timeline-page-bounds.js +37 -0
  313. package/dist/server/server/agent/timeline-projection.d.ts +74 -0
  314. package/dist/server/server/agent/timeline-projection.js +467 -0
  315. package/dist/server/server/agent/timeline-prompt-index.d.ts +12 -0
  316. package/dist/server/server/agent/timeline-prompt-index.js +23 -0
  317. package/dist/server/server/agent/tools/paseo-tool-serialization.d.ts +4 -0
  318. package/dist/server/server/agent/tools/paseo-tool-serialization.js +58 -0
  319. package/dist/server/server/agent/tools/paseo-tools.d.ts +62 -0
  320. package/dist/server/server/agent/tools/paseo-tools.js +2445 -0
  321. package/dist/server/server/agent/tools/types.d.ts +39 -0
  322. package/dist/server/server/agent/tools/types.js +2 -0
  323. package/dist/server/server/agent/tts-debug.d.ts +8 -0
  324. package/dist/server/server/agent/tts-debug.js +24 -0
  325. package/dist/server/server/agent/tts-manager.d.ts +41 -0
  326. package/dist/server/server/agent/tts-manager.js +375 -0
  327. package/dist/server/server/agent-attention-policy.d.ts +29 -0
  328. package/dist/server/server/agent-attention-policy.js +36 -0
  329. package/dist/server/server/agent-history-search.d.ts +48 -0
  330. package/dist/server/server/agent-history-search.js +129 -0
  331. package/dist/server/server/atomic-file.d.ts +3 -0
  332. package/dist/server/server/atomic-file.js +19 -0
  333. package/dist/server/server/auth.d.ts +38 -0
  334. package/dist/server/server/auth.js +122 -0
  335. package/dist/server/server/authorization/index.d.ts +18 -0
  336. package/dist/server/server/authorization/index.js +47 -0
  337. package/dist/server/server/authorization/operation-permissions.d.ts +8 -0
  338. package/dist/server/server/authorization/operation-permissions.js +438 -0
  339. package/dist/server/server/auto-archive-on-merge/archive-if-safe.d.ts +40 -0
  340. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +64 -0
  341. package/dist/server/server/auto-archive-on-merge/index.d.ts +13 -0
  342. package/dist/server/server/auto-archive-on-merge/index.js +77 -0
  343. package/dist/server/server/bootstrap.d.ts +166 -0
  344. package/dist/server/server/bootstrap.js +1388 -0
  345. package/dist/server/server/browser-tools/broker.d.ts +45 -0
  346. package/dist/server/server/browser-tools/broker.js +390 -0
  347. package/dist/server/server/browser-tools/errors.d.ts +22 -0
  348. package/dist/server/server/browser-tools/errors.js +27 -0
  349. package/dist/server/server/browser-tools/policy.d.ts +10 -0
  350. package/dist/server/server/browser-tools/policy.js +16 -0
  351. package/dist/server/server/browser-tools/tools.d.ts +16 -0
  352. package/dist/server/server/browser-tools/tools.js +796 -0
  353. package/dist/server/server/checkout/status-projection.d.ts +19 -0
  354. package/dist/server/server/checkout/status-projection.js +127 -0
  355. package/dist/server/server/checkout-diff-manager.d.ts +48 -0
  356. package/dist/server/server/checkout-diff-manager.js +284 -0
  357. package/dist/server/server/checkout-git-utils.d.ts +11 -0
  358. package/dist/server/server/checkout-git-utils.js +34 -0
  359. package/dist/server/server/client-message-id.d.ts +3 -0
  360. package/dist/server/server/client-message-id.js +12 -0
  361. package/dist/server/server/config.d.ts +26 -0
  362. package/dist/server/server/config.js +594 -0
  363. package/dist/server/server/connection-offer.d.ts +20 -0
  364. package/dist/server/server/connection-offer.js +59 -0
  365. package/dist/server/server/creation/index.d.ts +41 -0
  366. package/dist/server/server/creation/index.js +250 -0
  367. package/dist/server/server/daemon-config-store.d.ts +63 -0
  368. package/dist/server/server/daemon-config-store.js +524 -0
  369. package/dist/server/server/daemon-keypair.d.ts +8 -0
  370. package/dist/server/server/daemon-keypair.js +42 -0
  371. package/dist/server/server/daemon-version.d.ts +5 -0
  372. package/dist/server/server/daemon-version.js +22 -0
  373. package/dist/server/server/daemon-worker.d.ts +2 -0
  374. package/dist/server/server/daemon-worker.js +287 -0
  375. package/dist/server/server/dictation/dictation-stream-manager.d.ts +88 -0
  376. package/dist/server/server/dictation/dictation-stream-manager.js +578 -0
  377. package/dist/server/server/directory-sync/index.d.ts +45 -0
  378. package/dist/server/server/directory-sync/index.js +98 -0
  379. package/dist/server/server/directory-sync/internal/versioned-collection.d.ts +56 -0
  380. package/dist/server/server/directory-sync/internal/versioned-collection.js +94 -0
  381. package/dist/server/server/exports.d.ts +24 -0
  382. package/dist/server/server/exports.js +24 -0
  383. package/dist/server/server/file-download/token-store.d.ts +24 -0
  384. package/dist/server/server/file-download/token-store.js +40 -0
  385. package/dist/server/server/file-explorer/observer.d.ts +32 -0
  386. package/dist/server/server/file-explorer/observer.js +130 -0
  387. package/dist/server/server/file-explorer/service.d.ts +125 -0
  388. package/dist/server/server/file-explorer/service.js +663 -0
  389. package/dist/server/server/file-observer/index.d.ts +43 -0
  390. package/dist/server/server/file-observer/index.js +114 -0
  391. package/dist/server/server/file-observer/internal/contracts.d.ts +26 -0
  392. package/dist/server/server/file-observer/internal/contracts.js +2 -0
  393. package/dist/server/server/file-observer/internal/linux.d.ts +4 -0
  394. package/dist/server/server/file-observer/internal/linux.js +260 -0
  395. package/dist/server/server/file-observer/internal/native-recursive.d.ts +9 -0
  396. package/dist/server/server/file-observer/internal/native-recursive.js +577 -0
  397. package/dist/server/server/file-observer/internal/observation.d.ts +21 -0
  398. package/dist/server/server/file-observer/internal/observation.js +129 -0
  399. package/dist/server/server/file-observer/internal/paths.d.ts +10 -0
  400. package/dist/server/server/file-observer/internal/paths.js +43 -0
  401. package/dist/server/server/file-upload/index.d.ts +27 -0
  402. package/dist/server/server/file-upload/index.js +158 -0
  403. package/dist/server/server/git-metadata-event-rules.d.ts +123 -0
  404. package/dist/server/server/git-metadata-event-rules.js +152 -0
  405. package/dist/server/server/hostnames.d.ts +13 -0
  406. package/dist/server/server/hostnames.js +94 -0
  407. package/dist/server/server/hub/daemon-executions.d.ts +89 -0
  408. package/dist/server/server/hub/daemon-executions.js +287 -0
  409. package/dist/server/server/hub/execution-controller.d.ts +30 -0
  410. package/dist/server/server/hub/execution-controller.js +220 -0
  411. package/dist/server/server/hub/relationship-controller.d.ts +116 -0
  412. package/dist/server/server/hub/relationship-controller.js +534 -0
  413. package/dist/server/server/hub/relationship-remote.d.ts +68 -0
  414. package/dist/server/server/hub/relationship-remote.js +159 -0
  415. package/dist/server/server/hub/relationship-retry.d.ts +7 -0
  416. package/dist/server/server/hub/relationship-retry.js +15 -0
  417. package/dist/server/server/json-utils.d.ts +11 -0
  418. package/dist/server/server/json-utils.js +45 -0
  419. package/dist/server/server/lifecycle-reasons.d.ts +4 -0
  420. package/dist/server/server/lifecycle-reasons.js +6 -0
  421. package/dist/server/server/logger.d.ts +29 -0
  422. package/dist/server/server/logger.js +127 -0
  423. package/dist/server/server/managed-processes/managed-processes.d.ts +76 -0
  424. package/dist/server/server/managed-processes/managed-processes.js +326 -0
  425. package/dist/server/server/messages.d.ts +9 -0
  426. package/dist/server/server/messages.js +29 -0
  427. package/dist/server/server/migrations/backfill-workspace-id.migration.d.ts +9 -0
  428. package/dist/server/server/migrations/backfill-workspace-id.migration.js +64 -0
  429. package/dist/server/server/orchestration-skills/index.d.ts +18 -0
  430. package/dist/server/server/orchestration-skills/index.js +18 -0
  431. package/dist/server/server/orchestration-skills/internal/controller.d.ts +39 -0
  432. package/dist/server/server/orchestration-skills/internal/controller.js +108 -0
  433. package/dist/server/server/orchestration-skills/internal/operations.d.ts +43 -0
  434. package/dist/server/server/orchestration-skills/internal/operations.js +178 -0
  435. package/dist/server/server/orchestration-skills/internal/paths.d.ts +4 -0
  436. package/dist/server/server/orchestration-skills/internal/paths.js +21 -0
  437. package/dist/server/server/orchestration-skills/internal/selection-store.d.ts +12 -0
  438. package/dist/server/server/orchestration-skills/internal/selection-store.js +39 -0
  439. package/dist/server/server/orchestration-skills/internal/sync.d.ts +21 -0
  440. package/dist/server/server/orchestration-skills/internal/sync.js +177 -0
  441. package/dist/server/server/orchestration-skills/internal/transaction.d.ts +22 -0
  442. package/dist/server/server/orchestration-skills/internal/transaction.js +483 -0
  443. package/dist/server/server/package-version.d.ts +19 -0
  444. package/dist/server/server/package-version.js +60 -0
  445. package/dist/server/server/pagination/cursor.d.ts +16 -0
  446. package/dist/server/server/pagination/cursor.js +62 -0
  447. package/dist/server/server/pagination/sortable-pager.d.ts +24 -0
  448. package/dist/server/server/pagination/sortable-pager.js +68 -0
  449. package/dist/server/server/pairing-offer.d.ts +18 -0
  450. package/dist/server/server/pairing-offer.js +47 -0
  451. package/dist/server/server/pairing-qr.d.ts +2 -0
  452. package/dist/server/server/pairing-qr.js +15 -0
  453. package/dist/server/server/paseo-env.d.ts +13 -0
  454. package/dist/server/server/paseo-env.js +54 -0
  455. package/dist/server/server/paseo-home.d.ts +2 -0
  456. package/dist/server/server/paseo-home.js +19 -0
  457. package/dist/server/server/paseo-worktree-service.d.ts +45 -0
  458. package/dist/server/server/paseo-worktree-service.js +191 -0
  459. package/dist/server/server/path-utils.d.ts +5 -0
  460. package/dist/server/server/path-utils.js +34 -0
  461. package/dist/server/server/persisted-config.d.ts +397 -0
  462. package/dist/server/server/persisted-config.js +411 -0
  463. package/dist/server/server/persistence-hooks.d.ts +32 -0
  464. package/dist/server/server/persistence-hooks.js +96 -0
  465. package/dist/server/server/pid-lock.d.ts +44 -0
  466. package/dist/server/server/pid-lock.js +285 -0
  467. package/dist/server/server/plugins/compiler-imports.d.ts +13 -0
  468. package/dist/server/server/plugins/compiler-imports.js +90 -0
  469. package/dist/server/server/plugins/compiler.d.ts +10 -0
  470. package/dist/server/server/plugins/compiler.js +354 -0
  471. package/dist/server/server/plugins/daemon-transport.d.ts +9 -0
  472. package/dist/server/server/plugins/daemon-transport.js +68 -0
  473. package/dist/server/server/plugins/index.d.ts +102 -0
  474. package/dist/server/server/plugins/index.js +575 -0
  475. package/dist/server/server/plugins/lifecycle/index.d.ts +40 -0
  476. package/dist/server/server/plugins/lifecycle/index.js +200 -0
  477. package/dist/server/server/plugins/managed-source.d.ts +50 -0
  478. package/dist/server/server/plugins/managed-source.js +327 -0
  479. package/dist/server/server/plugins/manifest.d.ts +12 -0
  480. package/dist/server/server/plugins/manifest.js +26 -0
  481. package/dist/server/server/plugins/plugin-process-protocol.d.ts +120 -0
  482. package/dist/server/server/plugins/plugin-process-protocol.js +154 -0
  483. package/dist/server/server/plugins/plugin-process.d.ts +2 -0
  484. package/dist/server/server/plugins/plugin-process.js +419 -0
  485. package/dist/server/server/plugins/plugin-sdk-specifiers.d.ts +5 -0
  486. package/dist/server/server/plugins/plugin-sdk-specifiers.js +23 -0
  487. package/dist/server/server/plugins/plugin-session-identity.d.ts +4 -0
  488. package/dist/server/server/plugins/plugin-session-identity.js +11 -0
  489. package/dist/server/server/plugins/preparation.d.ts +4 -0
  490. package/dist/server/server/plugins/preparation.js +49 -0
  491. package/dist/server/server/plugins/provider-icon.d.ts +2 -0
  492. package/dist/server/server/plugins/provider-icon.js +55 -0
  493. package/dist/server/server/plugins/runtime.d.ts +83 -0
  494. package/dist/server/server/plugins/runtime.js +836 -0
  495. package/dist/server/server/plugins/session-socket.d.ts +23 -0
  496. package/dist/server/server/plugins/session-socket.js +82 -0
  497. package/dist/server/server/plugins/settings/index.d.ts +96 -0
  498. package/dist/server/server/plugins/settings/index.js +115 -0
  499. package/dist/server/server/private-files.d.ts +6 -0
  500. package/dist/server/server/private-files.js +37 -0
  501. package/dist/server/server/process-diagnostics.d.ts +17 -0
  502. package/dist/server/server/process-diagnostics.js +22 -0
  503. package/dist/server/server/project-directory-service.d.ts +30 -0
  504. package/dist/server/server/project-directory-service.js +120 -0
  505. package/dist/server/server/project-key.d.ts +14 -0
  506. package/dist/server/server/project-key.js +44 -0
  507. package/dist/server/server/push/index.d.ts +16 -0
  508. package/dist/server/server/push/index.js +26 -0
  509. package/dist/server/server/push/push-service.d.ts +19 -0
  510. package/dist/server/server/push/push-service.js +66 -0
  511. package/dist/server/server/push/token-store.d.ts +22 -0
  512. package/dist/server/server/push/token-store.js +125 -0
  513. package/dist/server/server/relay-runtime.d.ts +27 -0
  514. package/dist/server/server/relay-runtime.js +46 -0
  515. package/dist/server/server/relay-transport.d.ts +33 -0
  516. package/dist/server/server/relay-transport.js +481 -0
  517. package/dist/server/server/request-receipts/index.d.ts +33 -0
  518. package/dist/server/server/request-receipts/index.js +131 -0
  519. package/dist/server/server/resolve-workspace-id-for-path.d.ts +3 -0
  520. package/dist/server/server/resolve-workspace-id-for-path.js +41 -0
  521. package/dist/server/server/resolve-worktree-creation-intent.d.ts +44 -0
  522. package/dist/server/server/resolve-worktree-creation-intent.js +186 -0
  523. package/dist/server/server/schedule/cron.d.ts +4 -0
  524. package/dist/server/server/schedule/cron.js +83 -0
  525. package/dist/server/server/schedule/service.d.ts +75 -0
  526. package/dist/server/server/schedule/service.js +810 -0
  527. package/dist/server/server/schedule/store.d.ts +27 -0
  528. package/dist/server/server/schedule/store.js +190 -0
  529. package/dist/server/server/script-health-monitor.d.ts +39 -0
  530. package/dist/server/server/script-health-monitor.js +159 -0
  531. package/dist/server/server/script-proxy.d.ts +3 -0
  532. package/dist/server/server/script-proxy.js +2 -0
  533. package/dist/server/server/script-route-branch-handler.d.ts +10 -0
  534. package/dist/server/server/script-route-branch-handler.js +11 -0
  535. package/dist/server/server/script-status-projection.d.ts +36 -0
  536. package/dist/server/server/script-status-projection.js +200 -0
  537. package/dist/server/server/server-id.d.ts +17 -0
  538. package/dist/server/server/server-id.js +68 -0
  539. package/dist/server/server/service-proxy.d.ts +237 -0
  540. package/dist/server/server/service-proxy.js +679 -0
  541. package/dist/server/server/session/agent-config/agent-config-session.d.ts +75 -0
  542. package/dist/server/server/session/agent-config/agent-config-session.js +151 -0
  543. package/dist/server/server/session/agent-updates/agent-updates-service.d.ts +65 -0
  544. package/dist/server/server/session/agent-updates/agent-updates-service.js +266 -0
  545. package/dist/server/server/session/checkout/checkout-session.d.ts +150 -0
  546. package/dist/server/server/session/checkout/checkout-session.js +1187 -0
  547. package/dist/server/server/session/checkout/git-metadata-generator.d.ts +53 -0
  548. package/dist/server/server/session/checkout/git-metadata-generator.js +159 -0
  549. package/dist/server/server/session/daemon/daemon-self-update-session-controller.d.ts +34 -0
  550. package/dist/server/server/session/daemon/daemon-self-update-session-controller.js +90 -0
  551. package/dist/server/server/session/daemon/daemon-self-updater.d.ts +33 -0
  552. package/dist/server/server/session/daemon/daemon-self-updater.js +60 -0
  553. package/dist/server/server/session/daemon/daemon-session.d.ts +90 -0
  554. package/dist/server/server/session/daemon/daemon-session.js +224 -0
  555. package/dist/server/server/session/daemon/diagnostics.d.ts +41 -0
  556. package/dist/server/server/session/daemon/diagnostics.js +431 -0
  557. package/dist/server/server/session/daemon/install-origin.d.ts +7 -0
  558. package/dist/server/server/session/daemon/install-origin.js +64 -0
  559. package/dist/server/server/session/daemon/npm-global-cli.d.ts +29 -0
  560. package/dist/server/server/session/daemon/npm-global-cli.js +98 -0
  561. package/dist/server/server/session/files/workspace-files-session.d.ts +55 -0
  562. package/dist/server/server/session/files/workspace-files-session.js +359 -0
  563. package/dist/server/server/session/git-mutation/git-mutation-service.d.ts +32 -0
  564. package/dist/server/server/session/git-mutation/git-mutation-service.js +74 -0
  565. package/dist/server/server/session/project-config/project-config-session.d.ts +35 -0
  566. package/dist/server/server/session/project-config/project-config-session.js +143 -0
  567. package/dist/server/server/session/project-config/worktree-setup-commit-status.d.ts +6 -0
  568. package/dist/server/server/session/project-config/worktree-setup-commit-status.js +38 -0
  569. package/dist/server/server/session/provider/provider-catalog-session.d.ts +78 -0
  570. package/dist/server/server/session/provider/provider-catalog-session.js +388 -0
  571. package/dist/server/server/session/schedule/schedule-session.d.ts +47 -0
  572. package/dist/server/server/session/schedule/schedule-session.js +188 -0
  573. package/dist/server/server/session/voice/voice-session.d.ts +166 -0
  574. package/dist/server/server/session/voice/voice-session.js +904 -0
  575. package/dist/server/server/session/voice/voice-turn-controller.d.ts +38 -0
  576. package/dist/server/server/session/voice/voice-turn-controller.js +393 -0
  577. package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.d.ts +42 -0
  578. package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.js +170 -0
  579. package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.d.ts +59 -0
  580. package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.js +326 -0
  581. package/dist/server/server/session/workspace-recovery/workspace-recovery-service.d.ts +30 -0
  582. package/dist/server/server/session/workspace-recovery/workspace-recovery-service.js +178 -0
  583. package/dist/server/server/session/workspace-scripts/workspace-scripts-service.d.ts +54 -0
  584. package/dist/server/server/session/workspace-scripts/workspace-scripts-service.js +156 -0
  585. package/dist/server/server/session.d.ts +555 -0
  586. package/dist/server/server/session.js +6540 -0
  587. package/dist/server/server/speech/audio.d.ts +10 -0
  588. package/dist/server/server/speech/audio.js +101 -0
  589. package/dist/server/server/speech/provider-resolver.d.ts +3 -0
  590. package/dist/server/server/speech/provider-resolver.js +7 -0
  591. package/dist/server/server/speech/providers/local/config.d.ts +30 -0
  592. package/dist/server/server/speech/providers/local/config.js +134 -0
  593. package/dist/server/server/speech/providers/local/models.d.ts +12 -0
  594. package/dist/server/server/speech/providers/local/models.js +18 -0
  595. package/dist/server/server/speech/providers/local/runtime.d.ts +31 -0
  596. package/dist/server/server/speech/providers/local/runtime.js +135 -0
  597. package/dist/server/server/speech/providers/local/sherpa/assets/silero_vad.onnx +0 -0
  598. package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts +56 -0
  599. package/dist/server/server/speech/providers/local/sherpa/model-catalog.js +74 -0
  600. package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts +17 -0
  601. package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +145 -0
  602. package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts +49 -0
  603. package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js +73 -0
  604. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts +9 -0
  605. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +107 -0
  606. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts +28 -0
  607. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +137 -0
  608. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts +21 -0
  609. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +133 -0
  610. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.d.ts +18 -0
  611. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.js +84 -0
  612. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts +21 -0
  613. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js +101 -0
  614. package/dist/server/server/speech/providers/local/sherpa/silero-vad-provider.d.ts +19 -0
  615. package/dist/server/server/speech/providers/local/sherpa/silero-vad-provider.js +49 -0
  616. package/dist/server/server/speech/providers/local/sherpa/silero-vad-session.d.ts +38 -0
  617. package/dist/server/server/speech/providers/local/sherpa/silero-vad-session.js +176 -0
  618. package/dist/server/server/speech/providers/local/worker-bytes.d.ts +4 -0
  619. package/dist/server/server/speech/providers/local/worker-bytes.js +9 -0
  620. package/dist/server/server/speech/providers/local/worker-client.d.ts +93 -0
  621. package/dist/server/server/speech/providers/local/worker-client.js +590 -0
  622. package/dist/server/server/speech/providers/local/worker-process.d.ts +2 -0
  623. package/dist/server/server/speech/providers/local/worker-process.js +270 -0
  624. package/dist/server/server/speech/providers/local/worker-protocol.d.ts +95 -0
  625. package/dist/server/server/speech/providers/local/worker-protocol.js +2 -0
  626. package/dist/server/server/speech/providers/openai/config.d.ts +19 -0
  627. package/dist/server/server/speech/providers/openai/config.js +148 -0
  628. package/dist/server/server/speech/providers/openai/runtime.d.ts +29 -0
  629. package/dist/server/server/speech/providers/openai/runtime.js +102 -0
  630. package/dist/server/server/speech/providers/openai/stt.d.ts +23 -0
  631. package/dist/server/server/speech/providers/openai/stt.js +209 -0
  632. package/dist/server/server/speech/providers/openai/tts.d.ts +19 -0
  633. package/dist/server/server/speech/providers/openai/tts.js +48 -0
  634. package/dist/server/server/speech/speech-config-resolver.d.ts +11 -0
  635. package/dist/server/server/speech/speech-config-resolver.js +132 -0
  636. package/dist/server/server/speech/speech-provider.d.ts +59 -0
  637. package/dist/server/server/speech/speech-provider.js +2 -0
  638. package/dist/server/server/speech/speech-runtime.d.ts +45 -0
  639. package/dist/server/server/speech/speech-runtime.js +571 -0
  640. package/dist/server/server/speech/speech-types.d.ts +22 -0
  641. package/dist/server/server/speech/speech-types.js +8 -0
  642. package/dist/server/server/speech/turn-detection-provider.d.ts +23 -0
  643. package/dist/server/server/speech/turn-detection-provider.js +2 -0
  644. package/dist/server/server/utils/diff-highlighter.d.ts +57 -0
  645. package/dist/server/server/utils/diff-highlighter.js +304 -0
  646. package/dist/server/server/voice-config.d.ts +15 -0
  647. package/dist/server/server/voice-config.js +54 -0
  648. package/dist/server/server/voice-permission-policy.d.ts +4 -0
  649. package/dist/server/server/voice-permission-policy.js +13 -0
  650. package/dist/server/server/voice-types.d.ts +12 -0
  651. package/dist/server/server/voice-types.js +2 -0
  652. package/dist/server/server/watcher-liveness-canary.d.ts +11 -0
  653. package/dist/server/server/watcher-liveness-canary.js +53 -0
  654. package/dist/server/server/web-ui.d.ts +10 -0
  655. package/dist/server/server/web-ui.js +205 -0
  656. package/dist/server/server/websocket/encrypted-relay-socket.d.ts +23 -0
  657. package/dist/server/server/websocket/encrypted-relay-socket.js +64 -0
  658. package/dist/server/server/websocket/physical-socket.d.ts +36 -0
  659. package/dist/server/server/websocket/physical-socket.js +95 -0
  660. package/dist/server/server/websocket/runtime-metrics.d.ts +95 -0
  661. package/dist/server/server/websocket/runtime-metrics.js +148 -0
  662. package/dist/server/server/websocket-server.d.ts +214 -0
  663. package/dist/server/server/websocket-server.js +2258 -0
  664. package/dist/server/server/workspace-archive-service.d.ts +63 -0
  665. package/dist/server/server/workspace-archive-service.js +355 -0
  666. package/dist/server/server/workspace-auto-name.d.ts +55 -0
  667. package/dist/server/server/workspace-auto-name.js +127 -0
  668. package/dist/server/server/workspace-automation-gate.d.ts +16 -0
  669. package/dist/server/server/workspace-automation-gate.js +35 -0
  670. package/dist/server/server/workspace-bootstrap-dedupe.d.ts +34 -0
  671. package/dist/server/server/workspace-bootstrap-dedupe.js +23 -0
  672. package/dist/server/server/workspace-directory.d.ts +99 -0
  673. package/dist/server/server/workspace-directory.js +467 -0
  674. package/dist/server/server/workspace-git-fetch.d.ts +33 -0
  675. package/dist/server/server/workspace-git-fetch.js +108 -0
  676. package/dist/server/server/workspace-git-metadata.d.ts +8 -0
  677. package/dist/server/server/workspace-git-metadata.js +24 -0
  678. package/dist/server/server/workspace-git-service.d.ts +348 -0
  679. package/dist/server/server/workspace-git-service.js +2534 -0
  680. package/dist/server/server/workspace-labels/index.d.ts +14 -0
  681. package/dist/server/server/workspace-labels/index.js +10 -0
  682. package/dist/server/server/workspace-labels/internal/catalog-store.d.ts +50 -0
  683. package/dist/server/server/workspace-labels/internal/catalog-store.js +203 -0
  684. package/dist/server/server/workspace-labels/internal/sequence.d.ts +43 -0
  685. package/dist/server/server/workspace-labels/internal/sequence.js +80 -0
  686. package/dist/server/server/workspace-labels/internal/service.d.ts +57 -0
  687. package/dist/server/server/workspace-labels/internal/service.js +224 -0
  688. package/dist/server/server/workspace-reconciliation-service.d.ts +103 -0
  689. package/dist/server/server/workspace-reconciliation-service.js +379 -0
  690. package/dist/server/server/workspace-registry-bootstrap-legacy.d.ts +21 -0
  691. package/dist/server/server/workspace-registry-bootstrap-legacy.js +57 -0
  692. package/dist/server/server/workspace-registry-bootstrap.d.ts +14 -0
  693. package/dist/server/server/workspace-registry-bootstrap.js +155 -0
  694. package/dist/server/server/workspace-registry-model.d.ts +56 -0
  695. package/dist/server/server/workspace-registry-model.js +150 -0
  696. package/dist/server/server/workspace-registry.d.ts +228 -0
  697. package/dist/server/server/workspace-registry.js +468 -0
  698. package/dist/server/server/workspace-script-runtime-store.d.ts +28 -0
  699. package/dist/server/server/workspace-script-runtime-store.js +78 -0
  700. package/dist/server/server/workspace-service-env.d.ts +18 -0
  701. package/dist/server/server/workspace-service-env.js +85 -0
  702. package/dist/server/server/workspace-service-port-allocator.d.ts +11 -0
  703. package/dist/server/server/workspace-service-port-allocator.js +89 -0
  704. package/dist/server/server/workspace-service-port-registry.d.ts +24 -0
  705. package/dist/server/server/workspace-service-port-registry.js +172 -0
  706. package/dist/server/server/workspace-setup-runtime.d.ts +7 -0
  707. package/dist/server/server/workspace-setup-runtime.js +30 -0
  708. package/dist/server/server/workspace-source.d.ts +7 -0
  709. package/dist/server/server/workspace-source.js +15 -0
  710. package/dist/server/server/worktree/commands.d.ts +55 -0
  711. package/dist/server/server/worktree/commands.js +99 -0
  712. package/dist/server/server/worktree-bootstrap.d.ts +86 -0
  713. package/dist/server/server/worktree-bootstrap.js +753 -0
  714. package/dist/server/server/worktree-branch-name-generator.d.ts +35 -0
  715. package/dist/server/server/worktree-branch-name-generator.js +89 -0
  716. package/dist/server/server/worktree-core.d.ts +32 -0
  717. package/dist/server/server/worktree-core.js +114 -0
  718. package/dist/server/server/worktree-errors.d.ts +12 -0
  719. package/dist/server/server/worktree-errors.js +28 -0
  720. package/dist/server/server/worktree-session.d.ts +165 -0
  721. package/dist/server/server/worktree-session.js +594 -0
  722. package/dist/server/services/forge-cli-command.d.ts +128 -0
  723. package/dist/server/services/forge-cli-command.js +212 -0
  724. package/dist/server/services/forge-registry.d.ts +25 -0
  725. package/dist/server/services/forge-registry.js +155 -0
  726. package/dist/server/services/forge-resolver.d.ts +38 -0
  727. package/dist/server/services/forge-resolver.js +191 -0
  728. package/dist/server/services/forge-service.d.ts +430 -0
  729. package/dist/server/services/forge-service.js +50 -0
  730. package/dist/server/services/gitea-facts.d.ts +11 -0
  731. package/dist/server/services/gitea-facts.js +4 -0
  732. package/dist/server/services/gitea-service.d.ts +62 -0
  733. package/dist/server/services/gitea-service.js +1844 -0
  734. package/dist/server/services/github-facts.d.ts +27 -0
  735. package/dist/server/services/github-facts.js +4 -0
  736. package/dist/server/services/github-service.d.ts +76 -0
  737. package/dist/server/services/github-service.js +3297 -0
  738. package/dist/server/services/gitlab-facts.d.ts +26 -0
  739. package/dist/server/services/gitlab-facts.js +4 -0
  740. package/dist/server/services/gitlab-service.d.ts +43 -0
  741. package/dist/server/services/gitlab-service.js +1092 -0
  742. package/dist/server/services/quota-fetcher/manifest.d.ts +5 -0
  743. package/dist/server/services/quota-fetcher/manifest.js +118 -0
  744. package/dist/server/services/quota-fetcher/provider.d.ts +18 -0
  745. package/dist/server/services/quota-fetcher/provider.js +2 -0
  746. package/dist/server/services/quota-fetcher/providers/claude.d.ts +40 -0
  747. package/dist/server/services/quota-fetcher/providers/claude.js +389 -0
  748. package/dist/server/services/quota-fetcher/providers/codex.d.ts +23 -0
  749. package/dist/server/services/quota-fetcher/providers/codex.js +167 -0
  750. package/dist/server/services/quota-fetcher/providers/copilot.d.ts +21 -0
  751. package/dist/server/services/quota-fetcher/providers/copilot.js +77 -0
  752. package/dist/server/services/quota-fetcher/providers/cursor.d.ts +19 -0
  753. package/dist/server/services/quota-fetcher/providers/cursor.js +185 -0
  754. package/dist/server/services/quota-fetcher/providers/grok.d.ts +23 -0
  755. package/dist/server/services/quota-fetcher/providers/grok.js +137 -0
  756. package/dist/server/services/quota-fetcher/providers/kimi.d.ts +23 -0
  757. package/dist/server/services/quota-fetcher/providers/kimi.js +260 -0
  758. package/dist/server/services/quota-fetcher/providers/minimax.d.ts +29 -0
  759. package/dist/server/services/quota-fetcher/providers/minimax.js +227 -0
  760. package/dist/server/services/quota-fetcher/providers/zai.d.ts +17 -0
  761. package/dist/server/services/quota-fetcher/providers/zai.js +58 -0
  762. package/dist/server/services/quota-fetcher/service.d.ts +34 -0
  763. package/dist/server/services/quota-fetcher/service.js +74 -0
  764. package/dist/server/services/quota-fetcher/usage.d.ts +39 -0
  765. package/dist/server/services/quota-fetcher/usage.js +78 -0
  766. package/dist/server/skills/paseo/SKILL.md +129 -0
  767. package/dist/server/skills/paseo-advisor/SKILL.md +63 -0
  768. package/dist/server/skills/paseo-committee/SKILL.md +46 -0
  769. package/dist/server/skills/paseo-handoff/SKILL.md +65 -0
  770. package/dist/server/skills/paseo-help/SKILL.md +92 -0
  771. package/dist/server/skills/paseo-plugin/SKILL.md +639 -0
  772. package/dist/server/terminal/activity/terminal-activity-tracker.d.ts +21 -0
  773. package/dist/server/terminal/activity/terminal-activity-tracker.js +65 -0
  774. package/dist/server/terminal/agent-hooks/agent-hook-installer.d.ts +62 -0
  775. package/dist/server/terminal/agent-hooks/agent-hook-installer.js +117 -0
  776. package/dist/server/terminal/agent-hooks/claude/claude-settings.d.ts +7 -0
  777. package/dist/server/terminal/agent-hooks/claude/claude-settings.js +88 -0
  778. package/dist/server/terminal/agent-hooks/claude/claude.d.ts +4 -0
  779. package/dist/server/terminal/agent-hooks/claude/claude.js +47 -0
  780. package/dist/server/terminal/agent-hooks/codex/codex-settings.d.ts +7 -0
  781. package/dist/server/terminal/agent-hooks/codex/codex-settings.js +99 -0
  782. package/dist/server/terminal/agent-hooks/codex/codex.d.ts +4 -0
  783. package/dist/server/terminal/agent-hooks/codex/codex.js +30 -0
  784. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.d.ts +4 -0
  785. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.js +81 -0
  786. package/dist/server/terminal/agent-hooks/opencode/opencode.d.ts +3 -0
  787. package/dist/server/terminal/agent-hooks/opencode/opencode.js +23 -0
  788. package/dist/server/terminal/agent-hooks/provider-registry.d.ts +24 -0
  789. package/dist/server/terminal/agent-hooks/provider-registry.js +36 -0
  790. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.d.ts +10 -0
  791. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.js +26 -0
  792. package/dist/server/terminal/shell-integration/zsh/.zshenv +17 -0
  793. package/dist/server/terminal/shell-integration/zsh/paseo-integration.zsh +32 -0
  794. package/dist/server/terminal/terminal-capture.d.ts +12 -0
  795. package/dist/server/terminal/terminal-capture.js +43 -0
  796. package/dist/server/terminal/terminal-manager-factory.d.ts +6 -0
  797. package/dist/server/terminal/terminal-manager-factory.js +5 -0
  798. package/dist/server/terminal/terminal-manager.d.ts +80 -0
  799. package/dist/server/terminal/terminal-manager.js +321 -0
  800. package/dist/server/terminal/terminal-output-coalescer.d.ts +34 -0
  801. package/dist/server/terminal/terminal-output-coalescer.js +73 -0
  802. package/dist/server/terminal/terminal-restore.d.ts +18 -0
  803. package/dist/server/terminal/terminal-restore.js +52 -0
  804. package/dist/server/terminal/terminal-session-controller.d.ts +90 -0
  805. package/dist/server/terminal/terminal-session-controller.js +849 -0
  806. package/dist/server/terminal/terminal-size-ownership.d.ts +9 -0
  807. package/dist/server/terminal/terminal-size-ownership.js +23 -0
  808. package/dist/server/terminal/terminal-ts-loader.mjs +20 -0
  809. package/dist/server/terminal/terminal-worker-process.d.ts +2 -0
  810. package/dist/server/terminal/terminal-worker-process.js +308 -0
  811. package/dist/server/terminal/terminal-worker-protocol.d.ts +121 -0
  812. package/dist/server/terminal/terminal-worker-protocol.js +2 -0
  813. package/dist/server/terminal/terminal.d.ts +151 -0
  814. package/dist/server/terminal/terminal.js +1234 -0
  815. package/dist/server/terminal/worker-terminal-manager.d.ts +20 -0
  816. package/dist/server/terminal/worker-terminal-manager.js +688 -0
  817. package/dist/server/utils/build-metadata-prompt.d.ts +19 -0
  818. package/dist/server/utils/build-metadata-prompt.js +29 -0
  819. package/dist/server/utils/checkout-git.d.ts +317 -0
  820. package/dist/server/utils/checkout-git.js +2886 -0
  821. package/dist/server/utils/directory-suggestions.d.ts +29 -0
  822. package/dist/server/utils/directory-suggestions.js +596 -0
  823. package/dist/server/utils/git-command-runtime-metrics.d.ts +67 -0
  824. package/dist/server/utils/git-command-runtime-metrics.js +126 -0
  825. package/dist/server/utils/git-command-trace.d.ts +29 -0
  826. package/dist/server/utils/git-command-trace.js +74 -0
  827. package/dist/server/utils/git-process-scheduler.d.ts +34 -0
  828. package/dist/server/utils/git-process-scheduler.js +112 -0
  829. package/dist/server/utils/git-rev-parse-path.d.ts +3 -0
  830. package/dist/server/utils/git-rev-parse-path.js +21 -0
  831. package/dist/server/utils/paseo-config-file.d.ts +30 -0
  832. package/dist/server/utils/paseo-config-file.js +90 -0
  833. package/dist/server/utils/path.d.ts +27 -0
  834. package/dist/server/utils/path.js +156 -0
  835. package/dist/server/utils/project-custom-icon.d.ts +40 -0
  836. package/dist/server/utils/project-custom-icon.js +144 -0
  837. package/dist/server/utils/project-icon.d.ts +54 -0
  838. package/dist/server/utils/project-icon.js +445 -0
  839. package/dist/server/utils/promise-timeout.d.ts +9 -0
  840. package/dist/server/utils/promise-timeout.js +25 -0
  841. package/dist/server/utils/run-git-command.d.ts +59 -0
  842. package/dist/server/utils/run-git-command.js +393 -0
  843. package/dist/server/utils/spawn.d.ts +26 -0
  844. package/dist/server/utils/spawn.js +60 -0
  845. package/dist/server/utils/ssh-hostname.d.ts +8 -0
  846. package/dist/server/utils/ssh-hostname.js +60 -0
  847. package/dist/server/utils/string-command-shell.d.ts +13 -0
  848. package/dist/server/utils/string-command-shell.js +37 -0
  849. package/dist/server/utils/tree-kill.d.ts +19 -0
  850. package/dist/server/utils/tree-kill.js +77 -0
  851. package/dist/server/utils/windows-command.d.ts +15 -0
  852. package/dist/server/utils/windows-command.js +41 -0
  853. package/dist/server/utils/worktree-metadata.d.ts +77 -0
  854. package/dist/server/utils/worktree-metadata.js +280 -0
  855. package/dist/server/utils/worktree.d.ts +232 -0
  856. package/dist/server/utils/worktree.js +1193 -0
  857. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css +1 -0
  858. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.br +0 -0
  859. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.gz +0 -0
  860. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-29f33408b1a3c5b435c5202d62a36719.js +1 -0
  861. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-29f33408b1a3c5b435c5202d62a36719.js.br +0 -0
  862. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-29f33408b1a3c5b435c5202d62a36719.js.gz +0 -0
  863. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-41547ee520dfff946caa727824742a5c.js +1 -0
  864. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-41547ee520dfff946caa727824742a5c.js.br +0 -0
  865. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-41547ee520dfff946caa727824742a5c.js.gz +0 -0
  866. package/dist/server/web-ui/_expo/static/js/web/index-03b99be4265ac4a2bc5a6d602fd59cc4.js +16819 -0
  867. package/dist/server/web-ui/_expo/static/js/web/index-03b99be4265ac4a2bc5a6d602fd59cc4.js.br +0 -0
  868. package/dist/server/web-ui/_expo/static/js/web/index-03b99be4265ac4a2bc5a6d602fd59cc4.js.gz +0 -0
  869. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-5444610146b0794f1e7d9edad4522d41.js +1 -0
  870. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-5444610146b0794f1e7d9edad4522d41.js.br +0 -0
  871. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-5444610146b0794f1e7d9edad4522d41.js.gz +0 -0
  872. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-88b083190031a44788be59103814f511.js +3 -0
  873. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-88b083190031a44788be59103814f511.js.br +0 -0
  874. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-88b083190031a44788be59103814f511.js.gz +0 -0
  875. package/dist/server/web-ui/apple-touch-icon.png +0 -0
  876. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png +0 -0
  877. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png +0 -0
  878. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png +0 -0
  879. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png +0 -0
  880. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png +0 -0
  881. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png +0 -0
  882. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png +0 -0
  883. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png +0 -0
  884. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png +0 -0
  885. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png +0 -0
  886. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png +0 -0
  887. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png +0 -0
  888. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png +0 -0
  889. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png +0 -0
  890. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png +0 -0
  891. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png +0 -0
  892. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png +0 -0
  893. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png +0 -0
  894. package/dist/server/web-ui/assets/assets/images/favicon-dark-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
  895. package/dist/server/web-ui/assets/assets/images/favicon-dark-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
  896. package/dist/server/web-ui/assets/assets/images/favicon-dark.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
  897. package/dist/server/web-ui/assets/assets/images/favicon-light-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
  898. package/dist/server/web-ui/assets/assets/images/favicon-light-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
  899. package/dist/server/web-ui/assets/assets/images/favicon-light.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
  900. package/dist/server/web-ui/assets/assets/images/notification-icon.3bf81d33ddbf380606bdd248ba83e158.png +0 -0
  901. package/dist/server/web-ui/favicon.ico +0 -0
  902. package/dist/server/web-ui/index.html +90 -0
  903. package/dist/server/web-ui/index.html.br +0 -0
  904. package/dist/server/web-ui/index.html.gz +0 -0
  905. package/dist/server/web-ui/manifest.json +27 -0
  906. package/dist/server/web-ui/manifest.json.br +0 -0
  907. package/dist/server/web-ui/manifest.json.gz +0 -0
  908. package/dist/server/web-ui/metadata.json +1 -0
  909. package/dist/server/web-ui/metadata.json.br +1 -0
  910. package/dist/server/web-ui/metadata.json.gz +0 -0
  911. package/dist/server/web-ui/pwa-icon-192.png +0 -0
  912. package/dist/server/web-ui/pwa-icon-512.png +0 -0
  913. package/dist/server/web-ui/robots.txt +2 -0
  914. package/dist/src/executable-resolution/executable-resolution.js +121 -0
  915. package/dist/src/executable-resolution/windows.js +65 -0
  916. package/dist/src/server/agent/provider-launch-config.js +167 -0
  917. package/dist/src/server/paseo-env.js +54 -0
  918. package/dist/src/server/paseo-home.js +19 -0
  919. package/dist/src/server/persisted-config.js +411 -0
  920. package/dist/src/server/pid-lock.js +285 -0
  921. package/dist/src/server/private-files.js +37 -0
  922. package/dist/src/server/speech/providers/local/sherpa/sherpa-runtime-env.js +84 -0
  923. package/dist/src/terminal/shell-integration/zsh/.zshenv +17 -0
  924. package/dist/src/terminal/shell-integration/zsh/paseo-integration.zsh +32 -0
  925. package/dist/src/utils/spawn.js +60 -0
  926. package/dist/src/utils/tree-kill.js +77 -0
  927. package/dist/src/utils/windows-command.js +41 -0
  928. package/package.json +125 -0
@@ -0,0 +1,4106 @@
1
+ import { createOpencodeClient, } from "@opencode-ai/sdk/v2/client";
2
+ import fs from "node:fs/promises";
3
+ import { randomBytes } from "node:crypto";
4
+ import { isDeepStrictEqual } from "node:util";
5
+ import { createPathEquivalenceMatcher } from "../../../utils/path.js";
6
+ import pLimit from "p-limit";
7
+ import { z } from "zod";
8
+ import { getAgentStreamEventTurnId, } from "../agent-sdk-types.js";
9
+ import { importSessionFromPersistence } from "../provider-session-import.js";
10
+ import { raceProviderRefreshAbort, runProviderRefreshActivity, } from "../provider-refresh-deadline.js";
11
+ import { isDefaultAgentCreateConfigUnattended, resolveDefaultAgentCreateConfig, } from "../create-agent-mode.js";
12
+ import { checkProviderLaunchAvailable, createProviderEnvSpec, resolveProviderLaunch, } from "../provider-launch-config.js";
13
+ import { withTimeout } from "../../../utils/promise-timeout.js";
14
+ import { execCommand } from "../../../utils/spawn.js";
15
+ import { mapOpencodeToolCall } from "./opencode/tool-call-mapper.js";
16
+ import { OPENCODE_EVENT_STREAM_READY_TIMEOUT_MS, OpenCodeServerManager, OPENCODE_SERVER_STARTUP_TIMEOUT_MS, } from "./opencode/server-manager.js";
17
+ import { OpenCodeEventConsumer, } from "./opencode/event-consumer.js";
18
+ import { resolveOpenCodeHomeDir } from "./opencode/paths.js";
19
+ import { formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
20
+ import { runProviderTurn } from "./provider-runner.js";
21
+ import { renderPromptAttachmentAsText } from "../prompt-attachments.js";
22
+ import { composeSystemPromptParts } from "../system-prompt.js";
23
+ import { normalizeProviderReplayTimestamp } from "../provider-history-timestamps.js";
24
+ import { revertOpenCodeConversationAndFiles } from "./opencode/rewind.js";
25
+ import { askOpenCodeSideQuestion } from "./opencode/side-question.js";
26
+ import { claimOpenCodeSubagentFallbackTitle, foldOpenCodeSubagentPresentation, } from "./opencode/subagent-presentation.js";
27
+ import { buildOpenCodePermissionRules, OpenCodeProviderOptionsSchema, } from "./opencode/options.js";
28
+ function formatOpenCodeEventStreamDiagnostics(diagnostics) {
29
+ return [
30
+ "opencode-stream",
31
+ `attempt=${diagnostics.attempt}`,
32
+ `phase=${diagnostics.phase}`,
33
+ `elapsedMs=${diagnostics.elapsedMs}`,
34
+ ...(diagnostics.lastOutcome ? [`lastOutcome=${diagnostics.lastOutcome}`] : []),
35
+ ...(diagnostics.lastError ? [`lastError=${JSON.stringify(diagnostics.lastError)}`] : []),
36
+ ].join(" ");
37
+ }
38
+ const OPENCODE_CAPABILITIES = {
39
+ supportsStreaming: true,
40
+ supportsSessionPersistence: true,
41
+ supportsSessionListing: true,
42
+ supportsDynamicModes: true,
43
+ supportsMcpServers: true,
44
+ supportsReasoningStream: true,
45
+ supportsToolInvocations: true,
46
+ supportsRewindConversation: false,
47
+ supportsRewindFiles: false,
48
+ supportsRewindBoth: true,
49
+ };
50
+ const OPENCODE_BUILD_MODE_ID = "build";
51
+ const OPENCODE_LEGACY_FULL_ACCESS_MODE_ID = "full-access";
52
+ const OPENCODE_DEFAULT_VARIANT_ID = "default";
53
+ const EMPTY_OPENCODE_EVENT_SOURCE = {
54
+ ready: async () => undefined,
55
+ subscribe: () => () => undefined,
56
+ };
57
+ const OPENCODE_ID_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
58
+ let lastOpenCodeMessageTimestamp = -1;
59
+ let openCodeMessageCounter = 0;
60
+ function createOpenCodeMessageId(now = Date.now(), random = (length) => Array.from(randomBytes(length), (value) => OPENCODE_ID_ALPHABET[value % 62]).join("")) {
61
+ if (now !== lastOpenCodeMessageTimestamp)
62
+ openCodeMessageCounter = 0;
63
+ lastOpenCodeMessageTimestamp = now;
64
+ openCodeMessageCounter += 1;
65
+ const ascending = (BigInt(now) * 0x1000n + BigInt(openCodeMessageCounter))
66
+ .toString(16)
67
+ .padStart(12, "0")
68
+ .slice(-12);
69
+ return `msg_${ascending}${random(14)}`;
70
+ }
71
+ const OPENCODE_AUTO_ACCEPT_FEATURE_ID = "auto_accept";
72
+ const OPENCODE_PERSISTED_SESSION_LIMIT = 200;
73
+ const OPENCODE_PENDING_ABORT_START_TIMEOUT_MS = 10000;
74
+ const OPENCODE_CHILD_SESSION_HYDRATION_LIMIT = 100;
75
+ const OPENCODE_STOP_STATUS_MAX_DELAY_MS = 1000;
76
+ function waitForOpenCodeStopProbe(delayMs, signal) {
77
+ if (signal.aborted)
78
+ return Promise.reject(signal.reason);
79
+ return new Promise((resolve, reject) => {
80
+ const onAbort = () => reject(signal.reason);
81
+ setTimeout(() => {
82
+ signal.removeEventListener("abort", onAbort);
83
+ resolve();
84
+ }, delayMs).unref();
85
+ signal.addEventListener("abort", onAbort, { once: true });
86
+ });
87
+ }
88
+ function recoverChildStatus(snapshot, type, assistant) {
89
+ if (type === "busy" || type === "retry")
90
+ return "running";
91
+ if (assistant && "error" in assistant.info && assistant.info.error)
92
+ return "failed";
93
+ const time = assistant?.info.time;
94
+ if (snapshot || (time && "completed" in time && time.completed !== undefined))
95
+ return "completed";
96
+ }
97
+ const OPENCODE_CHILD_SESSION_SERVER_REGISTRY_LIMIT = 500;
98
+ const OPENCODE_PERMISSION_ACTION_ALLOW_ONCE = "allow_once";
99
+ const OPENCODE_PERMISSION_ACTION_ALLOW_ALWAYS = "allow_always";
100
+ // OpenCode child sessions run on the server process that spawned them. Adoption
101
+ // resumes must attach to that same helper server to receive live global events.
102
+ const openCodeChildSessionServerUrls = new Map();
103
+ function registerOpenCodeChildSessionServerUrl(sessionId, serverUrl) {
104
+ openCodeChildSessionServerUrls.delete(sessionId);
105
+ openCodeChildSessionServerUrls.set(sessionId, serverUrl);
106
+ if (openCodeChildSessionServerUrls.size <= OPENCODE_CHILD_SESSION_SERVER_REGISTRY_LIMIT) {
107
+ return;
108
+ }
109
+ const oldestSessionId = openCodeChildSessionServerUrls.keys().next().value;
110
+ if (typeof oldestSessionId === "string") {
111
+ openCodeChildSessionServerUrls.delete(oldestSessionId);
112
+ }
113
+ }
114
+ function unregisterOpenCodeChildSessionServerUrl(sessionId) {
115
+ openCodeChildSessionServerUrls.delete(sessionId);
116
+ }
117
+ function getOpenCodeChildSessionServerUrl(sessionId) {
118
+ return openCodeChildSessionServerUrls.get(sessionId);
119
+ }
120
+ const DEFAULT_MODES = [
121
+ {
122
+ id: OPENCODE_BUILD_MODE_ID,
123
+ label: "Build",
124
+ description: "Allows edits and tool execution for implementation work",
125
+ },
126
+ {
127
+ id: "plan",
128
+ label: "Plan",
129
+ description: "Read-only planning mode that avoids file edits",
130
+ },
131
+ ];
132
+ function isOpenCodeAutoAcceptEnabled(config) {
133
+ return config.featureValues?.[OPENCODE_AUTO_ACCEPT_FEATURE_ID] === true;
134
+ }
135
+ function withOpenCodeAutoAcceptFeature(featureValues, enabled) {
136
+ return {
137
+ ...featureValues,
138
+ [OPENCODE_AUTO_ACCEPT_FEATURE_ID]: enabled,
139
+ };
140
+ }
141
+ function resolveOpenCodeCreateConfig(input) {
142
+ const legacyFullAccess = input.requestedMode === OPENCODE_LEGACY_FULL_ACCESS_MODE_ID;
143
+ const parent = input.parent;
144
+ const isUnattendedCreate = input.unattended || parent?.isUnattended === true;
145
+ const inheritsUnattended = input.requestedMode === undefined && isUnattendedCreate;
146
+ const inheritedOpenCodeMode = inheritsUnattended && parent?.provider === input.provider
147
+ ? (parent.modeId ?? undefined)
148
+ : undefined;
149
+ const requestedMode = legacyFullAccess
150
+ ? OPENCODE_BUILD_MODE_ID
151
+ : (input.requestedMode ?? inheritedOpenCodeMode);
152
+ const featureValues = legacyFullAccess ||
153
+ (isUnattendedCreate && input.featureValues?.[OPENCODE_AUTO_ACCEPT_FEATURE_ID] === undefined)
154
+ ? withOpenCodeAutoAcceptFeature(input.featureValues, true)
155
+ : input.featureValues;
156
+ if (inheritsUnattended && requestedMode === undefined) {
157
+ // Unattendedness for OpenCode is carried by auto_accept (set above), not
158
+ // by any particular agent. Leave the mode unset so OpenCode uses its own
159
+ // default agent — `build` may not exist in the user's OpenCode config.
160
+ return { modeId: undefined, featureValues };
161
+ }
162
+ const resolved = resolveDefaultAgentCreateConfig({
163
+ ...input,
164
+ requestedMode,
165
+ featureValues,
166
+ });
167
+ return { ...resolved, featureValues };
168
+ }
169
+ function isOpenCodeCreateConfigUnattended(input) {
170
+ return (isDefaultAgentCreateConfigUnattended(input) ||
171
+ input.config.featureValues?.[OPENCODE_AUTO_ACCEPT_FEATURE_ID] === true ||
172
+ input.features?.some((feature) => feature.id === OPENCODE_AUTO_ACCEPT_FEATURE_ID &&
173
+ (feature.value === true || feature.value === "true")) === true);
174
+ }
175
+ function buildOpenCodeAutoAcceptFeature(config) {
176
+ return {
177
+ type: "toggle",
178
+ id: OPENCODE_AUTO_ACCEPT_FEATURE_ID,
179
+ label: "Auto Accept",
180
+ description: "Automatically approves OpenCode tool permission prompts.",
181
+ tooltip: "Auto accept permission prompts",
182
+ icon: "shield-check",
183
+ value: isOpenCodeAutoAcceptEnabled(config),
184
+ };
185
+ }
186
+ function buildOpenCodePermissionActions() {
187
+ return [
188
+ {
189
+ id: "deny",
190
+ label: "Deny",
191
+ behavior: "deny",
192
+ variant: "danger",
193
+ intent: "dismiss",
194
+ },
195
+ {
196
+ id: OPENCODE_PERMISSION_ACTION_ALLOW_ALWAYS,
197
+ label: "Allow always",
198
+ behavior: "allow",
199
+ variant: "secondary",
200
+ },
201
+ {
202
+ id: OPENCODE_PERMISSION_ACTION_ALLOW_ONCE,
203
+ label: "Allow once",
204
+ behavior: "allow",
205
+ variant: "primary",
206
+ },
207
+ ];
208
+ }
209
+ function resolveOpenCodePermissionReply(response) {
210
+ if (response.behavior === "deny") {
211
+ return "reject";
212
+ }
213
+ if (response.selectedActionId === OPENCODE_PERMISSION_ACTION_ALLOW_ALWAYS) {
214
+ return "always";
215
+ }
216
+ return "once";
217
+ }
218
+ const OPENCODE_SESSION_ENV_KEYS = new Set(["PASEO_AGENT_ID", "PASEO_AGENT_CWD"]);
219
+ function requiresDedicatedOpenCodeServer(config, launchContext) {
220
+ if (config.mcpServers && Object.keys(config.mcpServers).length > 0)
221
+ return true;
222
+ return Object.keys(launchContext?.env ?? {}).some((key) => !OPENCODE_SESSION_ENV_KEYS.has(key));
223
+ }
224
+ const MCP_ALREADY_PRESENT_ERROR_TOKENS = ["already", "exists", "connected"];
225
+ const OPENCODE_METADATA_CONCURRENCY = 4;
226
+ const openCodeMetadataLimit = pLimit(OPENCODE_METADATA_CONCURRENCY);
227
+ const OPENCODE_HANDLED_BUILTIN_SLASH_COMMANDS = [
228
+ {
229
+ name: "compact",
230
+ description: "Compact the current session",
231
+ argumentHint: "",
232
+ kind: "command",
233
+ },
234
+ {
235
+ name: "summarize",
236
+ description: "Compact the current session",
237
+ argumentHint: "",
238
+ kind: "command",
239
+ },
240
+ ];
241
+ const OPENCODE_HEADERS_TIMEOUT_TOKENS = [
242
+ "headers timeout",
243
+ "headers timeout error",
244
+ "headers_timeout",
245
+ "und_err_headers_timeout",
246
+ ];
247
+ const OpencodeToolStateSchema = z
248
+ .object({
249
+ status: z.string().optional(),
250
+ input: z.unknown().optional(),
251
+ output: z.unknown().optional(),
252
+ error: z.unknown().optional(),
253
+ metadata: z.record(z.string(), z.unknown()).optional(),
254
+ })
255
+ .passthrough();
256
+ const OpencodeToolPartBaseSchema = z
257
+ .object({
258
+ tool: z.string().trim().min(1),
259
+ state: OpencodeToolStateSchema.optional(),
260
+ })
261
+ .passthrough();
262
+ const OpencodeToolPartWithCallIdSchema = OpencodeToolPartBaseSchema.extend({
263
+ callID: z.string().trim().min(1),
264
+ id: z.string().optional(),
265
+ }).transform((part) => ({
266
+ toolName: part.tool,
267
+ callId: part.callID,
268
+ status: part.state?.status,
269
+ input: part.state?.input,
270
+ output: part.state?.output,
271
+ error: part.state?.error,
272
+ metadata: part.state?.metadata,
273
+ }));
274
+ const OpencodeToolPartWithIdSchema = OpencodeToolPartBaseSchema.extend({
275
+ id: z.string().trim().min(1),
276
+ callID: z.string().optional(),
277
+ }).transform((part) => ({
278
+ toolName: part.tool,
279
+ callId: part.id,
280
+ status: part.state?.status,
281
+ input: part.state?.input,
282
+ output: part.state?.output,
283
+ error: part.state?.error,
284
+ metadata: part.state?.metadata,
285
+ }));
286
+ const OpencodeToolPartWithoutIdSchema = OpencodeToolPartBaseSchema.extend({
287
+ id: z.string().optional(),
288
+ callID: z.string().optional(),
289
+ }).transform((part) => ({
290
+ toolName: part.tool,
291
+ callId: undefined,
292
+ status: part.state?.status,
293
+ input: part.state?.input,
294
+ output: part.state?.output,
295
+ error: part.state?.error,
296
+ metadata: part.state?.metadata,
297
+ }));
298
+ const OpencodeToolPartSchema = z.union([
299
+ OpencodeToolPartWithCallIdSchema,
300
+ OpencodeToolPartWithIdSchema,
301
+ OpencodeToolPartWithoutIdSchema,
302
+ ]);
303
+ const OpencodeToolPartTimelineEnvelopeSchema = OpencodeToolPartSchema.transform((part) => ({
304
+ toolName: part.toolName,
305
+ callId: part.callId,
306
+ status: part.status,
307
+ input: part.input,
308
+ output: part.output,
309
+ error: part.error,
310
+ metadata: part.metadata,
311
+ }));
312
+ const OpencodeToolPartToTimelineItemSchema = OpencodeToolPartTimelineEnvelopeSchema.transform((part) => mapOpencodeToolCall({
313
+ toolName: part.toolName,
314
+ callId: part.callId,
315
+ status: part.status,
316
+ input: part.input,
317
+ output: part.output,
318
+ error: part.error,
319
+ metadata: part.metadata,
320
+ }));
321
+ function toOpenCodeMcpConfig(config) {
322
+ if (config.type === "stdio") {
323
+ return {
324
+ type: "local",
325
+ command: [config.command, ...(config.args ?? [])],
326
+ ...(config.env ? { environment: config.env } : {}),
327
+ enabled: true,
328
+ };
329
+ }
330
+ return {
331
+ type: "remote",
332
+ url: config.url,
333
+ ...(config.headers ? { headers: config.headers } : {}),
334
+ enabled: true,
335
+ };
336
+ }
337
+ function toTerminalTurnEvent(event) {
338
+ if (event.type === "turn_failed") {
339
+ return {
340
+ type: "turn_failed",
341
+ provider: "opencode",
342
+ error: toDiagnosticErrorMessage(event.error),
343
+ };
344
+ }
345
+ if (event.type === "turn_completed" || event.type === "turn_canceled") {
346
+ return event;
347
+ }
348
+ return null;
349
+ }
350
+ function isOpenCodeNotFoundError(error) {
351
+ return (typeof error === "object" &&
352
+ error !== null &&
353
+ "name" in error &&
354
+ error.name === "NotFoundError");
355
+ }
356
+ async function abortOpenCodeSession(params) {
357
+ const { client, sessionId, directory, logger } = params;
358
+ try {
359
+ const response = await client.session.abort({
360
+ sessionID: sessionId,
361
+ directory,
362
+ });
363
+ if (response.error && !isOpenCodeNotFoundError(response.error)) {
364
+ logger.warn({
365
+ sessionId,
366
+ error: toDiagnosticErrorMessage(response.error),
367
+ }, "Failed to abort OpenCode session during close");
368
+ }
369
+ }
370
+ catch (error) {
371
+ logger.warn({
372
+ sessionId,
373
+ error: toDiagnosticErrorMessage(error),
374
+ }, "Failed to abort OpenCode session during close");
375
+ }
376
+ }
377
+ function isOpenCodeHeadersTimeoutFailure(error) {
378
+ const diagnostics = new Set();
379
+ const queue = [error];
380
+ while (queue.length > 0) {
381
+ const current = queue.shift();
382
+ if (!current) {
383
+ continue;
384
+ }
385
+ const normalized = toDiagnosticErrorMessage(current).trim().toLowerCase();
386
+ if (normalized) {
387
+ diagnostics.add(normalized);
388
+ }
389
+ if (typeof current === "object") {
390
+ const record = current;
391
+ for (const value of [record.message, record.code, record.name]) {
392
+ if (typeof value !== "string") {
393
+ continue;
394
+ }
395
+ const diagnostic = value.trim().toLowerCase();
396
+ if (diagnostic) {
397
+ diagnostics.add(diagnostic);
398
+ }
399
+ }
400
+ if (record.cause) {
401
+ queue.push(record.cause);
402
+ }
403
+ }
404
+ }
405
+ return [...diagnostics].some((diagnostic) => OPENCODE_HEADERS_TIMEOUT_TOKENS.some((token) => diagnostic.includes(token)));
406
+ }
407
+ function isAlreadyPresentMcpError(error) {
408
+ const normalized = toDiagnosticErrorMessage(error).toLowerCase();
409
+ return MCP_ALREADY_PRESENT_ERROR_TOKENS.some((token) => normalized.includes(token));
410
+ }
411
+ function readOpenCodeMcpOperationError(data, name) {
412
+ const root = readOpenCodeRecord(data);
413
+ const entry = readOpenCodeRecord(root?.[name]);
414
+ if (!entry || entry.status !== "failed") {
415
+ return undefined;
416
+ }
417
+ return entry.error ?? `OpenCode reported MCP server '${name}' failed`;
418
+ }
419
+ function matchesHydratedFingerprint(fingerprints, id, value) {
420
+ const hydratedFingerprint = fingerprints?.get(id);
421
+ if (!hydratedFingerprint) {
422
+ return false;
423
+ }
424
+ fingerprints?.delete(id);
425
+ return hydratedFingerprint === JSON.stringify(value);
426
+ }
427
+ // `null` = no explicit mode. The `agent` field is then omitted from OpenCode
428
+ // prompt/command calls so OpenCode falls back to its own configured default
429
+ // agent — never assume any particular agent (even `build`) exists, since
430
+ // OpenCode users can define or delete agents at will.
431
+ function normalizeOpenCodeModeId(modeId) {
432
+ const trimmed = typeof modeId === "string" ? modeId.trim() : "";
433
+ if (!trimmed || trimmed === "default") {
434
+ return null;
435
+ }
436
+ return trimmed;
437
+ }
438
+ function normalizeOpenCodeVariantId(variantId) {
439
+ const trimmed = typeof variantId === "string" ? variantId.trim() : "";
440
+ if (!trimmed || trimmed === OPENCODE_DEFAULT_VARIANT_ID) {
441
+ return null;
442
+ }
443
+ return trimmed;
444
+ }
445
+ function resolveOpenCodeRuntimeAgentId(modeId) {
446
+ const normalizedModeId = normalizeOpenCodeModeId(modeId);
447
+ if (normalizedModeId === null) {
448
+ return undefined;
449
+ }
450
+ return normalizedModeId === OPENCODE_LEGACY_FULL_ACCESS_MODE_ID
451
+ ? OPENCODE_BUILD_MODE_ID
452
+ : normalizedModeId;
453
+ }
454
+ function normalizeOpenCodeConfig(config) {
455
+ const normalized = {
456
+ ...config,
457
+ thinkingOptionId: normalizeOpenCodeVariantId(config.thinkingOptionId) ?? undefined,
458
+ };
459
+ if (normalizeOpenCodeModeId(normalized.modeId) !== OPENCODE_LEGACY_FULL_ACCESS_MODE_ID) {
460
+ return normalized;
461
+ }
462
+ return {
463
+ ...normalized,
464
+ modeId: OPENCODE_BUILD_MODE_ID,
465
+ featureValues: {
466
+ ...normalized.featureValues,
467
+ [OPENCODE_AUTO_ACCEPT_FEATURE_ID]: true,
468
+ },
469
+ };
470
+ }
471
+ function isSelectableOpenCodeAgent(agent) {
472
+ return (agent.mode === "primary" || agent.mode === "all") && agent.hidden !== true;
473
+ }
474
+ const OPENCODE_AGENT_HEX_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
475
+ function readOpenCodeAgentHexColor(agent) {
476
+ return typeof agent.color === "string" && OPENCODE_AGENT_HEX_COLOR_PATTERN.test(agent.color)
477
+ ? agent.color
478
+ : undefined;
479
+ }
480
+ function mapOpenCodeAgentToMode(agent) {
481
+ const colorTier = readOpenCodeAgentHexColor(agent);
482
+ return {
483
+ id: agent.name,
484
+ label: agent.name.charAt(0).toUpperCase() + agent.name.slice(1),
485
+ icon: "Bot",
486
+ description: typeof agent.description === "string" && agent.description.trim().length > 0
487
+ ? agent.description.trim()
488
+ : DEFAULT_MODES.find((mode) => mode.id === agent.name)?.description,
489
+ ...(colorTier ? { colorTier } : {}),
490
+ };
491
+ }
492
+ function mergeOpenCodeModes(discoveredModes) {
493
+ const filtered = discoveredModes.filter((mode) => mode.id !== OPENCODE_LEGACY_FULL_ACCESS_MODE_ID);
494
+ // When discovery returns results, trust them exactly — don't inject hardcoded
495
+ // defaults that the user may have intentionally disabled in their OpenCode config.
496
+ // When discovery produced nothing, return empty rather than fabricating modes:
497
+ // OpenCode users can rename or delete any agent, so a hardcoded fallback can
498
+ // validate a mode that does not actually exist (failing later at prompt time).
499
+ return sortOpenCodeModes(filtered);
500
+ }
501
+ function sortOpenCodeModes(modes) {
502
+ const order = new Map(DEFAULT_MODES.map((mode, index) => [mode.id, index]));
503
+ return [...modes].sort((left, right) => {
504
+ const leftOrder = order.get(left.id) ?? Number.MAX_SAFE_INTEGER;
505
+ const rightOrder = order.get(right.id) ?? Number.MAX_SAFE_INTEGER;
506
+ if (leftOrder !== rightOrder) {
507
+ return leftOrder - rightOrder;
508
+ }
509
+ return left.label.localeCompare(right.label);
510
+ });
511
+ }
512
+ function readPositiveFiniteNumber(value) {
513
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
514
+ }
515
+ function maxFiniteNumber(left, right) {
516
+ return left === undefined ? right : Math.max(left, right);
517
+ }
518
+ function assignUsageNumber(usage, key, value) {
519
+ if (value !== undefined) {
520
+ usage[key] = value;
521
+ }
522
+ }
523
+ function buildOpenCodeModelLookupKey(providerId, modelId) {
524
+ return `${providerId}/${modelId}`;
525
+ }
526
+ function parseOpenCodeModelLookupKey(modelId) {
527
+ if (typeof modelId !== "string" || modelId.trim().length === 0) {
528
+ return undefined;
529
+ }
530
+ const slashIndex = modelId.indexOf("/");
531
+ if (slashIndex <= 0 || slashIndex === modelId.length - 1) {
532
+ return undefined;
533
+ }
534
+ const providerId = modelId.slice(0, slashIndex).trim();
535
+ const providerModelId = modelId.slice(slashIndex + 1).trim();
536
+ if (!providerId || !providerModelId) {
537
+ return undefined;
538
+ }
539
+ return buildOpenCodeModelLookupKey(providerId, providerModelId);
540
+ }
541
+ function extractOpenCodeModelContextWindow(model) {
542
+ if (!model || typeof model !== "object") {
543
+ return undefined;
544
+ }
545
+ const limit = model.limit;
546
+ return readPositiveFiniteNumber(limit?.context);
547
+ }
548
+ function buildOpenCodeModelDefinition(provider, modelId, model) {
549
+ const rawVariants = model.variants ? Object.keys(model.variants) : [];
550
+ // OpenCode lists only overrides; its base model behavior is selected by omitting `variant`.
551
+ const thinkingOptions = rawVariants.length
552
+ ? [
553
+ { id: OPENCODE_DEFAULT_VARIANT_ID, label: "Default", isDefault: true },
554
+ ...rawVariants.map((id) => ({ id, label: id })),
555
+ ]
556
+ : [];
557
+ return {
558
+ provider: "opencode",
559
+ id: `${provider.id}/${modelId}`,
560
+ label: model.name,
561
+ description: `${provider.name} - ${model.family ?? ""}`.trim(),
562
+ thinkingOptions: thinkingOptions.length > 0 ? thinkingOptions : undefined,
563
+ defaultThinkingOptionId: thinkingOptions[0]?.id,
564
+ metadata: {
565
+ providerId: provider.id,
566
+ providerName: provider.name,
567
+ modelId,
568
+ family: model.family,
569
+ releaseDate: model.release_date,
570
+ supportsAttachments: model.attachment,
571
+ supportsReasoning: model.reasoning,
572
+ supportsToolCall: model.tool_call,
573
+ cost: model.cost,
574
+ contextWindowMaxTokens: extractOpenCodeModelContextWindow(model),
575
+ ...(model.limit ? { limit: model.limit } : {}),
576
+ },
577
+ };
578
+ }
579
+ function resolveOpenCodeSelectedModelContextWindow(providers, modelId) {
580
+ if (!providers) {
581
+ return undefined;
582
+ }
583
+ const modelLookupKey = parseOpenCodeModelLookupKey(modelId);
584
+ if (!modelLookupKey) {
585
+ return undefined;
586
+ }
587
+ const lookup = buildOpenCodeModelContextWindowLookup(providers);
588
+ return lookup.get(modelLookupKey);
589
+ }
590
+ function buildOpenCodeModelContextWindowLookup(providers) {
591
+ const lookup = new Map();
592
+ if (!providers) {
593
+ return lookup;
594
+ }
595
+ const connectedProviderIds = new Set(providers.connected ?? []);
596
+ for (const provider of providers.all ?? []) {
597
+ // Providers with source "api" are managed by the OpenCode console/subscription and are
598
+ // usable even though they don't appear in `connected` (which only lists env/config providers).
599
+ if (!connectedProviderIds.has(provider.id) && provider.source !== "api") {
600
+ continue;
601
+ }
602
+ for (const [modelId, modelDefinition] of Object.entries(provider.models ?? {})) {
603
+ const contextWindow = extractOpenCodeModelContextWindow(modelDefinition);
604
+ if (contextWindow === undefined) {
605
+ continue;
606
+ }
607
+ lookup.set(buildOpenCodeModelLookupKey(provider.id, modelId), contextWindow);
608
+ }
609
+ }
610
+ return lookup;
611
+ }
612
+ function resolveOpenCodeModelLookupKeyFromAssistantMessage(info) {
613
+ const providerId = info.providerID;
614
+ const modelId = info.modelID;
615
+ if (!providerId || !modelId) {
616
+ return undefined;
617
+ }
618
+ return buildOpenCodeModelLookupKey(providerId, modelId);
619
+ }
620
+ function mergeOpenCodeStepFinishUsage(usage, part, options = {}) {
621
+ const inputTokens = readPositiveFiniteNumber(part.tokens?.input);
622
+ const outputTokens = readPositiveFiniteNumber(part.tokens?.output);
623
+ const reasoningTokens = readPositiveFiniteNumber(part.tokens?.reasoning);
624
+ const cacheReadTokens = readPositiveFiniteNumber(part.tokens?.cache?.read);
625
+ const cacheWriteTokens = readPositiveFiniteNumber(part.tokens?.cache?.write);
626
+ const totalTokens = (inputTokens ?? 0) +
627
+ (outputTokens ?? 0) +
628
+ (reasoningTokens ?? 0) +
629
+ (cacheReadTokens ?? 0) +
630
+ (cacheWriteTokens ?? 0);
631
+ const cost = readPositiveFiniteNumber(part.cost);
632
+ assignUsageNumber(usage, "inputTokens", inputTokens);
633
+ assignUsageNumber(usage, "cachedInputTokens", cacheReadTokens);
634
+ assignUsageNumber(usage, "outputTokens", outputTokens);
635
+ if (totalTokens > 0) {
636
+ usage.contextWindowUsedTokens = totalTokens;
637
+ }
638
+ if (cost !== undefined) {
639
+ usage.totalCostUsd = options.totalCostUsd ?? (usage.totalCostUsd ?? 0) + cost;
640
+ }
641
+ }
642
+ function hasNormalizedOpenCodeUsage(usage) {
643
+ return [
644
+ usage.inputTokens,
645
+ usage.cachedInputTokens,
646
+ usage.outputTokens,
647
+ usage.totalCostUsd,
648
+ usage.contextWindowMaxTokens,
649
+ usage.contextWindowUsedTokens,
650
+ ].some((value) => typeof value === "number" && Number.isFinite(value));
651
+ }
652
+ function getOpenCodeAttachmentExtension(mimeType) {
653
+ switch (mimeType) {
654
+ case "image/png":
655
+ return "png";
656
+ case "image/jpeg":
657
+ return "jpg";
658
+ case "image/webp":
659
+ return "webp";
660
+ case "image/gif":
661
+ return "gif";
662
+ case "image/svg+xml":
663
+ return "svg";
664
+ default:
665
+ return "bin";
666
+ }
667
+ }
668
+ function toOpenCodeDataUrl(mimeType, data) {
669
+ const match = data.match(/^data:([^;,]+);base64,(.+)$/);
670
+ if (match) {
671
+ return {
672
+ mimeType: match[1] ?? mimeType,
673
+ url: data,
674
+ };
675
+ }
676
+ return {
677
+ mimeType,
678
+ url: `data:${mimeType};base64,${data}`,
679
+ };
680
+ }
681
+ function buildOpenCodePromptParts(prompt) {
682
+ if (typeof prompt === "string") {
683
+ return [{ type: "text", text: prompt }];
684
+ }
685
+ let attachmentOrdinal = 0;
686
+ const output = [];
687
+ for (const part of prompt) {
688
+ if (part.type === "text") {
689
+ output.push({ type: "text", text: part.text });
690
+ continue;
691
+ }
692
+ if (part.type === "image") {
693
+ attachmentOrdinal += 1;
694
+ const normalized = toOpenCodeDataUrl(part.mimeType, part.data);
695
+ output.push({
696
+ type: "file",
697
+ mime: normalized.mimeType,
698
+ filename: `attachment-${attachmentOrdinal}.${getOpenCodeAttachmentExtension(normalized.mimeType)}`,
699
+ url: normalized.url,
700
+ });
701
+ continue;
702
+ }
703
+ output.push({ type: "text", text: renderPromptAttachmentAsText(part) });
704
+ }
705
+ return output;
706
+ }
707
+ function buildOpenCodeUserTimelineText(prompt) {
708
+ if (typeof prompt === "string") {
709
+ return prompt;
710
+ }
711
+ return prompt
712
+ .map((part) => {
713
+ if (part.type === "text") {
714
+ return part.text;
715
+ }
716
+ if (part.type === "image") {
717
+ return "[Image]";
718
+ }
719
+ return renderPromptAttachmentAsText(part);
720
+ })
721
+ .filter((text) => text.trim().length > 0)
722
+ .join("\n");
723
+ }
724
+ function isOpenCodeDefinitiveSteerRejection(error, status) {
725
+ if (status === 404)
726
+ return true;
727
+ const message = toDiagnosticErrorMessage(error).toLowerCase();
728
+ return /session\s+(?:is\s+)?(?:not found|inactive|not active|not running)/.test(message);
729
+ }
730
+ async function collectOpenCodeImportableSessionsFromSdk(client, options) {
731
+ const limit = options?.limit ?? OPENCODE_PERSISTED_SESSION_LIMIT;
732
+ const scanLimit = Math.min(options?.scanLimit ?? limit, 500);
733
+ const sessionListLimit = Math.min(options?.cwd ? Math.max(scanLimit, OPENCODE_PERSISTED_SESSION_LIMIT) : scanLimit, 500);
734
+ const response = await client.experimental.session.list({
735
+ archived: true,
736
+ roots: true,
737
+ limit: sessionListLimit,
738
+ ...(options?.cwd ? { directory: options.cwd } : {}),
739
+ });
740
+ if (response.error) {
741
+ throw new Error(`Failed to list OpenCode sessions: ${JSON.stringify(response.error)}`);
742
+ }
743
+ return selectOpenCodeSessionsForWorkspace(response.data ?? [], options?.cwd)
744
+ .sort((left, right) => getOpenCodeSessionTimestamp(right) - getOpenCodeSessionTimestamp(left))
745
+ .slice(0, limit)
746
+ .map((session) => ({
747
+ providerHandleId: session.id,
748
+ cwd: session.directory,
749
+ title: normalizeOpenCodeSessionTitle(session.title),
750
+ firstPromptPreview: null,
751
+ lastPromptPreview: null,
752
+ lastActivityAt: new Date(getOpenCodeSessionTimestamp(session)),
753
+ }));
754
+ }
755
+ function selectOpenCodeSessionsForWorkspace(sessions, cwd) {
756
+ if (!cwd)
757
+ return sessions;
758
+ const belongsToWorkspace = createPathEquivalenceMatcher(cwd);
759
+ return sessions.filter((session) => belongsToWorkspace(session.directory));
760
+ }
761
+ function openCodeCatalogDirectory(options, resolveHomeDir) {
762
+ if (options.scope === "workspace") {
763
+ return { directory: options.cwd, needsDirectory: false };
764
+ }
765
+ return { directory: resolveHomeDir(), needsDirectory: true };
766
+ }
767
+ function normalizeOpenCodeSessionTitle(title) {
768
+ const normalized = title?.trim();
769
+ return normalized ? normalized : null;
770
+ }
771
+ function getOpenCodeSessionTimestamp(session) {
772
+ return session.time?.updated ?? session.time?.created ?? 0;
773
+ }
774
+ function resolveOpenCodeReplayTimestamp(params) {
775
+ const timedPart = params.part;
776
+ const partTimestamp = timedPart?.time?.start ??
777
+ timedPart?.time?.end ??
778
+ params.message.time?.created ??
779
+ params.message.time?.completed;
780
+ return normalizeProviderReplayTimestamp(partTimestamp);
781
+ }
782
+ function buildOpenCodeReplayTimelineEvent(params) {
783
+ const timestamp = resolveOpenCodeReplayTimestamp({
784
+ message: params.message,
785
+ part: params.part,
786
+ });
787
+ return {
788
+ type: "timeline",
789
+ provider: "opencode",
790
+ item: params.item,
791
+ ...(timestamp ? { timestamp } : {}),
792
+ };
793
+ }
794
+ function buildOpenCodeReplayPartTimelineEvent(params) {
795
+ const { part, message } = params;
796
+ if (part.type === "text" && part.text) {
797
+ return buildOpenCodeReplayTimelineEvent({
798
+ item: { type: "assistant_message", text: part.text, messageId: message.id },
799
+ message,
800
+ part,
801
+ });
802
+ }
803
+ if (part.type === "reasoning" && part.text) {
804
+ return buildOpenCodeReplayTimelineEvent({
805
+ item: { type: "reasoning", text: part.text },
806
+ message,
807
+ part,
808
+ });
809
+ }
810
+ if (part.type !== "tool") {
811
+ return null;
812
+ }
813
+ if (isOpenCodeTodoWriteToolPart(part)) {
814
+ const todos = readOpenCodeTodoItemsFromToolPart(part);
815
+ if (!todos) {
816
+ return null;
817
+ }
818
+ return buildOpenCodeReplayTimelineEvent({
819
+ item: mapOpenCodeTodosToTimelineItems(todos),
820
+ message,
821
+ part,
822
+ });
823
+ }
824
+ const parsedToolPart = OpencodeToolPartToTimelineItemSchema.safeParse(part);
825
+ if (!parsedToolPart.success || !parsedToolPart.data) {
826
+ return null;
827
+ }
828
+ return buildOpenCodeReplayTimelineEvent({
829
+ item: parsedToolPart.data,
830
+ message,
831
+ part,
832
+ });
833
+ }
834
+ function isOpenCodeCompactionSummaryMessage(message) {
835
+ return (message.role === "assistant" &&
836
+ (message.summary === true || message.agent === "compaction" || message.mode === "compaction"));
837
+ }
838
+ function findOpenCodeCompactionPart(message) {
839
+ return message.parts.find((part) => part.type === "compaction");
840
+ }
841
+ async function readOpenCodeSessionMessagesFromSdk(client, session, signal) {
842
+ const response = await client.session.messages({
843
+ sessionID: session.id,
844
+ directory: session.directory,
845
+ }, signal ? { signal } : undefined);
846
+ if (response.error || !response.data) {
847
+ return [];
848
+ }
849
+ return filterOpenCodeRevertedMessages(response.data, session.revert);
850
+ }
851
+ function buildOpenCodeSessionTimeline(messages) {
852
+ const timeline = [];
853
+ let hideNextAssistantAfterCompaction = false;
854
+ for (const message of messages) {
855
+ const compactionPart = findOpenCodeCompactionPart(message);
856
+ if (message.info.role === "assistant" && hideNextAssistantAfterCompaction) {
857
+ hideNextAssistantAfterCompaction = false;
858
+ continue;
859
+ }
860
+ if (message.info.role === "user" && !compactionPart) {
861
+ hideNextAssistantAfterCompaction = false;
862
+ }
863
+ timeline.push(...buildOpenCodeReplayTimelineEvents(message).map((event) => event.item));
864
+ if (message.info.role === "user" && compactionPart) {
865
+ timeline.push(createCompactionTimelineItem("completed", compactionPart.auto ? "auto" : "manual"));
866
+ hideNextAssistantAfterCompaction = true;
867
+ }
868
+ }
869
+ return timeline;
870
+ }
871
+ function filterOpenCodeRevertedMessages(messages, revert) {
872
+ if (!revert?.messageID || revert.partID) {
873
+ return [...messages];
874
+ }
875
+ const revertIndex = messages.findIndex((message) => message.info.id === revert.messageID);
876
+ if (revertIndex < 0) {
877
+ return [...messages];
878
+ }
879
+ return messages.slice(0, revertIndex);
880
+ }
881
+ function resolveOpenCodePersistedSessionModeId(session, messages) {
882
+ const agent = session.agent ?? messages.map(readOpenCodeMessageAgent).find(Boolean);
883
+ return agent ? (normalizeOpenCodeModeId(agent) ?? undefined) : undefined;
884
+ }
885
+ function readOpenCodeMessageAgent(message) {
886
+ const agent = message.info.agent;
887
+ return typeof agent === "string" && agent.trim() ? agent : undefined;
888
+ }
889
+ function resolveOpenCodePersistedSessionModel(session, messages) {
890
+ if (session.model) {
891
+ return buildOpenCodeModelLookupKey(session.model.providerID, session.model.id);
892
+ }
893
+ const model = messages.map(readOpenCodeMessageModel).find(Boolean);
894
+ return model ? buildOpenCodeModelLookupKey(model.providerID, model.modelID) : undefined;
895
+ }
896
+ function readOpenCodeMessageModel(message) {
897
+ const { info } = message;
898
+ if (info.role === "user") {
899
+ return info.model;
900
+ }
901
+ return {
902
+ providerID: info.providerID,
903
+ modelID: info.modelID,
904
+ };
905
+ }
906
+ function buildOpenCodeReplayTimelineEvents(message) {
907
+ const { info, parts } = message;
908
+ if (isOpenCodeCompactionSummaryMessage(info)) {
909
+ return [];
910
+ }
911
+ if (info.role === "user") {
912
+ const text = parts
913
+ .filter((part) => part.type === "text")
914
+ .map((part) => part.text)
915
+ .join("");
916
+ return text
917
+ ? [
918
+ buildOpenCodeReplayTimelineEvent({
919
+ item: { type: "user_message", text, messageId: info.id },
920
+ message: info,
921
+ }),
922
+ ]
923
+ : [];
924
+ }
925
+ const events = [];
926
+ let emittedAssistantText = false;
927
+ for (const part of parts) {
928
+ if (part.type === "text" && part.text) {
929
+ emittedAssistantText = true;
930
+ }
931
+ const event = buildOpenCodeReplayPartTimelineEvent({ part, message: info });
932
+ if (event) {
933
+ events.push(event);
934
+ }
935
+ }
936
+ if (!emittedAssistantText) {
937
+ const text = stringifyStructuredAssistantMessage(info.structured);
938
+ if (text) {
939
+ events.push(buildOpenCodeReplayTimelineEvent({
940
+ item: { type: "assistant_message", text, messageId: info.id },
941
+ message: info,
942
+ }));
943
+ }
944
+ }
945
+ return events;
946
+ }
947
+ export const __openCodeInternals = {
948
+ buildOpenCodePromptParts,
949
+ buildOpenCodeSessionTimeline,
950
+ buildOpenCodeModelContextWindowLookup,
951
+ buildOpenCodeModelDefinition,
952
+ buildOpenCodeModelLookupKey,
953
+ extractOpenCodeModelContextWindow,
954
+ hasNormalizedOpenCodeUsage,
955
+ mergeOpenCodeStepFinishUsage,
956
+ parseOpenCodeModelLookupKey,
957
+ resolveOpenCodeModelLookupKeyFromAssistantMessage,
958
+ resolveOpenCodeSelectedModelContextWindow,
959
+ isSelectableOpenCodeAgent,
960
+ mapOpenCodeAgentToMode,
961
+ resolveOpenCodeHomeDir,
962
+ get OpenCodeAgentSession() {
963
+ return OpenCodeAgentSession;
964
+ },
965
+ };
966
+ function createSdkOpenCodeClient(options) {
967
+ return createOpencodeClient(options);
968
+ }
969
+ export class OpenCodeAgentClient {
970
+ constructor(logger, runtimeSettings, deps = {}) {
971
+ this.provider = "opencode";
972
+ this.resolveCreateConfig = resolveOpenCodeCreateConfig;
973
+ this.isCreateConfigUnattended = isOpenCodeCreateConfigUnattended;
974
+ this.modelContextWindows = new Map();
975
+ this.logger = logger.child({ module: "agent", provider: "opencode" });
976
+ this.bridge = deps.bridge;
977
+ this.capabilities = {
978
+ ...OPENCODE_CAPABILITIES,
979
+ ...(this.bridge ? { supportsNativePaseoTools: true } : {}),
980
+ };
981
+ this.runtimeSettings = runtimeSettings;
982
+ this.createOpenCodeClient = deps.createClient ?? createSdkOpenCodeClient;
983
+ this.serverManager =
984
+ deps.serverManager ??
985
+ OpenCodeServerManager.getInstance(this.logger, runtimeSettings, {
986
+ managedProcesses: deps.managedProcesses,
987
+ resolveHomeDir: deps.resolveHomeDir,
988
+ createEventSource: ({ serverUrl, processExit, logger: eventLogger }) => new OpenCodeEventConsumer({
989
+ serverUrl,
990
+ processExit,
991
+ logger: eventLogger,
992
+ createClient: (baseUrl) => this.createOpenCodeClient({ baseUrl, directory: "" }),
993
+ }),
994
+ decorateServerEnv: this.bridge
995
+ ? (env) => this.bridge?.decorateServerEnv(env) ?? env
996
+ : undefined,
997
+ });
998
+ this.resolveHomeDir = deps.resolveHomeDir ?? resolveOpenCodeHomeDir;
999
+ }
1000
+ async createSession(config, launchContext, options) {
1001
+ const openCodeConfig = this.assertConfig(config);
1002
+ const acquisition = await this.acquireServer(openCodeConfig, launchContext);
1003
+ const { url } = acquisition.server;
1004
+ const client = this.createOpenCodeClient({
1005
+ baseUrl: url,
1006
+ directory: openCodeConfig.cwd,
1007
+ });
1008
+ try {
1009
+ // Creating the first session for a directory is part of OpenCode coming up, so it
1010
+ // shares the server startup budget instead of a shorter one that fails agent
1011
+ // creation on contended cold starts.
1012
+ const response = await withTimeout(client.session.create({ directory: openCodeConfig.cwd }), OPENCODE_SERVER_STARTUP_TIMEOUT_MS, `OpenCode session.create timed out after ${Math.round(OPENCODE_SERVER_STARTUP_TIMEOUT_MS / 1000)}s`);
1013
+ if (response.error) {
1014
+ throw new Error(`Failed to create OpenCode session: ${JSON.stringify(response.error)}`);
1015
+ }
1016
+ const session = response.data;
1017
+ if (!session) {
1018
+ throw new Error("OpenCode session creation returned no data");
1019
+ }
1020
+ await this.populateModelContextWindowCache(client, openCodeConfig.cwd);
1021
+ const unbindBridge = this.bindBridgeSession(session.id, launchContext);
1022
+ return new OpenCodeAgentSession(openCodeConfig, client, session.id, this.logger, new Map(this.modelContextWindows), acquisition.events, acquisition.release, options?.persistSession, launchContext?.agentId, url, false, unbindBridge);
1023
+ }
1024
+ catch (error) {
1025
+ await acquisition.release();
1026
+ throw error;
1027
+ }
1028
+ }
1029
+ async resumeSession(handle, overrides, launchContext) {
1030
+ const metadata = (handle.metadata ?? {});
1031
+ const cwd = overrides?.cwd ?? metadata.cwd;
1032
+ if (!cwd) {
1033
+ throw new Error("OpenCode resume requires the original working directory");
1034
+ }
1035
+ const config = {
1036
+ ...metadata,
1037
+ ...overrides,
1038
+ provider: "opencode",
1039
+ cwd,
1040
+ };
1041
+ const openCodeConfig = this.assertConfig(config);
1042
+ const registeredServerUrl = getOpenCodeChildSessionServerUrl(handle.sessionId);
1043
+ const registeredAcquisition = registeredServerUrl
1044
+ ? this.serverManager.acquireExisting(registeredServerUrl)
1045
+ : null;
1046
+ const acquisition = registeredAcquisition ?? (await this.acquireServer(openCodeConfig, launchContext));
1047
+ const { url } = acquisition.server;
1048
+ const client = this.createOpenCodeClient({
1049
+ baseUrl: url,
1050
+ directory: openCodeConfig.cwd,
1051
+ });
1052
+ try {
1053
+ await this.populateModelContextWindowCache(client, openCodeConfig.cwd);
1054
+ const unbindBridge = this.bindBridgeSession(handle.sessionId, launchContext);
1055
+ return new OpenCodeAgentSession(openCodeConfig, client, handle.sessionId, this.logger, new Map(this.modelContextWindows), acquisition.events, acquisition.release, undefined, launchContext?.agentId, url, registeredAcquisition !== null, unbindBridge);
1056
+ }
1057
+ catch (error) {
1058
+ await acquisition.release();
1059
+ throw error;
1060
+ }
1061
+ }
1062
+ acquireServer(config, launchContext) {
1063
+ if (!this.bridge || requiresDedicatedOpenCodeServer(config, launchContext)) {
1064
+ return launchContext?.env
1065
+ ? this.serverManager.acquireDedicated(launchContext.env)
1066
+ : this.serverManager.acquireCurrent();
1067
+ }
1068
+ return this.serverManager.acquireCurrent();
1069
+ }
1070
+ bindBridgeSession(sessionId, launchContext) {
1071
+ if (!this.bridge || !launchContext)
1072
+ return undefined;
1073
+ return this.bridge.bindSession({
1074
+ sessionId,
1075
+ env: launchContext.env ?? {},
1076
+ tools: launchContext.paseoTools,
1077
+ });
1078
+ }
1079
+ async fetchCatalog(options, context) {
1080
+ let acquisition;
1081
+ try {
1082
+ await runProviderRefreshActivity(context, "server.acquire", async () => {
1083
+ acquisition = options.force
1084
+ ? await this.serverManager.acquireNew(context?.signal)
1085
+ : await this.serverManager.acquireCurrent(context?.signal);
1086
+ });
1087
+ if (!acquisition)
1088
+ throw new Error("OpenCode server acquisition did not complete");
1089
+ context?.signal.throwIfAborted();
1090
+ const { url } = acquisition.server;
1091
+ const catalogDirectory = openCodeCatalogDirectory(options, this.resolveHomeDir);
1092
+ const { directory } = catalogDirectory;
1093
+ if (catalogDirectory.needsDirectory) {
1094
+ await fs.mkdir(directory, { recursive: true });
1095
+ this.logger.debug({ directory }, "opencode catalog refresh: using opencode-home for global provider catalog");
1096
+ }
1097
+ const client = this.createOpenCodeClient({ baseUrl: url, directory });
1098
+ const [models, modes] = await Promise.all([
1099
+ this.fetchModelsFromClient(client, directory, context),
1100
+ this.fetchModesFromClient(client, directory, context),
1101
+ ]);
1102
+ return { models, modes };
1103
+ }
1104
+ finally {
1105
+ await acquisition?.release();
1106
+ }
1107
+ }
1108
+ async listCommands(config) {
1109
+ const openCodeConfig = this.assertConfig(config);
1110
+ const acquisition = await this.serverManager.acquireCurrent();
1111
+ const { url } = acquisition.server;
1112
+ const client = this.createOpenCodeClient({
1113
+ baseUrl: url,
1114
+ directory: openCodeConfig.cwd,
1115
+ });
1116
+ try {
1117
+ return await listOpenCodeCommandsFromSdk(client, openCodeConfig.cwd);
1118
+ }
1119
+ finally {
1120
+ await acquisition.release();
1121
+ }
1122
+ }
1123
+ async listFeatures(config) {
1124
+ return [buildOpenCodeAutoAcceptFeature(this.assertConfig(config))];
1125
+ }
1126
+ async listImportableSessions(options) {
1127
+ const acquisition = await this.serverManager.acquireCurrent();
1128
+ const { url } = acquisition.server;
1129
+ const client = this.createOpenCodeClient({
1130
+ baseUrl: url,
1131
+ directory: options?.cwd ?? "",
1132
+ });
1133
+ try {
1134
+ return await collectOpenCodeImportableSessionsFromSdk(client, options);
1135
+ }
1136
+ finally {
1137
+ await acquisition.release();
1138
+ }
1139
+ }
1140
+ async importSession(input, context) {
1141
+ const acquisition = await this.serverManager.acquireCurrent();
1142
+ const { url } = acquisition.server;
1143
+ const client = this.createOpenCodeClient({
1144
+ baseUrl: url,
1145
+ directory: input.cwd,
1146
+ });
1147
+ try {
1148
+ const sessionResponse = await client.session.get({
1149
+ sessionID: input.providerHandleId,
1150
+ directory: input.cwd,
1151
+ });
1152
+ if (sessionResponse.error || !sessionResponse.data) {
1153
+ throw new Error(`Failed to load OpenCode session ${input.providerHandleId}`);
1154
+ }
1155
+ const session = sessionResponse.data;
1156
+ const messages = await readOpenCodeSessionMessagesFromSdk(client, session);
1157
+ const modeId = resolveOpenCodePersistedSessionModeId(session, messages);
1158
+ const model = resolveOpenCodePersistedSessionModel(session, messages);
1159
+ return await importSessionFromPersistence({
1160
+ provider: "opencode",
1161
+ request: input,
1162
+ context,
1163
+ resumeSession: this.resumeSession.bind(this),
1164
+ config: {
1165
+ title: normalizeOpenCodeSessionTitle(session.title) ?? undefined,
1166
+ ...(modeId ? { modeId } : {}),
1167
+ ...(model ? { model } : {}),
1168
+ },
1169
+ });
1170
+ }
1171
+ finally {
1172
+ await acquisition.release();
1173
+ }
1174
+ }
1175
+ async archiveNativeSession(handle) {
1176
+ await this.setNativeSessionArchived(handle, Date.now());
1177
+ }
1178
+ async unarchiveNativeSession(handle) {
1179
+ // OpenCode's numeric archive field uses zero as the active-session sentinel.
1180
+ await this.setNativeSessionArchived(handle, 0);
1181
+ }
1182
+ async setNativeSessionArchived(handle, archivedAt) {
1183
+ const metadata = (handle.metadata ?? {});
1184
+ if (!metadata.cwd) {
1185
+ throw new Error("OpenCode native archive update requires the original working directory");
1186
+ }
1187
+ const registeredServerUrl = getOpenCodeChildSessionServerUrl(handle.sessionId);
1188
+ const acquisition = (registeredServerUrl ? this.serverManager.acquireExisting(registeredServerUrl) : null) ??
1189
+ (await this.serverManager.acquireCurrent());
1190
+ const client = this.createOpenCodeClient({
1191
+ baseUrl: acquisition.server.url,
1192
+ directory: metadata.cwd,
1193
+ });
1194
+ try {
1195
+ const response = readOpenCodeRecord(await client.session.update({
1196
+ sessionID: handle.sessionId,
1197
+ directory: metadata.cwd,
1198
+ time: { archived: archivedAt },
1199
+ }));
1200
+ if (response?.error) {
1201
+ throw new Error(`Failed to ${archivedAt === 0 ? "unarchive" : "archive"} OpenCode session: ${toDiagnosticErrorMessage(response.error)}`);
1202
+ }
1203
+ }
1204
+ finally {
1205
+ await acquisition.release();
1206
+ }
1207
+ }
1208
+ async isAvailable() {
1209
+ const launch = await resolveProviderLaunch({
1210
+ commandConfig: this.runtimeSettings?.command,
1211
+ defaultBinary: "opencode",
1212
+ });
1213
+ const availability = await checkProviderLaunchAvailable(launch);
1214
+ return availability.available;
1215
+ }
1216
+ async shutdown() {
1217
+ await this.serverManager.shutdown();
1218
+ }
1219
+ async getDiagnostic() {
1220
+ try {
1221
+ const launch = await resolveProviderLaunch({
1222
+ commandConfig: this.runtimeSettings?.command,
1223
+ defaultBinary: "opencode",
1224
+ });
1225
+ const availability = await checkProviderLaunchAvailable(launch);
1226
+ let authValue = "Not checked";
1227
+ const authCommand = availability.available
1228
+ ? (availability.resolvedPath ?? launch.command)
1229
+ : null;
1230
+ if (authCommand) {
1231
+ try {
1232
+ const { stdout, stderr } = await execCommand(authCommand, [...launch.args, "auth", "list"], {
1233
+ ...createProviderEnvSpec(),
1234
+ timeout: 5000,
1235
+ });
1236
+ const text = (stdout.trim() || stderr.trim()).trim();
1237
+ authValue = text ? `\n ${text.replace(/\n/g, "\n ")}` : "(empty)";
1238
+ }
1239
+ catch (error) {
1240
+ authValue = `Error - ${toDiagnosticErrorMessage(error)}`;
1241
+ }
1242
+ }
1243
+ return {
1244
+ diagnostic: formatProviderDiagnostic("OpenCode", [
1245
+ ...(await buildCommandResolutionDiagnosticRows(launch, {
1246
+ knownBinaryNames: ["opencode"],
1247
+ })),
1248
+ ...(await buildBinaryDiagnosticRows(launch, availability)),
1249
+ { label: "Auth", value: authValue },
1250
+ ]),
1251
+ };
1252
+ }
1253
+ catch (error) {
1254
+ return {
1255
+ diagnostic: formatProviderDiagnosticError("OpenCode", error),
1256
+ };
1257
+ }
1258
+ }
1259
+ async fetchModelsFromClient(client, directory, context) {
1260
+ const response = await runProviderRefreshActivity(context, "provider.list", () => raceProviderRefreshAbort(context?.signal, openCodeMetadataLimit(() => {
1261
+ context?.signal.throwIfAborted();
1262
+ return client.provider.list({ directory }, context ? { signal: context.signal } : undefined);
1263
+ })));
1264
+ if (response.error) {
1265
+ throw new Error(`Failed to fetch OpenCode providers: ${JSON.stringify(response.error)}`);
1266
+ }
1267
+ const providers = response.data;
1268
+ if (!providers) {
1269
+ return [];
1270
+ }
1271
+ const connectedProviderIds = new Set(providers.connected);
1272
+ const isAccessible = (provider) => connectedProviderIds.has(provider.id) || provider.source === "api";
1273
+ if (!providers.all.some(isAccessible)) {
1274
+ throw new Error("OpenCode has no connected providers. Please authenticate with at least one provider " +
1275
+ "(e.g., openai, anthropic), set appropriate environment variables (e.g., OPENAI_API_KEY), " +
1276
+ "or log in to OpenCode Go via the console.");
1277
+ }
1278
+ const models = [];
1279
+ const contextWindows = new Map();
1280
+ for (const provider of providers.all) {
1281
+ if (!isAccessible(provider)) {
1282
+ continue;
1283
+ }
1284
+ for (const [modelId, model] of Object.entries(provider.models)) {
1285
+ const definition = buildOpenCodeModelDefinition(provider, modelId, model);
1286
+ const contextWindowMaxTokens = extractOpenCodeModelContextWindow(model);
1287
+ if (contextWindowMaxTokens !== undefined) {
1288
+ contextWindows.set(buildOpenCodeModelLookupKey(provider.id, modelId), contextWindowMaxTokens);
1289
+ }
1290
+ models.push(definition);
1291
+ }
1292
+ }
1293
+ context?.signal.throwIfAborted();
1294
+ this.modelContextWindows.clear();
1295
+ for (const [key, value] of contextWindows)
1296
+ this.modelContextWindows.set(key, value);
1297
+ return models;
1298
+ }
1299
+ async fetchModesFromClient(client, directory, context) {
1300
+ const response = await runProviderRefreshActivity(context, "app.agents", () => raceProviderRefreshAbort(context?.signal, openCodeMetadataLimit(() => {
1301
+ context?.signal.throwIfAborted();
1302
+ return client.app.agents({ directory }, context ? { signal: context.signal } : undefined);
1303
+ })));
1304
+ if (response.error || !response.data) {
1305
+ // Discovery failed — return an empty list rather than fabricating
1306
+ // modes. OpenCode users can rename or delete any agent (including
1307
+ // "build"/"plan"), so a hardcoded fallback can validate a mode that
1308
+ // does not actually exist, which then fails at prompt time.
1309
+ return [];
1310
+ }
1311
+ const discovered = response.data.filter(isSelectableOpenCodeAgent).map(mapOpenCodeAgentToMode);
1312
+ return mergeOpenCodeModes(discovered);
1313
+ }
1314
+ assertConfig(config) {
1315
+ if (config.provider !== "opencode") {
1316
+ throw new Error(`OpenCodeAgentClient received config for provider '${config.provider}'`);
1317
+ }
1318
+ const providerOptions = OpenCodeProviderOptionsSchema.parse(config.providerOptions ?? {});
1319
+ return normalizeOpenCodeConfig({ ...config, provider: "opencode", providerOptions });
1320
+ }
1321
+ async populateModelContextWindowCache(client, cwd) {
1322
+ const response = await openCodeMetadataLimit(() => client.provider.list({ directory: cwd }));
1323
+ if (response.error || !response.data) {
1324
+ return;
1325
+ }
1326
+ const lookup = buildOpenCodeModelContextWindowLookup(response.data);
1327
+ this.modelContextWindows.clear();
1328
+ for (const [modelLookupKey, contextWindowMaxTokens] of lookup.entries()) {
1329
+ this.modelContextWindows.set(modelLookupKey, contextWindowMaxTokens);
1330
+ }
1331
+ }
1332
+ }
1333
+ function stringifyStructuredAssistantMessage(value) {
1334
+ if (value === undefined) {
1335
+ return null;
1336
+ }
1337
+ if (typeof value === "string") {
1338
+ const trimmed = value.trim();
1339
+ return trimmed.length > 0 ? trimmed : null;
1340
+ }
1341
+ try {
1342
+ return JSON.stringify(value);
1343
+ }
1344
+ catch {
1345
+ return null;
1346
+ }
1347
+ }
1348
+ async function listOpenCodeCommandsFromSdk(client, directory) {
1349
+ const result = await client.command.list({ directory });
1350
+ const commandsByName = new Map(OPENCODE_HANDLED_BUILTIN_SLASH_COMMANDS.map((command) => [command.name, command]));
1351
+ if (result.error || !result.data) {
1352
+ return Array.from(commandsByName.values());
1353
+ }
1354
+ for (const cmd of result.data) {
1355
+ commandsByName.set(cmd.name, {
1356
+ name: cmd.name,
1357
+ description: cmd.description ?? "",
1358
+ argumentHint: cmd.hints?.length ? cmd.hints.join(" ") : "",
1359
+ kind: cmd.source === "skill" ? "skill" : "command",
1360
+ });
1361
+ }
1362
+ return Array.from(commandsByName.values());
1363
+ }
1364
+ function readOpenCodeRecord(value) {
1365
+ return typeof value === "object" && value !== null && !Array.isArray(value)
1366
+ ? value
1367
+ : null;
1368
+ }
1369
+ function readNonEmptyString(value) {
1370
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
1371
+ }
1372
+ function isOpenCodeTodoWriteToolPart(part) {
1373
+ return part.type === "tool" && part.tool.trim().toLowerCase() === "todowrite";
1374
+ }
1375
+ function readOpenCodeTodoItems(value) {
1376
+ if (typeof value === "string") {
1377
+ try {
1378
+ return readOpenCodeTodoItems(JSON.parse(value));
1379
+ }
1380
+ catch {
1381
+ return null;
1382
+ }
1383
+ }
1384
+ if (Array.isArray(value)) {
1385
+ return value.flatMap((entry) => {
1386
+ const record = readOpenCodeRecord(entry);
1387
+ if (!record) {
1388
+ return [];
1389
+ }
1390
+ const content = readNonEmptyString(record.content);
1391
+ if (!content) {
1392
+ return [];
1393
+ }
1394
+ return [
1395
+ {
1396
+ content,
1397
+ status: readNonEmptyString(record.status),
1398
+ },
1399
+ ];
1400
+ });
1401
+ }
1402
+ const record = readOpenCodeRecord(value);
1403
+ if (!record) {
1404
+ return null;
1405
+ }
1406
+ return readOpenCodeTodoItems(record.todos);
1407
+ }
1408
+ function readOpenCodeTodoItemsFromToolPart(part) {
1409
+ const state = readOpenCodeRecord(part.state);
1410
+ return (readOpenCodeTodoItems(state?.input) ??
1411
+ readOpenCodeTodoItems(state?.output) ??
1412
+ readOpenCodeTodoItems(state?.metadata));
1413
+ }
1414
+ function mapOpenCodeTodosToTimelineItems(todos) {
1415
+ return {
1416
+ type: "todo",
1417
+ items: todos.flatMap((todo) => {
1418
+ const text = readNonEmptyString(todo.content);
1419
+ if (!text) {
1420
+ return [];
1421
+ }
1422
+ return [
1423
+ {
1424
+ text,
1425
+ status: normalizeOpenCodeTodoStatus(todo.status),
1426
+ completed: todo.status === "completed",
1427
+ },
1428
+ ];
1429
+ }),
1430
+ };
1431
+ }
1432
+ function normalizeOpenCodeTodoStatus(status) {
1433
+ if (status === "completed")
1434
+ return "completed";
1435
+ if (status === "in_progress" || status === "inProgress")
1436
+ return "in_progress";
1437
+ return "pending";
1438
+ }
1439
+ function createCompactionTimelineItem(status, trigger) {
1440
+ return {
1441
+ type: "compaction",
1442
+ status,
1443
+ ...(trigger ? { trigger } : {}),
1444
+ };
1445
+ }
1446
+ const PERMISSION_COMMAND_KEYS = ["command", "cmd", "shellCommand"];
1447
+ const PERMISSION_CWD_KEYS = ["cwd", "directory", "path", "workdir"];
1448
+ const PERMISSION_REASON_KEYS = ["reason", "purpose", "description", "message"];
1449
+ const PERMISSION_TITLE_BY_NAME = {
1450
+ external_directory: "Access external directory",
1451
+ bash: "Run shell command",
1452
+ read: "Read files",
1453
+ read_file: "Read files",
1454
+ write: "Write files",
1455
+ write_file: "Write files",
1456
+ create_file: "Write files",
1457
+ edit: "Edit files",
1458
+ apply_patch: "Edit files",
1459
+ apply_diff: "Edit files",
1460
+ };
1461
+ function toHumanReadablePermissionTitle(permission) {
1462
+ const mapped = PERMISSION_TITLE_BY_NAME[permission];
1463
+ if (mapped) {
1464
+ return mapped;
1465
+ }
1466
+ const normalized = permission
1467
+ .split(/[\s_-]+/)
1468
+ .map((part) => part.trim())
1469
+ .filter((part) => part.length > 0)
1470
+ .map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`)
1471
+ .join(" ");
1472
+ return normalized.length > 0 ? normalized : "Permission request";
1473
+ }
1474
+ function readFirstStringFromRecord(record, keys) {
1475
+ if (!record) {
1476
+ return null;
1477
+ }
1478
+ for (const key of keys) {
1479
+ const value = readNonEmptyString(record[key]);
1480
+ if (value) {
1481
+ return value;
1482
+ }
1483
+ }
1484
+ return null;
1485
+ }
1486
+ function readPermissionField(metadata, keys) {
1487
+ const direct = readFirstStringFromRecord(metadata, keys);
1488
+ if (direct) {
1489
+ return direct;
1490
+ }
1491
+ const nestedInput = readOpenCodeRecord(metadata?.input);
1492
+ return readFirstStringFromRecord(nestedInput, keys);
1493
+ }
1494
+ function buildOpenCodePermissionInput(params) {
1495
+ return {
1496
+ ...(params.patterns.length > 0 ? { patterns: params.patterns } : {}),
1497
+ ...(params.metadata ? { metadata: params.metadata } : {}),
1498
+ ...(params.tool ? { tool: params.tool } : {}),
1499
+ ...(params.command ? { command: params.command } : {}),
1500
+ };
1501
+ }
1502
+ function buildOpenCodePermissionDetail(params) {
1503
+ if (params.command) {
1504
+ return {
1505
+ type: "shell",
1506
+ command: params.command,
1507
+ ...(params.cwd ? { cwd: params.cwd } : {}),
1508
+ };
1509
+ }
1510
+ return {
1511
+ type: "unknown",
1512
+ input: {
1513
+ permission: params.permission,
1514
+ ...params.input,
1515
+ },
1516
+ output: null,
1517
+ };
1518
+ }
1519
+ function buildOpenCodePermissionDescription(params) {
1520
+ const parts = [];
1521
+ if (params.reason) {
1522
+ parts.push(params.reason);
1523
+ }
1524
+ if (params.patterns.length > 0) {
1525
+ parts.push(`Scope: ${params.patterns.join(", ")}`);
1526
+ }
1527
+ return parts.length > 0 ? parts.join(" - ") : undefined;
1528
+ }
1529
+ export function translateOpenCodeEvent(event, state) {
1530
+ const events = [];
1531
+ switch (event.type) {
1532
+ case "session.created":
1533
+ case "session.updated":
1534
+ appendOpenCodeSessionCreatedOrUpdated(event, state, events);
1535
+ break;
1536
+ case "session.deleted":
1537
+ appendOpenCodeSessionDeleted(event, state, events);
1538
+ break;
1539
+ case "message.updated":
1540
+ appendOpenCodeMessageUpdated(event, state, events);
1541
+ break;
1542
+ case "message.part.updated":
1543
+ appendOpenCodeMessagePartUpdated(event, state, events);
1544
+ break;
1545
+ case "message.part.delta":
1546
+ appendOpenCodeMessagePartDelta(event, state, events);
1547
+ break;
1548
+ case "permission.asked":
1549
+ appendOpenCodePermissionAsked(event, state, events);
1550
+ break;
1551
+ case "question.asked":
1552
+ appendOpenCodeQuestionAsked(event, state, events);
1553
+ break;
1554
+ case "todo.updated":
1555
+ if (event.properties.sessionID === state.sessionId) {
1556
+ events.push({
1557
+ type: "timeline",
1558
+ provider: "opencode",
1559
+ item: mapOpenCodeTodosToTimelineItems(event.properties.todos),
1560
+ });
1561
+ }
1562
+ break;
1563
+ case "session.compacted":
1564
+ if (event.properties.sessionID === state.sessionId) {
1565
+ events.push({
1566
+ type: "timeline",
1567
+ provider: "opencode",
1568
+ item: createCompactionTimelineItem("completed"),
1569
+ });
1570
+ }
1571
+ break;
1572
+ case "session.idle":
1573
+ if (event.properties.sessionID === state.sessionId) {
1574
+ resetOpenCodeTurnTrackingState(state);
1575
+ events.push({ type: "turn_completed", provider: "opencode", usage: undefined });
1576
+ }
1577
+ break;
1578
+ case "session.error":
1579
+ appendOpenCodeSessionError(event, state, events);
1580
+ break;
1581
+ case "session.status":
1582
+ appendOpenCodeSessionStatus(event, state, events);
1583
+ break;
1584
+ }
1585
+ return events;
1586
+ }
1587
+ function resetOpenCodeTurnTrackingState(state) {
1588
+ state.partTypes.clear();
1589
+ state.compactionSummaryMessageIds.clear();
1590
+ state.emittedCompactionPartIds.clear();
1591
+ if (state.suppressAssistantMessagesUntilIdle) {
1592
+ state.suppressAssistantMessagesUntilIdle.active = false;
1593
+ }
1594
+ }
1595
+ function getOpenCodeSubAgentMaps(state) {
1596
+ state.subAgentsByCallId ?? (state.subAgentsByCallId = new Map());
1597
+ state.subAgentCallIdByChildSessionId ?? (state.subAgentCallIdByChildSessionId = new Map());
1598
+ return {
1599
+ byCallId: state.subAgentsByCallId,
1600
+ callIdByChildSessionId: state.subAgentCallIdByChildSessionId,
1601
+ };
1602
+ }
1603
+ function getOpenCodeKnownChildSessionIds(state) {
1604
+ state.knownChildSessionIds ?? (state.knownChildSessionIds = new Set());
1605
+ return state.knownChildSessionIds;
1606
+ }
1607
+ function getOpenCodeSubagentPresentationState(childSessionId, state) {
1608
+ state.subagentPresentationByChildId ?? (state.subagentPresentationByChildId = new Map());
1609
+ const existing = state.subagentPresentationByChildId.get(childSessionId);
1610
+ if (existing) {
1611
+ return existing;
1612
+ }
1613
+ const created = { facts: {} };
1614
+ state.subagentPresentationByChildId.set(childSessionId, created);
1615
+ return created;
1616
+ }
1617
+ function sumOpenCodeAssistantMessageTokens(tokens) {
1618
+ if (!tokens) {
1619
+ return 0;
1620
+ }
1621
+ return ((readPositiveFiniteNumber(tokens.input) ?? 0) +
1622
+ (readPositiveFiniteNumber(tokens.output) ?? 0) +
1623
+ (readPositiveFiniteNumber(tokens.reasoning) ?? 0) +
1624
+ (readPositiveFiniteNumber(tokens.cache?.read) ?? 0) +
1625
+ (readPositiveFiniteNumber(tokens.cache?.write) ?? 0));
1626
+ }
1627
+ /** Presentation facts observable on a child assistant message. Token sums only count once the
1628
+ * message completes, so partial frames don't publish a shrinking total. */
1629
+ function readOpenCodeAssistantPresentationFacts(info) {
1630
+ const facts = {};
1631
+ const agentName = readNonEmptyString(info.agent);
1632
+ if (agentName) {
1633
+ facts.agentName = agentName;
1634
+ }
1635
+ const modelId = readNonEmptyString(info.modelID);
1636
+ if (modelId) {
1637
+ facts.modelId = modelId;
1638
+ }
1639
+ const variant = readNonEmptyString(info.variant);
1640
+ if (variant) {
1641
+ facts.variant = variant;
1642
+ }
1643
+ if (info.time?.completed !== undefined) {
1644
+ const totalTokens = sumOpenCodeAssistantMessageTokens(info.tokens);
1645
+ if (totalTokens > 0) {
1646
+ facts.totalTokens = totalTokens;
1647
+ }
1648
+ }
1649
+ return Object.keys(facts).length > 0 ? facts : null;
1650
+ }
1651
+ function isOpenCodeSessionTrackedByParent(sessionId, state) {
1652
+ if (state.sideQuestionSessionIds?.has(sessionId) === true)
1653
+ return false;
1654
+ return (sessionId === state.sessionId ||
1655
+ state.knownChildSessionIds?.has(sessionId) === true ||
1656
+ state.subAgentCallIdByChildSessionId?.has(sessionId) === true);
1657
+ }
1658
+ function appendOpenCodeChildSessionDetected(child, state, events, status = "running") {
1659
+ if (child.id === state.sessionId ||
1660
+ !isOpenCodeSessionTrackedByParent(child.parentSessionId, state)) {
1661
+ return false;
1662
+ }
1663
+ const knownChildSessionIds = getOpenCodeKnownChildSessionIds(state);
1664
+ // Known limitation: detection runs once per child, so a session record that gains `agent`
1665
+ // only in a later session.updated is not refreshed here. Assistant-frame facts recover the
1666
+ // descriptor title and subtitle via appendChildAssistantPresentationUpsert.
1667
+ if (knownChildSessionIds.has(child.id)) {
1668
+ return false;
1669
+ }
1670
+ knownChildSessionIds.add(child.id);
1671
+ const presentation = getOpenCodeSubagentPresentationState(child.id, state);
1672
+ const subtitle = foldOpenCodeSubagentPresentation(presentation, {
1673
+ ...(child.agent ? { agentName: child.agent } : {}),
1674
+ ...(child.model?.id ? { modelId: child.model.id } : {}),
1675
+ ...(child.model?.variant ? { variant: child.model.variant } : {}),
1676
+ });
1677
+ const title = claimOpenCodeSubagentFallbackTitle(presentation, child.agent);
1678
+ // The row label contract: `description` carries the task (session title fallback), `title`
1679
+ // carries the subagent type. Neither gets a placeholder — absent facts render as nothing.
1680
+ events.push({
1681
+ type: "provider_subagent",
1682
+ provider: "opencode",
1683
+ event: {
1684
+ type: "upsert",
1685
+ id: child.id,
1686
+ parentSubagentId: child.parentSessionId === state.sessionId ? null : child.parentSessionId,
1687
+ ...(title ? { title } : {}),
1688
+ ...(child.title && !presentation.descriptionFromLink ? { description: child.title } : {}),
1689
+ ...(status ? { status } : {}),
1690
+ ...(child.directory ? { cwd: child.directory } : {}),
1691
+ ...(subtitle ? { subtitle } : {}),
1692
+ },
1693
+ });
1694
+ return true;
1695
+ }
1696
+ function getOpenCodeSubAgentState(callId, state, toolCall) {
1697
+ const maps = getOpenCodeSubAgentMaps(state);
1698
+ const existing = maps.byCallId.get(callId);
1699
+ if (existing) {
1700
+ existing.toolCall = toolCall;
1701
+ return existing;
1702
+ }
1703
+ const created = {
1704
+ toolCall,
1705
+ };
1706
+ maps.byCallId.set(callId, created);
1707
+ return created;
1708
+ }
1709
+ function linkOpenCodeSubAgentChildSession(activity, childSessionId, state, events) {
1710
+ activity.childSessionId = childSessionId;
1711
+ const maps = getOpenCodeSubAgentMaps(state);
1712
+ maps.callIdByChildSessionId.set(childSessionId, activity.toolCall.callId);
1713
+ appendOpenCodeSubAgentLinkPresentation(activity, childSessionId, state, events);
1714
+ }
1715
+ /**
1716
+ * When a child session ties to a parent `task` tool call, publish the task's identity onto the
1717
+ * descriptor: `description` (task input), `title` (subagent type), `toolCallId`. Presentation
1718
+ * only — no `status`, so it can never revert a finished child.
1719
+ */
1720
+ function appendOpenCodeSubAgentLinkPresentation(activity, childSessionId, state, events) {
1721
+ const detail = activity.toolCall.detail;
1722
+ if (detail.type !== "sub_agent") {
1723
+ return;
1724
+ }
1725
+ const presentation = getOpenCodeSubagentPresentationState(childSessionId, state);
1726
+ if (presentation.linkedToolCallId === activity.toolCall.callId) {
1727
+ return;
1728
+ }
1729
+ presentation.linkedToolCallId = activity.toolCall.callId;
1730
+ const subAgentType = readNonEmptyString(detail.subAgentType);
1731
+ const description = readNonEmptyString(detail.description);
1732
+ if (subAgentType) {
1733
+ presentation.titleFromLink = true;
1734
+ presentation.titleEmitted = true;
1735
+ }
1736
+ if (description) {
1737
+ presentation.descriptionFromLink = true;
1738
+ }
1739
+ const subtitle = foldOpenCodeSubagentPresentation(presentation, subAgentType ? { agentName: subAgentType } : {});
1740
+ events.push({
1741
+ type: "provider_subagent",
1742
+ provider: "opencode",
1743
+ event: {
1744
+ type: "upsert",
1745
+ id: childSessionId,
1746
+ toolCallId: activity.toolCall.callId,
1747
+ ...(subAgentType ? { title: subAgentType } : {}),
1748
+ ...(description ? { description } : {}),
1749
+ ...(subtitle ? { subtitle } : {}),
1750
+ },
1751
+ });
1752
+ }
1753
+ function buildOpenCodeSubAgentTimelineItem(activity) {
1754
+ const toolCall = activity.toolCall;
1755
+ if (toolCall.detail.type !== "sub_agent") {
1756
+ return toolCall;
1757
+ }
1758
+ const childSessionId = activity.childSessionId ?? toolCall.detail.childSessionId;
1759
+ return {
1760
+ ...toolCall,
1761
+ detail: {
1762
+ ...toolCall.detail,
1763
+ ...(childSessionId ? { childSessionId } : {}),
1764
+ },
1765
+ };
1766
+ }
1767
+ function registerOpenCodeSubAgentToolCall(item, state, events) {
1768
+ if (item.detail.type !== "sub_agent") {
1769
+ return item;
1770
+ }
1771
+ const activity = getOpenCodeSubAgentState(item.callId, state, item);
1772
+ if (item.detail.childSessionId) {
1773
+ linkOpenCodeSubAgentChildSession(activity, item.detail.childSessionId, state, events);
1774
+ }
1775
+ return buildOpenCodeSubAgentTimelineItem(activity);
1776
+ }
1777
+ function findOnlyOpenCodeSubAgentWaitingForChild(state) {
1778
+ const maps = getOpenCodeSubAgentMaps(state);
1779
+ const candidates = [...maps.byCallId.values()].filter((activity) => activity.toolCall.status === "running" &&
1780
+ activity.toolCall.detail.type === "sub_agent" &&
1781
+ !activity.childSessionId);
1782
+ return candidates.length === 1 ? (candidates[0] ?? null) : null;
1783
+ }
1784
+ function appendOpenCodeToolCallTimelineItem(item, state, events) {
1785
+ const timelineItem = registerOpenCodeSubAgentToolCall(item, state, events);
1786
+ events.push({
1787
+ type: "timeline",
1788
+ provider: "opencode",
1789
+ item: timelineItem,
1790
+ });
1791
+ }
1792
+ function appendOpenCodeSubAgentChildSessionLinked(childSessionId, state, events) {
1793
+ const activity = findOnlyOpenCodeSubAgentWaitingForChild(state);
1794
+ if (!activity) {
1795
+ return;
1796
+ }
1797
+ linkOpenCodeSubAgentChildSession(activity, childSessionId, state, events);
1798
+ events.push({
1799
+ type: "timeline",
1800
+ provider: "opencode",
1801
+ item: buildOpenCodeSubAgentTimelineItem(activity),
1802
+ });
1803
+ }
1804
+ function appendOpenCodeSessionCreatedOrUpdated(event, state, events) {
1805
+ const info = readOpenCodeRecord(event.properties.info);
1806
+ if (event.properties.info.id === state.sessionId) {
1807
+ const sessionCost = readPositiveFiniteNumber(info?.cost);
1808
+ if (sessionCost !== undefined) {
1809
+ state.sessionTotalCostUsd = maxFiniteNumber(state.sessionTotalCostUsd, sessionCost);
1810
+ state.accumulatedUsage.totalCostUsd = state.sessionTotalCostUsd;
1811
+ }
1812
+ events.push({
1813
+ type: "thread_started",
1814
+ sessionId: state.sessionId,
1815
+ provider: "opencode",
1816
+ });
1817
+ return;
1818
+ }
1819
+ if (state.sideQuestionSessionIds?.has(event.properties.info.id) === true) {
1820
+ return;
1821
+ }
1822
+ const parentSessionId = readNonEmptyString(info?.parentID) ?? readNonEmptyString(info?.parentId);
1823
+ if (parentSessionId) {
1824
+ const child = readOpenCodeChildSessionInfo({
1825
+ ...info,
1826
+ id: event.properties.info.id,
1827
+ parentID: parentSessionId,
1828
+ });
1829
+ if (child) {
1830
+ appendOpenCodeChildSessionDetected(child, state, events);
1831
+ }
1832
+ }
1833
+ if (parentSessionId === state.sessionId) {
1834
+ appendOpenCodeSubAgentChildSessionLinked(event.properties.info.id, state, events);
1835
+ }
1836
+ }
1837
+ function appendOpenCodeSessionDeleted(event, state, events) {
1838
+ const sessionId = event.properties.sessionID;
1839
+ if (!isOpenCodeSessionTrackedByParent(sessionId, state)) {
1840
+ return;
1841
+ }
1842
+ state.knownChildSessionIds?.delete(sessionId);
1843
+ state.subAgentCallIdByChildSessionId?.delete(sessionId);
1844
+ state.subagentPresentationByChildId?.delete(sessionId);
1845
+ events.push({
1846
+ type: "provider_subagent",
1847
+ provider: "opencode",
1848
+ event: { type: "remove", id: sessionId },
1849
+ });
1850
+ }
1851
+ function appendOpenCodeMessageUpdated(event, state, events) {
1852
+ const info = event.properties.info;
1853
+ if (info.sessionID !== state.sessionId) {
1854
+ return;
1855
+ }
1856
+ state.messageRoles.set(info.id, info.role);
1857
+ if (matchesHydratedFingerprint(state.hydratedMessageFingerprints, info.id, info)) {
1858
+ return;
1859
+ }
1860
+ if (info.role === "user") {
1861
+ appendOpenCodeUserMessageUpdated(info, state, events);
1862
+ return;
1863
+ }
1864
+ if (info.role !== "assistant") {
1865
+ return;
1866
+ }
1867
+ if (state.suppressAssistantMessagesUntilIdle?.active) {
1868
+ state.compactionSummaryMessageIds.add(info.id);
1869
+ return;
1870
+ }
1871
+ if (isOpenCodeCompactionSummaryMessage(info)) {
1872
+ state.compactionSummaryMessageIds.add(info.id);
1873
+ return;
1874
+ }
1875
+ const modelLookupKey = resolveOpenCodeModelLookupKeyFromAssistantMessage(info);
1876
+ if (modelLookupKey) {
1877
+ const contextWindowMaxTokens = state.modelContextWindowsByModelKey?.get(modelLookupKey);
1878
+ if (contextWindowMaxTokens !== undefined) {
1879
+ state.onAssistantModelContextWindowResolved?.(contextWindowMaxTokens);
1880
+ }
1881
+ }
1882
+ if (state.emittedStructuredMessageIds.has(info.id) || info.time?.completed === undefined) {
1883
+ return;
1884
+ }
1885
+ const text = stringifyStructuredAssistantMessage(info.structured);
1886
+ if (!text) {
1887
+ return;
1888
+ }
1889
+ state.emittedStructuredMessageIds.add(info.id);
1890
+ events.push({
1891
+ type: "timeline",
1892
+ provider: "opencode",
1893
+ item: { type: "assistant_message", text, messageId: info.id },
1894
+ });
1895
+ }
1896
+ function appendOpenCodeUserMessageUpdated(info, state, events) {
1897
+ const pendingSteerIndex = state.pendingSteerSubmissions?.findIndex((submission) => submission.providerMessageId === info.id);
1898
+ const pendingSteer = pendingSteerIndex !== undefined && pendingSteerIndex >= 0
1899
+ ? state.pendingSteerSubmissions?.splice(pendingSteerIndex, 1)[0]
1900
+ : undefined;
1901
+ const text = pendingSteer?.text ?? state.pendingUserMessageText;
1902
+ if (!text || text.trim().length === 0 || state.emittedUserMessageIds?.has(info.id)) {
1903
+ return;
1904
+ }
1905
+ state.emittedUserMessageIds?.add(info.id);
1906
+ const clientMessageId = pendingSteer?.clientMessageId ?? state.pendingClientMessageId;
1907
+ events.push({
1908
+ type: "timeline",
1909
+ provider: "opencode",
1910
+ item: {
1911
+ type: "user_message",
1912
+ text,
1913
+ messageId: info.id,
1914
+ ...(clientMessageId ? { clientMessageId } : {}),
1915
+ },
1916
+ });
1917
+ }
1918
+ function appendOpenCodeMessagePartUpdated(event, state, events) {
1919
+ const part = event.properties.part;
1920
+ if (part.type === "tool" && isOpenCodeTodoWriteToolPart(part)) {
1921
+ return;
1922
+ }
1923
+ if (part.sessionID !== state.sessionId) {
1924
+ return;
1925
+ }
1926
+ if (matchesHydratedFingerprint(state.hydratedPartFingerprints, part.id, part)) {
1927
+ return;
1928
+ }
1929
+ const messageRole = state.messageRoles.get(part.messageID);
1930
+ state.partTypes.set(part.id, part.type);
1931
+ if (state.compactionSummaryMessageIds.has(part.messageID)) {
1932
+ return;
1933
+ }
1934
+ if (shouldSuppressOpenCodeAssistantPart(part, messageRole, state)) {
1935
+ state.compactionSummaryMessageIds.add(part.messageID);
1936
+ return;
1937
+ }
1938
+ if (part.type === "text") {
1939
+ appendOpenCodeTextPart(part, messageRole, state, events);
1940
+ return;
1941
+ }
1942
+ if (part.type === "reasoning") {
1943
+ appendOpenCodeReasoningPart(part, state, events);
1944
+ return;
1945
+ }
1946
+ if (part.type === "tool") {
1947
+ const parsedToolPart = OpencodeToolPartToTimelineItemSchema.safeParse(part);
1948
+ if (parsedToolPart.success && parsedToolPart.data) {
1949
+ appendOpenCodeToolCallTimelineItem(parsedToolPart.data, state, events);
1950
+ }
1951
+ return;
1952
+ }
1953
+ if (part.type === "compaction") {
1954
+ if (state.emittedCompactionPartIds.has(part.id)) {
1955
+ return;
1956
+ }
1957
+ state.emittedCompactionPartIds.add(part.id);
1958
+ events.push({
1959
+ type: "timeline",
1960
+ provider: "opencode",
1961
+ item: createCompactionTimelineItem("loading", part.auto ? "auto" : "manual"),
1962
+ });
1963
+ return;
1964
+ }
1965
+ if (part.type === "step-finish") {
1966
+ const stepCost = readPositiveFiniteNumber(part.cost);
1967
+ if (stepCost !== undefined) {
1968
+ state.sessionTotalCostUsd = (state.sessionTotalCostUsd ?? 0) + stepCost;
1969
+ }
1970
+ mergeOpenCodeStepFinishUsage(state.accumulatedUsage, part, {
1971
+ totalCostUsd: state.sessionTotalCostUsd,
1972
+ });
1973
+ if (hasNormalizedOpenCodeUsage(state.accumulatedUsage)) {
1974
+ events.push({
1975
+ type: "usage_updated",
1976
+ provider: "opencode",
1977
+ usage: { ...state.accumulatedUsage },
1978
+ });
1979
+ }
1980
+ }
1981
+ }
1982
+ function shouldSuppressOpenCodeAssistantPart(part, messageRole, state) {
1983
+ return (state.suppressAssistantMessagesUntilIdle?.active === true &&
1984
+ part.type === "text" &&
1985
+ messageRole !== "user");
1986
+ }
1987
+ function appendOpenCodeTextPart(part, messageRole, state, events) {
1988
+ if (messageRole === "user") {
1989
+ if (!part.text || state.emittedUserMessageIds?.has(part.messageID)) {
1990
+ return;
1991
+ }
1992
+ state.emittedUserMessageIds?.add(part.messageID);
1993
+ events.push({
1994
+ type: "timeline",
1995
+ provider: "opencode",
1996
+ item: { type: "user_message", text: part.text, messageId: part.messageID },
1997
+ });
1998
+ return;
1999
+ }
2000
+ if (!part.time?.end) {
2001
+ return;
2002
+ }
2003
+ const materialized = state.materializedParts.get(part.id);
2004
+ if (materialized?.closed)
2005
+ return;
2006
+ const emittedText = materialized?.messageId === part.messageID ? materialized.emittedText : "";
2007
+ if (!part.text.startsWith(emittedText)) {
2008
+ state.onMaterializationMismatch?.({
2009
+ partId: part.id,
2010
+ messageId: part.messageID,
2011
+ kind: "text",
2012
+ });
2013
+ return;
2014
+ }
2015
+ const suffix = part.text.slice(emittedText.length);
2016
+ state.materializedParts.set(part.id, {
2017
+ messageId: part.messageID,
2018
+ emittedText: part.text,
2019
+ closed: true,
2020
+ });
2021
+ if (suffix) {
2022
+ events.push({
2023
+ type: "timeline",
2024
+ provider: "opencode",
2025
+ item: { type: "assistant_message", text: suffix, messageId: part.messageID },
2026
+ });
2027
+ }
2028
+ }
2029
+ function appendOpenCodeReasoningPart(part, state, events) {
2030
+ if (!part.time.end) {
2031
+ return;
2032
+ }
2033
+ const materialized = state.materializedParts.get(part.id);
2034
+ if (materialized?.closed)
2035
+ return;
2036
+ const emittedText = materialized?.messageId === part.messageID ? materialized.emittedText : "";
2037
+ if (!part.text.startsWith(emittedText)) {
2038
+ state.onMaterializationMismatch?.({
2039
+ partId: part.id,
2040
+ messageId: part.messageID,
2041
+ kind: "reasoning",
2042
+ });
2043
+ return;
2044
+ }
2045
+ const suffix = part.text.slice(emittedText.length);
2046
+ state.materializedParts.set(part.id, {
2047
+ messageId: part.messageID,
2048
+ emittedText: part.text,
2049
+ closed: true,
2050
+ });
2051
+ if (suffix) {
2052
+ events.push({
2053
+ type: "timeline",
2054
+ provider: "opencode",
2055
+ item: { type: "reasoning", text: suffix },
2056
+ });
2057
+ }
2058
+ }
2059
+ function appendOpenCodeMessagePartDelta(event, state, events) {
2060
+ const { sessionID, messageID, partID, field, delta } = event.properties;
2061
+ if (sessionID !== state.sessionId) {
2062
+ return;
2063
+ }
2064
+ if (!delta || !field) {
2065
+ return;
2066
+ }
2067
+ const messageRole = messageID ? state.messageRoles.get(messageID) : undefined;
2068
+ const knownPartType = partID ? state.partTypes.get(partID) : undefined;
2069
+ const isReasoning = knownPartType === "reasoning" || field === "reasoning";
2070
+ if (messageID && state.compactionSummaryMessageIds.has(messageID)) {
2071
+ return;
2072
+ }
2073
+ if (isReasoning) {
2074
+ if (!appendOpenCodeMaterializedDelta(state, partID, messageID, delta))
2075
+ return;
2076
+ events.push({
2077
+ type: "timeline",
2078
+ provider: "opencode",
2079
+ item: { type: "reasoning", text: delta },
2080
+ });
2081
+ return;
2082
+ }
2083
+ if (field !== "text") {
2084
+ return;
2085
+ }
2086
+ if (messageRole === "user") {
2087
+ return;
2088
+ }
2089
+ const assistantMessageId = messageID || partID;
2090
+ if (!assistantMessageId) {
2091
+ return;
2092
+ }
2093
+ if (state.suppressAssistantMessagesUntilIdle?.active === true) {
2094
+ state.compactionSummaryMessageIds.add(assistantMessageId);
2095
+ return;
2096
+ }
2097
+ if (!appendOpenCodeMaterializedDelta(state, partID, assistantMessageId, delta))
2098
+ return;
2099
+ events.push({
2100
+ type: "timeline",
2101
+ provider: "opencode",
2102
+ item: {
2103
+ type: "assistant_message",
2104
+ text: delta,
2105
+ messageId: assistantMessageId,
2106
+ },
2107
+ });
2108
+ }
2109
+ function appendOpenCodeMaterializedDelta(state, partId, messageId, delta) {
2110
+ if (!partId)
2111
+ return true;
2112
+ const previous = state.materializedParts.get(partId);
2113
+ if (previous?.closed)
2114
+ return false;
2115
+ state.materializedParts.set(partId, {
2116
+ messageId,
2117
+ emittedText: `${previous?.emittedText ?? ""}${delta}`,
2118
+ closed: false,
2119
+ });
2120
+ return true;
2121
+ }
2122
+ function appendOpenCodePermissionAsked(event, state, events) {
2123
+ if (!isOpenCodeSessionTrackedByParent(event.properties.sessionID, state)) {
2124
+ return;
2125
+ }
2126
+ const metadata = readOpenCodeRecord(event.properties.metadata);
2127
+ const tool = readOpenCodeRecord(event.properties.tool);
2128
+ const patterns = Array.isArray(event.properties.patterns)
2129
+ ? event.properties.patterns.filter((value) => typeof value === "string")
2130
+ : [];
2131
+ const command = readPermissionField(metadata, PERMISSION_COMMAND_KEYS);
2132
+ const cwd = readPermissionField(metadata, PERMISSION_CWD_KEYS);
2133
+ const reason = readPermissionField(metadata, PERMISSION_REASON_KEYS);
2134
+ const input = buildOpenCodePermissionInput({ patterns, metadata, tool, command });
2135
+ const detail = buildOpenCodePermissionDetail({
2136
+ permission: event.properties.permission,
2137
+ input,
2138
+ command,
2139
+ cwd,
2140
+ });
2141
+ const description = buildOpenCodePermissionDescription({ reason, patterns });
2142
+ events.push({
2143
+ type: "permission_requested",
2144
+ provider: "opencode",
2145
+ request: {
2146
+ id: event.properties.id,
2147
+ provider: "opencode",
2148
+ name: event.properties.permission,
2149
+ kind: "tool",
2150
+ title: toHumanReadablePermissionTitle(event.properties.permission),
2151
+ ...(description ? { description } : {}),
2152
+ input,
2153
+ detail,
2154
+ actions: buildOpenCodePermissionActions(),
2155
+ },
2156
+ });
2157
+ }
2158
+ function appendOpenCodeQuestionAsked(event, state, events) {
2159
+ if (event.properties.sessionID !== state.sessionId) {
2160
+ return;
2161
+ }
2162
+ const questions = event.properties.questions.flatMap((q) => {
2163
+ if (!q.question || !q.header) {
2164
+ return [];
2165
+ }
2166
+ const options = q.options?.map((o) => ({
2167
+ label: o.label,
2168
+ ...(o.description ? { description: o.description } : {}),
2169
+ })) ?? [];
2170
+ return [
2171
+ {
2172
+ question: q.question,
2173
+ header: q.header,
2174
+ options,
2175
+ ...(q.multiple === true ? { multiSelect: true } : {}),
2176
+ allowOther: true,
2177
+ },
2178
+ ];
2179
+ });
2180
+ if (questions.length === 0) {
2181
+ return;
2182
+ }
2183
+ events.push({
2184
+ type: "permission_requested",
2185
+ provider: "opencode",
2186
+ request: {
2187
+ id: event.properties.id,
2188
+ provider: "opencode",
2189
+ name: "question",
2190
+ kind: "question",
2191
+ title: "Question",
2192
+ input: { questions },
2193
+ metadata: {
2194
+ source: "opencode_question",
2195
+ ...event.properties.tool,
2196
+ },
2197
+ },
2198
+ });
2199
+ }
2200
+ function appendOpenCodeSessionError(event, state, events) {
2201
+ if (event.properties.sessionID !== state.sessionId) {
2202
+ return;
2203
+ }
2204
+ resetOpenCodeTurnTrackingState(state);
2205
+ const error = event.properties.error;
2206
+ if (typeof error === "object" &&
2207
+ error !== null &&
2208
+ "name" in error &&
2209
+ error.name === "MessageAbortedError") {
2210
+ events.push({
2211
+ type: "turn_canceled",
2212
+ provider: "opencode",
2213
+ reason: "interrupted",
2214
+ });
2215
+ }
2216
+ else {
2217
+ events.push({
2218
+ type: "turn_failed",
2219
+ provider: "opencode",
2220
+ error: toDiagnosticErrorMessage(error),
2221
+ });
2222
+ }
2223
+ }
2224
+ function appendOpenCodeSessionStatus(event, state, events) {
2225
+ if (event.properties.sessionID !== state.sessionId) {
2226
+ return;
2227
+ }
2228
+ const { status } = event.properties;
2229
+ if (status.type === "idle") {
2230
+ resetOpenCodeTurnTrackingState(state);
2231
+ events.push({ type: "turn_completed", provider: "opencode", usage: undefined });
2232
+ return;
2233
+ }
2234
+ if (status.type === "retry") {
2235
+ // Mirror what opencode's TUI shows: retry attempts are visible activity, not
2236
+ // terminal. opencode itself never gives up — it backs off and tries again
2237
+ // forever. If we silently swallow these the user sees a spinner with no
2238
+ // explanation. Forwarding as a timeline error item is a no-op for old
2239
+ // clients (the schema already supports it).
2240
+ const message = typeof status.message === "string" ? status.message.trim() : "";
2241
+ const text = message
2242
+ ? `Provider retry (attempt ${status.attempt}): ${message}`
2243
+ : `Provider retry (attempt ${status.attempt})`;
2244
+ events.push({
2245
+ type: "timeline",
2246
+ provider: "opencode",
2247
+ item: { type: "error", message: text },
2248
+ });
2249
+ return;
2250
+ }
2251
+ }
2252
+ function createDeferred() {
2253
+ let resolve;
2254
+ let reject;
2255
+ const promise = new Promise((res, rej) => {
2256
+ resolve = res;
2257
+ reject = rej;
2258
+ });
2259
+ return { promise, resolve, reject };
2260
+ }
2261
+ function unwrapOpenCodeGlobalEvent(event) {
2262
+ const record = readOpenCodeRecord(event);
2263
+ if (!record) {
2264
+ return null;
2265
+ }
2266
+ const payload = readOpenCodeRecord(record.payload);
2267
+ if (typeof payload?.type === "string") {
2268
+ return payload;
2269
+ }
2270
+ if (typeof record.type === "string") {
2271
+ return record;
2272
+ }
2273
+ return null;
2274
+ }
2275
+ function getOpenCodeEventSessionId(event) {
2276
+ const properties = readOpenCodeRecord(event.properties);
2277
+ const info = readOpenCodeRecord(properties?.info);
2278
+ const part = readOpenCodeRecord(properties?.part);
2279
+ return (readNonEmptyString(properties?.sessionID) ??
2280
+ readNonEmptyString(properties?.sessionId) ??
2281
+ readNonEmptyString(info?.sessionID) ??
2282
+ readNonEmptyString(info?.sessionId) ??
2283
+ readNonEmptyString(part?.sessionID) ??
2284
+ readNonEmptyString(part?.sessionId) ??
2285
+ (event.type === "session.created" || event.type === "session.updated"
2286
+ ? readNonEmptyString(info?.id)
2287
+ : null));
2288
+ }
2289
+ function getOpenCodeRunnerStatusFromEvent(event, sessionId) {
2290
+ if (getOpenCodeEventSessionId(event) !== sessionId) {
2291
+ return null;
2292
+ }
2293
+ if (event.type === "session.status") {
2294
+ return event.properties.status.type;
2295
+ }
2296
+ if (event.type === "session.idle" || event.type === "session.error") {
2297
+ return "idle";
2298
+ }
2299
+ return null;
2300
+ }
2301
+ function isOpenCodeRunnerActive(status) {
2302
+ return status === "busy" || status === "retry";
2303
+ }
2304
+ function isOpenCodeTerminalEvent(event, sessionId) {
2305
+ return getOpenCodeRunnerStatusFromEvent(event, sessionId) === "idle";
2306
+ }
2307
+ function isOpenCodeProviderInternalEvent(event) {
2308
+ return event.type === "provider_subagent";
2309
+ }
2310
+ function readOpenCodeChildSessionInfo(value) {
2311
+ const record = readOpenCodeRecord(value);
2312
+ if (!record) {
2313
+ return null;
2314
+ }
2315
+ const id = readNonEmptyString(record.id);
2316
+ const parentSessionId = readNonEmptyString(record.parentID) ?? readNonEmptyString(record.parentId);
2317
+ if (!id || !parentSessionId) {
2318
+ return null;
2319
+ }
2320
+ const title = readNonEmptyString(record.title);
2321
+ const directory = readNonEmptyString(record.directory);
2322
+ const revert = readOpenCodeRecord(record.revert);
2323
+ const agent = readNonEmptyString(record.agent);
2324
+ const model = readOpenCodeChildSessionModel(record.model);
2325
+ return {
2326
+ id,
2327
+ parentSessionId,
2328
+ ...(title ? { title } : {}),
2329
+ ...(directory ? { directory } : {}),
2330
+ ...(revert ? { revert } : {}),
2331
+ ...(agent ? { agent } : {}),
2332
+ ...(model ? { model } : {}),
2333
+ };
2334
+ }
2335
+ function readOpenCodeChildSessionModel(value) {
2336
+ const record = readOpenCodeRecord(value);
2337
+ const id = readNonEmptyString(record?.id);
2338
+ if (!record || !id) {
2339
+ return null;
2340
+ }
2341
+ const variant = readNonEmptyString(record.variant);
2342
+ return {
2343
+ id,
2344
+ ...(variant ? { variant } : {}),
2345
+ };
2346
+ }
2347
+ function readOpenCodeChildSessionInfosFromResponse(response) {
2348
+ const record = readOpenCodeRecord(response);
2349
+ if (!record || record.error) {
2350
+ return null;
2351
+ }
2352
+ const data = record.data;
2353
+ if (!Array.isArray(data)) {
2354
+ return null;
2355
+ }
2356
+ return data.flatMap((item) => {
2357
+ const child = readOpenCodeChildSessionInfo(item);
2358
+ return child ? [child] : [];
2359
+ });
2360
+ }
2361
+ async function listOpenCodeChildSessions(client, sessionId, directory, signal) {
2362
+ const sessionIdResponse = await client.session.children({ sessionID: sessionId, directory }, { signal });
2363
+ return readOpenCodeChildSessionInfosFromResponse(sessionIdResponse) ?? [];
2364
+ }
2365
+ class OpenCodeAgentSession {
2366
+ constructor(config, client, sessionId, logger, modelContextWindowsByModelKey = new Map(), events = EMPTY_OPENCODE_EVENT_SOURCE, releaseServer, persistSession = true, agentId, serverUrl, externallyDriven = false, releaseBridge) {
2367
+ this.events = events;
2368
+ this.agentId = agentId;
2369
+ this.serverUrl = serverUrl;
2370
+ this.externallyDriven = externallyDriven;
2371
+ this.provider = "opencode";
2372
+ this.capabilities = OPENCODE_CAPABILITIES;
2373
+ this.currentMode = null;
2374
+ this.autoAcceptEnabled = false;
2375
+ this.pendingPermissions = new Map();
2376
+ this.abortController = null;
2377
+ this.accumulatedUsage = {};
2378
+ this.mcpConfigured = false;
2379
+ this.mcpSetupPromise = null;
2380
+ this.messageRoles = new Map();
2381
+ this.pendingUserMessageText = null;
2382
+ this.pendingClientMessageId = null;
2383
+ this.pendingSteerSubmissions = [];
2384
+ this.emittedUserMessageIds = new Set();
2385
+ this.materializedParts = new Map();
2386
+ this.activeDispatchMessageId = null;
2387
+ this.emittedStructuredMessageIds = new Set();
2388
+ this.compactionSummaryMessageIds = new Set();
2389
+ this.emittedCompactionPartIds = new Set();
2390
+ this.suppressAssistantMessagesUntilIdle = { active: false };
2391
+ this.partTypes = new Map();
2392
+ this.availableModesCache = null;
2393
+ this.subscribers = new Set();
2394
+ this.nextTurnOrdinal = 0;
2395
+ this.turnState = { status: "idle" };
2396
+ /**
2397
+ * Settlement of every session-scoped abort issued so far. It outlives the stop
2398
+ * that issued it because a request still in flight can cancel a replacement
2399
+ * run, and a rejection means we never proved the runner stopped.
2400
+ */
2401
+ this.abortSettlement = Promise.resolve();
2402
+ this.externalStatusReconciliationStarted = false;
2403
+ this.runnerStatusRevision = 0;
2404
+ this.runningToolCalls = new Map();
2405
+ this.subAgentsByCallId = new Map();
2406
+ this.subAgentCallIdByChildSessionId = new Map();
2407
+ this.knownChildSessionIds = new Set();
2408
+ this.sideQuestionSessionIds = new Set();
2409
+ this.subagentPresentationByChildId = new Map();
2410
+ this.childTranslationStates = new Map();
2411
+ this.childSessionCwds = new Map();
2412
+ this.childStatuses = new Map();
2413
+ this.pendingPermissionDirectories = new Map();
2414
+ this.childHydrationPromise = null;
2415
+ this.childHydrationCompleted = false;
2416
+ this.unrelatedSessionIds = new Set();
2417
+ this.ingress = Promise.resolve();
2418
+ this.gapRepairRevision = 0;
2419
+ this.recoveryAbortController = new AbortController();
2420
+ this.unsubscribeEvents = null;
2421
+ this.closed = false;
2422
+ this.deletedFromProvider = false;
2423
+ this.config = config;
2424
+ this.client = client;
2425
+ this.sessionId = sessionId;
2426
+ this.logger = logger.child({ agentId: this.agentId });
2427
+ this.modelContextWindowsByModelKey = modelContextWindowsByModelKey;
2428
+ this.currentMode = normalizeOpenCodeModeId(config.modeId);
2429
+ this.autoAcceptEnabled = !config.toolPolicy && isOpenCodeAutoAcceptEnabled(config);
2430
+ this.releaseServer = releaseServer ?? null;
2431
+ this.releaseBridge = releaseBridge ?? null;
2432
+ this.persistSession = persistSession;
2433
+ this.selectedModelContextWindowMaxTokens = this.resolveConfiguredModelContextWindowMaxTokens(config.model);
2434
+ this.unsubscribeEvents = this.events.subscribe((input) => {
2435
+ if ("type" in input && input.type === "server-exited")
2436
+ this.recoveryAbortController.abort(input.error);
2437
+ this.ingress = this.ingress
2438
+ .then(() => this.consumeEventSourceInput(input))
2439
+ .catch((error) => {
2440
+ this.logger.warn({ err: error, sessionId: this.sessionId }, "OpenCode event ingress failed");
2441
+ });
2442
+ });
2443
+ }
2444
+ get id() {
2445
+ return this.sessionId;
2446
+ }
2447
+ get activeForegroundTurnId() {
2448
+ return this.turnState.status === "running" ? this.turnState.turnId : null;
2449
+ }
2450
+ get features() {
2451
+ return [buildOpenCodeAutoAcceptFeature(this.config)];
2452
+ }
2453
+ async getRuntimeInfo() {
2454
+ return {
2455
+ provider: "opencode",
2456
+ sessionId: this.sessionId,
2457
+ model: this.config.model ?? null,
2458
+ modeId: this.currentMode,
2459
+ };
2460
+ }
2461
+ async setModel(modelId) {
2462
+ const normalizedModelId = typeof modelId === "string" && modelId.trim().length > 0 ? modelId : null;
2463
+ this.config.model = normalizedModelId ?? undefined;
2464
+ this.selectedModelContextWindowMaxTokens = this.resolveConfiguredModelContextWindowMaxTokens(this.config.model);
2465
+ }
2466
+ async setThinkingOption(thinkingOptionId) {
2467
+ const normalizedThinkingOptionId = normalizeOpenCodeVariantId(thinkingOptionId);
2468
+ this.config.thinkingOptionId = normalizedThinkingOptionId ?? undefined;
2469
+ }
2470
+ async run(prompt, options) {
2471
+ return runProviderTurn({
2472
+ prompt,
2473
+ runOptions: options,
2474
+ startTurn: (p, o) => this.startTurn(p, o),
2475
+ subscribe: (callback) => this.subscribe(callback),
2476
+ getSessionId: () => this.sessionId,
2477
+ });
2478
+ }
2479
+ async interrupt() {
2480
+ const turnId = this.activeForegroundTurnId;
2481
+ this.abortController?.abort();
2482
+ const abort = this.issueStop(turnId);
2483
+ // COMPAT(opencodeSlowAbort): OpenCode 1.14.42+ blocks session.abort until
2484
+ // the running tool actually stops, which can be tens of seconds for
2485
+ // long-running tools. Cap the wait so the user-visible cancel lands
2486
+ // quickly while still giving OpenCode a chance to confirm the abort
2487
+ // cleanly. Drop the timeout once upstream returns abort acknowledgement
2488
+ // before tool teardown.
2489
+ const settledAbort = abort.then(() => undefined, (error) => error);
2490
+ // Only the cap is tolerated. A settled failure means the runner may still be
2491
+ // going, and the caller must hear about it.
2492
+ const abortFailure = await withTimeout(settledAbort, 2000, "OpenCode session.abort").catch((error) => {
2493
+ this.logger.warn({ err: error, sessionId: this.sessionId, turnId }, "OpenCode session.abort did not settle within the cancel cap");
2494
+ return undefined;
2495
+ });
2496
+ if (abortFailure !== undefined) {
2497
+ throw abortFailure;
2498
+ }
2499
+ }
2500
+ async steerActiveTurn(prompt, options) {
2501
+ if (this.closed || this.activeForegroundTurnId !== options.expectedTurnId) {
2502
+ return { status: "unavailable" };
2503
+ }
2504
+ if (await this.resolveSlashCommandInvocation(prompt)) {
2505
+ return { status: "unavailable" };
2506
+ }
2507
+ if (this.activeForegroundTurnId !== options.expectedTurnId) {
2508
+ return { status: "unavailable" };
2509
+ }
2510
+ const promptId = createOpenCodeMessageId();
2511
+ const pending = {
2512
+ providerMessageId: promptId,
2513
+ text: buildOpenCodeUserTimelineText(prompt),
2514
+ clientMessageId: options.clientMessageId ?? null,
2515
+ };
2516
+ this.pendingSteerSubmissions.push(pending);
2517
+ const parts = buildOpenCodePromptParts(prompt);
2518
+ const systemPrompt = composeSystemPromptParts(this.config.systemPrompt, this.config.daemonAppendSystemPrompt);
2519
+ const permission = buildOpenCodePermissionRules(this.config.providerOptions, this.config.toolPolicy);
2520
+ const model = this.parseModel(this.config.model);
2521
+ const effectiveMode = resolveOpenCodeRuntimeAgentId(this.currentMode);
2522
+ const effectiveVariant = this.config.thinkingOptionId ?? undefined;
2523
+ try {
2524
+ const response = await this.client.session.promptAsync({
2525
+ sessionID: this.sessionId,
2526
+ directory: this.config.cwd,
2527
+ messageID: promptId,
2528
+ parts,
2529
+ ...(systemPrompt ? { system: systemPrompt } : {}),
2530
+ ...(permission ? { permission } : {}),
2531
+ ...(model ? { model } : {}),
2532
+ ...(effectiveMode ? { agent: effectiveMode } : {}),
2533
+ ...(effectiveVariant ? { variant: effectiveVariant } : {}),
2534
+ });
2535
+ if (response.error) {
2536
+ if (isOpenCodeDefinitiveSteerRejection(response.error, response.response?.status)) {
2537
+ this.removePendingSteerSubmission(promptId);
2538
+ return { status: "unavailable" };
2539
+ }
2540
+ throw new Error(`OpenCode steer request failed: ${toDiagnosticErrorMessage(response.error)}`);
2541
+ }
2542
+ if (options.clearPendingPermissions) {
2543
+ await this.clearPendingPermissionsForSteer();
2544
+ }
2545
+ return { status: "accepted" };
2546
+ }
2547
+ catch (error) {
2548
+ if (isOpenCodeDefinitiveSteerRejection(error)) {
2549
+ this.removePendingSteerSubmission(promptId);
2550
+ return { status: "unavailable" };
2551
+ }
2552
+ throw error;
2553
+ }
2554
+ }
2555
+ async askSideQuestion(question, history, options) {
2556
+ if (this.closed)
2557
+ return { status: "unavailable", reason: "session_closed" };
2558
+ try {
2559
+ return await askOpenCodeSideQuestion({
2560
+ client: this.client,
2561
+ parentSessionId: this.sessionId,
2562
+ cwd: this.config.cwd,
2563
+ question,
2564
+ history,
2565
+ messageId: createOpenCodeMessageId(),
2566
+ logger: this.logger,
2567
+ signal: options?.signal,
2568
+ onForkCreated: (forkSessionId) => this.registerSideQuestionFork(forkSessionId),
2569
+ onForkReleased: (forkSessionId) => this.sideQuestionSessionIds.delete(forkSessionId),
2570
+ model: this.parseModel(this.config.model),
2571
+ agent: resolveOpenCodeRuntimeAgentId(this.currentMode) ?? undefined,
2572
+ variant: this.config.thinkingOptionId,
2573
+ });
2574
+ }
2575
+ catch (error) {
2576
+ return {
2577
+ status: "failed",
2578
+ error: toDiagnosticErrorMessage(error),
2579
+ threading: "threaded",
2580
+ };
2581
+ }
2582
+ }
2583
+ removePendingSteerSubmission(providerMessageId) {
2584
+ const index = this.pendingSteerSubmissions.findIndex((submission) => submission.providerMessageId === providerMessageId);
2585
+ if (index >= 0) {
2586
+ this.pendingSteerSubmissions.splice(index, 1);
2587
+ }
2588
+ }
2589
+ async clearPendingPermissionsForSteer() {
2590
+ const requestIds = Array.from(this.pendingPermissions.keys());
2591
+ for (const requestId of requestIds) {
2592
+ if (!this.pendingPermissions.has(requestId))
2593
+ continue;
2594
+ await this.respondToPermission(requestId, {
2595
+ behavior: "deny",
2596
+ message: "The user answered with a message instead of approving. Their message follows.",
2597
+ });
2598
+ }
2599
+ }
2600
+ async revertBoth(input) {
2601
+ await revertOpenCodeConversationAndFiles({
2602
+ client: this.client,
2603
+ sessionId: this.sessionId,
2604
+ cwd: this.config.cwd,
2605
+ messageId: input.messageId,
2606
+ });
2607
+ }
2608
+ abortSession(turnId, reason) {
2609
+ return this.client.session
2610
+ .abort({
2611
+ sessionID: this.sessionId,
2612
+ directory: this.config.cwd,
2613
+ })
2614
+ .then((response) => {
2615
+ if (response.error) {
2616
+ throw new Error(toDiagnosticErrorMessage(response.error));
2617
+ }
2618
+ return undefined;
2619
+ })
2620
+ .catch((error) => {
2621
+ this.logger.warn({ err: error, sessionId: this.sessionId, turnId, reason }, "OpenCode session.abort rejected");
2622
+ throw error;
2623
+ });
2624
+ }
2625
+ /**
2626
+ * Gate every runner-affecting operation on the previous stop. OpenCode runs one
2627
+ * runner per session and aborts it session-wide, so a replacement may start
2628
+ * only once the canceled run published its terminal and our own abort settled.
2629
+ * A failed abort never proved the runner stopped, so it fails closed until the
2630
+ * next Stop issues a fresh one.
2631
+ */
2632
+ async awaitRunnerQuiescence() {
2633
+ const providerIdle = this.waitUntilProviderIdle();
2634
+ // A failed abort is decisive on its own, so let it reject this wait without
2635
+ // leaving the still-running observation unhandled.
2636
+ void providerIdle.catch(() => undefined);
2637
+ let observed = this.abortSettlement;
2638
+ await Promise.all([observed, providerIdle]);
2639
+ // Stop can issue a further abort while we waited, and the settlement is
2640
+ // replaced rather than mutated, so drain until what we observed is current.
2641
+ while (this.abortSettlement !== observed) {
2642
+ observed = this.abortSettlement;
2643
+ await observed;
2644
+ }
2645
+ }
2646
+ async waitUntilProviderIdle() {
2647
+ if (this.turnState.status !== "stopping")
2648
+ return;
2649
+ await withTimeout(this.observeProviderStopBoundary(this.turnState.stop), OPENCODE_PENDING_ABORT_START_TIMEOUT_MS, "OpenCode previous turn to stop");
2650
+ }
2651
+ async observeProviderStopBoundary(stop) {
2652
+ let delayMs = 100;
2653
+ while (this.isStopping(stop)) {
2654
+ const boundary = await Promise.race([
2655
+ stop.terminal.promise.then(() => "terminal"),
2656
+ waitForOpenCodeStopProbe(delayMs, this.recoveryAbortController.signal).then(() => "probe"),
2657
+ ]);
2658
+ if (boundary === "terminal")
2659
+ return;
2660
+ await this.reconcileStopWithProviderStatus(stop);
2661
+ delayMs = Math.min(delayMs * 2, OPENCODE_STOP_STATUS_MAX_DELAY_MS);
2662
+ }
2663
+ }
2664
+ async reconcileStopWithProviderStatus(stop) {
2665
+ try {
2666
+ if ((await this.readProviderRunnerStatus()) === "idle") {
2667
+ this.finishStoppingTurn(stop);
2668
+ }
2669
+ }
2670
+ catch (error) {
2671
+ this.logger.warn({ err: error, sessionId: this.sessionId, turnId: stop.pendingCancellationTurnId }, "Failed to reconcile the OpenCode stop with provider session status");
2672
+ }
2673
+ }
2674
+ async readProviderRunnerStatus() {
2675
+ const response = await this.client.session.status({ directory: this.config.cwd }, { signal: this.recoveryAbortController.signal });
2676
+ if (response.error) {
2677
+ throw new Error(`Failed to confirm OpenCode session status: ${toDiagnosticErrorMessage(response.error)}`);
2678
+ }
2679
+ const statuses = readOpenCodeRecord(response.data);
2680
+ if (!statuses) {
2681
+ throw new Error("OpenCode returned an invalid session status response");
2682
+ }
2683
+ const status = readOpenCodeRecord(statuses[this.sessionId]);
2684
+ // OpenCode drops idle sessions from the status map entirely.
2685
+ if (!status) {
2686
+ return "idle";
2687
+ }
2688
+ const statusType = readNonEmptyString(status.type);
2689
+ if (statusType !== "idle" && statusType !== "busy" && statusType !== "retry") {
2690
+ throw new Error(`OpenCode returned an unknown session status '${statusType ?? "missing"}'`);
2691
+ }
2692
+ return statusType;
2693
+ }
2694
+ async startTurn(prompt, options) {
2695
+ if (this.closed) {
2696
+ throw new Error("OpenCode session is closed");
2697
+ }
2698
+ if (this.turnState.status === "running") {
2699
+ throw new Error("A foreground turn is already active");
2700
+ }
2701
+ try {
2702
+ await this.awaitRunnerQuiescence();
2703
+ }
2704
+ catch (error) {
2705
+ this.rethrowRunnerWaitError(error);
2706
+ }
2707
+ if (this.closed) {
2708
+ throw new Error("OpenCode session is closed");
2709
+ }
2710
+ if (this.turnState.status !== "idle") {
2711
+ throw new Error("OpenCode is still stopping the previous turn");
2712
+ }
2713
+ this.runningToolCalls.clear();
2714
+ this.subAgentsByCallId.clear();
2715
+ this.subAgentCallIdByChildSessionId.clear();
2716
+ const turnAbortController = new AbortController();
2717
+ this.abortController = turnAbortController;
2718
+ await this.ensureMcpServersConfigured();
2719
+ const contextWindowMaxTokens = this.resolveSelectedModelContextWindowMaxTokens();
2720
+ this.accumulatedUsage = contextWindowMaxTokens !== undefined ? { contextWindowMaxTokens } : {};
2721
+ const parts = buildOpenCodePromptParts(prompt);
2722
+ this.pendingUserMessageText = buildOpenCodeUserTimelineText(prompt);
2723
+ this.pendingClientMessageId = options?.clientMessageId ?? null;
2724
+ this.suppressAssistantMessagesUntilIdle.active = false;
2725
+ const model = this.parseModel(this.config.model);
2726
+ const thinkingOptionId = this.config.thinkingOptionId;
2727
+ const effectiveVariant = thinkingOptionId ?? undefined;
2728
+ const effectiveMode = resolveOpenCodeRuntimeAgentId(this.currentMode);
2729
+ await this.awaitEventStreamReady(turnAbortController);
2730
+ const turnId = this.createTurnId();
2731
+ this.materializedParts.clear();
2732
+ this.turnState = { status: "running", turnId };
2733
+ this.notifySubscribers({ type: "turn_started", provider: "opencode" }, turnId);
2734
+ const slashCommand = await this.resolveSlashCommandInvocation(prompt);
2735
+ if (slashCommand) {
2736
+ if (slashCommand.commandName === "compact" || slashCommand.commandName === "summarize") {
2737
+ this.activeDispatchMessageId = null;
2738
+ this.suppressAssistantMessagesUntilIdle.active = true;
2739
+ void this.client.session
2740
+ .summarize({
2741
+ sessionID: this.sessionId,
2742
+ directory: this.config.cwd,
2743
+ ...(model ? { providerID: model.providerID, modelID: model.modelID } : {}),
2744
+ })
2745
+ .then((response) => {
2746
+ if (response.error) {
2747
+ this.suppressAssistantMessagesUntilIdle.active = false;
2748
+ this.finishForegroundTurn({
2749
+ type: "turn_failed",
2750
+ provider: "opencode",
2751
+ error: toDiagnosticErrorMessage(response.error),
2752
+ }, turnId);
2753
+ }
2754
+ return;
2755
+ })
2756
+ .catch((error) => {
2757
+ this.suppressAssistantMessagesUntilIdle.active = false;
2758
+ this.finishForegroundTurn({
2759
+ type: "turn_failed",
2760
+ provider: "opencode",
2761
+ error: toDiagnosticErrorMessage(error),
2762
+ }, turnId);
2763
+ });
2764
+ return { turnId };
2765
+ }
2766
+ // command() is only dispatch acknowledgement. OpenCode session events are
2767
+ // the source of truth for when the command turn becomes idle or fails.
2768
+ this.activeDispatchMessageId = createOpenCodeMessageId();
2769
+ void this.client.session
2770
+ .command({
2771
+ sessionID: this.sessionId,
2772
+ directory: this.config.cwd,
2773
+ command: slashCommand.commandName,
2774
+ arguments: slashCommand.args ?? "",
2775
+ messageID: this.activeDispatchMessageId,
2776
+ ...(this.config.model ? { model: this.config.model } : {}),
2777
+ ...(effectiveMode ? { agent: effectiveMode } : {}),
2778
+ ...(effectiveVariant ? { variant: effectiveVariant } : {}),
2779
+ })
2780
+ .then((response) => {
2781
+ if (response.error) {
2782
+ if (isOpenCodeHeadersTimeoutFailure(response.error)) {
2783
+ this.logger.warn({
2784
+ err: response.error,
2785
+ commandName: slashCommand.commandName,
2786
+ turnId,
2787
+ }, "OpenCode slash command hit a header timeout; waiting for SSE terminal event");
2788
+ return;
2789
+ }
2790
+ const errorMsg = toDiagnosticErrorMessage(response.error);
2791
+ this.finishForegroundTurn({ type: "turn_failed", provider: "opencode", error: errorMsg }, turnId);
2792
+ }
2793
+ return;
2794
+ })
2795
+ .catch((err) => {
2796
+ if (isOpenCodeHeadersTimeoutFailure(err)) {
2797
+ this.logger.warn({
2798
+ err,
2799
+ commandName: slashCommand.commandName,
2800
+ turnId,
2801
+ }, "OpenCode slash command hit a header timeout; waiting for SSE terminal event");
2802
+ return;
2803
+ }
2804
+ this.finishForegroundTurn({ type: "turn_failed", provider: "opencode", error: toDiagnosticErrorMessage(err) }, turnId);
2805
+ });
2806
+ }
2807
+ else {
2808
+ const dispatchMessageId = createOpenCodeMessageId();
2809
+ this.activeDispatchMessageId = dispatchMessageId;
2810
+ // Wrap in an async IIFE so a synchronous throw from promptAsync (e.g.
2811
+ // SDK input validation) is caught alongside async rejections. A plain
2812
+ // `.then().catch()` chain would let a sync throw escape unhandled.
2813
+ void (async () => {
2814
+ this.traceOpenCode("provider.opencode.prompt_async.start", {
2815
+ turnId,
2816
+ sessionId: this.sessionId,
2817
+ model,
2818
+ effectiveMode,
2819
+ effectiveVariant,
2820
+ partTypes: parts.map((p) => p.type),
2821
+ });
2822
+ try {
2823
+ const systemPrompt = composeSystemPromptParts(this.config.systemPrompt, this.config.daemonAppendSystemPrompt);
2824
+ const permission = buildOpenCodePermissionRules(this.config.providerOptions, this.config.toolPolicy);
2825
+ const promptResponse = await this.client.session.promptAsync({
2826
+ sessionID: this.sessionId,
2827
+ directory: this.config.cwd,
2828
+ messageID: dispatchMessageId,
2829
+ parts,
2830
+ ...(options?.outputSchema
2831
+ ? {
2832
+ format: {
2833
+ type: "json_schema",
2834
+ schema: options.outputSchema,
2835
+ },
2836
+ }
2837
+ : {}),
2838
+ ...(systemPrompt ? { system: systemPrompt } : {}),
2839
+ ...(permission ? { permission } : {}),
2840
+ ...(model ? { model } : {}),
2841
+ ...(effectiveMode ? { agent: effectiveMode } : {}),
2842
+ ...(effectiveVariant ? { variant: effectiveVariant } : {}),
2843
+ });
2844
+ this.traceOpenCode("provider.opencode.prompt_async.response", {
2845
+ turnId,
2846
+ hasError: promptResponse.error !== undefined,
2847
+ error: promptResponse.error,
2848
+ data: promptResponse.data,
2849
+ });
2850
+ if (promptResponse.error) {
2851
+ this.finishForegroundTurn({
2852
+ type: "turn_failed",
2853
+ provider: "opencode",
2854
+ error: toDiagnosticErrorMessage(promptResponse.error),
2855
+ }, turnId);
2856
+ }
2857
+ }
2858
+ catch (error) {
2859
+ this.traceOpenCode("provider.opencode.prompt_async.throw", {
2860
+ turnId,
2861
+ error: error instanceof Error
2862
+ ? { name: error.name, message: error.message, stack: error.stack }
2863
+ : String(error),
2864
+ });
2865
+ this.finishForegroundTurn({
2866
+ type: "turn_failed",
2867
+ provider: "opencode",
2868
+ error: toDiagnosticErrorMessage(error),
2869
+ }, turnId);
2870
+ }
2871
+ })();
2872
+ }
2873
+ return { turnId };
2874
+ }
2875
+ async awaitEventStreamReady(turnAbortController) {
2876
+ try {
2877
+ await withTimeout(this.events.ready(), OPENCODE_EVENT_STREAM_READY_TIMEOUT_MS, "OpenCode server.connected event");
2878
+ }
2879
+ catch (error) {
2880
+ if (this.abortController === turnAbortController)
2881
+ this.abortController = null;
2882
+ if (!(error instanceof Error) || error.message !== "OpenCode server.connected event") {
2883
+ throw error;
2884
+ }
2885
+ const diagnostics = this.events.diagnostics?.();
2886
+ if (!diagnostics)
2887
+ throw error;
2888
+ throw new Error(`${error.message}; your message was not sent. ${formatOpenCodeEventStreamDiagnostics(diagnostics)}`, { cause: error });
2889
+ }
2890
+ }
2891
+ rethrowRunnerWaitError(error) {
2892
+ if (this.closed)
2893
+ throw new Error("OpenCode session is closed", { cause: error });
2894
+ throw error;
2895
+ }
2896
+ subscribe(callback) {
2897
+ this.subscribers.add(callback);
2898
+ this.startExternalStatusReconciliation();
2899
+ this.startChildSessionHydration();
2900
+ return () => {
2901
+ this.subscribers.delete(callback);
2902
+ };
2903
+ }
2904
+ startExternalStatusReconciliation() {
2905
+ if (!this.externallyDriven || this.externalStatusReconciliationStarted || this.closed) {
2906
+ return;
2907
+ }
2908
+ this.externalStatusReconciliationStarted = true;
2909
+ void this.reconcileExternalRunnerStatus().catch((error) => {
2910
+ this.logger.warn({ err: error, sessionId: this.sessionId }, "Failed to reconcile externally driven OpenCode session status");
2911
+ });
2912
+ }
2913
+ async reconcileExternalRunnerStatus() {
2914
+ await this.events.ready();
2915
+ const observedRevision = this.runnerStatusRevision;
2916
+ const runnerStatus = await this.readProviderRunnerStatus();
2917
+ if (this.runnerStatusRevision !== observedRevision ||
2918
+ this.turnState.status !== "idle" ||
2919
+ !isOpenCodeRunnerActive(runnerStatus)) {
2920
+ return;
2921
+ }
2922
+ this.startAutonomousTurn();
2923
+ }
2924
+ startChildSessionHydration() {
2925
+ if (this.childHydrationPromise) {
2926
+ return;
2927
+ }
2928
+ const hydration = this.hydrateChildSessions()
2929
+ .then(() => {
2930
+ this.childHydrationCompleted = true;
2931
+ return undefined;
2932
+ })
2933
+ .finally(() => {
2934
+ if (this.childHydrationPromise === hydration) {
2935
+ this.childHydrationPromise = null;
2936
+ }
2937
+ });
2938
+ this.childHydrationPromise = hydration;
2939
+ void hydration.catch((error) => {
2940
+ this.logger.warn({ err: error, sessionId: this.sessionId }, "OpenCode child hydration failed");
2941
+ });
2942
+ }
2943
+ async hydrateChildSessions(recovered = false) {
2944
+ const discovered = await this.discoverChildSessions();
2945
+ const statusesByDirectory = await this.readChildStatuses(discovered);
2946
+ for (const child of discovered) {
2947
+ await this.hydrateDiscoveredChild(child, statusesByDirectory, recovered);
2948
+ }
2949
+ }
2950
+ async discoverChildSessions() {
2951
+ const queue = [{ id: this.sessionId, directory: this.config.cwd }];
2952
+ const visited = new Set();
2953
+ const discovered = [];
2954
+ while (queue.length > 0 && visited.size < OPENCODE_CHILD_SESSION_HYDRATION_LIMIT) {
2955
+ const parent = queue.shift();
2956
+ if (!parent || visited.has(parent.id)) {
2957
+ continue;
2958
+ }
2959
+ visited.add(parent.id);
2960
+ const children = await listOpenCodeChildSessions(this.client, parent.id, parent.directory, this.recoveryAbortController.signal);
2961
+ if (this.closed)
2962
+ return discovered;
2963
+ for (const child of children) {
2964
+ discovered.push(child);
2965
+ if (visited.size + queue.length < OPENCODE_CHILD_SESSION_HYDRATION_LIMIT) {
2966
+ queue.push({ id: child.id, directory: child.directory ?? parent.directory });
2967
+ }
2968
+ }
2969
+ }
2970
+ return discovered;
2971
+ }
2972
+ async readChildStatuses(children) {
2973
+ const statusesByDirectory = new Map();
2974
+ for (const directory of new Set(children.map((child) => child.directory ?? this.config.cwd))) {
2975
+ const response = await this.client.session
2976
+ .status({ directory }, { signal: this.recoveryAbortController.signal })
2977
+ .catch(() => null);
2978
+ const record = readOpenCodeRecord(response);
2979
+ statusesByDirectory.set(directory, record && !record.error ? readOpenCodeRecord(record.data) : null);
2980
+ }
2981
+ return statusesByDirectory;
2982
+ }
2983
+ async hydrateDiscoveredChild(child, statusesByDirectory, recovered) {
2984
+ const directory = child.directory ?? this.config.cwd;
2985
+ const snapshot = statusesByDirectory.get(directory) ?? null;
2986
+ const status = readOpenCodeRecord(snapshot?.[child.id]);
2987
+ const active = snapshot === null || status?.type === "busy" || status?.type === "retry";
2988
+ const detectedStatus = active ? "running" : "completed";
2989
+ const detectionEvents = [];
2990
+ appendOpenCodeChildSessionDetected(child, this.createTranslationState(), detectionEvents, recovered ? null : detectedStatus);
2991
+ for (const event of detectionEvents) {
2992
+ this.recordProviderInternalEvent(event);
2993
+ this.notifySubscribers(event, null);
2994
+ }
2995
+ let messages = null;
2996
+ try {
2997
+ messages = await this.hydrateChildSessionTimeline(child, recovered);
2998
+ }
2999
+ catch (error) {
3000
+ this.logger.warn({ err: error, sessionId: child.id }, "OpenCode child timeline hydration failed");
3001
+ }
3002
+ if (!recovered)
3003
+ return;
3004
+ const latestAssistant = messages?.findLast((message) => message.info.role === "assistant");
3005
+ const recoveredStatus = recoverChildStatus(snapshot !== null, status?.type, latestAssistant);
3006
+ if (!recoveredStatus)
3007
+ return;
3008
+ const statusEvent = {
3009
+ type: "provider_subagent",
3010
+ provider: "opencode",
3011
+ event: { type: "upsert", id: child.id, status: recoveredStatus },
3012
+ };
3013
+ this.recordProviderInternalEvent(statusEvent);
3014
+ this.notifySubscribers(statusEvent, null);
3015
+ }
3016
+ async hydrateChildSessionTimeline(child, recovered = false) {
3017
+ const messages = await readOpenCodeSessionMessagesFromSdk(this.client, {
3018
+ id: child.id,
3019
+ directory: child.directory ?? this.config.cwd,
3020
+ ...(child.revert ? { revert: child.revert } : {}),
3021
+ }, this.recoveryAbortController.signal);
3022
+ if (recovered) {
3023
+ for (const message of messages) {
3024
+ await this.consumeOpenCodeStreamEvent({
3025
+ rawEvent: {
3026
+ directory: child.directory ?? this.config.cwd,
3027
+ payload: { type: "message.updated", properties: { info: message.info } },
3028
+ },
3029
+ eventCount: 0,
3030
+ });
3031
+ for (const part of message.parts) {
3032
+ await this.consumeOpenCodeStreamEvent({
3033
+ rawEvent: {
3034
+ directory: child.directory ?? this.config.cwd,
3035
+ payload: { type: "message.part.updated", properties: { part } },
3036
+ },
3037
+ eventCount: 0,
3038
+ });
3039
+ }
3040
+ }
3041
+ this.emitHydratedChildPresentation(child, messages);
3042
+ return messages;
3043
+ }
3044
+ const translationState = this.getChildTranslationState(child.id);
3045
+ let latestReplayedMessage = null;
3046
+ for (const message of messages) {
3047
+ if (message.info.role === "assistant" && message.info.time?.completed === undefined) {
3048
+ continue;
3049
+ }
3050
+ latestReplayedMessage = message;
3051
+ for (const timelineEvent of buildOpenCodeReplayTimelineEvents(message)) {
3052
+ const event = {
3053
+ type: "provider_subagent",
3054
+ provider: "opencode",
3055
+ event: {
3056
+ type: "timeline",
3057
+ id: child.id,
3058
+ item: timelineEvent.item,
3059
+ ...(timelineEvent.timestamp ? { timestamp: timelineEvent.timestamp } : {}),
3060
+ },
3061
+ };
3062
+ this.recordProviderInternalEvent(event);
3063
+ this.notifySubscribers(event, null);
3064
+ }
3065
+ }
3066
+ if (latestReplayedMessage) {
3067
+ translationState.hydratedMessageFingerprints?.set(latestReplayedMessage.info.id, JSON.stringify(latestReplayedMessage.info));
3068
+ for (const part of latestReplayedMessage.parts) {
3069
+ translationState.hydratedPartFingerprints?.set(part.id, JSON.stringify(part));
3070
+ }
3071
+ }
3072
+ this.emitHydratedChildPresentation(child, messages);
3073
+ return messages;
3074
+ }
3075
+ /**
3076
+ * After replaying a historical child, derive presentation facts from the last assistant
3077
+ * message (the session record's agent/model were already folded at detection) and publish
3078
+ * any missing title plus the updated subtitle once. Presentation-only: no `status`.
3079
+ */
3080
+ emitHydratedChildPresentation(child, messages) {
3081
+ const lastAssistant = messages.findLast((message) => message.info.role === "assistant");
3082
+ if (!lastAssistant) {
3083
+ return;
3084
+ }
3085
+ const facts = readOpenCodeAssistantPresentationFacts(lastAssistant.info);
3086
+ if (!facts) {
3087
+ return;
3088
+ }
3089
+ const presentation = getOpenCodeSubagentPresentationState(child.id, this.getChildTranslationState(child.id));
3090
+ const subtitle = foldOpenCodeSubagentPresentation(presentation, facts);
3091
+ const title = claimOpenCodeSubagentFallbackTitle(presentation, facts.agentName);
3092
+ if (!subtitle && !title) {
3093
+ return;
3094
+ }
3095
+ const event = {
3096
+ type: "provider_subagent",
3097
+ provider: "opencode",
3098
+ event: {
3099
+ type: "upsert",
3100
+ id: child.id,
3101
+ ...(title ? { title } : {}),
3102
+ ...(subtitle ? { subtitle } : {}),
3103
+ },
3104
+ };
3105
+ this.recordProviderInternalEvent(event);
3106
+ this.notifySubscribers(event, null);
3107
+ }
3108
+ recordProviderInternalEvent(event) {
3109
+ if (event.type !== "provider_subagent") {
3110
+ return;
3111
+ }
3112
+ if (event.event.type === "upsert") {
3113
+ this.unrelatedSessionIds.delete(event.event.id);
3114
+ if (event.event.cwd) {
3115
+ this.childSessionCwds.set(event.event.id, event.event.cwd);
3116
+ }
3117
+ if (this.serverUrl) {
3118
+ registerOpenCodeChildSessionServerUrl(event.event.id, this.serverUrl);
3119
+ }
3120
+ }
3121
+ else if (event.event.type === "remove") {
3122
+ unregisterOpenCodeChildSessionServerUrl(event.event.id);
3123
+ this.childTranslationStates.delete(event.event.id);
3124
+ this.childSessionCwds.delete(event.event.id);
3125
+ this.childStatuses.delete(event.event.id);
3126
+ this.subagentPresentationByChildId.delete(event.event.id);
3127
+ }
3128
+ }
3129
+ async consumeEventSourceInput(input) {
3130
+ if (!("payload" in input)) {
3131
+ if (this.turnState.status === "stopping")
3132
+ return this.finishStoppingTurn(this.turnState.stop);
3133
+ const turnId = this.activeForegroundTurnId;
3134
+ if (turnId) {
3135
+ this.finishForegroundTurn({ type: "turn_failed", provider: "opencode", error: input.error.message }, turnId);
3136
+ }
3137
+ return;
3138
+ }
3139
+ if (input.payload.type === "server.connected") {
3140
+ await this.reconcileAfterGap(++this.gapRepairRevision);
3141
+ return;
3142
+ }
3143
+ await this.consumeOpenCodeStreamEvent({ rawEvent: input, eventCount: 0 });
3144
+ }
3145
+ async reconcileAfterGap(revision, refresh = true, delay = 100) {
3146
+ if (revision !== this.gapRepairRevision)
3147
+ return;
3148
+ const turnId = this.activeForegroundTurnId;
3149
+ const dispatchMessageId = this.activeDispatchMessageId;
3150
+ await this.refreshGapScope(refresh);
3151
+ if (revision !== this.gapRepairRevision || !turnId)
3152
+ return;
3153
+ const runnerStatus = await this.readProviderRunnerStatus().catch(() => null);
3154
+ if (revision !== this.gapRepairRevision)
3155
+ return;
3156
+ if (runnerStatus === null) {
3157
+ this.scheduleGapRepair(revision, delay);
3158
+ return;
3159
+ }
3160
+ if (dispatchMessageId === null) {
3161
+ if (runnerStatus === "idle") {
3162
+ this.suppressAssistantMessagesUntilIdle.active = false;
3163
+ this.finishForegroundTurn({ type: "turn_completed", provider: "opencode" }, turnId);
3164
+ }
3165
+ return;
3166
+ }
3167
+ const messages = await readOpenCodeSessionMessagesFromSdk(this.client, { id: this.sessionId, directory: this.config.cwd }, this.recoveryAbortController.signal).catch(() => null);
3168
+ if (revision !== this.gapRepairRevision)
3169
+ return;
3170
+ if (messages === null) {
3171
+ this.scheduleGapRepair(revision, delay);
3172
+ return;
3173
+ }
3174
+ const boundary = messages.findIndex((message) => message.info.id === dispatchMessageId);
3175
+ if (boundary < 0) {
3176
+ if (runnerStatus === "idle") {
3177
+ this.finishForegroundTurn({ type: "turn_failed", provider: "opencode", error: "Active dispatch not found" }, turnId);
3178
+ }
3179
+ return;
3180
+ }
3181
+ for (const message of messages.slice(boundary)) {
3182
+ if (revision !== this.gapRepairRevision)
3183
+ return;
3184
+ await this.consumeOpenCodeStreamEvent({
3185
+ rawEvent: {
3186
+ directory: this.config.cwd,
3187
+ payload: { type: "message.updated", properties: { info: message.info } },
3188
+ },
3189
+ eventCount: 0,
3190
+ });
3191
+ for (const part of message.parts) {
3192
+ if (revision !== this.gapRepairRevision)
3193
+ return;
3194
+ await this.consumeOpenCodeStreamEvent({
3195
+ rawEvent: {
3196
+ directory: this.config.cwd,
3197
+ payload: { type: "message.part.updated", properties: { part } },
3198
+ },
3199
+ eventCount: 0,
3200
+ });
3201
+ }
3202
+ }
3203
+ if (runnerStatus === "idle" && this.activeForegroundTurnId === turnId) {
3204
+ await this.settleRecoveredGap(messages, boundary);
3205
+ }
3206
+ }
3207
+ async refreshGapScope(refresh) {
3208
+ if (!refresh)
3209
+ return;
3210
+ await this.hydrateChildSessions(true).catch(() => undefined);
3211
+ await this.reconcileBlockingRequests();
3212
+ }
3213
+ async settleRecoveredGap(messages, boundary) {
3214
+ const latestAssistant = messages
3215
+ .slice(boundary)
3216
+ .findLast((message) => message.info.role === "assistant");
3217
+ const persistedError = latestAssistant && "error" in latestAssistant.info ? latestAssistant.info.error : undefined;
3218
+ const payload = persistedError
3219
+ ? {
3220
+ type: "session.error",
3221
+ properties: { sessionID: this.sessionId, error: persistedError },
3222
+ }
3223
+ : {
3224
+ type: "session.status",
3225
+ properties: { sessionID: this.sessionId, status: { type: "idle" } },
3226
+ };
3227
+ await this.consumeOpenCodeStreamEvent({
3228
+ rawEvent: { directory: this.config.cwd, payload },
3229
+ eventCount: 0,
3230
+ });
3231
+ }
3232
+ scheduleGapRepair(revision, delayMs) {
3233
+ setTimeout(() => {
3234
+ if (revision !== this.gapRepairRevision || this.recoveryAbortController.signal.aborted)
3235
+ return;
3236
+ const nextDelay = Math.min(delayMs * 2, OPENCODE_STOP_STATUS_MAX_DELAY_MS);
3237
+ this.ingress = this.ingress
3238
+ .then(() => this.reconcileAfterGap(revision, false, nextDelay))
3239
+ .catch(() => undefined);
3240
+ }, delayMs).unref();
3241
+ }
3242
+ async reconcileBlockingRequests() {
3243
+ const directories = new Set([this.config.cwd, ...this.childSessionCwds.values()]);
3244
+ for (const directory of directories) {
3245
+ const [permissions, questions] = await Promise.all([
3246
+ this.client.permission
3247
+ .list({ directory }, { signal: this.recoveryAbortController.signal })
3248
+ .catch(() => null),
3249
+ this.client.question
3250
+ .list({ directory }, { signal: this.recoveryAbortController.signal })
3251
+ .catch(() => null),
3252
+ ]);
3253
+ for (const [kind, response] of [
3254
+ ["tool", permissions],
3255
+ ["question", questions],
3256
+ ]) {
3257
+ const record = readOpenCodeRecord(response);
3258
+ if (!record || record.error || !Array.isArray(record.data))
3259
+ continue;
3260
+ const liveIds = new Set();
3261
+ for (const properties of record.data) {
3262
+ const propertiesRecord = readOpenCodeRecord(properties);
3263
+ const id = readNonEmptyString(propertiesRecord?.id);
3264
+ const sessionId = readNonEmptyString(propertiesRecord?.sessionID);
3265
+ if (!id || !sessionId || !this.isOwnedSessionId(sessionId))
3266
+ continue;
3267
+ liveIds.add(id);
3268
+ await this.consumeOpenCodeStreamEvent({
3269
+ rawEvent: {
3270
+ directory,
3271
+ payload: {
3272
+ type: kind === "question" ? "question.asked" : "permission.asked",
3273
+ properties,
3274
+ },
3275
+ },
3276
+ eventCount: 0,
3277
+ });
3278
+ }
3279
+ for (const [id, pendingDirectory] of this.pendingPermissionDirectories) {
3280
+ const pending = this.pendingPermissions.get(id);
3281
+ if (pendingDirectory !== directory ||
3282
+ liveIds.has(id) ||
3283
+ (kind === "question") !== (pending?.kind === "question")) {
3284
+ continue;
3285
+ }
3286
+ this.pendingPermissionDirectories.delete(id);
3287
+ this.pendingPermissions.delete(id);
3288
+ this.notifySubscribers({
3289
+ type: "permission_resolved",
3290
+ provider: "opencode",
3291
+ requestId: id,
3292
+ resolution: { behavior: "allow" },
3293
+ }, null);
3294
+ }
3295
+ }
3296
+ }
3297
+ }
3298
+ isOwnedSessionId(sessionId) {
3299
+ return sessionId === this.sessionId || this.knownChildSessionIds.has(sessionId);
3300
+ }
3301
+ async consumeOpenCodeStreamEvent(params) {
3302
+ const { rawEvent, eventCount } = params;
3303
+ let turnId = this.activeForegroundTurnId;
3304
+ const event = unwrapOpenCodeGlobalEvent(rawEvent);
3305
+ this.traceOpenCode("provider.opencode.raw_event", {
3306
+ turnId: turnId ?? undefined,
3307
+ n: eventCount,
3308
+ type: event?.type,
3309
+ rawType: readOpenCodeRecord(rawEvent)?.type,
3310
+ directory: readOpenCodeRecord(rawEvent)?.directory,
3311
+ rawEvent,
3312
+ properties: event?.properties,
3313
+ });
3314
+ if (!event) {
3315
+ return;
3316
+ }
3317
+ this.observeRunnerStatusEvent(event);
3318
+ if (this.discardEventWhileStopping(event, eventCount)) {
3319
+ return;
3320
+ }
3321
+ const translated = await this.translateEvent(event);
3322
+ const foregroundEvents = [];
3323
+ for (const translatedEvent of translated) {
3324
+ if (isOpenCodeProviderInternalEvent(translatedEvent)) {
3325
+ this.notifySubscribers(translatedEvent, null);
3326
+ }
3327
+ else {
3328
+ foregroundEvents.push(translatedEvent);
3329
+ }
3330
+ }
3331
+ if (!turnId && this.shouldStartAutonomousTurn(event)) {
3332
+ turnId = this.startAutonomousTurn();
3333
+ }
3334
+ if (!turnId) {
3335
+ this.emitBackgroundPermissionRequests(foregroundEvents);
3336
+ this.traceOpenCode("provider.opencode.event.skip", {
3337
+ n: eventCount,
3338
+ reason: "no_active_turn",
3339
+ type: event.type,
3340
+ });
3341
+ return;
3342
+ }
3343
+ this.traceOpenCode("provider.opencode.parsed_event", {
3344
+ turnId,
3345
+ n: eventCount,
3346
+ count: foregroundEvents.length,
3347
+ types: foregroundEvents.map((t) => t.type),
3348
+ events: foregroundEvents,
3349
+ });
3350
+ for (const e of foregroundEvents) {
3351
+ if (this.activeForegroundTurnId !== turnId) {
3352
+ this.traceOpenCode("provider.opencode.parsed_event.skip_active", { turnId, type: e.type });
3353
+ return;
3354
+ }
3355
+ if (e.type === "timeline" && e.item.type === "tool_call") {
3356
+ this.trackToolCall(e.item);
3357
+ }
3358
+ const terminalEvent = toTerminalTurnEvent(e);
3359
+ if (terminalEvent) {
3360
+ this.traceOpenCode("provider.opencode.event.terminal", {
3361
+ turnId,
3362
+ type: terminalEvent.type,
3363
+ });
3364
+ this.finishForegroundTurn(terminalEvent, turnId);
3365
+ return;
3366
+ }
3367
+ this.notifySubscribers(e, turnId);
3368
+ }
3369
+ }
3370
+ discardEventWhileStopping(event, eventCount) {
3371
+ if (this.turnState.status !== "stopping" ||
3372
+ getOpenCodeEventSessionId(event) !== this.sessionId) {
3373
+ return false;
3374
+ }
3375
+ // Residue of the canceled run must not surface as a new turn. Its terminal
3376
+ // is the authoritative end of the stop, so anything OpenCode publishes
3377
+ // afterwards belongs to a new run by construction and takes the live path.
3378
+ if (isOpenCodeTerminalEvent(event, this.sessionId)) {
3379
+ this.finishStoppingTurn(this.turnState.stop);
3380
+ }
3381
+ this.traceOpenCode("provider.opencode.event.skip", {
3382
+ n: eventCount,
3383
+ reason: "turn_stopping",
3384
+ type: event.type,
3385
+ });
3386
+ return true;
3387
+ }
3388
+ emitBackgroundPermissionRequests(events) {
3389
+ for (const event of events) {
3390
+ if (event.type === "permission_requested") {
3391
+ this.notifySubscribers(event, null);
3392
+ }
3393
+ }
3394
+ }
3395
+ observeRunnerStatusEvent(event) {
3396
+ if (getOpenCodeRunnerStatusFromEvent(event, this.sessionId) !== null) {
3397
+ this.runnerStatusRevision += 1;
3398
+ }
3399
+ }
3400
+ shouldStartAutonomousTurn(event) {
3401
+ if (this.turnState.status !== "idle") {
3402
+ return false;
3403
+ }
3404
+ // Message records are mutable and can be patched after the runner stops.
3405
+ // Only OpenCode's execution status is authoritative for autonomous activity.
3406
+ const runnerStatus = getOpenCodeRunnerStatusFromEvent(event, this.sessionId);
3407
+ return runnerStatus !== null && isOpenCodeRunnerActive(runnerStatus);
3408
+ }
3409
+ startAutonomousTurn() {
3410
+ const turnId = this.createTurnId();
3411
+ this.materializedParts.clear();
3412
+ this.turnState = { status: "running", turnId };
3413
+ this.runningToolCalls.clear();
3414
+ this.subAgentsByCallId.clear();
3415
+ this.subAgentCallIdByChildSessionId.clear();
3416
+ this.pendingSteerSubmissions = [];
3417
+ this.pendingUserMessageText = null;
3418
+ this.pendingClientMessageId = null;
3419
+ this.activeDispatchMessageId = null;
3420
+ this.abortController = null;
3421
+ this.notifySubscribers({ type: "turn_started", provider: "opencode" }, turnId);
3422
+ return turnId;
3423
+ }
3424
+ finishForegroundTurn(event, turnId) {
3425
+ this.traceOpenCode("provider.opencode.finish_foreground_turn", {
3426
+ turnId,
3427
+ activeTurnId: this.activeForegroundTurnId,
3428
+ type: event.type,
3429
+ error: event.type === "turn_failed" ? event.error : undefined,
3430
+ reason: event.type === "turn_canceled" ? event.reason : undefined,
3431
+ });
3432
+ if (this.activeForegroundTurnId !== turnId) {
3433
+ return;
3434
+ }
3435
+ if (event.type === "turn_canceled" || event.type === "turn_failed") {
3436
+ this.synthesizeInterruptedToolCalls(turnId);
3437
+ }
3438
+ else {
3439
+ this.runningToolCalls.clear();
3440
+ }
3441
+ this.pendingUserMessageText = null;
3442
+ this.pendingClientMessageId = null;
3443
+ this.pendingSteerSubmissions = [];
3444
+ this.turnState = { status: "idle" };
3445
+ this.abortController = null;
3446
+ this.notifySubscribers(event, turnId);
3447
+ }
3448
+ isStopping(stop) {
3449
+ return this.turnState.status === "stopping" && this.turnState.stop === stop;
3450
+ }
3451
+ issueStop(turnId) {
3452
+ if (this.turnState.status === "stopping") {
3453
+ // Stop pressed again during a stop retries that same stop. There is one
3454
+ // runner per session, so a second boundary would race the first — and
3455
+ // after a failed abort, a fresh one is both the only proof that can still
3456
+ // acknowledge the canceled turn and the only way out of fail-closed.
3457
+ return this.issueOwnedAbort(this.turnState.stop);
3458
+ }
3459
+ const stop = {
3460
+ pendingCancellationTurnId: turnId,
3461
+ terminal: createDeferred(),
3462
+ };
3463
+ const abort = this.issueOwnedAbort(stop);
3464
+ if (turnId) {
3465
+ this.synthesizeInterruptedToolCalls(turnId);
3466
+ // An idle session has no run to observe, so only abort settlement gates
3467
+ // reuse there. A running one also owes the canceled run's terminal.
3468
+ this.turnState = { status: "stopping", stop };
3469
+ }
3470
+ this.pendingUserMessageText = null;
3471
+ this.pendingClientMessageId = null;
3472
+ this.pendingSteerSubmissions = [];
3473
+ this.abortController = null;
3474
+ return abort;
3475
+ }
3476
+ issueOwnedAbort(stop) {
3477
+ const abort = this.runOwnedAbort(stop.pendingCancellationTurnId);
3478
+ // Abort is session-scoped, so its settlement is too: an older request lands
3479
+ // on the runner whenever the server gets to it, however many stops have come
3480
+ // and gone since. Only the newest abort may hold the gate closed, since
3481
+ // recovering from a failed one is what pressing Stop again is for.
3482
+ const stillInFlight = this.abortSettlement.catch(() => undefined);
3483
+ this.abortSettlement = Promise.all([stillInFlight, abort]).then(() => undefined);
3484
+ void this.abortSettlement.catch(() => undefined);
3485
+ // Cancellation is acknowledged as soon as an owned abort succeeds, or when
3486
+ // the provider publishes the canceled run's terminal.
3487
+ void abort.then(() => this.acknowledgeCancellation(stop), () => undefined);
3488
+ return abort;
3489
+ }
3490
+ acknowledgeCancellation(stop) {
3491
+ const turnId = stop.pendingCancellationTurnId;
3492
+ if (!turnId) {
3493
+ return;
3494
+ }
3495
+ stop.pendingCancellationTurnId = null;
3496
+ this.notifySubscribers({ type: "turn_canceled", provider: "opencode", reason: "interrupted" }, turnId);
3497
+ }
3498
+ /**
3499
+ * Issues the session-scoped abort for one stop, retrying it once. The stop owns
3500
+ * every abort it needs: a detached retry would outlive its own boundary and
3501
+ * cancel whichever run happened to be current when it landed.
3502
+ */
3503
+ runOwnedAbort(turnId) {
3504
+ // The turn hop also converts a synchronous SDK throw into a rejection.
3505
+ return Promise.resolve()
3506
+ .then(() => this.abortSession(turnId, "interrupt"))
3507
+ .catch((error) => {
3508
+ if (this.closed) {
3509
+ throw error;
3510
+ }
3511
+ return this.abortSession(turnId, "stop_retry");
3512
+ });
3513
+ }
3514
+ finishStoppingTurn(stop) {
3515
+ if (!this.isStopping(stop)) {
3516
+ return;
3517
+ }
3518
+ // Acknowledge before leaving the stopping state so a successor run adopted
3519
+ // from the very next event cannot start ahead of the cancellation.
3520
+ this.acknowledgeCancellation(stop);
3521
+ resetOpenCodeTurnTrackingState(this.createTranslationState());
3522
+ const contextWindowMaxTokens = this.resolveSelectedModelContextWindowMaxTokens();
3523
+ this.accumulatedUsage = contextWindowMaxTokens !== undefined ? { contextWindowMaxTokens } : {};
3524
+ this.turnState = { status: "idle" };
3525
+ stop.terminal.resolve();
3526
+ }
3527
+ trackToolCall(item) {
3528
+ if (item.status === "running") {
3529
+ this.runningToolCalls.set(item.callId, item);
3530
+ return;
3531
+ }
3532
+ this.runningToolCalls.delete(item.callId);
3533
+ }
3534
+ synthesizeInterruptedToolCalls(turnId) {
3535
+ for (const item of this.runningToolCalls.values()) {
3536
+ const error = { message: "Tool execution aborted" };
3537
+ this.notifySubscribers({
3538
+ type: "timeline",
3539
+ provider: "opencode",
3540
+ item: {
3541
+ ...item,
3542
+ status: "failed",
3543
+ error,
3544
+ detail: item.detail.type === "sub_agent"
3545
+ ? {
3546
+ ...item.detail,
3547
+ log: [item.detail.log, error.message]
3548
+ .filter((entry) => entry.trim().length > 0)
3549
+ .join("\n"),
3550
+ }
3551
+ : item.detail,
3552
+ },
3553
+ }, turnId);
3554
+ }
3555
+ this.runningToolCalls.clear();
3556
+ }
3557
+ /**
3558
+ * The fork id only exists once session.fork resolves, so its session.created event can land
3559
+ * first and be translated into a subagent row. Registering reaps that row, which is why this
3560
+ * removes as well as records.
3561
+ */
3562
+ registerSideQuestionFork(forkSessionId) {
3563
+ this.sideQuestionSessionIds.add(forkSessionId);
3564
+ // Both deletes must run: || would skip the second whenever the first succeeded.
3565
+ const wasKnownChild = this.knownChildSessionIds.delete(forkSessionId);
3566
+ const hadSubAgentCall = this.subAgentCallIdByChildSessionId.delete(forkSessionId);
3567
+ const raced = wasKnownChild || hadSubAgentCall;
3568
+ this.subagentPresentationByChildId.delete(forkSessionId);
3569
+ this.childStatuses.delete(forkSessionId);
3570
+ if (raced) {
3571
+ this.notifySubscribers({
3572
+ type: "provider_subagent",
3573
+ provider: "opencode",
3574
+ event: { type: "remove", id: forkSessionId },
3575
+ });
3576
+ }
3577
+ }
3578
+ notifySubscribers(event, turnIdOverride) {
3579
+ if (this.closed) {
3580
+ return;
3581
+ }
3582
+ if (event.type === "provider_subagent" && event.event.type === "upsert" && event.event.status) {
3583
+ const previous = this.childStatuses.get(event.event.id);
3584
+ const current = event.event.parentSubagentId === undefined && previous?.parentSubagentId !== undefined
3585
+ ? { ...event.event, parentSubagentId: previous.parentSubagentId }
3586
+ : event.event;
3587
+ if (isDeepStrictEqual(previous, current))
3588
+ return;
3589
+ this.childStatuses.set(event.event.id, structuredClone(current));
3590
+ }
3591
+ const turnId = turnIdOverride === null ? null : (turnIdOverride ?? this.activeForegroundTurnId);
3592
+ const tagged = turnId ? { ...event, turnId } : event;
3593
+ this.traceOpenCode("provider.opencode.event_emit", {
3594
+ turnId: getAgentStreamEventTurnId(tagged),
3595
+ event: tagged,
3596
+ });
3597
+ for (const callback of this.subscribers) {
3598
+ try {
3599
+ callback(tagged);
3600
+ }
3601
+ catch { }
3602
+ }
3603
+ }
3604
+ createTurnId() {
3605
+ this.gapRepairRevision += 1;
3606
+ return `opencode-turn-${this.nextTurnOrdinal++}`;
3607
+ }
3608
+ traceOpenCode(msg, data = {}) {
3609
+ this.logger.trace({
3610
+ agentId: this.agentId,
3611
+ provider: "opencode",
3612
+ sessionId: this.sessionId,
3613
+ turnId: data.turnId ?? this.activeForegroundTurnId ?? undefined,
3614
+ ...data,
3615
+ }, msg);
3616
+ }
3617
+ async *streamHistory() {
3618
+ const sessionResponse = await this.client.session.get({
3619
+ sessionID: this.sessionId,
3620
+ directory: this.config.cwd,
3621
+ });
3622
+ const response = await this.client.session.messages({
3623
+ sessionID: this.sessionId,
3624
+ directory: this.config.cwd,
3625
+ });
3626
+ if (response.error || !response.data) {
3627
+ return;
3628
+ }
3629
+ const messages = filterOpenCodeRevertedMessages(response.data, sessionResponse.error ? null : sessionResponse.data?.revert);
3630
+ for (const message of messages) {
3631
+ for (const event of buildOpenCodeReplayTimelineEvents(message)) {
3632
+ yield event;
3633
+ }
3634
+ }
3635
+ }
3636
+ async getAvailableModes() {
3637
+ if (this.availableModesCache) {
3638
+ return this.availableModesCache;
3639
+ }
3640
+ const response = await openCodeMetadataLimit(() => this.client.app.agents({
3641
+ directory: this.config.cwd,
3642
+ }));
3643
+ const agents = response.error || !response.data ? [] : response.data;
3644
+ const discoveredModes = agents.filter(isSelectableOpenCodeAgent).map(mapOpenCodeAgentToMode);
3645
+ this.availableModesCache = mergeOpenCodeModes(discoveredModes);
3646
+ return this.availableModesCache;
3647
+ }
3648
+ async getCurrentMode() {
3649
+ return this.currentMode;
3650
+ }
3651
+ async listCommands() {
3652
+ return await listOpenCodeCommandsFromSdk(this.client, this.config.cwd);
3653
+ }
3654
+ async setMode(modeId) {
3655
+ const normalizedModeId = normalizeOpenCodeModeId(modeId);
3656
+ if (normalizedModeId === OPENCODE_LEGACY_FULL_ACCESS_MODE_ID) {
3657
+ this.currentMode = OPENCODE_BUILD_MODE_ID;
3658
+ await this.setFeature(OPENCODE_AUTO_ACCEPT_FEATURE_ID, true);
3659
+ return;
3660
+ }
3661
+ this.currentMode = normalizedModeId;
3662
+ this.config.modeId = normalizedModeId ?? undefined;
3663
+ }
3664
+ async setFeature(featureId, value) {
3665
+ if (featureId !== OPENCODE_AUTO_ACCEPT_FEATURE_ID) {
3666
+ throw new Error(`Unsupported OpenCode feature '${featureId}'`);
3667
+ }
3668
+ const enabled = value === true;
3669
+ this.autoAcceptEnabled = enabled;
3670
+ this.config.featureValues = {
3671
+ ...this.config.featureValues,
3672
+ [OPENCODE_AUTO_ACCEPT_FEATURE_ID]: enabled,
3673
+ };
3674
+ }
3675
+ getPendingPermissions() {
3676
+ return Array.from(this.pendingPermissions.values());
3677
+ }
3678
+ async respondToPermission(requestId, response) {
3679
+ const pending = this.pendingPermissions.get(requestId);
3680
+ if (!pending) {
3681
+ throw new Error(`No pending permission request with id '${requestId}'`);
3682
+ }
3683
+ const directory = this.pendingPermissionDirectories.get(requestId) ?? this.config.cwd;
3684
+ if (pending.kind === "question") {
3685
+ if (response.behavior === "deny") {
3686
+ await this.client.question.reject({
3687
+ requestID: requestId,
3688
+ directory,
3689
+ });
3690
+ }
3691
+ else {
3692
+ const answersRecord = readOpenCodeRecord(response.updatedInput?.answers);
3693
+ const questions = Array.isArray(pending.input?.questions) ? pending.input.questions : [];
3694
+ const answers = questions.map((item) => {
3695
+ const header = readNonEmptyString(readOpenCodeRecord(item)?.header);
3696
+ const rawAnswer = header ? readNonEmptyString(answersRecord?.[header]) : null;
3697
+ if (!rawAnswer) {
3698
+ return [];
3699
+ }
3700
+ return rawAnswer
3701
+ .split(",")
3702
+ .map((entry) => entry.trim())
3703
+ .filter((entry) => entry.length > 0);
3704
+ });
3705
+ await this.client.question.reply({
3706
+ requestID: requestId,
3707
+ directory,
3708
+ answers,
3709
+ });
3710
+ }
3711
+ this.pendingPermissions.delete(requestId);
3712
+ this.pendingPermissionDirectories.delete(requestId);
3713
+ return;
3714
+ }
3715
+ const reply = resolveOpenCodePermissionReply(response);
3716
+ await this.client.permission.reply({
3717
+ requestID: requestId,
3718
+ directory,
3719
+ reply,
3720
+ message: response.behavior === "deny" ? response.message : undefined,
3721
+ });
3722
+ this.pendingPermissions.delete(requestId);
3723
+ this.pendingPermissionDirectories.delete(requestId);
3724
+ }
3725
+ describePersistence() {
3726
+ return {
3727
+ provider: "opencode",
3728
+ sessionId: this.sessionId,
3729
+ nativeHandle: this.sessionId,
3730
+ metadata: {
3731
+ cwd: this.config.cwd,
3732
+ ...(this.config.modeId ? { modeId: this.config.modeId } : {}),
3733
+ ...(this.config.model ? { model: this.config.model } : {}),
3734
+ },
3735
+ };
3736
+ }
3737
+ async close() {
3738
+ try {
3739
+ this.closed = true;
3740
+ this.abortController?.abort();
3741
+ this.recoveryAbortController.abort();
3742
+ this.unsubscribeEvents?.();
3743
+ this.unsubscribeEvents = null;
3744
+ await this.ingress.catch(() => undefined);
3745
+ this.subscribers.clear();
3746
+ await abortOpenCodeSession({
3747
+ client: this.client,
3748
+ sessionId: this.sessionId,
3749
+ directory: this.config.cwd,
3750
+ logger: this.logger,
3751
+ });
3752
+ await this.deleteProviderSessionIfEphemeral();
3753
+ this.turnState = { status: "idle" };
3754
+ }
3755
+ finally {
3756
+ this.releaseBridge?.();
3757
+ this.releaseBridge = null;
3758
+ await this.releaseServer?.();
3759
+ this.releaseServer = null;
3760
+ }
3761
+ }
3762
+ async deleteProviderSessionIfEphemeral() {
3763
+ if (this.persistSession || this.deletedFromProvider) {
3764
+ return;
3765
+ }
3766
+ this.deletedFromProvider = true;
3767
+ try {
3768
+ const response = await this.client.session.delete({
3769
+ sessionID: this.sessionId,
3770
+ directory: this.config.cwd,
3771
+ });
3772
+ if (response.error) {
3773
+ throw new Error(`OpenCode session.delete failed: ${JSON.stringify(response.error)}`);
3774
+ }
3775
+ }
3776
+ catch (error) {
3777
+ this.logger.debug({ err: error, sessionId: this.sessionId }, "Failed to delete non-persistent OpenCode session");
3778
+ }
3779
+ }
3780
+ parseSlashCommandInput(text) {
3781
+ const trimmed = text.trim();
3782
+ if (!trimmed.startsWith("/") || trimmed.length <= 1) {
3783
+ return null;
3784
+ }
3785
+ const withoutPrefix = trimmed.slice(1);
3786
+ const firstWhitespaceIdx = withoutPrefix.search(/\s/);
3787
+ const commandName = firstWhitespaceIdx === -1 ? withoutPrefix : withoutPrefix.slice(0, firstWhitespaceIdx);
3788
+ if (!commandName || commandName.includes("/")) {
3789
+ return null;
3790
+ }
3791
+ const rawArgs = firstWhitespaceIdx === -1 ? "" : withoutPrefix.slice(firstWhitespaceIdx + 1).trim();
3792
+ return rawArgs.length > 0 ? { commandName, args: rawArgs } : { commandName };
3793
+ }
3794
+ async resolveSlashCommandInvocation(prompt) {
3795
+ if (typeof prompt !== "string") {
3796
+ return null;
3797
+ }
3798
+ const parsed = this.parseSlashCommandInput(prompt);
3799
+ if (!parsed) {
3800
+ return null;
3801
+ }
3802
+ try {
3803
+ const commands = await this.listCommands();
3804
+ return commands.some((command) => command.name === parsed.commandName) ? parsed : null;
3805
+ }
3806
+ catch (error) {
3807
+ this.logger.warn({ err: error, commandName: parsed.commandName }, "Failed to resolve slash command; falling back to plain prompt input");
3808
+ return null;
3809
+ }
3810
+ }
3811
+ parseModel(model) {
3812
+ if (!model) {
3813
+ return undefined;
3814
+ }
3815
+ const parts = model.split("/");
3816
+ if (parts.length >= 2) {
3817
+ return { providerID: parts[0], modelID: parts.slice(1).join("/") };
3818
+ }
3819
+ return { providerID: "opencode", modelID: model };
3820
+ }
3821
+ async ensureMcpServersConfigured() {
3822
+ if (this.mcpConfigured) {
3823
+ return;
3824
+ }
3825
+ const mcpServers = this.config.mcpServers;
3826
+ if (!mcpServers || Object.keys(mcpServers).length === 0) {
3827
+ this.mcpConfigured = true;
3828
+ return;
3829
+ }
3830
+ if (!this.mcpSetupPromise) {
3831
+ this.mcpSetupPromise = this.configureMcpServers(mcpServers);
3832
+ }
3833
+ try {
3834
+ await this.mcpSetupPromise;
3835
+ this.mcpConfigured = true;
3836
+ }
3837
+ catch (error) {
3838
+ this.mcpSetupPromise = null;
3839
+ throw error;
3840
+ }
3841
+ }
3842
+ async configureMcpServers(mcpServers) {
3843
+ await Promise.all(Object.entries(mcpServers).map(([name, serverConfig]) => this.registerMcpServer(name, toOpenCodeMcpConfig(serverConfig))));
3844
+ }
3845
+ async registerMcpServer(name, config) {
3846
+ await this.runMcpOperation("add", name, () => this.client.mcp.add({
3847
+ directory: this.config.cwd,
3848
+ name,
3849
+ config,
3850
+ }));
3851
+ }
3852
+ async runMcpOperation(operation, name, run) {
3853
+ const response = await run();
3854
+ const error = response.error ?? readOpenCodeMcpOperationError(response.data, name);
3855
+ if (!error) {
3856
+ return;
3857
+ }
3858
+ if (isAlreadyPresentMcpError(error)) {
3859
+ return;
3860
+ }
3861
+ throw new Error(`Failed to ${operation} OpenCode MCP server '${name}': ${toDiagnosticErrorMessage(error)}`);
3862
+ }
3863
+ createTranslationState() {
3864
+ return {
3865
+ sessionId: this.sessionId,
3866
+ cwd: this.config.cwd,
3867
+ messageRoles: this.messageRoles,
3868
+ pendingUserMessageText: this.pendingUserMessageText,
3869
+ pendingClientMessageId: this.pendingClientMessageId,
3870
+ pendingSteerSubmissions: this.pendingSteerSubmissions,
3871
+ emittedUserMessageIds: this.emittedUserMessageIds,
3872
+ accumulatedUsage: this.accumulatedUsage,
3873
+ sessionTotalCostUsd: this.sessionTotalCostUsd,
3874
+ materializedParts: this.materializedParts,
3875
+ emittedStructuredMessageIds: this.emittedStructuredMessageIds,
3876
+ compactionSummaryMessageIds: this.compactionSummaryMessageIds,
3877
+ emittedCompactionPartIds: this.emittedCompactionPartIds,
3878
+ suppressAssistantMessagesUntilIdle: this.suppressAssistantMessagesUntilIdle,
3879
+ partTypes: this.partTypes,
3880
+ subAgentsByCallId: this.subAgentsByCallId,
3881
+ subAgentCallIdByChildSessionId: this.subAgentCallIdByChildSessionId,
3882
+ knownChildSessionIds: this.knownChildSessionIds,
3883
+ sideQuestionSessionIds: this.sideQuestionSessionIds,
3884
+ subagentPresentationByChildId: this.subagentPresentationByChildId,
3885
+ modelContextWindowsByModelKey: this.modelContextWindowsByModelKey,
3886
+ onMaterializationMismatch: (diagnostic) => {
3887
+ this.logger.warn({ ...diagnostic, sessionId: this.sessionId }, "OpenCode final part snapshot replaced streamed content");
3888
+ },
3889
+ onAssistantModelContextWindowResolved: (contextWindowMaxTokens) => {
3890
+ this.accumulatedUsage.contextWindowMaxTokens = contextWindowMaxTokens;
3891
+ if (!this.config.model) {
3892
+ this.selectedModelContextWindowMaxTokens = contextWindowMaxTokens;
3893
+ }
3894
+ },
3895
+ };
3896
+ }
3897
+ getChildTranslationState(sessionId) {
3898
+ const existing = this.childTranslationStates.get(sessionId);
3899
+ if (existing) {
3900
+ return existing;
3901
+ }
3902
+ const state = {
3903
+ sessionId,
3904
+ cwd: this.config.cwd,
3905
+ messageRoles: new Map(),
3906
+ emittedUserMessageIds: new Set(),
3907
+ accumulatedUsage: {},
3908
+ materializedParts: new Map(),
3909
+ emittedStructuredMessageIds: new Set(),
3910
+ compactionSummaryMessageIds: new Set(),
3911
+ emittedCompactionPartIds: new Set(),
3912
+ hydratedMessageFingerprints: new Map(),
3913
+ hydratedPartFingerprints: new Map(),
3914
+ suppressAssistantMessagesUntilIdle: { active: false },
3915
+ partTypes: new Map(),
3916
+ subAgentsByCallId: new Map(),
3917
+ subAgentCallIdByChildSessionId: new Map(),
3918
+ knownChildSessionIds: new Set(),
3919
+ subagentPresentationByChildId: this.subagentPresentationByChildId,
3920
+ modelContextWindowsByModelKey: this.modelContextWindowsByModelKey,
3921
+ onMaterializationMismatch: (diagnostic) => {
3922
+ this.logger.warn({ ...diagnostic, sessionId }, "OpenCode final part snapshot replaced streamed content");
3923
+ },
3924
+ };
3925
+ this.childTranslationStates.set(sessionId, state);
3926
+ return state;
3927
+ }
3928
+ appendProviderSubagentEvents(event, translated) {
3929
+ const childSessionId = getOpenCodeEventSessionId(event);
3930
+ const isKnownChild = childSessionId && this.knownChildSessionIds.has(childSessionId);
3931
+ if (!childSessionId || childSessionId === this.sessionId || !isKnownChild) {
3932
+ return;
3933
+ }
3934
+ translated.push(...this.translateProviderSubagentEvent(childSessionId, event));
3935
+ }
3936
+ translateProviderSubagentEvent(sessionId, event) {
3937
+ const translated = translateOpenCodeEvent(event, this.getChildTranslationState(sessionId));
3938
+ const events = [];
3939
+ let markedRunning = false;
3940
+ const markRunning = () => {
3941
+ if (markedRunning)
3942
+ return;
3943
+ markedRunning = true;
3944
+ events.push({
3945
+ type: "provider_subagent",
3946
+ provider: "opencode",
3947
+ event: { type: "upsert", id: sessionId, status: "running" },
3948
+ });
3949
+ };
3950
+ if (event.type === "session.status" && event.properties.status.type === "busy") {
3951
+ markRunning();
3952
+ }
3953
+ this.appendChildAssistantPresentationUpsert(sessionId, event, events);
3954
+ for (const childEvent of translated) {
3955
+ if (childEvent.type === "timeline") {
3956
+ markRunning();
3957
+ events.push({
3958
+ type: "provider_subagent",
3959
+ provider: "opencode",
3960
+ event: {
3961
+ type: "timeline",
3962
+ id: sessionId,
3963
+ item: childEvent.item,
3964
+ timestamp: childEvent.timestamp,
3965
+ },
3966
+ });
3967
+ }
3968
+ else if (childEvent.type === "turn_started") {
3969
+ markRunning();
3970
+ }
3971
+ else if (childEvent.type === "turn_completed") {
3972
+ events.push({
3973
+ type: "provider_subagent",
3974
+ provider: "opencode",
3975
+ event: { type: "upsert", id: sessionId, status: "completed" },
3976
+ });
3977
+ }
3978
+ else if (childEvent.type === "turn_failed") {
3979
+ events.push({
3980
+ type: "provider_subagent",
3981
+ provider: "opencode",
3982
+ event: { type: "upsert", id: sessionId, status: "failed" },
3983
+ });
3984
+ }
3985
+ else if (childEvent.type === "turn_canceled") {
3986
+ events.push({
3987
+ type: "provider_subagent",
3988
+ provider: "opencode",
3989
+ event: { type: "upsert", id: sessionId, status: "canceled" },
3990
+ });
3991
+ }
3992
+ else if (childEvent.type === "permission_requested" &&
3993
+ childEvent.request.kind === "question") {
3994
+ events.push(childEvent);
3995
+ }
3996
+ }
3997
+ return events;
3998
+ }
3999
+ /**
4000
+ * Fold presentation facts (agent, model, variant, completed-message tokens) off a child
4001
+ * assistant `message.updated` frame and emit the missing title and/or changed subtitle.
4002
+ * Never carries `status`: a presentation upsert must not revert a finished child.
4003
+ */
4004
+ appendChildAssistantPresentationUpsert(sessionId, event, events) {
4005
+ if (event.type !== "message.updated") {
4006
+ return;
4007
+ }
4008
+ const info = event.properties.info;
4009
+ if (info.sessionID !== sessionId || info.role !== "assistant") {
4010
+ return;
4011
+ }
4012
+ const facts = readOpenCodeAssistantPresentationFacts(info);
4013
+ if (!facts) {
4014
+ return;
4015
+ }
4016
+ const presentation = getOpenCodeSubagentPresentationState(sessionId, this.getChildTranslationState(sessionId));
4017
+ const subtitle = foldOpenCodeSubagentPresentation(presentation, facts);
4018
+ const title = claimOpenCodeSubagentFallbackTitle(presentation, facts.agentName);
4019
+ if (!subtitle && !title) {
4020
+ return;
4021
+ }
4022
+ events.push({
4023
+ type: "provider_subagent",
4024
+ provider: "opencode",
4025
+ event: {
4026
+ type: "upsert",
4027
+ id: sessionId,
4028
+ ...(title ? { title } : {}),
4029
+ ...(subtitle ? { subtitle } : {}),
4030
+ },
4031
+ });
4032
+ }
4033
+ async translateEvent(event) {
4034
+ const eventSessionId = getOpenCodeEventSessionId(event);
4035
+ if (event.type !== "session.created" &&
4036
+ eventSessionId &&
4037
+ eventSessionId !== this.sessionId &&
4038
+ !this.knownChildSessionIds.has(eventSessionId) &&
4039
+ !this.unrelatedSessionIds.has(eventSessionId)) {
4040
+ if (!this.childHydrationCompleted) {
4041
+ this.startChildSessionHydration();
4042
+ await this.childHydrationPromise?.catch(() => undefined);
4043
+ }
4044
+ if (!this.knownChildSessionIds.has(eventSessionId)) {
4045
+ this.unrelatedSessionIds.add(eventSessionId);
4046
+ }
4047
+ }
4048
+ const translated = translateOpenCodeEvent(event, this.createTranslationState());
4049
+ this.appendProviderSubagentEvents(event, translated);
4050
+ const events = [];
4051
+ if (typeof this.accumulatedUsage.totalCostUsd === "number") {
4052
+ this.sessionTotalCostUsd = maxFiniteNumber(this.sessionTotalCostUsd, this.accumulatedUsage.totalCostUsd);
4053
+ }
4054
+ for (const translatedEvent of translated) {
4055
+ this.recordProviderInternalEvent(translatedEvent);
4056
+ if (translatedEvent.type === "permission_requested") {
4057
+ const directory = (eventSessionId ? this.childSessionCwds.get(eventSessionId) : undefined) ??
4058
+ this.config.cwd;
4059
+ const autoApproved = await this.tryAutoApproveToolPermission(translatedEvent.request, directory);
4060
+ if (autoApproved) {
4061
+ continue;
4062
+ }
4063
+ this.pendingPermissions.set(translatedEvent.request.id, translatedEvent.request);
4064
+ this.pendingPermissionDirectories.set(translatedEvent.request.id, directory);
4065
+ }
4066
+ if (translatedEvent.type === "turn_completed") {
4067
+ if (hasNormalizedOpenCodeUsage(this.accumulatedUsage)) {
4068
+ translatedEvent.usage = this.accumulatedUsage;
4069
+ }
4070
+ const contextWindowMaxTokens = this.resolveSelectedModelContextWindowMaxTokens();
4071
+ this.accumulatedUsage =
4072
+ contextWindowMaxTokens !== undefined ? { contextWindowMaxTokens } : {};
4073
+ }
4074
+ events.push(translatedEvent);
4075
+ }
4076
+ return events;
4077
+ }
4078
+ async tryAutoApproveToolPermission(request, directory) {
4079
+ if (!this.autoAcceptEnabled || request.kind !== "tool") {
4080
+ return false;
4081
+ }
4082
+ try {
4083
+ await this.client.permission.reply({
4084
+ requestID: request.id,
4085
+ directory,
4086
+ reply: "once",
4087
+ });
4088
+ return true;
4089
+ }
4090
+ catch (error) {
4091
+ this.logger.warn({ err: error, requestId: request.id }, "Failed to auto-approve OpenCode tool permission");
4092
+ return false;
4093
+ }
4094
+ }
4095
+ resolveSelectedModelContextWindowMaxTokens() {
4096
+ return this.selectedModelContextWindowMaxTokens;
4097
+ }
4098
+ resolveConfiguredModelContextWindowMaxTokens(modelId) {
4099
+ const modelLookupKey = parseOpenCodeModelLookupKey(modelId);
4100
+ if (!modelLookupKey) {
4101
+ return undefined;
4102
+ }
4103
+ return this.modelContextWindowsByModelKey.get(modelLookupKey);
4104
+ }
4105
+ }
4106
+ //# sourceMappingURL=opencode-agent.js.map