@vantran-se/openchamber-web 1.24.4 → 2.0.2

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-B4a0JkUz.js → CodeMirrorCommentWidgets-B82Oye3V.js} +1 -1
  5. package/dist/assets/DiffView-DJLmWn6Z.js +4 -0
  6. package/dist/assets/FilesView-DjksmZRo.js +17 -0
  7. package/dist/assets/{GitView-Byu2DY7s.js → GitView-DiUsUIgr.js} +4 -4
  8. package/dist/assets/{GuestAttachDialog-B808E0-d.js → GuestAttachDialog-CYwWYLr3.js} +1 -1
  9. package/dist/assets/GuestSurfacePane-CmctyRI4.js +1 -0
  10. package/dist/assets/{JsonTreeView-VW_7czo3.js → JsonTreeView-DOHHcbgJ.js} +1 -1
  11. package/dist/assets/LinearIssuesView-DaqnylcV.js +1 -0
  12. package/dist/assets/MarkdownImageGallery-HJNvWt7L.js +1 -0
  13. package/dist/assets/MarkdownRendererImpl-nDZRGg2I.js +12 -0
  14. package/dist/assets/OnboardingScreen-C2B5Bsof.js +1 -0
  15. package/dist/assets/{PatchDiff-DCjGhlYV.js → PatchDiff-C4FLBjpt.js} +1 -1
  16. package/dist/assets/{PierreDiffViewer-CEDZNkU2.js → PierreDiffViewer-C_1S9c9n.js} +1 -1
  17. package/dist/assets/PlanView-_eZvb-G5.js +5 -0
  18. package/dist/assets/PluginPane-sM8fcZIV.js +3 -0
  19. package/dist/assets/SettingsView-BRfr46hb.js +29 -0
  20. package/dist/assets/SettingsWindow-CcUDwQHg.js +1 -0
  21. package/dist/assets/SubmoduleDiffSummary-CrN1ZGwl.js +1 -0
  22. package/dist/assets/ToolOutputDialog-Cij4jI09.js +15 -0
  23. package/dist/assets/ToolPartDiffPreview-BXzwQ-JY.js +8 -0
  24. package/dist/assets/{VirtualizedFileDiff-NU0FHFhT.js → VirtualizedFileDiff-DSWTLJNH.js} +4 -4
  25. package/dist/assets/{WalkthroughView-BZyjhqHv.js → WalkthroughView-CpUUgY8H.js} +2 -2
  26. package/dist/assets/appThemeRegistry-B5tHTkR8.js +1 -0
  27. package/dist/assets/{commitAndPush-BDftrjr6.js → commitAndPush-D7D8qV8p.js} +1 -1
  28. package/dist/assets/{computeVirtualFileMetrics-DlWlEM3x.js → computeVirtualFileMetrics-cq9uQ30i.js} +1 -1
  29. package/dist/assets/de-CUO1-KqF.js +10 -0
  30. package/dist/assets/es-BlbC6sGJ.js +16 -0
  31. package/dist/assets/fr-D2nwe_0W.js +14 -0
  32. package/dist/assets/index-BQOoYIOu.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-CO4e5J_S.js → isDiffPlainText-D0obJ2p8.js} +1 -1
  36. package/dist/assets/{isFilePlainText-ue6kCou7.js → isFilePlainText-DB3_rjyW.js} +1 -1
  37. package/dist/assets/ja-CA7vnDsZ.js +16 -0
  38. package/dist/assets/ko-Chy6a9l-.js +16 -0
  39. package/dist/assets/main-B9JFK3vF.js +896 -0
  40. package/dist/assets/main-Bhiqnrhd.js +2 -0
  41. package/dist/assets/{markdownCore-CK48LG0z.js → markdownCore-tfqOFaBd.js} +4 -4
  42. package/dist/assets/miniChat-B0UOL5zA.js +2 -0
  43. package/dist/assets/mobile-BJppFIEo.js +2 -0
  44. package/dist/assets/{patchFileDiff-D7QVlovD.js → patchFileDiff-Db6KuwCP.js} +3 -3
  45. package/dist/assets/pl-CTR5A_1P.js +16 -0
  46. package/dist/assets/pt-BR-BE1O1KEx.js +16 -0
  47. package/dist/assets/renderElectronMiniChatApp-Yz5sfoFh.js +2 -0
  48. package/dist/assets/renderMobileApp-QQ-yB8aY.js +25 -0
  49. package/dist/assets/runtimeEndpointReset-DKDdzRzm.js +27 -0
  50. package/dist/assets/scheduledTasksApi-C5sCuNqf.js +1 -0
  51. package/dist/assets/{shikiHighlight-BPu3JiQs.js → shikiHighlight-xURoo5t_.js} +1 -1
  52. package/dist/assets/{textMateThemeFromAppTheme-DWqRPo9A.js → textMateThemeFromAppTheme-BZLGuYTU.js} +1 -1
  53. package/dist/assets/tr-Bh5vK6cW.js +7 -0
  54. package/dist/assets/uk-CLDkZFy_.js +16 -0
  55. package/dist/assets/useAppFontEffects-BxrtCnfR.js +7337 -0
  56. package/dist/assets/{useInlineCommentController-CgS0fnw_.js → useInlineCommentController-CeXuR-SR.js} +2 -2
  57. package/dist/assets/useRootScrollLock-DgWxezc1.js +2 -0
  58. package/dist/assets/{vendor-codemirror-language-data-Bx2EHc1O.js → vendor-codemirror-language-data-DOuaQUZ0.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-DxX8bZ1o.js → web-components-63H1h21j.js} +2 -2
  64. package/dist/assets/zh-CN-DODgcmYj.js +16 -0
  65. package/dist/assets/zh-TW-ByNfIwLA.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-B2CD9wC8.js +0 -4
  316. package/dist/assets/FilesView-C4vMFclc.js +0 -13
  317. package/dist/assets/LinearIssuesView-EzGNCGrd.js +0 -1
  318. package/dist/assets/MarkdownImageGallery-B2YUDFaB.js +0 -1
  319. package/dist/assets/MarkdownRendererImpl-B4ikIzR3.js +0 -12
  320. package/dist/assets/OnboardingScreen-CQHBSTEi.js +0 -1
  321. package/dist/assets/PlanView-D3x-pTkZ.js +0 -5
  322. package/dist/assets/PluginPane-DEcgDQ9h.js +0 -3
  323. package/dist/assets/SettingsView-CSinuH-1.js +0 -29
  324. package/dist/assets/SettingsWindow-B5CHoJFZ.js +0 -1
  325. package/dist/assets/SubmoduleDiffSummary-oxeACCWs.js +0 -1
  326. package/dist/assets/ToolOutputDialog-tLNWmfcW.js +0 -15
  327. package/dist/assets/ToolPartDiffPreview-CflzmK-x.js +0 -8
  328. package/dist/assets/appThemeRegistry-DLicw4dH.js +0 -1
  329. package/dist/assets/de-Bro6_zyl.js +0 -10
  330. package/dist/assets/es-Bb9XQZvd.js +0 -16
  331. package/dist/assets/fr-Dgfzn-IL.js +0 -14
  332. package/dist/assets/index-CtQNmqUL.js +0 -1
  333. package/dist/assets/index-DqaMWNrC.css +0 -1
  334. package/dist/assets/index-Dqc6USl3.js +0 -40
  335. package/dist/assets/ja-BYsakGFh.js +0 -16
  336. package/dist/assets/ko-BSaQz9aN.js +0 -16
  337. package/dist/assets/main-B62_pjL5.js +0 -2
  338. package/dist/assets/main-BEdcOI2P.js +0 -896
  339. package/dist/assets/miniChat-LT8Rqofr.js +0 -2
  340. package/dist/assets/mobile-CqarEynh.js +0 -2
  341. package/dist/assets/pl-OIviPdoj.js +0 -16
  342. package/dist/assets/pt-BR-Cltg-E6s.js +0 -16
  343. package/dist/assets/renderElectronMiniChatApp-COyLTtZx.js +0 -2
  344. package/dist/assets/renderMobileApp-BC1MHg6g.js +0 -25
  345. package/dist/assets/runtimeEndpointReset-DdrazOVH.js +0 -25
  346. package/dist/assets/scheduledTasksApi-B2SWMGEU.js +0 -1
  347. package/dist/assets/tr-CQI-KPre.js +0 -7
  348. package/dist/assets/uk-CqW7R4DA.js +0 -16
  349. package/dist/assets/useAppFontEffects-ne84JBVL.js +0 -7333
  350. package/dist/assets/useRootScrollLock-Cpf1qoGp.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-CVZG_o_J.js +0 -16
  354. package/dist/assets/zh-TW-D5ZxzCZp.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
