@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,137 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { applyNativePatch, convertAgentConfig, inspectAgentConfig, writeAgentDocument } from './agent-document.js';
4
+
5
+ describe('inspectAgentConfig', () => {
6
+ it('treats a native file as current', () => {
7
+ expect(inspectAgentConfig({
8
+ description: 'Reviewer',
9
+ mode: 'subagent',
10
+ model: 'openai/gpt-5#high',
11
+ hidden: true,
12
+ color: '#ff6b6b',
13
+ steps: 5,
14
+ permissions: [{ action: 'shell', resource: '*', effect: 'ask' }],
15
+ })).toEqual({ legacy: false, dropped: [] });
16
+ });
17
+
18
+ it('reports fields the next request does not use', () => {
19
+ const inspection = inspectAgentConfig({
20
+ temperature: 0.2,
21
+ top_p: 0.9,
22
+ options: { reasoningEffort: 'high' },
23
+ prompt: '{file:./prompt.md}',
24
+ color: 'red',
25
+ variant: 'high',
26
+ extra: true,
27
+ });
28
+ expect(inspection.legacy).toBe(true);
29
+ expect(inspection.dropped).toEqual([
30
+ { key: 'temperature', reason: 'generation' },
31
+ { key: 'top_p', reason: 'generation' },
32
+ { key: 'options', reason: 'unknown' },
33
+ { key: 'prompt', reason: 'prompt-file' },
34
+ { key: 'color', reason: 'color' },
35
+ { key: 'variant', reason: 'variant' },
36
+ { key: 'extra', reason: 'unknown' },
37
+ ]);
38
+ });
39
+ });
40
+
41
+ describe('convertAgentConfig', () => {
42
+ it('folds a legacy agent into native markdown fields', () => {
43
+ const converted = convertAgentConfig({
44
+ description: 'Reviewer',
45
+ mode: 'subagent',
46
+ model: 'openai/gpt-5',
47
+ variant: 'high',
48
+ temperature: 0.2,
49
+ prompt: 'Be careful.',
50
+ permission: { bash: 'ask', task: 'allow', write: 'deny' },
51
+ tools: { write: false },
52
+ maxSteps: 4,
53
+ disable: true,
54
+ color: '#112233',
55
+ request: { body: { temperature: 0.2 } },
56
+ });
57
+
58
+ expect(converted.legacy).toBe(true);
59
+ expect(converted.body).toBe('Be careful.');
60
+ expect(converted.frontmatter).toMatchObject({
61
+ description: 'Reviewer',
62
+ mode: 'subagent',
63
+ model: 'openai/gpt-5#high',
64
+ steps: 4,
65
+ disabled: true,
66
+ color: '#112233',
67
+ request: { body: { temperature: 0.2 } },
68
+ });
69
+ expect(converted.frontmatter).not.toHaveProperty('temperature');
70
+ expect(converted.frontmatter).not.toHaveProperty('hidden');
71
+ expect(converted.frontmatter.permissions).toEqual(expect.arrayContaining([
72
+ { action: 'shell', resource: '*', effect: 'ask' },
73
+ { action: 'subagent', resource: '*', effect: 'allow' },
74
+ { action: 'edit', resource: '*', effect: 'deny' },
75
+ ]));
76
+ });
77
+ });
78
+
79
+ describe('applyNativePatch', () => {
80
+ it('patches only the keys present in the update', () => {
81
+ const next = applyNativePatch({
82
+ frontmatter: {
83
+ model: 'openai/gpt-5',
84
+ hidden: true,
85
+ permissions: [{ action: 'read', resource: '*', effect: 'allow' }],
86
+ variant: 'high',
87
+ temperature: 1,
88
+ },
89
+ body: 'old',
90
+ }, {
91
+ model: null,
92
+ hidden: false,
93
+ permissions: [],
94
+ system: null,
95
+ steps: 0,
96
+ });
97
+
98
+ expect(next.body).toBe('');
99
+ expect(next.frontmatter).toEqual({
100
+ temperature: 1,
101
+ });
102
+ });
103
+ });
104
+
105
+ describe('writeAgentDocument', () => {
106
+ it('leaves unmentioned fields alone on a prompt-only patch', () => {
107
+ const next = writeAgentDocument({
108
+ frontmatter: {
109
+ temperature: 1,
110
+ permission: { bash: 'allow' },
111
+ },
112
+ body: 'legacy prompt',
113
+ }, {
114
+ system: 'Only the prompt changed.',
115
+ }, false);
116
+
117
+ expect(next.body).toBe('Only the prompt changed.');
118
+ expect(next.frontmatter.temperature).toBe(1);
119
+ expect(next.frontmatter.permission).toEqual({ bash: 'allow' });
120
+ });
121
+
122
+ it('drops legacy fields when confirmDrop is true', () => {
123
+ const next = writeAgentDocument({
124
+ frontmatter: {
125
+ temperature: 1,
126
+ permission: { bash: 'allow' },
127
+ },
128
+ body: 'legacy prompt',
129
+ }, {
130
+ system: 'Only the prompt changed.',
131
+ }, true);
132
+
133
+ expect(next.body).toBe('Only the prompt changed.');
134
+ expect(next.frontmatter.temperature).toBeUndefined();
135
+ expect(next.frontmatter.permission).toEqual({ bash: 'allow' });
136
+ });
137
+ });
@@ -16,6 +16,10 @@ import {
16
16
  resolvePromptFilePath,
17
17
  writePromptFile,
18
18
  } from './shared.js';
