@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
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import { createProjectIdFromPath } from '../projects/project-id.js';
|
|
2
2
|
import { projectBootstrapSettingsResponse } from './settings-helpers.js';
|
|
3
|
+
import {
|
|
4
|
+
PINNED_OPENCODE2_VERSION,
|
|
5
|
+
evaluateOpenCodeHealthBody,
|
|
6
|
+
isOpenCode1xVersion,
|
|
7
|
+
resolveOpenCode2UpgradeTarget,
|
|
8
|
+
} from './opencode2-pin.js';
|
|
9
|
+
import {
|
|
10
|
+
installPinnedOpenCode2Cli,
|
|
11
|
+
readOpenCode2BinaryVersion,
|
|
12
|
+
resolveOpenChamberDataDir,
|
|
13
|
+
} from './ensure-cli.js';
|
|
14
|
+
import { evaluateRuntimeContract } from './runtime-contract.js';
|
|
15
|
+
import {
|
|
16
|
+
buildUpgradeStatusSnapshot,
|
|
17
|
+
classifyRuntimeOwnership,
|
|
18
|
+
createUpgradeOperationState,
|
|
19
|
+
evaluateOwnedUpgradeResult,
|
|
20
|
+
resolveOwnedCacheBinaryPath,
|
|
21
|
+
} from './owned-runtime-upgrade.js';
|
|
3
22
|
import fs from 'fs';
|
|
4
23
|
import os from 'os';
|
|
5
24
|
import path from 'path';
|
|
@@ -22,8 +41,23 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
22
41
|
buildOpenCodeUrl,
|
|
23
42
|
getOpenCodeAuthHeaders,
|
|
24
43
|
onSettingsPersisted,
|
|
44
|
+
getIsExternalOpenCode = () => false,
|
|
45
|
+
getIsSharedOpenCodeService = () => false,
|
|
46
|
+
forceResolvedOpenCodeBinary = null,
|
|
47
|
+
restartOpenCode = null,
|
|
48
|
+
waitForOpenCodeReady = null,
|
|
49
|
+
getRuntimeContract = () => null,
|
|
50
|
+
getOpenCodeServeVersion = () => null,
|
|
51
|
+
getOpenCodeCliVersion = () => null,
|
|
52
|
+
getResolvedOpenCodeBinary = () => null,
|
|
53
|
+
getResolvedOpenCodeBinarySource = () => null,
|
|
54
|
+
getActiveSessionCount = () => 0,
|
|
55
|
+
openchamberDataDir = null,
|
|
25
56
|
} = dependencies;
|
|
26
57
|
|
|
58
|
+
const upgradeOperation = createUpgradeOperationState();
|
|
59
|
+
const resolveDataDir = () => openchamberDataDir || resolveOpenChamberDataDir();
|
|
60
|
+
|
|
27
61
|
let authLibrary = null;
|
|
28
62
|
const pendingMcpAuthContextByState = new Map();
|
|
29
63
|
const PENDING_MCP_AUTH_TTL_MS = 30 * 60 * 1000;
|
|
@@ -50,16 +84,87 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
50
84
|
};
|
|
51
85
|
|
|
52
86
|
const readOpenCodeCurrentVersion = async () => {
|
|
53
|
-
const healthResponse = await fetch(buildOpenCodeUrl('/
|
|
87
|
+
const healthResponse = await fetch(buildOpenCodeUrl('/api/info', ''), {
|
|
54
88
|
method: 'GET',
|
|
55
89
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() },
|
|
56
90
|
});
|
|
57
91
|
const health = await healthResponse.json().catch(() => null);
|
|
58
92
|
if (!healthResponse.ok) {
|
|
59
|
-
return {
|
|
93
|
+
return {
|
|
94
|
+
ok: false,
|
|
95
|
+
status: healthResponse.status,
|
|
96
|
+
error: health?.error || healthResponse.statusText,
|
|
97
|
+
authenticated: healthResponse.status === 401 || healthResponse.status === 403 ? false : null,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const gate = evaluateOpenCodeHealthBody(health);
|
|
101
|
+
const currentVersion = gate.version
|
|
102
|
+
|| (typeof health?.version === 'string' ? health.version.replace(/^v/, '') : null);
|
|
103
|
+
return { ok: gate.ok, currentVersion, healthOk: gate.ok, authenticated: true };
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const resolveOwnershipContext = async () => {
|
|
107
|
+
const isExternal = getIsExternalOpenCode() === true;
|
|
108
|
+
let binarySource = typeof getResolvedOpenCodeBinarySource === 'function'
|
|
109
|
+
? getResolvedOpenCodeBinarySource()
|
|
110
|
+
: null;
|
|
111
|
+
let binaryPath = typeof getResolvedOpenCodeBinary === 'function'
|
|
112
|
+
? getResolvedOpenCodeBinary()
|
|
113
|
+
: null;
|
|
114
|
+
try {
|
|
115
|
+
const settings = await readSettingsFromDiskMigrated();
|
|
116
|
+
const resolution = await getOpenCodeResolutionSnapshot(settings);
|
|
117
|
+
binarySource = binarySource || resolution?.source || resolution?.detectedSourceNow || null;
|
|
118
|
+
binaryPath = binaryPath || resolution?.resolved || null;
|
|
119
|
+
if (resolution?.source === 'bundled' || resolution?.detectedSourceNow === 'bundled') {
|
|
120
|
+
binarySource = 'bundled';
|
|
121
|
+
}
|
|
122
|
+
} catch {
|
|
123
|
+
// Resolution failures still allow ownership classification from runtime flags.
|
|
60
124
|
}
|
|
61
|
-
|
|
62
|
-
|
|
125
|
+
return classifyRuntimeOwnership({
|
|
126
|
+
isExternal,
|
|
127
|
+
isSharedService: getIsSharedOpenCodeService() === true,
|
|
128
|
+
binarySource,
|
|
129
|
+
binaryPath,
|
|
130
|
+
dataDir: resolveDataDir(),
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const buildLiveContract = async ({ fresh = false } = {}) => {
|
|
135
|
+
const cached = typeof getRuntimeContract === 'function' ? getRuntimeContract() : null;
|
|
136
|
+
const serveProbe = await readOpenCodeCurrentVersion().catch(() => ({ ok: false, currentVersion: null }));
|
|
137
|
+
const serveVersion = serveProbe.currentVersion
|
|
138
|
+
|| (!fresh && typeof getOpenCodeServeVersion === 'function' ? getOpenCodeServeVersion() : null);
|
|
139
|
+
const binaryPath = typeof getResolvedOpenCodeBinary === 'function' ? getResolvedOpenCodeBinary() : null;
|
|
140
|
+
const cliVersion = (typeof getOpenCodeCliVersion === 'function' ? getOpenCodeCliVersion() : null)
|
|
141
|
+
|| (binaryPath ? readOpenCode2BinaryVersion(binaryPath) : null)
|
|
142
|
+
|| null;
|
|
143
|
+
return evaluateRuntimeContract({
|
|
144
|
+
serveVersion,
|
|
145
|
+
cliVersion,
|
|
146
|
+
reachable: fresh ? serveProbe.ok === true : serveProbe.ok === true || Boolean(serveVersion) || Boolean(cached?.reachable),
|
|
147
|
+
authenticated: serveProbe.authenticated ?? (fresh ? null : cached?.authenticated) ?? null,
|
|
148
|
+
healthOk: serveProbe.healthOk ?? serveProbe.ok ?? (fresh ? false : cached?.healthOk) ?? null,
|
|
149
|
+
migrationAdmitTranscript: cached?.migrationExecutable ?? null,
|
|
150
|
+
migrationPhase: cached?.migrationPhase ?? null,
|
|
151
|
+
migrationError: cached?.migrationError ?? null,
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const buildUpgradeStatus = async () => {
|
|
156
|
+
const ownership = await resolveOwnershipContext();
|
|
157
|
+
const contract = await buildLiveContract();
|
|
158
|
+
const activeCount = typeof getActiveSessionCount === 'function' ? Number(getActiveSessionCount()) || 0 : 0;
|
|
159
|
+
return buildUpgradeStatusSnapshot({
|
|
160
|
+
ownership,
|
|
161
|
+
serveVersion: contract.serveVersion,
|
|
162
|
+
cliVersion: contract.cliVersion,
|
|
163
|
+
targetVersion: PINNED_OPENCODE2_VERSION,
|
|
164
|
+
contract,
|
|
165
|
+
operation: upgradeOperation.getState(),
|
|
166
|
+
hasActiveTasks: activeCount > 0,
|
|
167
|
+
});
|
|
63
168
|
};
|
|
64
169
|
|
|
65
170
|
const parseVersionForComparison = (value) => {
|
|
@@ -183,51 +288,157 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
183
288
|
|
|
184
289
|
app.post('/api/opencode/upgrade', async (req, res) => {
|
|
185
290
|
try {
|
|
186
|
-
|
|
187
|
-
|
|
291
|
+
const ownership = await resolveOwnershipContext();
|
|
292
|
+
if (!ownership.canUpgradeInApp) {
|
|
293
|
+
const status = ownership.ownership === 'external-serve' || ownership.ownership === 'bundled' ? 409 : 409;
|
|
294
|
+
return res.status(status).json({
|
|
188
295
|
success: false,
|
|
189
|
-
error:
|
|
296
|
+
error: ownership.guidance
|
|
297
|
+
|| 'OpenChamber can only upgrade its owned OpenCode cache in-app.',
|
|
298
|
+
errorCode: ownership.reason || 'UPGRADE_NOT_MANAGED',
|
|
299
|
+
ownership: ownership.ownership,
|
|
300
|
+
management: ownership.management,
|
|
301
|
+
guidance: ownership.guidance,
|
|
190
302
|
});
|
|
191
303
|
}
|
|
192
304
|
|
|
193
|
-
const
|
|
194
|
-
|
|
305
|
+
const rawTarget = typeof req.body?.target === 'string' && req.body.target.trim().length > 0
|
|
306
|
+
? req.body.target.trim()
|
|
307
|
+
: undefined;
|
|
308
|
+
if (isOpenCode1xVersion(rawTarget)) {
|
|
195
309
|
return res.status(400).json({
|
|
196
310
|
success: false,
|
|
197
|
-
error: 'OpenCode upgrade
|
|
311
|
+
error: 'OpenCode upgrade refuses 1.x targets. Only pinned opencode2 is allowed.',
|
|
312
|
+
errorCode: 'OPENCODE_UPGRADE_1X_REFUSED',
|
|
198
313
|
});
|
|
199
314
|
}
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
Accept: 'application/json',
|
|
206
|
-
...getOpenCodeAuthHeaders(),
|
|
207
|
-
},
|
|
208
|
-
body: JSON.stringify({ target }),
|
|
209
|
-
});
|
|
210
|
-
const payload = await response.json().catch(() => null);
|
|
211
|
-
if (!response.ok) {
|
|
212
|
-
return res.status(response.status).json({
|
|
315
|
+
const target = resolveOpenCode2UpgradeTarget(rawTarget);
|
|
316
|
+
const confirmActive = req.body?.confirmActiveTasks === true || req.body?.force === true;
|
|
317
|
+
const activeCount = typeof getActiveSessionCount === 'function' ? Number(getActiveSessionCount()) || 0 : 0;
|
|
318
|
+
if (activeCount > 0 && !confirmActive) {
|
|
319
|
+
return res.status(409).json({
|
|
213
320
|
success: false,
|
|
214
|
-
error:
|
|
321
|
+
error: 'OpenCode has active sessions. Confirm upgrade to interrupt them, or wait until idle.',
|
|
322
|
+
errorCode: 'UPGRADE_ACTIVE_TASKS',
|
|
323
|
+
hasActiveTasks: true,
|
|
324
|
+
activeSessionCount: activeCount,
|
|
215
325
|
});
|
|
216
326
|
}
|
|
217
327
|
|
|
328
|
+
const begin = upgradeOperation.begin(target);
|
|
329
|
+
if (!begin.ok) {
|
|
330
|
+
return res.status(begin.status).json(begin.body);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const expectedBinaryPath = resolveOwnedCacheBinaryPath(target, { dataDir: resolveDataDir() });
|
|
334
|
+
let installedPath = expectedBinaryPath;
|
|
335
|
+
const previousBinary = getResolvedOpenCodeBinary();
|
|
336
|
+
const previousSource = getResolvedOpenCodeBinarySource();
|
|
337
|
+
|
|
218
338
|
try {
|
|
219
|
-
|
|
220
|
-
|
|
339
|
+
upgradeOperation.setPhase('download');
|
|
340
|
+
installedPath = await installPinnedOpenCode2Cli({
|
|
341
|
+
version: target,
|
|
342
|
+
dataDir: resolveDataDir(),
|
|
343
|
+
});
|
|
344
|
+
const diskVersion = readOpenCode2BinaryVersion(installedPath);
|
|
345
|
+
if (diskVersion !== target) {
|
|
346
|
+
const error = new Error(
|
|
347
|
+
`Owned-cache binary version mismatch after install: expected ${target}, got ${diskVersion || 'unknown'}`,
|
|
348
|
+
);
|
|
349
|
+
error.code = 'UPGRADE_BINARY_VERSION_MISMATCH';
|
|
350
|
+
throw error;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
upgradeOperation.setPhase('pin-binary', { binaryPath: installedPath });
|
|
354
|
+
if (typeof forceResolvedOpenCodeBinary !== 'function') {
|
|
355
|
+
const error = new Error('Owned-cache upgrade requires forceResolvedOpenCodeBinary');
|
|
356
|
+
error.code = 'UPGRADE_FORCE_BINARY_UNAVAILABLE';
|
|
357
|
+
throw error;
|
|
358
|
+
}
|
|
359
|
+
// Keep target identity through restart — do not rediscover global CLI.
|
|
360
|
+
forceResolvedOpenCodeBinary(installedPath, 'installed');
|
|
361
|
+
|
|
362
|
+
upgradeOperation.setPhase('restart');
|
|
363
|
+
if (typeof restartOpenCode === 'function') {
|
|
364
|
+
await restartOpenCode(ownership.ownership === 'shared-service' ? { binaryPath: installedPath } : undefined);
|
|
365
|
+
} else if (typeof refreshOpenCodeAfterConfigChange === 'function') {
|
|
366
|
+
// Fallback: still pin binary first so restart prefers owned cache.
|
|
367
|
+
await refreshOpenCodeAfterConfigChange('OpenCode owned-cache upgrade');
|
|
368
|
+
} else {
|
|
369
|
+
const error = new Error('No OpenCode restart path is configured');
|
|
370
|
+
error.code = 'UPGRADE_RESTART_UNAVAILABLE';
|
|
371
|
+
throw error;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (typeof waitForOpenCodeReady === 'function') {
|
|
375
|
+
upgradeOperation.setPhase('wait-ready');
|
|
376
|
+
await waitForOpenCodeReady();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
upgradeOperation.setPhase('verify');
|
|
380
|
+
// Re-pin after restart helpers that may clear resolution.
|
|
381
|
+
forceResolvedOpenCodeBinary(installedPath, 'installed');
|
|
382
|
+
const contract = await buildLiveContract({ fresh: true });
|
|
383
|
+
const verification = evaluateOwnedUpgradeResult({
|
|
384
|
+
targetVersion: target,
|
|
385
|
+
serveVersion: contract.serveVersion,
|
|
386
|
+
cliVersion: contract.cliVersion,
|
|
387
|
+
binaryPath: typeof getResolvedOpenCodeBinary === 'function'
|
|
388
|
+
? getResolvedOpenCodeBinary()
|
|
389
|
+
: installedPath,
|
|
390
|
+
expectedBinaryPath: installedPath,
|
|
391
|
+
contract,
|
|
392
|
+
});
|
|
393
|
+
if (!verification.ok) {
|
|
394
|
+
const error = new Error(verification.error);
|
|
395
|
+
error.code = verification.errorCode;
|
|
396
|
+
error.serveVersion = verification.serveVersion;
|
|
397
|
+
error.contract = verification.contract;
|
|
398
|
+
throw error;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
upgradeOperation.succeed({
|
|
402
|
+
serveVersion: verification.serveVersion,
|
|
403
|
+
binaryPath: installedPath,
|
|
404
|
+
});
|
|
405
|
+
return res.json({
|
|
406
|
+
success: true,
|
|
407
|
+
upgraded: true,
|
|
408
|
+
restarted: true,
|
|
409
|
+
version: verification.serveVersion,
|
|
410
|
+
targetVersion: target,
|
|
411
|
+
pinned: true,
|
|
412
|
+
supplySource: 'owned-cache',
|
|
413
|
+
ownership: ownership.ownership === 'shared-service' ? 'shared-service' : 'owned-cache',
|
|
414
|
+
binaryPath: installedPath,
|
|
415
|
+
contract: verification.contract,
|
|
416
|
+
operation: upgradeOperation.getState(),
|
|
417
|
+
});
|
|
418
|
+
} catch (upgradeError) {
|
|
419
|
+
if (previousBinary && typeof forceResolvedOpenCodeBinary === 'function') {
|
|
420
|
+
forceResolvedOpenCodeBinary(previousBinary, previousSource);
|
|
421
|
+
}
|
|
422
|
+
const message = upgradeError instanceof Error ? upgradeError.message : 'Failed to upgrade OpenCode';
|
|
423
|
+
const errorCode = upgradeError?.code || 'UPGRADE_FAILED';
|
|
424
|
+
upgradeOperation.fail({
|
|
425
|
+
error: message,
|
|
426
|
+
errorCode,
|
|
427
|
+
phase: upgradeOperation.getState().phase,
|
|
428
|
+
serveVersion: upgradeError?.serveVersion ?? null,
|
|
429
|
+
binaryPath: installedPath,
|
|
430
|
+
});
|
|
431
|
+
// Preserve previous owned cache on disk; only report failure.
|
|
221
432
|
return res.status(500).json({
|
|
222
433
|
success: false,
|
|
223
|
-
upgraded:
|
|
224
|
-
error:
|
|
225
|
-
|
|
226
|
-
|
|
434
|
+
upgraded: false,
|
|
435
|
+
error: message,
|
|
436
|
+
errorCode,
|
|
437
|
+
targetVersion: target,
|
|
438
|
+
operation: upgradeOperation.getState(),
|
|
439
|
+
contract: upgradeError?.contract || null,
|
|
227
440
|
});
|
|
228
441
|
}
|
|
229
|
-
|
|
230
|
-
return res.json({ ...(payload ?? { success: true }), restarted: true });
|
|
231
442
|
} catch (error) {
|
|
232
443
|
console.error('Failed to upgrade OpenCode:', error);
|
|
233
444
|
return res.status(500).json({
|
|
@@ -239,74 +450,88 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
239
450
|
|
|
240
451
|
app.get('/api/opencode/upgrade-status', async (_req, res) => {
|
|
241
452
|
try {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
453
|
+
const status = await buildUpgradeStatus();
|
|
454
|
+
return res.json(status);
|
|
455
|
+
} catch (error) {
|
|
456
|
+
return res.status(500).json({
|
|
457
|
+
available: null,
|
|
458
|
+
error: error instanceof Error ? error.message : 'Failed to check OpenCode upgrade status',
|
|
459
|
+
operation: upgradeOperation.getState(),
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
});
|
|
251
463
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}),
|
|
257
|
-
fetchLatestOpenCodeVersion(),
|
|
258
|
-
]);
|
|
259
|
-
const health = await healthResponse.json().catch(() => null);
|
|
260
|
-
if (!healthResponse.ok) {
|
|
261
|
-
return res.status(healthResponse.status).json({
|
|
262
|
-
available: null,
|
|
263
|
-
error: health?.error || healthResponse.statusText || 'Failed to read OpenCode version',
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
const currentVersion = typeof health?.version === 'string' ? health.version.replace(/^v/, '') : null;
|
|
267
|
-
if (!currentVersion || !latestVersion) {
|
|
268
|
-
return res.json({ available: null, currentVersion, latestVersion: latestVersion || null });
|
|
269
|
-
}
|
|
270
|
-
const available = compareVersions(latestVersion, currentVersion) > 0;
|
|
464
|
+
app.get('/api/opencode/contract', async (_req, res) => {
|
|
465
|
+
try {
|
|
466
|
+
const contract = await buildLiveContract();
|
|
467
|
+
const ownership = await resolveOwnershipContext();
|
|
271
468
|
return res.json({
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
469
|
+
...contract,
|
|
470
|
+
ownership: ownership.ownership,
|
|
471
|
+
supplySource: ownership.supplySource,
|
|
472
|
+
canManageUpgrade: ownership.canUpgradeInApp,
|
|
473
|
+
management: ownership.management,
|
|
474
|
+
guidance: ownership.guidance,
|
|
275
475
|
});
|
|
276
476
|
} catch (error) {
|
|
277
477
|
return res.status(500).json({
|
|
278
|
-
|
|
279
|
-
|
|
478
|
+
schemaVersion: 1,
|
|
479
|
+
phase: 'unknown',
|
|
480
|
+
executionAllowed: false,
|
|
481
|
+
error: error instanceof Error ? error.message : 'Failed to evaluate OpenCode runtime contract',
|
|
280
482
|
});
|
|
281
483
|
}
|
|
282
484
|
});
|
|
283
485
|
|
|
284
486
|
app.get('/api/opencode/health', async (_req, res) => {
|
|
285
487
|
try {
|
|
286
|
-
const healthResponse = await fetch(buildOpenCodeUrl('/
|
|
488
|
+
const healthResponse = await fetch(buildOpenCodeUrl('/api/info', ''), {
|
|
287
489
|
method: 'GET',
|
|
288
490
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() },
|
|
289
491
|
signal: AbortSignal.timeout(4_000),
|
|
290
492
|
});
|
|
291
493
|
const health = await healthResponse.json().catch(() => null);
|
|
292
494
|
if (!healthResponse.ok) {
|
|
495
|
+
const contract = evaluateRuntimeContract({
|
|
496
|
+
reachable: false,
|
|
497
|
+
authenticated: healthResponse.status === 401 || healthResponse.status === 403 ? false : null,
|
|
498
|
+
healthOk: false,
|
|
499
|
+
});
|
|
293
500
|
return res.status(healthResponse.status).json({
|
|
294
501
|
healthy: false,
|
|
295
502
|
error: health?.error || healthResponse.statusText || 'OpenCode health check failed',
|
|
503
|
+
contract,
|
|
296
504
|
});
|
|
297
505
|
}
|
|
298
|
-
|
|
506
|
+
// Reuse lifecycle/sidecar gate: official 2.x ServerInfo omits `healthy`.
|
|
507
|
+
const gate = evaluateOpenCodeHealthBody(health);
|
|
508
|
+
const contract = await buildLiveContract().catch(() => evaluateRuntimeContract({
|
|
509
|
+
serveVersion: gate.version,
|
|
510
|
+
reachable: gate.ok,
|
|
511
|
+
authenticated: true,
|
|
512
|
+
healthOk: gate.ok,
|
|
513
|
+
}));
|
|
514
|
+
return res.json({
|
|
515
|
+
healthy: gate.ok,
|
|
516
|
+
version: gate.version,
|
|
517
|
+
// Healthy is reachability/version shape only — not full execution semantics.
|
|
518
|
+
executionAllowed: contract.executionAllowed === true,
|
|
519
|
+
protocolCompatible: contract.protocolCompatible === true,
|
|
520
|
+
contract,
|
|
521
|
+
});
|
|
299
522
|
} catch (error) {
|
|
300
523
|
return res.status(503).json({
|
|
301
524
|
healthy: false,
|
|
302
525
|
error: error instanceof Error ? error.message : 'OpenCode health check failed',
|
|
526
|
+
contract: evaluateRuntimeContract({ reachable: false, healthOk: false }),
|
|
303
527
|
});
|
|
304
528
|
}
|
|
305
529
|
});
|
|
306
530
|
|
|
307
531
|
app.get('/api/opencode/version', async (_req, res) => {
|
|
308
532
|
try {
|
|
309
|
-
const
|
|
533
|
+
const contract = await buildLiveContract();
|
|
534
|
+
const healthResponse = await fetch(buildOpenCodeUrl('/api/info', ''), {
|
|
310
535
|
method: 'GET',
|
|
311
536
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() },
|
|
312
537
|
});
|
|
@@ -314,11 +539,20 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
314
539
|
if (!healthResponse.ok) {
|
|
315
540
|
return res.status(healthResponse.status).json({
|
|
316
541
|
version: null,
|
|
542
|
+
serveVersion: null,
|
|
543
|
+
cliVersion: contract.cliVersion,
|
|
317
544
|
error: health?.error || healthResponse.statusText || 'Failed to read OpenCode version',
|
|
545
|
+
contract,
|
|
318
546
|
});
|
|
319
547
|
}
|
|
320
548
|
const version = typeof health?.version === 'string' ? health.version.replace(/^v/, '') : null;
|
|
321
|
-
return res.json({
|
|
549
|
+
return res.json({
|
|
550
|
+
version,
|
|
551
|
+
serveVersion: version,
|
|
552
|
+
cliVersion: contract.cliVersion,
|
|
553
|
+
versionMismatch: Boolean(version && contract.cliVersion && version !== contract.cliVersion),
|
|
554
|
+
contract,
|
|
555
|
+
});
|
|
322
556
|
} catch (error) {
|
|
323
557
|
return res.status(500).json({
|
|
324
558
|
version: null,
|
|
@@ -606,13 +840,6 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
606
840
|
|
|
607
841
|
await fs.promises.writeFile(AGENTS_MD_PATH, content, 'utf8');
|
|
608
842
|
|
|
609
|
-
// Refresh OpenCode so it picks up the new AGENTS.md without a full restart
|
|
610
|
-
try {
|
|
611
|
-
await refreshOpenCodeAfterConfigChange('global behavior (AGENTS.md) updated');
|
|
612
|
-
} catch {
|
|
613
|
-
// Non-fatal: file was written successfully
|
|
614
|
-
}
|
|
615
|
-
|
|
616
843
|
return res.json({ success: true });
|
|
617
844
|
} catch (error) {
|
|
618
845
|
console.error('Failed to write AGENTS.md:', error);
|