@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.
- package/README.md +13 -7
- package/bin/cli-opencode.test.js +208 -0
- package/bin/cli.js +62 -9
- package/bin/lib/cli-startup.js +105 -2
- package/bin/lib/cli-startup.test.js +179 -0
- package/dist/assets/{AgentAvatar-CRaBJXKs.js → AgentAvatar-B_JQoreg.js} +1 -1
- package/dist/assets/AssistantView-ClQAfGOT.js +3 -0
- package/dist/assets/{DiagramView-D1LGK_s2.js → DiagramView-BNnda8qO.js} +1 -1
- package/dist/assets/{FadeInOnReveal-B0kJo9Ii.js → FadeInOnReveal-VYQTSAkr.js} +1 -1
- package/dist/assets/{Icon-BgdfPhNs.js → Icon-BiEQEcih.js} +1 -1
- package/dist/assets/MarkdownRenderer-CJHSsWin.js +2 -0
- package/dist/assets/{MarkdownRendererImpl-DfoCJ1Mq.js → MarkdownRendererImpl-DwrHFGUp.js} +3 -3
- package/dist/assets/{MarkstreamRendererImpl-D2dsW5Lg.js → MarkstreamRendererImpl-CSnbQMu3.js} +1 -1
- package/dist/assets/MobileDetailNavigation-BXr6AGLT.js +1 -0
- package/dist/assets/{MobileShareBridge-2Yjn6wXg.js → MobileShareBridge-D7OE9OP_.js} +2 -2
- package/dist/assets/MobileSurface-D2jUkX9l.js +2 -0
- package/dist/assets/{MultiRunWindow-tTbMFowS.js → MultiRunWindow-DF3iIFCd.js} +1 -1
- package/dist/assets/{OnboardingScreen-CD2KtlF3.js → OnboardingScreen-BjHmlwlw.js} +1 -1
- package/dist/assets/OverlayScrollbar-DLtWO_Gp.js +2 -0
- package/dist/assets/SettingsView-BRxELjow.js +25 -0
- package/dist/assets/{SettingsWindow-zIa76s4t.js → SettingsWindow-BI5swspb.js} +1 -1
- package/dist/assets/{TerminalView-CDdzF4yi.js → TerminalView-BU3x8-fr.js} +1 -1
- package/dist/assets/{ToolOutputDialog-DNqA4uBl.js → ToolOutputDialog-BEWhBcRd.js} +2 -2
- package/dist/assets/appThemeRegistry-4MR0F7Jz.js +1 -0
- package/dist/assets/{button-CI7Q-Zw_.js → button-DKuz3L8l.js} +1 -1
- package/dist/assets/collapsible-DXbDynN4.js +3 -0
- package/dist/assets/context-menu-CqolsLCm.js +1 -0
- package/dist/assets/{desktopHosts-B1ixEylr.js → desktopHosts-CoDkOnyS.js} +1 -1
- package/dist/assets/{desktopRelayRestore-4JmFUw8r.js → desktopRelayRestore-DDlVKyOE.js} +1 -1
- package/dist/assets/{diagram-DdLO8HZ9.js → diagram-D7T8HQgj.js} +1 -1
- package/dist/assets/{dialog-B6pnIYmp.js → dialog-DQYl3W_o.js} +1 -1
- package/dist/assets/es-CN3E_zXj.js +15 -0
- package/dist/assets/{fileMentionTouchSelection-DNeiqns-.js → fileMentionTouchSelection-BZ6ovBYH.js} +1 -1
- package/dist/assets/{fileQueries-DQc8EJUf.js → fileQueries-JrpcsOCs.js} +1 -1
- package/dist/assets/fr-9zZvQZD2.js +13 -0
- package/dist/assets/gitApi-CM42qUed.js +10 -0
- package/dist/assets/{imageSource-BlAJJUEI.js → imageSource-CIl0FL10.js} +1 -1
- package/dist/assets/{input-D-__fwRi.js → input-CzQy8UhV.js} +1 -1
- package/dist/assets/insertionBoundaries-CtkZ9720.js +1 -0
- package/dist/assets/ja-Dnjk_82N.js +15 -0
- package/dist/assets/ko-BxCEE99C.js +15 -0
- package/dist/assets/main-BILgBI3B.js +169 -0
- package/dist/assets/main-BeveiW6F.js +2 -0
- package/dist/assets/markdown-worker-bS5OgGO3.js +2 -0
- package/dist/assets/{markdownHeightCache-BhxqJOvf.js → markdownHeightCache-Cj1I5NDw.js} +1 -1
- package/dist/assets/{markdownTheme-DOfGg-A7.js → markdownTheme-CKac3wKC.js} +1 -1
- package/dist/assets/mcpQueries-D5mQymgM.js +1 -0
- package/dist/assets/miniChat-BgrzM3u7.js +2 -0
- package/dist/assets/mobile-DtYoQE8C.js +2 -0
- package/dist/assets/multirun-jy8dEI96.js +4 -0
- package/dist/assets/{persistence-Ce3AnpEr.js → persistence-C9LQpiOS.js} +2 -2
- package/dist/assets/pl-CNNsWnPM.js +15 -0
- package/dist/assets/platform-BQghHRfp.js +6 -0
- package/dist/assets/pt-BR-BZB2DJMp.js +15 -0
- package/dist/assets/renderElectronMiniChatApp-BGrrmeME.js +2 -0
- package/dist/assets/renderMobileApp-u3c4GtFC.js +28 -0
- package/dist/assets/{runtimeConfig-CMkwoQ_X.js → runtimeConfig-BIGBRGQI.js} +1 -1
- package/dist/assets/{runtimeEndpointReset-ChOxt-J7.js → runtimeEndpointReset-D2savkuw.js} +12 -12
- package/dist/assets/{sessionChangeSummary-NnxcqCTI.js → sessionChangeSummary-eIbpSfrO.js} +1 -1
- package/dist/assets/{sessionLookup-BrU3rFHJ.js → sessionLookup-myHe5ltu.js} +1 -1
- package/dist/assets/{sortable-tabs-strip-Fnfhf3K9.js → sortable-tabs-strip-BQtmHx9r.js} +1 -1
- package/dist/assets/src-CLN7Z-zx.css +2 -0
- package/dist/assets/store-DLCiZaA6.js +15 -0
- package/dist/assets/{terminalApi-xjqssKke.js → terminalApi-BxcdiduX.js} +1 -1
- package/dist/assets/{textarea-bHYxZtfH.js → textarea-CakKvqFw.js} +1 -1
- package/dist/assets/{tooltip-0T5jv0cu.js → tooltip-Cx5gTbdY.js} +1 -1
- package/dist/assets/uk-rwQrxeYM.js +15 -0
- package/dist/assets/{url-_z7evzdK.js → url-CDHnjlsm.js} +1 -1
- package/dist/assets/{useAppFontEffects-C02YFyAv.js → useAppFontEffects-CNeo0aZs.js} +59 -45
- package/dist/assets/{useAssistantUIStore-CMutVh9B.js → useAssistantUIStore-asNG6K7n.js} +1 -1
- package/dist/assets/useDesktopWindowControlsLayout-DBJ56qIo.js +1 -0
- package/dist/assets/useEffectiveDirectory-B4LvR8Gt.js +1 -0
- package/dist/assets/{useFontPreferences-B1JYyzpK.js → useFontPreferences-CUnQ4TVm.js} +1 -1
- package/dist/assets/useMobileNavigationStore-ZHJPxlHt.js +414 -0
- package/dist/assets/{useRuntimeAPIs-DSLXJybW.js → useRuntimeAPIs-DwLtO0c_.js} +1 -1
- package/dist/assets/useSessionAutoCleanup-BIVmrnYU.js +2 -0
- package/dist/assets/{useThemeSystem-DMzWVJaW.js → useThemeSystem-BlNUWH47.js} +1 -1
- package/dist/assets/useUIStore-CQYKJnrg.js +1 -0
- package/dist/assets/{useWorkerHighlightedLines-C9z0ML1z.js → useWorkerHighlightedLines-CJZbJDW3.js} +2 -2
- package/dist/assets/{vendor-base-ui-CnHfUmDN.js → vendor-base-ui-CDjyofeD.js} +1 -1
- package/dist/assets/{vendor-cmdk-CeAGfrLo.js → vendor-cmdk-BFH0UpXX.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-accessibility-BY5LhhUB.js → vendor-dnd-kit-accessibility-BrR3AKvM.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-core-CvWxUPdb.js → vendor-dnd-kit-core-CNfdvk6H.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-sortable-hHdP9lLb.js → vendor-dnd-kit-sortable-DQUaTeGj.js} +1 -1
- package/dist/assets/{vendor-framer-motion-DFy_BSVd.js → vendor-framer-motion-4dogsUk3.js} +1 -1
- package/dist/assets/{vendor-legendapp-list-WE32lwNk.js → vendor-legendapp-list-BU7MdPZR.js} +1 -1
- package/dist/assets/{vendor-markstream-react-DX55XLGO.js → vendor-markstream-react-qHC2FykU.js} +3 -3
- package/dist/assets/vendor-opencode-client-BOe2qpQb.js +12 -0
- package/dist/assets/{vendor-pierre-diffs-DX7XTPG3.js → vendor-pierre-diffs-CUfqC003.js} +1 -1
- package/dist/assets/{vendor-react-DLPElpoQ.js → vendor-react-C94A0AHl.js} +1 -1
- package/dist/assets/{vendor-react-drawio-ECtEwvbc.js → vendor-react-drawio-FVlWqKVE.js} +1 -1
- package/dist/assets/{vendor-reactuses-core-BnW6GxJt.js → vendor-reactuses-core-C2A3EjUi.js} +1 -1
- package/dist/assets/{vendor-sonner-DVzioF3d.js → vendor-sonner-DNqHmUQs.js} +1 -1
- package/dist/assets/{vendor-stream-diffs-DWy3xSmp.js → vendor-stream-diffs-CwbKsmlv.js} +2 -2
- package/dist/assets/{vendor-tanstack-react-query-D7pys_c9.js → vendor-tanstack-react-query-D0iFK57C.js} +1 -1
- package/dist/assets/{vendor-tanstack-react-virtual-tlDgH6PG.js → vendor-tanstack-react-virtual-B2kV6cnT.js} +1 -1
- package/dist/assets/{vendor-yaml-DIcAK3EC.js → vendor-yaml-C9KlJAlj.js} +37 -37
- package/dist/assets/{vendor-zustand-B4dlGEM2.js → vendor-zustand-BqLKf6ZY.js} +1 -1
- package/dist/assets/zh-CN-BvmBDnkD.js +15 -0
- package/dist/assets/zh-TW-9wcHTX0y.js +15 -0
- package/dist/index.html +13 -13
- package/dist/mini-chat.html +13 -13
- package/dist/mobile.html +13 -13
- package/package.json +2 -2
- package/server/index.js +392 -20
- package/server/lib/assistants/DOCUMENTATION.md +26 -21
- package/server/lib/assistants/assign.js +2 -1
- package/server/lib/assistants/contact-store.js +37 -19
- package/server/lib/assistants/contracts.js +11 -1
- package/server/lib/assistants/projection-history.test.js +454 -0
- package/server/lib/assistants/routes.js +11 -5
- package/server/lib/assistants/service.js +850 -294
- package/server/lib/assistants/service.test.js +588 -274
- package/server/lib/conversations/DOCUMENTATION.md +5 -5
- package/server/lib/conversations/service.js +87 -57
- package/server/lib/conversations/service.test.js +132 -100
- package/server/lib/conversations/validation.js +11 -1
- package/server/lib/event-stream/directory-ws-bridge.js +13 -2
- package/server/lib/event-stream/global-hub.js +51 -5
- package/server/lib/event-stream/runtime.js +57 -20
- package/server/lib/event-stream/runtime.test.js +112 -0
- package/server/lib/llm/DOCUMENTATION.md +95 -84
- package/server/lib/llm/catalog.js +111 -45
- package/server/lib/llm/catalog.test.js +121 -59
- package/server/lib/llm/completions.js +41 -12
- package/server/lib/llm/completions.test.js +45 -4
- package/server/lib/llm/generate.js +516 -453
- package/server/lib/llm/generate.test.js +705 -484
- package/server/lib/llm/routes.js +8 -4
- package/server/lib/message-queue/DOCUMENTATION.md +5 -5
- package/server/lib/message-queue/opencode-adapter.js +191 -104
- package/server/lib/message-queue/opencode-adapter.test.js +328 -58
- package/server/lib/message-queue/runtime.js +15 -2
- package/server/lib/message-queue/runtime.test.js +6 -6
- package/server/lib/message-queue/worker.js +7 -1
- package/server/lib/notifications/runtime.js +5 -0
- package/server/lib/opencode/DOCUMENTATION.md +103 -16
- package/server/lib/opencode/agent-document.d.ts +28 -0
- package/server/lib/opencode/agent-document.js +280 -0
- package/server/lib/opencode/agent-document.test.js +137 -0
- package/server/lib/opencode/agents.js +96 -0
- package/server/lib/opencode/auth-state-runtime.js +5 -0
- package/server/lib/opencode/bootstrap-runtime.js +2 -0
- package/server/lib/opencode/config-entity-routes.js +111 -102
- package/server/lib/opencode/config-entity-routes.test.js +123 -10
- package/server/lib/opencode/config-hot-reload.integration.test.js +105 -0
- package/server/lib/opencode/ensure-cli.js +238 -0
- package/server/lib/opencode/ensure-cli.test.js +119 -0
- package/server/lib/opencode/env-runtime.js +208 -111
- package/server/lib/opencode/env-runtime.test.js +211 -14
- package/server/lib/opencode/feature-routes-runtime.js +80 -5
- package/server/lib/opencode/feature-routes-runtime.test.js +18 -0
- package/server/lib/opencode/http-server-connections.js +98 -0
- package/server/lib/opencode/http-server-connections.test.js +321 -0
- package/server/lib/opencode/lifecycle.js +539 -95
- package/server/lib/opencode/lifecycle.test.js +698 -6
- package/server/lib/opencode/managed-capabilities-runtime.js +15 -2
- package/server/lib/opencode/managed-capabilities-runtime.test.js +1 -0
- package/server/lib/opencode/network-runtime.js +28 -16
- package/server/lib/opencode/network-runtime.test.js +68 -4
- package/server/lib/opencode/openchamber-routes.js +7 -1
- package/server/lib/opencode/opencode2-pin.js +139 -0
- package/server/lib/opencode/opencode2-pin.test.js +88 -0
- package/server/lib/opencode/opencode2-sidecar.e2e.test.js +326 -0
- package/server/lib/opencode/owned-runtime-upgrade.js +431 -0
- package/server/lib/opencode/owned-runtime-upgrade.test.js +160 -0
- package/server/lib/opencode/plugin-compatibility.js +15 -0
- package/server/lib/opencode/plugin-compatibility.test.js +21 -0
- package/server/lib/opencode/plugin-routes.js +3 -18
- package/server/lib/opencode/plugin-routes.test.js +9 -9
- package/server/lib/opencode/plugins.js +4 -3
- package/server/lib/opencode/plugins.test.js +12 -0
- package/server/lib/opencode/provider-catalog.js +58 -12
- package/server/lib/opencode/provider-catalog.test.js +48 -0
- package/server/lib/opencode/proxy.js +368 -28
- package/server/lib/opencode/proxy.test.js +338 -0
- package/server/lib/opencode/routes.js +303 -76
- package/server/lib/opencode/routes.test.js +315 -50
- package/server/lib/opencode/runtime-contract.js +401 -0
- package/server/lib/opencode/runtime-contract.test.js +214 -0
- package/server/lib/opencode/server-opencode-fetch.js +242 -0
- package/server/lib/opencode/server-opencode-fetch.test.js +130 -0
- package/server/lib/opencode/server-utils-runtime.js +35 -0
- package/server/lib/opencode/shared-service.integration.test.js +66 -0
- package/server/lib/opencode/shared-service.js +147 -0
- package/server/lib/opencode/shared-service.test.js +93 -0
- package/server/lib/opencode/shared.js +3 -3
- package/server/lib/opencode/shutdown-runtime.js +15 -6
- package/server/lib/opencode/shutdown-runtime.test.js +49 -1
- package/server/lib/opencode/skill-routes.js +26 -40
- package/server/lib/opencode/skill-routes.test.js +71 -7
- package/server/lib/opencode/skills.test.js +15 -0
- package/server/lib/opencode/startup-pipeline-runtime.js +4 -0
- package/server/lib/opencode/static-routes-runtime.js +3 -1
- package/server/lib/opencode/static-routes-runtime.test.js +33 -0
- package/server/lib/opencode/v1-migration-gate.js +157 -0
- package/server/lib/opencode/v1-migration-gate.test.js +111 -0
- package/server/lib/opencode/v2-client.js +60 -0
- package/server/lib/opencode/v2-plugin-host-shim/index.mjs +155 -0
- package/server/lib/opencode/v2-plugin-host-shim/package.json +4 -0
- package/server/lib/opencode/watcher.js +2 -1
- package/server/lib/opencode/watcher.test.js +1 -1
- package/server/lib/permission-auto-accept/DOCUMENTATION.md +5 -5
- package/server/lib/permission-auto-accept/runtime.js +14 -7
- package/server/lib/permission-auto-accept/runtime.test.js +27 -12
- package/server/lib/relay/reasoning-projection.e2e.test.ts +22 -7
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +79 -39
- package/server/lib/scheduled-tasks/managed-tool-route.js +31 -1
- package/server/lib/scheduled-tasks/managed-tool-route.test.js +23 -0
- package/server/lib/scheduled-tasks/routes.js +27 -0
- package/server/lib/scheduled-tasks/routes.test.js +94 -0
- package/server/lib/scheduled-tasks/runtime.js +381 -310
- package/server/lib/scheduled-tasks/runtime.test.js +600 -309
- package/server/lib/session-goal/DOCUMENTATION.md +173 -22
- package/server/lib/session-goal/capability.js +57 -0
- package/server/lib/session-goal/capability.test.js +33 -0
- package/server/lib/session-goal/routes.js +240 -2
- package/server/lib/session-goal/routes.test.js +211 -0
- package/server/lib/session-goal/runtime.js +1617 -113
- package/server/lib/session-goal/runtime.test.js +1500 -70
- package/server/lib/session-index/DOCUMENTATION.md +18 -15
- package/server/lib/session-index/event-ingest.js +89 -16
- package/server/lib/session-index/event-ingest.test.js +73 -0
- package/server/lib/session-index/host-authority-snapshot.js +92 -0
- package/server/lib/session-index/routes.host-archive.test.js +201 -0
- package/server/lib/session-index/routes.js +63 -10
- package/server/lib/session-index/routes.test.js +8 -8
- package/server/lib/session-index/service.js +7 -1
- package/server/lib/session-index/sync-runtime.js +171 -41
- package/server/lib/session-index/sync-runtime.test.js +164 -9
- package/server/lib/session-metadata/DOCUMENTATION.md +86 -0
- package/server/lib/session-metadata/routes.js +193 -0
- package/server/lib/session-metadata/routes.test.js +156 -0
- package/server/lib/session-metadata/session-archive.d.ts +73 -0
- package/server/lib/session-metadata/session-archive.js +654 -0
- package/server/lib/session-metadata/session-archive.test.js +359 -0
- package/server/lib/session-metadata/session-metadata-store.d.ts +36 -0
- package/server/lib/session-metadata/session-metadata-store.js +375 -0
- package/server/lib/session-metadata/session-metadata-store.test.js +379 -0
- package/server/lib/session-metadata/session-projection.d.ts +41 -0
- package/server/lib/session-metadata/session-projection.js +255 -0
- package/server/lib/session-metadata/session-projection.test.js +64 -0
- package/server/lib/session-metadata/system-session.js +55 -0
- package/server/lib/session-metadata/system-session.test.js +55 -0
- package/server/lib/session-title/DOCUMENTATION.md +40 -7
- package/server/lib/session-title/native-runtime.test.js +167 -0
- package/server/lib/session-title/runtime.js +67 -42
- package/server/lib/session-title/session-access.js +46 -0
- package/server/lib/session-title/session-access.test.js +91 -0
- package/server/lib/session-turn-pages/DOCUMENTATION.md +12 -11
- package/server/lib/session-turn-pages/reconcile.service.js +1 -1
- package/server/lib/session-turn-pages/reconcile.service.test.js +16 -0
- package/server/lib/session-turn-pages/routes.js +123 -75
- package/server/lib/session-turn-pages/routes.test.js +566 -0
- package/server/lib/session-turn-pages/service.js +6 -2
- package/server/lib/session-turn-pages/service.test.js +34 -0
- package/server/lib/session-turn-pages/session-message-projection.d.ts +13 -0
- package/server/lib/session-turn-pages/session-message-projection.js +281 -0
- package/server/lib/small-model/DOCUMENTATION.md +101 -146
- package/server/lib/small-model/catalog.js +84 -54
- package/server/lib/small-model/catalog.test.js +111 -9
- package/server/lib/small-model/custom-api.js +68 -0
- package/server/lib/small-model/custom-api.test.js +64 -0
- package/server/lib/small-model/index.js +125 -241
- package/server/lib/small-model/resolve.js +35 -120
- package/server/lib/small-model/resolve.test.js +20 -110
- package/server/lib/small-model/routes.js +1 -3
- package/server/lib/small-model/summary-settings.test.js +157 -253
- package/server/opencode-proxy.test.js +63 -12
- package/dist/assets/AssistantView-BUveAgc4.js +0 -3
- package/dist/assets/MarkdownRenderer-BbrbDH6-.js +0 -2
- package/dist/assets/MobileDetailNavigation-B0aqKXd7.js +0 -1
- package/dist/assets/MobileSurface-DW7WfPsy.js +0 -2
- package/dist/assets/OverlayScrollbar-DrA0Vsg5.js +0 -2
- package/dist/assets/SettingsView-PkXIavr7.js +0 -25
- package/dist/assets/appThemeRegistry-D5Yxg4YF.js +0 -1
- package/dist/assets/collapsible-D5Phaykh.js +0 -1
- package/dist/assets/context-menu-CubSDW2g.js +0 -1
- package/dist/assets/es-DA3MqOo0.js +0 -15
- package/dist/assets/fr-Dbz0CdIA.js +0 -13
- package/dist/assets/gitApi-DXyC4MiV.js +0 -7
- package/dist/assets/insertionBoundaries-KlOVrHHt.js +0 -1
- package/dist/assets/ja-DumanVQA.js +0 -15
- package/dist/assets/ko-C0IkiUjQ.js +0 -15
- package/dist/assets/main-BPS5ylib.js +0 -2
- package/dist/assets/main-Cpd9VWYs.js +0 -169
- package/dist/assets/markdown-worker-CptoICmq.js +0 -2
- package/dist/assets/miniChat-B8_KLWiY.js +0 -2
- package/dist/assets/mobile-CtktKrXn.js +0 -2
- package/dist/assets/multirun-CYfP9Cfm.js +0 -4
- package/dist/assets/pl-B9No6MQp.js +0 -15
- package/dist/assets/platform-0w_Q9_ji.js +0 -2
- package/dist/assets/projectMeta-S1hJ7oBp.js +0 -3
- package/dist/assets/pt-BR-DyQ0WTDh.js +0 -15
- package/dist/assets/renderElectronMiniChatApp-iK14LWm8.js +0 -2
- package/dist/assets/renderMobileApp-DORLPWnb.js +0 -28
- package/dist/assets/src-rS3zCcsC.css +0 -2
- package/dist/assets/store-5B_LDnLM.js +0 -15
- package/dist/assets/uk-C_1KkqyP.js +0 -15
- package/dist/assets/useDesktopWindowControlsLayout-Dnr-jX0C.js +0 -1
- package/dist/assets/useEffectiveDirectory-CZLLyarc.js +0 -1
- package/dist/assets/useMobileNavigationStore-CoCiqNgm.js +0 -413
- package/dist/assets/useSessionAutoCleanup-xQyETQkG.js +0 -2
- package/dist/assets/useUIStore-Bxv3f23A.js +0 -1
- package/dist/assets/vendor-opencode-sdk-C07HQypa.js +0 -7
- package/dist/assets/zh-CN-uWILgBdt.js +0 -15
- package/dist/assets/zh-TW-MYfdvhbD.js +0 -15
- package/server/lib/small-model/call.js +0 -427
- package/server/lib/small-model/call.test.js +0 -382
- package/server/lib/small-model/opencode-session.js +0 -339
- 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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
125
|
-
|
|
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(
|
|
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:
|
|
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
|
-
//
|
|
203
|
-
//
|
|
204
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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' });
|