19
+ import {
20
+ inspectAgentConfig,
21
+ writeAgentDocument,
22
+ } from './agent-document.js';
19
23
 
20
24
  // ============== AGENT SCOPE HELPERS ==============
21
25
 
@@ -321,21 +325,100 @@ function getAgentSources(agentName, workingDirectory, lookupCache = createAgentL
321
325
  }
322
326
  };
323
327
 
328
+ const stored = {};
329
+ if (jsonSection && typeof jsonSection === 'object') {
330
+ Object.assign(stored, jsonSection);
331
+ }
324
332
  if (mdExists) {
325
333
  const { frontmatter, body } = parseMdFile(mdPath);
326
334
  sources.md.fields = Object.keys(frontmatter);
327
335
  if (body) {
328
336
  sources.md.fields.push('prompt');
329
337
  }
338
+ Object.assign(stored, frontmatter);
339
+ if (typeof body === 'string' && body.trim()) stored.prompt = body.trim();
330
340
  }
331
341
 
332
342
  if (jsonSection) {
333
343
  sources.json.fields = Object.keys(jsonSection);
334
344
  }
345
+ sources.document = inspectAgentConfig(stored);
335
346
 
336
347
  return sources;
337
348
  }
338
349
 
350
+ function listDisabledAgentOverrides(workingDirectory) {
351
+ /** @type {Array<{ name: string, scope: string, description?: string, mode?: string }>} */
352
+ const found = [];
353
+ const visit = (directory, scope) => {
354
+ if (!directory || !fs.existsSync(directory)) return;
355
+ const walk = (current, prefix) => {
356
+ let entries = [];
357
+ try {
358
+ entries = fs.readdirSync(current, { withFileTypes: true });
359
+ } catch {
360
+ return;
361
+ }
362
+ for (const entry of entries) {
363
+ if (found.length >= 200) return;
364
+ const full = path.join(current, entry.name);
365
+ if (entry.isDirectory()) {
366
+ walk(full, prefix ? `${prefix}/${entry.name}` : entry.name);
367
+ continue;
368
+ }
369
+ if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
370
+ const base = entry.name.slice(0, -3);
371
+ const name = prefix ? `${prefix}/${base}` : base;
372
+ let frontmatter = {};
373
+ try {
374
+ frontmatter = parseMdFile(full).frontmatter || {};
375
+ } catch {
376
+ continue;
377
+ }
378
+ if (frontmatter.disabled !== true && frontmatter.disable !== true) continue;
379
+ found.push({
380
+ name,
381
+ scope,
382
+ ...(typeof frontmatter.description === 'string' ? { description: frontmatter.description } : {}),
383
+ ...(frontmatter.mode === 'primary' || frontmatter.mode === 'subagent' || frontmatter.mode === 'all'
384
+ ? { mode: frontmatter.mode }
385
+ : {}),
386
+ });
387
+ }
388
+ };
389
+ walk(directory, '');
390
+ };
391
+
392
+ visit(AGENT_DIR, AGENT_SCOPE.USER);
393
+ if (workingDirectory) {
394
+ visit(path.join(workingDirectory, '.opencode', 'agents'), AGENT_SCOPE.PROJECT);
395
+ visit(path.join(workingDirectory, '.opencode', 'agent'), AGENT_SCOPE.PROJECT);
396
+ }
397
+ return found;
398
+ }
399
+
400
+ function nativeWritePath(agentName, workingDirectory, scope, lookupCache) {
401
+ if (scope === AGENT_SCOPE.PROJECT && workingDirectory) {
402
+ ensureProjectAgentDir(workingDirectory);
403
+ return getProjectAgentPath(workingDirectory, agentName);
404
+ }
405
+ if (scope === AGENT_SCOPE.USER) {
406
+ return getUserAgentPath(agentName, lookupCache);
407
+ }
408
+ const existing = getAgentWritePath(agentName, workingDirectory, undefined, lookupCache);
409
+ if (existing.path && fs.existsSync(existing.path)) return existing.path;
410
+ return getUserAgentPath(agentName, lookupCache);
411
+ }
412
+
413
+ function writeNativeAgent(agentName, patch, workingDirectory, scope, confirmDrop) {
414
+ ensureDirs();
415
+ const lookupCache = createAgentLookupCache();
416
+ const targetPath = nativeWritePath(agentName, workingDirectory, scope, lookupCache);
417
+ const existing = fs.existsSync(targetPath) ? parseMdFile(targetPath) : { frontmatter: {}, body: '' };
418
+ const next = writeAgentDocument(existing, patch && typeof patch === 'object' ? patch : {}, confirmDrop === true);
419
+ writeMdFile(targetPath, next.frontmatter, next.body);
420
+ }
421
+
339
422
  function getAgentConfig(agentName, workingDirectory, lookupCache = createAgentLookupCache()) {
340
423
  const projectPath = workingDirectory ? getProjectAgentPath(workingDirectory, agentName) : null;
341
424
  const projectExists = projectPath && fs.existsSync(projectPath);
@@ -409,6 +492,12 @@ function createAgent(agentName, config, workingDirectory, scope) {
409
492
  targetScope = AGENT_SCOPE.USER;
410
493
  }
411
494
 
495
+ if (config && Object.prototype.hasOwnProperty.call(config, 'native')) {
496
+ writeNativeAgent(agentName, config.native, workingDirectory, targetScope, config.confirmDrop === true);
497
+ console.log(`Created new agent: ${agentName} (scope: ${targetScope})`);
498
+ return;
499
+ }
500
+
412
501
  const { prompt, scope: _scopeFromConfig, ...rawFrontmatter } = config;
413
502
  const frontmatter = Object.fromEntries(
414
503
  Object.entries(rawFrontmatter).filter(([, value]) => value !== null && value !== undefined)
@@ -419,6 +508,12 @@ function createAgent(agentName, config, workingDirectory, scope) {
419
508
  }
420
509
 
421
510
  function updateAgent(agentName, updates, workingDirectory) {
511
+ if (updates && Object.prototype.hasOwnProperty.call(updates, 'native')) {
512
+ writeNativeAgent(agentName, updates.native, workingDirectory, updates.scope, updates.confirmDrop === true);
513
+ console.log(`Updated agent: ${agentName}`);
514
+ return;
515
+ }
516
+
422
517
  ensureDirs();
423
518
  const lookupCache = createAgentLookupCache();
424
519
 
@@ -693,6 +788,7 @@ function deleteAgent(agentName, workingDirectory, scope) {
693
788
  export {
694
789
  getAgentSources,
695
790
  getAgentConfig,
791
+ listDisabledAgentOverrides,
696
792
  createAgent,
697
793
  updateAgent,
698
794
  deleteAgent,
@@ -81,9 +81,14 @@ export const createOpenCodeAuthStateRuntime = (dependencies) => {
81
81
  return generatedPassword;
82
82
  };
83
83
 
84
+ // A server OpenChamber does not own (the shared official service) keeps its
85
+ // own password; adopt it instead of generating one.
86
+ const adoptOpenCodeServerPassword = (password, source) => setOpenCodeAuthState(password, source);
87
+
84
88
  return {
85
89
  getOpenCodeAuthHeaders,
86
90
  isOpenCodeConnectionSecure,
87
91
  ensureLocalOpenCodeServerPassword,
92
+ adoptOpenCodeServerPassword,
88
93
  };
89
94
  };
@@ -64,6 +64,7 @@ export const createBootstrapRuntime = (dependencies) => {
64
64
  setAutoAcceptSession,
65
65
  sessionIndexService,
66
66
  sessionIndexSyncRuntime,
67
+ getCommittedHostMetadata = null,
67
68
  transcriptCacheService,
68
69
  } = options;
69
70
 
@@ -156,6 +157,7 @@ export const createBootstrapRuntime = (dependencies) => {
156
157
  getCachedZenModels,
157
158
  sessionIndexService,
158
159
  sessionIndexSyncRuntime,
160
+ getCommittedHostMetadata,
159
161
  transcriptCacheService,
160
162
  express,
161
163
  });
@@ -2,9 +2,62 @@ import fs from 'node:fs/promises';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import { parse as parseJsonc } from 'jsonc-parser';
5
- import { createOpencodeClient } from '@opencode-ai/sdk/v2';
5
+ import { OpenCode } from '@opencode/client';
6
6
  import { projectProviderCatalog } from './provider-catalog.js';
7
7
 
8
+ // Compose official v2 provider.list + model.list (+ optional default) into the
9
+ // catalog shape consumed by projectProviderCatalog. Missing arrays are failure.
10
+ const composeV2ProviderCatalogSource = (providers, models, defaultModel) => {
11
+ if (!Array.isArray(providers) || !Array.isArray(models)) return null;
12
+
13
+ const modelsByProvider = new Map();
14
+ for (const model of models) {
15
+ if (!model || typeof model !== 'object') continue;
16
+ const providerID = typeof model.providerID === 'string' ? model.providerID : '';
17
+ // ModelInfo.id is the external model id used in generate/session refs.
18
+ // ModelInfo.modelID is a separate internal field and must not be preferred.
19
+ const modelID = typeof model.id === 'string' && model.id
20
+ ? model.id
21
+ : (typeof model.modelID === 'string' ? model.modelID : '');
22
+ if (!providerID || !modelID) continue;
23
+ if (!modelsByProvider.has(providerID)) modelsByProvider.set(providerID, Object.create(null));
24
+ const entry = { id: modelID };
25
+ if (typeof model.name === 'string' && model.name) entry.name = model.name;
26
+ if (typeof model.family === 'string' && model.family) entry.family = model.family;
27
+ if (model.limit && typeof model.limit === 'object') entry.limit = model.limit;
28
+ if (model.capabilities) entry.capabilities = model.capabilities;
29
+ // v2 cost is a tier array; v2 variants are `{ id }[]`. Projection owns the safe shape.
30
+ if (model.cost && typeof model.cost === 'object') entry.cost = model.cost;
31
+ if (model.variants && typeof model.variants === 'object') entry.variants = model.variants;
32
+ if (typeof model.time?.released === 'number' && Number.isFinite(model.time.released)) {
33
+ entry.release_date = new Date(model.time.released).toISOString().slice(0, 10);
34
+ }
35
+ modelsByProvider.get(providerID)[modelID] = entry;
36
+ }
37
+
38
+ const list = [];
39
+ for (const provider of providers) {
40
+ if (!provider || typeof provider.id !== 'string' || !provider.id) continue;
41
+ list.push({
42
+ id: provider.id,
43
+ name: typeof provider.name === 'string' && provider.name ? provider.name : provider.id,
44
+ models: modelsByProvider.get(provider.id) || Object.create(null),
45
+ });
46
+ }
47
+
48
+ const defaults = Object.create(null);
49
+ const defaultModelID = typeof defaultModel?.id === 'string' && defaultModel.id
50
+ ? defaultModel.id
51
+ : (typeof defaultModel?.modelID === 'string' ? defaultModel.modelID : '');
52
+ if (defaultModel && typeof defaultModel.providerID === 'string' && defaultModelID) {
53
+ defaults[defaultModel.providerID] = defaultModelID;
54
+ }
55
+ return { providers: list, default: defaults };
56
+ };
57
+
58
+ const createOpenCodeClient = ({ baseUrl, headers, fetch: fetchImpl }) =>
59
+ OpenCode.make({ baseUrl, headers, fetch: fetchImpl });
60
+
8
61
  const MAX_GLOBAL_CONFIG_SIZE = 2 * 1024 * 1024;
9
62
  const GLOBAL_CONFIG_FILES = {
10
63
  opencode: ['opencode.json', 'opencode.jsonc'],
@@ -81,10 +134,10 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
81
134
  const {
82
135
  resolveProjectDirectory,
83
136
  resolveOptionalProjectDirectory,
84
- refreshOpenCodeAfterConfigChange,
85
- clientReloadDelayMs,
137
+ waitForOpenCodeReady,
86
138
  getAgentSources,
87
139
  getAgentConfig,
140
+ listDisabledAgentOverrides,
88
141
  createAgent,
89
142
  updateAgent,
90
143
  deleteAgent,
@@ -115,25 +168,43 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
115
168
  if (!directory) {
116
169
  return res.status(400).json({ error });
117
170
  }
118
- const client = createOpencodeClient({
171
+ // Gate on managed-OpenCode readiness like the generic proxy: without this
172
+ // the SDK hits an upstream that is still starting (or a stale orphan from
173
+ // a nodemon restart) and gets HTML/401 back, surfacing as a spurious 502.
174
+ if (typeof waitForOpenCodeReady === 'function') {
175
+ await waitForOpenCodeReady(20_000, 200);
176
+ }
177
+ const client = createOpenCodeClient({
119
178
  baseUrl: buildOpenCodeUrl('/', '').replace(/\/$/, ''),
120
- directory,
121
179
  headers: getOpenCodeAuthHeaders(),
122
- fetch: (request) => fetch(request, { signal: AbortSignal.timeout(8_000) }),
180
+ // Forward the full init: the SDK carries Authorization in init.headers.
181
+ // Dropping init (the old `(request) => fetch(request, { signal })` shape)
182
+ // silently stripped auth and produced spurious upstream 401s.
183
+ fetch: (request, init) => fetch(request, { ...init, signal: AbortSignal.timeout(8_000) }),
123
184
  });
124
- const response = await client.config.providers({ directory });
125
- if (response?.error || response?.data === undefined) {
185
+ const location = { directory };
186
+ const [providersResult, modelsResult, defaultResult] = await Promise.all([
187
+ client.provider.list({ location }),
188
+ client.model.list({ location }),
189
+ client.model.default({ location }),
190
+ ]);
191
+ const source = composeV2ProviderCatalogSource(
192
+ providersResult?.data,
193
+ modelsResult?.data,
194
+ defaultResult?.data,
195
+ );
196
+ if (!source) {
126
197
  console.error('Provider catalog upstream response failed');
127
198
  return res.status(502).json({ error: 'Provider catalog is unavailable' });
128
199
  }
129
- const catalog = projectProviderCatalog(response?.data);
200
+ const catalog = projectProviderCatalog(source);
130
201
  if (!catalog.ok) {
131
202
  console.error('Provider catalog upstream response is malformed');
132
203
  return res.status(502).json({ error: 'Provider catalog is unavailable' });
133
204
  }
134
205
  return res.json(catalog.value);
135
- } catch {
136
- console.error('Provider catalog request failed');
206
+ } catch (catalogError) {
207
+ console.error('Provider catalog request failed', catalogError?.reason ? `(${catalogError.reason})` : catalogError?.message ?? catalogError);
137
208
  return res.status(502).json({ error: 'Provider catalog is unavailable' });
138
209
  }
139
210
  });
@@ -191,7 +262,8 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
191
262
  target: req.params.target,
192
263
  fileName: target.fileName,
193
264
  content,
194
- requiresManualRestart: true,
265
+ requiresManualRestart: req.params.target !== 'opencode',
266
+ application: req.params.target === 'opencode' ? 'watch' : 'manual',
195
267
  });
196
268
  } catch (error) {
197
269
  console.error('Failed to write global configuration:', error);
@@ -199,29 +271,9 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
199
271
  }
200
272
  });
