@openchambery/web 2.0.0-beta.1 → 2.0.0-beta.4

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 (287) hide show
  1. package/README.md +15 -11
  2. package/bin/cli-opencode.test.js +4 -4
  3. package/bin/cli.js +1 -1
  4. package/bin/lib/cli-startup.js +1 -1
  5. package/bin/lib/cli-startup.test.js +18 -4
  6. package/dist/assets/{AgentAvatar-CLWWNu_Q.js → AgentAvatar-Q1SmFRx2.js} +1 -1
  7. package/dist/assets/AssistantView-CwXkiCAd.js +3 -0
  8. package/dist/assets/{DiagramView-xuSJTnv7.js → DiagramView-BW92schO.js} +1 -1
  9. package/dist/assets/{FadeInOnReveal-Ov0D96d0.js → FadeInOnReveal-BZmwl-zE.js} +1 -1
  10. package/dist/assets/{Icon-DD-BuMfZ.js → Icon-AQPvxMiU.js} +1 -1
  11. package/dist/assets/{MarkdownRenderer-bc_p1H7l.js → MarkdownRenderer-Bv05iDZZ.js} +2 -2
  12. package/dist/assets/{MarkdownRendererImpl-SKi4oG0c.js → MarkdownRendererImpl-C81xqYib.js} +3 -3
  13. package/dist/assets/MarkstreamRendererImpl-CXUCQuKJ.js +3 -0
  14. package/dist/assets/{MobileDetailNavigation-Bnx59U_J.js → MobileDetailNavigation-BMgIu7zc.js} +1 -1
  15. package/dist/assets/{MobileShareBridge-BQlP4J-F.js → MobileShareBridge-BOXGNHmC.js} +2 -2
  16. package/dist/assets/MobileSurface-xuc_z0_G.js +2 -0
  17. package/dist/assets/{MultiRunWindow-ChZGob0v.js → MultiRunWindow-B5At2Z95.js} +1 -1
  18. package/dist/assets/{OnboardingScreen-DtQJxZG-.js → OnboardingScreen-bsPLgz4r.js} +1 -1
  19. package/dist/assets/OverlayScrollbar-4wp4migh.js +2 -0
  20. package/dist/assets/SettingsView-CJ6tcH5_.js +25 -0
  21. package/dist/assets/{SettingsWindow-DfnsFa8y.js → SettingsWindow-CMtX2bMl.js} +1 -1
  22. package/dist/assets/{TerminalView-Dh9MWCpS.js → TerminalView-Dvr-ysTS.js} +1 -1
  23. package/dist/assets/{ToolOutputDialog-BejmjrRk.js → ToolOutputDialog-uH1ZZDSS.js} +2 -2
  24. package/dist/assets/appThemeRegistry-DK7q2juD.js +1 -0
  25. package/dist/assets/{assistant-attachment-cache-C0aRnFkj.js → assistant-attachment-cache-DphJleHr.js} +1 -1
  26. package/dist/assets/{button-D-rATN7w.js → button-CcNJUxUd.js} +1 -1
  27. package/dist/assets/collapsible-ZmZ6rLWs.js +3 -0
  28. package/dist/assets/context-menu-B2LXJgXL.js +1 -0
  29. package/dist/assets/{desktopHosts-B1ixEylr.js → desktopHosts-C6HrP0jq.js} +1 -1
  30. package/dist/assets/{desktopRelayRestore-4JmFUw8r.js → desktopRelayRestore-DdVBp45U.js} +1 -1
  31. package/dist/assets/{diagram-DQf7Y_uR.js → diagram-CxTs9hCQ.js} +1 -1
  32. package/dist/assets/{dialog-bfbvR4VH.js → dialog-KMVL9QKF.js} +1 -1
  33. package/dist/assets/es-CN3E_zXj.js +15 -0
  34. package/dist/assets/{fileMentionTouchSelection-BvrNCroG.js → fileMentionTouchSelection-7RIwlpkB.js} +1 -1
  35. package/dist/assets/{fileQueries-DQc8EJUf.js → fileQueries-CjdBRy8y.js} +1 -1
  36. package/dist/assets/fr-9zZvQZD2.js +13 -0
  37. package/dist/assets/gitApi-yuWg9BN4.js +10 -0
  38. package/dist/assets/{imageSource-BlAJJUEI.js → imageSource-9vQBq3zp.js} +1 -1
  39. package/dist/assets/{input-8r6F_Fza.js → input-CrIvk3HZ.js} +1 -1
  40. package/dist/assets/insertionBoundaries-BiUCSkx-.js +1 -0
  41. package/dist/assets/ja-Dnjk_82N.js +15 -0
  42. package/dist/assets/ko-BxCEE99C.js +15 -0
  43. package/dist/assets/{main-CCE_4y5F.js → main-C9mIBo77.js} +2 -2
  44. package/dist/assets/main-DiL6w6KF.js +169 -0
  45. package/dist/assets/markdown-worker-bS5OgGO3.js +2 -0
  46. package/dist/assets/{markdownHeightCache-1Qo6y6IJ.js → markdownHeightCache-BmXVY_gc.js} +1 -1
  47. package/dist/assets/{markdownTheme-DOfGg-A7.js → markdownTheme-CKac3wKC.js} +1 -1
  48. package/dist/assets/mcpQueries-C7jknHV8.js +1 -0
  49. package/dist/assets/miniChat-CwtUaElU.js +2 -0
  50. package/dist/assets/mobile-DB-6--ws.js +2 -0
  51. package/dist/assets/multirun-TAsxFI8e.js +4 -0
  52. package/dist/assets/{persistence-Ce3AnpEr.js → persistence-56kq8Z4V.js} +2 -2
  53. package/dist/assets/pl-CNNsWnPM.js +15 -0
  54. package/dist/assets/platform-C13fMVEs.js +6 -0
  55. package/dist/assets/pt-BR-BZB2DJMp.js +15 -0
  56. package/dist/assets/{relay-image-stream-DM7atqJs.js → relay-image-stream-DrdVj99c.js} +1 -1
  57. package/dist/assets/renderElectronMiniChatApp-CGj0MNRU.js +2 -0
  58. package/dist/assets/renderMobileApp-CGMMqbsO.js +28 -0
  59. package/dist/assets/runtime-fetch-Fs9ZV2V8.js +1 -0
  60. package/dist/assets/{runtimeConfig-BMvqa5we.js → runtimeConfig-BEANkvOd.js} +1 -1
  61. package/dist/assets/runtimeEndpointReset-A_ZBUJFS.js +147 -0
  62. package/dist/assets/sessionChangeSummary-qOLrP9fw.js +2 -0
  63. package/dist/assets/{sessionLookup-gh-hVRIc.js → sessionLookup-34XFmP9C.js} +1 -1
  64. package/dist/assets/{sortable-tabs-strip-CudoSgV4.js → sortable-tabs-strip-DyEV0Heg.js} +1 -1
  65. package/dist/assets/src-ubCWXZhR.css +2 -0
  66. package/dist/assets/store-DLCiZaA6.js +15 -0
  67. package/dist/assets/{terminalApi-DiF6JmBP.js → terminalApi-CXaBEoa_.js} +1 -1
  68. package/dist/assets/textarea-BBOlRI9O.js +1 -0
  69. package/dist/assets/{tooltip-CQvpK-UV.js → tooltip-CPI4fr1a.js} +1 -1
  70. package/dist/assets/uk-rwQrxeYM.js +15 -0
  71. package/dist/assets/{url-_z7evzdK.js → url-DRDQXjyX.js} +1 -1
  72. package/dist/assets/{useAppFontEffects-Cpmpo7Wb.js → useAppFontEffects-CiDe42I5.js} +57 -43
  73. package/dist/assets/{useAssistantUIStore-CMutVh9B.js → useAssistantUIStore-asNG6K7n.js} +1 -1
  74. package/dist/assets/useDesktopWindowControlsLayout-BlizAlOt.js +1 -0
  75. package/dist/assets/useEffectiveDirectory-C_CouL5v.js +1 -0
  76. package/dist/assets/{useFontPreferences-DcbXQOkc.js → useFontPreferences-B0oUZAiB.js} +1 -1
  77. package/dist/assets/useMobileNavigationStore-DfPClaW-.js +414 -0
  78. package/dist/assets/{useRuntimeAPIs-DSLXJybW.js → useRuntimeAPIs-DwLtO0c_.js} +1 -1
  79. package/dist/assets/useSessionAutoCleanup-DtrfbxAp.js +2 -0
  80. package/dist/assets/{useThemeSystem-DMzWVJaW.js → useThemeSystem-BlNUWH47.js} +1 -1
  81. package/dist/assets/useUIStore-CQYKJnrg.js +1 -0
  82. package/dist/assets/{useWorkerHighlightedLines-Bqn4AiBL.js → useWorkerHighlightedLines-CPNYz6Wf.js} +2 -2
  83. package/dist/assets/{vendor-base-ui-CnHfUmDN.js → vendor-base-ui-CDjyofeD.js} +1 -1
  84. package/dist/assets/{vendor-cmdk-CeAGfrLo.js → vendor-cmdk-BFH0UpXX.js} +1 -1
  85. package/dist/assets/{vendor-dnd-kit-accessibility-BY5LhhUB.js → vendor-dnd-kit-accessibility-BrR3AKvM.js} +1 -1
  86. package/dist/assets/{vendor-dnd-kit-core-CvWxUPdb.js → vendor-dnd-kit-core-CNfdvk6H.js} +1 -1
  87. package/dist/assets/{vendor-dnd-kit-sortable-hHdP9lLb.js → vendor-dnd-kit-sortable-DQUaTeGj.js} +1 -1
  88. package/dist/assets/{vendor-framer-motion-DFy_BSVd.js → vendor-framer-motion-4dogsUk3.js} +1 -1
  89. package/dist/assets/{vendor-legendapp-list-WE32lwNk.js → vendor-legendapp-list-BU7MdPZR.js} +1 -1
  90. package/dist/assets/{vendor-markstream-react-DX55XLGO.js → vendor-markstream-react-qHC2FykU.js} +3 -3
  91. package/dist/assets/{vendor-pierre-diffs-DX7XTPG3.js → vendor-pierre-diffs-CUfqC003.js} +1 -1
  92. package/dist/assets/{vendor-react-DLPElpoQ.js → vendor-react-C94A0AHl.js} +1 -1
  93. package/dist/assets/{vendor-react-drawio-ECtEwvbc.js → vendor-react-drawio-FVlWqKVE.js} +1 -1
  94. package/dist/assets/{vendor-reactuses-core-BnW6GxJt.js → vendor-reactuses-core-C2A3EjUi.js} +1 -1
  95. package/dist/assets/{vendor-sonner-DVzioF3d.js → vendor-sonner-DNqHmUQs.js} +1 -1
  96. package/dist/assets/{vendor-stream-diffs-DWy3xSmp.js → vendor-stream-diffs-CwbKsmlv.js} +2 -2
  97. package/dist/assets/{vendor-tanstack-react-query-D7pys_c9.js → vendor-tanstack-react-query-D0iFK57C.js} +1 -1
  98. package/dist/assets/{vendor-tanstack-react-virtual-tlDgH6PG.js → vendor-tanstack-react-virtual-B2kV6cnT.js} +1 -1
  99. package/dist/assets/{vendor-zustand-B4dlGEM2.js → vendor-zustand-BqLKf6ZY.js} +1 -1
  100. package/dist/assets/zh-CN-BvmBDnkD.js +15 -0
  101. package/dist/assets/zh-TW-9wcHTX0y.js +15 -0
  102. package/dist/index.html +13 -13
  103. package/dist/mini-chat.html +13 -13
  104. package/dist/mobile.html +13 -13
  105. package/package.json +1 -1
  106. package/server/index.js +327 -62
  107. package/server/lib/assistants/DOCUMENTATION.md +14 -9
  108. package/server/lib/assistants/contracts.js +11 -1
  109. package/server/lib/assistants/projection-history.test.js +265 -18
  110. package/server/lib/assistants/routes.js +6 -0
  111. package/server/lib/assistants/service.js +417 -231
  112. package/server/lib/assistants/service.test.js +392 -148
  113. package/server/lib/conversations/DOCUMENTATION.md +1 -1
  114. package/server/lib/conversations/service.js +1 -0
  115. package/server/lib/conversations/service.test.js +16 -0
  116. package/server/lib/conversations/validation.js +11 -1
  117. package/server/lib/event-stream/DOCUMENTATION.md +3 -1
  118. package/server/lib/event-stream/directory-ws-bridge.js +13 -2
  119. package/server/lib/event-stream/global-hub.js +49 -4
  120. package/server/lib/event-stream/reasoning-projection.js +16 -1
  121. package/server/lib/event-stream/reasoning-projection.test.js +15 -0
  122. package/server/lib/event-stream/runtime.js +57 -20
  123. package/server/lib/event-stream/runtime.test.js +112 -0
  124. package/server/lib/llm/DOCUMENTATION.md +33 -9
  125. package/server/lib/llm/catalog.js +1 -1
  126. package/server/lib/llm/completions.js +5 -1
  127. package/server/lib/llm/completions.test.js +3 -3
  128. package/server/lib/llm/generate.js +237 -145
  129. package/server/lib/llm/generate.test.js +201 -46
  130. package/server/lib/llm/routes.js +2 -0
  131. package/server/lib/message-queue/runtime.js +15 -2
  132. package/server/lib/notifications/runtime.js +23 -5
  133. package/server/lib/notifications/runtime.test.js +11 -0
  134. package/server/lib/opencode/DOCUMENTATION.md +85 -17
  135. package/server/lib/opencode/agent-document.d.ts +28 -0
  136. package/server/lib/opencode/agent-document.js +280 -0
  137. package/server/lib/opencode/agent-document.test.js +137 -0
  138. package/server/lib/opencode/agents.js +96 -0
  139. package/server/lib/opencode/auth-state-runtime.js +5 -0
  140. package/server/lib/opencode/bootstrap-runtime.js +2 -0
  141. package/server/lib/opencode/config-entity-routes.js +42 -99
  142. package/server/lib/opencode/config-entity-routes.test.js +107 -0
  143. package/server/lib/opencode/config-hot-reload.integration.test.js +105 -0
  144. package/server/lib/opencode/ensure-cli.js +1 -2
  145. package/server/lib/opencode/env-runtime.js +40 -26
  146. package/server/lib/opencode/env-runtime.test.js +10 -17
  147. package/server/lib/opencode/feature-routes-runtime.js +43 -4
  148. package/server/lib/opencode/feature-routes-runtime.test.js +18 -0
  149. package/server/lib/opencode/http-server-connections.js +98 -0
  150. package/server/lib/opencode/http-server-connections.test.js +321 -0
  151. package/server/lib/opencode/lifecycle.js +349 -39
  152. package/server/lib/opencode/lifecycle.test.js +322 -0
  153. package/server/lib/opencode/managed-capabilities-runtime.js +15 -2
  154. package/server/lib/opencode/managed-capabilities-runtime.test.js +1 -0
  155. package/server/lib/opencode/openchamber-routes.js +7 -1
  156. package/server/lib/opencode/opencode2-pin.js +4 -4
  157. package/server/lib/opencode/opencode2-pin.test.js +1 -0
  158. package/server/lib/opencode/opencode2-sidecar.e2e.test.js +127 -4
  159. package/server/lib/opencode/owned-runtime-upgrade.js +431 -0
  160. package/server/lib/opencode/owned-runtime-upgrade.test.js +160 -0
  161. package/server/lib/opencode/plugin-routes.js +3 -18
  162. package/server/lib/opencode/plugin-routes.test.js +9 -9
  163. package/server/lib/opencode/provider-catalog.js +58 -12
  164. package/server/lib/opencode/provider-catalog.test.js +48 -0
  165. package/server/lib/opencode/proxy.js +252 -46
  166. package/server/lib/opencode/proxy.test.js +235 -2
  167. package/server/lib/opencode/routes.js +296 -62
  168. package/server/lib/opencode/routes.test.js +278 -12
  169. package/server/lib/opencode/runtime-contract.js +401 -0
  170. package/server/lib/opencode/runtime-contract.test.js +214 -0
  171. package/server/lib/opencode/server-opencode-fetch.js +242 -0
  172. package/server/lib/opencode/server-opencode-fetch.test.js +130 -0
  173. package/server/lib/opencode/server-utils-runtime.js +33 -0
  174. package/server/lib/opencode/shared-service.integration.test.js +66 -0
  175. package/server/lib/opencode/shared-service.js +147 -0
  176. package/server/lib/opencode/shared-service.test.js +93 -0
  177. package/server/lib/opencode/shared.js +3 -3
  178. package/server/lib/opencode/shutdown-runtime.js +15 -6
  179. package/server/lib/opencode/shutdown-runtime.test.js +49 -1
  180. package/server/lib/opencode/skill-routes.js +20 -33
  181. package/server/lib/opencode/skill-routes.test.js +35 -2
  182. package/server/lib/opencode/skills.test.js +15 -0
  183. package/server/lib/opencode/startup-pipeline-runtime.js +4 -0
  184. package/server/lib/opencode/static-routes-runtime.js +3 -1
  185. package/server/lib/opencode/static-routes-runtime.test.js +33 -0
  186. package/server/lib/opencode/v2-client.js +14 -3
  187. package/server/lib/opencode/v2-plugin-host-shim/index.mjs +155 -0
  188. package/server/lib/opencode/v2-plugin-host-shim/package.json +4 -0
  189. package/server/lib/permission-auto-accept/DOCUMENTATION.md +5 -5
  190. package/server/lib/permission-auto-accept/runtime.js +14 -7
  191. package/server/lib/permission-auto-accept/runtime.test.js +27 -12
  192. package/server/lib/relay/reasoning-projection.e2e.test.ts +22 -7
  193. package/server/lib/scheduled-tasks/DOCUMENTATION.md +8 -0
  194. package/server/lib/scheduled-tasks/runtime.js +52 -4
  195. package/server/lib/scheduled-tasks/runtime.test.js +80 -1
  196. package/server/lib/session-goal/DOCUMENTATION.md +113 -13
  197. package/server/lib/session-goal/routes.js +9 -0
  198. package/server/lib/session-goal/runtime.js +1579 -117
  199. package/server/lib/session-goal/runtime.test.js +1453 -84
  200. package/server/lib/session-index/DOCUMENTATION.md +18 -15
  201. package/server/lib/session-index/event-ingest.js +89 -16
  202. package/server/lib/session-index/event-ingest.test.js +73 -0
  203. package/server/lib/session-index/host-authority-snapshot.js +92 -0
  204. package/server/lib/session-index/routes.host-archive.test.js +201 -0
  205. package/server/lib/session-index/routes.js +63 -10
  206. package/server/lib/session-index/routes.test.js +8 -8
  207. package/server/lib/session-index/service.js +7 -1
  208. package/server/lib/session-index/sync-runtime.js +161 -34
  209. package/server/lib/session-index/sync-runtime.test.js +155 -1
  210. package/server/lib/session-metadata/DOCUMENTATION.md +61 -16
  211. package/server/lib/session-metadata/routes.js +108 -9
  212. package/server/lib/session-metadata/routes.test.js +47 -2
  213. package/server/lib/session-metadata/session-archive.d.ts +73 -0
  214. package/server/lib/session-metadata/session-archive.js +654 -0
  215. package/server/lib/session-metadata/session-archive.test.js +359 -0
  216. package/server/lib/session-metadata/session-metadata-store.d.ts +36 -0
  217. package/server/lib/session-metadata/session-metadata-store.js +212 -72
  218. package/server/lib/session-metadata/session-metadata-store.test.js +205 -10
  219. package/server/lib/session-metadata/session-projection.d.ts +41 -0
  220. package/server/lib/session-metadata/session-projection.js +255 -0
  221. package/server/lib/session-metadata/session-projection.test.js +64 -0
  222. package/server/lib/session-metadata/system-session.js +55 -0
  223. package/server/lib/session-metadata/system-session.test.js +55 -0
  224. package/server/lib/session-title/DOCUMENTATION.md +40 -7
  225. package/server/lib/session-title/native-runtime.test.js +167 -0
  226. package/server/lib/session-title/runtime.js +67 -42
  227. package/server/lib/session-title/session-access.js +46 -0
  228. package/server/lib/session-title/session-access.test.js +91 -0
  229. package/server/lib/session-turn-pages/DOCUMENTATION.md +9 -8
  230. package/server/lib/session-turn-pages/routes.js +17 -102
  231. package/server/lib/session-turn-pages/routes.test.js +281 -0
  232. package/server/lib/session-turn-pages/session-message-projection.d.ts +13 -0
  233. package/server/lib/session-turn-pages/session-message-projection.js +281 -0
  234. package/server/lib/small-model/DOCUMENTATION.md +101 -147
  235. package/server/lib/small-model/catalog.js +31 -51
  236. package/server/lib/small-model/catalog.test.js +65 -10
  237. package/server/lib/small-model/custom-api.js +68 -0
  238. package/server/lib/small-model/custom-api.test.js +64 -0
  239. package/server/lib/small-model/index.js +124 -240
  240. package/server/lib/small-model/resolve.js +35 -120
  241. package/server/lib/small-model/resolve.test.js +20 -110
  242. package/server/lib/small-model/routes.js +1 -3
  243. package/server/lib/small-model/summary-settings.test.js +157 -253
  244. package/server/opencode-proxy.test.js +2 -0
  245. package/dist/assets/AssistantView-BTCkm8yk.js +0 -3
  246. package/dist/assets/MarkstreamRendererImpl-CnkodGJW.js +0 -3
  247. package/dist/assets/MobileSurface-BXLeiZ4d.js +0 -2
  248. package/dist/assets/OverlayScrollbar-pMwxaCca.js +0 -2
  249. package/dist/assets/SettingsView-B5I0KDTZ.js +0 -25
  250. package/dist/assets/appThemeRegistry-COGfxTFV.js +0 -1
  251. package/dist/assets/collapsible-BXRd5_Hr.js +0 -1
  252. package/dist/assets/context-menu-jGtH6fR9.js +0 -1
  253. package/dist/assets/es-c52LTHHe.js +0 -15
  254. package/dist/assets/fr-PisFbUE8.js +0 -13
  255. package/dist/assets/gitApi-ButwzQ0N.js +0 -9
  256. package/dist/assets/insertionBoundaries-DGs7S5zv.js +0 -1
  257. package/dist/assets/ja-C8Ikun3Z.js +0 -15
  258. package/dist/assets/ko-ClFys5o2.js +0 -15
  259. package/dist/assets/main-Dn9rpsgl.js +0 -169
  260. package/dist/assets/markdown-worker-CptoICmq.js +0 -2
  261. package/dist/assets/miniChat-BpjxVqgg.js +0 -2
  262. package/dist/assets/mobile-nMJCaNq1.js +0 -2
  263. package/dist/assets/multirun-BvSG94mW.js +0 -4
  264. package/dist/assets/pl-CnaKWN5F.js +0 -15
  265. package/dist/assets/platform-CWTIp02q.js +0 -4
  266. package/dist/assets/projectMeta-DOe49dM_.js +0 -3
  267. package/dist/assets/pt-BR-s8OpfRI6.js +0 -15
  268. package/dist/assets/renderElectronMiniChatApp-R6dKh79f.js +0 -2
  269. package/dist/assets/renderMobileApp-y-S8y8v_.js +0 -28
  270. package/dist/assets/runtime-fetch-zIalUnbb.js +0 -1
  271. package/dist/assets/runtimeEndpointReset-B6BxhvR0.js +0 -147
  272. package/dist/assets/sessionChangeSummary-VVBlEXuh.js +0 -2
  273. package/dist/assets/src-BzX5UI-c.css +0 -2
  274. package/dist/assets/store-DJczmczv.js +0 -15
  275. package/dist/assets/textarea-3XR8sUfy.js +0 -1
  276. package/dist/assets/uk-CaX0iqkB.js +0 -15
  277. package/dist/assets/useDesktopWindowControlsLayout-B1GX59-L.js +0 -1
  278. package/dist/assets/useEffectiveDirectory-CN6JoCFw.js +0 -1
  279. package/dist/assets/useMobileNavigationStore-BVjFtXSy.js +0 -414
  280. package/dist/assets/useSessionAutoCleanup-BLjymaFt.js +0 -2
  281. package/dist/assets/useUIStore-Bxv3f23A.js +0 -1
  282. package/dist/assets/zh-CN-20MYEjha.js +0 -15
  283. package/dist/assets/zh-TW-DiN04qTw.js +0 -15
  284. package/server/lib/small-model/call.js +0 -427
  285. package/server/lib/small-model/call.test.js +0 -382
  286. package/server/lib/small-model/opencode-session.js +0 -183
  287. package/server/lib/small-model/opencode-session.test.js +0 -147
