@openchambery/web 1.19.22-beta.1 → 2.0.0-beta.10

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 (328) hide show
  1. package/README.md +13 -7
  2. package/bin/cli-opencode.test.js +208 -0
  3. package/bin/cli.js +62 -9
  4. package/bin/lib/cli-startup.js +105 -2
  5. package/bin/lib/cli-startup.test.js +179 -0
  6. package/dist/assets/{AgentAvatar-CRaBJXKs.js → AgentAvatar-CzTtVMnI.js} +1 -1
  7. package/dist/assets/AssistantView-Cg1qQvVe.js +3 -0
  8. package/dist/assets/{DiagramView-D1LGK_s2.js → DiagramView-hOi72Wdx.js} +1 -1
  9. package/dist/assets/{FadeInOnReveal-B0kJo9Ii.js → FadeInOnReveal-DCqrQkkz.js} +1 -1
  10. package/dist/assets/Icon-B8fSTLdP.js +1 -0
  11. package/dist/assets/MarkdownRenderer-Cw74oVxV.js +2 -0
  12. package/dist/assets/{MarkdownRendererImpl-DfoCJ1Mq.js → MarkdownRendererImpl-YM7iRmzK.js} +3 -3
  13. package/dist/assets/MarkstreamRendererImpl-BDy_oGJQ.js +3 -0
  14. package/dist/assets/MobileDetailNavigation-iX_hb_Xt.js +1 -0
  15. package/dist/assets/{MobileShareBridge-2Yjn6wXg.js → MobileShareBridge-CAMUupwR.js} +2 -2
  16. package/dist/assets/MobileSurface-CHbdPcLH.js +2 -0
  17. package/dist/assets/{MultiRunWindow-tTbMFowS.js → MultiRunWindow-Ci1ODFFX.js} +1 -1
  18. package/dist/assets/{OnboardingScreen-CD2KtlF3.js → OnboardingScreen-O4cGdz5p.js} +1 -1
  19. package/dist/assets/OverlayScrollbar-CRfGtcmG.js +2 -0
  20. package/dist/assets/SettingsView-Dg8BtTV1.js +25 -0
  21. package/dist/assets/{SettingsWindow-zIa76s4t.js → SettingsWindow-B8d8qIQ7.js} +1 -1
  22. package/dist/assets/TerminalView-CMiw3s_c.js +8 -0
  23. package/dist/assets/{ToolOutputDialog-DNqA4uBl.js → ToolOutputDialog-ByaQYRTp.js} +2 -2
  24. package/dist/assets/appThemeRegistry-BGGHio8T.js +1 -0
  25. package/dist/assets/{assistant-attachment-cache-C0aRnFkj.js → assistant-attachment-cache-DphJleHr.js} +1 -1
  26. package/dist/assets/{button-CI7Q-Zw_.js → button-DIIrsMjW.js} +1 -1
  27. package/dist/assets/{collapsible-D5Phaykh.js → collapsible-CnvUeYst.js} +1 -1
  28. package/dist/assets/{context-menu-CubSDW2g.js → context-menu-BGBUpZEQ.js} +1 -1
  29. package/dist/assets/{desktopHosts-B1ixEylr.js → desktopHosts-JGFqhlaM.js} +1 -1
  30. package/dist/assets/{desktopRelayRestore-4JmFUw8r.js → desktopRelayRestore-CHEwrI93.js} +1 -1
  31. package/dist/assets/{diagram-DdLO8HZ9.js → diagram-rvn7_qBM.js} +1 -1
  32. package/dist/assets/{dialog-B6pnIYmp.js → dialog-CQ63sc9E.js} +1 -1
  33. package/dist/assets/es-Dsmc0A_3.js +15 -0
  34. package/dist/assets/fileMentionTouchSelection-BzzcWJCi.js +3 -0
  35. package/dist/assets/{fileQueries-DQc8EJUf.js → fileQueries-DN6gbLhM.js} +1 -1
  36. package/dist/assets/fr-C_ZlZDI2.js +13 -0
  37. package/dist/assets/gitApi-BF8vuoZc.js +10 -0
  38. package/dist/assets/{imageSource-BlAJJUEI.js → imageSource-BMztRu0c.js} +1 -1
  39. package/dist/assets/{input-D-__fwRi.js → input-BVu-iykl.js} +1 -1
  40. package/dist/assets/insertionBoundaries-EcAfGT2D.js +1 -0
  41. package/dist/assets/ja-BqqTaWTi.js +15 -0
  42. package/dist/assets/ko-DP2XPM37.js +15 -0
  43. package/dist/assets/main-B7t9lavz.js +2 -0
  44. package/dist/assets/main-D2BzpnUt.css +1 -0
  45. package/dist/assets/main-DWP-prNB.js +169 -0
  46. package/dist/assets/markdown-worker-bS5OgGO3.js +2 -0
  47. package/dist/assets/{markdownHeightCache-BhxqJOvf.js → markdownHeightCache-D9-B1wdY.js} +1 -1
  48. package/dist/assets/markdownTheme-DM5h1i18.js +1 -0
  49. package/dist/assets/mcpQueries-CfXrAkuU.js +1 -0
  50. package/dist/assets/miniChat-DgOrEQbN.js +2 -0
  51. package/dist/assets/mobile-Co_ZOHkZ.js +2 -0
  52. package/dist/assets/multirun-DelyUO6k.js +4 -0
  53. package/dist/assets/persistence-D0y7226-.js +3 -0
  54. package/dist/assets/pl-BCf5uLlK.js +15 -0
  55. package/dist/assets/platform-CurqO28D.js +6 -0
  56. package/dist/assets/{projectMeta-S1hJ7oBp.js → projectMeta-CPElzJ0n.js} +2 -2
  57. package/dist/assets/pt-BR-W09Q2pvn.js +15 -0
  58. package/dist/assets/{relay-image-stream-DM7atqJs.js → relay-image-stream-DrdVj99c.js} +1 -1
  59. package/dist/assets/renderElectronMiniChatApp-pOE93w86.js +2 -0
  60. package/dist/assets/renderMobileApp-F7ZSLcw8.js +28 -0
  61. package/dist/assets/runtime-fetch-Fs9ZV2V8.js +1 -0
  62. package/dist/assets/{runtimeConfig-CMkwoQ_X.js → runtimeConfig-DSS0KxG3.js} +1 -1
  63. package/dist/assets/runtimeEndpointReset-x2Wgx57R.js +149 -0
  64. package/dist/assets/sessionChangeSummary-BUGSYcHp.js +2 -0
  65. package/dist/assets/{sessionLookup-BrU3rFHJ.js → sessionLookup-Bss8M20i.js} +1 -1
  66. package/dist/assets/{sortable-tabs-strip-Fnfhf3K9.js → sortable-tabs-strip-CE7W7lJ9.js} +1 -1
  67. package/dist/assets/src-lS1keDVV.css +2 -0
  68. package/dist/assets/store-jaP79mqI.js +15 -0
  69. package/dist/assets/{terminalApi-xjqssKke.js → terminalApi-mDR2jXTo.js} +1 -1
  70. package/dist/assets/textarea-XD2oX_Ee.js +1 -0
  71. package/dist/assets/{tooltip-0T5jv0cu.js → tooltip-DYeQ_Hvy.js} +1 -1
  72. package/dist/assets/uk-BgFzz8m2.js +15 -0
  73. package/dist/assets/{url-_z7evzdK.js → url-CGbJbiJq.js} +1 -1
  74. package/dist/assets/{useAppFontEffects-C02YFyAv.js → useAppFontEffects-BAWHZ-t0.js} +64 -45
  75. package/dist/assets/{useAssistantUIStore-CMutVh9B.js → useAssistantUIStore-Bz4tRflF.js} +1 -1
  76. package/dist/assets/useDesktopWindowControlsLayout-hN_nLb7T.js +1 -0
  77. package/dist/assets/useEffectiveDirectory-Do9DQ453.js +1 -0
  78. package/dist/assets/{useFontPreferences-B1JYyzpK.js → useFontPreferences-Bjx8zkGM.js} +1 -1
  79. package/dist/assets/useMobileNavigationStore-BsY_gi_K.js +414 -0
  80. package/dist/assets/useSessionAutoCleanup-C4g5KmDf.js +2 -0
  81. package/dist/assets/useUIStore-syVmbuDA.js +1 -0
  82. package/dist/assets/{useWorkerHighlightedLines-C9z0ML1z.js → useWorkerHighlightedLines-B5QXxBok.js} +2 -2
  83. package/dist/assets/vendor-opencode-client-C12gfjag.js +12 -0
  84. package/dist/assets/{vendor-reactuses-core-BnW6GxJt.js → vendor-reactuses-core-Dq5ocTF8.js} +1 -1
  85. package/dist/assets/{vendor-yaml-DIcAK3EC.js → vendor-yaml-C9KlJAlj.js} +37 -37
  86. package/dist/assets/zh-CN-BhqSLgUY.js +15 -0
  87. package/dist/assets/zh-TW-BsaBgY-p.js +15 -0
  88. package/dist/index.html +12 -12
  89. package/dist/mini-chat.html +12 -12
  90. package/dist/mobile.html +12 -12
  91. package/package.json +3 -2
  92. package/server/index.js +423 -20
  93. package/server/lib/assistants/DOCUMENTATION.md +26 -21
  94. package/server/lib/assistants/assign.js +2 -1
  95. package/server/lib/assistants/contact-store.js +37 -19
  96. package/server/lib/assistants/contracts.js +11 -1
  97. package/server/lib/assistants/projection-history.test.js +454 -0
  98. package/server/lib/assistants/routes.js +11 -5
  99. package/server/lib/assistants/service.js +850 -294
  100. package/server/lib/assistants/service.test.js +588 -274
  101. package/server/lib/browser-provider/DOCUMENTATION.md +141 -0
  102. package/server/lib/browser-provider/contract.js +312 -0
  103. package/server/lib/browser-provider/host.js +421 -0
  104. package/server/lib/browser-provider/host.test.js +304 -0
  105. package/server/lib/browser-provider/routes.js +122 -0
  106. package/server/lib/browser-provider/routes.test.js +120 -0
  107. package/server/lib/browser-provider/selection-store.js +43 -0
  108. package/server/lib/browser-provider/selection-store.test.js +35 -0
  109. package/server/lib/conversations/DOCUMENTATION.md +5 -5
  110. package/server/lib/conversations/service.js +87 -57
  111. package/server/lib/conversations/service.test.js +132 -100
  112. package/server/lib/conversations/validation.js +11 -1
  113. package/server/lib/event-stream/DOCUMENTATION.md +3 -1
  114. package/server/lib/event-stream/directory-ws-bridge.js +13 -2
  115. package/server/lib/event-stream/global-hub.js +51 -5
  116. package/server/lib/event-stream/reasoning-projection.js +16 -1
  117. package/server/lib/event-stream/reasoning-projection.test.js +15 -0
  118. package/server/lib/event-stream/runtime.js +57 -20
  119. package/server/lib/event-stream/runtime.test.js +112 -0
  120. package/server/lib/llm/DOCUMENTATION.md +95 -84
  121. package/server/lib/llm/catalog.js +111 -45
  122. package/server/lib/llm/catalog.test.js +121 -59
  123. package/server/lib/llm/completions.js +41 -12
  124. package/server/lib/llm/completions.test.js +45 -4
  125. package/server/lib/llm/generate.js +516 -453
  126. package/server/lib/llm/generate.test.js +705 -484
  127. package/server/lib/llm/routes.js +8 -4
  128. package/server/lib/message-queue/DOCUMENTATION.md +5 -5
  129. package/server/lib/message-queue/opencode-adapter.js +191 -104
  130. package/server/lib/message-queue/opencode-adapter.test.js +328 -58
  131. package/server/lib/message-queue/runtime.js +15 -2
  132. package/server/lib/message-queue/runtime.test.js +6 -6
  133. package/server/lib/message-queue/worker.js +7 -1
  134. package/server/lib/notifications/DOCUMENTATION.md +3 -1
  135. package/server/lib/notifications/runtime.js +133 -31
  136. package/server/lib/notifications/runtime.test.js +103 -0
  137. package/server/lib/notifications/template-runtime.js +130 -38
  138. package/server/lib/notifications/template-runtime.test.js +96 -0
  139. package/server/lib/opencode/DOCUMENTATION.md +111 -16
  140. package/server/lib/opencode/agent-document.d.ts +28 -0
  141. package/server/lib/opencode/agent-document.js +280 -0
  142. package/server/lib/opencode/agent-document.test.js +137 -0
  143. package/server/lib/opencode/agents.js +96 -0
  144. package/server/lib/opencode/auth-state-runtime.js +5 -0
  145. package/server/lib/opencode/bootstrap-runtime.js +2 -0
  146. package/server/lib/opencode/config-entity-routes.js +117 -103
  147. package/server/lib/opencode/config-entity-routes.test.js +148 -10
  148. package/server/lib/opencode/config-hot-reload.integration.test.js +105 -0
  149. package/server/lib/opencode/ensure-cli.d.ts +8 -0
  150. package/server/lib/opencode/ensure-cli.js +238 -0
  151. package/server/lib/opencode/ensure-cli.test.js +119 -0
  152. package/server/lib/opencode/env-runtime.js +208 -111
  153. package/server/lib/opencode/env-runtime.test.js +211 -14
  154. package/server/lib/opencode/feature-routes-runtime.js +90 -5
  155. package/server/lib/opencode/feature-routes-runtime.test.js +25 -0
  156. package/server/lib/opencode/http-server-connections.js +98 -0
  157. package/server/lib/opencode/http-server-connections.test.js +321 -0
  158. package/server/lib/opencode/lifecycle.js +539 -95
  159. package/server/lib/opencode/lifecycle.test.js +698 -6
  160. package/server/lib/opencode/managed-capabilities-runtime.js +15 -2
  161. package/server/lib/opencode/managed-capabilities-runtime.test.js +1 -0
  162. package/server/lib/opencode/network-runtime.js +28 -16
  163. package/server/lib/opencode/network-runtime.test.js +68 -4
  164. package/server/lib/opencode/openchamber-routes.js +7 -1
  165. package/server/lib/opencode/opencode2-pin.js +139 -0
  166. package/server/lib/opencode/opencode2-pin.test.js +88 -0
  167. package/server/lib/opencode/opencode2-sidecar.e2e.test.js +326 -0
  168. package/server/lib/opencode/owned-runtime-upgrade.js +431 -0
  169. package/server/lib/opencode/owned-runtime-upgrade.test.js +160 -0
  170. package/server/lib/opencode/plugin-compatibility.js +15 -0
  171. package/server/lib/opencode/plugin-compatibility.test.js +21 -0
  172. package/server/lib/opencode/plugin-routes.js +3 -18
  173. package/server/lib/opencode/plugin-routes.test.js +9 -9
  174. package/server/lib/opencode/plugins.js +4 -3
  175. package/server/lib/opencode/plugins.test.js +12 -0
  176. package/server/lib/opencode/provider-catalog.js +58 -12
  177. package/server/lib/opencode/provider-catalog.test.js +48 -0
  178. package/server/lib/opencode/proxy.js +373 -28
  179. package/server/lib/opencode/proxy.test.js +353 -0
  180. package/server/lib/opencode/routes.js +333 -76
  181. package/server/lib/opencode/routes.test.js +315 -50
  182. package/server/lib/opencode/runtime-contract.js +401 -0
  183. package/server/lib/opencode/runtime-contract.test.js +214 -0
  184. package/server/lib/opencode/server-opencode-fetch.js +242 -0
  185. package/server/lib/opencode/server-opencode-fetch.test.js +130 -0
  186. package/server/lib/opencode/server-utils-runtime.js +35 -0
  187. package/server/lib/opencode/shared-service.integration.test.js +66 -0
  188. package/server/lib/opencode/shared-service.js +147 -0
  189. package/server/lib/opencode/shared-service.test.js +93 -0
  190. package/server/lib/opencode/shared.js +3 -3
  191. package/server/lib/opencode/shutdown-runtime.js +15 -6
  192. package/server/lib/opencode/shutdown-runtime.test.js +49 -1
  193. package/server/lib/opencode/skill-routes.js +26 -40
  194. package/server/lib/opencode/skill-routes.test.js +71 -7
  195. package/server/lib/opencode/skills.test.js +15 -0
  196. package/server/lib/opencode/startup-pipeline-runtime.js +4 -0
  197. package/server/lib/opencode/static-routes-runtime.js +3 -1
  198. package/server/lib/opencode/static-routes-runtime.test.js +33 -0
  199. package/server/lib/opencode/upgrade-screen.d.ts +30 -0
  200. package/server/lib/opencode/upgrade-screen.js +299 -0
  201. package/server/lib/opencode/upgrade-screen.test.js +196 -0
  202. package/server/lib/opencode/v1-migration-gate.js +157 -0
  203. package/server/lib/opencode/v1-migration-gate.test.js +111 -0
  204. package/server/lib/opencode/v2-client.js +60 -0
  205. package/server/lib/opencode/v2-plugin-host-shim/index.mjs +155 -0
  206. package/server/lib/opencode/v2-plugin-host-shim/package.json +4 -0
  207. package/server/lib/opencode/watcher.js +2 -1
  208. package/server/lib/opencode/watcher.test.js +1 -1
  209. package/server/lib/permission-auto-accept/DOCUMENTATION.md +5 -5
  210. package/server/lib/permission-auto-accept/runtime.js +14 -7
  211. package/server/lib/permission-auto-accept/runtime.test.js +27 -12
  212. package/server/lib/relay/reasoning-projection.e2e.test.ts +22 -7
  213. package/server/lib/scheduled-tasks/DOCUMENTATION.md +79 -39
  214. package/server/lib/scheduled-tasks/managed-tool-route.js +31 -1
  215. package/server/lib/scheduled-tasks/managed-tool-route.test.js +23 -0
  216. package/server/lib/scheduled-tasks/routes.js +27 -0
  217. package/server/lib/scheduled-tasks/routes.test.js +94 -0
  218. package/server/lib/scheduled-tasks/runtime.js +381 -310
  219. package/server/lib/scheduled-tasks/runtime.test.js +600 -309
  220. package/server/lib/session-goal/DOCUMENTATION.md +173 -22
  221. package/server/lib/session-goal/capability.js +57 -0
  222. package/server/lib/session-goal/capability.test.js +33 -0
  223. package/server/lib/session-goal/routes.js +240 -2
  224. package/server/lib/session-goal/routes.test.js +211 -0
  225. package/server/lib/session-goal/runtime.js +1617 -113
  226. package/server/lib/session-goal/runtime.test.js +1500 -70
  227. package/server/lib/session-index/DOCUMENTATION.md +18 -15
  228. package/server/lib/session-index/event-ingest.js +89 -16
  229. package/server/lib/session-index/event-ingest.test.js +73 -0
  230. package/server/lib/session-index/host-authority-snapshot.js +92 -0
  231. package/server/lib/session-index/routes.host-archive.test.js +201 -0
  232. package/server/lib/session-index/routes.js +63 -10
  233. package/server/lib/session-index/routes.test.js +8 -8
  234. package/server/lib/session-index/service.js +7 -1
  235. package/server/lib/session-index/sync-runtime.js +171 -41
  236. package/server/lib/session-index/sync-runtime.test.js +164 -9
  237. package/server/lib/session-metadata/DOCUMENTATION.md +96 -0
  238. package/server/lib/session-metadata/opencode-session-record.d.ts +57 -0
  239. package/server/lib/session-metadata/opencode-session-record.js +316 -0
  240. package/server/lib/session-metadata/opencode-session-record.test.js +242 -0
  241. package/server/lib/session-metadata/routes.js +197 -0
  242. package/server/lib/session-metadata/routes.test.js +156 -0
  243. package/server/lib/session-metadata/session-archive.d.ts +73 -0
  244. package/server/lib/session-metadata/session-archive.js +654 -0
  245. package/server/lib/session-metadata/session-archive.test.js +359 -0
  246. package/server/lib/session-metadata/session-metadata-store.d.ts +38 -0
  247. package/server/lib/session-metadata/session-metadata-store.js +422 -0
  248. package/server/lib/session-metadata/session-metadata-store.test.js +379 -0
  249. package/server/lib/session-metadata/session-projection.d.ts +41 -0
  250. package/server/lib/session-metadata/session-projection.js +279 -0
  251. package/server/lib/session-metadata/session-projection.test.js +64 -0
  252. package/server/lib/session-metadata/system-session.js +55 -0
  253. package/server/lib/session-metadata/system-session.test.js +55 -0
  254. package/server/lib/session-title/DOCUMENTATION.md +40 -7
  255. package/server/lib/session-title/native-runtime.test.js +167 -0
  256. package/server/lib/session-title/runtime.js +69 -44
  257. package/server/lib/session-title/session-access.js +46 -0
  258. package/server/lib/session-title/session-access.test.js +91 -0
  259. package/server/lib/session-turn-pages/DOCUMENTATION.md +12 -11
  260. package/server/lib/session-turn-pages/reconcile.service.js +1 -1
  261. package/server/lib/session-turn-pages/reconcile.service.test.js +16 -0
  262. package/server/lib/session-turn-pages/routes.js +123 -75
  263. package/server/lib/session-turn-pages/routes.test.js +566 -0
  264. package/server/lib/session-turn-pages/service.js +6 -2
  265. package/server/lib/session-turn-pages/service.test.js +34 -0
  266. package/server/lib/session-turn-pages/session-message-projection.d.ts +13 -0
  267. package/server/lib/session-turn-pages/session-message-projection.js +281 -0
  268. package/server/lib/small-model/DOCUMENTATION.md +101 -146
  269. package/server/lib/small-model/catalog.js +84 -54
  270. package/server/lib/small-model/catalog.test.js +111 -9
  271. package/server/lib/small-model/custom-api.js +68 -0
  272. package/server/lib/small-model/custom-api.test.js +64 -0
  273. package/server/lib/small-model/index.js +125 -241
  274. package/server/lib/small-model/resolve.js +35 -120
  275. package/server/lib/small-model/resolve.test.js +20 -110
  276. package/server/lib/small-model/routes.js +1 -3
  277. package/server/lib/small-model/summary-settings.test.js +157 -253
  278. package/server/opencode-proxy.test.js +63 -12
  279. package/dist/assets/AssistantView-BUveAgc4.js +0 -3
  280. package/dist/assets/Icon-BgdfPhNs.js +0 -1
  281. package/dist/assets/MarkdownRenderer-BbrbDH6-.js +0 -2
  282. package/dist/assets/MarkstreamRendererImpl-D2dsW5Lg.js +0 -3
  283. package/dist/assets/MobileDetailNavigation-B0aqKXd7.js +0 -1
  284. package/dist/assets/MobileSurface-DW7WfPsy.js +0 -2
  285. package/dist/assets/OverlayScrollbar-DrA0Vsg5.js +0 -2
  286. package/dist/assets/SettingsView-PkXIavr7.js +0 -25
  287. package/dist/assets/TerminalView-CDdzF4yi.js +0 -8
  288. package/dist/assets/appThemeRegistry-D5Yxg4YF.js +0 -1
  289. package/dist/assets/es-DA3MqOo0.js +0 -15
  290. package/dist/assets/fileMentionTouchSelection-DNeiqns-.js +0 -4
  291. package/dist/assets/fr-Dbz0CdIA.js +0 -13
  292. package/dist/assets/gitApi-DXyC4MiV.js +0 -7
  293. package/dist/assets/insertionBoundaries-KlOVrHHt.js +0 -1
  294. package/dist/assets/ja-DumanVQA.js +0 -15
  295. package/dist/assets/ko-C0IkiUjQ.js +0 -15
  296. package/dist/assets/main-BPS5ylib.js +0 -2
  297. package/dist/assets/main-Cpd9VWYs.js +0 -169
  298. package/dist/assets/main-qSeeJRW1.css +0 -1
  299. package/dist/assets/markdown-worker-CptoICmq.js +0 -2
  300. package/dist/assets/markdownTheme-DOfGg-A7.js +0 -1
  301. package/dist/assets/miniChat-B8_KLWiY.js +0 -2
  302. package/dist/assets/mobile-CtktKrXn.js +0 -2
  303. package/dist/assets/multirun-CYfP9Cfm.js +0 -4
  304. package/dist/assets/persistence-Ce3AnpEr.js +0 -3
  305. package/dist/assets/pl-B9No6MQp.js +0 -15
  306. package/dist/assets/platform-0w_Q9_ji.js +0 -2
  307. package/dist/assets/pt-BR-DyQ0WTDh.js +0 -15
  308. package/dist/assets/renderElectronMiniChatApp-iK14LWm8.js +0 -2
  309. package/dist/assets/renderMobileApp-DORLPWnb.js +0 -28
  310. package/dist/assets/runtime-fetch-zIalUnbb.js +0 -1
  311. package/dist/assets/runtimeEndpointReset-ChOxt-J7.js +0 -147
  312. package/dist/assets/sessionChangeSummary-NnxcqCTI.js +0 -2
  313. package/dist/assets/src-rS3zCcsC.css +0 -2
  314. package/dist/assets/store-5B_LDnLM.js +0 -15
  315. package/dist/assets/textarea-bHYxZtfH.js +0 -1
  316. package/dist/assets/uk-C_1KkqyP.js +0 -15
  317. package/dist/assets/useDesktopWindowControlsLayout-Dnr-jX0C.js +0 -1
  318. package/dist/assets/useEffectiveDirectory-CZLLyarc.js +0 -1
  319. package/dist/assets/useMobileNavigationStore-CoCiqNgm.js +0 -413
  320. package/dist/assets/useSessionAutoCleanup-xQyETQkG.js +0 -2
  321. package/dist/assets/useUIStore-Bxv3f23A.js +0 -1
  322. package/dist/assets/vendor-opencode-sdk-C07HQypa.js +0 -7
  323. package/dist/assets/zh-CN-uWILgBdt.js +0 -15
  324. package/dist/assets/zh-TW-MYfdvhbD.js +0 -15
  325. package/server/lib/small-model/call.js +0 -427
  326. package/server/lib/small-model/call.test.js +0 -382
  327. package/server/lib/small-model/opencode-session.js +0 -339
  328. package/server/lib/small-model/opencode-session.test.js +0 -177
