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

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 (311) 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-B_JQoreg.js} +1 -1
  7. package/dist/assets/AssistantView-ClQAfGOT.js +3 -0
  8. package/dist/assets/{DiagramView-D1LGK_s2.js → DiagramView-BNnda8qO.js} +1 -1
  9. package/dist/assets/{FadeInOnReveal-B0kJo9Ii.js → FadeInOnReveal-VYQTSAkr.js} +1 -1
  10. package/dist/assets/{Icon-BgdfPhNs.js → Icon-BiEQEcih.js} +1 -1
  11. package/dist/assets/MarkdownRenderer-CJHSsWin.js +2 -0
  12. package/dist/assets/{MarkdownRendererImpl-DfoCJ1Mq.js → MarkdownRendererImpl-DwrHFGUp.js} +3 -3
  13. package/dist/assets/{MarkstreamRendererImpl-D2dsW5Lg.js → MarkstreamRendererImpl-CSnbQMu3.js} +1 -1
  14. package/dist/assets/MobileDetailNavigation-BXr6AGLT.js +1 -0
  15. package/dist/assets/{MobileShareBridge-2Yjn6wXg.js → MobileShareBridge-D7OE9OP_.js} +2 -2
  16. package/dist/assets/MobileSurface-D2jUkX9l.js +2 -0
  17. package/dist/assets/{MultiRunWindow-tTbMFowS.js → MultiRunWindow-DF3iIFCd.js} +1 -1
  18. package/dist/assets/{OnboardingScreen-CD2KtlF3.js → OnboardingScreen-BjHmlwlw.js} +1 -1
  19. package/dist/assets/OverlayScrollbar-DLtWO_Gp.js +2 -0
  20. package/dist/assets/SettingsView-BRxELjow.js +25 -0
  21. package/dist/assets/{SettingsWindow-zIa76s4t.js → SettingsWindow-BI5swspb.js} +1 -1
  22. package/dist/assets/{TerminalView-CDdzF4yi.js → TerminalView-BU3x8-fr.js} +1 -1
  23. package/dist/assets/{ToolOutputDialog-DNqA4uBl.js → ToolOutputDialog-BEWhBcRd.js} +2 -2
  24. package/dist/assets/appThemeRegistry-4MR0F7Jz.js +1 -0
  25. package/dist/assets/{button-CI7Q-Zw_.js → button-DKuz3L8l.js} +1 -1
  26. package/dist/assets/collapsible-DXbDynN4.js +3 -0
  27. package/dist/assets/context-menu-CqolsLCm.js +1 -0
  28. package/dist/assets/{desktopHosts-B1ixEylr.js → desktopHosts-CoDkOnyS.js} +1 -1
  29. package/dist/assets/{desktopRelayRestore-4JmFUw8r.js → desktopRelayRestore-DDlVKyOE.js} +1 -1
  30. package/dist/assets/{diagram-DdLO8HZ9.js → diagram-D7T8HQgj.js} +1 -1
  31. package/dist/assets/{dialog-B6pnIYmp.js → dialog-DQYl3W_o.js} +1 -1
  32. package/dist/assets/es-CN3E_zXj.js +15 -0
  33. package/dist/assets/{fileMentionTouchSelection-DNeiqns-.js → fileMentionTouchSelection-BZ6ovBYH.js} +1 -1
  34. package/dist/assets/{fileQueries-DQc8EJUf.js → fileQueries-JrpcsOCs.js} +1 -1
  35. package/dist/assets/fr-9zZvQZD2.js +13 -0
  36. package/dist/assets/gitApi-CM42qUed.js +10 -0
  37. package/dist/assets/{imageSource-BlAJJUEI.js → imageSource-CIl0FL10.js} +1 -1
  38. package/dist/assets/{input-D-__fwRi.js → input-CzQy8UhV.js} +1 -1
  39. package/dist/assets/insertionBoundaries-CtkZ9720.js +1 -0
  40. package/dist/assets/ja-Dnjk_82N.js +15 -0
  41. package/dist/assets/ko-BxCEE99C.js +15 -0
  42. package/dist/assets/main-BILgBI3B.js +169 -0
  43. package/dist/assets/main-BeveiW6F.js +2 -0
  44. package/dist/assets/markdown-worker-bS5OgGO3.js +2 -0
  45. package/dist/assets/{markdownHeightCache-BhxqJOvf.js → markdownHeightCache-Cj1I5NDw.js} +1 -1
  46. package/dist/assets/{markdownTheme-DOfGg-A7.js → markdownTheme-CKac3wKC.js} +1 -1
  47. package/dist/assets/mcpQueries-D5mQymgM.js +1 -0
  48. package/dist/assets/miniChat-BgrzM3u7.js +2 -0
  49. package/dist/assets/mobile-DtYoQE8C.js +2 -0
  50. package/dist/assets/multirun-jy8dEI96.js +4 -0
  51. package/dist/assets/{persistence-Ce3AnpEr.js → persistence-C9LQpiOS.js} +2 -2
  52. package/dist/assets/pl-CNNsWnPM.js +15 -0
  53. package/dist/assets/platform-BQghHRfp.js +6 -0
  54. package/dist/assets/pt-BR-BZB2DJMp.js +15 -0
  55. package/dist/assets/renderElectronMiniChatApp-BGrrmeME.js +2 -0
  56. package/dist/assets/renderMobileApp-u3c4GtFC.js +28 -0
  57. package/dist/assets/{runtimeConfig-CMkwoQ_X.js → runtimeConfig-BIGBRGQI.js} +1 -1
  58. package/dist/assets/{runtimeEndpointReset-ChOxt-J7.js → runtimeEndpointReset-D2savkuw.js} +12 -12
  59. package/dist/assets/{sessionChangeSummary-NnxcqCTI.js → sessionChangeSummary-eIbpSfrO.js} +1 -1
  60. package/dist/assets/{sessionLookup-BrU3rFHJ.js → sessionLookup-myHe5ltu.js} +1 -1
  61. package/dist/assets/{sortable-tabs-strip-Fnfhf3K9.js → sortable-tabs-strip-BQtmHx9r.js} +1 -1
  62. package/dist/assets/src-CLN7Z-zx.css +2 -0
  63. package/dist/assets/store-DLCiZaA6.js +15 -0
  64. package/dist/assets/{terminalApi-xjqssKke.js → terminalApi-BxcdiduX.js} +1 -1
  65. package/dist/assets/{textarea-bHYxZtfH.js → textarea-CakKvqFw.js} +1 -1
  66. package/dist/assets/{tooltip-0T5jv0cu.js → tooltip-Cx5gTbdY.js} +1 -1
  67. package/dist/assets/uk-rwQrxeYM.js +15 -0
  68. package/dist/assets/{url-_z7evzdK.js → url-CDHnjlsm.js} +1 -1
  69. package/dist/assets/{useAppFontEffects-C02YFyAv.js → useAppFontEffects-CNeo0aZs.js} +59 -45
  70. package/dist/assets/{useAssistantUIStore-CMutVh9B.js → useAssistantUIStore-asNG6K7n.js} +1 -1
  71. package/dist/assets/useDesktopWindowControlsLayout-DBJ56qIo.js +1 -0
  72. package/dist/assets/useEffectiveDirectory-B4LvR8Gt.js +1 -0
  73. package/dist/assets/{useFontPreferences-B1JYyzpK.js → useFontPreferences-CUnQ4TVm.js} +1 -1
  74. package/dist/assets/useMobileNavigationStore-ZHJPxlHt.js +414 -0
  75. package/dist/assets/{useRuntimeAPIs-DSLXJybW.js → useRuntimeAPIs-DwLtO0c_.js} +1 -1
  76. package/dist/assets/useSessionAutoCleanup-BIVmrnYU.js +2 -0
  77. package/dist/assets/{useThemeSystem-DMzWVJaW.js → useThemeSystem-BlNUWH47.js} +1 -1
  78. package/dist/assets/useUIStore-CQYKJnrg.js +1 -0
  79. package/dist/assets/{useWorkerHighlightedLines-C9z0ML1z.js → useWorkerHighlightedLines-CJZbJDW3.js} +2 -2
  80. package/dist/assets/{vendor-base-ui-CnHfUmDN.js → vendor-base-ui-CDjyofeD.js} +1 -1
  81. package/dist/assets/{vendor-cmdk-CeAGfrLo.js → vendor-cmdk-BFH0UpXX.js} +1 -1
  82. package/dist/assets/{vendor-dnd-kit-accessibility-BY5LhhUB.js → vendor-dnd-kit-accessibility-BrR3AKvM.js} +1 -1
  83. package/dist/assets/{vendor-dnd-kit-core-CvWxUPdb.js → vendor-dnd-kit-core-CNfdvk6H.js} +1 -1
  84. package/dist/assets/{vendor-dnd-kit-sortable-hHdP9lLb.js → vendor-dnd-kit-sortable-DQUaTeGj.js} +1 -1
  85. package/dist/assets/{vendor-framer-motion-DFy_BSVd.js → vendor-framer-motion-4dogsUk3.js} +1 -1
  86. package/dist/assets/{vendor-legendapp-list-WE32lwNk.js → vendor-legendapp-list-BU7MdPZR.js} +1 -1
  87. package/dist/assets/{vendor-markstream-react-DX55XLGO.js → vendor-markstream-react-qHC2FykU.js} +3 -3
  88. package/dist/assets/vendor-opencode-client-BOe2qpQb.js +12 -0
  89. package/dist/assets/{vendor-pierre-diffs-DX7XTPG3.js → vendor-pierre-diffs-CUfqC003.js} +1 -1
  90. package/dist/assets/{vendor-react-DLPElpoQ.js → vendor-react-C94A0AHl.js} +1 -1
  91. package/dist/assets/{vendor-react-drawio-ECtEwvbc.js → vendor-react-drawio-FVlWqKVE.js} +1 -1
  92. package/dist/assets/{vendor-reactuses-core-BnW6GxJt.js → vendor-reactuses-core-C2A3EjUi.js} +1 -1
  93. package/dist/assets/{vendor-sonner-DVzioF3d.js → vendor-sonner-DNqHmUQs.js} +1 -1
  94. package/dist/assets/{vendor-stream-diffs-DWy3xSmp.js → vendor-stream-diffs-CwbKsmlv.js} +2 -2
  95. package/dist/assets/{vendor-tanstack-react-query-D7pys_c9.js → vendor-tanstack-react-query-D0iFK57C.js} +1 -1
  96. package/dist/assets/{vendor-tanstack-react-virtual-tlDgH6PG.js → vendor-tanstack-react-virtual-B2kV6cnT.js} +1 -1
  97. package/dist/assets/{vendor-yaml-DIcAK3EC.js → vendor-yaml-C9KlJAlj.js} +37 -37
  98. package/dist/assets/{vendor-zustand-B4dlGEM2.js → vendor-zustand-BqLKf6ZY.js} +1 -1
  99. package/dist/assets/zh-CN-BvmBDnkD.js +15 -0
  100. package/dist/assets/zh-TW-9wcHTX0y.js +15 -0
  101. package/dist/index.html +13 -13
  102. package/dist/mini-chat.html +13 -13
  103. package/dist/mobile.html +13 -13
  104. package/package.json +2 -2
  105. package/server/index.js +392 -20
  106. package/server/lib/assistants/DOCUMENTATION.md +26 -21
  107. package/server/lib/assistants/assign.js +2 -1
  108. package/server/lib/assistants/contact-store.js +37 -19
  109. package/server/lib/assistants/contracts.js +11 -1
  110. package/server/lib/assistants/projection-history.test.js +454 -0
  111. package/server/lib/assistants/routes.js +11 -5
  112. package/server/lib/assistants/service.js +850 -294
  113. package/server/lib/assistants/service.test.js +588 -274
  114. package/server/lib/conversations/DOCUMENTATION.md +5 -5
  115. package/server/lib/conversations/service.js +87 -57
  116. package/server/lib/conversations/service.test.js +132 -100
  117. package/server/lib/conversations/validation.js +11 -1
  118. package/server/lib/event-stream/directory-ws-bridge.js +13 -2
  119. package/server/lib/event-stream/global-hub.js +51 -5
  120. package/server/lib/event-stream/runtime.js +57 -20
  121. package/server/lib/event-stream/runtime.test.js +112 -0
  122. package/server/lib/llm/DOCUMENTATION.md +95 -84
  123. package/server/lib/llm/catalog.js +111 -45
  124. package/server/lib/llm/catalog.test.js +121 -59
  125. package/server/lib/llm/completions.js +41 -12
  126. package/server/lib/llm/completions.test.js +45 -4
  127. package/server/lib/llm/generate.js +516 -453
  128. package/server/lib/llm/generate.test.js +705 -484
  129. package/server/lib/llm/routes.js +8 -4
  130. package/server/lib/message-queue/DOCUMENTATION.md +5 -5
  131. package/server/lib/message-queue/opencode-adapter.js +191 -104
  132. package/server/lib/message-queue/opencode-adapter.test.js +328 -58
  133. package/server/lib/message-queue/runtime.js +15 -2
  134. package/server/lib/message-queue/runtime.test.js +6 -6
  135. package/server/lib/message-queue/worker.js +7 -1
  136. package/server/lib/notifications/runtime.js +5 -0
  137. package/server/lib/opencode/DOCUMENTATION.md +103 -16
  138. package/server/lib/opencode/agent-document.d.ts +28 -0
  139. package/server/lib/opencode/agent-document.js +280 -0
  140. package/server/lib/opencode/agent-document.test.js +137 -0
  141. package/server/lib/opencode/agents.js +96 -0
  142. package/server/lib/opencode/auth-state-runtime.js +5 -0
  143. package/server/lib/opencode/bootstrap-runtime.js +2 -0
  144. package/server/lib/opencode/config-entity-routes.js +111 -102
  145. package/server/lib/opencode/config-entity-routes.test.js +123 -10
  146. package/server/lib/opencode/config-hot-reload.integration.test.js +105 -0
  147. package/server/lib/opencode/ensure-cli.js +238 -0
  148. package/server/lib/opencode/ensure-cli.test.js +119 -0
  149. package/server/lib/opencode/env-runtime.js +208 -111
  150. package/server/lib/opencode/env-runtime.test.js +211 -14
  151. package/server/lib/opencode/feature-routes-runtime.js +80 -5
  152. package/server/lib/opencode/feature-routes-runtime.test.js +18 -0
  153. package/server/lib/opencode/http-server-connections.js +98 -0
  154. package/server/lib/opencode/http-server-connections.test.js +321 -0
  155. package/server/lib/opencode/lifecycle.js +539 -95
  156. package/server/lib/opencode/lifecycle.test.js +698 -6
  157. package/server/lib/opencode/managed-capabilities-runtime.js +15 -2
  158. package/server/lib/opencode/managed-capabilities-runtime.test.js +1 -0
  159. package/server/lib/opencode/network-runtime.js +28 -16
  160. package/server/lib/opencode/network-runtime.test.js +68 -4
  161. package/server/lib/opencode/openchamber-routes.js +7 -1
  162. package/server/lib/opencode/opencode2-pin.js +139 -0
  163. package/server/lib/opencode/opencode2-pin.test.js +88 -0
  164. package/server/lib/opencode/opencode2-sidecar.e2e.test.js +326 -0
  165. package/server/lib/opencode/owned-runtime-upgrade.js +431 -0
  166. package/server/lib/opencode/owned-runtime-upgrade.test.js +160 -0
  167. package/server/lib/opencode/plugin-compatibility.js +15 -0
  168. package/server/lib/opencode/plugin-compatibility.test.js +21 -0
  169. package/server/lib/opencode/plugin-routes.js +3 -18
  170. package/server/lib/opencode/plugin-routes.test.js +9 -9
  171. package/server/lib/opencode/plugins.js +4 -3
  172. package/server/lib/opencode/plugins.test.js +12 -0
  173. package/server/lib/opencode/provider-catalog.js +58 -12
  174. package/server/lib/opencode/provider-catalog.test.js +48 -0
  175. package/server/lib/opencode/proxy.js +368 -28
  176. package/server/lib/opencode/proxy.test.js +338 -0
  177. package/server/lib/opencode/routes.js +303 -76
  178. package/server/lib/opencode/routes.test.js +315 -50
  179. package/server/lib/opencode/runtime-contract.js +401 -0
  180. package/server/lib/opencode/runtime-contract.test.js +214 -0
  181. package/server/lib/opencode/server-opencode-fetch.js +242 -0
  182. package/server/lib/opencode/server-opencode-fetch.test.js +130 -0
  183. package/server/lib/opencode/server-utils-runtime.js +35 -0
  184. package/server/lib/opencode/shared-service.integration.test.js +66 -0
  185. package/server/lib/opencode/shared-service.js +147 -0
  186. package/server/lib/opencode/shared-service.test.js +93 -0
  187. package/server/lib/opencode/shared.js +3 -3
  188. package/server/lib/opencode/shutdown-runtime.js +15 -6
  189. package/server/lib/opencode/shutdown-runtime.test.js +49 -1
  190. package/server/lib/opencode/skill-routes.js +26 -40
  191. package/server/lib/opencode/skill-routes.test.js +71 -7
  192. package/server/lib/opencode/skills.test.js +15 -0
  193. package/server/lib/opencode/startup-pipeline-runtime.js +4 -0
  194. package/server/lib/opencode/static-routes-runtime.js +3 -1
  195. package/server/lib/opencode/static-routes-runtime.test.js +33 -0
  196. package/server/lib/opencode/v1-migration-gate.js +157 -0
  197. package/server/lib/opencode/v1-migration-gate.test.js +111 -0
  198. package/server/lib/opencode/v2-client.js +60 -0
  199. package/server/lib/opencode/v2-plugin-host-shim/index.mjs +155 -0
  200. package/server/lib/opencode/v2-plugin-host-shim/package.json +4 -0
  201. package/server/lib/opencode/watcher.js +2 -1
  202. package/server/lib/opencode/watcher.test.js +1 -1
  203. package/server/lib/permission-auto-accept/DOCUMENTATION.md +5 -5
  204. package/server/lib/permission-auto-accept/runtime.js +14 -7
  205. package/server/lib/permission-auto-accept/runtime.test.js +27 -12
  206. package/server/lib/relay/reasoning-projection.e2e.test.ts +22 -7
  207. package/server/lib/scheduled-tasks/DOCUMENTATION.md +79 -39
  208. package/server/lib/scheduled-tasks/managed-tool-route.js +31 -1
  209. package/server/lib/scheduled-tasks/managed-tool-route.test.js +23 -0
  210. package/server/lib/scheduled-tasks/routes.js +27 -0
  211. package/server/lib/scheduled-tasks/routes.test.js +94 -0
  212. package/server/lib/scheduled-tasks/runtime.js +381 -310
  213. package/server/lib/scheduled-tasks/runtime.test.js +600 -309
  214. package/server/lib/session-goal/DOCUMENTATION.md +173 -22
  215. package/server/lib/session-goal/capability.js +57 -0
  216. package/server/lib/session-goal/capability.test.js +33 -0
  217. package/server/lib/session-goal/routes.js +240 -2
  218. package/server/lib/session-goal/routes.test.js +211 -0
  219. package/server/lib/session-goal/runtime.js +1617 -113
  220. package/server/lib/session-goal/runtime.test.js +1500 -70
  221. package/server/lib/session-index/DOCUMENTATION.md +18 -15
  222. package/server/lib/session-index/event-ingest.js +89 -16
  223. package/server/lib/session-index/event-ingest.test.js +73 -0
  224. package/server/lib/session-index/host-authority-snapshot.js +92 -0
  225. package/server/lib/session-index/routes.host-archive.test.js +201 -0
  226. package/server/lib/session-index/routes.js +63 -10
  227. package/server/lib/session-index/routes.test.js +8 -8
  228. package/server/lib/session-index/service.js +7 -1
  229. package/server/lib/session-index/sync-runtime.js +171 -41
  230. package/server/lib/session-index/sync-runtime.test.js +164 -9
  231. package/server/lib/session-metadata/DOCUMENTATION.md +86 -0
  232. package/server/lib/session-metadata/routes.js +193 -0
  233. package/server/lib/session-metadata/routes.test.js +156 -0
  234. package/server/lib/session-metadata/session-archive.d.ts +73 -0
  235. package/server/lib/session-metadata/session-archive.js +654 -0
  236. package/server/lib/session-metadata/session-archive.test.js +359 -0
  237. package/server/lib/session-metadata/session-metadata-store.d.ts +36 -0
  238. package/server/lib/session-metadata/session-metadata-store.js +375 -0
  239. package/server/lib/session-metadata/session-metadata-store.test.js +379 -0
  240. package/server/lib/session-metadata/session-projection.d.ts +41 -0
  241. package/server/lib/session-metadata/session-projection.js +255 -0
  242. package/server/lib/session-metadata/session-projection.test.js +64 -0
  243. package/server/lib/session-metadata/system-session.js +55 -0
  244. package/server/lib/session-metadata/system-session.test.js +55 -0
  245. package/server/lib/session-title/DOCUMENTATION.md +40 -7
  246. package/server/lib/session-title/native-runtime.test.js +167 -0
  247. package/server/lib/session-title/runtime.js +67 -42
  248. package/server/lib/session-title/session-access.js +46 -0
  249. package/server/lib/session-title/session-access.test.js +91 -0
  250. package/server/lib/session-turn-pages/DOCUMENTATION.md +12 -11
  251. package/server/lib/session-turn-pages/reconcile.service.js +1 -1
  252. package/server/lib/session-turn-pages/reconcile.service.test.js +16 -0
  253. package/server/lib/session-turn-pages/routes.js +123 -75
  254. package/server/lib/session-turn-pages/routes.test.js +566 -0
  255. package/server/lib/session-turn-pages/service.js +6 -2
  256. package/server/lib/session-turn-pages/service.test.js +34 -0
  257. package/server/lib/session-turn-pages/session-message-projection.d.ts +13 -0
  258. package/server/lib/session-turn-pages/session-message-projection.js +281 -0
  259. package/server/lib/small-model/DOCUMENTATION.md +101 -146
  260. package/server/lib/small-model/catalog.js +84 -54
  261. package/server/lib/small-model/catalog.test.js +111 -9
  262. package/server/lib/small-model/custom-api.js +68 -0
  263. package/server/lib/small-model/custom-api.test.js +64 -0
  264. package/server/lib/small-model/index.js +125 -241
  265. package/server/lib/small-model/resolve.js +35 -120
  266. package/server/lib/small-model/resolve.test.js +20 -110
  267. package/server/lib/small-model/routes.js +1 -3
  268. package/server/lib/small-model/summary-settings.test.js +157 -253
  269. package/server/opencode-proxy.test.js +63 -12
  270. package/dist/assets/AssistantView-BUveAgc4.js +0 -3
  271. package/dist/assets/MarkdownRenderer-BbrbDH6-.js +0 -2
  272. package/dist/assets/MobileDetailNavigation-B0aqKXd7.js +0 -1
  273. package/dist/assets/MobileSurface-DW7WfPsy.js +0 -2
  274. package/dist/assets/OverlayScrollbar-DrA0Vsg5.js +0 -2
  275. package/dist/assets/SettingsView-PkXIavr7.js +0 -25
  276. package/dist/assets/appThemeRegistry-D5Yxg4YF.js +0 -1
  277. package/dist/assets/collapsible-D5Phaykh.js +0 -1
  278. package/dist/assets/context-menu-CubSDW2g.js +0 -1
  279. package/dist/assets/es-DA3MqOo0.js +0 -15
  280. package/dist/assets/fr-Dbz0CdIA.js +0 -13
  281. package/dist/assets/gitApi-DXyC4MiV.js +0 -7
  282. package/dist/assets/insertionBoundaries-KlOVrHHt.js +0 -1
  283. package/dist/assets/ja-DumanVQA.js +0 -15
  284. package/dist/assets/ko-C0IkiUjQ.js +0 -15
  285. package/dist/assets/main-BPS5ylib.js +0 -2
  286. package/dist/assets/main-Cpd9VWYs.js +0 -169
  287. package/dist/assets/markdown-worker-CptoICmq.js +0 -2
  288. package/dist/assets/miniChat-B8_KLWiY.js +0 -2
  289. package/dist/assets/mobile-CtktKrXn.js +0 -2
  290. package/dist/assets/multirun-CYfP9Cfm.js +0 -4
  291. package/dist/assets/pl-B9No6MQp.js +0 -15
  292. package/dist/assets/platform-0w_Q9_ji.js +0 -2
  293. package/dist/assets/projectMeta-S1hJ7oBp.js +0 -3
  294. package/dist/assets/pt-BR-DyQ0WTDh.js +0 -15
  295. package/dist/assets/renderElectronMiniChatApp-iK14LWm8.js +0 -2
  296. package/dist/assets/renderMobileApp-DORLPWnb.js +0 -28
  297. package/dist/assets/src-rS3zCcsC.css +0 -2
  298. package/dist/assets/store-5B_LDnLM.js +0 -15
  299. package/dist/assets/uk-C_1KkqyP.js +0 -15
  300. package/dist/assets/useDesktopWindowControlsLayout-Dnr-jX0C.js +0 -1
  301. package/dist/assets/useEffectiveDirectory-CZLLyarc.js +0 -1
  302. package/dist/assets/useMobileNavigationStore-CoCiqNgm.js +0 -413
  303. package/dist/assets/useSessionAutoCleanup-xQyETQkG.js +0 -2
  304. package/dist/assets/useUIStore-Bxv3f23A.js +0 -1
  305. package/dist/assets/vendor-opencode-sdk-C07HQypa.js +0 -7
  306. package/dist/assets/zh-CN-uWILgBdt.js +0 -15
  307. package/dist/assets/zh-TW-MYfdvhbD.js +0 -15
  308. package/server/lib/small-model/call.js +0 -427
  309. package/server/lib/small-model/call.test.js +0 -382
  310. package/server/lib/small-model/opencode-session.js +0 -339
  311. package/server/lib/small-model/opencode-session.test.js +0 -177