@@ -10,6 +10,7 @@ This module provides OpenCode server integration utilities for the web server ru
10
10
  - `packages/web/server/lib/opencode/cli-options.js`: CLI/environment option parsing for server startup arguments.
11
11
  - `packages/web/server/lib/opencode/cli-entry-runtime.js`: CLI entrypoint runtime that detects direct execution, parses CLI options, and starts server bootstrap.
12
12
  - `packages/web/server/lib/opencode/routes.js`: OpenCode/provider settings and auth-related route registration.
13
+ - `packages/web/server/lib/opencode/v1-migration-topup.js`: re-arms OpenCode's own V1 -> V2 session import for V1 sessions created after that migration already completed; runs only before a managed spawn. See "v1-migration-topup.js" below.
13
14
  - `packages/web/server/lib/opencode/lifecycle.js`: OpenCode process lifecycle runtime (startup, restart, readiness, health monitoring). After readiness it warms the most recently used directories (`getWarmupDirectories` dep, sequential and best-effort) because OpenCode initializes each directory lazily on first request and that cost would otherwise be paid by the user's first interactive session open.
14
15
  - `packages/web/server/lib/opencode/provider-env-aliases.js`: mirrors known provider credential env aliases into the managed OpenCode process environment (for example `GEMINI_API_KEY` → `GOOGLE_GENERATIVE_AI_API_KEY`) so OpenCode connection detection and the upstream AI SDK agree on the same key names. Canonical implementation shared by web lifecycle and the VS Code managed spawn path (`packages/vscode/src/provider-env-aliases.ts` re-exports this module).
15
16
  - `packages/web/server/lib/opencode/env-runtime.js`: OpenCode CLI/binary resolution and shell environment runtime.
@@ -18,12 +19,13 @@ This module provides OpenCode server integration utilities for the web server ru
18
19
  - `packages/web/server/lib/opencode/bootstrap-runtime.js`: base app bootstrap runtime for status/auth/tts/notification/OpenChamber route wiring.
19
20
  - `packages/web/server/lib/opencode/network-runtime.js`: OpenCode URL construction, health-probe readiness checks, and API prefix runtime.
20
21
  - `packages/web/server/lib/opencode/project-directory-runtime.js`: request-scoped and settings-backed project directory resolution/validation runtime.
21
- - `packages/web/server/lib/opencode/config-entity-routes.js`: route registration for agent/command/MCP config orchestration with deferred-apply semantics (`restartDeferred` payloads; explicit apply via `POST /api/config/reload`).
22
- - `packages/web/server/lib/opencode/config-mutation-response.js`: shared response builders for deferred OpenCode restarts and external manual-restart guidance.
22
+ - `packages/web/server/lib/opencode/config-entity-routes.js`: route registration for agent/command/MCP config orchestration. OpenCode 2 watches these files, so a write is live as soon as it lands and the route answers plain success.
23
+ - `packages/web/server/lib/opencode/websearch-config.js`: writes OpenCode's `websearch` choice (`PUT /api/config/websearch` in `routes.js`; body `{ selection: false | null | "random" | "<provider id>" }`, `null` removes the key, so OpenCode falls back to the answer given in its chat consent form, which it keeps in its own store) to `OPENCODE_CONFIG` when set, else the user config. `GET /api/config/websearch` returns `{ projectPath }`: the project config whose `websearch` overrides that write (OpenCode merges user < project < `OPENCODE_CONFIG`), so Settings disables the choice and names the file instead of letting it snap back; `findWebSearchProjectOverride` in `config-v2.js` holds the rule. The pure transform is `writeWebSearchSelection` in `config-v2.js`, shared with the VS Code bridge (`api:config/websearch`).
24
+ - `packages/web/server/lib/opencode/config-mutation-response.js`: shared response builders for applied config mutations and external manual-restart guidance.
23
25
  - `packages/web/server/lib/opencode/snippets.js`: opencode-snippets-compatible snippet file CRUD, discovery, and hashtag expansion.
24
26
  - `packages/web/server/lib/opencode/cli-options.js`: CLI/environment option parsing for server startup arguments.
25
27
  - `packages/web/server/lib/opencode/core-routes.js`: server status/system routes, auth/access guard routes, and settings utility route registration.
26
- - `packages/web/server/lib/opencode/shutdown-runtime.js`: graceful shutdown orchestration runtime for watcher/session/terminal/process/server teardown.
28
+ - `packages/web/server/lib/opencode/shutdown-runtime.js`: graceful shutdown orchestration runtime for watcher/session/guest-services/terminal/process/server teardown.
27
29
  - `packages/web/server/lib/opencode/server-startup-runtime.js`: server listen/startup tunnel flow and process/signal handler orchestration runtime.
28
30
  - `packages/web/server/lib/opencode/static-routes-runtime.js`: static asset/SPA fallback route registration and manifest route wiring.
29
31
  - `packages/web/server/lib/opencode/feature-routes-runtime.js`: feature route composition runtime for dynamic import-backed config/skill/provider route registration.
@@ -33,8 +35,26 @@ This module provides OpenCode server integration utilities for the web server ru
33
35
  - `packages/web/server/lib/opencode/startup-pipeline-runtime.js`: server startup tail orchestration runtime for terminal/proxy/static/start-listen flow.
34
36
  - `packages/web/server/lib/opencode/startup-performance.js`: opt-in startup phase diagnostics with fixed labels and numeric metadata allowlists.
35
37
  - `packages/web/server/lib/agent-tool/runtime.js`: managed OpenCode custom-tool materialization, environment injection, same-machine authentication (loopback, or the bound address for a concrete bind), and fixed CLI action dispatch.
36
- - `packages/web/server/lib/system-prompt/runtime.js`: opt-in managed OpenCode system-prompt optimizer materialization and plugin injection.
37
- - `packages/web/server/lib/opencode/managed-plugin-config.js`: the one `OPENCODE_CONFIG_CONTENT` merge every managed plugin (agent tools, system prompt optimizer) appends itself through.
38
+ - `packages/web/server/lib/opencode/managed-plugin-config.js`: the `OPENCODE_CONFIG_CONTENT` merge used only on the fallback path, when the user's own environment owns `OPENCODE_CONFIG`.
39
+ - `packages/web/server/lib/opencode/managed-config-file.js`: the managed OpenCode config layer — materializes the enabled OpenChamber plugins (agent tools, system prompt optimizer) and publishes them in a file OpenCode watches.
40
+
41
+ ### Managed plugins on OpenCode 2.x
42
+ A configured plugin must be a DIRECTORY holding a `package.json` that resolves an
43
+ entrypoint; a path to a `.js` file is skipped with "configured plugin path must
44
+ be a directory". The config key is `plugins` (an array of absolute directory
45
+ paths), not `plugin`.
46
+
47
+ The generated entrypoint has no imports. OpenCode loads it with a plain dynamic
48
+ `import()`, and resolution happens from the plugin's own directory, where nothing
49
+ is installed — `import { Plugin } from "@opencode/plugin"` fails there. None of
50
+ it is needed: a plugin only has to default-export `{ id, setup }`, and a tool's
51
+ `input` accepts plain JSON Schema.
52
+
53
+ Two v1 affordances are gone and the generated tools work around them: a tool
54
+ result has no `title` (it travels in `metadata`) and must not carry `output`
55
+ unless an output schema is declared; and a tool call no longer receives
56
+ `context.directory` or `context.abort`, so the callback sends `context.sessionID`
57
+ and OpenChamber resolves the directory itself.
38
58
  - `packages/web/server/lib/opencode/server-utils-runtime.js`: shared server runtime utilities for OpenCode proxy wiring, OpenCode port/readiness helpers, and snapshot fetchers.