package/server/index.js CHANGED
@@ -39,6 +39,7 @@ import { resolveOpenCodeEnvConfig } from './lib/opencode/env-config.js';
39
39
  import { createHmrStateRuntime } from './lib/opencode/hmr-state-runtime.js';
40
40
  import { createOpenCodeNetworkRuntime } from './lib/opencode/network-runtime.js';
41
41
  import { createOpenCodeAuthStateRuntime } from './lib/opencode/auth-state-runtime.js';
42
+ import { createSharedOpenCodeService, isSharedServiceEnabled } from './lib/opencode/shared-service.js';
42
43
  import { createProjectDirectoryRuntime } from './lib/opencode/project-directory-runtime.js';
43
44
  import { createSettingsNormalizationRuntime } from './lib/opencode/settings-normalization-runtime.js';
44
45
  import { createSettingsHelpers } from './lib/opencode/settings-helpers.js';
@@ -52,6 +53,11 @@ import {
52
53
  } from './lib/opencode/core-routes.js';
53
54
  import { registerOpenChamberRoutes } from './lib/opencode/openchamber-routes.js';
54
55
  import { createServerUtilsRuntime } from './lib/opencode/server-utils-runtime.js';
56
+ import {
57
+ configureServerOpenCodeFetchGate,
58
+ createServerOpenCodeFetch,
59
+ wrapFetchWithRuntimeContractGate,
60
+ } from './lib/opencode/server-opencode-fetch.js';
55
61
  import { createStaticRoutesRuntime } from './lib/opencode/static-routes-runtime.js';
