@openchambery/web 2.0.0-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 +15 -11
- package/bin/cli-opencode.test.js +4 -4
- package/bin/cli.js +1 -1
- package/bin/lib/cli-startup.js +1 -1
- package/bin/lib/cli-startup.test.js +18 -4
- package/dist/assets/{AgentAvatar-CLWWNu_Q.js → AgentAvatar-CzTtVMnI.js} +1 -1
- package/dist/assets/AssistantView-Cg1qQvVe.js +3 -0
- package/dist/assets/{DiagramView-xuSJTnv7.js → DiagramView-hOi72Wdx.js} +1 -1
- package/dist/assets/{FadeInOnReveal-Ov0D96d0.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-SKi4oG0c.js → MarkdownRendererImpl-YM7iRmzK.js} +3 -3
- package/dist/assets/MarkstreamRendererImpl-BDy_oGJQ.js +3 -0
- package/dist/assets/{MobileDetailNavigation-Bnx59U_J.js → MobileDetailNavigation-iX_hb_Xt.js} +1 -1
- package/dist/assets/{MobileShareBridge-BQlP4J-F.js → MobileShareBridge-CAMUupwR.js} +2 -2
- package/dist/assets/MobileSurface-CHbdPcLH.js +2 -0
- package/dist/assets/{MultiRunWindow-ChZGob0v.js → MultiRunWindow-Ci1ODFFX.js} +1 -1
- package/dist/assets/{OnboardingScreen-DtQJxZG-.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-DfnsFa8y.js → SettingsWindow-B8d8qIQ7.js} +1 -1
- package/dist/assets/TerminalView-CMiw3s_c.js +8 -0
- package/dist/assets/{ToolOutputDialog-BejmjrRk.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-D-rATN7w.js → button-DIIrsMjW.js} +1 -1
- package/dist/assets/{collapsible-BXRd5_Hr.js → collapsible-CnvUeYst.js} +1 -1
- package/dist/assets/{context-menu-jGtH6fR9.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-DQf7Y_uR.js → diagram-rvn7_qBM.js} +1 -1
- package/dist/assets/{dialog-bfbvR4VH.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-8r6F_Fza.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-CCE_4y5F.js → main-B7t9lavz.js} +2 -2
- 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-1Qo6y6IJ.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-CPElzJ0n.js +3 -0
- 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-BMvqa5we.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-gh-hVRIc.js → sessionLookup-Bss8M20i.js} +1 -1
- package/dist/assets/{sortable-tabs-strip-CudoSgV4.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-DiF6JmBP.js → terminalApi-mDR2jXTo.js} +1 -1
- package/dist/assets/textarea-XD2oX_Ee.js +1 -0
- package/dist/assets/{tooltip-CQvpK-UV.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-Cpmpo7Wb.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-DcbXQOkc.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-Bqn4AiBL.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/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 +359 -63
- package/server/lib/assistants/DOCUMENTATION.md +14 -9
- package/server/lib/assistants/contracts.js +11 -1
- package/server/lib/assistants/projection-history.test.js +265 -18
- package/server/lib/assistants/routes.js +6 -0
- package/server/lib/assistants/service.js +417 -231
- package/server/lib/assistants/service.test.js +392 -148
- 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 +1 -1
- package/server/lib/conversations/service.js +1 -0
- package/server/lib/conversations/service.test.js +16 -0
- 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 +49 -4
- 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 +33 -9
- package/server/lib/llm/catalog.js +1 -1
- package/server/lib/llm/completions.js +5 -1
- package/server/lib/llm/completions.test.js +3 -3
- package/server/lib/llm/generate.js +237 -145
- package/server/lib/llm/generate.test.js +201 -46
- package/server/lib/llm/routes.js +2 -0
- package/server/lib/message-queue/runtime.js +15 -2
- 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 +89 -17
- 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 +42 -99
- package/server/lib/opencode/config-entity-routes.test.js +107 -0
- 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 +1 -2
- package/server/lib/opencode/env-runtime.js +40 -26
- package/server/lib/opencode/env-runtime.test.js +10 -17
- package/server/lib/opencode/feature-routes-runtime.js +53 -4
- 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 +349 -39
- package/server/lib/opencode/lifecycle.test.js +322 -0
- 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/openchamber-routes.js +7 -1
- package/server/lib/opencode/opencode2-pin.js +4 -4
- package/server/lib/opencode/opencode2-pin.test.js +1 -0
- package/server/lib/opencode/opencode2-sidecar.e2e.test.js +127 -4
- 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-routes.js +3 -18
- package/server/lib/opencode/plugin-routes.test.js +9 -9
- 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 +254 -46
- package/server/lib/opencode/proxy.test.js +238 -5
- package/server/lib/opencode/routes.js +326 -62
- package/server/lib/opencode/routes.test.js +278 -12
- 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 +33 -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 +20 -33
- package/server/lib/opencode/skill-routes.test.js +35 -2
- 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/v2-client.js +14 -3
- 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/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 +8 -0
- package/server/lib/scheduled-tasks/runtime.js +52 -4
- package/server/lib/scheduled-tasks/runtime.test.js +80 -1
- package/server/lib/session-goal/DOCUMENTATION.md +113 -13
- package/server/lib/session-goal/routes.js +9 -0
- package/server/lib/session-goal/runtime.js +1579 -117
- package/server/lib/session-goal/runtime.test.js +1453 -84
- 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 +161 -34
- package/server/lib/session-index/sync-runtime.test.js +155 -1
- package/server/lib/session-metadata/DOCUMENTATION.md +73 -18
- 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 +112 -9
- package/server/lib/session-metadata/routes.test.js +47 -2
- 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 +270 -83
- package/server/lib/session-metadata/session-metadata-store.test.js +205 -10
- 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 +9 -8
- package/server/lib/session-turn-pages/routes.js +17 -102
- package/server/lib/session-turn-pages/routes.test.js +281 -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 -147
- package/server/lib/small-model/catalog.js +31 -51
- package/server/lib/small-model/catalog.test.js +65 -10
- 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 +124 -240
- 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 +2 -0
- package/dist/assets/AssistantView-BTCkm8yk.js +0 -3
- package/dist/assets/Icon-DD-BuMfZ.js +0 -1
- package/dist/assets/MarkdownRenderer-bc_p1H7l.js +0 -2
- package/dist/assets/MarkstreamRendererImpl-CnkodGJW.js +0 -3
- package/dist/assets/MobileSurface-BXLeiZ4d.js +0 -2
- package/dist/assets/OverlayScrollbar-pMwxaCca.js +0 -2
- package/dist/assets/SettingsView-B5I0KDTZ.js +0 -25
- package/dist/assets/TerminalView-Dh9MWCpS.js +0 -8
- package/dist/assets/appThemeRegistry-COGfxTFV.js +0 -1
- package/dist/assets/es-c52LTHHe.js +0 -15
- package/dist/assets/fileMentionTouchSelection-BvrNCroG.js +0 -4
- package/dist/assets/fr-PisFbUE8.js +0 -13
- package/dist/assets/gitApi-ButwzQ0N.js +0 -9
- package/dist/assets/insertionBoundaries-DGs7S5zv.js +0 -1
- package/dist/assets/ja-C8Ikun3Z.js +0 -15
- package/dist/assets/ko-ClFys5o2.js +0 -15
- package/dist/assets/main-Dn9rpsgl.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-BpjxVqgg.js +0 -2
- package/dist/assets/mobile-nMJCaNq1.js +0 -2
- package/dist/assets/multirun-BvSG94mW.js +0 -4
- package/dist/assets/persistence-Ce3AnpEr.js +0 -3
- package/dist/assets/pl-CnaKWN5F.js +0 -15
- package/dist/assets/platform-CWTIp02q.js +0 -4
- package/dist/assets/projectMeta-DOe49dM_.js +0 -3
- package/dist/assets/pt-BR-s8OpfRI6.js +0 -15
- package/dist/assets/renderElectronMiniChatApp-R6dKh79f.js +0 -2
- package/dist/assets/renderMobileApp-y-S8y8v_.js +0 -28
- package/dist/assets/runtime-fetch-zIalUnbb.js +0 -1
- package/dist/assets/runtimeEndpointReset-B6BxhvR0.js +0 -147
- package/dist/assets/sessionChangeSummary-VVBlEXuh.js +0 -2
- package/dist/assets/src-BzX5UI-c.css +0 -2
- package/dist/assets/store-DJczmczv.js +0 -15
- package/dist/assets/textarea-3XR8sUfy.js +0 -1
- package/dist/assets/uk-CaX0iqkB.js +0 -15
- package/dist/assets/useDesktopWindowControlsLayout-B1GX59-L.js +0 -1
- package/dist/assets/useEffectiveDirectory-CN6JoCFw.js +0 -1
- package/dist/assets/useMobileNavigationStore-BVjFtXSy.js +0 -414
- package/dist/assets/useSessionAutoCleanup-BLjymaFt.js +0 -2
- package/dist/assets/useUIStore-Bxv3f23A.js +0 -1
- package/dist/assets/vendor-opencode-client-BOe2qpQb.js +0 -12
- package/dist/assets/zh-CN-20MYEjha.js +0 -15
- package/dist/assets/zh-TW-DiN04qTw.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 -183
- package/server/lib/small-model/opencode-session.test.js +0 -147
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,8 +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';
|
|
72
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';
|
|
73
96
|
import { createScheduledTasksRuntime } from './lib/scheduled-tasks/runtime.js';
|
|
74
97
|
import { createScheduledTaskRunHistoryStore } from './lib/scheduled-tasks/run-history-store.js';
|
|
75
98
|
import { createServerStartupRuntime } from './lib/opencode/server-startup-runtime.js';
|
|
@@ -89,6 +112,7 @@ import { createNotificationTemplateRuntime } from './lib/notifications/template-
|
|
|
89
112
|
import { createPermissionAutoAcceptRuntime } from './lib/permission-auto-accept/runtime.js';
|
|
90
113
|
import { createQuestionAutoDelegateRuntime } from './lib/question-auto-delegate/runtime.js';
|
|
91
114
|
import { createGracefulShutdownRuntime } from './lib/opencode/shutdown-runtime.js';
|
|
115
|
+
import { attachHttpServerConnectionTracker } from './lib/opencode/http-server-connections.js';
|
|
92
116
|
import { createProjectConfigRuntime } from './lib/projects/project-config.js';
|
|
93
117
|
import { createRemoteClientAuthRuntime } from './lib/client-auth/remote-clients.js';
|
|
94
118
|
import { applyRuntimeCorsHeaders } from './lib/request-cors.js';
|
|
@@ -447,6 +471,11 @@ let lastOpenCodeError = null;
|
|
|
447
471
|
let lastOpenCodeLaunchDiagnostics = null;
|
|
448
472
|
let isOpenCodeReady = false;
|
|
449
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;
|
|
450
479
|
let openCodeNotReadySince = 0;
|
|
451
480
|
let isExternalOpenCode = false;
|
|
452
481
|
let exitOnShutdown = true;
|
|
@@ -551,6 +580,7 @@ const openCodeAuthStateRuntime = createOpenCodeAuthStateRuntime({
|
|
|
551
580
|
const getOpenCodeAuthHeaders = (...args) => openCodeAuthStateRuntime.getOpenCodeAuthHeaders(...args);
|
|
552
581
|
const isOpenCodeConnectionSecure = (...args) => openCodeAuthStateRuntime.isOpenCodeConnectionSecure(...args);
|
|
553
582
|
const ensureLocalOpenCodeServerPassword = (...args) => openCodeAuthStateRuntime.ensureLocalOpenCodeServerPassword(...args);
|
|
583
|
+
const adoptOpenCodeServerPassword = (...args) => openCodeAuthStateRuntime.adoptOpenCodeServerPassword(...args);
|
|
554
584
|
|
|
555
585
|
const openCodeNetworkState = {};
|
|
556
586
|
Object.defineProperties(openCodeNetworkState, {
|
|
@@ -574,6 +604,15 @@ const buildOpenCodeUrl = (...args) => openCodeNetworkRuntime.buildOpenCodeUrl(..
|
|
|
574
604
|
const ensureOpenCodeApiPrefix = (...args) => openCodeNetworkRuntime.ensureOpenCodeApiPrefix(...args);
|
|
575
605
|
const scheduleOpenCodeApiDetection = (...args) => openCodeNetworkRuntime.scheduleOpenCodeApiDetection(...args);
|
|
576
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
|
+
|
|
577
616
|
const ENV_CONFIGURED_API_PREFIX = normalizeApiPrefix(
|
|
578
617
|
process.env.OPENCODE_API_PREFIX || process.env.OPENCHAMBER_API_PREFIX || ''
|
|
579
618
|
);
|
|
@@ -624,6 +663,7 @@ const searchPathFor = (...args) => openCodeEnvRuntime.searchPathFor(...args);
|
|
|
624
663
|
const resolveGitBinaryForSpawn = (...args) => openCodeEnvRuntime.resolveGitBinaryForSpawn(...args);
|
|
625
664
|
const resolveManagedOpenCodeLaunchSpec = (...args) => openCodeEnvRuntime.resolveManagedOpenCodeLaunchSpec(...args);
|
|
626
665
|
const clearResolvedOpenCodeBinary = (...args) => openCodeEnvRuntime.clearResolvedOpenCodeBinary(...args);
|
|
666
|
+
const forceResolvedOpenCodeBinary = (...args) => openCodeEnvRuntime.forceResolvedOpenCodeBinary(...args);
|
|
627
667
|
const openCodeResolutionRuntime = createOpenCodeResolutionRuntime({
|
|
628
668
|
path,
|
|
629
669
|
resolveOpencodeCliPath,
|
|
@@ -699,6 +739,8 @@ const getSmallModelService = async () => {
|
|
|
699
739
|
smallModelServiceInstance = createSmallModelService({
|
|
700
740
|
buildOpenCodeUrl,
|
|
701
741
|
getOpenCodeAuthHeaders,
|
|
742
|
+
persistSessionMetadata: persistSessionMetadataToStore,
|
|
743
|
+
onSystemSessionPersisted: hideSystemSessionFromIndex,
|
|
702
744
|
});
|
|
703
745
|
}
|
|
704
746
|
return smallModelServiceInstance;
|
|
@@ -708,6 +750,19 @@ const sessionTitleRuntime = createSessionTitleRuntime({
|
|
|
708
750
|
buildOpenCodeUrl,
|
|
709
751
|
getOpenCodeAuthHeaders,
|
|
710
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
|
+
}),
|
|
711
766
|
});
|
|
712
767
|
|
|
713
768
|
// Forward declaration: question auto-delegate is created after the event hub;
|
|
@@ -716,11 +771,141 @@ let questionAutoDelegateRuntime = null;
|
|
|
716
771
|
/** Filled inside main() once the SQLite session index is constructed. */
|
|
717
772
|
let sessionIndexServiceRef = null;
|
|
718
773
|
|
|
719
|
-
const
|
|
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
|
+
};
|
|
720
904
|
|
|
721
905
|
const sessionGoalRuntime = createSessionGoalRuntime({
|
|
722
906
|
buildOpenCodeUrl,
|
|
723
907
|
getOpenCodeAuthHeaders,
|
|
908
|
+
serverOpenCodeFetch,
|
|
724
909
|
getSmallModelService,
|
|
725
910
|
shouldKeepGoalActiveForQuestion: (sessionId) => (
|
|
726
911
|
questionAutoDelegateRuntime?.isAutoHandling(sessionId) === true
|
|
@@ -732,21 +917,26 @@ const sessionGoalRuntime = createSessionGoalRuntime({
|
|
|
732
917
|
questionAutoDelegateRuntime?.pauseForSessionTree?.(sessionId, directory)
|
|
733
918
|
),
|
|
734
919
|
readSessionMetadata: (sessionId) => sessionMetadataStore.get(sessionId),
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
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
|
+
}
|
|
748
934
|
}
|
|
749
|
-
return
|
|
935
|
+
return result;
|
|
936
|
+
},
|
|
937
|
+
persistSessionGoal: async (sessionId, directory, goal) => {
|
|
938
|
+
const metadata = await persistSessionGoalToStore(sessionId, directory, goal);
|
|
939
|
+
return metadata?.openchamber?.goal ?? goal;
|
|
750
940
|
},
|
|
751
941
|
emitGoalNotification: async ({ sessionId, directory, status, goal }) => {
|
|
752
942
|
// The goal settle notification replaces the per-turn ready notifications
|
|
@@ -788,6 +978,7 @@ const globalMessageStreamHub = createGlobalMessageStreamHub({
|
|
|
788
978
|
buildOpenCodeUrl,
|
|
789
979
|
getOpenCodeAuthHeaders,
|
|
790
980
|
upstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
|
|
981
|
+
projectOutboundSessionPayload: projectHostSessionPayload,
|
|
791
982
|
});
|
|
792
983
|
|
|
793
984
|
const permissionAutoAcceptRuntime = createPermissionAutoAcceptRuntime({
|
|
@@ -930,6 +1121,9 @@ const serverUtilsRuntime = createServerUtilsRuntime({
|
|
|
930
1121
|
openCodeNotReadySince,
|
|
931
1122
|
isOpenCodeReady,
|
|
932
1123
|
isRestartingOpenCode,
|
|
1124
|
+
v1Migration,
|
|
1125
|
+
runtimeContract,
|
|
1126
|
+
openCodeServeVersion,
|
|
933
1127
|
}),
|
|
934
1128
|
getOpenCodeAuthHeaders,
|
|
935
1129
|
buildOpenCodeUrl,
|
|
@@ -957,6 +1151,12 @@ const serverUtilsRuntime = createServerUtilsRuntime({
|
|
|
957
1151
|
return snapshot.PATH;
|
|
958
1152
|
},
|
|
959
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
|
+
},
|
|
960
1160
|
});
|
|
961
1161
|
|
|
962
1162
|
const setOpenCodePort = (...args) => serverUtilsRuntime.setOpenCodePort(...args);
|
|
@@ -1027,6 +1227,13 @@ Object.defineProperties(openCodeLifecycleState, {
|
|
|
1027
1227
|
lastOpenCodeLaunchDiagnostics: { get: () => lastOpenCodeLaunchDiagnostics, set: (value) => { lastOpenCodeLaunchDiagnostics = value; } },
|
|
1028
1228
|
isOpenCodeReady: { get: () => isOpenCodeReady, set: (value) => { isOpenCodeReady = value; } },
|
|
1029
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
|
+
},
|
|
1030
1237
|
openCodeNotReadySince: { get: () => openCodeNotReadySince, set: (value) => { openCodeNotReadySince = value; } },
|
|
1031
1238
|
isExternalOpenCode: { get: () => isExternalOpenCode, set: (value) => { isExternalOpenCode = value; } },
|
|
1032
1239
|
isShuttingDown: { get: () => isShuttingDown, set: (value) => { isShuttingDown = value; } },
|
|
@@ -1073,6 +1280,8 @@ const openCodeLifecycleRuntime = createOpenCodeLifecycleRuntime({
|
|
|
1073
1280
|
ensureOpencodeCliEnv,
|
|
1074
1281
|
ensurePinnedOpenCode2CliEnv,
|
|
1075
1282
|
ensureLocalOpenCodeServerPassword,
|
|
1283
|
+
adoptOpenCodeServerPassword,
|
|
1284
|
+
sharedService: isSharedServiceEnabled() ? createSharedOpenCodeService() : null,
|
|
1076
1285
|
resolveManagedOpenCodeLaunchSpec,
|
|
1077
1286
|
setOpenCodePort,
|
|
1078
1287
|
setDetectedOpenCodeApiPrefix,
|
|
@@ -1128,20 +1337,9 @@ const scheduledTasksRuntime = createScheduledTasksRuntime({
|
|
|
1128
1337
|
runHistoryStore: scheduledTaskRunHistoryStore,
|
|
1129
1338
|
// Same Host store seam as session-goal / manual UI metadata writes.
|
|
1130
1339
|
readSessionMetadata: (sessionId) => sessionMetadataStore.get(sessionId),
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
});
|
|
1135
|
-
try {
|
|
1136
|
-
broadcastGlobalUiEvent({
|
|
1137
|
-
type: 'openchamber:session-metadata',
|
|
1138
|
-
properties: { sessionID: sessionId, metadata },
|
|
1139
|
-
});
|
|
1140
|
-
} catch (error) {
|
|
1141
|
-
console.warn('[session-metadata] broadcast failed:', error?.message ?? error);
|
|
1142
|
-
}
|
|
1143
|
-
return metadata;
|
|
1144
|
-
},
|
|
1340
|
+
persistSessionMetadata: persistSessionMetadataToStore,
|
|
1341
|
+
onSystemSessionPersisted: hideSystemSessionFromIndex,
|
|
1342
|
+
persistSessionGoal: persistSessionGoalToStore,
|
|
1145
1343
|
// Arm the goal loop after first persist only — do not feed progress writes
|
|
1146
1344
|
// back through processPayload (session-goal runtime already broadcasts those).
|
|
1147
1345
|
onGoalPersisted: ({ sessionID, directory, metadata }) => {
|
|
@@ -1183,7 +1381,19 @@ const ensureGlobalWatcherStarted = async () => {
|
|
|
1183
1381
|
return globalWatcherStartPromise;
|
|
1184
1382
|
}
|
|
1185
1383
|
|
|
1186
|
-
|
|
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) => {
|
|
1187
1397
|
globalWatcherStartPromise = null;
|
|
1188
1398
|
throw error;
|
|
1189
1399
|
});
|
|
@@ -1193,15 +1403,30 @@ const ensureGlobalWatcherStarted = async () => {
|
|
|
1193
1403
|
|
|
1194
1404
|
const completeOpenCodeStartup = () => {
|
|
1195
1405
|
scheduleOpenCodeApiDetection();
|
|
1196
|
-
if (
|
|
1406
|
+
if (
|
|
1407
|
+
(openCodeLifecycleState.openCodeProcess && !openCodeLifecycleState.isExternalOpenCode)
|
|
1408
|
+
|| openCodeLifecycleRuntime.isSharedOpenCodeService()
|
|
1409
|
+
) {
|
|
1197
1410
|
startHealthMonitoring();
|
|
1198
1411
|
}
|
|
1199
1412
|
// The global watcher used to start only for desktop notifications; session-title
|
|
1200
1413
|
// and session-goal also ride its event hub, so it now starts unconditionally
|
|
1201
|
-
// once OpenCode is up.
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
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();
|
|
1205
1430
|
};
|
|
1206
1431
|
|
|
1207
1432
|
const bootstrapOpenCodeAtStartup = async (...args) => {
|
|
@@ -1213,7 +1438,6 @@ const retryOpenCodeStartup = async (...args) => {
|
|
|
1213
1438
|
await openCodeLifecycleRuntime.retryOpenCodeStartup(...args);
|
|
1214
1439
|
completeOpenCodeStartup();
|
|
1215
1440
|
};
|
|
1216
|
-
const killProcessOnPort = (...args) => openCodeLifecycleRuntime.killProcessOnPort(...args);
|
|
1217
1441
|
const waitForPortRelease = (...args) => openCodeLifecycleRuntime.waitForPortRelease(...args);
|
|
1218
1442
|
|
|
1219
1443
|
const fetchAgentsSnapshot = (...args) => serverUtilsRuntime.fetchAgentsSnapshot(...args);
|
|
@@ -1250,7 +1474,6 @@ const gracefulShutdownRuntime = createGracefulShutdownRuntime({
|
|
|
1250
1474
|
setOpenCodeProcess: (value) => {
|
|
1251
1475
|
openCodeProcess = value;
|
|
1252
1476
|
},
|
|
1253
|
-
killProcessOnPort,
|
|
1254
1477
|
waitForPortRelease,
|
|
1255
1478
|
getServer: () => server,
|
|
1256
1479
|
getUiAuthController: () => uiAuthController,
|
|
@@ -1425,6 +1648,15 @@ async function main(options = {}) {
|
|
|
1425
1648
|
buildOpenCodeUrl,
|
|
1426
1649
|
getOpenCodeAuthHeaders,
|
|
1427
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
|
+
},
|
|
1428
1660
|
onRevisionTip: (tip) => {
|
|
1429
1661
|
broadcastOpenChamberEvent({
|
|
1430
1662
|
type: 'openchamber:session-index-changed',
|
|
@@ -1432,8 +1664,43 @@ async function main(options = {}) {
|
|
|
1432
1664
|
});
|
|
1433
1665
|
},
|
|
1434
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
|
+
|
|
1435
1693
|
const unsubscribeSessionIndexEvents = globalMessageStreamHub.subscribeEvent((event) => {
|
|
1436
|
-
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
|
+
})) {
|
|
1437
1704
|
sessionIndexSyncRuntime?.publishChange();
|
|
1438
1705
|
}
|
|
1439
1706
|
});
|
|
@@ -1499,6 +1766,9 @@ async function main(options = {}) {
|
|
|
1499
1766
|
}));
|
|
1500
1767
|
expressApp = app;
|
|
1501
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);
|
|
1502
1772
|
let realtimeProxyRuntime = { stop: () => {} };
|
|
1503
1773
|
|
|
1504
1774
|
// The relay service is constructed further below (it depends on the active
|
|
@@ -1526,6 +1796,9 @@ async function main(options = {}) {
|
|
|
1526
1796
|
openCodeApiPrefixDetected: true,
|
|
1527
1797
|
isOpenCodeReady,
|
|
1528
1798
|
v1Migration,
|
|
1799
|
+
openCodeServeVersion,
|
|
1800
|
+
openCodeCliVersion,
|
|
1801
|
+
runtimeContract,
|
|
1529
1802
|
lastOpenCodeError,
|
|
1530
1803
|
lastOpenCodeLaunchDiagnostics,
|
|
1531
1804
|
opencodeBinaryResolved: resolvedOpencodeBinary || null,
|
|
@@ -1636,6 +1909,8 @@ async function main(options = {}) {
|
|
|
1636
1909
|
setAutoAcceptSession,
|
|
1637
1910
|
sessionIndexService,
|
|
1638
1911
|
sessionIndexSyncRuntime,
|
|
1912
|
+
// Production snapshot/lookup filter: committed Host archive authority.
|
|
1913
|
+
getCommittedHostMetadata: async () => sessionMetadataStore.getAll(),
|
|
1639
1914
|
transcriptCacheService,
|
|
1640
1915
|
});
|
|
1641
1916
|
uiAuthController = bootstrapResult.uiAuthController;
|
|
@@ -1731,24 +2006,45 @@ async function main(options = {}) {
|
|
|
1731
2006
|
buildOpenCodeUrl,
|
|
1732
2007
|
getOpenCodeAuthHeaders,
|
|
1733
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,
|
|
1734
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
|
+
},
|
|
1735
2038
|
// Same store seam as sessionGoalRuntime / scheduledTasksRuntime.
|
|
1736
2039
|
readSessionMetadata: (sessionId) => sessionMetadataStore.get(sessionId),
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
});
|
|
1741
|
-
try {
|
|
1742
|
-
broadcastGlobalUiEvent({
|
|
1743
|
-
type: 'openchamber:session-metadata',
|
|
1744
|
-
properties: { sessionID: sessionId, metadata },
|
|
1745
|
-
});
|
|
1746
|
-
} catch (error) {
|
|
1747
|
-
console.warn('[session-metadata] broadcast failed:', error?.message ?? error);
|
|
1748
|
-
}
|
|
1749
|
-
return metadata;
|
|
1750
|
-
},
|
|
2040
|
+
persistSessionMetadata: persistSessionMetadataToStore,
|
|
2041
|
+
onSystemSessionPersisted: hideSystemSessionFromIndex,
|
|
2042
|
+
persistSessionGoal: persistSessionGoalToStore,
|
|
1751
2043
|
onSessionMetadataWritten: ({ sessionID, directory, metadata }) => {
|
|
2044
|
+
sessionTitleRuntime.processPayload({
|
|
2045
|
+
type: 'openchamber:session-metadata',
|
|
2046
|
+
properties: { sessionID, directory, metadata },
|
|
2047
|
+
}, directory || '');
|
|
1752
2048
|
sessionGoalRuntime.processPayload({
|
|
1753
2049
|
type: 'session.updated',
|
|
1754
2050
|
properties: {
|
|
@@ -1811,6 +2107,8 @@ async function main(options = {}) {
|
|
|
1811
2107
|
getOpenCodeAuthHeaders,
|
|
1812
2108
|
globalEventHub: globalMessageStreamHub,
|
|
1813
2109
|
processForwardedEventPayload,
|
|
2110
|
+
projectOutboundSessionPayload: projectHostSessionPayload,
|
|
2111
|
+
ensureSessionMetadataReady,
|
|
1814
2112
|
messageStreamWsClients: uiNotificationWsClients,
|
|
1815
2113
|
upstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
|
|
1816
2114
|
terminalHeartbeatIntervalMs: TERMINAL_INPUT_WS_HEARTBEAT_INTERVAL_MS,
|
|
@@ -1880,12 +2178,9 @@ async function main(options = {}) {
|
|
|
1880
2178
|
restartOpenCode: () => restartOpenCode(),
|
|
1881
2179
|
getOpenCodeProcessInfo: () => {
|
|
1882
2180
|
const managed = Boolean((openCodeProcess || openCodePort) && !ENV_SKIP_OPENCODE_START && !isExternalOpenCode);
|
|
1883
|
-
// Only ever expose pid/port for a server WE manage.
|
|
1884
|
-
//
|
|
1885
|
-
//
|
|
1886
|
-
// let a single miscomputed `managed` flag take down the user's separate
|
|
1887
|
-
// server. Structurally withhold what isn't ours so the killer has no
|
|
1888
|
-
// 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.
|
|
1889
2184
|
return {
|
|
1890
2185
|
managed,
|
|
1891
2186
|
pid: managed && typeof openCodeProcess?.pid === 'number' ? openCodeProcess.pid : null,
|
|
@@ -1899,6 +2194,8 @@ async function main(options = {}) {
|
|
|
1899
2194
|
unsubscribeScheduledTaskEvents();
|
|
1900
2195
|
sessionIndexSyncRuntime?.stop();
|
|
1901
2196
|
sessionIndexService?.close();
|
|
2197
|
+
sessionArchiveServiceRef?.stop?.();
|
|
2198
|
+
stopSessionRecordMigration();
|
|
1902
2199
|
} catch {
|
|
1903
2200
|
// The index is a local cache; a failed close must not block shutdown.
|
|
1904
2201
|
}
|
|
@@ -1926,11 +2223,10 @@ async function main(options = {}) {
|
|
|
1926
2223
|
// best-effort shutdown of the dictation worker
|
|
1927
2224
|
}
|
|
1928
2225
|
try {
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
}
|
|
2226
|
+
const { stopLlmTempDirectory } = await import('./lib/llm/temp-directory.js');
|
|
2227
|
+
await stopLlmTempDirectory();
|
|
1932
2228
|
} catch {
|
|
1933
|
-
// best-effort cleanup of the
|
|
2229
|
+
// best-effort cleanup of the LLM generator temp OpenCode directory
|
|
1934
2230
|
}
|
|
1935
2231
|
return gracefulShutdown({
|
|
1936
2232
|
exitProcess: shutdownOptions.exitProcess ?? false,
|