@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
@@ -76,62 +76,82 @@ describe('modelAcceptsImages', () => {
76
76
  expect(modelAcceptsImages({ attachment: true })).toBe(true)
77
77
  expect(modelAcceptsImages({ id: 'plain' })).toBe(false)
78
78
  })
79
+
80
+ it('accepts v2 list-shaped capabilities.input containing image', () => {
81
+ expect(modelAcceptsImages({
82
+ capabilities: { tools: true, input: ['text', 'image'], output: ['text'] },
83
+ })).toBe(true)
84
+ expect(modelAcceptsImages({
85
+ capabilities: { tools: true, input: ['text'], output: ['text'] },
86
+ })).toBe(false)
87
+ })
79
88
  })
80
89
 
81
90
  describe('projectConnectedModels', () => {
82
- it('projects only connected providers', () => {
91
+ it('projects models from provider.list + model.list using ModelInfo.id as modelID', () => {
83
92
  const catalog = projectConnectedModels({
84
- connected: ['openai'],
85
93
  providers: [
94
+ { id: 'openai', name: 'OpenAI' },
95
+ { id: 'anthropic', name: 'Anthropic' },
96
+ ],
97
+ models: [
86
98
  {
87
- id: 'openai',
88
- name: 'OpenAI',
89
- models: {
90
- 'gpt-5.2': { id: 'gpt-5.2', name: 'GPT-5.2' },
91
- },
99
+ id: 'gpt-5.2',
100
+ modelID: 'internal-gpt-pack',
101
+ providerID: 'openai',
102
+ name: 'GPT-5.2',
103
+ capabilities: { tools: true, input: ['text'], output: ['text'] },
92
104
  },
93
105
  {
94
- id: 'anthropic',
95
- name: 'Anthropic',
96
- models: { 'claude-sonnet-4': { id: 'claude-sonnet-4', name: 'Claude' } },
106
+ id: 'claude-sonnet-4',
107
+ modelID: 'internal-claude',
108
+ providerID: 'anthropic',
109
+ name: 'Claude',
110
+ capabilities: { tools: true, input: ['text'], output: ['text'] },
97
111
  },
98
112
  ],
99
113
  })
100
114
  expect(catalog.models).toEqual([
101
115
  { providerID: 'openai', modelID: 'gpt-5.2', name: 'GPT-5.2', acceptsImages: false },
116
+ { providerID: 'anthropic', modelID: 'claude-sonnet-4', name: 'Claude', acceptsImages: false },
102
117
  ])
118
+ expect(catalog.connected).toEqual(['openai', 'anthropic'])
103
119
  })
104
120
 
105
- it('marks vision from SDK capabilities and legacy modalities', () => {
121
+ it('marks vision from SDK capabilities, v2 list input, and legacy modalities', () => {
106
122
  const catalog = projectConnectedModels({
107
- connected: ['openai', 'xai'],
108
123
  providers: [
124
+ { id: 'openai', name: 'OpenAI' },
125
+ { id: 'xai', name: 'xAI' },
126
+ ],
127
+ models: [
109
128
  {
110
- id: 'openai',
111
- name: 'OpenAI',
112
- models: {
113
- 'gpt-4o': { id: 'gpt-4o', name: 'GPT-4o', modalities: { input: ['text', 'image'] } },
114
- 'deepseek-v4-flash': { id: 'deepseek-v4-flash', name: 'deepseek-v4-flash' },
115
- },
129
+ id: 'gpt-4o',
130
+ modelID: 'pack-4o',
131
+ providerID: 'openai',
132
+ name: 'GPT-4o',
133
+ capabilities: { tools: true, input: ['text', 'image'], output: ['text'] },
116
134
  },
117
135
  {
118
- id: 'xai',
119
- name: 'xAI',
120
- models: {
121
- 'grok-4.6': {
122
- id: 'grok-4.6',
123
- name: 'Grok 4.6',
124
- // Authoritative SDK shape — no modalities.input array
125
- capabilities: {
126
- temperature: true,
127
- reasoning: true,
128
- attachment: true,
129
- toolcall: true,
130
- input: { text: true, audio: false, image: true, video: false, pdf: false },
131
- output: { text: true, audio: false, image: false, video: false, pdf: false },
132
- interleaved: false,
133
- },
134
- },
136
+ id: 'deepseek-v4-flash',
137
+ modelID: 'pack-ds',
138
+ providerID: 'openai',
139
+ name: 'deepseek-v4-flash',
140
+ capabilities: { tools: true, input: ['text'], output: ['text'] },
141
+ },
142
+ {
143
+ id: 'grok-4.6',
144
+ modelID: 'pack-grok',
145
+ providerID: 'xai',
146
+ name: 'Grok 4.6',
147
+ capabilities: {
148
+ temperature: true,
149
+ reasoning: true,
150
+ attachment: true,
151
+ toolcall: true,
152
+ input: { text: true, audio: false, image: true, video: false, pdf: false },
153
+ output: { text: true, audio: false, image: false, video: false, pdf: false },
154
+ interleaved: false,
135
155
  },
136
156
  },
137
157
  ],
@@ -141,6 +161,17 @@ describe('projectConnectedModels', () => {
141
161
  expect(catalog.models.find((model) => model.modelID === 'deepseek-v4-flash')?.acceptsImages).toBe(false)
142
162
  expect(catalog.connected).toEqual(['openai', 'xai'])
143
163
  })
164
+
165
+ it('ignores models whose provider is not in provider.list when providers are present', () => {
166
+ const catalog = projectConnectedModels({
167
+ providers: [{ id: 'openai', name: 'OpenAI' }],
168
+ models: [
169
+ { id: 'gpt-5.2', providerID: 'openai', name: 'GPT-5.2', capabilities: { input: ['text'], output: ['text'], tools: false } },
170
+ { id: 'other', providerID: 'missing', name: 'Other', capabilities: { input: ['text'], output: ['text'], tools: false } },
171
+ ],
172
+ })
173
+ expect(catalog.models.map((m) => m.modelID)).toEqual(['gpt-5.2'])
174
+ })
144
175
  })
145
176
 
146
177
  describe('loadConnectedCatalog', () => {
@@ -148,42 +179,73 @@ describe('loadConnectedCatalog', () => {
148
179
  vi.restoreAllMocks()
149
180
  })
150
181
 
151
- it('requires both /provider and /config/providers', async () => {
182
+ it('requires provider.list and model.list data arrays', async () => {
152
183
  await expect(loadConnectedCatalog({
153
- provider: { list: async () => ({ data: { connected: ['openai'] } }) },
154
- config: { providers: async () => ({ error: { status: 500 } }) },
184
+ provider: { list: async () => ({ location: {}, data: [{ id: 'openai', name: 'OpenAI' }] }) },
185
+ model: { list: async () => ({ location: {}, data: null }) },
155
186
  })).rejects.toThrow(/provider catalog/)
156
187
  })
157
188
 
158
- it('passes AbortSignal to provider.list and config.providers', async () => {
189
+ it('composes real client-shaped catalog responses', async () => {
190
+ const catalog = await loadConnectedCatalog({
191
+ provider: {
192
+ list: async () => ({
193
+ location: { directory: '/tmp' },
194
+ data: [{ id: 'openai', name: 'OpenAI' }],
195
+ }),
196
+ },
197
+ model: {
198
+ list: async () => ({
199
+ location: { directory: '/tmp' },
200
+ data: [{
201
+ id: 'gpt-4o',
202
+ modelID: 'internal',
203
+ providerID: 'openai',
204
+ name: 'GPT-4o',
205
+ capabilities: { tools: true, input: ['text', 'image'], output: ['text'] },
206
+ }],
207
+ }),
208
+ },
209
+ })
210
+ expect(catalog.models).toEqual([
211
+ { providerID: 'openai', modelID: 'gpt-4o', name: 'GPT-4o', acceptsImages: true },
212
+ ])
213
+ })
214
+
215
+ it('surfaces thrown client errors as upstream_error', async () => {
216
+ await expect(loadConnectedCatalog({
217
+ provider: { list: async () => { throw new Error('boom') } },
218
+ model: { list: async () => ({ data: [] }) },
219
+ })).rejects.toMatchObject({ code: 'upstream_error', message: 'boom' })
220
+ })
221
+
222
+ it('passes AbortSignal to provider.list and model.list', async () => {
159
223
  const signals = []
160
224
  const catalog = await loadConnectedCatalog({
161
225
  provider: {
162
226
  list: async (_params, options) => {
163
227
  signals.push(options?.signal)
164
- return { data: { connected: ['xai'] } }
228
+ return {
229
+ location: {},
230
+ data: [{ id: 'xai', name: 'xAI' }],
231
+ }
165
232
  },
166
233
  },
167
- config: {
168
- providers: async (_params, options) => {
234
+ model: {
235
+ list: async (_params, options) => {
169
236
  signals.push(options?.signal)
170
237
  return {
171
- data: {
172
- providers: [{
173
- id: 'xai',
174
- name: 'xAI',
175
- models: {
176
- 'grok-4.6': {
177
- id: 'grok-4.6',
178
- name: 'Grok 4.6',
179
- capabilities: {
180
- input: { text: true, image: true },
181
- attachment: true,
182
- },
183
- },
184
- },
185
- }],
186
- },
238
+ location: {},
239
+ data: [{
240
+ id: 'grok-4.6',
241
+ modelID: 'internal',
242
+ providerID: 'xai',
243
+ name: 'Grok 4.6',
244
+ capabilities: {
245
+ input: { text: true, image: true },
246
+ attachment: true,
247
+ },
248
+ }],
187
249
  }
188
250
  },
189
251
  },
@@ -209,7 +271,7 @@ describe('loadConnectedCatalog', () => {
209
271
  else options?.signal?.addEventListener('abort', onAbort, { once: true })
210
272
  }),
211
273
  },
212
- config: { providers: async () => ({ data: { providers: [] } }) },
274
+ model: { list: async () => ({ data: [] }) },
213
275
  }, { timeoutMs: 30 })).rejects.toMatchObject({
214
276
  code: 'upstream_error',
215
277
  message: expect.stringMatching(/timed out|aborted/i),
@@ -1,5 +1,5 @@
1
1
  import { isConnectedModel, loadConnectedCatalog, parseModelRef } from './catalog.js';
2
- import { generateOpenCodeText } from './generate.js';
2
+ import { generateOpenCodeText, parseDataUrl, MAX_ATTACHMENT_BYTES } from './generate.js';
3
3
 
4
4
  const isRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
5
5
 
@@ -15,10 +15,29 @@ const normalizeCompletionFilePart = (part) => {
15
15
  if (!isRecord(part) || part.type !== 'file') return null;
16
16
  if (typeof part.mime !== 'string' || !part.mime.trim()) return null;
17
17
  if (typeof part.url !== 'string' || !part.url.trim()) return null;
18
+ const url = part.url.trim();
19
+ if (!url.startsWith('data:')) {
20
+ throw new LlmError('validation_error', 400, 'file part url must be a data URL');
21
+ }
22
+ let parsed;
23
+ try {
24
+ parsed = parseDataUrl(url);
25
+ } catch (error) {
26
+ if (error?.code === 'validation_error') {
27
+ throw new LlmError('validation_error', 400, error.message || 'attachment too large');
28
+ }
29
+ throw error;
30
+ }
31
+ if (!parsed) {
32
+ throw new LlmError('validation_error', 400, 'file part data URL is malformed');
33
+ }
34
+ if (parsed.byteLength > MAX_ATTACHMENT_BYTES) {
35
+ throw new LlmError('validation_error', 400, `Attachment exceeds ${MAX_ATTACHMENT_BYTES} byte limit`);
36
+ }
18
37
  return {
19
38
  type: 'file',
20
39
  mime: part.mime.trim(),
21
- url: part.url.trim(),
40
+ url,
22
41
  ...(typeof part.filename === 'string' && part.filename.trim() ? { filename: part.filename.trim() } : {}),
23
42
  };
24
43
  };
@@ -57,15 +76,15 @@ export function toOpenAICompletion({ id, model, text, created = Math.floor(Date.
57
76
  }],
58
77
  usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
59
78
  };
60
- }
79
+ };
61
80
 
62
81
  /**
63
82
  * OpenAI-shaped completions against OpenCode's already-connected providers.
64
83
  *
65
84
  * Public HTTP stays non-streaming (`stream: true` → validation_error).
66
85
  * In-process callers (Assistant contact harness) may pass `onTextDelta` and
67
- * `globalEventHub`; those are forwarded to generate for real throwaway-session
68
- * `message.part.delta` tokens only — never as fake post-hoc SSE on this route.
86
+ * `globalEventHub`; those are forwarded to generate for real attachment-session
87
+ * `session.text.delta` tokens only — never as fake post-hoc SSE on this route.
69
88
  */
70
89
  export async function createChatCompletion({
71
90
  body,
@@ -75,16 +94,16 @@ export async function createChatCompletion({
75
94
  loadCatalog = loadConnectedCatalog,
76
95
  generateText = generateOpenCodeText,
77
96
  ensureTempDirectory,
78
- fetchImpl,
79
97
  onTextDelta = null,
80
98
  globalEventHub = null,
99
+ persistSessionMetadata = null,
100
+ onSystemSessionPersisted = null,
81
101
  signal = null,
82
102
  }) {
83
103
  signal?.throwIfAborted();
84
104
  if (!isRecord(body)) throw new LlmError('validation_error', 400, 'JSON body is required');
85
- // Bundled OpenCode 1.18.4 generate is a full-turn JSON reply (sessionless
86
- // generate or throwaway session.promptAsync). This HTTP gateway does not
87
- // token-stream. Do not emit fake SSE after the fact.
105
+ // session.generate / attachment-session return a full turn. This HTTP gateway
106
+ // does not token-stream. Do not emit fake SSE after the fact.
88
107
  // In-process onTextDelta (optional) is a separate internal callback path.
89
108
  if (body.stream === true) {
90
109
  throw new LlmError(
@@ -103,8 +122,8 @@ export async function createChatCompletion({
103
122
 
104
123
  const client = clientFactory?.() ?? null;
105
124
  const catalog = await loadCatalog(client ?? {
106
- provider: { list: async () => ({ error: { status: 500 } }) },
107
- config: { providers: async () => ({ error: { status: 500 } }) },
125
+ provider: { list: async () => { throw new Error('no client'); } },
126
+ model: { list: async () => { throw new Error('no client'); } },
108
127
  });
109
128
  signal?.throwIfAborted();
110
129
  if (!isConnectedModel(catalog, resolved.providerID, resolved.modelID)) {
@@ -124,7 +143,6 @@ export async function createChatCompletion({
124
143
  modelID: resolved.modelID,
125
144
  ...(variant ? { variant } : {}),
126
145
  messages,
127
- fetchImpl,
128
146
  clientFactory,
129
147
  ensureTempDirectory,
130
148
  forwardImageParts: Boolean(catalog.models.find((entry) => (
@@ -132,6 +150,8 @@ export async function createChatCompletion({
132
150
  ))?.acceptsImages),
133
151
  onTextDelta,
134
152
  globalEventHub,
153
+ persistSessionMetadata,
154
+ onSystemSessionPersisted,
135
155
  signal,
136
156
  });
137
157
  } catch (error) {
@@ -139,6 +159,15 @@ export async function createChatCompletion({
139
159
  if (error?.code === 'validation_error') {
140
160
  throw new LlmError('validation_error', 400, error.message || 'validation_error');
141
161
  }
162
+ if (error?.code === 'llm_attachment_generation_unavailable') {
163
+ throw new LlmError(
164
+ 'llm_attachment_generation_unavailable',
165
+ 502,
166
+ typeof error?.message === 'string' && error.message.trim()
167
+ ? error.message
168
+ : 'LLM attachment generation is unavailable',
169
+ );
170
+ }
142
171
  throw new LlmError(
143
172
  'upstream_error',
144
173
  502,
@@ -52,7 +52,7 @@ describe('createChatCompletion', () => {
52
52
  })
53
53
 
54
54
  it('returns a non-stream completion from generateText', async () => {
55
- const generateText = vi.fn(async () => ({ text: 'done', source: 'throwaway-session' }))
55
+ const generateText = vi.fn(async () => ({ text: 'done', source: 'session.generate' }))
56
56
  const result = await createChatCompletion({
57
57
  generateText,
58
58
  loadCatalog: async () => ({
@@ -64,10 +64,11 @@ describe('createChatCompletion', () => {
64
64
  expect(result.completion.choices[0].message.content).toBe('done')
65
65
  expect(result.providerID).toBe('openai')
66
66
  expect(result.modelID).toBe('gpt-5.2')
67
+ expect(result.source).toBe('session.generate')
67
68
  })
68
69
 
69
70
  it('forwards in-process onTextDelta and globalEventHub to generateText', async () => {
70
- const generateText = vi.fn(async () => ({ text: 'streamed', source: 'throwaway-session' }))
71
+ const generateText = vi.fn(async () => ({ text: 'streamed', source: 'attachment-session' }))
71
72
  const onTextDelta = vi.fn()
72
73
  const signal = new AbortController().signal
73
74
  const globalEventHub = { subscribeEvent: vi.fn() }
@@ -88,7 +89,7 @@ describe('createChatCompletion', () => {
88
89
  })
89
90
 
90
91
  it('forwards optional file parts on user messages', async () => {
91
- const generateText = vi.fn(async () => ({ text: 'saw it', source: 'throwaway-session' }))
92
+ const generateText = vi.fn(async () => ({ text: 'saw it', source: 'attachment-session' }))
92
93
  const image = { type: 'file', mime: 'image/png', url: 'data:image/png;base64,aa', filename: 'shot.png' }
93
94
  await createChatCompletion({
94
95
  generateText,
@@ -108,7 +109,7 @@ describe('createChatCompletion', () => {
108
109
  })
109
110
 
110
111
  it('asks generate to skip image bytes when the catalog model is not vision-capable', async () => {
111
- const generateText = vi.fn(async () => ({ text: 'ok', source: 'throwaway-session' }))
112
+ const generateText = vi.fn(async () => ({ text: 'ok', source: 'session.generate' }))
112
113
  await createChatCompletion({
113
114
  generateText,
114
115
  loadCatalog: async () => ({
@@ -120,6 +121,26 @@ describe('createChatCompletion', () => {
120
121
  expect(generateText.mock.calls[0][0].forwardImageParts).toBe(false)
121
122
  })
122
123
 
124
+ it('rejects malformed data URL file parts', async () => {
125
+ const generateText = vi.fn()
126
+ await expect(createChatCompletion({
127
+ generateText,
128
+ loadCatalog: async () => ({
129
+ models: [{ providerID: 'openai', modelID: 'gpt-5.2', acceptsImages: true }],
130
+ connected: ['openai'],
131
+ }),
132
+ body: {
133
+ model: 'openai/gpt-5.2',
134
+ messages: [{
135
+ role: 'user',
136
+ content: 'look',
137
+ parts: [{ type: 'file', mime: 'image/png', url: 'https://example.com/x.png' }],
138
+ }],
139
+ },
140
+ })).rejects.toMatchObject({ code: 'validation_error', statusCode: 400 })
141
+ expect(generateText).not.toHaveBeenCalled()
142
+ })
143
+
123
144
  it('LlmError carries a stable code', () => {
124
145
  expect(new LlmError('no_provider', 400, 'missing')).toMatchObject({
125
146
  code: 'no_provider',
@@ -146,4 +167,24 @@ describe('createChatCompletion', () => {
146
167
  message: 'model refused the request',
147
168
  })
148
169
  })
170
+
171
+ it('maps llm_attachment_generation_unavailable before treating it as generic upstream', async () => {
172
+ const generateText = vi.fn(async () => {
173
+ const error = new Error('deny-all missing')
174
+ error.code = 'llm_attachment_generation_unavailable'
175
+ throw error
176
+ })
177
+ await expect(createChatCompletion({
178
+ generateText,
179
+ loadCatalog: async () => ({
180
+ models: [{ providerID: 'openai', modelID: 'gpt-4o', acceptsImages: true }],
181
+ connected: ['openai'],
182
+ }),
183
+ body: { model: 'openai/gpt-4o', messages: [{ role: 'user', content: 'hi' }] },
184
+ })).rejects.toMatchObject({
185
+ code: 'llm_attachment_generation_unavailable',
186
+ statusCode: 502,
187
+ message: 'deny-all missing',
188
+ })
189
+ })
149
190
  })