56
62
  import { createSettingsRuntime } from './lib/opencode/settings-runtime.js';
57
63
  import { createOpenCodeResolutionRuntime } from './lib/opencode/opencode-resolution-runtime.js';
@@ -59,6 +65,7 @@ import { createBootstrapRuntime } from './lib/opencode/bootstrap-runtime.js';
59
65
  import { createSessionRuntime } from './lib/opencode/session-runtime.js';
60
66
  import { createOpenCodeWatcherRuntime } from './lib/opencode/watcher.js';
61
67
  import { createSessionTitleRuntime } from './lib/session-title/runtime.js';
68
+ import { createTitleSessionAccess } from './lib/session-title/session-access.js';
62
69
  import { createSessionIndexService } from './lib/session-index/service.js';
63
70
  import { createSessionIndexSyncRuntime } from './lib/session-index/sync-runtime.js';
64
71
  import { resolveSessionIndexDbPath } from './lib/session-index/resolve-db-path.js';
@@ -68,7 +75,24 @@ import { resolveTranscriptCacheDbPath } from './lib/transcript-cache/resolve-db-
68
75
  import { createMessageQueueRuntime } from './lib/message-queue/runtime.js';
69
76
  import { resolveMessageQueueDbPath } from './lib/message-queue/resolve-db-path.js';