@@ -0,0 +1,64 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import {
4
+ extractSessionInfoFromPayload,
5
+ normalizeSessionEventType,
6
+ projectSessionLifecyclePayload,
7
+ resolveSessionDirectory,
8
+ } from './session-projection.js';
9
+
10
+ describe('session projection event shapes', () => {
11
+ it('normalizes version suffixes', () => {
12
+ expect(normalizeSessionEventType('session.updated.v2')).toBe('session.updated');
13
+ expect(normalizeSessionEventType('session.created')).toBe('session.created');
14
+ });
15
+
16
+ it('extracts info from properties.info and data.info', () => {
17
+ expect(extractSessionInfoFromPayload({
18
+ type: 'session.updated',
19
+ properties: { info: { id: 'ses_a' } },
20
+ })?.id).toBe('ses_a');
21
+ expect(extractSessionInfoFromPayload({
22
+ type: 'session.updated.v2',
23
+ data: { info: { id: 'ses_b' } },
24
+ })?.id).toBe('ses_b');
25
+ });
26
+
27
+ it('prefers location.directory', () => {
28
+ expect(resolveSessionDirectory({
29
+ location: { directory: '/loc' },
30
+ directory: '/legacy',
31
+ })).toBe('/loc');
32
+ });
33
+
34
+ it('projects GlobalEvent wrap and preserves envelope directory', () => {
35
+ const projected = projectSessionLifecyclePayload({
36
+ directory: '/repo',
37
+ payload: {
38
+ type: 'session.updated.v2',
39
+ data: {
40
+ info: {
41
+ id: 'ses_1',
42
+ time: { created: 1, updated: 2, archived: 50 },
43
+ },
44
+ },
45
+ },
46
+ }, () => ({ openchamber: { archive: { archivedAt: 99 } } }));
47
+
48
+ expect(projected.directory).toBe('/repo');
49
+ expect(projected.payload.type).toBe('session.updated.v2');
50
+ expect(projected.payload.data.info.time.archived).toBe(99);
51
+ });
52
+
53
+ it('returns null for lifecycle when hostReady is false', () => {
54
+ expect(projectSessionLifecyclePayload({
55
+ type: 'session.updated',
56
+ properties: { info: { id: 'ses_1', time: {} } },
57
+ }, () => null, { hostReady: false })).toBeNull();
58
+ });
59
+
60
+ it('leaves message events alone when hostReady is false', () => {
61
+ const msg = { type: 'message.updated', properties: { info: { role: 'user' } } };
62
+ expect(projectSessionLifecyclePayload(msg, () => null, { hostReady: false })).toBe(msg);
63
+ });
64
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Host-owned isolation markers for system sessions.
3
+ *
4
+ * Sidebar / session-index / notifications hide a session only when these
5
+ * fields are present. Title prefixes are labels and never ownership.
6
+ *
7
+ * Every system session creator (scheduled tasks, LLM attachment gateway,
8
+ * Assistant bindings) must persist the matching patch through the Host
9
+ * session-metadata store. OpenCode create-time `metadata` is a hint only.
10
+ */
11
+
12
+ export const LLM_SESSION_PURPOSE = 'chat-completions';
13
+
14
+ const nonEmpty = (value) => (typeof value === 'string' && value.trim() ? value.trim() : null);
15
+
16
+ export const buildScheduledTaskMetadata = ({ projectID, taskID, runID, name } = {}) => {
17
+ const id = nonEmpty(taskID);
18
+ if (!id) {
19
+ throw new Error('scheduled-task metadata requires taskID');
20
+ }
21
+ return {
22
+ openchamber: {
23
+ scheduledTask: {
24
+ taskID: id,
25
+ ...(nonEmpty(projectID) ? { projectID: nonEmpty(projectID) } : {}),
26
+ ...(nonEmpty(runID) ? { runID: nonEmpty(runID) } : {}),
27
+ ...(nonEmpty(name) ? { name: nonEmpty(name) } : {}),
28
+ },
29
+ },
30
+ };
31
+ };
32
+
33
+ export const buildLlmSessionMetadata = (purpose = LLM_SESSION_PURPOSE) => {
34
+ const resolved = nonEmpty(purpose) || LLM_SESSION_PURPOSE;
35
+ return {
36
+ openchamber: {
37
+ llm: { purpose: resolved },
38
+ },
39
+ };
40
+ };
41
+
42
+ export const buildAssistantSessionMetadata = ({ assistantID, name } = {}) => {
43
+ const id = nonEmpty(assistantID);
44
+ if (!id) {
45
+ throw new Error('assistant session metadata requires assistantID');
46
+ }
47
+ return {
48
+ openchamber: {
49
+ assistant: {
50
+ assistantID: id,
51
+ ...(nonEmpty(name) ? { name: nonEmpty(name) } : {}),
52
+ },
53
+ },
54
+ };
55
+ };
@@ -0,0 +1,55 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ LLM_SESSION_PURPOSE,
4
+ buildAssistantSessionMetadata,
5
+ buildLlmSessionMetadata,
6
+ buildScheduledTaskMetadata,
7
+ } from './system-session.js';
8
+
9
+ describe('system session metadata builders', () => {
10
+ it('builds scheduled-task isolation from a non-empty taskID', () => {
11
+ expect(buildScheduledTaskMetadata({
12
+ projectID: 'project-1',
13
+ taskID: 'task-1',
14
+ runID: 'run-1',
15
+ name: 'Morning Sync',
16
+ })).toEqual({
17
+ openchamber: {
18
+ scheduledTask: {
19
+ taskID: 'task-1',
20
+ projectID: 'project-1',
21
+ runID: 'run-1',
22
+ name: 'Morning Sync',
23
+ },
24
+ },
25
+ });
26
+ });
27
+
28
+ it('refuses scheduled-task metadata without taskID', () => {
29
+ expect(() => buildScheduledTaskMetadata({ projectID: 'project-1' })).toThrow(/taskID/);
30
+ });
31
+
32
+ it('builds llm isolation with the chat-completions purpose', () => {
33
+ expect(buildLlmSessionMetadata()).toEqual({
34
+ openchamber: { llm: { purpose: LLM_SESSION_PURPOSE } },
35
+ });
36
+ expect(buildLlmSessionMetadata(' ')).toEqual({
37
+ openchamber: { llm: { purpose: LLM_SESSION_PURPOSE } },
38
+ });
39
+ });
40
+
41
+ it('builds assistant isolation from a non-empty assistantID', () => {
42
+ expect(buildAssistantSessionMetadata({
43
+ assistantID: 'assistant_1',
44
+ name: 'Ops',
45
+ })).toEqual({
46
+ openchamber: {
47
+ assistant: { assistantID: 'assistant_1', name: 'Ops' },
48
+ },
49
+ });
50
+ });
51
+
52
+ it('refuses assistant metadata without assistantID', () => {
53
+ expect(() => buildAssistantSessionMetadata({ name: 'Ops' })).toThrow(/assistantID/);
54
+ });
55
+ });
@@ -5,20 +5,53 @@ conversation's **main subject** (overall feature / goal) with the small model
5
5
  (`lib/small-model`), then PATCHes `title` plus `metadata.openchamber.titleRefresh`.
6
6
 
7
7
  OpenCode only auto-titles once from the first user message
8
- (`SessionPrompt.ensureTitle`). This module auto-refreshes sparsely (first idle
9
- of a new session, first newly-sent reply on a fork) and on explicit smart-title
8
+ (`SessionPrompt.ensureTitle`). This module auto-refreshes sparsely (first user
9
+ admission of a new session, first newly-sent reply on a fork) and on explicit smart-title
10
10
  requests, naming the durable work being done — not the last wrap-up utterance
11
11
  like "commit and push". Background auto refreshes still respect a 5-minute
12
12
  throttle (`TITLE_THROTTLE_MS`) when a refresh is armed.
13
13
 
14
14
  ## Flow
15
15
 
16
+ ### OpenCode 2 smart-title boundary
17
+
18
+ Manual requests arrive as Host `openchamber:session-metadata` writes. The
19
+ metadata route's committed-write callback explicitly notifies the title runtime;
20
+ it must not rely on OpenCode echoing Host metadata as `session.updated`.
21
+ `session-access.js` owns the production boundary: official client session reads
22
+ and title updates, a bounded `message.list({ order: 'desc' })` page projected into
23
+ chronological transcript records, and Host metadata reads/merge patches.
24
+ Only changed `titleRefresh` fields are persisted. Transient fields are removed
25
+ with RFC 7386 `null`, so `isGenerating` and `requestedAt` cannot survive a clear.
26
+ Unrelated goal, archive, and ownership metadata is never replaced by a title read.
27
+
28
+ After a successful title write or generation-state change, an authoritative full session row is published
29
+ as `session.updated` and applied to the session index. Connected clients receive
30
+ both loading metadata and the new title without reselecting the session. Neither
31
+ event represents an execution-status transition: the original session's busy /
32
+ retry status and subsequent execution events remain independently authoritative.
33
+ Publishing the loading row also covers first-send admission arriving before the
34
+ renderer inserts the new session: a metadata-only event would otherwise be ignored
35
+ for that still-unknown row.
36
+ This Host path serves web, Electron, and connected hosted/native mobile clients;
37
+ extension-only VS Code retains the limitation below.
38
+
16
39
  1. `createSessionTitleRuntime` is a consumer of the server's global SSE
17
40
  fan-out (`index.js` → `globalMessageStreamHub.subscribeEvent`). Purely event-driven — dormant sessions never
18
41
  generate anything.
19
- 2. Auto title refresh is intentionally sparse (title stability first). A newly
20
- observed root `session.created` generates its first title immediately on the
21
- first `session.status: idle`. A fork title (`(fork #n)`) waits for its first
42
+ 2. Auto title refresh is intentionally sparse (title stability first). A newly
43
+ observed root `session.created` generates its first title immediately on
44
+ the first native `session.inbox.enqueued` user item. Native `data` envelopes
45
+ are accepted alongside legacy `properties`. The admitted text is bounded
46
+ to the user-message limit and retained only until the generation starts;
47
+ it avoids a race with the not-yet-materialized message projection. Synthetic,
48
+ compaction, and move items cannot start this title. Busy/execution-start
49
+ events do not cancel this first-title timer: title generation and the main
50
+ assistant reply run concurrently. Generation publishes `isGenerating` via
51
+ the existing Host metadata path, then the final title through `session.updated`.
52
+ Later user admissions/idle events do not regenerate the initial title.
53
+ The legacy first-idle edge remains a fallback when no admission was observed.
54
+ A fork title (`(fork #n)`) waits for its first
22
55
  newly-created user message; the matching assistant completion triggers an
23
56
  immediate title refresh that bypasses inherited title metadata and throttle.
24
57
  If the fork's `session.created` was lost (SSE reconnect gap, server or
@@ -27,8 +60,8 @@ throttle (`TITLE_THROTTLE_MS`) when a refresh is armed.
27
60
  title + message created after the fork + activity timestamp not yet past
28
61
  the fork time), so the first-reply refresh still fires.
