@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
package/server/index.js
CHANGED
|
@@ -39,6 +39,7 @@ import { resolveOpenCodeEnvConfig } from './lib/opencode/env-config.js';
|
|
|
39
39
|
import { createHmrStateRuntime } from './lib/opencode/hmr-state-runtime.js';
|
|
40
40
|
import { createOpenCodeNetworkRuntime } from './lib/opencode/network-runtime.js';
|
|
41
41
|
import { createOpenCodeAuthStateRuntime } from './lib/opencode/auth-state-runtime.js';
|
|
42
|
+
import { createSharedOpenCodeService, isSharedServiceEnabled } from './lib/opencode/shared-service.js';
|
|
42
43
|
import { createProjectDirectoryRuntime } from './lib/opencode/project-directory-runtime.js';
|
|
43
44
|
import { createSettingsNormalizationRuntime } from './lib/opencode/settings-normalization-runtime.js';
|
|
44
45
|
import { createSettingsHelpers } from './lib/opencode/settings-helpers.js';
|
|
@@ -52,6 +53,11 @@ import {
|
|
|
52
53
|
} from './lib/opencode/core-routes.js';
|
|
53
54
|
import { registerOpenChamberRoutes } from './lib/opencode/openchamber-routes.js';
|
|
54
55
|
import { createServerUtilsRuntime } from './lib/opencode/server-utils-runtime.js';
|
|
56
|
+
import {
|
|
57
|
+
configureServerOpenCodeFetchGate,
|
|
58
|
+
createServerOpenCodeFetch,
|
|
59
|
+
wrapFetchWithRuntimeContractGate,
|
|
60
|
+
} from './lib/opencode/server-opencode-fetch.js';
|
|
55
61
|
import { createStaticRoutesRuntime } from './lib/opencode/static-routes-runtime.js';
|
|
56
62
|
import { createSettingsRuntime } from './lib/opencode/settings-runtime.js';
|
|
57
63
|
import { createOpenCodeResolutionRuntime } from './lib/opencode/opencode-resolution-runtime.js';
|
|
@@ -59,6 +65,7 @@ import { createBootstrapRuntime } from './lib/opencode/bootstrap-runtime.js';
|
|
|
59
65
|
import { createSessionRuntime } from './lib/opencode/session-runtime.js';
|
|
60
66
|
import { createOpenCodeWatcherRuntime } from './lib/opencode/watcher.js';
|
|
61
67
|
import { createSessionTitleRuntime } from './lib/session-title/runtime.js';
|
|
68
|
+
import { createTitleSessionAccess } from './lib/session-title/session-access.js';
|
|
62
69
|
import { createSessionIndexService } from './lib/session-index/service.js';
|
|
63
70
|
import { createSessionIndexSyncRuntime } from './lib/session-index/sync-runtime.js';
|
|
64
71
|
import { resolveSessionIndexDbPath } from './lib/session-index/resolve-db-path.js';
|
|
@@ -68,7 +75,24 @@ import { resolveTranscriptCacheDbPath } from './lib/transcript-cache/resolve-db-
|
|
|
68
75
|
import { createMessageQueueRuntime } from './lib/message-queue/runtime.js';
|
|
69
76
|
import { resolveMessageQueueDbPath } from './lib/message-queue/resolve-db-path.js';
|
|
70
77
|
import { createOpenChamberEventBroadcaster } from './lib/opencode/feature-routes-runtime.js';
|
|
71
|
-
import {
|
|
78
|
+
import {
|
|
79
|
+
createSessionGoalRuntime,
|
|
80
|
+
withGoalExecutionGeneration,
|
|
81
|
+
} from './lib/session-goal/runtime.js';
|
|
82
|
+
import { createSessionMetadataStore } from './lib/session-metadata/session-metadata-store.js';
|
|
83
|
+
import {
|
|
84
|
+
createHttpSessionRecordClient,
|
|
85
|
+
retainOpenCodeSessions,
|
|
86
|
+
startSideStoreMigration,
|
|
87
|
+
} from './lib/session-metadata/opencode-session-record.js';
|
|
88
|
+
import {
|
|
89
|
+
createSessionArchiveService,
|
|
90
|
+
createUpstreamSessionFetcher,
|
|
91
|
+
} from './lib/session-metadata/session-archive.js';
|
|
92
|
+
import {
|
|
93
|
+
projectSessionLifecyclePayload,
|
|
94
|
+
projectSessionWithStoredMap,
|
|
95
|
+
} from './lib/session-metadata/session-projection.js';
|
|
72
96
|
import { createScheduledTasksRuntime } from './lib/scheduled-tasks/runtime.js';
|
|
73
97
|
import { createScheduledTaskRunHistoryStore } from './lib/scheduled-tasks/run-history-store.js';
|
|
74
98
|
import { createServerStartupRuntime } from './lib/opencode/server-startup-runtime.js';
|
|
@@ -88,6 +112,7 @@ import { createNotificationTemplateRuntime } from './lib/notifications/template-
|
|
|
88
112
|
import { createPermissionAutoAcceptRuntime } from './lib/permission-auto-accept/runtime.js';
|
|
89
113
|
import { createQuestionAutoDelegateRuntime } from './lib/question-auto-delegate/runtime.js';
|
|
90
114
|
import { createGracefulShutdownRuntime } from './lib/opencode/shutdown-runtime.js';
|
|
115
|
+
import { attachHttpServerConnectionTracker } from './lib/opencode/http-server-connections.js';
|
|
91
116
|
import { createProjectConfigRuntime } from './lib/projects/project-config.js';
|
|
92
117
|
import { createRemoteClientAuthRuntime } from './lib/client-auth/remote-clients.js';
|
|
93
118
|
import { applyRuntimeCorsHeaders } from './lib/request-cors.js';
|
|
@@ -445,6 +470,12 @@ let openCodeApiDetectionTimer = null;
|
|
|
445
470
|
let lastOpenCodeError = null;
|
|
446
471
|
let lastOpenCodeLaunchDiagnostics = null;
|
|
447
472
|
let isOpenCodeReady = false;
|
|
473
|
+
let v1Migration = null;
|
|
474
|
+
let openCodeServeVersion = null;
|
|
475
|
+
let openCodeCliVersion = null;
|
|
476
|
+
let runtimeContract = null;
|
|
477
|
+
/** Bumps on start/restart so stale async health cannot re-permit an old instance. */
|
|
478
|
+
let runtimeContractGeneration = 0;
|
|
448
479
|
let openCodeNotReadySince = 0;
|
|
449
480
|
let isExternalOpenCode = false;
|
|
450
481
|
let exitOnShutdown = true;
|
|
@@ -549,6 +580,7 @@ const openCodeAuthStateRuntime = createOpenCodeAuthStateRuntime({
|
|
|
549
580
|
const getOpenCodeAuthHeaders = (...args) => openCodeAuthStateRuntime.getOpenCodeAuthHeaders(...args);
|
|
550
581
|
const isOpenCodeConnectionSecure = (...args) => openCodeAuthStateRuntime.isOpenCodeConnectionSecure(...args);
|
|
551
582
|
const ensureLocalOpenCodeServerPassword = (...args) => openCodeAuthStateRuntime.ensureLocalOpenCodeServerPassword(...args);
|
|
583
|
+
const adoptOpenCodeServerPassword = (...args) => openCodeAuthStateRuntime.adoptOpenCodeServerPassword(...args);
|
|
552
584
|
|
|
553
585
|
const openCodeNetworkState = {};
|
|
554
586
|
Object.defineProperties(openCodeNetworkState, {
|
|
@@ -572,6 +604,15 @@ const buildOpenCodeUrl = (...args) => openCodeNetworkRuntime.buildOpenCodeUrl(..
|
|
|
572
604
|
const ensureOpenCodeApiPrefix = (...args) => openCodeNetworkRuntime.ensureOpenCodeApiPrefix(...args);
|
|
573
605
|
const scheduleOpenCodeApiDetection = (...args) => openCodeNetworkRuntime.scheduleOpenCodeApiDetection(...args);
|
|
574
606
|
|
|
607
|
+
// Host OpenCode transport gate (queue/goal/scheduled/assistants + v2-client).
|
|
608
|
+
// Registered before background runtimes so direct OpenCode writes share proxy admission.
|
|
609
|
+
configureServerOpenCodeFetchGate(() => runtimeContract);
|
|
610
|
+
const serverOpenCodeFetch = createServerOpenCodeFetch({
|
|
611
|
+
buildOpenCodeUrl,
|
|
612
|
+
getOpenCodeAuthHeaders,
|
|
613
|
+
getRuntimeContract: () => runtimeContract,
|
|
614
|
+
});
|
|
615
|
+
|
|
575
616
|
const ENV_CONFIGURED_API_PREFIX = normalizeApiPrefix(
|
|
576
617
|
process.env.OPENCODE_API_PREFIX || process.env.OPENCHAMBER_API_PREFIX || ''
|
|
577
618
|
);
|
|
@@ -614,6 +655,7 @@ const openCodeEnvRuntime = createOpenCodeEnvRuntime({
|
|
|
614
655
|
const applyLoginShellEnvSnapshot = (...args) => openCodeEnvRuntime.applyLoginShellEnvSnapshot(...args);
|
|
615
656
|
const getLoginShellEnvSnapshot = (...args) => openCodeEnvRuntime.getLoginShellEnvSnapshot(...args);
|
|
616
657
|
const ensureOpencodeCliEnv = (...args) => openCodeEnvRuntime.ensureOpencodeCliEnv(...args);
|
|
658
|
+
const ensurePinnedOpenCode2CliEnv = (...args) => openCodeEnvRuntime.ensurePinnedOpenCode2CliEnv(...args);
|
|
617
659
|
const applyOpencodeBinaryFromSettings = (...args) => openCodeEnvRuntime.applyOpencodeBinaryFromSettings(...args);
|
|
618
660
|
const resolveOpencodeCliPath = (...args) => openCodeEnvRuntime.resolveOpencodeCliPath(...args);
|
|
619
661
|
const isExecutable = (...args) => openCodeEnvRuntime.isExecutable(...args);
|
|
@@ -621,6 +663,7 @@ const searchPathFor = (...args) => openCodeEnvRuntime.searchPathFor(...args);
|
|
|
621
663
|
const resolveGitBinaryForSpawn = (...args) => openCodeEnvRuntime.resolveGitBinaryForSpawn(...args);
|
|
622
664
|
const resolveManagedOpenCodeLaunchSpec = (...args) => openCodeEnvRuntime.resolveManagedOpenCodeLaunchSpec(...args);
|
|
623
665
|
const clearResolvedOpenCodeBinary = (...args) => openCodeEnvRuntime.clearResolvedOpenCodeBinary(...args);
|
|
666
|
+
const forceResolvedOpenCodeBinary = (...args) => openCodeEnvRuntime.forceResolvedOpenCodeBinary(...args);
|
|
624
667
|
const openCodeResolutionRuntime = createOpenCodeResolutionRuntime({
|
|
625
668
|
path,
|
|
626
669
|
resolveOpencodeCliPath,
|
|
@@ -696,6 +739,8 @@ const getSmallModelService = async () => {
|
|
|
696
739
|
smallModelServiceInstance = createSmallModelService({
|
|
697
740
|
buildOpenCodeUrl,
|
|
698
741
|
getOpenCodeAuthHeaders,
|
|
742
|
+
persistSessionMetadata: persistSessionMetadataToStore,
|
|
743
|
+
onSystemSessionPersisted: hideSystemSessionFromIndex,
|
|
699
744
|
});
|
|
700
745
|
}
|
|
701
746
|
return smallModelServiceInstance;
|
|
@@ -705,6 +750,19 @@ const sessionTitleRuntime = createSessionTitleRuntime({
|
|
|
705
750
|
buildOpenCodeUrl,
|
|
706
751
|
getOpenCodeAuthHeaders,
|
|
707
752
|
getSmallModelService,
|
|
753
|
+
serverOpenCodeFetch,
|
|
754
|
+
sessionAccess: createTitleSessionAccess({
|
|
755
|
+
buildOpenCodeUrl,
|
|
756
|
+
getOpenCodeAuthHeaders,
|
|
757
|
+
readSessionMetadata: (sessionID) => sessionMetadataStore.get(sessionID),
|
|
758
|
+
persistSessionMetadata: (sessionID, patch) => persistSessionMetadataToStore(sessionID, patch),
|
|
759
|
+
publishSession: (session, directory) => {
|
|
760
|
+
const payload = { type: 'session.updated', properties: { info: session, directory } };
|
|
761
|
+
broadcastGlobalUiEvent(payload);
|
|
762
|
+
const changed = sessionIndexServiceRef?.upsertAndReportChange(session);
|
|
763
|
+
if (changed) sessionIndexSyncRuntimeRef?.publishChange();
|
|
764
|
+
},
|
|
765
|
+
}),
|
|
708
766
|
});
|
|
709
767
|
|
|
710
768
|
// Forward declaration: question auto-delegate is created after the event hub;
|
|
@@ -713,9 +771,141 @@ let questionAutoDelegateRuntime = null;
|
|
|
713
771
|
/** Filled inside main() once the SQLite session index is constructed. */
|
|
714
772
|
let sessionIndexServiceRef = null;
|
|
715
773
|
|
|
774
|
+
const sessionRecordClient = createHttpSessionRecordClient({
|
|
775
|
+
buildSessionUrl: (sessionID, directory) => {
|
|
776
|
+
const url = new URL(buildOpenCodeUrl(`/session/${encodeURIComponent(sessionID)}`));
|
|
777
|
+
if (directory) url.searchParams.set('directory', directory);
|
|
778
|
+
return url.toString();
|
|
779
|
+
},
|
|
780
|
+
getHeaders: () => getOpenCodeAuthHeaders(),
|
|
781
|
+
fetchFn: wrapFetchWithRuntimeContractGate(fetch),
|
|
782
|
+
});
|
|
783
|
+
const sessionMetadataStore = createSessionMetadataStore({
|
|
784
|
+
dataDir: OPENCHAMBER_DATA_DIR,
|
|
785
|
+
recordReader: (sessionID, directory) => sessionRecordClient.read(sessionID, directory),
|
|
786
|
+
recordWriter: (sessionID, metadata, directory) => sessionRecordClient.write({
|
|
787
|
+
sessionID,
|
|
788
|
+
metadata,
|
|
789
|
+
directory,
|
|
790
|
+
}),
|
|
791
|
+
});
|
|
792
|
+
const stopSessionRecordMigration = startSideStoreMigration({
|
|
793
|
+
load: () => sessionMetadataStore.load(),
|
|
794
|
+
readSession: (sessionID) => sessionRecordClient.read(sessionID),
|
|
795
|
+
writeMetadata: async (sessionID, metadata, record) => {
|
|
796
|
+
const directory = record?.location?.directory || record?.directory || undefined;
|
|
797
|
+
await sessionRecordClient.write({ sessionID, metadata, directory });
|
|
798
|
+
},
|
|
799
|
+
});
|
|
800
|
+
/**
|
|
801
|
+
* load() resolves `{ ok:false }` on read/corrupt failure (does not reject).
|
|
802
|
+
* Callers must check ok / isLoaded — never treat unresolved as empty success.
|
|
803
|
+
*/
|
|
804
|
+
const ensureSessionMetadataReady = async () => {
|
|
805
|
+
try {
|
|
806
|
+
const result = await sessionMetadataStore.load();
|
|
807
|
+
return result?.ok === true && sessionMetadataStore.isLoaded();
|
|
808
|
+
} catch (error) {
|
|
809
|
+
console.warn('[session-metadata] load threw:', error?.message ?? error);
|
|
810
|
+
return false;
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
// Prime without blocking module init; production gates (hub/SSE/routes) await ready.
|
|
814
|
+
void ensureSessionMetadataReady().then((ok) => {
|
|
815
|
+
if (!ok) {
|
|
816
|
+
console.warn(
|
|
817
|
+
'[session-metadata] initial load not ready:',
|
|
818
|
+
sessionMetadataStore.getLoadFailureReason?.() || 'unknown',
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* Goal write through the Host metadata store.
|
|
825
|
+
* Advances executionGeneration on pause/resume/condition changes so late audits
|
|
826
|
+
* cannot commit against a prior execution permit. Broadcasts only after commit.
|
|
827
|
+
*/
|
|
828
|
+
const persistSessionGoalToStore = async (sessionId, _directory, goal) => {
|
|
829
|
+
const result = await sessionMetadataStore.mutateSessionMetadata(sessionId, (current) => {
|
|
830
|
+
const previousGoal = current?.openchamber?.goal && typeof current.openchamber.goal === 'object'
|
|
831
|
+
? current.openchamber.goal
|
|
832
|
+
: null;
|
|
833
|
+
const nextGoal = withGoalExecutionGeneration(previousGoal, goal);
|
|
834
|
+
return { ok: true, patch: { openchamber: { goal: nextGoal } } };
|
|
835
|
+
});
|
|
836
|
+
if (!result?.committed) {
|
|
837
|
+
throw new Error(result?.reason || 'session goal persist was rejected');
|
|
838
|
+
}
|
|
839
|
+
const metadata = result.metadata;
|
|
840
|
+
try {
|
|
841
|
+
broadcastGlobalUiEvent({
|
|
842
|
+
type: 'openchamber:session-metadata',
|
|
843
|
+
properties: { sessionID: sessionId, metadata },
|
|
844
|
+
});
|
|
845
|
+
} catch (error) {
|
|
846
|
+
console.warn('[session-metadata] broadcast failed:', error?.message ?? error);
|
|
847
|
+
}
|
|
848
|
+
return metadata;
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Isolation / Host metadata write. Same store + broadcast seam as goal persist.
|
|
853
|
+
* Callers pass an RFC 7386 merge patch; the store returns the committed object.
|
|
854
|
+
*/
|
|
855
|
+
const persistSessionMetadataToStore = async (sessionId, patch) => {
|
|
856
|
+
const metadata = await sessionMetadataStore.setSessionMetadata(sessionId, patch);
|
|
857
|
+
try {
|
|
858
|
+
broadcastGlobalUiEvent({
|
|
859
|
+
type: 'openchamber:session-metadata',
|
|
860
|
+
properties: { sessionID: sessionId, metadata },
|
|
861
|
+
});
|
|
862
|
+
} catch (error) {
|
|
863
|
+
console.warn('[session-metadata] broadcast failed:', error?.message ?? error);
|
|
864
|
+
}
|
|
865
|
+
return metadata;
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* After Host isolation metadata is committed, drop the session from the
|
|
870
|
+
* sidebar index immediately. Do not wait for the next directory list sync.
|
|
871
|
+
* Reads refs at call time — scheduled-task runtime is constructed before main().
|
|
872
|
+
*/
|
|
873
|
+
const hideSystemSessionFromIndex = ({ sessionID, directory, metadata } = {}) => {
|
|
874
|
+
if (!sessionIndexServiceRef || typeof sessionID !== 'string' || !sessionID) return;
|
|
875
|
+
const changed = sessionIndexServiceRef.upsertAndReportChange({
|
|
876
|
+
id: sessionID,
|
|
877
|
+
directory: directory || '',
|
|
878
|
+
metadata,
|
|
879
|
+
});
|
|
880
|
+
if (changed) {
|
|
881
|
+
sessionIndexSyncRuntimeRef?.publishChange();
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
/** Filled in main() once the session index + broadcast sinks exist. */
|
|
886
|
+
let sessionArchiveServiceRef = null;
|
|
887
|
+
let sessionIndexSyncRuntimeRef = null;
|
|
888
|
+
|
|
889
|
+
const readHostMetadataForSession = (sessionID) => {
|
|
890
|
+
const snap = sessionMetadataStore.getSnapshotSync();
|
|
891
|
+
if (!snap || typeof sessionID !== 'string') return null;
|
|
892
|
+
const host = snap[sessionID];
|
|
893
|
+
return host && typeof host === 'object' && !Array.isArray(host) ? host : null;
|
|
894
|
+
};
|
|
895
|
+
|
|
896
|
+
const projectHostSessionPayload = (payload) => {
|
|
897
|
+
const ready = sessionMetadataStore.isLoaded();
|
|
898
|
+
return projectSessionLifecyclePayload(
|
|
899
|
+
payload,
|
|
900
|
+
readHostMetadataForSession,
|
|
901
|
+
{ hostReady: ready },
|
|
902
|
+
);
|
|
903
|
+
};
|
|
904
|
+
|
|
716
905
|
const sessionGoalRuntime = createSessionGoalRuntime({
|
|
717
906
|
buildOpenCodeUrl,
|
|
718
907
|
getOpenCodeAuthHeaders,
|
|
908
|
+
serverOpenCodeFetch,
|
|
719
909
|
getSmallModelService,
|
|
720
910
|
shouldKeepGoalActiveForQuestion: (sessionId) => (
|
|
721
911
|
questionAutoDelegateRuntime?.isAutoHandling(sessionId) === true
|
|
@@ -726,6 +916,28 @@ const sessionGoalRuntime = createSessionGoalRuntime({
|
|
|
726
916
|
onGoalPaused: (sessionId, directory) => (
|
|
727
917
|
questionAutoDelegateRuntime?.pauseForSessionTree?.(sessionId, directory)
|
|
728
918
|
),
|
|
919
|
+
readSessionMetadata: (sessionId) => sessionMetadataStore.get(sessionId),
|
|
920
|
+
// Conditional commit on the store's exclusive serial boundary (generation +
|
|
921
|
+
// status preconditions share the lock with persist). Broadcast-only on
|
|
922
|
+
// success — do not feed progress writes back into processPayload.
|
|
923
|
+
mutateSessionMetadata: async (sessionId, decide) => {
|
|
924
|
+
const result = await sessionMetadataStore.mutateSessionMetadata(sessionId, decide);
|
|
925
|
+
if (result?.committed) {
|
|
926
|
+
try {
|
|
927
|
+
broadcastGlobalUiEvent({
|
|
928
|
+
type: 'openchamber:session-metadata',
|
|
929
|
+
properties: { sessionID: sessionId, metadata: result.metadata },
|
|
930
|
+
});
|
|
931
|
+
} catch (error) {
|
|
932
|
+
console.warn('[session-metadata] broadcast failed:', error?.message ?? error);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
return result;
|
|
936
|
+
},
|
|
937
|
+
persistSessionGoal: async (sessionId, directory, goal) => {
|
|
938
|
+
const metadata = await persistSessionGoalToStore(sessionId, directory, goal);
|
|
939
|
+
return metadata?.openchamber?.goal ?? goal;
|
|
940
|
+
},
|
|
729
941
|
emitGoalNotification: async ({ sessionId, directory, status, goal }) => {
|
|
730
942
|
// The goal settle notification replaces the per-turn ready notifications
|
|
731
943
|
// (suppressed while the goal is active) — so it obeys the same toggle.
|
|
@@ -766,6 +978,7 @@ const globalMessageStreamHub = createGlobalMessageStreamHub({
|
|
|
766
978
|
buildOpenCodeUrl,
|
|
767
979
|
getOpenCodeAuthHeaders,
|
|
768
980
|
upstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
|
|
981
|
+
projectOutboundSessionPayload: projectHostSessionPayload,
|
|
769
982
|
});
|
|
770
983
|
|
|
771
984
|
const permissionAutoAcceptRuntime = createPermissionAutoAcceptRuntime({
|
|
@@ -908,6 +1121,9 @@ const serverUtilsRuntime = createServerUtilsRuntime({
|
|
|
908
1121
|
openCodeNotReadySince,
|
|
909
1122
|
isOpenCodeReady,
|
|
910
1123
|
isRestartingOpenCode,
|
|
1124
|
+
v1Migration,
|
|
1125
|
+
runtimeContract,
|
|
1126
|
+
openCodeServeVersion,
|
|
911
1127
|
}),
|
|
912
1128
|
getOpenCodeAuthHeaders,
|
|
913
1129
|
buildOpenCodeUrl,
|
|
@@ -934,6 +1150,13 @@ const serverUtilsRuntime = createServerUtilsRuntime({
|
|
|
934
1150
|
}
|
|
935
1151
|
return snapshot.PATH;
|
|
936
1152
|
},
|
|
1153
|
+
getStoredSessionMetadata: () => sessionMetadataStore.getAll(),
|
|
1154
|
+
getStoredSessionMetadataSync: () => sessionMetadataStore.getSnapshotSync(),
|
|
1155
|
+
ensureSessionMetadataReady,
|
|
1156
|
+
onSessionDeleted: (sessionID) => {
|
|
1157
|
+
if (!sessionArchiveServiceRef) return sessionMetadataStore.removeSession(sessionID);
|
|
1158
|
+
return sessionArchiveServiceRef.forgetSession(sessionID);
|
|
1159
|
+
},
|
|
937
1160
|
});
|
|
938
1161
|
|
|
939
1162
|
const setOpenCodePort = (...args) => serverUtilsRuntime.setOpenCodePort(...args);
|
|
@@ -1003,6 +1226,14 @@ Object.defineProperties(openCodeLifecycleState, {
|
|
|
1003
1226
|
lastOpenCodeError: { get: () => lastOpenCodeError, set: (value) => { lastOpenCodeError = value; } },
|
|
1004
1227
|
lastOpenCodeLaunchDiagnostics: { get: () => lastOpenCodeLaunchDiagnostics, set: (value) => { lastOpenCodeLaunchDiagnostics = value; } },
|
|
1005
1228
|
isOpenCodeReady: { get: () => isOpenCodeReady, set: (value) => { isOpenCodeReady = value; } },
|
|
1229
|
+
v1Migration: { get: () => v1Migration, set: (value) => { v1Migration = value; } },
|
|
1230
|
+
openCodeServeVersion: { get: () => openCodeServeVersion, set: (value) => { openCodeServeVersion = value; } },
|
|
1231
|
+
openCodeCliVersion: { get: () => openCodeCliVersion, set: (value) => { openCodeCliVersion = value; } },
|
|
1232
|
+
runtimeContract: { get: () => runtimeContract, set: (value) => { runtimeContract = value; } },
|
|
1233
|
+
runtimeContractGeneration: {
|
|
1234
|
+
get: () => runtimeContractGeneration,
|
|
1235
|
+
set: (value) => { runtimeContractGeneration = value; },
|
|
1236
|
+
},
|
|
1006
1237
|
openCodeNotReadySince: { get: () => openCodeNotReadySince, set: (value) => { openCodeNotReadySince = value; } },
|
|
1007
1238
|
isExternalOpenCode: { get: () => isExternalOpenCode, set: (value) => { isExternalOpenCode = value; } },
|
|
1008
1239
|
isShuttingDown: { get: () => isShuttingDown, set: (value) => { isShuttingDown = value; } },
|
|
@@ -1047,7 +1278,10 @@ const openCodeLifecycleRuntime = createOpenCodeLifecycleRuntime({
|
|
|
1047
1278
|
normalizeApiPrefix,
|
|
1048
1279
|
applyOpencodeBinaryFromSettings,
|
|
1049
1280
|
ensureOpencodeCliEnv,
|
|
1281
|
+
ensurePinnedOpenCode2CliEnv,
|
|
1050
1282
|
ensureLocalOpenCodeServerPassword,
|
|
1283
|
+
adoptOpenCodeServerPassword,
|
|
1284
|
+
sharedService: isSharedServiceEnabled() ? createSharedOpenCodeService() : null,
|
|
1051
1285
|
resolveManagedOpenCodeLaunchSpec,
|
|
1052
1286
|
setOpenCodePort,
|
|
1053
1287
|
setDetectedOpenCodeApiPrefix,
|
|
@@ -1059,6 +1293,26 @@ const openCodeLifecycleRuntime = createOpenCodeLifecycleRuntime({
|
|
|
1059
1293
|
getManagedOpenCodeShellEnvSnapshot: getLoginShellEnvSnapshot,
|
|
1060
1294
|
managedCapabilitiesRuntime,
|
|
1061
1295
|
getActiveSessionCount,
|
|
1296
|
+
// Most-recently-used directories first: OpenCode initializes each directory
|
|
1297
|
+
// lazily on first request (seconds on large session stores), so the
|
|
1298
|
+
// lifecycle warms these right after readiness — before the UI's first
|
|
1299
|
+
// interactive request would otherwise pay that cost.
|
|
1300
|
+
getWarmupDirectories: async () => {
|
|
1301
|
+
const settings = await readSettingsFromDiskMigrated().catch(() => null);
|
|
1302
|
+
if (!settings) return [];
|
|
1303
|
+
const directories = [];
|
|
1304
|
+
if (typeof settings.lastDirectory === 'string' && settings.lastDirectory) {
|
|
1305
|
+
directories.push(settings.lastDirectory);
|
|
1306
|
+
}
|
|
1307
|
+
const projects = Array.isArray(settings.projects) ? [...settings.projects] : [];
|
|
1308
|
+
projects.sort((a, b) => (b?.lastOpenedAt ?? 0) - (a?.lastOpenedAt ?? 0));
|
|
1309
|
+
for (const project of projects) {
|
|
1310
|
+
if (typeof project?.path === 'string' && project.path) {
|
|
1311
|
+
directories.push(project.path);
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
return [...new Set(directories)];
|
|
1315
|
+
},
|
|
1062
1316
|
});
|
|
1063
1317
|
|
|
1064
1318
|
const restartOpenCode = (...args) => openCodeLifecycleRuntime.restartOpenCode(...args);
|
|
@@ -1081,6 +1335,25 @@ const scheduledTasksRuntime = createScheduledTasksRuntime({
|
|
|
1081
1335
|
getSmallModelService,
|
|
1082
1336
|
waitForOpenCodeReady,
|
|
1083
1337
|
runHistoryStore: scheduledTaskRunHistoryStore,
|
|
1338
|
+
// Same Host store seam as session-goal / manual UI metadata writes.
|
|
1339
|
+
readSessionMetadata: (sessionId) => sessionMetadataStore.get(sessionId),
|
|
1340
|
+
persistSessionMetadata: persistSessionMetadataToStore,
|
|
1341
|
+
onSystemSessionPersisted: hideSystemSessionFromIndex,
|
|
1342
|
+
persistSessionGoal: persistSessionGoalToStore,
|
|
1343
|
+
// Arm the goal loop after first persist only — do not feed progress writes
|
|
1344
|
+
// back through processPayload (session-goal runtime already broadcasts those).
|
|
1345
|
+
onGoalPersisted: ({ sessionID, directory, metadata }) => {
|
|
1346
|
+
sessionGoalRuntime.processPayload({
|
|
1347
|
+
type: 'session.updated',
|
|
1348
|
+
properties: {
|
|
1349
|
+
info: {
|
|
1350
|
+
id: sessionID,
|
|
1351
|
+
directory: directory || '',
|
|
1352
|
+
metadata,
|
|
1353
|
+
},
|
|
1354
|
+
},
|
|
1355
|
+
}, directory || '');
|
|
1356
|
+
},
|
|
1084
1357
|
emitTaskRunEvent: (event) => {
|
|
1085
1358
|
for (const client of uiOpenChamberEventClients) {
|
|
1086
1359
|
try {
|
|
@@ -1108,7 +1381,19 @@ const ensureGlobalWatcherStarted = async () => {
|
|
|
1108
1381
|
return globalWatcherStartPromise;
|
|
1109
1382
|
}
|
|
1110
1383
|
|
|
1111
|
-
|
|
1384
|
+
// Await Host metadata ready before the internal hub attaches upstream SSE so
|
|
1385
|
+
// session lifecycle frames are projected (not dropped) from the first event.
|
|
1386
|
+
globalWatcherStartPromise = (async () => {
|
|
1387
|
+
const ready = await ensureSessionMetadataReady();
|
|
1388
|
+
if (!ready) {
|
|
1389
|
+
const reason = sessionMetadataStore.getLoadFailureReason?.() || 'not ready';
|
|
1390
|
+
const error = new Error(`session metadata unavailable before global watcher start: ${reason}`);
|
|
1391
|
+
error.code = 'session_metadata_unavailable';
|
|
1392
|
+
error.retryable = true;
|
|
1393
|
+
throw error;
|
|
1394
|
+
}
|
|
1395
|
+
return openCodeWatcherRuntime.start();
|
|
1396
|
+
})().catch((error) => {
|
|
1112
1397
|
globalWatcherStartPromise = null;
|
|
1113
1398
|
throw error;
|
|
1114
1399
|
});
|
|
@@ -1118,15 +1403,30 @@ const ensureGlobalWatcherStarted = async () => {
|
|
|
1118
1403
|
|
|
1119
1404
|
const completeOpenCodeStartup = () => {
|
|
1120
1405
|
scheduleOpenCodeApiDetection();
|
|
1121
|
-
if (
|
|
1406
|
+
if (
|
|
1407
|
+
(openCodeLifecycleState.openCodeProcess && !openCodeLifecycleState.isExternalOpenCode)
|
|
1408
|
+
|| openCodeLifecycleRuntime.isSharedOpenCodeService()
|
|
1409
|
+
) {
|
|
1122
1410
|
startHealthMonitoring();
|
|
1123
1411
|
}
|
|
1124
1412
|
// The global watcher used to start only for desktop notifications; session-title
|
|
1125
1413
|
// and session-goal also ride its event hub, so it now starts unconditionally
|
|
1126
|
-
// once OpenCode is up.
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1414
|
+
// once OpenCode is up. Controlled retry when metadata is not yet ready.
|
|
1415
|
+
const startWatcherWithRetry = (attempt = 0) => {
|
|
1416
|
+
void ensureGlobalWatcherStarted().catch((error) => {
|
|
1417
|
+
const retryable = error?.retryable === true || error?.code === 'session_metadata_unavailable';
|
|
1418
|
+
const delays = [500, 1_500, 3_000, 6_000, 12_000];
|
|
1419
|
+
if (retryable && attempt < delays.length) {
|
|
1420
|
+
console.warn(
|
|
1421
|
+
`Global event watcher deferred (metadata): ${error?.message || error}; retry ${attempt + 1}/${delays.length}`,
|
|
1422
|
+
);
|
|
1423
|
+
setTimeout(() => startWatcherWithRetry(attempt + 1), delays[attempt]);
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
console.warn(`Global event watcher startup failed: ${error?.message || error}`);
|
|
1427
|
+
});
|
|
1428
|
+
};
|
|
1429
|
+
startWatcherWithRetry();
|
|
1130
1430
|
};
|
|
1131
1431
|
|
|
1132
1432
|
const bootstrapOpenCodeAtStartup = async (...args) => {
|
|
@@ -1138,7 +1438,6 @@ const retryOpenCodeStartup = async (...args) => {
|
|
|
1138
1438
|
await openCodeLifecycleRuntime.retryOpenCodeStartup(...args);
|
|
1139
1439
|
completeOpenCodeStartup();
|
|
1140
1440
|
};
|
|
1141
|
-
const killProcessOnPort = (...args) => openCodeLifecycleRuntime.killProcessOnPort(...args);
|
|
1142
1441
|
const waitForPortRelease = (...args) => openCodeLifecycleRuntime.waitForPortRelease(...args);
|
|
1143
1442
|
|
|
1144
1443
|
const fetchAgentsSnapshot = (...args) => serverUtilsRuntime.fetchAgentsSnapshot(...args);
|
|
@@ -1175,7 +1474,6 @@ const gracefulShutdownRuntime = createGracefulShutdownRuntime({
|
|
|
1175
1474
|
setOpenCodeProcess: (value) => {
|
|
1176
1475
|
openCodeProcess = value;
|
|
1177
1476
|
},
|
|
1178
|
-
killProcessOnPort,
|
|
1179
1477
|
waitForPortRelease,
|
|
1180
1478
|
getServer: () => server,
|
|
1181
1479
|
getUiAuthController: () => uiAuthController,
|
|
@@ -1350,6 +1648,15 @@ async function main(options = {}) {
|
|
|
1350
1648
|
buildOpenCodeUrl,
|
|
1351
1649
|
getOpenCodeAuthHeaders,
|
|
1352
1650
|
waitForOpenCodeReady,
|
|
1651
|
+
projectSessions: (sessions) => {
|
|
1652
|
+
const snap = sessionMetadataStore.getSnapshotSync();
|
|
1653
|
+
// Not ready / unavailable — throw so sync keeps prior directory rows.
|
|
1654
|
+
// A missing side-store row must not drop a session OpenCode still has.
|
|
1655
|
+
if (!snap) {
|
|
1656
|
+
throw new Error('session metadata is unavailable: Host store not ready');
|
|
1657
|
+
}
|
|
1658
|
+
return retainOpenCodeSessions(sessions, snap);
|
|
1659
|
+
},
|
|
1353
1660
|
onRevisionTip: (tip) => {
|
|
1354
1661
|
broadcastOpenChamberEvent({
|
|
1355
1662
|
type: 'openchamber:session-index-changed',
|
|
@@ -1357,8 +1664,43 @@ async function main(options = {}) {
|
|
|
1357
1664
|
});
|
|
1358
1665
|
},
|
|
1359
1666
|
});
|
|
1667
|
+
sessionIndexSyncRuntimeRef = sessionIndexSyncRuntime;
|
|
1668
|
+
|
|
1669
|
+
sessionArchiveServiceRef = createSessionArchiveService({
|
|
1670
|
+
sessionMetadataStore,
|
|
1671
|
+
fetchUpstreamSession: createUpstreamSessionFetcher({
|
|
1672
|
+
buildOpenCodeUrl,
|
|
1673
|
+
getOpenCodeAuthHeaders,
|
|
1674
|
+
}),
|
|
1675
|
+
sessionIndexService,
|
|
1676
|
+
broadcastSessionEvent: (payload, options = {}) => {
|
|
1677
|
+
try {
|
|
1678
|
+
broadcastGlobalUiEvent(payload, options);
|
|
1679
|
+
} catch (error) {
|
|
1680
|
+
console.warn('[session-archive] global UI broadcast failed:', error?.message ?? error);
|
|
1681
|
+
}
|
|
1682
|
+
try {
|
|
1683
|
+
broadcastOpenChamberEvent(payload);
|
|
1684
|
+
} catch (error) {
|
|
1685
|
+
console.warn('[session-archive] openchamber event broadcast failed:', error?.message ?? error);
|
|
1686
|
+
}
|
|
1687
|
+
},
|
|
1688
|
+
onIndexChanged: () => {
|
|
1689
|
+
sessionIndexSyncRuntimeRef?.publishChange();
|
|
1690
|
+
},
|
|
1691
|
+
});
|
|
1692
|
+
|
|
1360
1693
|
const unsubscribeSessionIndexEvents = globalMessageStreamHub.subscribeEvent((event) => {
|
|
1361
|
-
if (applySessionIndexEvent(sessionIndexService, event)
|
|
1694
|
+
if (applySessionIndexEvent(sessionIndexService, event, Date.now(), {
|
|
1695
|
+
isHostReady: () => sessionMetadataStore.isLoaded(),
|
|
1696
|
+
projectSession: (session) => {
|
|
1697
|
+
if (!sessionMetadataStore.isLoaded()) return null;
|
|
1698
|
+
const snap = sessionMetadataStore.getSnapshotSync();
|
|
1699
|
+
if (!snap) return null;
|
|
1700
|
+
return projectSessionWithStoredMap(session, snap);
|
|
1701
|
+
},
|
|
1702
|
+
onSessionDeleted: (sessionID) => sessionArchiveServiceRef?.forgetSession(sessionID),
|
|
1703
|
+
})) {
|
|
1362
1704
|
sessionIndexSyncRuntime?.publishChange();
|
|
1363
1705
|
}
|
|
1364
1706
|
});
|
|
@@ -1424,6 +1766,9 @@ async function main(options = {}) {
|
|
|
1424
1766
|
}));
|
|
1425
1767
|
expressApp = app;
|
|
1426
1768
|
server = http.createServer(app);
|
|
1769
|
+
// Track server-owned sockets so forceCloseConnections can destroy upgraded
|
|
1770
|
+
// WS/SSE leftovers that closeAllConnections does not release.
|
|
1771
|
+
attachHttpServerConnectionTracker(server);
|
|
1427
1772
|
let realtimeProxyRuntime = { stop: () => {} };
|
|
1428
1773
|
|
|
1429
1774
|
// The relay service is constructed further below (it depends on the active
|
|
@@ -1444,11 +1789,16 @@ async function main(options = {}) {
|
|
|
1444
1789
|
return {
|
|
1445
1790
|
openCodePort,
|
|
1446
1791
|
openCodeRunning: Boolean(openCodePort && isOpenCodeReady && !isRestartingOpenCode),
|
|
1792
|
+
openCodeStarting: Boolean(!isOpenCodeReady && !lastOpenCodeError),
|
|
1447
1793
|
openCodeSecureConnection: isOpenCodeConnectionSecure(),
|
|
1448
1794
|
openCodeAuthSource: openCodeAuthSource || null,
|
|
1449
1795
|
openCodeApiPrefix: '',
|
|
1450
1796
|
openCodeApiPrefixDetected: true,
|
|
1451
1797
|
isOpenCodeReady,
|
|
1798
|
+
v1Migration,
|
|
1799
|
+
openCodeServeVersion,
|
|
1800
|
+
openCodeCliVersion,
|
|
1801
|
+
runtimeContract,
|
|
1452
1802
|
lastOpenCodeError,
|
|
1453
1803
|
lastOpenCodeLaunchDiagnostics,
|
|
1454
1804
|
opencodeBinaryResolved: resolvedOpencodeBinary || null,
|
|
@@ -1559,6 +1909,8 @@ async function main(options = {}) {
|
|
|
1559
1909
|
setAutoAcceptSession,
|
|
1560
1910
|
sessionIndexService,
|
|
1561
1911
|
sessionIndexSyncRuntime,
|
|
1912
|
+
// Production snapshot/lookup filter: committed Host archive authority.
|
|
1913
|
+
getCommittedHostMetadata: async () => sessionMetadataStore.getAll(),
|
|
1562
1914
|
transcriptCacheService,
|
|
1563
1915
|
});
|
|
1564
1916
|
uiAuthController = bootstrapResult.uiAuthController;
|
|
@@ -1653,6 +2005,57 @@ async function main(options = {}) {
|
|
|
1653
2005
|
isUnsafeSkillRelativePath,
|
|
1654
2006
|
buildOpenCodeUrl,
|
|
1655
2007
|
getOpenCodeAuthHeaders,
|
|
2008
|
+
getIsExternalOpenCode: () => isExternalOpenCode,
|
|
2009
|
+
getIsSharedOpenCodeService: () => openCodeLifecycleRuntime.isSharedOpenCodeService(),
|
|
2010
|
+
forceResolvedOpenCodeBinary,
|
|
2011
|
+
restartOpenCode,
|
|
2012
|
+
waitForOpenCodeReady,
|
|
2013
|
+
getRuntimeContract: () => runtimeContract,
|
|
2014
|
+
getOpenCodeServeVersion: () => openCodeServeVersion,
|
|
2015
|
+
getOpenCodeCliVersion: () => openCodeCliVersion,
|
|
2016
|
+
getResolvedOpenCodeBinary: () => resolvedOpencodeBinary,
|
|
2017
|
+
getResolvedOpenCodeBinarySource: () => resolvedOpencodeBinarySource,
|
|
2018
|
+
getActiveSessionCount,
|
|
2019
|
+
sessionMetadataStore,
|
|
2020
|
+
sessionArchiveService: {
|
|
2021
|
+
setArchive: (...args) => {
|
|
2022
|
+
if (!sessionArchiveServiceRef) {
|
|
2023
|
+
const error = new Error('session archive is not configured');
|
|
2024
|
+
error.status = 503;
|
|
2025
|
+
throw error;
|
|
2026
|
+
}
|
|
2027
|
+
return sessionArchiveServiceRef.setArchive(...args);
|
|
2028
|
+
},
|
|
2029
|
+
archiveSession: (...args) => {
|
|
2030
|
+
if (!sessionArchiveServiceRef) {
|
|
2031
|
+
const error = new Error('session archive is not configured');
|
|
2032
|
+
error.status = 503;
|
|
2033
|
+
throw error;
|
|
2034
|
+
}
|
|
2035
|
+
return sessionArchiveServiceRef.archiveSession(...args);
|
|
2036
|
+
},
|
|
2037
|
+
},
|
|
2038
|
+
// Same store seam as sessionGoalRuntime / scheduledTasksRuntime.
|
|
2039
|
+
readSessionMetadata: (sessionId) => sessionMetadataStore.get(sessionId),
|
|
2040
|
+
persistSessionMetadata: persistSessionMetadataToStore,
|
|
2041
|
+
onSystemSessionPersisted: hideSystemSessionFromIndex,
|
|
2042
|
+
persistSessionGoal: persistSessionGoalToStore,
|
|
2043
|
+
onSessionMetadataWritten: ({ sessionID, directory, metadata }) => {
|
|
2044
|
+
sessionTitleRuntime.processPayload({
|
|
2045
|
+
type: 'openchamber:session-metadata',
|
|
2046
|
+
properties: { sessionID, directory, metadata },
|
|
2047
|
+
}, directory || '');
|
|
2048
|
+
sessionGoalRuntime.processPayload({
|
|
2049
|
+
type: 'session.updated',
|
|
2050
|
+
properties: {
|
|
2051
|
+
info: {
|
|
2052
|
+
id: sessionID,
|
|
2053
|
+
directory: directory || '',
|
|
2054
|
+
metadata,
|
|
2055
|
+
},
|
|
2056
|
+
},
|
|
2057
|
+
}, directory || '');
|
|
2058
|
+
},
|
|
1656
2059
|
getSmallModelService,
|
|
1657
2060
|
getOpenCodePort: () => openCodePort,
|
|
1658
2061
|
buildAugmentedPath,
|
|
@@ -1704,6 +2107,8 @@ async function main(options = {}) {
|
|
|
1704
2107
|
getOpenCodeAuthHeaders,
|
|
1705
2108
|
globalEventHub: globalMessageStreamHub,
|
|
1706
2109
|
processForwardedEventPayload,
|
|
2110
|
+
projectOutboundSessionPayload: projectHostSessionPayload,
|
|
2111
|
+
ensureSessionMetadataReady,
|
|
1707
2112
|
messageStreamWsClients: uiNotificationWsClients,
|
|
1708
2113
|
upstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
|
|
1709
2114
|
terminalHeartbeatIntervalMs: TERMINAL_INPUT_WS_HEARTBEAT_INTERVAL_MS,
|
|
@@ -1773,12 +2178,9 @@ async function main(options = {}) {
|
|
|
1773
2178
|
restartOpenCode: () => restartOpenCode(),
|
|
1774
2179
|
getOpenCodeProcessInfo: () => {
|
|
1775
2180
|
const managed = Boolean((openCodeProcess || openCodePort) && !ENV_SKIP_OPENCODE_START && !isExternalOpenCode);
|
|
1776
|
-
// Only ever expose pid/port for a server WE manage.
|
|
1777
|
-
//
|
|
1778
|
-
//
|
|
1779
|
-
// let a single miscomputed `managed` flag take down the user's separate
|
|
1780
|
-
// server. Structurally withhold what isn't ours so the killer has no
|
|
1781
|
-
// target, instead of relying on the flag check alone.
|
|
2181
|
+
// Only ever expose pid/port for a server WE manage. Desktop no longer runs a
|
|
2182
|
+
// post-stop detached killer of a pre-captured pid; still withhold non-owned
|
|
2183
|
+
// process identity so diagnostics cannot imply we may kill an external serve.
|
|
1782
2184
|
return {
|
|
1783
2185
|
managed,
|
|
1784
2186
|
pid: managed && typeof openCodeProcess?.pid === 'number' ? openCodeProcess.pid : null,
|
|
@@ -1792,6 +2194,8 @@ async function main(options = {}) {
|
|
|
1792
2194
|
unsubscribeScheduledTaskEvents();
|
|
1793
2195
|
sessionIndexSyncRuntime?.stop();
|
|
1794
2196
|
sessionIndexService?.close();
|
|
2197
|
+
sessionArchiveServiceRef?.stop?.();
|
|
2198
|
+
stopSessionRecordMigration();
|
|
1795
2199
|
} catch {
|
|
1796
2200
|
// The index is a local cache; a failed close must not block shutdown.
|
|
1797
2201
|
}
|
|
@@ -1819,11 +2223,10 @@ async function main(options = {}) {
|
|
|
1819
2223
|
// best-effort shutdown of the dictation worker
|
|
1820
2224
|
}
|
|
1821
2225
|
try {
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
}
|
|
2226
|
+
const { stopLlmTempDirectory } = await import('./lib/llm/temp-directory.js');
|
|
2227
|
+
await stopLlmTempDirectory();
|
|
1825
2228
|
} catch {
|
|
1826
|
-
// best-effort cleanup of the
|
|
2229
|
+
// best-effort cleanup of the LLM generator temp OpenCode directory
|
|
1827
2230
|
}
|
|
1828
2231
|
return gracefulShutdown({
|
|
1829
2232
|
exitProcess: shutdownOptions.exitProcess ?? false,
|