@@ -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
  });
@@ -14,9 +14,11 @@ const composeV2ProviderCatalogSource = (providers, models, defaultModel) => {
14
14
  for (const model of models) {
15
15
  if (!model || typeof model !== 'object') continue;
16
16
  const providerID = typeof model.providerID === 'string' ? model.providerID : '';
17
- const modelID = typeof model.modelID === 'string' && model.modelID
18
- ? model.modelID
19
- : (typeof model.id === 'string' ? model.id : '');
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 : '');
20
22
  if (!providerID || !modelID) continue;
21
23
  if (!modelsByProvider.has(providerID)) modelsByProvider.set(providerID, Object.create(null));
22
24
  const entry = { id: modelID };
@@ -24,10 +26,9 @@ const composeV2ProviderCatalogSource = (providers, models, defaultModel) => {
24
26
  if (typeof model.family === 'string' && model.family) entry.family = model.family;
25
27
  if (model.limit && typeof model.limit === 'object') entry.limit = model.limit;
26
28
  if (model.capabilities) entry.capabilities = model.capabilities;
27
- if (model.cost && typeof model.cost === 'object' && !Array.isArray(model.cost)) entry.cost = model.cost;
28
- if (model.variants && typeof model.variants === 'object' && !Array.isArray(model.variants)) {
29
- entry.variants = model.variants;
30
- }
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;
31
32
  if (typeof model.time?.released === 'number' && Number.isFinite(model.time.released)) {
32
33
  entry.release_date = new Date(model.time.released).toISOString().slice(0, 10);
33
34
  }
@@ -45,8 +46,11 @@ const composeV2ProviderCatalogSource = (providers, models, defaultModel) => {
45
46
  }
46
47
 
47
48
  const defaults = Object.create(null);
48
- if (defaultModel && typeof defaultModel.providerID === 'string' && typeof defaultModel.modelID === 'string') {
49
- defaults[defaultModel.providerID] = defaultModel.modelID;
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;
50
54
  }
51
55
  return { providers: list, default: defaults };
52
56
  };
@@ -130,11 +134,10 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
130
134
  const {
131
135
  resolveProjectDirectory,
132
136
  resolveOptionalProjectDirectory,
133
- refreshOpenCodeAfterConfigChange,
134
- clientReloadDelayMs,
135
137
  waitForOpenCodeReady,
136
138
  getAgentSources,
137
139
  getAgentConfig,
140
+ listDisabledAgentOverrides,
138
141
  createAgent,
139
142
  updateAgent,
140
143
  deleteAgent,
@@ -259,7 +262,8 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
259
262
  target: req.params.target,
260
263
  fileName: target.fileName,
261
264
  content,
262
- requiresManualRestart: true,
265
+ requiresManualRestart: req.params.target !== 'opencode',
266
+ application: req.params.target === 'opencode' ? 'watch' : 'manual',
263
267
  });