70
77
  import { createOpenChamberEventBroadcaster } from './lib/opencode/feature-routes-runtime.js';
71
- import { createSessionGoalRuntime } from './lib/session-goal/runtime.js';
78
+ import {
79
+ createSessionGoalRuntime,
80
+ withGoalExecutionGeneration,
81
+ } from './lib/session-goal/runtime.js';
82
+ import { createSessionMetadataStore } from './lib/session-metadata/session-metadata-store.js';
83
+ import {
84
+ createHttpSessionRecordClient,
85
+ retainOpenCodeSessions,
86
+ startSideStoreMigration,
87
+ } from './lib/session-metadata/opencode-session-record.js';
88
+ import {
89
+ createSessionArchiveService,
90
+ createUpstreamSessionFetcher,
91
+ } from './lib/session-metadata/session-archive.js';
92
+ import {
93
+ projectSessionLifecyclePayload,
94
+ projectSessionWithStoredMap,
95
+ } from './lib/session-metadata/session-projection.js';
72
96
  import { createScheduledTasksRuntime } from './lib/scheduled-tasks/runtime.js';
73
97
  import { createScheduledTaskRunHistoryStore } from './lib/scheduled-tasks/run-history-store.js';
74
98
  import { createServerStartupRuntime } from './lib/opencode/server-startup-runtime.js';
@@ -88,6 +112,7 @@ import { createNotificationTemplateRuntime } from './lib/notifications/template-
88
112
  import { createPermissionAutoAcceptRuntime } from './lib/permission-auto-accept/runtime.js';
89
113
  import { createQuestionAutoDelegateRuntime } from './lib/question-auto-delegate/runtime.js';
90
114
  import { createGracefulShutdownRuntime } from './lib/opencode/shutdown-runtime.js';
115
+ import { attachHttpServerConnectionTracker } from './lib/opencode/http-server-connections.js';
91
116
  import { createProjectConfigRuntime } from './lib/projects/project-config.js';
92
117
  import { createRemoteClientAuthRuntime } from './lib/client-auth/remote-clients.js';
93
118
  import { applyRuntimeCorsHeaders } from './lib/request-cors.js';
@@ -445,6 +470,12 @@ let openCodeApiDetectionTimer = null;
445
470
  let lastOpenCodeError = null;
446
471
  let lastOpenCodeLaunchDiagnostics = null;
447
472
  let isOpenCodeReady = false;
473
+ let v1Migration = null;
474
+ let openCodeServeVersion = null;
475
+ let openCodeCliVersion = null;
476
+ let runtimeContract = null;
477
+ /** Bumps on start/restart so stale async health cannot re-permit an old instance. */
478
+ let runtimeContractGeneration = 0;
448
479
  let openCodeNotReadySince = 0;
449
480
  let isExternalOpenCode = false;
450
481
  let exitOnShutdown = true;