29
62
  Ordinary later idle transitions do **not** arm another refresh. Any
30
- `busy`/`retry` status or a fresh user `message.updated` still clears an
31
- already-armed timer (so initial/fork timers cancel if the user keeps going).
63
+ `busy`/`retry` status or a fresh user `message.updated` still clears an
64
+ ordinary already-armed timer; an admitted first-title timer is exempt.
32
65
  A sidebar smart-title request sets `titleRefresh.requestedAt`; its
33
66
  `session.updated` event arms the same flow immediately (forced / manual
34
67
  refresh is unaffected by the background gate).
@@ -0,0 +1,167 @@
1
+ import { afterEach, expect, it, vi } from 'vitest';
2
+ import { createSessionTitleRuntime } from './runtime.js';
3
+ import { mergeMetadataPatch } from '../session-metadata/session-metadata-store.js';
4
+ import { createTitleSessionAccess } from './session-access.js';
5
+ import { configureServerOpenCodeFetchGate } from '../opencode/server-opencode-fetch.js';
6
+
7
+ afterEach(() => {
8
+ vi.useRealTimers();
9
+ vi.unstubAllGlobals();
10
+ configureServerOpenCodeFetchGate(null);
11
+ });
12
+
13
+ it.each([false, true])('runs a Host smart-title request and clears loading (model failure: %s)', async (fail) => {
14
+ vi.useFakeTimers();
15
+ const metadata = { openchamber: { titleRefresh: { lastAutoTitle: 'Original', requestedAt: 1000 } } };
16
+ const session = { id: 'ses_title', title: 'Original', directory: '/repo', metadata };
17
+ const updates = [];
18
+ const sessionAccess = {
19
+ get: vi.fn(async () => structuredClone(session)),
20
+ update: vi.fn(async (_id, _directory, patch) => {
21
+ if (patch.title) session.title = patch.title;
22
+ if (patch.metadata) session.metadata = mergeMetadataPatch(session.metadata, patch.metadata);
23
+ updates.push(structuredClone(session));
24
+ }),
25
+ messages: vi.fn(async () => [
26
+ { info: { id: 'u1', role: 'user' }, parts: [{ type: 'text', text: 'Implement a title refresh' }] },
27
+ { info: { id: 'a1', role: 'assistant' }, parts: [{ type: 'text', text: 'Done' }] },
28
+ ]),
29
+ };
30
+ const generate = vi.fn(async () => {
31
+ expect(session.metadata.openchamber.titleRefresh.isGenerating).toBe(true);
32
+ if (fail) throw new Error('title model unavailable');
33
+ return { text: 'Title refresh', providerID: 'test', modelID: 'test' };
34
+ });
35
+ const runtime = createSessionTitleRuntime({
36
+ sessionAccess,
37
+ buildOpenCodeUrl: (path) => `http://opencode${path}`,
38
+ getOpenCodeAuthHeaders: () => ({}),
39
+ getSmallModelService: async () => ({ generateSmallModelText: generate }),
40
+ now: () => 1000,
41
+ });
42
+ try {
43
+ runtime.processPayload({ type: 'openchamber:session-metadata', properties: {
44
+ sessionID: session.id, directory: '/repo', metadata,
45
+ } });
46
+ await vi.runAllTimersAsync();
47
+ expect(generate).toHaveBeenCalledTimes(1);
48
+ expect(session.title).toBe(fail ? 'Original' : 'Title refresh');
49
+ if (fail) expect(session.metadata.openchamber.titleRefresh.lastError).toBe('title model unavailable');
50
+ expect(session.metadata.openchamber.titleRefresh.isGenerating).not.toBe(true);
51
+ expect(session.metadata.openchamber.titleRefresh.requestedAt).toBeUndefined();
52
+ expect(updates.some((row) => row.metadata.openchamber.titleRefresh.isGenerating)).toBe(true);
53
+ } finally {
54
+ runtime.stop();
55
+ }
56
+ });
57
+
58
+ it('uses the real v2 client and publishes the generated title without another session click', async () => {
59
+ vi.useFakeTimers();
60
+ configureServerOpenCodeFetchGate(null, { allowMissingContract: true });
61
+ let metadata = { openchamber: { titleRefresh: { lastAutoTitle: 'Original', requestedAt: 1000 } } };
62
+ const session = { id: 'ses_title', title: 'Original', location: { directory: '/repo' }, time: { created: 1, updated: 2 } };
63
+ const requests = [];
64
+ vi.stubGlobal('fetch', vi.fn(async (input, init) => {
65
+ const request = input instanceof Request ? input : new Request(input, init);
66
+ const url = new URL(request.url);
67
+ requests.push(`${request.method} ${url.pathname}`);
68
+ if (url.pathname.endsWith('/message')) {
69
+ expect(url.searchParams.get('order')).toBe('desc');
70
+ return Response.json({ data: [
71
+ { id: 'a1', type: 'assistant', content: [{ type: 'text', text: 'Done' }] },
72
+ { id: 'u1', type: 'user', text: 'Implement title refresh' },
73
+ ] });
74
+ }
75
+ if (request.method === 'PATCH') {
76
+ const body = await request.json();
77
+ expect(Object.keys(body)).toEqual(['title']);
78
+ session.title = body.title;
79
+ return new Response(null, { status: 204 });
80
+ }
81
+ return Response.json({ data: session });
82
+ }));
83
+ const events = [];
84
+ const access = createTitleSessionAccess({
85
+ buildOpenCodeUrl: (path) => `http://opencode${path}`,
86
+ getOpenCodeAuthHeaders: () => ({}),
87
+ readSessionMetadata: async () => metadata,
88
+ persistSessionMetadata: async (_id, patch) => {
89
+ metadata = mergeMetadataPatch(metadata, patch);
90
+ events.push({ type: 'metadata', metadata: structuredClone(metadata) });
91
+ },
92
+ publishSession: (row) => events.push({ type: 'session', row }),
93
+ });
94
+ const runtime = createSessionTitleRuntime({
95
+ sessionAccess: access,
96
+ getSmallModelService: async () => ({ generateSmallModelText: async () => ({ text: 'Title refresh', providerID: 'test', modelID: 'test' }) }),
97
+ now: () => 1000,
98
+ });
99
+ try {
100
+ runtime.processPayload({ type: 'openchamber:session-metadata', properties: {
101
+ sessionID: session.id, metadata, directory: '/repo',
102
+ } });
103
+ await vi.runAllTimersAsync();
104
+ expect(events.some((event) => event.metadata?.openchamber?.titleRefresh?.isGenerating === true)).toBe(true);
105
+ expect(events.at(-1)).toMatchObject({ type: 'session', row: { title: 'Title refresh', directory: '/repo' } });
106
+ expect(metadata.openchamber.titleRefresh.isGenerating).toBeUndefined();
107
+ expect(requests).toContain('PATCH /api/session/ses_title');
108
+ } finally {
109
+ runtime.stop();
110
+ }
111
+ });
112
+
113
+ it('starts the first title from admitted user text while the assistant is still running', async () => {
114
+ vi.useFakeTimers();
115
+ const session = {
116
+ id: 'ses_first', title: '', time: { created: 1, updated: 1 },
117
+ metadata: {},
118
+ };
119
+ let finishTitle;
120
+ const generation = new Promise((resolve) => { finishTitle = resolve; });
121
+ const generate = vi.fn(() => generation);
122
+ const access = {
123
+ get: vi.fn(async () => structuredClone(session)),
124
+ update: vi.fn(async (_id, _directory, patch) => {
125
+ if (patch.metadata) session.metadata = mergeMetadataPatch(session.metadata, patch.metadata);
126
+ if (patch.title) session.title = patch.title;
127
+ }),
128
+ messages: vi.fn(async () => []),
129
+ };
130
+ const runtime = createSessionTitleRuntime({
131
+ sessionAccess: access,
132
+ getSmallModelService: async () => ({ generateSmallModelText: generate }),
133
+ isTitleRefreshEnabled: () => true,
134
+ now: () => 1000,
135
+ });
136
+ const emit = (type, data) => runtime.processPayload({ type, data, created: 1000, location: { directory: '/repo' } });
137
+ try {
138
+ emit('session.created', { sessionID: session.id, location: { directory: '/repo' } });
139
+ emit('session.inbox.enqueued', { sessionID: session.id, inboxID: 'msg_synthetic', item: {
140
+ type: 'synthetic', delivery: 'steer', payload: { text: 'Internal instructions' },
141
+ } });
142
+ await vi.runAllTimersAsync();
143
+ expect(generate).not.toHaveBeenCalled();
144
+ emit('session.inbox.enqueued', { sessionID: session.id, inboxID: 'msg_first', item: {
145
+ type: 'user', delivery: 'steer', payload: { text: 'Implement a session title generator' },
146
+ } });
147
+ emit('session.execution.started', { sessionID: session.id });
148
+ emit('session.status', { sessionID: session.id, status: { type: 'busy' } });
149
+ await vi.runAllTimersAsync();
150
+ expect(generate).toHaveBeenCalledTimes(1);
151
+ expect(generate.mock.calls[0][0].prompt).toContain('Implement a session title generator');
152
+ expect(session.metadata.openchamber?.titleRefresh?.isGenerating).toBe(true);
153
+ expect(access.messages).not.toHaveBeenCalled();
154
+ finishTitle({ text: 'Session titles', providerID: 'test', modelID: 'test' });
155
+ await vi.runAllTimersAsync();
156
+ expect(session.title).toBe('Session titles');
157
+ expect(session.metadata.openchamber.titleRefresh.isGenerating).toBeUndefined();
158
+ emit('session.execution.succeeded', { sessionID: session.id });
159
+ emit('session.inbox.enqueued', { sessionID: session.id, inboxID: 'msg_second', item: {
160
+ type: 'user', delivery: 'steer', payload: { text: 'Follow up on the implementation' },
161
+ } });
162
+ await vi.runAllTimersAsync();
163
+ expect(generate).toHaveBeenCalledTimes(1);
164
+ } finally {
165
+ runtime.stop();
166
+ }
167
+ });