264
268
  } catch (error) {
265
269
  console.error('Failed to write global configuration:', error);
@@ -267,29 +271,9 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
267
271
  }
268
272
  });
269
273
 
270
- // Build the response for a config mutation based on whether OpenCode actually
271
- // reloaded the change. When connected to an external OpenCode server that
272
- // OpenChamber cannot restart, the change is persisted to disk but the running
273
- // server will not serve it until the user restarts that server. We must not
274
- // report a clean "reloading" success in that case, otherwise the UI silently
275
- // reverts the edit to the stale value on the next refresh.
276
- const buildConfigMutationResponse = (refreshResult, { liveMessage, manualRestartMessage }) => {
277
- if (refreshResult && refreshResult.external) {
278
- return {
279
- success: true,
280
- requiresReload: false,
281
- requiresManualRestart: true,
282
- message: manualRestartMessage,
283
- };
284
- }
285
-
286
- return {
287
- success: true,
288
- requiresReload: true,
289
- message: liveMessage,
290
- reloadDelayMs: clientReloadDelayMs,
291
- };
292
- };
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' });
293
277
 
294
278
  const readMutationBody = (req) => (
295
279
  req.body && typeof req.body === 'object' && !Array.isArray(req.body) ? req.body : {}
@@ -298,24 +282,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
298
282
  const completeMcpMutation = async (res, action, name, applyChange) => {
299
283
  applyChange();
300
284
 
301
- try {
302
- await refreshOpenCodeAfterConfigChange(`mcp ${action}`);
303
- return res.json({
304
- success: true,
305
- requiresReload: true,
306
- message: `MCP server "${name}" ${action}d. Reloading interface…`,
307
- reloadDelayMs: clientReloadDelayMs,
308
- });
309
- } catch (error) {
310
- console.error(`[API:MCP ${action}] Reload failed after config write:`, error);
311
- return res.json({
312
- success: true,
313
- requiresReload: false,
314
- reloadFailed: true,
315
- message: `MCP server "${name}" ${action}d, but OpenCode reload failed.`,
316
- warning: error.message || 'OpenCode reload failed after the MCP configuration changed',
317
- });
318
- }
285
+ return res.json({ ...configSaved(), message: `MCP server "${name}" ${action}d.` });
319
286
  };
320
287
 
321
288
  app.post('/api/config/agents/metadata', async (req, res) => {
@@ -345,7 +312,10 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
345
312
  sources,
346
313
  };
347
314
  }
348
- return res.json({ agents });
315
+ const disabled = typeof listDisabledAgentOverrides === 'function'
316
+ ? listDisabledAgentOverrides(directory)
317
+ : [];
318
+ return res.json(disabled.length > 0 ? { agents, disabled } : { agents });
349
319
  } catch (error) {
350
320
  console.error('Failed to get agent metadata batch:', error);
351
321
  return res.status(500).json({ error: 'Failed to get agent configuration metadata' });
@@ -405,15 +375,11 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
405
375
  console.log('[Server] Creating agent');
406
376
 
407
377
  createAgent(agentName, config, directory, scope);
408
- const refreshResult = await refreshOpenCodeAfterConfigChange('agent creation', {
409
- agentName
410
- });
411
-
412
- res.json(buildConfigMutationResponse(refreshResult, {
413
- liveMessage: `Agent ${agentName} created successfully. Reloading interface…`,
414
- manualRestartMessage: `Agent ${agentName} saved. Restart your connected OpenCode server to apply the change.`,
415
- }));
378
+ res.json(configSaved());
416
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
+ }
417
383
  console.error('Failed to create agent');