201
273
 
202
- // Build the response for a config mutation based on whether OpenCode actually
203
- // reloaded the change. When connected to an external OpenCode server that
204
- // OpenChamber cannot restart, the change is persisted to disk but the running
205
- // server will not serve it until the user restarts that server. We must not
206
- // report a clean "reloading" success in that case, otherwise the UI silently
207
- // reverts the edit to the stale value on the next refresh.
208
- const buildConfigMutationResponse = (refreshResult, { liveMessage, manualRestartMessage }) => {
209
- if (refreshResult && refreshResult.external) {
210
- return {
211
- success: true,
212
- requiresReload: false,
213
- requiresManualRestart: true,
214
- message: manualRestartMessage,
215
- };
216
- }
217
-
218
- return {
219
- success: true,
220
- requiresReload: true,
221
- message: liveMessage,
222
- reloadDelayMs: clientReloadDelayMs,
223
- };
224
- };
274
+ // A receipt confirms persistence, not runtime activation. V2 watches local
275
+ // configuration; domain events confirm changes without rebuilding locations.
276
+ const configSaved = () => ({ success: true, requiresReload: false, application: 'watch' });
225
277
 
226
278
  const readMutationBody = (req) => (
227
279
  req.body && typeof req.body === 'object' && !Array.isArray(req.body) ? req.body : {}
@@ -230,24 +282,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
230
282
  const completeMcpMutation = async (res, action, name, applyChange) => {
231
283
  applyChange();
232
284
 
233
- try {
234
- await refreshOpenCodeAfterConfigChange(`mcp ${action}`);
235
- return res.json({
236
- success: true,
237
- requiresReload: true,
238
- message: `MCP server "${name}" ${action}d. Reloading interface…`,
239
- reloadDelayMs: clientReloadDelayMs,
240
- });
241
- } catch (error) {
242
- console.error(`[API:MCP ${action}] Reload failed after config write:`, error);
243
- return res.json({
244
- success: true,
245
- requiresReload: false,
246
- reloadFailed: true,
247
- message: `MCP server "${name}" ${action}d, but OpenCode reload failed.`,
248
- warning: error.message || 'OpenCode reload failed after the MCP configuration changed',
249
- });
250
- }
285
+ return res.json({ ...configSaved(), message: `MCP server "${name}" ${action}d.` });
251
286
  };
252
287
 
253
288
  app.post('/api/config/agents/metadata', async (req, res) => {
@@ -277,7 +312,10 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
277
312
  sources,
278
313
  };
279
314
  }
280
- return res.json({ agents });
315
+ const disabled = typeof listDisabledAgentOverrides === 'function'
316
+ ? listDisabledAgentOverrides(directory)
317
+ : [];
318
+ return res.json(disabled.length > 0 ? { agents, disabled } : { agents });
281
319
  } catch (error) {
282
320
  console.error('Failed to get agent metadata batch:', error);
283
321
  return res.status(500).json({ error: 'Failed to get agent configuration metadata' });
@@ -337,15 +375,11 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
337
375
  console.log('[Server] Creating agent');
338
376
 
339
377
  createAgent(agentName, config, directory, scope);
340
- const refreshResult = await refreshOpenCodeAfterConfigChange('agent creation', {
341
- agentName
342
- });
343
-
344
- res.json(buildConfigMutationResponse(refreshResult, {
345
- liveMessage: `Agent ${agentName} created successfully. Reloading interface…`,
346
- manualRestartMessage: `Agent ${agentName} saved. Restart your connected OpenCode server to apply the change.`,
347
- }));
378
+ res.json(configSaved());
348
379
  } catch (error) {
380
+ if (error?.code === 'drop-confirmation') {
381
+ return res.status(409).json({ code: 'drop-confirmation', dropped: error.dropped, error: error.message });
382
+ }
349
383
  console.error('Failed to create agent');
350
384
  res.status(500).json({ error: error.message || 'Failed to create agent' });
351
385
  }