39
59
  - `packages/web/server/lib/opencode/openchamber-routes.js`: OpenChamber update and models metadata route registration.
40
60
  - `packages/web/server/lib/opencode/pwa-manifest-routes.js`: PWA manifest route registration with recent-session shortcut resolution and short-lived caching.
@@ -70,22 +90,107 @@ This module provides OpenCode server integration utilities for the web server ru
70
90
  - `packages/web/server/lib/opencode/session-runtime.js`: session status/attention/activity runtime for OpenCode SSE events.
71
91
  - `packages/web/server/lib/opencode/watcher.js`: global SSE watcher runtime for push/session event fanout.
72
92
  - `packages/web/server/lib/opencode/shared.js`: shared utilities for config, markdown, skills, and git helpers.
93
+ - `packages/web/server/lib/opencode/config-v2.js`: the canonical OpenCode 2 shape layer — section-key resolution (v2 first, v1 fallback), permission map -> rule array translation, model `provider/model#variant` split/join, and the agent/command/MCP/provider/plugin entity conversions. Pure functions with no filesystem access; `packages/vscode/src/opencode-config-v2.ts` re-exports it so the web server and the extension host cannot write different files. See "Entity routes (v2 shapes)" below.
73
94
  - `packages/web/server/lib/ui-auth/ui-auth.js`: UI session authentication runtime (outside OpenCode module).
74
95
  - `packages/web/server/lib/ui-auth/ui-passkeys.js`: UI passkey storage and WebAuthn registration/authentication helpers (outside OpenCode module).
75
96
 
76
97
  ## Public exports (auth.js)
77
- - `readAuthFile()`: Reads and parses `~/.local/share/opencode/auth.json`.
78
- - `writeAuthFile(auth)`: Writes auth file with automatic backup.
79
- - `removeProviderAuth(providerId)`: Removes a provider's auth entry.
98
+ `auth.js` is read-only. OpenCode 2.x imports `auth.json` once into its own
99
+ database and never writes the file again; credentials live behind
100
+ `/api/integration` and `/api/credential`, and no HTTP route hands a key back.
101
+ OpenChamber needs the raw credential for provider quota lookups, voice keys and
102
+ the GitHub and Linear helpers, so `readAuthFile()` answers from the database
103
+ OpenCode actually uses (`credential-db.js`, below). A successful database read
104
+ is authoritative, `{}` included: OpenCode never clears `auth.json` after the
105
+ import and a credential removed in OpenCode vanishes only from the database,
106
+ so the file is never merged over a readable database. The legacy file is the
107
+ fallback only when the database cannot be read (no sqlite runtime, no file,
108
+ unknown schema); a corrupt file then throws, but never blocks a healthy
109
+ database. A write here would be invisible to the running OpenCode, so every
110
+ write path is gone.
111
+
112
+ - `readAuthFile()`: The credentials OpenCode uses, keyed by provider id, in the
113
+ legacy `auth.json` entry shape (`{ type: 'api', key }` /
114
+ `{ type: 'oauth', access, refresh, expires, accountId?, enterpriseUrl? }`).
80
115
  - `getProviderAuth(providerId)`: Returns auth for a specific provider or null.
81
116
  - `listProviderAuths()`: Returns list of provider IDs with configured auth.
82
- - `AUTH_FILE`: Auth file path constant.
117
+ - `AUTH_FILE`: Legacy auth file path constant.
83
118
  - `OPENCODE_DATA_DIR`: OpenCode data directory path constant.
84
119
 