418
384
  res.status(500).json({ error: error.message || 'Failed to create agent' });
419
385
  }
@@ -431,15 +397,14 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
431
397
  console.log('[Server] Updating agent');
432
398
 
433
399
  updateAgent(agentName, updates, directory);
434
- const refreshResult = await refreshOpenCodeAfterConfigChange('agent update');
435
400
 
436
401
  console.log('[Server] Agent updated successfully');
437
402
 
438
- res.json(buildConfigMutationResponse(refreshResult, {
439
- liveMessage: `Agent ${agentName} updated successfully. Reloading interface…`,
440
- manualRestartMessage: `Agent ${agentName} saved. Restart your connected OpenCode server to apply the change.`,
441
- }));
403
+ res.json(configSaved());
442
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
+ }
443
408
  console.error('[Server] Failed to update agent');
444
409
  res.status(500).json({ error: error.message || 'Failed to update agent' });
445
410
  }
@@ -455,12 +420,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
455
420
 
456
421
  const scope = req.body?.scope;
457
422
  deleteAgent(agentName, directory, scope);
458
- const refreshResult = await refreshOpenCodeAfterConfigChange('agent deletion');
459
-
460
- res.json(buildConfigMutationResponse(refreshResult, {
461
- liveMessage: `Agent ${agentName} deleted successfully. Reloading interface…`,
462
- manualRestartMessage: `Agent ${agentName} deleted. Restart your connected OpenCode server to apply the change.`,
463
- }));
423
+ res.json(configSaved());
464
424
  } catch (error) {
465
425
  console.error('Failed to delete agent');
466
426
  res.status(500).json({ error: error.message || 'Failed to delete agent' });
@@ -571,7 +531,12 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
571
531
  const client = createOpenCodeClient({
572
532
  baseUrl: buildOpenCodeUrl('/', '').replace(/\/$/, ''),
573
533
  headers: getOpenCodeAuthHeaders(),
574
- fetch: (request) => fetch(request, { signal: AbortSignal.timeout(8_000) }),
534
+ fetch: (request, init) => fetch(request, {
535
+ ...init,
536
+ signal: init?.signal
537
+ ? AbortSignal.any([init.signal, AbortSignal.timeout(8_000)])
538
+ : AbortSignal.timeout(8_000),
539
+ }),
575
540
  });
576
541
  const response = await client.command.list({ location: { directory } });
577
542
  if (!Array.isArray(response?.data)) {
@@ -669,16 +634,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
669
634
  console.log('[Server] Creating command');
670
635
 
671
636
  createCommand(commandName, config, directory, scope);
672
- await refreshOpenCodeAfterConfigChange('command creation', {
673
- commandName
674
- });
675
-
676
- res.json({
677
- success: true,
678
- requiresReload: true,
679
- message: `Command ${commandName} created successfully. Reloading interface…`,
680
- reloadDelayMs: clientReloadDelayMs,
681
- });
637
+ res.json(configSaved());
682
638
  } catch (error) {
683
639
  console.error('Failed to create command');
684
640
  res.status(500).json({ error: error.message || 'Failed to create command' });
@@ -697,16 +653,10 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
697
653
  console.log('[Server] Updating command');
698
654
 
699
655
  updateCommand(commandName, updates, directory);
700
- await refreshOpenCodeAfterConfigChange('command update');
701
656
 
702
657
  console.log('[Server] Command updated successfully');
703
658
 
704
- res.json({
705
- success: true,
706
- requiresReload: true,
707
- message: `Command ${commandName} updated successfully. Reloading interface…`,
708
- reloadDelayMs: clientReloadDelayMs,
709
- });
659
+ res.json(configSaved());
710
660
  } catch (error) {
711
661
  console.error('[Server] Failed to update command');
712
662
  res.status(500).json({ error: error.message || 'Failed to update command' });
@@ -722,14 +672,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
722
672
  }
723
673
 
724
674
  deleteCommand(commandName, directory);
725
- await refreshOpenCodeAfterConfigChange('command deletion');
726
-
727
- res.json({
728
- success: true,
729
- requiresReload: true,
730
- message: `Command ${commandName} deleted successfully. Reloading interface…`,
731
- reloadDelayMs: clientReloadDelayMs,
732
- });
675
+ res.json(configSaved());
733
676
  } catch (error) {
734
677
  console.error('Failed to delete command');
735
678
  res.status(500).json({ error: error.message || 'Failed to delete command' });