@vantran-se/openchamber-web 1.24.3 → 2.0.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 (367) hide show
  1. package/README.md +2 -8
  2. package/bin/lib/commands-connect-url.js +3 -8
  3. package/bin/lib/commands-tunnel.js +3 -0
  4. package/dist/assets/{CodeMirrorCommentWidgets-BjJHrzmU.js → CodeMirrorCommentWidgets-ntXIbhV2.js} +1 -1
  5. package/dist/assets/DiffView-CjxUovbM.js +4 -0
  6. package/dist/assets/FilesView-DFWD0RQR.js +17 -0
  7. package/dist/assets/{GitView-CDOJy5Ay.js → GitView-BWa7e5vw.js} +4 -4
  8. package/dist/assets/{GuestAttachDialog-D3S0Rjic.js → GuestAttachDialog-DdOuyZzp.js} +1 -1
  9. package/dist/assets/GuestSurfacePane-DDfzid3U.js +1 -0
  10. package/dist/assets/{JsonTreeView-D0C9nU7K.js → JsonTreeView-3sGwqexh.js} +1 -1
  11. package/dist/assets/LinearIssuesView-C6dpIdjw.js +1 -0
  12. package/dist/assets/MarkdownImageGallery-Q7YR_tl4.js +1 -0
  13. package/dist/assets/MarkdownRendererImpl-DxDV56bL.js +12 -0
  14. package/dist/assets/OnboardingScreen-rK4Stg__.js +1 -0
  15. package/dist/assets/{PatchDiff-DnEhjXcC.js → PatchDiff-DS-IMU1j.js} +1 -1
  16. package/dist/assets/{PierreDiffViewer-DyxZVVVR.js → PierreDiffViewer-DW23KWKZ.js} +1 -1
  17. package/dist/assets/PlanView-BCk_VobP.js +5 -0
  18. package/dist/assets/PluginPane-BPP1dbck.js +3 -0
  19. package/dist/assets/SettingsView-kMmrpn43.js +29 -0
  20. package/dist/assets/SettingsWindow-BpvD6IYQ.js +1 -0
  21. package/dist/assets/SubmoduleDiffSummary-BLttSS1X.js +1 -0
  22. package/dist/assets/ToolOutputDialog-CtqDqbyr.js +15 -0
  23. package/dist/assets/ToolPartDiffPreview-5FcKdyRy.js +8 -0
  24. package/dist/assets/{VirtualizedFileDiff-0pyr_mHY.js → VirtualizedFileDiff-C763hNCR.js} +4 -4
  25. package/dist/assets/{WalkthroughView-yNj4nOP5.js → WalkthroughView-lap5btCF.js} +2 -2
  26. package/dist/assets/appThemeRegistry-u4zw1l0B.js +1 -0
  27. package/dist/assets/{commitAndPush-DvJKa3Ks.js → commitAndPush-CwGJfJG-.js} +1 -1
  28. package/dist/assets/{computeVirtualFileMetrics-DxTBMuu-.js → computeVirtualFileMetrics-DW5jjX4n.js} +1 -1
  29. package/dist/assets/de-CndEg67T.js +10 -0
  30. package/dist/assets/es-DglvPlaC.js +16 -0
  31. package/dist/assets/fr-DejPCpbS.js +14 -0
  32. package/dist/assets/index-C2r64QfD.js +1 -0
  33. package/dist/assets/index-CLcM8HKx.css +1 -0
  34. package/dist/assets/index-CvLgnuNI.js +41 -0
  35. package/dist/assets/{isDiffPlainText-D7FkBMP6.js → isDiffPlainText-D47a6hMP.js} +1 -1
  36. package/dist/assets/{isFilePlainText-CL2vsrIZ.js → isFilePlainText-B-mGgeKl.js} +1 -1
  37. package/dist/assets/ja-CVpQawCd.js +16 -0
  38. package/dist/assets/ko-Bw446h9j.js +16 -0
  39. package/dist/assets/main-Bz4WWXbr.js +2 -0
  40. package/dist/assets/main-oreqDsOV.js +896 -0
  41. package/dist/assets/{markdownCore-Dh7WEsdM.js → markdownCore-D2e5sp9y.js} +4 -4
  42. package/dist/assets/miniChat-D1v2gsBI.js +2 -0
  43. package/dist/assets/mobile-DBj3lCf2.js +2 -0
  44. package/dist/assets/{patchFileDiff-Bsba8KFp.js → patchFileDiff-BpeUOV91.js} +3 -3
  45. package/dist/assets/pl-BYNlPdhm.js +16 -0
  46. package/dist/assets/pt-BR-CL-Yfv9H.js +16 -0
  47. package/dist/assets/renderElectronMiniChatApp-DVtfEB2z.js +2 -0
  48. package/dist/assets/renderMobileApp-DFp9-xbG.js +25 -0
  49. package/dist/assets/runtimeEndpointReset-CsIpUep1.js +27 -0
  50. package/dist/assets/scheduledTasksApi-B5OHVpPM.js +1 -0
  51. package/dist/assets/{shikiHighlight-8_3csmr6.js → shikiHighlight-DNm2Z_Jc.js} +1 -1
  52. package/dist/assets/{textMateThemeFromAppTheme-CHo2fCgW.js → textMateThemeFromAppTheme-DGF2kG7g.js} +1 -1
  53. package/dist/assets/tr-DzmbxLy-.js +7 -0
  54. package/dist/assets/uk-C7vQnwro.js +16 -0
  55. package/dist/assets/useAppFontEffects-Ci3FEaPf.js +7337 -0
  56. package/dist/assets/{useInlineCommentController-DkQ_gqpn.js → useInlineCommentController-CuUuakrt.js} +2 -2
  57. package/dist/assets/useRootScrollLock-CQIsyERq.js +2 -0
  58. package/dist/assets/{vendor-codemirror-language-data-CdzUmUyZ.js → vendor-codemirror-language-data-CQa7_1cr.js} +2 -2
  59. package/dist/assets/vendor-cron-parser-CjvYVigk.js +2 -0
  60. package/dist/assets/vendor-opencode-client-_BAHQo4R.js +12 -0
  61. package/dist/assets/{vendor-remixicon-react-BDmGmFCA.js → vendor-remixicon-react-D6dZ0UwF.js} +1 -1
  62. package/dist/assets/{vendor-zod-CgAdXWZO.js → vendor-zod-Gea9uBlY.js} +1 -1
  63. package/dist/assets/{web-components-B8IcVQAA.js → web-components-B6tKQyJN.js} +2 -2
  64. package/dist/assets/zh-CN-Cl0srS-z.js +16 -0
  65. package/dist/assets/zh-TW-DtII5bDb.js +16 -0
  66. package/dist/index.html +13 -7
  67. package/dist/mini-chat.html +5 -5
  68. package/dist/mobile.html +5 -5
  69. package/package.json +6 -5
  70. package/server/index.d.ts +1 -0
  71. package/server/index.js +246 -91
  72. package/server/lib/agent-tool/DOCUMENTATION.md +32 -15
  73. package/server/lib/agent-tool/runtime.js +135 -54
  74. package/server/lib/agent-tool/runtime.test.js +155 -87
  75. package/server/lib/browser-control/DOCUMENTATION.md +37 -2
  76. package/server/lib/browser-control/provider.js +217 -0
  77. package/server/lib/browser-control/provider.test.js +251 -0
  78. package/server/lib/context-obligatory/runtime.js +61 -50
  79. package/server/lib/context-obligatory/runtime.test.js +62 -162
  80. package/server/lib/event-stream/DOCUMENTATION.md +12 -1
  81. package/server/lib/event-stream/delta-coalescer.js +0 -0
  82. package/server/lib/event-stream/delta-coalescer.test.js +68 -57
  83. package/server/lib/event-stream/directory-ws-bridge.js +1 -1
  84. package/server/lib/event-stream/global-hub.js +10 -1
  85. package/server/lib/event-stream/global-hub.test.js +27 -26
  86. package/server/lib/event-stream/index.js +6 -0
  87. package/server/lib/event-stream/protocol.js +26 -19
  88. package/server/lib/event-stream/protocol.test.js +18 -7
  89. package/server/lib/event-stream/rebind.test.js +5 -5
  90. package/server/lib/event-stream/runtime.test.js +17 -15
  91. package/server/lib/event-stream/translate-v2.js +313 -0
  92. package/server/lib/event-stream/translate-v2.test.js +209 -0
  93. package/server/lib/event-stream/upstream-reader.test.js +16 -16
  94. package/server/lib/fs/DOCUMENTATION.md +4 -2
  95. package/server/lib/fs/byte-range.js +35 -0
  96. package/server/lib/fs/byte-range.test.js +31 -0
  97. package/server/lib/fs/routes.js +47 -42
  98. package/server/lib/fs/routes.test.js +123 -18
  99. package/server/lib/git/service.js +12 -0
  100. package/server/lib/github/DOCUMENTATION.md +1 -1
  101. package/server/lib/github/pr-status.js +22 -2
  102. package/server/lib/github/pr-status.test.js +27 -14
  103. package/server/lib/guests/DOCUMENTATION.md +13 -0
  104. package/server/lib/guests/catalog.js +12 -0
  105. package/server/lib/guests/catalog.test.js +33 -0
  106. package/server/lib/guests/routes.js +10 -1
  107. package/server/lib/guests/service.js +192 -14
  108. package/server/lib/guests/service.test.js +201 -1
  109. package/server/lib/guests/surface.js +630 -0
  110. package/server/lib/guests/surface.test.js +486 -0
  111. package/server/lib/markdown-image-grants/routes.js +18 -5
  112. package/server/lib/markdown-image-grants/routes.test.js +9 -6
  113. package/server/lib/message-queue/DOCUMENTATION.md +33 -22
  114. package/server/lib/message-queue/runtime.js +155 -100
  115. package/server/lib/message-queue/runtime.test.js +168 -82
  116. package/server/lib/notifications/DOCUMENTATION.md +28 -0
  117. package/server/lib/notifications/control-stream.http.test.js +68 -0
  118. package/server/lib/notifications/emitter-runtime.js +15 -0
  119. package/server/lib/notifications/emitter-runtime.test.js +32 -0
  120. package/server/lib/notifications/push-runtime.js +5 -1
  121. package/server/lib/notifications/push-runtime.test.js +2 -2
  122. package/server/lib/notifications/routes.js +1 -1
  123. package/server/lib/notifications/runtime.js +115 -26
  124. package/server/lib/notifications/template-runtime.js +13 -15
  125. package/server/lib/notifications/template-runtime.test.js +16 -9
  126. package/server/lib/notifications/trigger-runtime.test.js +187 -0
  127. package/server/lib/openchamber-control/DOCUMENTATION.md +10 -0
  128. package/server/lib/openchamber-control/actions.js +3 -2
  129. package/server/lib/openchamber-control/error.js +1 -1
  130. package/server/lib/openchamber-control/file-open.js +59 -0
  131. package/server/lib/openchamber-control/file-open.test.js +57 -0
  132. package/server/lib/openchamber-control/routes.test.js +12 -0
  133. package/server/lib/openchamber-control/service.js +102 -49
  134. package/server/lib/openchamber-control/service.test.js +84 -44
  135. package/server/lib/openchamber-sessions/archive-store.js +224 -0
  136. package/server/lib/openchamber-sessions/archive-store.test.js +187 -0
  137. package/server/lib/openchamber-sessions/opencode-client.js +22 -0
  138. package/server/lib/openchamber-sessions/routes.js +398 -328
  139. package/server/lib/openchamber-sessions/routes.test.js +777 -740
  140. package/server/lib/openchamber-sessions/session-metadata-store.js +285 -0
  141. package/server/lib/openchamber-sessions/session-metadata-store.test.js +259 -0
  142. package/server/lib/opencode/DOCUMENTATION.md +449 -29
  143. package/server/lib/opencode/agents.js +233 -327
  144. package/server/lib/opencode/auth.js +41 -44
  145. package/server/lib/opencode/auth.test.js +92 -0
  146. package/server/lib/opencode/cli-upgrade.d.ts +4 -0
  147. package/server/lib/opencode/cli-upgrade.js +18 -0
  148. package/server/lib/opencode/cli-upgrade.test.js +36 -0
  149. package/server/lib/opencode/commands.js +164 -145
  150. package/server/lib/opencode/compatibility.d.ts +16 -0
  151. package/server/lib/opencode/compatibility.js +88 -0
  152. package/server/lib/opencode/compatibility.test.js +62 -0
  153. package/server/lib/opencode/config-entity-routes.js +58 -29
  154. package/server/lib/opencode/config-entity-v2.test.js +290 -0
  155. package/server/lib/opencode/config-mutation-response.js +17 -7
  156. package/server/lib/opencode/config-mutation-response.test.js +4 -7
  157. package/server/lib/opencode/config-paths.test.js +2 -2
  158. package/server/lib/opencode/config-v2.d.ts +183 -0
  159. package/server/lib/opencode/config-v2.js +801 -0
  160. package/server/lib/opencode/config-v2.test.js +466 -0
  161. package/server/lib/opencode/credential-db.js +144 -0
  162. package/server/lib/opencode/credential-db.test.js +104 -0
  163. package/server/lib/opencode/env-runtime.js +48 -9
  164. package/server/lib/opencode/env-runtime.test.js +45 -0
  165. package/server/lib/opencode/feature-routes-runtime.js +15 -5
  166. package/server/lib/opencode/lifecycle-process.test.js +7 -4
  167. package/server/lib/opencode/lifecycle.js +85 -30
  168. package/server/lib/opencode/lifecycle.test.js +80 -8
  169. package/server/lib/opencode/login-shell-env.js +27 -0
  170. package/server/lib/opencode/managed-config-file.js +119 -0
  171. package/server/lib/opencode/managed-config-file.test.js +152 -0
  172. package/server/lib/opencode/managed-plugin-config.js +33 -13
  173. package/server/lib/opencode/mcp.js +43 -149
  174. package/server/lib/opencode/network-runtime.js +6 -7
  175. package/server/lib/opencode/openchamber-routes.test.js +2 -5
  176. package/server/lib/opencode/plugin-routes.js +3 -3
  177. package/server/lib/opencode/plugin-routes.test.js +6 -24
  178. package/server/lib/opencode/plugins.js +91 -40
  179. package/server/lib/opencode/plugins.test.js +28 -15
  180. package/server/lib/opencode/providers.js +63 -83
  181. package/server/lib/opencode/providers.test.js +128 -59
  182. package/server/lib/opencode/proxy-agent-wiring.test.js +4 -2
  183. package/server/lib/opencode/proxy.js +179 -129
  184. package/server/lib/opencode/pwa-manifest-routes.js +4 -2
  185. package/server/lib/opencode/pwa-manifest-routes.test.js +3 -2
  186. package/server/lib/opencode/response-envelope.js +14 -0
  187. package/server/lib/opencode/response-envelope.test.js +23 -0
  188. package/server/lib/opencode/routes-upgrade.test.js +73 -116
  189. package/server/lib/opencode/routes.js +121 -428
  190. package/server/lib/opencode/server-utils-runtime.js +10 -4
  191. package/server/lib/opencode/session-activity.js +78 -0
  192. package/server/lib/opencode/session-runtime.js +21 -10
  193. package/server/lib/opencode/session-runtime.test.js +9 -9
  194. package/server/lib/opencode/settings-helpers.js +9 -9
  195. package/server/lib/opencode/settings-helpers.test.js +7 -12
  196. package/server/lib/opencode/settings-registry.json +6 -8
  197. package/server/lib/opencode/settings-runtime.js +18 -1
  198. package/server/lib/opencode/settings-runtime.test.js +31 -2
  199. package/server/lib/opencode/shared.js +54 -22
  200. package/server/lib/opencode/shared.test.js +8 -4
  201. package/server/lib/opencode/shutdown-runtime.js +54 -7
  202. package/server/lib/opencode/shutdown-runtime.test.js +224 -30
  203. package/server/lib/opencode/skill-routes.js +23 -24
  204. package/server/lib/opencode/skills.js +7 -5
  205. package/server/lib/opencode/tunnel-wiring-runtime.js +2 -1
  206. package/server/lib/opencode/upgrade-capability.test.js +1 -1
  207. package/server/lib/opencode/v1-migration-topup.js +288 -0
  208. package/server/lib/opencode/v1-migration-topup.test.js +266 -0
  209. package/server/lib/opencode/v2-install.d.ts +8 -0
  210. package/server/lib/opencode/v2-install.js +158 -0
  211. package/server/lib/opencode/v2-install.test.js +124 -0
  212. package/server/lib/opencode/watcher.js +10 -3
  213. package/server/lib/opencode/watcher.test.js +17 -21
  214. package/server/lib/opencode/websearch-config.js +66 -0
  215. package/server/lib/package-manager.js +55 -68
  216. package/server/lib/package-manager.test.js +241 -75
  217. package/server/lib/permission-auto-accept/runtime.js +38 -22
  218. package/server/lib/permission-auto-accept/runtime.test.js +39 -17
  219. package/server/lib/quota/DOCUMENTATION.md +4 -0
  220. package/server/lib/quota/providers/xai.js +4 -4
  221. package/server/lib/relay/tunnel-host.js +4 -1
  222. package/server/lib/relay/tunnel-host.test.js +7 -0
  223. package/server/lib/routing/DOCUMENTATION.md +52 -21
  224. package/server/lib/routing/defaults.js +23 -6
  225. package/server/lib/routing/jev.js +17 -7
  226. package/server/lib/routing/routes.http.test.js +68 -33
  227. package/server/lib/routing/routes.js +65 -22
  228. package/server/lib/routing/runtime.js +145 -48
  229. package/server/lib/routing/runtime.test.js +79 -55
  230. package/server/lib/scheduled-tasks/DOCUMENTATION.md +4 -0
  231. package/server/lib/scheduled-tasks/issue-2710-double-execution.test.js +51 -46
  232. package/server/lib/scheduled-tasks/runtime.js +81 -74
  233. package/server/lib/scheduled-tasks/runtime.test.js +53 -1
  234. package/server/lib/session-assist/DOCUMENTATION.md +8 -3
  235. package/server/lib/session-assist/context.js +122 -46
  236. package/server/lib/session-assist/context.test.js +117 -49
  237. package/server/lib/session-assist/runtime.js +52 -22
  238. package/server/lib/session-assist/runtime.test.js +145 -173
  239. package/server/lib/session-goal/DOCUMENTATION.md +23 -15
  240. package/server/lib/session-goal/create.js +9 -12
  241. package/server/lib/session-goal/create.test.js +27 -28
  242. package/server/lib/session-goal/runtime.js +164 -77
  243. package/server/lib/session-goal/runtime.test.js +271 -519
  244. package/server/lib/session-knowledge/DOCUMENTATION.md +5 -0
  245. package/server/lib/session-knowledge/runtime.js +59 -41
  246. package/server/lib/session-knowledge/runtime.test.js +90 -20
  247. package/server/lib/small-model/DOCUMENTATION.md +154 -208
  248. package/server/lib/small-model/client.js +113 -0
  249. package/server/lib/small-model/index.js +296 -158
  250. package/server/lib/small-model/index.test.js +423 -256
  251. package/server/lib/small-model/routes.js +1 -1
  252. package/server/lib/spaces/DOCUMENTATION.md +807 -0
  253. package/server/lib/spaces/code-in-bait.js +185 -0
  254. package/server/lib/spaces/code-in.js +641 -0
  255. package/server/lib/spaces/code-in.test.js +1048 -0
  256. package/server/lib/spaces/errors.js +8 -0
  257. package/server/lib/spaces/exec-http.js +94 -0
  258. package/server/lib/spaces/gatekeeper-channel.js +202 -0
  259. package/server/lib/spaces/gatekeeper-channel.test.js +215 -0
  260. package/server/lib/spaces/gatekeeper-program.cjs +914 -0
  261. package/server/lib/spaces/gatekeeper-program.test.js +1391 -0
  262. package/server/lib/spaces/hardening.js +457 -0
  263. package/server/lib/spaces/hardening.test.js +368 -0
  264. package/server/lib/spaces/host-git.js +127 -0
  265. package/server/lib/spaces/host-git.test.js +137 -0
  266. package/server/lib/spaces/labels.js +234 -0
  267. package/server/lib/spaces/labels.test.js +219 -0
  268. package/server/lib/spaces/layout.js +184 -0
  269. package/server/lib/spaces/layout.test.js +30 -0
  270. package/server/lib/spaces/manager.js +82 -0
  271. package/server/lib/spaces/manager.test.js +114 -0
  272. package/server/lib/spaces/places/code-in.docker.live.test.js +216 -0
  273. package/server/lib/spaces/places/contract-suite.js +156 -0
  274. package/server/lib/spaces/places/contract.docker.live.test.js +7 -0
  275. package/server/lib/spaces/places/contract.test.js +6 -0
  276. package/server/lib/spaces/places/docker-engine.js +126 -0
  277. package/server/lib/spaces/places/docker-live-support.js +202 -0
  278. package/server/lib/spaces/places/docker-tools.js +186 -0
  279. package/server/lib/spaces/places/docker.js +587 -0
  280. package/server/lib/spaces/places/docker.test.js +1610 -0
  281. package/server/lib/spaces/places/escape-suite.js +1018 -0
  282. package/server/lib/spaces/places/escape.docker.live.test.js +7 -0
  283. package/server/lib/spaces/places/fake-docker.js +375 -0
  284. package/server/lib/spaces/places/memory-place.js +103 -0
  285. package/server/lib/spaces/places/packed.docker.live.test.js +77 -0
  286. package/server/lib/spaces/places/registry.js +43 -0
  287. package/server/lib/spaces/places/registry.test.js +50 -0
  288. package/server/lib/spaces/places/server.docker.live.test.js +225 -0
  289. package/server/lib/spaces/run-command.js +261 -0
  290. package/server/lib/spaces/run-command.test.js +396 -0
  291. package/server/lib/spaces/space-server.js +190 -0
  292. package/server/lib/spaces/space-server.test.js +335 -0
  293. package/server/lib/spaces/tools-filler.js +82 -0
  294. package/server/lib/spaces/tools-filler.test.js +148 -0
  295. package/server/lib/spaces/tools-pack.js +49 -0
  296. package/server/lib/spaces/tools-pack.test.js +57 -0
  297. package/server/lib/spaces/tools.js +138 -0
  298. package/server/lib/spaces/tools.test.js +153 -0
  299. package/server/lib/tts/openai-sdk.js +11 -0
  300. package/server/lib/tts/service.js +7 -5
  301. package/server/lib/tts/stt.js +3 -2
  302. package/server/lib/tunnels/DOCUMENTATION.md +2 -0
  303. package/server/lib/tunnels/routes.js +7 -0
  304. package/server/lib/tunnels/routes.test.js +55 -0
  305. package/server/lib/ui-auth/ui-auth.js +38 -2
  306. package/server/lib/ui-auth/ui-auth.test.js +42 -0
  307. package/server/lib/ui-auth/ui-passkeys.js +12 -10
  308. package/server/lib/walkthrough/DOCUMENTATION.md +10 -1
  309. package/server/lib/walkthrough/pull-request.js +61 -8
  310. package/server/lib/walkthrough/pull-request.test.js +54 -1
  311. package/server/lib/walkthrough/routes.js +20 -0
  312. package/server/lib/walkthrough/routes.test.js +19 -0
  313. package/server/opencode-proxy.test.js +190 -166
  314. package/server/opencode-worktree-readiness.test.js +5 -4
  315. package/dist/assets/DiffView-COVQhWGd.js +0 -4
  316. package/dist/assets/FilesView-B1V5JxFX.js +0 -13
  317. package/dist/assets/LinearIssuesView-D7FKg1XJ.js +0 -1
  318. package/dist/assets/MarkdownImageGallery-BrFjAVEf.js +0 -1
  319. package/dist/assets/MarkdownRendererImpl-DWepTafh.js +0 -12
  320. package/dist/assets/OnboardingScreen-Dyxxiqdt.js +0 -1
  321. package/dist/assets/PlanView-LW2z_EAP.js +0 -5
  322. package/dist/assets/PluginPane-B4tKno2h.js +0 -3
  323. package/dist/assets/SettingsView-DEaMulN9.js +0 -29
  324. package/dist/assets/SettingsWindow-FLDJXOgQ.js +0 -1
  325. package/dist/assets/SubmoduleDiffSummary-CvVwD-Vi.js +0 -1
  326. package/dist/assets/ToolOutputDialog-BiP0x2Rw.js +0 -15
  327. package/dist/assets/ToolPartDiffPreview-CkR4msKP.js +0 -8
  328. package/dist/assets/appThemeRegistry-BuUKhbYQ.js +0 -1
  329. package/dist/assets/de-DgxgFyGG.js +0 -10
  330. package/dist/assets/es-BFsZj5F_.js +0 -16
  331. package/dist/assets/fr-jdZ5KKQi.js +0 -14
  332. package/dist/assets/index-CKHjPKbq.js +0 -1
  333. package/dist/assets/index-Cbci4i1W.js +0 -40
  334. package/dist/assets/index-DqaMWNrC.css +0 -1
  335. package/dist/assets/ja-C5kKrhO4.js +0 -16
  336. package/dist/assets/ko-DXDTT_0O.js +0 -16
  337. package/dist/assets/main-CZALtVek.js +0 -896
  338. package/dist/assets/main-CgXMBNvG.js +0 -2
  339. package/dist/assets/miniChat-CwTmDixi.js +0 -2
  340. package/dist/assets/mobile-CLf2vCtO.js +0 -2
  341. package/dist/assets/pl-D-7x4Y8Q.js +0 -16
  342. package/dist/assets/pt-BR-CSBZrHa8.js +0 -16
  343. package/dist/assets/renderElectronMiniChatApp-C5gAFBk0.js +0 -2
  344. package/dist/assets/renderMobileApp-V4hYd32H.js +0 -25
  345. package/dist/assets/runtimeEndpointReset-DhlHCn-2.js +0 -25
  346. package/dist/assets/scheduledTasksApi-DzjbLd8P.js +0 -1
  347. package/dist/assets/tr-Dr-oJ22L.js +0 -7
  348. package/dist/assets/uk-9Nx83UcI.js +0 -16
  349. package/dist/assets/useAppFontEffects-khZXpFL_.js +0 -7333
  350. package/dist/assets/useRootScrollLock-DdvHf9Pt.js +0 -2
  351. package/dist/assets/vendor-cron-parser-CUcP7OfX.js +0 -2
  352. package/dist/assets/vendor-opencode-sdk-BJ73u-bH.js +0 -7
  353. package/dist/assets/zh-CN-Bxy_Hj3r.js +0 -16
  354. package/dist/assets/zh-TW-0BB4gpHM.js +0 -16
  355. package/server/lib/opencode/mcp-oauth-callback.test.js +0 -111
  356. package/server/lib/routing/feature-flag.js +0 -11
  357. package/server/lib/small-model/call.js +0 -851
  358. package/server/lib/small-model/call.test.js +0 -1292
  359. package/server/lib/small-model/catalog.js +0 -13
  360. package/server/lib/small-model/resolve.js +0 -131
  361. package/server/lib/small-model/resolve.test.js +0 -197
  362. package/server/lib/small-model/runtime-providers.js +0 -164
  363. package/server/lib/small-model/runtime-providers.test.js +0 -118
  364. package/server/lib/system-prompt/DOCUMENTATION.md +0 -36
  365. package/server/lib/system-prompt/runtime.js +0 -49
  366. package/server/lib/system-prompt/runtime.test.js +0 -76
  367. package/server/lib/walkthrough/reproduce-2607.test.js +0 -148
