@openchambery/web 1.19.22-beta.1 → 2.0.0-beta.10
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-CzTtVMnI.js} +1 -1
- package/dist/assets/AssistantView-Cg1qQvVe.js +3 -0
- package/dist/assets/{DiagramView-D1LGK_s2.js → DiagramView-hOi72Wdx.js} +1 -1
- package/dist/assets/{FadeInOnReveal-B0kJo9Ii.js → FadeInOnReveal-DCqrQkkz.js} +1 -1
- package/dist/assets/Icon-B8fSTLdP.js +1 -0
- package/dist/assets/MarkdownRenderer-Cw74oVxV.js +2 -0
- package/dist/assets/{MarkdownRendererImpl-DfoCJ1Mq.js → MarkdownRendererImpl-YM7iRmzK.js} +3 -3
- package/dist/assets/MarkstreamRendererImpl-BDy_oGJQ.js +3 -0
- package/dist/assets/MobileDetailNavigation-iX_hb_Xt.js +1 -0
- package/dist/assets/{MobileShareBridge-2Yjn6wXg.js → MobileShareBridge-CAMUupwR.js} +2 -2
- package/dist/assets/MobileSurface-CHbdPcLH.js +2 -0
- package/dist/assets/{MultiRunWindow-tTbMFowS.js → MultiRunWindow-Ci1ODFFX.js} +1 -1
- package/dist/assets/{OnboardingScreen-CD2KtlF3.js → OnboardingScreen-O4cGdz5p.js} +1 -1
- package/dist/assets/OverlayScrollbar-CRfGtcmG.js +2 -0
- package/dist/assets/SettingsView-Dg8BtTV1.js +25 -0
- package/dist/assets/{SettingsWindow-zIa76s4t.js → SettingsWindow-B8d8qIQ7.js} +1 -1
- package/dist/assets/TerminalView-CMiw3s_c.js +8 -0
- package/dist/assets/{ToolOutputDialog-DNqA4uBl.js → ToolOutputDialog-ByaQYRTp.js} +2 -2
- package/dist/assets/appThemeRegistry-BGGHio8T.js +1 -0
- package/dist/assets/{assistant-attachment-cache-C0aRnFkj.js → assistant-attachment-cache-DphJleHr.js} +1 -1
- package/dist/assets/{button-CI7Q-Zw_.js → button-DIIrsMjW.js} +1 -1
- package/dist/assets/{collapsible-D5Phaykh.js → collapsible-CnvUeYst.js} +1 -1
- package/dist/assets/{context-menu-CubSDW2g.js → context-menu-BGBUpZEQ.js} +1 -1
- package/dist/assets/{desktopHosts-B1ixEylr.js → desktopHosts-JGFqhlaM.js} +1 -1
- package/dist/assets/{desktopRelayRestore-4JmFUw8r.js → desktopRelayRestore-CHEwrI93.js} +1 -1
- package/dist/assets/{diagram-DdLO8HZ9.js → diagram-rvn7_qBM.js} +1 -1
- package/dist/assets/{dialog-B6pnIYmp.js → dialog-CQ63sc9E.js} +1 -1
- package/dist/assets/es-Dsmc0A_3.js +15 -0
- package/dist/assets/fileMentionTouchSelection-BzzcWJCi.js +3 -0
- package/dist/assets/{fileQueries-DQc8EJUf.js → fileQueries-DN6gbLhM.js} +1 -1
- package/dist/assets/fr-C_ZlZDI2.js +13 -0
- package/dist/assets/gitApi-BF8vuoZc.js +10 -0
- package/dist/assets/{imageSource-BlAJJUEI.js → imageSource-BMztRu0c.js} +1 -1
- package/dist/assets/{input-D-__fwRi.js → input-BVu-iykl.js} +1 -1
- package/dist/assets/insertionBoundaries-EcAfGT2D.js +1 -0
- package/dist/assets/ja-BqqTaWTi.js +15 -0
- package/dist/assets/ko-DP2XPM37.js +15 -0
- package/dist/assets/main-B7t9lavz.js +2 -0
- package/dist/assets/main-D2BzpnUt.css +1 -0
- package/dist/assets/main-DWP-prNB.js +169 -0
- package/dist/assets/markdown-worker-bS5OgGO3.js +2 -0
- package/dist/assets/{markdownHeightCache-BhxqJOvf.js → markdownHeightCache-D9-B1wdY.js} +1 -1
- package/dist/assets/markdownTheme-DM5h1i18.js +1 -0
- package/dist/assets/mcpQueries-CfXrAkuU.js +1 -0
- package/dist/assets/miniChat-DgOrEQbN.js +2 -0
- package/dist/assets/mobile-Co_ZOHkZ.js +2 -0
- package/dist/assets/multirun-DelyUO6k.js +4 -0
- package/dist/assets/persistence-D0y7226-.js +3 -0
- package/dist/assets/pl-BCf5uLlK.js +15 -0
- package/dist/assets/platform-CurqO28D.js +6 -0
- package/dist/assets/{projectMeta-S1hJ7oBp.js → projectMeta-CPElzJ0n.js} +2 -2
- package/dist/assets/pt-BR-W09Q2pvn.js +15 -0
- package/dist/assets/{relay-image-stream-DM7atqJs.js → relay-image-stream-DrdVj99c.js} +1 -1
- package/dist/assets/renderElectronMiniChatApp-pOE93w86.js +2 -0
- package/dist/assets/renderMobileApp-F7ZSLcw8.js +28 -0
- package/dist/assets/runtime-fetch-Fs9ZV2V8.js +1 -0
- package/dist/assets/{runtimeConfig-CMkwoQ_X.js → runtimeConfig-DSS0KxG3.js} +1 -1
- package/dist/assets/runtimeEndpointReset-x2Wgx57R.js +149 -0
- package/dist/assets/sessionChangeSummary-BUGSYcHp.js +2 -0
- package/dist/assets/{sessionLookup-BrU3rFHJ.js → sessionLookup-Bss8M20i.js} +1 -1
- package/dist/assets/{sortable-tabs-strip-Fnfhf3K9.js → sortable-tabs-strip-CE7W7lJ9.js} +1 -1
- package/dist/assets/src-lS1keDVV.css +2 -0
- package/dist/assets/store-jaP79mqI.js +15 -0
- package/dist/assets/{terminalApi-xjqssKke.js → terminalApi-mDR2jXTo.js} +1 -1
- package/dist/assets/textarea-XD2oX_Ee.js +1 -0
- package/dist/assets/{tooltip-0T5jv0cu.js → tooltip-DYeQ_Hvy.js} +1 -1
- package/dist/assets/uk-BgFzz8m2.js +15 -0
- package/dist/assets/{url-_z7evzdK.js → url-CGbJbiJq.js} +1 -1
- package/dist/assets/{useAppFontEffects-C02YFyAv.js → useAppFontEffects-BAWHZ-t0.js} +64 -45
- package/dist/assets/{useAssistantUIStore-CMutVh9B.js → useAssistantUIStore-Bz4tRflF.js} +1 -1
- package/dist/assets/useDesktopWindowControlsLayout-hN_nLb7T.js +1 -0
- package/dist/assets/useEffectiveDirectory-Do9DQ453.js +1 -0
- package/dist/assets/{useFontPreferences-B1JYyzpK.js → useFontPreferences-Bjx8zkGM.js} +1 -1
- package/dist/assets/useMobileNavigationStore-BsY_gi_K.js +414 -0
- package/dist/assets/useSessionAutoCleanup-C4g5KmDf.js +2 -0
- package/dist/assets/useUIStore-syVmbuDA.js +1 -0
- package/dist/assets/{useWorkerHighlightedLines-C9z0ML1z.js → useWorkerHighlightedLines-B5QXxBok.js} +2 -2
- package/dist/assets/vendor-opencode-client-C12gfjag.js +12 -0
- package/dist/assets/{vendor-reactuses-core-BnW6GxJt.js → vendor-reactuses-core-Dq5ocTF8.js} +1 -1
- package/dist/assets/{vendor-yaml-DIcAK3EC.js → vendor-yaml-C9KlJAlj.js} +37 -37
- package/dist/assets/zh-CN-BhqSLgUY.js +15 -0
- package/dist/assets/zh-TW-BsaBgY-p.js +15 -0
- package/dist/index.html +12 -12
- package/dist/mini-chat.html +12 -12
- package/dist/mobile.html +12 -12
- package/package.json +3 -2
- package/server/index.js +423 -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/browser-provider/DOCUMENTATION.md +141 -0
- package/server/lib/browser-provider/contract.js +312 -0
- package/server/lib/browser-provider/host.js +421 -0
- package/server/lib/browser-provider/host.test.js +304 -0
- package/server/lib/browser-provider/routes.js +122 -0
- package/server/lib/browser-provider/routes.test.js +120 -0
- package/server/lib/browser-provider/selection-store.js +43 -0
- package/server/lib/browser-provider/selection-store.test.js +35 -0
- 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/DOCUMENTATION.md +3 -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/reasoning-projection.js +16 -1
- package/server/lib/event-stream/reasoning-projection.test.js +15 -0
- 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/DOCUMENTATION.md +3 -1
- package/server/lib/notifications/runtime.js +133 -31
- package/server/lib/notifications/runtime.test.js +103 -0
- package/server/lib/notifications/template-runtime.js +130 -38
- package/server/lib/notifications/template-runtime.test.js +96 -0
- package/server/lib/opencode/DOCUMENTATION.md +111 -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 +117 -103
- package/server/lib/opencode/config-entity-routes.test.js +148 -10
- package/server/lib/opencode/config-hot-reload.integration.test.js +105 -0
- package/server/lib/opencode/ensure-cli.d.ts +8 -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 +90 -5
- package/server/lib/opencode/feature-routes-runtime.test.js +25 -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 +373 -28
- package/server/lib/opencode/proxy.test.js +353 -0
- package/server/lib/opencode/routes.js +333 -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/upgrade-screen.d.ts +30 -0
- package/server/lib/opencode/upgrade-screen.js +299 -0
- package/server/lib/opencode/upgrade-screen.test.js +196 -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 +96 -0
- package/server/lib/session-metadata/opencode-session-record.d.ts +57 -0
- package/server/lib/session-metadata/opencode-session-record.js +316 -0
- package/server/lib/session-metadata/opencode-session-record.test.js +242 -0
- package/server/lib/session-metadata/routes.js +197 -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 +38 -0
- package/server/lib/session-metadata/session-metadata-store.js +422 -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 +279 -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 +69 -44
- 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/Icon-BgdfPhNs.js +0 -1
- package/dist/assets/MarkdownRenderer-BbrbDH6-.js +0 -2
- package/dist/assets/MarkstreamRendererImpl-D2dsW5Lg.js +0 -3
- 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/TerminalView-CDdzF4yi.js +0 -8
- package/dist/assets/appThemeRegistry-D5Yxg4YF.js +0 -1
- package/dist/assets/es-DA3MqOo0.js +0 -15
- package/dist/assets/fileMentionTouchSelection-DNeiqns-.js +0 -4
- 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/main-qSeeJRW1.css +0 -1
- package/dist/assets/markdown-worker-CptoICmq.js +0 -2
- package/dist/assets/markdownTheme-DOfGg-A7.js +0 -1
- 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/persistence-Ce3AnpEr.js +0 -3
- package/dist/assets/pl-B9No6MQp.js +0 -15
- package/dist/assets/platform-0w_Q9_ji.js +0 -2
- 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/runtime-fetch-zIalUnbb.js +0 -1
- package/dist/assets/runtimeEndpointReset-ChOxt-J7.js +0 -147
- package/dist/assets/sessionChangeSummary-NnxcqCTI.js +0 -2
- package/dist/assets/src-rS3zCcsC.css +0 -2
- package/dist/assets/store-5B_LDnLM.js +0 -15
- package/dist/assets/textarea-bHYxZtfH.js +0 -1
- 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,25 @@
|
|
|
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 { registerUpgradeScreenRoutes } from './upgrade-screen.js';
|
|
15
|
+
import { evaluateRuntimeContract } from './runtime-contract.js';
|
|
16
|
+
import {
|
|
17
|
+
buildUpgradeStatusSnapshot,
|
|
18
|
+
classifyRuntimeOwnership,
|
|
19
|
+
createUpgradeOperationState,
|
|
20
|
+
evaluateOwnedUpgradeResult,
|
|
21
|
+
resolveOwnedCacheBinaryPath,
|
|
22
|
+
} from './owned-runtime-upgrade.js';
|
|
3
23
|
import fs from 'fs';
|
|
4
24
|
import os from 'os';
|
|
5
25
|
import path from 'path';
|
|
@@ -22,8 +42,23 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
22
42
|
buildOpenCodeUrl,
|
|
23
43
|
getOpenCodeAuthHeaders,
|
|
24
44
|
onSettingsPersisted,
|
|
45
|
+
getIsExternalOpenCode = () => false,
|
|
46
|
+
getIsSharedOpenCodeService = () => false,
|
|
47
|
+
forceResolvedOpenCodeBinary = null,
|
|
48
|
+
restartOpenCode = null,
|
|
49
|
+
waitForOpenCodeReady = null,
|
|
50
|
+
getRuntimeContract = () => null,
|
|
51
|
+
getOpenCodeServeVersion = () => null,
|
|
52
|
+
getOpenCodeCliVersion = () => null,
|
|
53
|
+
getResolvedOpenCodeBinary = () => null,
|
|
54
|
+
getResolvedOpenCodeBinarySource = () => null,
|
|
55
|
+
getActiveSessionCount = () => 0,
|
|
56
|
+
openchamberDataDir = null,
|
|
25
57
|
} = dependencies;
|
|
26
58
|
|
|
59
|
+
const upgradeOperation = createUpgradeOperationState();
|
|
60
|
+
const resolveDataDir = () => openchamberDataDir || resolveOpenChamberDataDir();
|
|
61
|
+
|
|
27
62
|
let authLibrary = null;
|
|
28
63
|
const pendingMcpAuthContextByState = new Map();
|
|
29
64
|
const PENDING_MCP_AUTH_TTL_MS = 30 * 60 * 1000;
|
|
@@ -50,16 +85,87 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
50
85
|
};
|
|
51
86
|
|
|
52
87
|
const readOpenCodeCurrentVersion = async () => {
|
|
53
|
-
const healthResponse = await fetch(buildOpenCodeUrl('/
|
|
88
|
+
const healthResponse = await fetch(buildOpenCodeUrl('/api/info', ''), {
|
|
54
89
|
method: 'GET',
|
|
55
90
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() },
|
|
56
91
|
});
|
|
57
92
|
const health = await healthResponse.json().catch(() => null);
|
|
58
93
|
if (!healthResponse.ok) {
|
|
59
|
-
return {
|
|
94
|
+
return {
|
|
95
|
+
ok: false,
|
|
96
|
+
status: healthResponse.status,
|
|
97
|
+
error: health?.error || healthResponse.statusText,
|
|
98
|
+
authenticated: healthResponse.status === 401 || healthResponse.status === 403 ? false : null,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const gate = evaluateOpenCodeHealthBody(health);
|
|
102
|
+
const currentVersion = gate.version
|
|
103
|
+
|| (typeof health?.version === 'string' ? health.version.replace(/^v/, '') : null);
|
|
104
|
+
return { ok: gate.ok, currentVersion, healthOk: gate.ok, authenticated: true };
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const resolveOwnershipContext = async () => {
|
|
108
|
+
const isExternal = getIsExternalOpenCode() === true;
|
|
109
|
+
let binarySource = typeof getResolvedOpenCodeBinarySource === 'function'
|
|
110
|
+
? getResolvedOpenCodeBinarySource()
|
|
111
|
+
: null;
|
|
112
|
+
let binaryPath = typeof getResolvedOpenCodeBinary === 'function'
|
|
113
|
+
? getResolvedOpenCodeBinary()
|
|
114
|
+
: null;
|
|
115
|
+
try {
|
|
116
|
+
const settings = await readSettingsFromDiskMigrated();
|
|
117
|
+
const resolution = await getOpenCodeResolutionSnapshot(settings);
|
|
118
|
+
binarySource = binarySource || resolution?.source || resolution?.detectedSourceNow || null;
|
|
119
|
+
binaryPath = binaryPath || resolution?.resolved || null;
|
|
120
|
+
if (resolution?.source === 'bundled' || resolution?.detectedSourceNow === 'bundled') {
|
|
121
|
+
binarySource = 'bundled';
|
|
122
|
+
}
|
|
123
|
+
} catch {
|
|
124
|
+
// Resolution failures still allow ownership classification from runtime flags.
|
|
60
125
|
}
|
|
61
|
-
|
|
62
|
-
|
|
126
|
+
return classifyRuntimeOwnership({
|
|
127
|
+
isExternal,
|
|
128
|
+
isSharedService: getIsSharedOpenCodeService() === true,
|
|
129
|
+
binarySource,
|
|
130
|
+
binaryPath,
|
|
131
|
+
dataDir: resolveDataDir(),
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const buildLiveContract = async ({ fresh = false } = {}) => {
|
|
136
|
+
const cached = typeof getRuntimeContract === 'function' ? getRuntimeContract() : null;
|
|
137
|
+
const serveProbe = await readOpenCodeCurrentVersion().catch(() => ({ ok: false, currentVersion: null }));
|
|
138
|
+
const serveVersion = serveProbe.currentVersion
|
|
139
|
+
|| (!fresh && typeof getOpenCodeServeVersion === 'function' ? getOpenCodeServeVersion() : null);
|
|
140
|
+
const binaryPath = typeof getResolvedOpenCodeBinary === 'function' ? getResolvedOpenCodeBinary() : null;
|
|
141
|
+
const cliVersion = (typeof getOpenCodeCliVersion === 'function' ? getOpenCodeCliVersion() : null)
|
|
142
|
+
|| (binaryPath ? readOpenCode2BinaryVersion(binaryPath) : null)
|
|
143
|
+
|| null;
|
|
144
|
+
return evaluateRuntimeContract({
|
|
145
|
+
serveVersion,
|
|
146
|
+
cliVersion,
|
|
147
|
+
reachable: fresh ? serveProbe.ok === true : serveProbe.ok === true || Boolean(serveVersion) || Boolean(cached?.reachable),
|
|
148
|
+
authenticated: serveProbe.authenticated ?? (fresh ? null : cached?.authenticated) ?? null,
|
|
149
|
+
healthOk: serveProbe.healthOk ?? serveProbe.ok ?? (fresh ? false : cached?.healthOk) ?? null,
|
|
150
|
+
migrationAdmitTranscript: cached?.migrationExecutable ?? null,
|
|
151
|
+
migrationPhase: cached?.migrationPhase ?? null,
|
|
152
|
+
migrationError: cached?.migrationError ?? null,
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const buildUpgradeStatus = async () => {
|
|
157
|
+
const ownership = await resolveOwnershipContext();
|
|
158
|
+
const contract = await buildLiveContract();
|
|
159
|
+
const activeCount = typeof getActiveSessionCount === 'function' ? Number(getActiveSessionCount()) || 0 : 0;
|
|
160
|
+
return buildUpgradeStatusSnapshot({
|
|
161
|
+
ownership,
|
|
162
|
+
serveVersion: contract.serveVersion,
|
|
163
|
+
cliVersion: contract.cliVersion,
|
|
164
|
+
targetVersion: PINNED_OPENCODE2_VERSION,
|
|
165
|
+
contract,
|
|
166
|
+
operation: upgradeOperation.getState(),
|
|
167
|
+
hasActiveTasks: activeCount > 0,
|
|
168
|
+
});
|
|
63
169
|
};
|
|
64
170
|
|
|
65
171
|
const parseVersionForComparison = (value) => {
|
|
@@ -148,6 +254,35 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
148
254
|
return fallback;
|
|
149
255
|
};
|
|
150
256
|
|
|
257
|
+
registerUpgradeScreenRoutes(app, {
|
|
258
|
+
resolveOwnership: resolveOwnershipContext,
|
|
259
|
+
readServeVersion: async () => {
|
|
260
|
+
const probe = await readOpenCodeCurrentVersion().catch(() => ({ currentVersion: null }));
|
|
261
|
+
return probe.currentVersion || null;
|
|
262
|
+
},
|
|
263
|
+
readCliVersion: () => {
|
|
264
|
+
const fromRuntime = typeof getOpenCodeCliVersion === 'function' ? getOpenCodeCliVersion() : null;
|
|
265
|
+
if (fromRuntime) return fromRuntime;
|
|
266
|
+
const binaryPath = typeof getResolvedOpenCodeBinary === 'function' ? getResolvedOpenCodeBinary() : null;
|
|
267
|
+
return binaryPath ? readOpenCode2BinaryVersion(binaryPath) : null;
|
|
268
|
+
},
|
|
269
|
+
readConfiguredBinary: async () => {
|
|
270
|
+
const settings = await readSettingsFromDiskMigrated();
|
|
271
|
+
return typeof settings?.opencodeBinary === 'string' ? settings.opencodeBinary : null;
|
|
272
|
+
},
|
|
273
|
+
persistBinary: async (binaryPath) => {
|
|
274
|
+
await persistSettings({ opencodeBinary: binaryPath });
|
|
275
|
+
},
|
|
276
|
+
getResolvedBinary: getResolvedOpenCodeBinary,
|
|
277
|
+
getResolvedBinarySource: getResolvedOpenCodeBinarySource,
|
|
278
|
+
forceBinary: typeof forceResolvedOpenCodeBinary === 'function' ? forceResolvedOpenCodeBinary : null,
|
|
279
|
+
restart: typeof restartOpenCode === 'function' ? restartOpenCode : null,
|
|
280
|
+
waitReady: typeof waitForOpenCodeReady === 'function' ? waitForOpenCodeReady : null,
|
|
281
|
+
isSharedService: () => getIsSharedOpenCodeService() === true,
|
|
282
|
+
install: (options) => installPinnedOpenCode2Cli({ ...options, dataDir: resolveDataDir() }),
|
|
283
|
+
readBinaryVersion: readOpenCode2BinaryVersion,
|
|
284
|
+
});
|
|
285
|
+
|
|
151
286
|
app.get('/api/config/settings', async (req, res) => {
|
|
152
287
|
try {
|
|
153
288
|
const settings = await readSettingsFromDiskMigrated();
|
|
@@ -183,51 +318,157 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
183
318
|
|
|
184
319
|
app.post('/api/opencode/upgrade', async (req, res) => {
|
|
185
320
|
try {
|
|
186
|
-
|
|
187
|
-
|
|
321
|
+
const ownership = await resolveOwnershipContext();
|
|
322
|
+
if (!ownership.canUpgradeInApp) {
|
|
323
|
+
const status = ownership.ownership === 'external-serve' || ownership.ownership === 'bundled' ? 409 : 409;
|
|
324
|
+
return res.status(status).json({
|
|
188
325
|
success: false,
|
|
189
|
-
error:
|
|
326
|
+
error: ownership.guidance
|
|
327
|
+
|| 'OpenChamber can only upgrade its owned OpenCode cache in-app.',
|
|
328
|
+
errorCode: ownership.reason || 'UPGRADE_NOT_MANAGED',
|
|
329
|
+
ownership: ownership.ownership,
|
|
330
|
+
management: ownership.management,
|
|
331
|
+
guidance: ownership.guidance,
|
|
190
332
|
});
|
|
191
333
|
}
|
|
192
334
|
|
|
193
|
-
const
|
|
194
|
-
|
|
335
|
+
const rawTarget = typeof req.body?.target === 'string' && req.body.target.trim().length > 0
|
|
336
|
+
? req.body.target.trim()
|
|
337
|
+
: undefined;
|
|
338
|
+
if (isOpenCode1xVersion(rawTarget)) {
|
|
195
339
|
return res.status(400).json({
|
|
196
340
|
success: false,
|
|
197
|
-
error: 'OpenCode upgrade
|
|
341
|
+
error: 'OpenCode upgrade refuses 1.x targets. Only pinned opencode2 is allowed.',
|
|
342
|
+
errorCode: 'OPENCODE_UPGRADE_1X_REFUSED',
|
|
198
343
|
});
|
|
199
344
|
}
|
|
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({
|
|
345
|
+
const target = resolveOpenCode2UpgradeTarget(rawTarget);
|
|
346
|
+
const confirmActive = req.body?.confirmActiveTasks === true || req.body?.force === true;
|
|
347
|
+
const activeCount = typeof getActiveSessionCount === 'function' ? Number(getActiveSessionCount()) || 0 : 0;
|
|
348
|
+
if (activeCount > 0 && !confirmActive) {
|
|
349
|
+
return res.status(409).json({
|
|
213
350
|
success: false,
|
|
214
|
-
error:
|
|
351
|
+
error: 'OpenCode has active sessions. Confirm upgrade to interrupt them, or wait until idle.',
|
|
352
|
+
errorCode: 'UPGRADE_ACTIVE_TASKS',
|
|
353
|
+
hasActiveTasks: true,
|
|
354
|
+
activeSessionCount: activeCount,
|
|
215
355
|
});
|
|
216
356
|
}
|
|
217
357
|
|
|
358
|
+
const begin = upgradeOperation.begin(target);
|
|
359
|
+
if (!begin.ok) {
|
|
360
|
+
return res.status(begin.status).json(begin.body);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const expectedBinaryPath = resolveOwnedCacheBinaryPath(target, { dataDir: resolveDataDir() });
|
|
364
|
+
let installedPath = expectedBinaryPath;
|
|
365
|
+
const previousBinary = getResolvedOpenCodeBinary();
|
|
366
|
+
const previousSource = getResolvedOpenCodeBinarySource();
|
|
367
|
+
|
|
218
368
|
try {
|
|
219
|
-
|
|
220
|
-
|
|
369
|
+
upgradeOperation.setPhase('download');
|
|
370
|
+
installedPath = await installPinnedOpenCode2Cli({
|
|
371
|
+
version: target,
|
|
372
|
+
dataDir: resolveDataDir(),
|
|
373
|
+
});
|
|
374
|
+
const diskVersion = readOpenCode2BinaryVersion(installedPath);
|
|
375
|
+
if (diskVersion !== target) {
|
|
376
|
+
const error = new Error(
|
|
377
|
+
`Owned-cache binary version mismatch after install: expected ${target}, got ${diskVersion || 'unknown'}`,
|
|
378
|
+
);
|
|
379
|
+
error.code = 'UPGRADE_BINARY_VERSION_MISMATCH';
|
|
380
|
+
throw error;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
upgradeOperation.setPhase('pin-binary', { binaryPath: installedPath });
|
|
384
|
+
if (typeof forceResolvedOpenCodeBinary !== 'function') {
|
|
385
|
+
const error = new Error('Owned-cache upgrade requires forceResolvedOpenCodeBinary');
|
|
386
|
+
error.code = 'UPGRADE_FORCE_BINARY_UNAVAILABLE';
|
|
387
|
+
throw error;
|
|
388
|
+
}
|
|
389
|
+
// Keep target identity through restart — do not rediscover global CLI.
|
|
390
|
+
forceResolvedOpenCodeBinary(installedPath, 'installed');
|
|
391
|
+
|
|
392
|
+
upgradeOperation.setPhase('restart');
|
|
393
|
+
if (typeof restartOpenCode === 'function') {
|
|
394
|
+
await restartOpenCode(ownership.ownership === 'shared-service' ? { binaryPath: installedPath } : undefined);
|
|
395
|
+
} else if (typeof refreshOpenCodeAfterConfigChange === 'function') {
|
|
396
|
+
// Fallback: still pin binary first so restart prefers owned cache.
|
|
397
|
+
await refreshOpenCodeAfterConfigChange('OpenCode owned-cache upgrade');
|
|
398
|
+
} else {
|
|
399
|
+
const error = new Error('No OpenCode restart path is configured');
|
|
400
|
+
error.code = 'UPGRADE_RESTART_UNAVAILABLE';
|
|
401
|
+
throw error;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (typeof waitForOpenCodeReady === 'function') {
|
|
405
|
+
upgradeOperation.setPhase('wait-ready');
|
|
406
|
+
await waitForOpenCodeReady();
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
upgradeOperation.setPhase('verify');
|
|
410
|
+
// Re-pin after restart helpers that may clear resolution.
|
|
411
|
+
forceResolvedOpenCodeBinary(installedPath, 'installed');
|
|
412
|
+
const contract = await buildLiveContract({ fresh: true });
|
|
413
|
+
const verification = evaluateOwnedUpgradeResult({
|
|
414
|
+
targetVersion: target,
|
|
415
|
+
serveVersion: contract.serveVersion,
|
|
416
|
+
cliVersion: contract.cliVersion,
|
|
417
|
+
binaryPath: typeof getResolvedOpenCodeBinary === 'function'
|
|
418
|
+
? getResolvedOpenCodeBinary()
|
|
419
|
+
: installedPath,
|
|
420
|
+
expectedBinaryPath: installedPath,
|
|
421
|
+
contract,
|
|
422
|
+
});
|
|
423
|
+
if (!verification.ok) {
|
|
424
|
+
const error = new Error(verification.error);
|
|
425
|
+
error.code = verification.errorCode;
|
|
426
|
+
error.serveVersion = verification.serveVersion;
|
|
427
|
+
error.contract = verification.contract;
|
|
428
|
+
throw error;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
upgradeOperation.succeed({
|
|
432
|
+
serveVersion: verification.serveVersion,
|
|
433
|
+
binaryPath: installedPath,
|
|
434
|
+
});
|
|
435
|
+
return res.json({
|
|
436
|
+
success: true,
|
|
437
|
+
upgraded: true,
|
|
438
|
+
restarted: true,
|
|
439
|
+
version: verification.serveVersion,
|
|
440
|
+
targetVersion: target,
|
|
441
|
+
pinned: true,
|
|
442
|
+
supplySource: 'owned-cache',
|
|
443
|
+
ownership: ownership.ownership === 'shared-service' ? 'shared-service' : 'owned-cache',
|
|
444
|
+
binaryPath: installedPath,
|
|
445
|
+
contract: verification.contract,
|
|
446
|
+
operation: upgradeOperation.getState(),
|
|
447
|
+
});
|
|
448
|
+
} catch (upgradeError) {
|
|
449
|
+
if (previousBinary && typeof forceResolvedOpenCodeBinary === 'function') {
|
|
450
|
+
forceResolvedOpenCodeBinary(previousBinary, previousSource);
|
|
451
|
+
}
|
|
452
|
+
const message = upgradeError instanceof Error ? upgradeError.message : 'Failed to upgrade OpenCode';
|
|
453
|
+
const errorCode = upgradeError?.code || 'UPGRADE_FAILED';
|
|
454
|
+
upgradeOperation.fail({
|
|
455
|
+
error: message,
|
|
456
|
+
errorCode,
|
|
457
|
+
phase: upgradeOperation.getState().phase,
|
|
458
|
+
serveVersion: upgradeError?.serveVersion ?? null,
|
|
459
|
+
binaryPath: installedPath,
|
|
460
|
+
});
|
|
461
|
+
// Preserve previous owned cache on disk; only report failure.
|
|
221
462
|
return res.status(500).json({
|
|
222
463
|
success: false,
|
|
223
|
-
upgraded:
|
|
224
|
-
error:
|
|
225
|
-
|
|
226
|
-
|
|
464
|
+
upgraded: false,
|
|
465
|
+
error: message,
|
|
466
|
+
errorCode,
|
|
467
|
+
targetVersion: target,
|
|
468
|
+
operation: upgradeOperation.getState(),
|
|
469
|
+
contract: upgradeError?.contract || null,
|
|
227
470
|
});
|
|
228
471
|
}
|
|
229
|
-
|
|
230
|
-
return res.json({ ...(payload ?? { success: true }), restarted: true });
|
|
231
472
|
} catch (error) {
|
|
232
473
|
console.error('Failed to upgrade OpenCode:', error);
|
|
233
474
|
return res.status(500).json({
|
|
@@ -239,74 +480,88 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
239
480
|
|
|
240
481
|
app.get('/api/opencode/upgrade-status', async (_req, res) => {
|
|
241
482
|
try {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
483
|
+
const status = await buildUpgradeStatus();
|
|
484
|
+
return res.json(status);
|
|
485
|
+
} catch (error) {
|
|
486
|
+
return res.status(500).json({
|
|
487
|
+
available: null,
|
|
488
|
+
error: error instanceof Error ? error.message : 'Failed to check OpenCode upgrade status',
|
|
489
|
+
operation: upgradeOperation.getState(),
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
});
|
|
251
493
|
|
|
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;
|
|
494
|
+
app.get('/api/opencode/contract', async (_req, res) => {
|
|
495
|
+
try {
|
|
496
|
+
const contract = await buildLiveContract();
|
|
497
|
+
const ownership = await resolveOwnershipContext();
|
|
271
498
|
return res.json({
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
499
|
+
...contract,
|
|
500
|
+
ownership: ownership.ownership,
|
|
501
|
+
supplySource: ownership.supplySource,
|
|
502
|
+
canManageUpgrade: ownership.canUpgradeInApp,
|
|
503
|
+
management: ownership.management,
|
|
504
|
+
guidance: ownership.guidance,
|
|
275
505
|
});
|
|
276
506
|
} catch (error) {
|
|
277
507
|
return res.status(500).json({
|
|
278
|
-
|
|
279
|
-
|
|
508
|
+
schemaVersion: 1,
|
|
509
|
+
phase: 'unknown',
|
|
510
|
+
executionAllowed: false,
|
|
511
|
+
error: error instanceof Error ? error.message : 'Failed to evaluate OpenCode runtime contract',
|
|
280
512
|
});
|
|
281
513
|
}
|
|
282
514
|
});
|
|
283
515
|
|
|
284
516
|
app.get('/api/opencode/health', async (_req, res) => {
|
|
285
517
|
try {
|
|
286
|
-
const healthResponse = await fetch(buildOpenCodeUrl('/
|
|
518
|
+
const healthResponse = await fetch(buildOpenCodeUrl('/api/info', ''), {
|
|
287
519
|
method: 'GET',
|
|
288
520
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() },
|
|
289
521
|
signal: AbortSignal.timeout(4_000),
|
|
290
522
|
});
|
|
291
523
|
const health = await healthResponse.json().catch(() => null);
|
|
292
524
|
if (!healthResponse.ok) {
|
|
525
|
+
const contract = evaluateRuntimeContract({
|
|
526
|
+
reachable: false,
|
|
527
|
+
authenticated: healthResponse.status === 401 || healthResponse.status === 403 ? false : null,
|
|
528
|
+
healthOk: false,
|
|
529
|
+
});
|
|
293
530
|
return res.status(healthResponse.status).json({
|
|
294
531
|
healthy: false,
|
|
295
532
|
error: health?.error || healthResponse.statusText || 'OpenCode health check failed',
|
|
533
|
+
contract,
|
|
296
534
|
});
|
|
297
535
|
}
|
|
298
|
-
|
|
536
|
+
// Reuse lifecycle/sidecar gate: official 2.x ServerInfo omits `healthy`.
|
|
537
|
+
const gate = evaluateOpenCodeHealthBody(health);
|
|
538
|
+
const contract = await buildLiveContract().catch(() => evaluateRuntimeContract({
|
|
539
|
+
serveVersion: gate.version,
|
|
540
|
+
reachable: gate.ok,
|
|
541
|
+
authenticated: true,
|
|
542
|
+
healthOk: gate.ok,
|
|
543
|
+
}));
|
|
544
|
+
return res.json({
|
|
545
|
+
healthy: gate.ok,
|
|
546
|
+
version: gate.version,
|
|
547
|
+
// Healthy is reachability/version shape only — not full execution semantics.
|
|
548
|
+
executionAllowed: contract.executionAllowed === true,
|
|
549
|
+
protocolCompatible: contract.protocolCompatible === true,
|
|
550
|
+
contract,
|
|
551
|
+
});
|
|
299
552
|
} catch (error) {
|
|
300
553
|
return res.status(503).json({
|
|
301
554
|
healthy: false,
|
|
302
555
|
error: error instanceof Error ? error.message : 'OpenCode health check failed',
|
|
556
|
+
contract: evaluateRuntimeContract({ reachable: false, healthOk: false }),
|
|
303
557
|
});
|
|
304
558
|
}
|
|
305
559
|
});
|
|
306
560
|
|
|
307
561
|
app.get('/api/opencode/version', async (_req, res) => {
|
|
308
562
|
try {
|
|
309
|
-
const
|
|
563
|
+
const contract = await buildLiveContract();
|
|
564
|
+
const healthResponse = await fetch(buildOpenCodeUrl('/api/info', ''), {
|
|
310
565
|
method: 'GET',
|
|
311
566
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() },
|
|
312
567
|
});
|
|
@@ -314,11 +569,20 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
314
569
|
if (!healthResponse.ok) {
|
|
315
570
|
return res.status(healthResponse.status).json({
|
|
316
571
|
version: null,
|
|
572
|
+
serveVersion: null,
|
|
573
|
+
cliVersion: contract.cliVersion,
|
|
317
574
|
error: health?.error || healthResponse.statusText || 'Failed to read OpenCode version',
|
|
575
|
+
contract,
|
|
318
576
|
});
|
|
319
577
|
}
|
|
320
578
|
const version = typeof health?.version === 'string' ? health.version.replace(/^v/, '') : null;
|
|
321
|
-
return res.json({
|
|
579
|
+
return res.json({
|
|
580
|
+
version,
|
|
581
|
+
serveVersion: version,
|
|
582
|
+
cliVersion: contract.cliVersion,
|
|
583
|
+
versionMismatch: Boolean(version && contract.cliVersion && version !== contract.cliVersion),
|
|
584
|
+
contract,
|
|
585
|
+
});
|
|
322
586
|
} catch (error) {
|
|
323
587
|
return res.status(500).json({
|
|
324
588
|
version: null,
|
|
@@ -606,13 +870,6 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
|
|
606
870
|
|
|
607
871
|
await fs.promises.writeFile(AGENTS_MD_PATH, content, 'utf8');
|
|
608
872
|
|
|
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
873
|
return res.json({ success: true });
|
|
617
874
|
} catch (error) {
|
|
618
875
|
console.error('Failed to write AGENTS.md:', error);
|