@@ -549,6 +580,7 @@ const openCodeAuthStateRuntime = createOpenCodeAuthStateRuntime({
549
580
  const getOpenCodeAuthHeaders = (...args) => openCodeAuthStateRuntime.getOpenCodeAuthHeaders(...args);
550
581
  const isOpenCodeConnectionSecure = (...args) => openCodeAuthStateRuntime.isOpenCodeConnectionSecure(...args);
551
582
  const ensureLocalOpenCodeServerPassword = (...args) => openCodeAuthStateRuntime.ensureLocalOpenCodeServerPassword(...args);
583
+ const adoptOpenCodeServerPassword = (...args) => openCodeAuthStateRuntime.adoptOpenCodeServerPassword(...args);
552
584
 
553
585
  const openCodeNetworkState = {};
554
586
  Object.defineProperties(openCodeNetworkState, {
@@ -572,6 +604,15 @@ const buildOpenCodeUrl = (...args) => openCodeNetworkRuntime.buildOpenCodeUrl(..
572
604
  const ensureOpenCodeApiPrefix = (...args) => openCodeNetworkRuntime.ensureOpenCodeApiPrefix(...args);
573
605
  const scheduleOpenCodeApiDetection = (...args) => openCodeNetworkRuntime.scheduleOpenCodeApiDetection(...args);
574
606
 
607
+ // Host OpenCode transport gate (queue/goal/scheduled/assistants + v2-client).
608
+ // Registered before background runtimes so direct OpenCode writes share proxy admission.
609
+ configureServerOpenCodeFetchGate(() => runtimeContract);
610
+ const serverOpenCodeFetch = createServerOpenCodeFetch({
611
+ buildOpenCodeUrl,
612
+ getOpenCodeAuthHeaders,
613
+ getRuntimeContract: () => runtimeContract,
614
+ });
615
+
575
616
  const ENV_CONFIGURED_API_PREFIX = normalizeApiPrefix(
576
617
  process.env.OPENCODE_API_PREFIX || process.env.OPENCHAMBER_API_PREFIX || ''
577
618
  );
@@ -614,6 +655,7 @@ const openCodeEnvRuntime = createOpenCodeEnvRuntime({
614
655
  const applyLoginShellEnvSnapshot = (...args) => openCodeEnvRuntime.applyLoginShellEnvSnapshot(...args);
615
656
  const getLoginShellEnvSnapshot = (...args) => openCodeEnvRuntime.getLoginShellEnvSnapshot(...args);
616
657
  const ensureOpencodeCliEnv = (...args) => openCodeEnvRuntime.ensureOpencodeCliEnv(...args);
658
+ const ensurePinnedOpenCode2CliEnv = (...args) => openCodeEnvRuntime.ensurePinnedOpenCode2CliEnv(...args);
617
659
  const applyOpencodeBinaryFromSettings = (...args) => openCodeEnvRuntime.applyOpencodeBinaryFromSettings(...args);
618
660
  const resolveOpencodeCliPath = (...args) => openCodeEnvRuntime.resolveOpencodeCliPath(...args);
619
661
  const isExecutable = (...args) => openCodeEnvRuntime.isExecutable(...args);
@@ -621,6 +663,7 @@ const searchPathFor = (...args) => openCodeEnvRuntime.searchPathFor(...args);
621
663
  const resolveGitBinaryForSpawn = (...args) => openCodeEnvRuntime.resolveGitBinaryForSpawn(...args);
622
664
  const resolveManagedOpenCodeLaunchSpec = (...args) => openCodeEnvRuntime.resolveManagedOpenCodeLaunchSpec(...args);
623
665
  const clearResolvedOpenCodeBinary = (...args) => openCodeEnvRuntime.clearResolvedOpenCodeBinary(...args);
666
+ const forceResolvedOpenCodeBinary = (...args) => openCodeEnvRuntime.forceResolvedOpenCodeBinary(...args);
624
667
  const openCodeResolutionRuntime = createOpenCodeResolutionRuntime({
625
668
  path,
626
669
  resolveOpencodeCliPath,
@@ -696,6 +739,8 @@ const getSmallModelService = async () => {
696
739
  smallModelServiceInstance = createSmallModelService({
697
740
  buildOpenCodeUrl,
698
741
  getOpenCodeAuthHeaders,
742
+ persistSessionMetadata: persistSessionMetadataToStore,
743
+ onSystemSessionPersisted: hideSystemSessionFromIndex,
699
744
  });
700
745
  }
701
746
  return smallModelServiceInstance;
@@ -705,6 +750,19 @@ const sessionTitleRuntime = createSessionTitleRuntime({
705
750
  buildOpenCodeUrl,
706
751
  getOpenCodeAuthHeaders,
707
752
  getSmallModelService,
753
+ serverOpenCodeFetch,
754
+ sessionAccess: createTitleSessionAccess({
755
+ buildOpenCodeUrl,
756
+ getOpenCodeAuthHeaders,
757
+ readSessionMetadata: (sessionID) => sessionMetadataStore.get(sessionID),
758
+ persistSessionMetadata: (sessionID, patch) => persistSessionMetadataToStore(sessionID, patch),
759
+ publishSession: (session, directory) => {
760
+ const payload = { type: 'session.updated', properties: { info: session, directory } };
761
+ broadcastGlobalUiEvent(payload);
762
+ const changed = sessionIndexServiceRef?.upsertAndReportChange(session);
763
+ if (changed) sessionIndexSyncRuntimeRef?.publishChange();
764
+ },
765
+ }),
708
766
  });
709
767
 
710
768
  // Forward declaration: question auto-delegate is created after the event hub;
@@ -713,9 +771,141 @@ let questionAutoDelegateRuntime = null;
713
771
  /** Filled inside main() once the SQLite session index is constructed. */
714
772
  let sessionIndexServiceRef = null;
715
773
 
774
+ const sessionRecordClient = createHttpSessionRecordClient({
775
+ buildSessionUrl: (sessionID, directory) => {
776
+ const url = new URL(buildOpenCodeUrl(`/session/${encodeURIComponent(sessionID)}`));
777
+ if (directory) url.searchParams.set('directory', directory);
778
+ return url.toString();
779
+ },
780
+ getHeaders: () => getOpenCodeAuthHeaders(),
781
+ fetchFn: wrapFetchWithRuntimeContractGate(fetch),
782
+ });
783
+ const sessionMetadataStore = createSessionMetadataStore({
784
+ dataDir: OPENCHAMBER_DATA_DIR,
785
+ recordReader: (sessionID, directory) => sessionRecordClient.read(sessionID, directory),
786
+ recordWriter: (sessionID, metadata, directory) => sessionRecordClient.write({
787
+ sessionID,
788
+ metadata,
789
+ directory,
790
+ }),
791
+ });
792
+ const stopSessionRecordMigration = startSideStoreMigration({
793
+ load: () => sessionMetadataStore.load(),
794
+ readSession: (sessionID) => sessionRecordClient.read(sessionID),
795
+ writeMetadata: async (sessionID, metadata, record) => {
796
+ const directory = record?.location?.directory || record?.directory || undefined;
797
+ await sessionRecordClient.write({ sessionID, metadata, directory });
798
+ },
799
+ });
800
+ /**
801
+ * load() resolves `{ ok:false }` on read/corrupt failure (does not reject).
802
+ * Callers must check ok / isLoaded — never treat unresolved as empty success.
803
+ */
804
+ const ensureSessionMetadataReady = async () => {
805
+ try {
806
+ const result = await sessionMetadataStore.load();
807
+ return result?.ok === true && sessionMetadataStore.isLoaded();
808
+ } catch (error) {
809
+ console.warn('[session-metadata] load threw:', error?.message ?? error);
810
+ return false;
811
+ }
812
+ };
813
+ // Prime without blocking module init; production gates (hub/SSE/routes) await ready.
814
+ void ensureSessionMetadataReady().then((ok) => {
815
+ if (!ok) {
816
+ console.warn(
817
+ '[session-metadata] initial load not ready:',
818
+ sessionMetadataStore.getLoadFailureReason?.() || 'unknown',
819
+ );
820
+ }
821
+ });
822
+
823
+ /**
824
+ * Goal write through the Host metadata store.
825
+ * Advances executionGeneration on pause/resume/condition changes so late audits
826
+ * cannot commit against a prior execution permit. Broadcasts only after commit.
827
+ */
828
+ const persistSessionGoalToStore = async (sessionId, _directory, goal) => {
829
+ const result = await sessionMetadataStore.mutateSessionMetadata(sessionId, (current) => {
830
+ const previousGoal = current?.openchamber?.goal && typeof current.openchamber.goal === 'object'
831
+ ? current.openchamber.goal
832
+ : null;
833
+ const nextGoal = withGoalExecutionGeneration(previousGoal, goal);
834
+ return { ok: true, patch: { openchamber: { goal: nextGoal } } };
835
+ });
836
+ if (!result?.committed) {
837
+ throw new Error(result?.reason || 'session goal persist was rejected');
838
+ }
839
+ const metadata = result.metadata;
840
+ try {
841
+ broadcastGlobalUiEvent({
842
+ type: 'openchamber:session-metadata',
843
+ properties: { sessionID: sessionId, metadata },
844
+ });
845
+ } catch (error) {
846
+ console.warn('[session-metadata] broadcast failed:', error?.message ?? error);
847
+ }
848
+ return metadata;
849
+ };
850
+
851
+ /**
852
+ * Isolation / Host metadata write. Same store + broadcast seam as goal persist.
853
+ * Callers pass an RFC 7386 merge patch; the store returns the committed object.
854
+ */
855
+ const persistSessionMetadataToStore = async (sessionId, patch) => {
856
+ const metadata = await sessionMetadataStore.setSessionMetadata(sessionId, patch);
857
+ try {
858
+ broadcastGlobalUiEvent({
859
+ type: 'openchamber:session-metadata',
860
+ properties: { sessionID: sessionId, metadata },
861
+ });
862
+ } catch (error) {
863
+ console.warn('[session-metadata] broadcast failed:', error?.message ?? error);
864
+ }
865
+ return metadata;
866
+ };
867
+
868
+ /**
869
+ * After Host isolation metadata is committed, drop the session from the
870
+ * sidebar index immediately. Do not wait for the next directory list sync.
871
+ * Reads refs at call time — scheduled-task runtime is constructed before main().
872
+ */
873
+ const hideSystemSessionFromIndex = ({ sessionID, directory, metadata } = {}) => {
874
+ if (!sessionIndexServiceRef || typeof sessionID !== 'string' || !sessionID) return;
875
+ const changed = sessionIndexServiceRef.upsertAndReportChange({
876
+ id: sessionID,
877
+ directory: directory || '',
878
+ metadata,
879
+ });
880
+ if (changed) {
881
+ sessionIndexSyncRuntimeRef?.publishChange();
882
+ }
883
+ };
884
+
885
+ /** Filled in main() once the session index + broadcast sinks exist. */
886
+ let sessionArchiveServiceRef = null;
887
+ let sessionIndexSyncRuntimeRef = null;
888
+
889
+ const readHostMetadataForSession = (sessionID) => {
890
+ const snap = sessionMetadataStore.getSnapshotSync();
891
+ if (!snap || typeof sessionID !== 'string') return null;
892
+ const host = snap[sessionID];
893
+ return host && typeof host === 'object' && !Array.isArray(host) ? host : null;
894
+ };
895
+
896
+ const projectHostSessionPayload = (payload) => {
897
+ const ready = sessionMetadataStore.isLoaded();
898
+ return projectSessionLifecyclePayload(
899
+ payload,
900
+ readHostMetadataForSession,
901
+ { hostReady: ready },
902
+ );
903
+ };
904
+
716
905
  const sessionGoalRuntime = createSessionGoalRuntime({
717
906
  buildOpenCodeUrl,
718
907
  getOpenCodeAuthHeaders,
908
+ serverOpenCodeFetch,
719
909
  getSmallModelService,
720
910
  shouldKeepGoalActiveForQuestion: (sessionId) => (
721
911
  questionAutoDelegateRuntime?.isAutoHandling(sessionId) === true
@@ -726,6 +916,28 @@ const sessionGoalRuntime = createSessionGoalRuntime({
726
916
  onGoalPaused: (sessionId, directory) => (
727
917
  questionAutoDelegateRuntime?.pauseForSessionTree?.(sessionId, directory)
728
918
  ),
919
+ readSessionMetadata: (sessionId) => sessionMetadataStore.get(sessionId),
920
+ // Conditional commit on the store's exclusive serial boundary (generation +
921
+ // status preconditions share the lock with persist). Broadcast-only on
922
+ // success — do not feed progress writes back into processPayload.
923
+ mutateSessionMetadata: async (sessionId, decide) => {
924
+ const result = await sessionMetadataStore.mutateSessionMetadata(sessionId, decide);
925
+ if (result?.committed) {
926
+ try {
927
+ broadcastGlobalUiEvent({
928
+ type: 'openchamber:session-metadata',
929
+ properties: { sessionID: sessionId, metadata: result.metadata },
930
+ });
931
+ } catch (error) {
932
+ console.warn('[session-metadata] broadcast failed:', error?.message ?? error);
933
+ }
934
+ }
935
+ return result;
936
+ },
937
+ persistSessionGoal: async (sessionId, directory, goal) => {
938
+ const metadata = await persistSessionGoalToStore(sessionId, directory, goal);
939
+ return metadata?.openchamber?.goal ?? goal;
940
+ },
729
941
  emitGoalNotification: async ({ sessionId, directory, status, goal }) => {
730
942
  // The goal settle notification replaces the per-turn ready notifications
731
943
  // (suppressed while the goal is active) — so it obeys the same toggle.
@@ -766,6 +978,7 @@ const globalMessageStreamHub = createGlobalMessageStreamHub({
766
978
  buildOpenCodeUrl,
767
979
  getOpenCodeAuthHeaders,
768
980
  upstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
981
+ projectOutboundSessionPayload: projectHostSessionPayload,
769
982
  });
770
983
 
771
984
  const permissionAutoAcceptRuntime = createPermissionAutoAcceptRuntime({
@@ -908,6 +1121,9 @@ const serverUtilsRuntime = createServerUtilsRuntime({
908
1121
  openCodeNotReadySince,
909
1122
  isOpenCodeReady,
910
1123
  isRestartingOpenCode,
1124
+ v1Migration,
1125
+ runtimeContract,
1126
+ openCodeServeVersion,
911
1127
  }),
912
1128
  getOpenCodeAuthHeaders,
913
1129
  buildOpenCodeUrl,
@@ -934,6 +1150,13 @@ const serverUtilsRuntime = createServerUtilsRuntime({
934
1150
  }
935
1151
  return snapshot.PATH;
936
1152
  },
1153
+ getStoredSessionMetadata: () => sessionMetadataStore.getAll(),
1154
+ getStoredSessionMetadataSync: () => sessionMetadataStore.getSnapshotSync(),
1155
+ ensureSessionMetadataReady,
1156
+ onSessionDeleted: (sessionID) => {
1157
+ if (!sessionArchiveServiceRef) return sessionMetadataStore.removeSession(sessionID);
1158
+ return sessionArchiveServiceRef.forgetSession(sessionID);
1159
+ },
937
1160
  });
938
1161
 
939
1162
  const setOpenCodePort = (...args) => serverUtilsRuntime.setOpenCodePort(...args);
@@ -1003,6 +1226,14 @@ Object.defineProperties(openCodeLifecycleState, {
1003
1226
  lastOpenCodeError: { get: () => lastOpenCodeError, set: (value) => { lastOpenCodeError = value; } },
1004
1227
  lastOpenCodeLaunchDiagnostics: { get: () => lastOpenCodeLaunchDiagnostics, set: (value) => { lastOpenCodeLaunchDiagnostics = value; } },
1005
1228
  isOpenCodeReady: { get: () => isOpenCodeReady, set: (value) => { isOpenCodeReady = value; } },
1229
+ v1Migration: { get: () => v1Migration, set: (value) => { v1Migration = value; } },
1230
+ openCodeServeVersion: { get: () => openCodeServeVersion, set: (value) => { openCodeServeVersion = value; } },
1231
+ openCodeCliVersion: { get: () => openCodeCliVersion, set: (value) => { openCodeCliVersion = value; } },
1232
+ runtimeContract: { get: () => runtimeContract, set: (value) => { runtimeContract = value; } },
1233
+ runtimeContractGeneration: {
1234
+ get: () => runtimeContractGeneration,
1235
+ set: (value) => { runtimeContractGeneration = value; },
1236
+ },
1006
1237
  openCodeNotReadySince: { get: () => openCodeNotReadySince, set: (value) => { openCodeNotReadySince = value; } },
1007
1238
  isExternalOpenCode: { get: () => isExternalOpenCode, set: (value) => { isExternalOpenCode = value; } },
1008
1239
  isShuttingDown: { get: () => isShuttingDown, set: (value) => { isShuttingDown = value; } },
@@ -1047,7 +1278,10 @@ const openCodeLifecycleRuntime = createOpenCodeLifecycleRuntime({
1047
1278
  normalizeApiPrefix,
1048
1279
  applyOpencodeBinaryFromSettings,
1049
1280
  ensureOpencodeCliEnv,
1281
+ ensurePinnedOpenCode2CliEnv,
1050
1282
  ensureLocalOpenCodeServerPassword,
1283
+ adoptOpenCodeServerPassword,
1284
+ sharedService: isSharedServiceEnabled() ? createSharedOpenCodeService() : null,
1051
1285
  resolveManagedOpenCodeLaunchSpec,
1052
1286
  setOpenCodePort,
1053
1287
  setDetectedOpenCodeApiPrefix,
@@ -1059,6 +1293,26 @@ const openCodeLifecycleRuntime = createOpenCodeLifecycleRuntime({
1059
1293
  getManagedOpenCodeShellEnvSnapshot: getLoginShellEnvSnapshot,
1060
1294
  managedCapabilitiesRuntime,
1061
1295
  getActiveSessionCount,
1296
+ // Most-recently-used directories first: OpenCode initializes each directory
1297
+ // lazily on first request (seconds on large session stores), so the
1298
+ // lifecycle warms these right after readiness — before the UI's first
1299
+ // interactive request would otherwise pay that cost.
1300
+ getWarmupDirectories: async () => {
1301
+ const settings = await readSettingsFromDiskMigrated().catch(() => null);
1302
+ if (!settings) return [];
1303
+ const directories = [];
1304
+ if (typeof settings.lastDirectory === 'string' && settings.lastDirectory) {
1305
+ directories.push(settings.lastDirectory);
1306
+ }
1307
+ const projects = Array.isArray(settings.projects) ? [...settings.projects] : [];
1308
+ projects.sort((a, b) => (b?.lastOpenedAt ?? 0) - (a?.lastOpenedAt ?? 0));
1309
+ for (const project of projects) {
1310
+ if (typeof project?.path === 'string' && project.path) {
1311
+ directories.push(project.path);
1312
+ }
1313
+ }
1314
+ return [...new Set(directories)];
1315
+ },
1062
1316
  });
1063
1317
 
1064
1318
  const restartOpenCode = (...args) => openCodeLifecycleRuntime.restartOpenCode(...args);
@@ -1081,6 +1335,25 @@ const scheduledTasksRuntime = createScheduledTasksRuntime({
1081
1335
  getSmallModelService,
1082
1336
  waitForOpenCodeReady,
1083
1337
  runHistoryStore: scheduledTaskRunHistoryStore,
1338
+ // Same Host store seam as session-goal / manual UI metadata writes.
1339
+ readSessionMetadata: (sessionId) => sessionMetadataStore.get(sessionId),
1340
+ persistSessionMetadata: persistSessionMetadataToStore,
1341
+ onSystemSessionPersisted: hideSystemSessionFromIndex,
1342
+ persistSessionGoal: persistSessionGoalToStore,
1343
+ // Arm the goal loop after first persist only — do not feed progress writes
1344
+ // back through processPayload (session-goal runtime already broadcasts those).
1345
+ onGoalPersisted: ({ sessionID, directory, metadata }) => {
1346
+ sessionGoalRuntime.processPayload({
1347
+ type: 'session.updated',
1348
+ properties: {
1349
+ info: {
1350
+ id: sessionID,
1351
+ directory: directory || '',
1352
+ metadata,
1353
+ },
1354
+ },
1355
+ }, directory || '');
1356
+ },
1084
1357
  emitTaskRunEvent: (event) => {
1085
1358
  for (const client of uiOpenChamberEventClients) {
1086
1359
  try {
@@ -1108,7 +1381,19 @@ const ensureGlobalWatcherStarted = async () => {
1108
1381
  return globalWatcherStartPromise;
1109
1382
  }
1110
1383
 
1111
- globalWatcherStartPromise = openCodeWatcherRuntime.start().catch((error) => {
1384
+ // Await Host metadata ready before the internal hub attaches upstream SSE so
1385
+ // session lifecycle frames are projected (not dropped) from the first event.
1386
+ globalWatcherStartPromise = (async () => {
1387
+ const ready = await ensureSessionMetadataReady();
1388
+ if (!ready) {
1389
+ const reason = sessionMetadataStore.getLoadFailureReason?.() || 'not ready';
1390
+ const error = new Error(`session metadata unavailable before global watcher start: ${reason}`);
1391
+ error.code = 'session_metadata_unavailable';
1392
+ error.retryable = true;
1393
+ throw error;
1394
+ }
1395
+ return openCodeWatcherRuntime.start();
1396
+ })().catch((error) => {
1112
1397
  globalWatcherStartPromise = null;
1113
1398
  throw error;
1114
1399
  });
@@ -1118,15 +1403,30 @@ const ensureGlobalWatcherStarted = async () => {
1118
1403
 
1119
1404
  const completeOpenCodeStartup = () => {
1120
1405
  scheduleOpenCodeApiDetection();
1121
- if (openCodeLifecycleState.openCodeProcess && !openCodeLifecycleState.isExternalOpenCode) {
1406
+ if (
1407
+ (openCodeLifecycleState.openCodeProcess && !openCodeLifecycleState.isExternalOpenCode)
1408
+ || openCodeLifecycleRuntime.isSharedOpenCodeService()
1409
+ ) {
1122
1410
  startHealthMonitoring();
1123
1411
  }
1124
1412
  // The global watcher used to start only for desktop notifications; session-title
1125
1413
  // and session-goal also ride its event hub, so it now starts unconditionally
1126
- // once OpenCode is up.
1127
- void ensureGlobalWatcherStarted().catch((error) => {
1128
- console.warn(`Global event watcher startup failed: ${error?.message || error}`);
1129
- });
1414
+ // once OpenCode is up. Controlled retry when metadata is not yet ready.
1415
+ const startWatcherWithRetry = (attempt = 0) => {
1416
+ void ensureGlobalWatcherStarted().catch((error) => {
1417
+ const retryable = error?.retryable === true || error?.code === 'session_metadata_unavailable';
1418
+ const delays = [500, 1_500, 3_000, 6_000, 12_000];
1419
+ if (retryable && attempt < delays.length) {
1420
+ console.warn(
1421
+ `Global event watcher deferred (metadata): ${error?.message || error}; retry ${attempt + 1}/${delays.length}`,
1422
+ );
1423
+ setTimeout(() => startWatcherWithRetry(attempt + 1), delays[attempt]);
1424
+ return;
1425
+ }
1426
+ console.warn(`Global event watcher startup failed: ${error?.message || error}`);
1427
+ });
1428
+ };
1429
+ startWatcherWithRetry();
1130
1430
  };
1131
1431
 
1132
1432
  const bootstrapOpenCodeAtStartup = async (...args) => {
@@ -1138,7 +1438,6 @@ const retryOpenCodeStartup = async (...args) => {
1138
1438
  await openCodeLifecycleRuntime.retryOpenCodeStartup(...args);
1139
1439
  completeOpenCodeStartup();
1140
1440
  };
1141
- const killProcessOnPort = (...args) => openCodeLifecycleRuntime.killProcessOnPort(...args);
1142
1441
  const waitForPortRelease = (...args) => openCodeLifecycleRuntime.waitForPortRelease(...args);
1143
1442
 
1144
1443
  const fetchAgentsSnapshot = (...args) => serverUtilsRuntime.fetchAgentsSnapshot(...args);
@@ -1175,7 +1474,6 @@ const gracefulShutdownRuntime = createGracefulShutdownRuntime({
1175
1474
  setOpenCodeProcess: (value) => {
1176
1475
  openCodeProcess = value;
1177
1476
  },
1178
- killProcessOnPort,
1179
1477
  waitForPortRelease,
1180
1478
  getServer: () => server,
1181
1479
  getUiAuthController: () => uiAuthController,
@@ -1350,6 +1648,15 @@ async function main(options = {}) {
1350
1648
  buildOpenCodeUrl,
1351
1649
  getOpenCodeAuthHeaders,
1352
1650
  waitForOpenCodeReady,
1651
+ projectSessions: (sessions) => {
1652
+ const snap = sessionMetadataStore.getSnapshotSync();
1653
+ // Not ready / unavailable — throw so sync keeps prior directory rows.
1654
+ // A missing side-store row must not drop a session OpenCode still has.
1655
+ if (!snap) {
1656
+ throw new Error('session metadata is unavailable: Host store not ready');
1657
+ }
1658
+ return retainOpenCodeSessions(sessions, snap);
1659
+ },
1353
1660
  onRevisionTip: (tip) => {
1354
1661
  broadcastOpenChamberEvent({
1355
1662
  type: 'openchamber:session-index-changed',
@@ -1357,8 +1664,43 @@ async function main(options = {}) {
1357
1664
  });
1358
1665
  },
1359
1666
  });
1667
+ sessionIndexSyncRuntimeRef = sessionIndexSyncRuntime;
1668
+
1669
+ sessionArchiveServiceRef = createSessionArchiveService({
1670
+ sessionMetadataStore,
1671
+ fetchUpstreamSession: createUpstreamSessionFetcher({
1672
+ buildOpenCodeUrl,
1673
+ getOpenCodeAuthHeaders,
1674
+ }),
1675
+ sessionIndexService,
1676
+ broadcastSessionEvent: (payload, options = {}) => {
1677
+ try {
1678
+ broadcastGlobalUiEvent(payload, options);
1679
+ } catch (error) {
1680
+ console.warn('[session-archive] global UI broadcast failed:', error?.message ?? error);
1681
+ }
1682
+ try {
1683
+ broadcastOpenChamberEvent(payload);
1684
+ } catch (error) {
1685
+ console.warn('[session-archive] openchamber event broadcast failed:', error?.message ?? error);
1686
+ }
1687
+ },
1688
+ onIndexChanged: () => {
1689
+ sessionIndexSyncRuntimeRef?.publishChange();
1690
+ },
1691
+ });
1692
+
1360
1693
  const unsubscribeSessionIndexEvents = globalMessageStreamHub.subscribeEvent((event) => {
1361
- if (applySessionIndexEvent(sessionIndexService, event)) {
1694
+ if (applySessionIndexEvent(sessionIndexService, event, Date.now(), {
1695
+ isHostReady: () => sessionMetadataStore.isLoaded(),
1696
+ projectSession: (session) => {
1697
+ if (!sessionMetadataStore.isLoaded()) return null;
1698
+ const snap = sessionMetadataStore.getSnapshotSync();
1699
+ if (!snap) return null;
1700
+ return projectSessionWithStoredMap(session, snap);
1701
+ },
1702
+ onSessionDeleted: (sessionID) => sessionArchiveServiceRef?.forgetSession(sessionID),
1703
+ })) {
1362
1704
  sessionIndexSyncRuntime?.publishChange();
1363
1705
  }
1364
1706
  });
@@ -1424,6 +1766,9 @@ async function main(options = {}) {
1424
1766
  }));
1425
1767
  expressApp = app;
1426
1768
  server = http.createServer(app);
1769
+ // Track server-owned sockets so forceCloseConnections can destroy upgraded
1770
+ // WS/SSE leftovers that closeAllConnections does not release.
1771
+ attachHttpServerConnectionTracker(server);
1427
1772
  let realtimeProxyRuntime = { stop: () => {} };
1428
1773
 
1429
1774
  // The relay service is constructed further below (it depends on the active
@@ -1444,11 +1789,16 @@ async function main(options = {}) {
1444
1789
  return {
1445
1790
  openCodePort,
1446
1791
  openCodeRunning: Boolean(openCodePort && isOpenCodeReady && !isRestartingOpenCode),
1792
+ openCodeStarting: Boolean(!isOpenCodeReady && !lastOpenCodeError),
1447
1793
  openCodeSecureConnection: isOpenCodeConnectionSecure(),
1448
1794
  openCodeAuthSource: openCodeAuthSource || null,
1449
1795
  openCodeApiPrefix: '',
1450
1796
  openCodeApiPrefixDetected: true,
1451
1797
  isOpenCodeReady,
1798
+ v1Migration,
1799
+ openCodeServeVersion,
1800
+ openCodeCliVersion,
1801
+ runtimeContract,
1452
1802
  lastOpenCodeError,
1453
1803
  lastOpenCodeLaunchDiagnostics,
1454
1804
  opencodeBinaryResolved: resolvedOpencodeBinary || null,
@@ -1559,6 +1909,8 @@ async function main(options = {}) {
1559
1909
  setAutoAcceptSession,
1560
1910
  sessionIndexService,
1561
1911
  sessionIndexSyncRuntime,
1912
+ // Production snapshot/lookup filter: committed Host archive authority.
1913
+ getCommittedHostMetadata: async () => sessionMetadataStore.getAll(),
1562
1914
  transcriptCacheService,
1563
1915
  });
1564
1916
  uiAuthController = bootstrapResult.uiAuthController;
@@ -1653,6 +2005,57 @@ async function main(options = {}) {
1653
2005
  isUnsafeSkillRelativePath,
1654
2006
  buildOpenCodeUrl,
1655
2007
  getOpenCodeAuthHeaders,
2008
+ getIsExternalOpenCode: () => isExternalOpenCode,
2009
+ getIsSharedOpenCodeService: () => openCodeLifecycleRuntime.isSharedOpenCodeService(),
2010
+ forceResolvedOpenCodeBinary,
2011
+ restartOpenCode,
2012
+ waitForOpenCodeReady,
2013
+ getRuntimeContract: () => runtimeContract,
2014
+ getOpenCodeServeVersion: () => openCodeServeVersion,
2015
+ getOpenCodeCliVersion: () => openCodeCliVersion,
2016
+ getResolvedOpenCodeBinary: () => resolvedOpencodeBinary,
2017
+ getResolvedOpenCodeBinarySource: () => resolvedOpencodeBinarySource,
2018
+ getActiveSessionCount,
2019
+ sessionMetadataStore,
2020
+ sessionArchiveService: {
2021
+ setArchive: (...args) => {
2022
+ if (!sessionArchiveServiceRef) {
2023
+ const error = new Error('session archive is not configured');
2024
+ error.status = 503;
2025
+ throw error;
2026
+ }
2027
+ return sessionArchiveServiceRef.setArchive(...args);
2028
+ },
2029
+ archiveSession: (...args) => {
2030
+ if (!sessionArchiveServiceRef) {
2031
+ const error = new Error('session archive is not configured');
2032
+ error.status = 503;
2033
+ throw error;
2034
+ }
2035
+ return sessionArchiveServiceRef.archiveSession(...args);
2036
+ },
2037
+ },
2038
+ // Same store seam as sessionGoalRuntime / scheduledTasksRuntime.
2039
+ readSessionMetadata: (sessionId) => sessionMetadataStore.get(sessionId),
2040
+ persistSessionMetadata: persistSessionMetadataToStore,
2041
+ onSystemSessionPersisted: hideSystemSessionFromIndex,
2042
+ persistSessionGoal: persistSessionGoalToStore,
2043
+ onSessionMetadataWritten: ({ sessionID, directory, metadata }) => {
2044
+ sessionTitleRuntime.processPayload({
2045
+ type: 'openchamber:session-metadata',
2046
+ properties: { sessionID, directory, metadata },
2047
+ }, directory || '');
2048
+ sessionGoalRuntime.processPayload({
2049
+ type: 'session.updated',
2050
+ properties: {
2051
+ info: {
2052
+ id: sessionID,
2053
+ directory: directory || '',
2054
+ metadata,
2055
+ },
2056
+ },
2057
+ }, directory || '');
2058
+ },
1656
2059
  getSmallModelService,
1657
2060
  getOpenCodePort: () => openCodePort,
1658
2061
  buildAugmentedPath,
@@ -1704,6 +2107,8 @@ async function main(options = {}) {
1704
2107
  getOpenCodeAuthHeaders,
1705
2108
  globalEventHub: globalMessageStreamHub,
1706
2109
  processForwardedEventPayload,
2110
+ projectOutboundSessionPayload: projectHostSessionPayload,
2111
+ ensureSessionMetadataReady,
1707
2112
  messageStreamWsClients: uiNotificationWsClients,
1708
2113
  upstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
1709
2114
  terminalHeartbeatIntervalMs: TERMINAL_INPUT_WS_HEARTBEAT_INTERVAL_MS,
@@ -1773,12 +2178,9 @@ async function main(options = {}) {
1773
2178
  restartOpenCode: () => restartOpenCode(),
1774
2179
  getOpenCodeProcessInfo: () => {
1775
2180
  const managed = Boolean((openCodeProcess || openCodePort) && !ENV_SKIP_OPENCODE_START && !isExternalOpenCode);
1776
- // Only ever expose pid/port for a server WE manage. The Electron-side
1777
- // killer kills by port (lsof + kill -KILL), so returning a port we don't
1778
- // own — e.g. an external/desktop OpenCode on 4096 we attached to — would
1779
- // let a single miscomputed `managed` flag take down the user's separate
1780
- // server. Structurally withhold what isn't ours so the killer has no
1781
- // target, instead of relying on the flag check alone.
2181
+ // Only ever expose pid/port for a server WE manage. Desktop no longer runs a
2182
+ // post-stop detached killer of a pre-captured pid; still withhold non-owned
2183
+ // process identity so diagnostics cannot imply we may kill an external serve.
1782
2184
  return {
1783
2185
  managed,
1784
2186
  pid: managed && typeof openCodeProcess?.pid === 'number' ? openCodeProcess.pid : null,
@@ -1792,6 +2194,8 @@ async function main(options = {}) {
1792
2194
  unsubscribeScheduledTaskEvents();
1793
2195
  sessionIndexSyncRuntime?.stop();
1794
2196
  sessionIndexService?.close();
2197
+ sessionArchiveServiceRef?.stop?.();
2198
+ stopSessionRecordMigration();
1795
2199
  } catch {
1796
2200
  // The index is a local cache; a failed close must not block shutdown.
1797
2201
  }
@@ -1819,11 +2223,10 @@ async function main(options = {}) {
1819
2223
  // best-effort shutdown of the dictation worker
1820
2224
  }
1821
2225
  try {
1822
- if (smallModelServiceInstance?.stop) {
1823
- await smallModelServiceInstance.stop();
1824
- }
2226
+ const { stopLlmTempDirectory } = await import('./lib/llm/temp-directory.js');
2227
+ await stopLlmTempDirectory();
1825
2228
  } catch {
1826
- // best-effort cleanup of the small-model temp OpenCode directory
2229
+ // best-effort cleanup of the LLM generator temp OpenCode directory
1827
2230
  }
1828
2231
  return gracefulShutdown({
1829
2232
  exitProcess: shutdownOptions.exitProcess ?? false,