package/server/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { installOpenCodeV2, supportsOpenCodeV2Install } from './lib/opencode/v2-install.js';
2
+ import { describeOpenCodeCompatibility, readOpenCodeCliVersion, readExternalOpenCodeVersion } from './lib/opencode/compatibility.js';
1
3
  import 'reflect-metadata';
2
4
  import express from 'express';
3
5
  import compression from 'compression';
@@ -41,6 +43,7 @@ import { createTerminalRuntime } from './lib/terminal/runtime.js';
41
43
  import { createDictationRuntime } from './lib/dictation/runtime.js';
42
44
  import {
43
45
  createGlobalUiEventBroadcaster,
46
+ translateWireEvent,
44
47
  createGlobalMessageStreamHub,
45
48
  createMessageStreamWsRuntime,
46
49
  resolveDeltaCoalesceWindowMs,
@@ -50,6 +53,7 @@ import {
50
53
  import { createFsSearchRuntime as createFsSearchRuntimeFactory } from './lib/fs/search.js';
51
54
  import { createOpenCodeLifecycleRuntime } from './lib/opencode/lifecycle.js';
52
55
  import { createOpenCodeEnvRuntime } from './lib/opencode/env-runtime.js';
56
+ import { providedLoginShellEnvSnapshot } from './lib/opencode/login-shell-env.js';
53
57
  import { resolveOpenCodeEnvConfig } from './lib/opencode/env-config.js';
54
58
  import { createHmrStateRuntime } from './lib/opencode/hmr-state-runtime.js';
55
59
  import { createOpenCodeNetworkRuntime } from './lib/opencode/network-runtime.js';
@@ -70,10 +74,11 @@ import { createServerUtilsRuntime } from './lib/opencode/server-utils-runtime.js
70
74
  import { createStaticRoutesRuntime } from './lib/opencode/static-routes-runtime.js';
71
75
  import { createSettingsRuntime } from './lib/opencode/settings-runtime.js';
72
76
  import { createOpenCodeResolutionRuntime } from './lib/opencode/opencode-resolution-runtime.js';
77
+ import { runOpenCodeCliUpgrade } from './lib/opencode/cli-upgrade.js';
73
78
  import { resolveOpenCodeUpgradeCapability } from './lib/opencode/upgrade-capability.js';
74
79
  import { createBootstrapRuntime } from './lib/opencode/bootstrap-runtime.js';
75
80
  import { createSessionRuntime } from './lib/opencode/session-runtime.js';
76
- import { configureOpenCodeRuntimeProviders, resetOpenCodeRuntimeProviders } from './lib/small-model/runtime-providers.js';
81
+ import { configureOpenCodeRuntimeProviders, resetOpenCodeRuntimeProviders } from './lib/small-model/client.js';
77
82
  import { createOpenCodeWatcherRuntime } from './lib/opencode/watcher.js';
78
83
  import { createSessionAssistRuntime } from './lib/session-assist/runtime.js';
79
84
  import { createSessionGoalRuntime } from './lib/session-goal/runtime.js';
@@ -95,7 +100,11 @@ import { createPermissionAutoAcceptRuntime } from './lib/permission-auto-accept/
95
100
  import { createMessageQueueRuntime } from './lib/message-queue/runtime.js';
96
101
  import { createRoutingRuntime } from './lib/routing/runtime.js';
97
102
  import { createGracefulShutdownRuntime } from './lib/opencode/shutdown-runtime.js';
98
- import { stopAllGuestServices } from './lib/guests/service.js';
103
+ import { beginGuestServiceHost, beginGuestServiceShutdown, stopAllGuestServices } from './lib/guests/service.js';
104
+ import { findInstalledGuest } from './lib/guests/catalog.js';
105
+ import { extensionsPersistPath } from './lib/guests/persist.js';
106
+ import { createGuestSurfaceRuntime } from './lib/guests/surface.js';
107
+ import { BROWSER_PROVIDER_IDLE_MS } from '@openchamber/sdk';
99
108
  import { createProjectConfigRuntime } from './lib/projects/project-config.js';
100
109
  import { migrateLegacyUserDirs } from './lib/data-dir-migration.js';
101
110
  import { createProjectContextRuntime } from './lib/project-context/runtime.js';
@@ -111,15 +120,17 @@ import { createRelayService } from './lib/relay/service.js';
111
120
  import { createRelayHostLock } from './lib/relay/host-lock.js';
112
121
  import { createAgentToolRuntime } from './lib/agent-tool/runtime.js';
113
122
  import { createBrowserControlBroker } from './lib/browser-control/broker.js';
123
+ import { createBrowserControlRouter } from './lib/browser-control/provider.js';
114
124
  import { createDevServerScanner } from './lib/dev-servers/routes.js';
115
125
  import { createDevTunnelRuntime } from './lib/dev-tunnel/runtime.js';
116
126
  import { registerBrowserControlRoutes } from './lib/browser-control/routes.js';
117
- import { createSystemPromptRuntime } from './lib/system-prompt/runtime.js';
127
+ import { createManagedConfigRuntime } from './lib/opencode/managed-config-file.js';
118
128
  import { createOpenChamberSessionService } from './lib/openchamber-sessions/routes.js';
129
+ import { createSessionMetadataStore, createOpenCodeSessionMetadata } from './lib/openchamber-sessions/session-metadata-store.js';
119
130
  import { createScheduledTaskService } from './lib/scheduled-tasks/service.js';
120
131
  import { createOpenChamberControlService } from './lib/openchamber-control/service.js';
121
132
  import { OpenChamberControlError } from './lib/openchamber-control/error.js';
122
- import webPush from 'web-push';
133
+ import { createFileOpenRequester } from './lib/openchamber-control/file-open.js';
123
134
  import { applyConnectAttemptTimeout } from './lib/network-defaults.js';
124
135
 
125
136
  // Background CLI launches enter here in a fresh process, without CLI defaults.
@@ -305,7 +316,7 @@ const deleteImportedTheme = (...args) => themeRuntime.deleteImportedTheme(...arg
305
316
 
306
317
  let notificationTemplateRuntime = null;
307
318
  let agentToolRuntime = null;
308
- let systemPromptRuntime = null;
319
+ let managedConfigRuntime = null;
309
320
 
310
321
  const createTimeoutSignal = (...args) => notificationTemplateRuntime.createTimeoutSignal(...args);
311
322
  const formatProjectLabel = (...args) => notificationTemplateRuntime.formatProjectLabel(...args);
@@ -399,6 +410,7 @@ const settingsRuntime = createSettingsRuntime({
399
410
  normalizeManagedRemoteTunnelPresetTokens,
400
411
  syncManagedRemoteTunnelConfigWithPresets,
401
412
  upsertManagedRemoteTunnelToken,
413
+ onManagedPluginSettingsChanged: () => managedConfigRuntime?.refreshManagedConfigFile(),
402
414
  });
403
415
 
404
416
  const readSettingsFromDiskMigrated = (...args) => settingsRuntime.readSettingsFromDiskMigrated(...args);
@@ -416,7 +428,7 @@ const getUiSessionTokenFromRequest = (...args) => requestSecurityRuntime.getUiSe
416
428
  const pushRuntime = createPushRuntime({
417
429
  fsPromises,
418
430
  path,
419
- webPush,
431
+ loadWebPush: () => import('web-push').then((module) => module.default),
420
432
  PUSH_SUBSCRIPTIONS_FILE_PATH,
421
433
  readSettingsFromDiskMigrated,
422
434
  writeSettingsToDisk,
@@ -469,6 +481,7 @@ const notificationEmitterRuntime = createNotificationEmitterRuntime({
469
481
  getDesktopNotifyEnabled: () => ENV_DESKTOP_NOTIFY,
470
482
  desktopNotifyPrefix: DESKTOP_NOTIFY_PREFIX,
471
483
  getUiNotificationClients: () => uiNotificationClients,
484
+ getOpenChamberEventClients: () => uiOpenChamberEventClients,
472
485
  getBroadcastGlobalUiEvent: () => broadcastGlobalUiEvent,
473
486
  });
474
487
 
@@ -481,6 +494,51 @@ const broadcastGlobalUiEvent = createGlobalUiEventBroadcaster({
481
494
  });
482
495
  const broadcastUiNotification = (...args) => notificationEmitterRuntime.broadcastUiNotification(...args);
483
496
 
497
+ // OpenChamber-owned events (queue changes, archive state) travel on the shared
498
+ // control stream, not on OpenCode's event proxy. One broadcaster so every owner
499
+ // reaches the same clients.
500
+ const broadcastOpenChamberUiEvent = createGlobalUiEventBroadcaster({
501
+ sseClients: uiOpenChamberEventClients,
502
+ wsClients: uiNotificationWsClients,
503
+ writeSseEvent,
504
+ });
505
+
506
+ /**
507
+ * Per-session OpenChamber state (goal progress, the assist recap, the
508
+ * obligatory-context cursor, pinned notes) lives in OpenCode's session
509
+ * metadata. The store merge-patches it there and migrates what older
510
+ * OpenChamber versions kept in `sessions-metadata.json`.
511
+ */
512
+ const sessionMetadataStore = createSessionMetadataStore({
513
+ dataDir: OPENCHAMBER_DATA_DIR,
514
+ // Called, not captured: the OpenCode URL and auth helpers are declared
515
+ // further down and only ever used once a request arrives.
516
+ openCode: {
517
+ read: (...args) => createOpenCodeSessionMetadata({ buildOpenCodeUrl, getOpenCodeAuthHeaders }).read(...args),
518
+ write: (...args) => createOpenCodeSessionMetadata({ buildOpenCodeUrl, getOpenCodeAuthHeaders }).write(...args),
519
+ },
520
+ });
521
+
522
+ const readStoredSessionMetadata = (sessionID) => sessionMetadataStore.get(sessionID);
523
+
524
+ const persistSessionMetadataPatch = async (sessionID, patch, { directory = '' } = {}) => {
525
+ const metadata = await sessionMetadataStore.setSessionMetadata(sessionID, patch, { directory });
526
+ // The full merged object, so a client that missed an earlier patch does not
527
+ // have to reconstruct it.
528
+ broadcastOpenChamberUiEvent({
529
+ type: 'openchamber:session-metadata',
530
+ properties: { sessionID, metadata },
531
+ });
532
+ // The write itself arms the goal loop: it is the authoritative signal and
533
+ // does not depend on the event stream being connected.
534
+ // Called, not captured: the runtime is declared further down.
535
+ if (patch?.openchamber && 'goal' in patch.openchamber) {
536
+ void Promise.resolve(sessionGoalRuntime.notifyGoalChanged(sessionID, directory, metadata))
537
+ .catch((error) => console.warn('[session-goal] could not arm after a goal change:', error?.message ?? error));
538
+ }
539
+ return metadata;
540
+ };
541
+
484
542
  const sessionRuntime = createSessionRuntime({
485
543
  writeSseEvent,
486
544
  getNotificationClients: () => uiNotificationClients,
@@ -583,6 +641,12 @@ let runtimeManagedRemoteTunnelToken = '';
583
641
  let runtimeManagedRemoteTunnelHostname = '';
584
642
  let terminalRuntime = null;
585
643
  let dictationRuntime = null;
644
+ // Built once the HTTP server exists (it hooks `upgrade`); the browser
645
+ // provider router is built earlier and reaches it through this holder.
646
+ let guestSurfaceRuntime = null;
647
+ let realtimeProxyRuntime = null;
648
+ let relayServiceInstance = null;
649
+ let relayReconcileTimer = null;
586
650
  let messageStreamRuntime = null;
587
651
  const userProvidedOpenCodePassword = hmrStateRuntime.getUserProvidedOpenCodePassword(hmrState);
588
652
  const initialOpenCodeAuthState = hmrStateRuntime.resolveOpenCodeAuthFromState({
@@ -739,6 +803,7 @@ const openCodeEnvRuntime = createOpenCodeEnvRuntime({
739
803
  state: openCodeEnvState,
740
804
  normalizeDirectoryPath,
741
805
  readSettingsFromDiskMigrated,
806
+ providedLoginShellEnvSnapshot,
742
807
  });
743
808
 
744
809
  const applyLoginShellEnvSnapshot = (...args) => openCodeEnvRuntime.applyLoginShellEnvSnapshot(...args);
@@ -800,6 +865,7 @@ const notificationTriggerRuntime = createNotificationTriggerRuntime({
800
865
  isAnyInteractiveClientVisible,
801
866
  buildOpenCodeUrl,
802
867
  getOpenCodeAuthHeaders,
868
+ readSessionMetadata: readStoredSessionMetadata,
803
869
  });
804
870
 
805
871
  const maybeSendPushForTrigger = (...args) => notificationTriggerRuntime.maybeSendPushForTrigger(...args);
@@ -810,12 +876,19 @@ const sessionAssistRuntime = createSessionAssistRuntime({
810
876
  buildOpenCodeUrl,
811
877
  getOpenCodeAuthHeaders,
812
878
  getSmallModelService: async () => import('./lib/small-model/index.js'),
879
+ persistSessionAssist: (sessionID, directory, assist) =>
880
+ persistSessionMetadataPatch(sessionID, { openchamber: { assist } }, { directory }),
881
+ // Declared further down; only ever called after startup.
882
+ isSessionArchived: (sessionID) => openChamberSessionService.archiveStore.isArchived(sessionID),
813
883
  });
814
884
 
815
885
  const sessionGoalRuntime = createSessionGoalRuntime({
816
886
  buildOpenCodeUrl,
817
887
  getOpenCodeAuthHeaders,
818
888
  getSmallModelService: async () => import('./lib/small-model/index.js'),
889
+ readSessionMetadata: readStoredSessionMetadata,
890
+ persistSessionGoal: (sessionID, directory, goal) =>
891
+ persistSessionMetadataPatch(sessionID, { openchamber: { goal } }, { directory }),
819
892
  emitGoalNotification: async ({ sessionId, directory, status, goal }) => {
820
893
  // The goal settle notification replaces the per-turn ready notifications
821
894
  // (suppressed while the goal is active) — so it obeys the same toggle.
@@ -863,29 +936,18 @@ const sessionKnowledgeRuntime = createSessionKnowledgeRuntime({
863
936
  // reference here would read it before it exists.
864
937
  resolveProjectId: (directory) => resolveMemoryProjectId(directory),
865
938
  isAgentMemoryEnabled,
866
- openCodeFetch: async (fetchPath, { directory, method = 'GET', body } = {}) => {
867
- const params = new URLSearchParams();
868
- if (directory) params.set('directory', directory);
869
- const search = params.toString();
870
- const response = await fetch(`${buildOpenCodeUrl(fetchPath, '')}${search ? `?${search}` : ''}`, {
871
- method,
872
- headers: {
873
- Accept: 'application/json',
874
- ...(body ? { 'Content-Type': 'application/json' } : {}),
875
- ...getOpenCodeAuthHeaders(),
876
- },
877
- ...(body ? { body: JSON.stringify(body) } : {}),
878
- signal: AbortSignal.timeout(15_000),
879
- });
880
- if (!response.ok) throw new Error(`OpenCode ${method} ${fetchPath} failed with ${response.status}`);
881
- return response.json().catch(() => null);
882
- },
939
+ readSessionMetadata: readStoredSessionMetadata,
940
+ // Pins and the delivered-signature cursor are read from and written to
941
+ // OpenChamber's own store; nothing here talks to OpenCode any more.
942
+ persistSessionMetadata: (sessionID, directory, patch) => persistSessionMetadataPatch(sessionID, patch, { directory }),
883
943
  });
884
944
 
885
945
  const contextObligatoryRuntime = createContextObligatoryRuntime({
886
946
  buildOpenCodeUrl,
887
947
  getOpenCodeAuthHeaders,
888
948
  sessionKnowledgeRuntime,
949
+ readSessionMetadata: readStoredSessionMetadata,
950
+ persistContextCursor: (sessionID, directory, patch) => persistSessionMetadataPatch(sessionID, patch, { directory }),
889
951
  });
890
952
 
891
953
  const linearSessionStatusRuntime = createLinearSessionStatusRuntime();
@@ -897,17 +959,8 @@ const globalMessageStreamHub = createGlobalMessageStreamHub({
897
959
  deltaCoalesceWindowMs: resolveDeltaCoalesceWindowMs(),
898
960
  });
899
961
 
900
- // OpenChamber-owned events for the UI control stream (SSE) plus the WS fan-out.
901
- // OpenCode's /global/event proxy cannot carry them.
902
- const broadcastOpenChamberUiEvent = createGlobalUiEventBroadcaster({
903
- sseClients: uiOpenChamberEventClients,
904
- wsClients: uiNotificationWsClients,
905
- writeSseEvent,
906
- });
907
-
908
- // Jev model routing and the permission safety net. Dark unless
909
- // OPENCHAMBER_ROUTING_ENABLE is set; every failure keeps the user's own model
910
- // or the auto-accept reply it was asked about.
962
+ // Jev model routing and the permission safety net. Every failure keeps the
963
+ // user's own model or the auto-accept reply it was asked about.
911
964
  const routingRuntime = createRoutingRuntime({
912
965
  dataDir: OPENCHAMBER_DATA_DIR,
913
966
  buildOpenCodeUrl,
@@ -937,8 +990,10 @@ const messageQueueRuntime = createMessageQueueRuntime({
937
990
  buildOpenCodeUrl,
938
991
  getOpenCodeAuthHeaders,
939
992
  sessionKnowledgeRuntime,
993
+ // OpenCode's event SSE proxy cannot carry OpenChamber-owned events. Use the
994
+ // shared control stream for SSE clients and the existing WS fan-out.
940
995
  broadcastGlobalUiEvent: broadcastOpenChamberUiEvent,
941
- resolvePromptBody: (body, target) => routingRuntime.resolvePromptBody(body, target),
996
+ resolveAutoSelection: (send) => routingRuntime.resolveAutoSelection(send),
942
997
  onPromptSent: (sessionId) => sessionRuntime.markUserMessageSent(sessionId),
943
998
  dataDir: OPENCHAMBER_DATA_DIR,
944
999
  });
@@ -961,23 +1016,41 @@ const openCodeWatcherRuntime = createOpenCodeWatcherRuntime({
961
1016
  // directory to route its own OpenCode calls to the right instance.
962
1017
  console.log('[session-assist] listening for session events');
963
1018
  globalMessageStreamHub.subscribeEvent((event) => {
964
- const raw = event?.payload;
965
- const payload = raw?.payload && typeof raw.payload === 'object' ? raw.payload : raw;
966
- if (!payload || typeof payload !== 'object') return;
967
1019
  const directory = typeof event?.directory === 'string' && event.directory && event.directory !== 'global'
968
1020
  ? event.directory
969
1021
  : '';
970
- sessionAssistRuntime.processPayload(payload, directory);
971
- sessionGoalRuntime.processPayload(payload, directory);
972
- contextObligatoryRuntime.processPayload(payload, directory);
973
- linearSessionStatusRuntime.processPayload(payload);
1022
+ // The hub translates v2 wire events into the server's vocabulary once; these
1023
+ // consumers were written against it and stay unaware of the wire shape.
1024
+ for (const payload of event?.translated?.() ?? []) {
1025
+ // The user cancelled the turn: stop the OpenChamber tool actions that
1026
+ // turn still has running (a browser action, a memory write). OpenCode 2
1027
+ // gives the plugin no abort signal, so this is where the cancel lands.
1028
+ if (payload.type === 'session.idle' && payload.properties?.aborted === true) {
1029
+ agentToolRuntime?.abortSession?.(payload.properties.sessionID);
1030
+ }
1031
+ sessionAssistRuntime.processPayload(payload, directory || payload.properties?.directory || '');
1032
+ sessionGoalRuntime.processPayload(payload, directory || payload.properties?.directory || '');
1033
+ contextObligatoryRuntime.processPayload(payload, directory || payload.properties?.directory || '');
1034
+ linearSessionStatusRuntime.processPayload(payload);
1035
+ }
974
1036
  });
975
1037
 
1038
+ /**
1039
+ * Browser bridges hand us the raw v2 wire payload (they forward it untouched to
1040
+ * the client). The synthetic OpenChamber frames the UI also expects are derived
1041
+ * from the translated event, so the translation happens here.
1042
+ */
976
1043
  const processForwardedEventPayload = (payload, emitSyntheticEvent) => {
977
1044
  if (!payload || typeof payload !== 'object' || typeof emitSyntheticEvent !== 'function') {
978
1045
  return;
979
1046
  }
980
1047
 
1048
+ for (const translated of translateWireEvent(payload)) {
1049
+ processForwardedServerEvent(translated, emitSyntheticEvent);
1050
+ }
1051
+ };
1052
+
1053
+ const processForwardedServerEvent = (payload, emitSyntheticEvent) => {
981
1054
  maybeCacheSessionInfoFromEvent(payload);
982
1055
 
983
1056
  if (payload.type !== 'session.status') {
@@ -1028,6 +1101,10 @@ const processForwardedEventPayload = (payload, emitSyntheticEvent) => {
1028
1101
 
1029
1102
 
1030
1103
  const serverUtilsRuntime = createServerUtilsRuntime({
1104
+ // Read lazily: the archive store is created with the session service further
1105
+ // down, while the proxy is registered later still.
1106
+ getArchivedSessions: () => openChamberSessionService.archiveStore.getAll(),
1107
+ getStoredSessionMetadata: () => sessionMetadataStore.listUnmigrated(),
1031
1108
  fs,
1032
1109
  os,
1033
1110
  path,
@@ -1264,25 +1341,21 @@ const openCodeLifecycleRuntime = createOpenCodeLifecycleRuntime({
1264
1341
  console.warn('Failed to reconcile sessions after OpenCode restart:', error?.message ?? error);
1265
1342
  }
1266
1343
  },
1267
- getManagedOpenCodeEnv: async () => {
1268
- const settings = await readSettingsFromDiskMigrated().catch(() => null);
1269
- // Each capability is its own tool and its own switch; the plugin is only
1270
- // injected while at least one of them is on.
1271
- const includeControl = settings?.agentControlToolEnabled !== false;
1272
- const includeWeb = settings?.agentWebToolEnabled !== false;
1273
- const includeMemory = isAgentMemoryFeatureAvailable() && settings?.agentMemoryToolEnabled === true;
1274
- const managedEnv = includeControl || includeWeb || includeMemory
1275
- ? await (agentToolRuntime?.prepareManagedOpenCodeEnv({ includeControl, includeWeb, includeMemory }) || {})
1276
- : {};
1277
-
1278
- if (settings?.optimizeSystemPrompt === true) {
1279
- const configContent = managedEnv.OPENCODE_CONFIG_CONTENT ?? process.env.OPENCODE_CONFIG_CONTENT;
1280
- Object.assign(managedEnv, await systemPromptRuntime.prepareManagedOpenCodeEnv(configContent));
1281
- }
1282
- return managedEnv;
1283
- },
1344
+ getManagedOpenCodeEnv: async () => (managedConfigRuntime ? managedConfigRuntime.buildManagedChildEnv() : {}),
1284
1345
  });
1285
1346
 
1347
+ const getOpenCodeCompatibility = async () => {
1348
+ if (isExternalOpenCode || ENV_SKIP_OPENCODE_START) {
1349
+ const base = ENV_CONFIGURED_OPENCODE_HOST?.origin || openCodeBaseUrl || `http://127.0.0.1:${openCodePort || ENV_EFFECTIVE_PORT}`;
1350
+ const version = await readExternalOpenCodeVersion(base, getOpenCodeAuthHeaders()).catch(() => null);
1351
+ return describeOpenCodeCompatibility(version, 'external', false);
1352
+ }
1353
+ const binary = ensureOpencodeCliEnv();
1354
+ const installation = isBundledOpenCodeCliPath(binary) ? 'bundled' : 'managed';
1355
+ const version = await readOpenCodeCliVersion(resolveManagedOpenCodeLaunchSpec(binary)).catch(() => null);
1356
+ return describeOpenCodeCompatibility(version, installation, supportsOpenCodeV2Install());
1357
+ };
1358
+
1286
1359
  const getOpenCodeUpgradeCapability = () => {
1287
1360
  const activeBinary = lastOpenCodeLaunchDiagnostics?.sourceBinary
1288
1361
  || lastOpenCodeLaunchDiagnostics?.binary
@@ -1311,6 +1384,8 @@ const scheduledTasksRuntime = createScheduledTasksRuntime({
1311
1384
  getOpenCodeAuthHeaders,
1312
1385
  waitForOpenCodeReady,
1313
1386
  sessionKnowledgeRuntime,
1387
+ persistSessionGoal: (sessionID, directory, goal) =>
1388
+ persistSessionMetadataPatch(sessionID, { openchamber: { goal } }, { directory }),
1314
1389
  setSessionAutoAccept: (sessionId, enabled, directory) => permissionAutoAcceptRuntime.setSessionPolicy(sessionId, enabled, directory),
1315
1390
  emitTaskRunEvent: (event) => {
1316
1391
  for (const client of uiOpenChamberEventClients) {
@@ -1399,7 +1474,13 @@ const openChamberSessionService = createOpenChamberSessionService({
1399
1474
  waitForOpenCodeReady,
1400
1475
  emitSessionCreatedEvent,
1401
1476
  sessionKnowledgeRuntime,
1402
- resolvePromptBody: (body, target) => routingRuntime.resolvePromptBody(body, target),
1477
+ // OpenCode 2.x has no archive route, so the state is OpenChamber's own and
1478
+ // lives beside the instance it describes.
1479
+ dataDir: OPENCHAMBER_DATA_DIR,
1480
+ sessionMetadataStore,
1481
+ persistSessionMetadata: persistSessionMetadataPatch,
1482
+ broadcastGlobalUiEvent: broadcastOpenChamberUiEvent,
1483
+ resolveAutoSelection: (input) => routingRuntime.resolveAutoSelection(input),
1403
1484
  });
1404
1485
  // Browser actions are published to whichever OpenChamber clients are connected;
1405
1486
  // the one owning the browser panel answers. `emitRequest` returns the number of
@@ -1432,6 +1513,56 @@ const browserControlBroker = createBrowserControlBroker({
1432
1513
  },
1433
1514
  });
1434
1515
 
1516
+ /**
1517
+ * Tells every client the selected browser provider was dropped back to the
1518
+ * in-app browser, so Settings shows the change and the user hears why.
1519
+ */
1520
+ const emitBrowserProviderResetEvent = ({ guestId, guestName }) => {
1521
+ for (const client of uiOpenChamberEventClients) {
1522
+ try {
1523
+ writeSseEvent(client, {
1524
+ type: 'openchamber:browser-provider-reset',
1525
+ properties: { guestId, guestName },
1526
+ });
1527
+ } catch {
1528
+ uiOpenChamberEventClients.delete(client);
1529
+ }
1530
+ }
1531
+ };
1532
+ // Every browser action passes through here: the in-app view by default, or an
1533
+ // extension service chosen in Settings → OpenChamber Tools.
1534
+ const browserControlRouter = createBrowserControlRouter({
1535
+ broker: browserControlBroker,
1536
+ readSettings: () => readSettingsFromDiskMigrated(),
1537
+ persistSettings: (changes) => persistSettings(changes),
1538
+ findGuest: (id) => findInstalledGuest(id, extensionsPersistPath(OPENCHAMBER_DATA_DIR)),
1539
+ persistPath: extensionsPersistPath(OPENCHAMBER_DATA_DIR),
1540
+ emitProviderReset: emitBrowserProviderResetEvent,
1541
+ createId: () => `browser-${crypto.randomUUID()}`,
1542
+ surfaceControl: {
1543
+ userControls: (guestId) => guestSurfaceRuntime?.userControls(guestId) ?? false,
1544
+ noteAgentActivity: (guestId) => guestSurfaceRuntime?.noteAgentActivity(guestId),
1545
+ },
1546
+ });
1547
+
1548
+ // "Show this file" reaches every connected client; the ones showing that
1549
+ // project open it. Nothing comes back, so the count of clients reached is the
1550
+ // only signal the agent gets.
1551
+ const fileOpenRequester = createFileOpenRequester({
1552
+ emit: (request) => {
1553
+ let delivered = 0;
1554
+ for (const client of uiOpenChamberEventClients) {
1555
+ try {
1556
+ writeSseEvent(client, { type: 'openchamber:file-open-request', properties: request });
1557
+ delivered += 1;
1558
+ } catch {
1559
+ uiOpenChamberEventClients.delete(client);
1560
+ }
1561
+ }
1562
+ return delivered;
1563
+ },
1564
+ });
1565
+
1435
1566
  const openChamberControlService = createOpenChamberControlService({
1436
1567
  readSettingsFromDiskMigrated,
1437
1568
  sanitizeProjects,
@@ -1440,7 +1571,8 @@ const openChamberControlService = createOpenChamberControlService({
1440
1571
  waitForOpenCodeReady,
1441
1572
  sessionService: openChamberSessionService,
1442
1573
  scheduledTaskService,
1443
- browserControl: browserControlBroker,
1574
+ browserControl: browserControlRouter,
1575
+ fileOpen: fileOpenRequester,
1444
1576
  agentMemoryActions: createAgentMemoryActions({
1445
1577
  agentMemoryRuntime,
1446
1578
  createError: (message, status) => new OpenChamberControlError(message, status),
@@ -1474,6 +1606,11 @@ const bootstrapOpenCodeAtStartup = async (...args) => {
1474
1606
  void ensureGlobalWatcherStarted().catch((error) => {
1475
1607
  console.warn(`Global event watcher startup failed: ${error?.message || error}`);
1476
1608
  });
1609
+ // Entries the sweep cannot push now stay in the legacy file and are pushed on
1610
+ // the session's next write or the next start.
1611
+ void waitForOpenCodeReady()
1612
+ .then(() => sessionMetadataStore.migrateLegacy())
1613
+ .catch((error) => console.warn('[openchamber-sessions] session metadata migration failed:', error?.message ?? error));
1477
1614
  };
1478
1615
  const killProcessOnPort = (...args) => openCodeLifecycleRuntime.killProcessOnPort(...args);
1479
1616
  const waitForPortRelease = (...args) => openCodeLifecycleRuntime.waitForPortRelease(...args);
@@ -1526,11 +1663,19 @@ const gracefulShutdownRuntime = createGracefulShutdownRuntime({
1526
1663
  },
1527
1664
  tunnelAuthController,
1528
1665
  scheduledTasksRuntime,
1666
+ beginGuestServiceShutdown,
1667
+ stopAllGuestServices,
1668
+ getGuestSurfaceRuntime: () => guestSurfaceRuntime,
1669
+ getRealtimeProxyRuntime: () => realtimeProxyRuntime,
1670
+ getDictationRuntime: () => dictationRuntime,
1671
+ getRelayService: () => relayServiceInstance,
1672
+ getRelayReconcileTimer: () => relayReconcileTimer,
1529
1673
  });
1530
1674
 
1531
1675
  const gracefulShutdown = (...args) => gracefulShutdownRuntime.gracefulShutdown(...args);
1532
1676
 
1533
1677
  async function main(options = {}) {
1678
+ beginGuestServiceHost();
1534
1679
  const port = Number.isFinite(options.port) && options.port >= 0 ? Math.trunc(options.port) : DEFAULT_PORT;
1535
1680
  const host = typeof options.host === 'string' && options.host.length > 0 ? options.host : undefined;
1536
1681
  const effectiveBindHost = host
@@ -1544,6 +1689,8 @@ async function main(options = {}) {
1544
1689
  dataDir: OPENCHAMBER_DATA_DIR,
1545
1690
  env: process.env,
1546
1691
  executeAction: (...args) => openChamberControlService.execute(...args),
1692
+ // A v2 tool call carries no directory, only the session it runs in.
1693
+ resolveSessionDirectory: (sessionID) => openChamberControlService.resolveSessionDirectory(sessionID),
1547
1694
  getActivePort: () => {
1548
1695
  const address = server?.address?.();
1549
1696
  return typeof address === 'object' && address ? address.port : null;
@@ -1551,10 +1698,14 @@ async function main(options = {}) {
1551
1698
  // A pipe listener reports a string here, which has no address to bind back to.
1552
1699
  getActiveHost: () => server?.address?.()?.address ?? null,
1553
1700
  });
1554
- systemPromptRuntime = createSystemPromptRuntime({
1701
+ managedConfigRuntime = createManagedConfigRuntime({
1555
1702
  fsPromises,
1556
1703
  path,
1557
1704
  dataDir: OPENCHAMBER_DATA_DIR,
1705
+ env: process.env,
1706
+ agentToolRuntime,
1707
+ readSettings: () => readSettingsFromDiskMigrated(),
1708
+ isAgentMemoryAvailable: isAgentMemoryFeatureAvailable,
1558
1709
  });
1559
1710
 
1560
1711
  // Pairing transports advertised to the create-device dialog. LAN reachability is
@@ -1744,13 +1895,7 @@ async function main(options = {}) {
1744
1895
  }));
1745
1896
  expressApp = app;
1746
1897
  server = http.createServer(app);
1747
- let realtimeProxyRuntime = { stop: () => {} };
1748
-
1749
- // The relay service is constructed further below (it depends on the tunnel
1750
- // runtime's active port). The pairing routes registered here only read the
1751
- // relay candidate lazily at request time, so a late-bound holder is enough.
1752
- let relayServiceInstance = null;
1753
-
1898
+ gracefulShutdownRuntime.trackServerConnections(server);
1754
1899
  // Same pattern for the tunnel runtime: created after the base routes so
1755
1900
  // /api/system/info resolves port + tunnel URL lazily at request time.
1756
1901
  let tunnelRuntimeContextHolder = null;
@@ -1877,7 +2022,7 @@ async function main(options = {}) {
1877
2022
  isRequestOriginAllowed,
1878
2023
  });
1879
2024
 
1880
- const tunnelRuntimeContext = tunnelWiringRuntime.initialize(app, port);
2025
+ const tunnelRuntimeContext = tunnelWiringRuntime.initialize(app, port, Boolean(uiPassword?.trim()));
1881
2026
  const { tunnelService, startTunnelWithNormalizedRequest } = tunnelRuntimeContext;
1882
2027
  tunnelRuntimeContextHolder = tunnelRuntimeContext;
1883
2028
 
@@ -1958,6 +2103,10 @@ async function main(options = {}) {
1958
2103
  createFsSearchRuntime: createFsSearchRuntimeFactory,
1959
2104
  openchamberDataDir: OPENCHAMBER_DATA_DIR,
1960
2105
  openchamberVersion: OPENCHAMBER_VERSION,
2106
+ onGuestDeactivated: async (event) => {
2107
+ guestSurfaceRuntime?.endForGuest(event.guestId);
2108
+ return browserControlRouter.handleGuestDeactivated(event);
2109
+ },
1961
2110
  builtInExtensionsDir: options.builtInExtensionsDir,
1962
2111
  openchamberUserConfigRoot: OPENCHAMBER_USER_CONFIG_ROOT,
1963
2112
  managedChatsRoot: OPENCHAMBER_CHATS_DIR,
@@ -1971,6 +2120,19 @@ async function main(options = {}) {
1971
2120
  refreshOpenCodeAfterConfigChange,
1972
2121
  getOpenCodeResolutionSnapshot,
1973
2122
  getOpenCodeUpgradeCapability,
2123
+ getOpenCodeCompatibility,
2124
+ installOpenCodeV2: async () => {
2125
+ const binary = await installOpenCodeV2({
2126
+ env: { ...getLoginShellEnvSnapshot(), ...process.env, PATH: buildManagedOpenCodePath() },
2127
+ });
2128
+ await persistSettings({ opencodeBinary: binary });
2129
+ await refreshOpenCodeAfterConfigChange('OpenCode v2 installation');
2130
+ await waitForOpenCodeReady();
2131
+ },
2132
+ upgradeOpenCodeCli: () => runOpenCodeCliUpgrade(
2133
+ resolveManagedOpenCodeLaunchSpec(lastOpenCodeLaunchDiagnostics?.sourceBinary || resolvedOpencodeBinary),
2134
+ { env: { ...getLoginShellEnvSnapshot(), ...process.env, PATH: buildManagedOpenCodePath() }, cwd: os.homedir() },
2135
+ ),
1974
2136
  formatSettingsResponse,
1975
2137
  readSettingsFromDisk,
1976
2138
  readSettingsFromDiskMigrated,
@@ -2004,6 +2166,17 @@ async function main(options = {}) {
2004
2166
  routingRuntime,
2005
2167
  });
2006
2168
 
2169
+ // After bootstrap: the upgrade gate needs the real UI auth controller.
2170
+ guestSurfaceRuntime = createGuestSurfaceRuntime({
2171
+ server,
2172
+ uiAuthController,
2173
+ isRequestOriginAllowed,
2174
+ rejectWebSocketUpgrade,
2175
+ persistPath: extensionsPersistPath(OPENCHAMBER_DATA_DIR),
2176
+ findGuest: (id) => findInstalledGuest(id, extensionsPersistPath(OPENCHAMBER_DATA_DIR)),
2177
+ idleStopMs: BROWSER_PROVIDER_IDLE_MS,
2178
+ });
2179
+
2007
2180
  const startupPipelineResult = await startupPipelineRuntime.run({
2008
2181
  app,
2009
2182
  server,
@@ -2073,7 +2246,7 @@ async function main(options = {}) {
2073
2246
  // --relay` writes a pending relay session straight to the on-disk store, and
2074
2247
  // pending sessions expire without any request hitting us. Poll reconcile so a
2075
2248
  // headless instance picks the relay up (or drops it) within a minute.
2076
- const relayReconcileTimer = setInterval(() => {
2249
+ relayReconcileTimer = setInterval(() => {
2077
2250
  void relayService.reconcile();
2078
2251
  }, 60_000);
2079
2252
  relayReconcileTimer.unref?.();
@@ -2091,6 +2264,7 @@ async function main(options = {}) {
2091
2264
  scheduledTasks: scheduledTasksRuntime.getStatus(),
2092
2265
  }),
2093
2266
  isReady: () => isOpenCodeReady,
2267
+ getManagedOpenCodePreflight: () => openCodeLifecycleRuntime.getManagedOpenCodePreflight(),
2094
2268
  restartOpenCode: () => restartOpenCode(),
2095
2269
  getOpenCodeProcessInfo: () => {
2096
2270
  const managed = Boolean((openCodeProcess || openCodePort) && !ENV_SKIP_OPENCODE_START && !isExternalOpenCode);
@@ -2106,26 +2280,7 @@ async function main(options = {}) {
2106
2280
  port: managed ? openCodePort : null,
2107
2281
  };
2108
2282
  },
2109
- stop: async (shutdownOptions = {}) => {
2110
- realtimeProxyRuntime.stop();
2111
- clearInterval(relayReconcileTimer);
2112
- try {
2113
- relayService.stop();
2114
- } catch {
2115
- // best-effort teardown of the relay host client
2116
- }
2117
- try {
2118
- dictationRuntime?.stop?.();
2119
- } catch {
2120
- // best-effort shutdown of the dictation worker
2121
- }
2122
- // Guest services are child processes; leaving before SIGTERM lands
2123
- // (and the SIGKILL fallback fires) orphans them on the user's machine.
2124
- await stopAllGuestServices().catch(() => {
2125
- // best-effort teardown of guest service processes
2126
- });
2127
- return gracefulShutdown({ exitProcess: shutdownOptions.exitProcess ?? false });
2128
- }
2283
+ stop: (shutdownOptions = {}) => gracefulShutdown({ exitProcess: shutdownOptions.exitProcess ?? false }),
2129
2284
  };
2130
2285
  }
2131
2286