@@ -363,15 +397,14 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
363
397
  console.log('[Server] Updating agent');
364
398
 
365
399
  updateAgent(agentName, updates, directory);
366
- const refreshResult = await refreshOpenCodeAfterConfigChange('agent update');
367
400
 
368
401
  console.log('[Server] Agent updated successfully');
369
402
 
370
- res.json(buildConfigMutationResponse(refreshResult, {
371
- liveMessage: `Agent ${agentName} updated successfully. Reloading interface…`,
372
- manualRestartMessage: `Agent ${agentName} saved. Restart your connected OpenCode server to apply the change.`,
373
- }));
403
+ res.json(configSaved());
374
404
  } catch (error) {
405
+ if (error?.code === 'drop-confirmation') {
406
+ return res.status(409).json({ code: 'drop-confirmation', dropped: error.dropped, error: error.message });
407
+ }
375
408
  console.error('[Server] Failed to update agent');
376
409
  res.status(500).json({ error: error.message || 'Failed to update agent' });
377
410
  }
@@ -387,12 +420,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
387
420
 
388
421
  const scope = req.body?.scope;
389
422
  deleteAgent(agentName, directory, scope);
390
- const refreshResult = await refreshOpenCodeAfterConfigChange('agent deletion');
391
-
392
- res.json(buildConfigMutationResponse(refreshResult, {
393
- liveMessage: `Agent ${agentName} deleted successfully. Reloading interface…`,
394
- manualRestartMessage: `Agent ${agentName} deleted. Restart your connected OpenCode server to apply the change.`,
395
- }));
423
+ res.json(configSaved());
396
424
  } catch (error) {
397
425
  console.error('Failed to delete agent');
398
426
  res.status(500).json({ error: error.message || 'Failed to delete agent' });
@@ -500,14 +528,17 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
500
528
  if (!getOpenCodePort()) {
501
529
  return res.json({ commands: [] });
502
530
  }
503
- const client = createOpencodeClient({
531
+ const client = createOpenCodeClient({
504
532
  baseUrl: buildOpenCodeUrl('/', '').replace(/\/$/, ''),
505
- directory,
506
533
  headers: getOpenCodeAuthHeaders(),
507
534
  fetch: (request) => fetch(request, { signal: AbortSignal.timeout(8_000) }),
508
535
  });
509
- const response = await client.command.list({ directory });
510
- const commands = Array.isArray(response?.data) ? response.data : [];
536
+ const response = await client.command.list({ location: { directory } });
537
+ if (!Array.isArray(response?.data)) {
538
+ console.error('Command catalog upstream response failed');
539
+ return res.status(502).json({ error: 'Command catalog is unavailable' });
540
+ }
541
+ const commands = response.data;
511
542
  return res.json({
512
543
  commands: commands
513
544
  .filter((command) => command?.source !== 'skill')
@@ -598,16 +629,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
598
629
  console.log('[Server] Creating command');
599
630
 
600
631
  createCommand(commandName, config, directory, scope);
601
- await refreshOpenCodeAfterConfigChange('command creation', {
602
- commandName
603
- });
604
-
605
- res.json({
606
- success: true,
607
- requiresReload: true,
608
- message: `Command ${commandName} created successfully. Reloading interface…`,
609
- reloadDelayMs: clientReloadDelayMs,
610
- });
632
+ res.json(configSaved());
611
633
  } catch (error) {
612
634
  console.error('Failed to create command');
613
635
  res.status(500).json({ error: error.message || 'Failed to create command' });
@@ -626,16 +648,10 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
626
648
  console.log('[Server] Updating command');
627
649
 
628
650
  updateCommand(commandName, updates, directory);
629
- await refreshOpenCodeAfterConfigChange('command update');
630
651
 
631
652
  console.log('[Server] Command updated successfully');
632
653
 
633
- res.json({
634
- success: true,
635
- requiresReload: true,
636
- message: `Command ${commandName} updated successfully. Reloading interface…`,
637
- reloadDelayMs: clientReloadDelayMs,
638
- });
654
+ res.json(configSaved());
639
655
  } catch (error) {
640
656
  console.error('[Server] Failed to update command');
641
657
  res.status(500).json({ error: error.message || 'Failed to update command' });
@@ -651,14 +667,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
651
667
  }
652
668
 
653
669
  deleteCommand(commandName, directory);
654
- await refreshOpenCodeAfterConfigChange('command deletion');
655
-
656
- res.json({
657
- success: true,
658
- requiresReload: true,
659
- message: `Command ${commandName} deleted successfully. Reloading interface…`,
660
- reloadDelayMs: clientReloadDelayMs,
661
- });
670
+ res.json(configSaved());
662
671
  } catch (error) {
663
672
  console.error('Failed to delete command');
664
673
  res.status(500).json({ error: error.message || 'Failed to delete command' });