120
+ ### credential-db.js
121
+
122
+ Reads `<data>/opencode.db` (or `OPENCODE_DB`), table `credential`, where
123
+ OpenCode 2.x stores every credential as plain JSON. This is OpenCode's private
124
+ schema, verified against v2.0.x `packages/core/src/credential/sql.ts`; the
125
+ reader opens the file read-only, picks the `active` row per integration (else
126
+ the newest), projects `{ type: 'key' }` / `{ type: 'oauth' }` values into the
127
+ legacy entry shape, and answers `null` for anything it cannot do (no sqlite
128
+ runtime, no file, a changed schema), so the caller can tell "no credentials"
129
+ from "could not look" and fall back to the file. `node:sqlite` on Node 22.13+,
130
+ `bun:sqlite` on Bun; no dependency is added. `packages/vscode/src/opencodeAuth.ts`
131
+ is the extension-host mirror.
132
+
133
+ ### v1-migration-topup.js
134
+
135
+ OpenCode 2.x imports the legacy `session`/`message`/`part` tables into
136
+ `session_v2`/`session_message` once and then records `{"phase":"completed"}`
137
+ under `migration.v1-v2` in the `kv` table. Anyone who kept using a bundled
138
+ OpenCode 1.x beside a v2 install created V1 sessions after that point, and
139
+ OpenCode never looks at them again — they are simply missing from the session
140
+ list. `topUpV1Migration()` hands OpenCode a resume cursor so its own migration
141
+ picks them up. OpenChamber never writes session rows itself.
142
+
143
+ It runs from `lifecycle.js` immediately before the MANAGED OpenCode is spawned:
144
+ never for an external, user-started OpenCode, and never while a managed one is
145
+ running, because the write would race OpenCode's own loop. Failure is never
146
+ fatal to startup. It opens `<data>/opencode.db` (or `OPENCODE_DB`) read-write
147
+ with the same loader strategy as `credential-db.js` — `node:sqlite` on Node,
148
+ `bun:sqlite` on Bun, skip silently on neither. It returns
149
+ `{ status: 'skipped' | 'scheduled' | 'unsafe' | 'unavailable', missing, revisited, reason? }`
150
+ and logs one line; there is no HTTP route and no UI.
151
+
152
+ What it does: when the migration row says `completed` and some `session` rows
153
+ have no `session_v2` twin AND were created after the migration completed
154
+ (`time_created` past the row's `time_updated`), it sets the row to
155
+ `{"phase":"sessions","cursor":…}`. The time test matters because a v2 delete
156
+ leaves the legacy row behind (`Session.remove` publishes `session.deleted`,
157
+ `bus.remove` then wipes that session's durable events, `session_v2` cascades):
158
+ a legacy session the migration already walked and that is absent now was
159
+ deleted, not missed, and is never re-imported.
160
+ The cursor is the largest missing id plus `U+FFFF`, because OpenCode's loop
161
+ walks `id < cursor` in descending id order and ids are fixed width, so nothing
162
+ real can fall between an id and that cursor. Ids are compared the way SQLite
163
+ does (BINARY/memcmp; neither id column declares a collation). Session ids
164
+ encode time descending in a field that wraps, so id order is **not** time
165
+ order — an August session can sort far below a newer one, and the code never
166
+ assumes otherwise.
167
+
168
+ Two hard rules, both verified against v2.0.8
169
+ `packages/core/src/database/v1-migration.bun.ts`:
170
+
171
+ - **Never clear or delete the `migration.v1-v2` row.** With no row at all
172
+ OpenCode treats the database as pre-migration and DELETEs the whole `event`
173
+ table, v2's durable event log.
174
+ - **Never make OpenCode revisit a session that has v2 activity.** Every session
175
+ the loop visits gets its `session_message` rows deleted and replaced by the
176
+ V1 transform. Before writing a cursor, the top-up lists the already-migrated
177
+ sessions below it and looks for a message created after the migration
178
+ completed, a `session_v2.time_updated` after it, or a message `type` the V1
179
+ transform never emits (it only produces `user`, `assistant`, `synthetic`,
180
+ `compaction`). Any hit and nothing is written: the outcome is `unsafe`
181
+ (`revisited-sessions-have-v2-activity`) and a single warning names how many
182
+ sessions stay missing.
183
+ - **Never resurrect a session deleted in v2.** OpenCode's loop walks every
184
+ legacy row under the cursor, so a deleted session sorting below a
185
+ never-imported one would come back. The top-up refuses that too
186
+ (`unsafe`, `deleted-sessions-would-return`); the never-imported sessions
187
+ then stay missing until upstream offers an import route.
188
+
85
189
  ## Public exports (providers.js)
86
190
  - `getProviderSources(providerId, workingDirectory)`: Resolves which OpenCode config layers define a provider.
87
- - `upsertProviderConfig(providerId, config, workingDirectory, scope?, options?)`: Validates and writes a custom provider block (`npm`, `name`, `options.baseURL`, `models`, optional `env`/`headers`) into the user/project/custom config layer. The adapter may be OpenAI Chat Completions, OpenAI Responses, or Anthropic Messages. Existing provider, option, and retained-model fields not managed by the form are preserved; omitted models, headers, and env credentials remain explicit removals. Updating a legacy `providers` entry migrates it to the canonical `provider` key. Does not store API keys. Requires `config.env` or `options.hasStoredAuth` (auth already written via OpenCode `auth.set`). Edit flows must pass the provider's effective existing layer (`custom` > `project` > `user`) so updates do not create a global user override.
88
- - `validateCustomProviderConfig(providerId, config, options?)`: Structural validation for custom provider payloads (id format, adapter allowlist `@ai-sdk/openai-compatible`/`@ai-sdk/openai`/`@ai-sdk/anthropic`, http(s) base URL, models, credentials via `env` or `hasStoredAuth`).
191
+ - `listProviderConfigs(workingDirectory)`: Every provider a config layer defines, projected into the canonical v2 `ProviderEntity` shape, with `legacy` marking entries still stored under the v1 `provider` key.
192
+ - `upsertProviderConfig(providerId, config, workingDirectory, scope?, options?)`: Validates and writes a custom provider block into the user/project/custom config layer. The payload may use the v2 spelling (`package`, `settings.baseURL`, `headers`) or the v1 spelling (`npm`, `options.baseURL`); what lands on disk is always a v2 `providers` entry with `package: "aisdk:<npm>"` and `settings.baseURL`. The adapter may be OpenAI Chat Completions, OpenAI Responses, or Anthropic Messages. Existing provider, option, and retained-model fields not managed by the form are preserved; omitted models, headers, and env credentials remain explicit removals. A model's `variants` (reasoning levels) are replaced when the payload carries the array, cleared when it carries an empty one, and kept when the key is absent. Updating an entry still stored under the legacy `provider` key rewrites it under `providers` in the same file, dropping the fields v2 accepts but ignores; unrelated legacy siblings are untouched. Does not store API keys. Requires `config.env` or `options.hasStoredAuth` (auth already written via OpenCode `auth.set`). Edit flows must pass the provider's effective existing layer (`custom` > `project` > `user`) so updates do not create a global user override.
193
+ - `validateCustomProviderConfig(providerId, config, options?)`: Structural validation for custom provider payloads (id format, adapter allowlist `@ai-sdk/openai-compatible`/`@ai-sdk/openai`/`@ai-sdk/anthropic`, http(s) base URL, models, credentials via `env` or `hasStoredAuth`). Accepts both spellings and returns the normalized v2 value.
89
194
  - `removeProviderConfig(providerId, workingDirectory, scope?)`: Removes a provider block from the selected config layer.
90
195
 
91
196
  ## Public exports (shared.js)
@@ -97,7 +202,7 @@ This module provides OpenCode server integration utilities for the web server ru
97
202
  - `readConfigFile(filePath)`: Reads one config file. Missing, whitespace-only, and comment-only files return `{}`; a comment-only file is recognized by `ValueExpected` being the only parse error. A `jsonc-parser` error that produces a partial or non-object tree throws `INVALID_JSONC` — partial parse trees must never be treated as authoritative (avoids rewriting a `$schema`-only stub over a full config). Content that yields no JSON value for any other reason (YAML, plain text) also throws instead of reading as empty.
98
203
  - `readConfigLayer(filePath)`: Same parse as `readConfigFile`, but isolates `INVALID_JSONC` to `{ config: {}, error }` so plugin/MCP/agent readers can skip one broken layer without aborting valid siblings. Writes still refuse to overwrite the broken file.
99
204
  - `writeConfig(config, filePath)`: Writes config with automatic backup. Refuses to overwrite an existing non-empty file that fails the same JSONC parse check.
100
- - `getJsonEntrySource(layers, sectionKey, entryName)`: Resolves which config layer provides an entry. A failed custom or user layer throws `INVALID_JSONC` instead of treating that file as empty. A failed project layer is skipped so a valid user/custom entry can still be found.
205
+ - `getJsonEntrySource(layers, sectionKind, entryName)`: Resolves which config layer provides an entry. `sectionKind` is `agents`, `commands`, `providers`, or `mcp`, and both the v2 and the v1 spelling are searched (v2 wins). The result carries `sectionKey` (the spelling that actually held the entry) and `legacy`, so a writer can rewrite the same file in v2 shape. A failed custom or user layer throws `INVALID_JSONC` instead of treating that file as empty. A failed project layer is skipped so a valid user/custom entry can still be found.
101
206
  - `getJsonWriteTarget(layers, preferredScope)`: Determines write target for config updates. Throws `INVALID_JSONC` when the chosen target file is the unparseable layer.
102
207
  - `getAncestors(startDir, stopDir)`, `findWorktreeRoot(startDir)`: Git worktree helpers.
103
208
  - `isPromptFileReference(value)`, `resolvePromptFilePath(reference)`, `writePromptFile(filePath, content)`: Prompt file reference handling.
@@ -111,7 +216,7 @@ This module provides OpenCode server integration utilities for the web server ru
111
216
  - `GET /api/config/settings`
112
217
  - `PUT /api/config/settings`
113
218
  - `GET /api/config/opencode-resolution`
114
- - `POST /api/opencode/upgrade` (enforces the active runtime's upgrade capability, serializes supported OpenCode upgrades, then restarts managed OpenCode so the new binary is active)
219
+ - `POST /api/opencode/upgrade` (enforces the active runtime's upgrade capability, shares concurrent upgrade requests and runs the resolved CLI with `upgrade`; the existing Reload action restarts managed OpenCode afterwards)
115
220
  - `GET /api/opencode/upgrade-status` (returns version availability plus the authoritative `upgrade.supported`, `upgrade.manager`, and `upgrade.reason` capability)
116
221
  - `POST /api/opencode/directory` (validates and activates an existing project directory; `{ create: true }` explicitly creates the requested project directory before activation, including outside the previously active workspace)
117
222
  - `GET /api/provider/:providerId/source`
@@ -120,6 +225,57 @@ This module provides OpenCode server integration utilities for the web server ru
120
225
  - Owns lazy auth library loading for provider auth checks/removal.
121
226
  - Keeps route behavior independent from composition root; `index.js` now supplies dependencies only.
122
227
 
228
+ ## CLI upgrades
229
+
230
+ `cli-upgrade.js` runs the host-resolved executable and wrapper arguments with
231
+ `upgrade`, without a shell or client-supplied arguments. OpenCode chooses the
232
+ installer. Web, hosted mobile, Capacitor, and Desktop with a separately installed
233
+ CLI use this server path. VS Code uses the same executor from its extension host.
234
+ Bundled Desktop, external URL connections, unavailable CLIs, and the Windows
235
+ ARM64 workaround remain unsupported at the host boundary.
236
+
237
+ An upgrade leaves the current server running. The toast's Reload action restarts
238
+ it using the installed version. Failed installations return an error and can be
239
+ retried; installer output is not returned or logged because it can contain registry
240
+ credentials. Requests from multiple clients share the in-flight operation. The
241
+ executor supplies EOF and bounds captured output; installation has no fixed time
242
+ limit, and the VS Code bridge does not apply its usual 30-second request timeout.
243
+
244
+ ### Migrating an installed v1 CLI
245
+
246
+ `GET /api/opencode/compatibility` reads the local CLI version without starting
247
+ its server, or probes an external server's JSON version contract. A confirmed
248
+ managed v1 CLI on macOS, Linux or Windows (x64/arm64) advertises `canInstall`;
249
+ bundled binaries and external connections do not.
250
+
251
+ `POST /api/opencode/install-v2` rechecks that capability and shares one operation
252
+ across concurrent clients. `v2-install.js` resolves a validated stable v2
253
+ release from npm. On macOS/Linux it downloads the official
254
+ `https://opencode.ai/v2/install` script and runs it with that release and
255
+ `--no-modify-path`. That script is bash, so on Windows it downloads the npm
256
+ platform package the script would fetch, `@opencode/cli-windows-x64-baseline`
257
+ (arm64 too, like the desktop bundle), checks it against the `sha512` integrity
258
+ npm publishes, and unpacks `opencode.exe` with the system `tar.exe`. Both
259
+ paths then verify the resulting executable.
260
+ It installs into the host user's standard `~/.opencode/bin`. Existing npm/Bun
261
+ packages remain installed; the host selects the new binary through
262
+ `opencodeBinary`, restarts OpenCode, and waits for v2 readiness before replying.
263
+
264
+ A filesystem lock prevents separate hosts sharing a home from installing at
265
+ the same time. The installer has a five-minute deadline and owns its subprocess
266
+ group. Existing executable/shim files are restored after an installation or
267
+ verification failure. If rollback fails, backups and the lock remain under
268
+ `.opencode/bin/.openchamber-install` for manual recovery. A successful install
269
+ followed by a settings/restart failure keeps v2 on disk; Check again can retry
270
+ the restart. A host crash may also leave the lock for manual recovery.
271
+ Installer output is discarded, not forwarded to clients or logs.
272
+
273
+ ## Public exports (response-envelope.js)
274
+ - `unwrapOpenCodeResponse(body)`: strips OpenCode 2.x's response envelope. A single record (`GET /api/session/:id`, one message) arrives as `{ data }`, some routes as `{ location, data }`, pages as `{ data, cursor }`. Records and plain lists are unwrapped; pages keep the envelope for their cursor. Every server-side OpenCode read goes through it: unwrapping only on `location` left record envelopes in place, so `parentID` and message ids read as missing.
275
+
276
+ ## Public exports (session-activity.js)
277
+ - `createSessionActivityProbe({ buildOpenCodeUrl, getOpenCodeAuthHeaders, timeoutMs })`: whether a session's turn really ended. A parent goes idle while a background subagent works and runs again when OpenCode hands the result back. `fetchActiveSessionStatuses()` reads `/api/session/active`, `fetchChildSessionIds(id)` pages `GET /api/session?parentID=`, `hasWorkingChildren(id, statuses)` combines them. Every read answers `null` when OpenCode could not be asked. Used by the goal loop (waits) and the notification runtime (stays silent on the pause).
278
+
123
279
  ## Public exports (session-runtime.js)
124
280
  - `createSessionRuntime({ writeSseEvent, getNotificationClients, broadcastEvent? })`: creates runtime-owned state machine and APIs for session status.
125
281
  - Returned API:
@@ -174,6 +330,8 @@ Set `OPENCHAMBER_STARTUP_PERF=1` to emit bounded startup phase records for serve
174
330
 
175
331
  macOS `say` voice enumeration starts concurrently with server composition. The server listener and managed OpenCode startup do not wait for it; `/api/tts/say/status` awaits the same authoritative capability promise when queried before enumeration completes.
176
332
 
333
+ Upstream health is probed with `GET /api/info` (OpenCode 2.0.8 removed `/api/health`). A 200 is the whole readiness answer — the payload is `{ version, pid, urls, paths }` and carries no `healthy` field — and its `version` is what the major-version gate reads. OpenChamber's own `/api/opencode/health` keeps answering `{ healthy }` to its clients, derived from that status.
334
+
177
335
  Transport-triggered health checks share the periodic monitor's failure accounting interval. Rapid WS reconnect callbacks therefore cannot exhaust the managed-process restart threshold using one cached unhealthy result; an exited managed process still restarts immediately.
178
336
 
179
337
  Managed health failures are classified as `timeout`, `connection_refused`, `connection_reset`, `invalid_response`, or `error`. The lifecycle retains the latest counted failure with a bounded detail string and source. Managed process wrappers continue capturing a sanitized, bounded stderr tail after readiness and retain exit code/signal. Before replacing a managed process, lifecycle snapshots the reason, latest health failure, process diagnostics/aliveness, busy-session count, and timestamp into `lastOpenCodeRestartDiagnostics`; successful startup does not clear this snapshot, and `/health` exposes it for post-restart diagnosis without process environment or credentials.
@@ -199,6 +357,7 @@ ConPTY or Console Window Host behavior.
199
357
  - `createOpenCodeEnvRuntime(dependencies)`: creates runtime that owns OpenCode CLI environment and binary discovery state.
200
358
  - OpenCode CLI resolution order is persisted settings, environment overrides, bundled Desktop CLI when available, PATH, known install locations, then platform shell discovery.
201
359
  - Automatic bundled resolution under `OPENCHAMBER_RUNTIME=desktop` stays in runtime state and is returned to the managed launch function, including on OpenCode restart. It does not populate `process.env.OPENCODE_BINARY`: AppImage updater relaunch inherits that environment and would mistake the previous bundle path for an explicit override. Explicit settings/env selections and non-desktop or non-bundled resolution retain their existing environment behavior. This prevents future inheritance; it does not reinterpret overrides already inherited from older releases.
360
+ - The login-shell snapshot (`$SHELL -lic 'env -0'`) is taken synchronously at import time, so it blocks whatever process embeds the server for as long as the user's shell startup files take. An embedding host that already probed the shell hands its result over before importing the server through `login-shell-env.js` (`provideLoginShellEnvSnapshot(snapshot | null)`); the runtime then uses that and never probes, `null` included. Desktop does this on macOS and Linux; on Windows the server keeps its own registry-based snapshot. The handoff is a module slot, never an environment variable: the snapshot is the user's whole shell environment and `process.env` reaches every child.
202
361
  - Returned API:
203
362
  - `applyLoginShellEnvSnapshot()`
204
363
  - `getLoginShellEnvSnapshot()`
@@ -302,16 +461,238 @@ ConPTY or Console Window Host behavior.
302
461
  - `resolveProjectDirectory(req)`
303
462
  - `resolveOptionalProjectDirectory(req)`
304
463
 
464
+ ## Entity routes (v2 shapes)
465
+
466
+ Everything OpenChamber persists into OpenCode config now speaks OpenCode 2.
467
+ This section is the contract the Settings UI builds on.
468
+
469
+ ### Ownership: which directory is written
470
+
471
+ OpenCode 2 still discovers the v1 directories, so OpenChamber READS all of them
472
+ and WRITES only the v2 one:
473
+
474
+ | Entity | Read from | Written to |
475
+ |---|---|---|
476
+ | Agents | `.opencode/{agent,agents,mode,modes}/**/*.md` | `.opencode/agents/<name>.md` |
477
+ | Commands | `.opencode/{command,commands}/**/*.md` | `.opencode/commands/<name>.md` |
478
+ | Skills | `.opencode/{skill,skills}/<id>/SKILL.md`, plus `.claude/skills` and `.agents/skills` | `.opencode/skills/<id>/SKILL.md` |
479
+ | Plugin files | `.opencode/{plugin,plugins}/` — `.ts`/`.js` files and plugin package directories | `.opencode/plugins/<file>` |
480
+
481
+ The same holds for the global config directory. Like OpenCode 2, agents,
482
+ commands and skills are looked up in every `.opencode` from the working
483
+ directory up to the worktree root, so a definition in a parent directory of a
484
+ monorepo package counts; a nested id (`team/reviewer`) maps onto the path.
485
+ Only files in the v2 `plugins/` directory are editable through the plugins
486
+ page; a package directory or a v1 `plugin/` file is listed as a package that
487
+ OpenCode loads and OpenChamber does not touch.
488
+
489
+ The global config directory is what OpenCode 2 uses: `OPENCODE_CONFIG_DIR`
490
+ when set, else `$XDG_CONFIG_HOME/opencode`, else `~/.config/opencode`. Config
491
+ files are `opencode.json(c)` only: OpenCode 2 no longer discovers the v1-era
492
+ `config.json`, so OpenChamber neither reads nor writes it. In a project both
493
+ `<project>/opencode.json(c)` and `<project>/.opencode/opencode.json(c)` are
494
+ discovered by OpenCode, `.opencode/` winning; OpenChamber reads and writes the
495
+ highest-priority existing one (`.opencode/opencode.json` for a new file), so
496
+ an entry that lives only in a lower file is visible through the resolved
497
+ catalog but not editable here.
498
+
499
+ ### v1 read fallback policy
500
+
501
+ Readers accept the v2 spelling first and fall back to the v1 spelling, because
502
+ v2 itself still decodes the legacy keys and users will have mixed files for a
503
+ while. When both exist for the same name, v2 wins — the precedence OpenCode's
504
+ normalizer applies.
505
+
506
+ | Entity | v2 | v1 still read |
507
+ |---|---|---|
508
+ | Agents | `agents` | `agent` |
509
+ | Commands | `commands` | `command` |
510
+ | Providers | `providers` | `provider` |
511
+ | MCP servers | `mcp.servers` | `mcp.<name>` (each layer normalized on its own, then custom > project > user; a raw merge would let a user-file `mcp.servers.<name>` shadow a project-file `mcp.<name>` override) |
512
+ | Plugins | `plugins` | `plugin` (including `[spec, options]` tuples) |
513
+ | Permissions | `permissions` rule array | `permission` map, `tools` map |
514
+
515
+ Writers emit v2 only. **Files are never moved.** Updating an entity that lives
516
+ in a v1 file rewrites it at its own path in v2 shape, and a v1 JSON entry moves
517
+ to the v2 section key inside the same file — unrelated v1 siblings are left
518
+ alone. Every mutation response reports the `path` that changed.
519
+
520
+ Two consequences worth knowing:
521
+
522
+ - An agent markdown file may not mix native and legacy frontmatter keys. One
523
+ legacy key routes the whole file through OpenCode's v1 decoder
524
+ (`config/plugin/agent.ts`), which would silently drop a `permissions` array.
525
+ `fromAgentEntity` therefore emits native keys only.
526
+ - Migrating a v1 provider entry drops the fields v2 accepts but ignores
527
+ (model `reasoning`, `attachment`, non-`deprecated` `status`, and unknown
528
+ custom keys). That is the documented native conversion, not data loss through
529
+ a bug. v1 model `interleaved` becomes `compatibility.reasoningField` the way
530
+ OpenCode's own migration does; the v2-only provider `canonical` and model
531
+ `compatibility` fields pass through every edit untouched.
532
+ - A v1 agent `color` may be a theme name (`primary`); v2 decodes only
533
+ `#rrggbb` and OpenCode's migration maps anything else to `#aaaaaa`.
534
+ `toAgentEntity` applies the same mapping so a rewritten file stays decodable.
535
+
536
+ ### Canonical entity shapes
537
+
538
+ One shape per entity, shared by the web routes and the VS Code bridge. The
539
+ conversions live in `config-v2.js`; `packages/vscode/src/opencode-config-v2.ts`
540
+ re-exports that module so both runtimes write identical files.
541
+
542
+ ```jsonc
543
+ // PermissionRule — ordered array, last match wins.
544
+ // Actions: shell, subagent, edit, read, grep, glob, patch, webfetch, websearch,
545
+ // skill, question, external_directory, provider.use, "*"
546
+ { "action": "shell", "resource": "git push *", "effect": "ask" } // effect: allow | deny | ask
547
+
548
+ // AgentEntity
549
+ {
550
+ "system": "Review for correctness.", // markdown body for .md agents
551
+ "description": "Reviewer",
552
+ "model": "anthropic/claude-sonnet-4-5#high",
553
+ "mode": "primary", // primary | subagent | all
554
+ "hidden": false,
555
+ "color": "#aabbcc",
556
+ "steps": 12,
557
+ "disabled": false,
558
+ "request": { "headers": {}, "body": { "temperature": 0.4, "top_p": 0.9 } },
559
+ "permissions": [ /* PermissionRule */ ]
560
+ }
561
+
562
+ // CommandEntity
563
+ {
564
+ "template": "Review the current changes.", // markdown body for .md commands
565
+ "description": "Review",
566
+ "agent": "reviewer",
567
+ "model": "anthropic/claude-sonnet-4-5#high",
568
+ "subagent": true
569
+ }
570
+
571
+ // McpEntity — `type` is required; v2 drops a v1 entry that only had `enabled`
572
+ { "type": "local", "command": ["npx", "@playwright/mcp"], "cwd": "…",
573
+ "environment": {}, "disabled": false, "codemode": true,
574
+ "timeout": { "startup": 0, "catalog": 30000, "execution": 30000 } }
575
+ { "type": "remote", "url": "https://mcp.example.com", "headers": {},
576
+ "oauth": { "client_id": "…", "client_secret": "…", "scope": "…",
577
+ "callback_port": 4242, "redirect_uri": "…" },
578
+ "disabled": false, "timeout": { "catalog": 30000, "execution": 30000 } }
579
+
580
+ // ProviderEntity
581
+ {
582
+ "canonical": "openai", // v2-only: built-in provider this entry inherits from
583
+ "name": "Campus LLM",
584
+ "package": "aisdk:@ai-sdk/openai-compatible",
585
+ "env": ["CAMPUS_KEY"],
586
+ "settings": { "baseURL": "https://llm.example.edu/v1" },
587
+ "headers": {}, "body": {},
588
+ "models": {
589
+ "fast-model": {
590
+ "modelID": "fast-model", "name": "Fast", "family": "…", "package": "aisdk:…",
591
+ "compatibility": { "reasoningField": "reasoning_content", "requireReasoning": true, "maxTokensField": "max_tokens" },
592
+ "settings": {}, "headers": {}, "body": {},
593
+ "capabilities": { "tools": true, "input": ["text","image"], "output": ["text"] },
594
+ "variants": [{ "id": "high", "settings": { "reasoningEffort": "high" } }],
595
+ "cost": { "input": 1, "output": 2, "cache": { "read": 0.1, "write": 0.2 } },
596
+ "limit": { "context": 200000, "output": 32000 },
597
+ "disabled": false
598
+ }
599
+ }
600
+ }
601
+
602
+ // PluginEntity — serialized as a bare string when there are no options
603
+ { "package": "./plugin/local.ts", "options": { "enabled": true } }
604
+ ```
605
+
606
+ `model` is always the joined string `providerID/modelID#variant`. Split it with
607
+ `parseModelSelection(model)` → `{ providerID, modelID, variant? }` and join it
608
+ back with `formatModelSelection(selection)`. Both are exported from
609
+ `config-v2.js`.
610
+
611
+ ### Request and response JSON per route
612
+
613
+ `GET /api/config/agents/:name` — metadata about where the agent is defined.
614
+ ```jsonc
615
+ {
616
+ "name": "reviewer",
617
+ "scope": "project", // project | user | null
618
+ "isBuiltIn": false,
619
+ "sources": {
620
+ "md": { "exists": true, "path": "…/.opencode/agent/reviewer.md", "scope": "project",
621
+ "legacy": true, // file uses v1-only frontmatter
622
+ "fields": ["description", "model", "permissions"] },
623
+ "json": { "exists": false, "path": "…/opencode.json", "scope": null,
624
+ "sectionKey": null, // "agents" or "agent" when the entry exists
625
+ "legacy": false, "fields": [] },
626
+ "projectMd": { "exists": true, "path": "…" },
627
+ "userMd": { "exists": false, "path": "…" }
628
+ }
629
+ }
630
+ ```
631
+
632
+ `GET /api/config/agents/:name/config` — the canonical entity.
633
+ ```jsonc
634
+ {
635
+ "source": "md", // md | json | none
636
+ "scope": "project",
637
+ "path": "…/.opencode/agent/reviewer.md",
638
+ "legacy": true,
639
+ "config": { /* AgentEntity */ }
640
+ }
641
+ ```
642
+
643
+ `GET /api/config/agents/:name/permissions` — what applies to this agent.
644
+ ```jsonc
645
+ {
646
+ "global": [ /* PermissionRule, from config `tools` + `permission` + `permissions` */ ],
647
+ "agent": [ /* PermissionRule, the agent's own rules */ ],
648
+ "effective": [ { "action": "edit", "resource": "*", "effect": "allow", "source": "global" },
649
+ { "action": "edit", "resource": "*", "effect": "deny", "source": "agent" } ],
650
+ "source": "md",
651
+ "path": "…"
652
+ }
653
+ ```
654
+ `effective` is in evaluation order: global rules first, agent rules last. Last
655
+ match wins, so a later rule overrides an earlier one.
656
+
657
+ `POST /api/config/agents/:name` — body is an `AgentEntity` plus
658
+ `scope: "user" | "project"`. Answers
659
+ `{ success: true, message, scope, path }`.
660
+
661
+ `PATCH /api/config/agents/:name` — body is a partial `AgentEntity`. `null`
662
+ removes a field, an omitted field is left alone. `permission` (a v1 map) and
663
+ `prompt` (the v1 name for `system`) are still accepted and translated. Answers
664
+ `{ success: true, message, source, scope, path }`.
665
+
666
+ `DELETE /api/config/agents/:name` — optional body `{ scope }`. Answers
667
+ `{ success: true, message }`.
668
+
669
+ `GET /api/config/commands/:name` — same `sources` envelope as agents.
670
+ `GET /api/config/commands/:name/config` — `{ source, scope, path, legacy, config }`
671
+ with a `CommandEntity`.
672
+ `POST` / `PATCH` / `DELETE /api/config/commands/:name` mirror the agent routes;
673
+ `subtask` is accepted as the v1 name for `subagent`.
674
+
675
+ `GET /api/config/mcp` — array of `McpEntity` extended with
676
+ `{ name, scope, sectionKey, legacy }`.
677
+ `GET /api/config/mcp/:name` — one such entry, or 404.
678
+ `POST` / `PATCH` / `DELETE /api/config/mcp/:name` — body is an `McpEntity`
679
+ (plus `scope` on create). Answers `{ success: true, message, path }`.
680
+
681
+ `PUT /api/provider` — body accepts either spelling: v2 `{ package, settings,
682
+ headers }` or v1 `{ npm, options }`. The stored entry is always a
683
+ `ProviderEntity` under `providers`. Answers `{ providerId, path, config }`.
684
+ `GET /api/provider/:providerId/source` reports which layers define it.
685
+
305
686
  ## Public exports (config-entity-routes.js)
306
687
  - `registerConfigEntityRoutes(app, dependencies)`: registers configuration entity routes:
307
- - Agents: `/api/config/agents/:name` and `/api/config/agents/:name/config`
308
- - Commands: `/api/config/commands/:name`
688
+ - Agents: `/api/config/agents/:name`, `/api/config/agents/:name/config`, `/api/config/agents/:name/permissions`
689
+ - Commands: `/api/config/commands/:name` and `/api/config/commands/:name/config`
309
690
  - MCP servers: `/api/config/mcp` and `/api/config/mcp/:name`
310
691
  - Snippets: `/api/config/snippets`, `/api/config/snippets/:name`, and `/api/config/snippets/expand`
311
- - Agent/command/MCP write routes persist config to disk and return a deferred-restart payload (`requiresReload: false`, `requiresRestart: true`, `restartDeferred: true`) instead of restarting OpenCode immediately. The UI accumulates these changes and applies them with `POST /api/config/reload`.
692
+ - Agent/command/MCP write routes persist config to disk and return plain success. OpenCode 2 watches those files and rebuilds the affected entity itself, so there is nothing left to apply.
312
693
 
313
694
  ## Public exports (config-mutation-response.js)
314
- - `buildDeferredRestartResponse(message)`: success payload for config mutations that are saved on disk but waiting for an explicit Apply & Restart (`restartDeferred: true`).
695
+ - `buildAppliedResponse(message, details?)`: success payload for a config mutation that is already live (`{ success: true, message }`, no restart flags). `details` carries the file the write landed in (`{ path, scope, source }`) so the caller can name the config file that changed, including a v1 file rewritten in place in v2 shape.
315
696
  - `buildExternalManualRestartResponse(message)`: success payload when OpenCode is an external process and the operator must restart it manually (`requiresManualRestart: true`).
316
697
 
317
698
  ## Public exports (auth-state-runtime.js)
@@ -342,7 +723,7 @@ ConPTY or Console Window Host behavior.
342
723
  - `app.use('/api', ...)` auth/tunnel guard
343
724
  - `registerSettingsUtilityRoutes(app, dependencies)`: registers small settings utility endpoints:
344
725
  - `GET /api/config/themes`
345
- - `POST /api/config/reload` — applies accumulated deferred OpenCode config changes. Managed OpenCode restarts and returns `requiresReload: true`. External OpenCode returns `requiresManualRestart: true` (changes are already on disk; the connected server must be restarted outside OpenChamber).
726
+ - `POST /api/config/reload` — restarts OpenCode on request. Config edits no longer need it; it stays for the changes that cannot be hot-applied (OpenCode binary, port, managed/external switch) and as a manual recovery. Managed OpenCode restarts and returns `requiresReload: true`. External OpenCode returns `requiresManualRestart: true` (changes are already on disk; the connected server must be restarted outside OpenChamber).
346
727
  - `registerCommonRequestMiddleware(app, dependencies)`: registers shared request middleware stack:
347
728
  - conditional JSON body parser behavior for `/api/*` vs non-API requests
348
729
  - URL-encoded parser setup
@@ -371,9 +752,11 @@ ConPTY or Console Window Host behavior.
371
752
 
372
753
  ## Public exports (shutdown-runtime.js)
373
754
  - `createGracefulShutdownRuntime(dependencies)`: creates graceful shutdown runtime for managed OpenCode and web server teardown sequencing.
374
- - After stopping owned runtimes and OpenCode, HTTP shutdown closes active connections as well as the listener. A remaining SSE response must not hold Desktop open until its fallback deadline. Upgraded sockets remain the responsibility of their owning runtime.
755
+ - Daemon signals, `POST /api/system/shutdown`, and embedded `stop()` share one shutdown promise. Guest admission closes synchronously before any await. Cleanup stops the relay reconciliation timer, guest viewers, realtime proxy, relay host, dictation worker and session runtimes before draining guest services, including pending starts. Each cleanup is best-effort and runs once per shutdown, including after partial startup. A hard kill still requires the separate crash/SIGKILL recovery work; no persistent registry or boot reaper is provided here.
756
+ - Register TCP connection tracking before the HTTP server starts listening. After stopping owned runtimes and OpenCode, HTTP shutdown closes the listener and all remaining sockets, including WebSocket upgrades and unanswered upgrade requests accepted during cleanup. This prevents client reconnects from holding Desktop open until the HTTP close deadline. Each runtime still owns its protocol cleanup; socket teardown runs afterwards and preserves the existing terminal and process grace periods.
375
757
  - Returned API:
376
758
  - `gracefulShutdown(options?)`
759
+ - `trackServerConnections(server)`: call once before listening; closed sockets leave the tracking set, and the server close event removes the connection listener.
377
760
 
378
761
  ## Public exports (server-startup-runtime.js)
379
762
  - `createServerStartupRuntime(dependencies)`: creates runtime for server bind/startup tunnel and process handler wiring.
@@ -400,7 +783,7 @@ ConPTY or Console Window Host behavior.
400
783
  ## Public exports (tunnel-wiring-runtime.js)
401
784
  - `createTunnelWiringRuntime(dependencies)`: creates runtime for tunnel service construction and tunnel route registration.
402
785
  - Returned API:
403
- - `initialize(app, initialPort)`
786
+ - `initialize(app, initialPort, hasUiPassword)`
404
787
 
405
788
  ## Public exports (startup-pipeline-runtime.js)
406
789
  - `createStartupPipelineRuntime(dependencies)`: creates runtime for terminal wiring, proxy/bootstrap scheduling, static route registration, and server startup/listen flow.
@@ -475,10 +858,12 @@ within a ten-minute overall deadline.
475
858
  - SSE forwarders: `GET /api/global/event`, `GET /api/event`
476
859
  - Downstream heartbeats keep clients and intermediaries alive, while a separate upstream-only stall watchdog closes the downstream response when OpenCode stops producing bytes so clients reconnect instead of trusting synthetic heartbeats indefinitely. Each watchdog reset uses the current load-aware timeout, matching the shared event transport.
477
860
  - Session message forwarder: `POST /api/session/:sessionId/message`
478
- - Interactive OAuth forwarder: `POST /api/provider/:providerID/oauth/callback`
479
- - Upstream blocks inside this call for the whole browser sign-in (device-code polling or a loopback redirect), so it is exempt from the ordinary request deadline and uses a 15-minute proxy timeout instead of `LONG_REQUEST_TIMEOUT_MS`. All other `/api/provider/*` routes, including `oauth/authorize`, keep the ordinary deadline.
861
+ - Session list and detail: `GET /api/session`, `GET /api/session/:sessionID`
862
+ - Both are sanitized to an allowlist of `SessionInfo` fields, then get archive state folded in from `lib/openchamber-sessions/archive-store.js`, because OpenCode 2.x has no archive route, plus any `metadata` entry `lib/openchamber-sessions/session-metadata-store.js` has not migrated from the legacy file yet. An unknown answer from either store leaves the upstream record untouched rather than reporting a session as un-archived or dropping its metadata.
863
+ - Upstream paths are the request paths. OpenCode 2.x serves everything under `/api/*` itself, so the mount prefix Express strips is put back instead of being rewritten away.
864
+ - There is no interactive OAuth forwarder any more: v2 connects providers through `/api/integration/*`, whose OAuth steps return immediately and are polled, so no route needs a longer deadline than the ordinary one.
480
865
  - Generic `/api/*` forwarding with hop-by-hop header filtering
481
- - Windows `/session` merge fallback path behavior
866
+ - Session list forwarding on every platform, preserving V2 query filters and pagination cursors. Global reads use OpenCode's cross-directory list rather than merging per-project pages on Windows.
482
867
  - OpenCode readiness gate for proxied `/api` requests
483
868
  - Worktree checkout gate before directory-scoped upstream reads and writes
484
869
 
@@ -498,15 +883,17 @@ The VS Code extension owns its separate Git and proxy implementation.
498
883
  - `stop()`
499
884
  - Behavior:
500
885
  - Waits for OpenCode readiness before attaching the watcher.
501
- - In production wiring, subscribes to the shared global message-stream hub instead of opening its own `/global/event` connection.
502
- - Can still create its own `/global/event` reader when no shared hub is provided, which keeps module tests and isolated reuse simple.
886
+ - In production wiring, subscribes to the shared global message-stream hub instead of opening its own `/api/event` connection.
887
+ - Can still create its own `/api/event` reader when no shared hub is provided, which keeps module tests and isolated reuse simple.
503
888
  - Reuses event-stream parsing, `Last-Event-ID`, stall timeout, and reconnect behavior.
504
- - Forwards unwrapped global event payloads into notification/session side effects.
889
+ - Translates each v2 wire event through `lib/event-stream/translate-v2.js` before handing it to notification/session side effects, so those consumers keep speaking the server's own event vocabulary.
505
890
 
506
891
  ## Storage and configuration
507
- - Provider auth: `~/.local/share/opencode/auth.json`.
508
- - User config: `$XDG_CONFIG_HOME/opencode/opencode.json`, falling back to `~/.config/opencode/opencode.json` when unset or blank.
509
- - Project config: `<workingDirectory>/.opencode/opencode.json` or `opencode.json`.
892
+ - Provider auth: `~/.local/share/opencode/opencode.db` table `credential` (read-only), with `auth.json` as the legacy fallback; OpenCode 2.x owns credentials.
893
+ - Session archive state: `sessions-archive.json` under the OpenChamber data dir.
894
+ - Session metadata (goal progress, the assist recap, the obligatory-context cursor, pinned notes) lives on the OpenCode session record, written with `PATCH /api/session/{id}` (OpenCode 2.0.15+, the minimum `compatibility.js` enforces). OpenCode replaces the whole object, so `sessionMetadataStore.setSessionMetadata` reads the record, applies the JSON Merge Patch and writes the result, one write per session at a time; a record that cannot be read stops the write. Every reader and writer (routes, goal loop, session assist, session knowledge, obligatory context, notifications) goes through `sessionMetadataStore.get` / `setSessionMetadata`. Older OpenChamber versions kept this state in `sessions-metadata.json` under the data dir. Its entries are the newest metadata their sessions have: the proxy lays them over OpenCode's records, a session's next write pushes its entry, and a sweep after OpenCode starts pushes the rest (a session OpenCode no longer knows is dropped, any other failure waits for the next write or start). The emptied file is renamed to `sessions-metadata.json.migrated`. Archive mutations still run one transaction at a time in the archive store.
895
+ - User config: `<config dir>/opencode.json(c)` where the config dir is `OPENCODE_CONFIG_DIR`, else `$XDG_CONFIG_HOME/opencode`, else `~/.config/opencode`. The v1 `config.json` is not read.
896
+ - Project config: `<workingDirectory>/.opencode/opencode.json(c)` first, else `<workingDirectory>/opencode.json(c)`.
510
897
  - Custom config: `OPENCODE_CONFIG` env var path.
511
898
  - Rate limit config: `OPENCHAMBER_RATE_LIMIT_MAX_ATTEMPTS`, `OPENCHAMBER_RATE_LIMIT_NO_IP_MAX_ATTEMPTS` env vars.
512
899
 
@@ -521,3 +908,36 @@ The VS Code extension owns its separate Git and proxy implementation.
521
908
  The behavior `GET /api/behavior/agents-md` response includes `path`, the effective
522
909
  server-side filename, whether or not the file exists. Settings displays this
523
910
  path without deriving a directory from the browser environment.
911
+
912
+ ## Managed OpenCode config layer (managed-config-file.js)
913
+
914
+ OpenChamber injects its own OpenCode plugins through a file it owns rather than
915
+ through the process environment, because an environment variable cannot change
916
+ under a running child.
917
+
918
+ - Contract: the managed child gets `OPENCODE_CONFIG=<data-dir>/opencode.managed.json`.
919
+ The file contains only `plugins`, holding the absolute directory of every
920
+ OpenChamber plugin currently switched on. Its layer sits above the user's
921
+ global `opencode.json` and below their project config.
922
+ - `OPENCODE_CONFIG_CONTENT` is passed through untouched, so whatever the user
923
+ put there still applies.
924
+ - `OPENCHAMBER_AGENT_TOOL_URL` and a fresh `OPENCHAMBER_AGENT_TOOL_TOKEN` are
925
+ always in the child environment, including while every managed tool is off —
926
+ a tool switched on later then reaches a process that can already call back.
927
+ - `persistSettings` rewrites the file (temp + rename) whenever
928
+ `agentControlToolEnabled`, `agentWebToolEnabled` or `agentMemoryToolEnabled`
929
+ changes. Plugin directories are written before the
930
+ file names them, and a disabled plugin is removed from the list. OpenCode
931
+ reloads within a couple of seconds; no restart is involved.
932
+ - Fallback: when the user's own environment already sets `OPENCODE_CONFIG`,
933
+ OpenChamber does not take it over. It merges its plugin directories into
934
+ `OPENCODE_CONFIG_CONTENT` instead, and those installs keep the old behavior —
935
+ a managed-tool toggle needs an OpenCode restart to take effect.
936
+
937
+ The embedded server controller exposes `getManagedOpenCodePreflight()` for
938
+ desktop bootstrap. It shares the lifecycle's current CLI validation promise,
939
+ including while validation is in flight. It returns false before validation
940
+ starts, after failure, during shutdown, or for external OpenCode. Restart clears
941
+ the previous result, and readers discard results from a replaced preflight.
942
+ This checks CLI compatibility, not server health; the normal startup flow still
943
+ owns connection readiness. Explicit user compatibility checks remain fresh.