@openchambery/web 2.0.0-beta.1 → 2.0.0-beta.4
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-Q1SmFRx2.js} +1 -1
- package/dist/assets/AssistantView-CwXkiCAd.js +3 -0
- package/dist/assets/{DiagramView-xuSJTnv7.js → DiagramView-BW92schO.js} +1 -1
- package/dist/assets/{FadeInOnReveal-Ov0D96d0.js → FadeInOnReveal-BZmwl-zE.js} +1 -1
- package/dist/assets/{Icon-DD-BuMfZ.js → Icon-AQPvxMiU.js} +1 -1
- package/dist/assets/{MarkdownRenderer-bc_p1H7l.js → MarkdownRenderer-Bv05iDZZ.js} +2 -2
- package/dist/assets/{MarkdownRendererImpl-SKi4oG0c.js → MarkdownRendererImpl-C81xqYib.js} +3 -3
- package/dist/assets/MarkstreamRendererImpl-CXUCQuKJ.js +3 -0
- package/dist/assets/{MobileDetailNavigation-Bnx59U_J.js → MobileDetailNavigation-BMgIu7zc.js} +1 -1
- package/dist/assets/{MobileShareBridge-BQlP4J-F.js → MobileShareBridge-BOXGNHmC.js} +2 -2
- package/dist/assets/MobileSurface-xuc_z0_G.js +2 -0
- package/dist/assets/{MultiRunWindow-ChZGob0v.js → MultiRunWindow-B5At2Z95.js} +1 -1
- package/dist/assets/{OnboardingScreen-DtQJxZG-.js → OnboardingScreen-bsPLgz4r.js} +1 -1
- package/dist/assets/OverlayScrollbar-4wp4migh.js +2 -0
- package/dist/assets/SettingsView-CJ6tcH5_.js +25 -0
- package/dist/assets/{SettingsWindow-DfnsFa8y.js → SettingsWindow-CMtX2bMl.js} +1 -1
- package/dist/assets/{TerminalView-Dh9MWCpS.js → TerminalView-Dvr-ysTS.js} +1 -1
- package/dist/assets/{ToolOutputDialog-BejmjrRk.js → ToolOutputDialog-uH1ZZDSS.js} +2 -2
- package/dist/assets/appThemeRegistry-DK7q2juD.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-CcNJUxUd.js} +1 -1
- package/dist/assets/collapsible-ZmZ6rLWs.js +3 -0
- package/dist/assets/context-menu-B2LXJgXL.js +1 -0
- package/dist/assets/{desktopHosts-B1ixEylr.js → desktopHosts-C6HrP0jq.js} +1 -1
- package/dist/assets/{desktopRelayRestore-4JmFUw8r.js → desktopRelayRestore-DdVBp45U.js} +1 -1
- package/dist/assets/{diagram-DQf7Y_uR.js → diagram-CxTs9hCQ.js} +1 -1
- package/dist/assets/{dialog-bfbvR4VH.js → dialog-KMVL9QKF.js} +1 -1
- package/dist/assets/es-CN3E_zXj.js +15 -0
- package/dist/assets/{fileMentionTouchSelection-BvrNCroG.js → fileMentionTouchSelection-7RIwlpkB.js} +1 -1
- package/dist/assets/{fileQueries-DQc8EJUf.js → fileQueries-CjdBRy8y.js} +1 -1
- package/dist/assets/fr-9zZvQZD2.js +13 -0
- package/dist/assets/gitApi-yuWg9BN4.js +10 -0
- package/dist/assets/{imageSource-BlAJJUEI.js → imageSource-9vQBq3zp.js} +1 -1
- package/dist/assets/{input-8r6F_Fza.js → input-CrIvk3HZ.js} +1 -1
- package/dist/assets/insertionBoundaries-BiUCSkx-.js +1 -0
- package/dist/assets/ja-Dnjk_82N.js +15 -0
- package/dist/assets/ko-BxCEE99C.js +15 -0
- package/dist/assets/{main-CCE_4y5F.js → main-C9mIBo77.js} +2 -2
- package/dist/assets/main-DiL6w6KF.js +169 -0
- package/dist/assets/markdown-worker-bS5OgGO3.js +2 -0
- package/dist/assets/{markdownHeightCache-1Qo6y6IJ.js → markdownHeightCache-BmXVY_gc.js} +1 -1
- package/dist/assets/{markdownTheme-DOfGg-A7.js → markdownTheme-CKac3wKC.js} +1 -1
- package/dist/assets/mcpQueries-C7jknHV8.js +1 -0
- package/dist/assets/miniChat-CwtUaElU.js +2 -0
- package/dist/assets/mobile-DB-6--ws.js +2 -0
- package/dist/assets/multirun-TAsxFI8e.js +4 -0
- package/dist/assets/{persistence-Ce3AnpEr.js → persistence-56kq8Z4V.js} +2 -2
- package/dist/assets/pl-CNNsWnPM.js +15 -0
- package/dist/assets/platform-C13fMVEs.js +6 -0
- package/dist/assets/pt-BR-BZB2DJMp.js +15 -0
- package/dist/assets/{relay-image-stream-DM7atqJs.js → relay-image-stream-DrdVj99c.js} +1 -1
- package/dist/assets/renderElectronMiniChatApp-CGj0MNRU.js +2 -0
- package/dist/assets/renderMobileApp-CGMMqbsO.js +28 -0
- package/dist/assets/runtime-fetch-Fs9ZV2V8.js +1 -0
- package/dist/assets/{runtimeConfig-BMvqa5we.js → runtimeConfig-BEANkvOd.js} +1 -1
- package/dist/assets/runtimeEndpointReset-A_ZBUJFS.js +147 -0
- package/dist/assets/sessionChangeSummary-qOLrP9fw.js +2 -0
- package/dist/assets/{sessionLookup-gh-hVRIc.js → sessionLookup-34XFmP9C.js} +1 -1
- package/dist/assets/{sortable-tabs-strip-CudoSgV4.js → sortable-tabs-strip-DyEV0Heg.js} +1 -1
- package/dist/assets/src-ubCWXZhR.css +2 -0
- package/dist/assets/store-DLCiZaA6.js +15 -0
- package/dist/assets/{terminalApi-DiF6JmBP.js → terminalApi-CXaBEoa_.js} +1 -1
- package/dist/assets/textarea-BBOlRI9O.js +1 -0
- package/dist/assets/{tooltip-CQvpK-UV.js → tooltip-CPI4fr1a.js} +1 -1
- package/dist/assets/uk-rwQrxeYM.js +15 -0
- package/dist/assets/{url-_z7evzdK.js → url-DRDQXjyX.js} +1 -1
- package/dist/assets/{useAppFontEffects-Cpmpo7Wb.js → useAppFontEffects-CiDe42I5.js} +57 -43
- package/dist/assets/{useAssistantUIStore-CMutVh9B.js → useAssistantUIStore-asNG6K7n.js} +1 -1
- package/dist/assets/useDesktopWindowControlsLayout-BlizAlOt.js +1 -0
- package/dist/assets/useEffectiveDirectory-C_CouL5v.js +1 -0
- package/dist/assets/{useFontPreferences-DcbXQOkc.js → useFontPreferences-B0oUZAiB.js} +1 -1
- package/dist/assets/useMobileNavigationStore-DfPClaW-.js +414 -0
- package/dist/assets/{useRuntimeAPIs-DSLXJybW.js → useRuntimeAPIs-DwLtO0c_.js} +1 -1
- package/dist/assets/useSessionAutoCleanup-DtrfbxAp.js +2 -0
- package/dist/assets/{useThemeSystem-DMzWVJaW.js → useThemeSystem-BlNUWH47.js} +1 -1
- package/dist/assets/useUIStore-CQYKJnrg.js +1 -0
- package/dist/assets/{useWorkerHighlightedLines-Bqn4AiBL.js → useWorkerHighlightedLines-CPNYz6Wf.js} +2 -2
- package/dist/assets/{vendor-base-ui-CnHfUmDN.js → vendor-base-ui-CDjyofeD.js} +1 -1
- package/dist/assets/{vendor-cmdk-CeAGfrLo.js → vendor-cmdk-BFH0UpXX.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-accessibility-BY5LhhUB.js → vendor-dnd-kit-accessibility-BrR3AKvM.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-core-CvWxUPdb.js → vendor-dnd-kit-core-CNfdvk6H.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-sortable-hHdP9lLb.js → vendor-dnd-kit-sortable-DQUaTeGj.js} +1 -1
- package/dist/assets/{vendor-framer-motion-DFy_BSVd.js → vendor-framer-motion-4dogsUk3.js} +1 -1
- package/dist/assets/{vendor-legendapp-list-WE32lwNk.js → vendor-legendapp-list-BU7MdPZR.js} +1 -1
- package/dist/assets/{vendor-markstream-react-DX55XLGO.js → vendor-markstream-react-qHC2FykU.js} +3 -3
- package/dist/assets/{vendor-pierre-diffs-DX7XTPG3.js → vendor-pierre-diffs-CUfqC003.js} +1 -1
- package/dist/assets/{vendor-react-DLPElpoQ.js → vendor-react-C94A0AHl.js} +1 -1
- package/dist/assets/{vendor-react-drawio-ECtEwvbc.js → vendor-react-drawio-FVlWqKVE.js} +1 -1
- package/dist/assets/{vendor-reactuses-core-BnW6GxJt.js → vendor-reactuses-core-C2A3EjUi.js} +1 -1
- package/dist/assets/{vendor-sonner-DVzioF3d.js → vendor-sonner-DNqHmUQs.js} +1 -1
- package/dist/assets/{vendor-stream-diffs-DWy3xSmp.js → vendor-stream-diffs-CwbKsmlv.js} +2 -2
- package/dist/assets/{vendor-tanstack-react-query-D7pys_c9.js → vendor-tanstack-react-query-D0iFK57C.js} +1 -1
- package/dist/assets/{vendor-tanstack-react-virtual-tlDgH6PG.js → vendor-tanstack-react-virtual-B2kV6cnT.js} +1 -1
- package/dist/assets/{vendor-zustand-B4dlGEM2.js → vendor-zustand-BqLKf6ZY.js} +1 -1
- package/dist/assets/zh-CN-BvmBDnkD.js +15 -0
- package/dist/assets/zh-TW-9wcHTX0y.js +15 -0
- package/dist/index.html +13 -13
- package/dist/mini-chat.html +13 -13
- package/dist/mobile.html +13 -13
- package/package.json +1 -1
- package/server/index.js +327 -62
- 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/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/runtime.js +23 -5
- package/server/lib/notifications/runtime.test.js +11 -0
- package/server/lib/opencode/DOCUMENTATION.md +85 -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.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 +43 -4
- package/server/lib/opencode/feature-routes-runtime.test.js +18 -0
- package/server/lib/opencode/http-server-connections.js +98 -0
- package/server/lib/opencode/http-server-connections.test.js +321 -0
- package/server/lib/opencode/lifecycle.js +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 +252 -46
- package/server/lib/opencode/proxy.test.js +235 -2
- package/server/lib/opencode/routes.js +296 -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/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 +61 -16
- package/server/lib/session-metadata/routes.js +108 -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 +36 -0
- package/server/lib/session-metadata/session-metadata-store.js +212 -72
- 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 +255 -0
- package/server/lib/session-metadata/session-projection.test.js +64 -0
- package/server/lib/session-metadata/system-session.js +55 -0
- package/server/lib/session-metadata/system-session.test.js +55 -0
- package/server/lib/session-title/DOCUMENTATION.md +40 -7
- package/server/lib/session-title/native-runtime.test.js +167 -0
- package/server/lib/session-title/runtime.js +67 -42
- package/server/lib/session-title/session-access.js +46 -0
- package/server/lib/session-title/session-access.test.js +91 -0
- package/server/lib/session-turn-pages/DOCUMENTATION.md +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/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/appThemeRegistry-COGfxTFV.js +0 -1
- package/dist/assets/collapsible-BXRd5_Hr.js +0 -1
- package/dist/assets/context-menu-jGtH6fR9.js +0 -1
- package/dist/assets/es-c52LTHHe.js +0 -15
- 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/markdown-worker-CptoICmq.js +0 -2
- 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/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/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,10 @@ 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
|
+
} from './lib/opencode/server-opencode-fetch.js';
|
|
55
60
|
import { createStaticRoutesRuntime } from './lib/opencode/static-routes-runtime.js';
|
|
56
61
|
import { createSettingsRuntime } from './lib/opencode/settings-runtime.js';
|
|
57
62
|
import { createOpenCodeResolutionRuntime } from './lib/opencode/opencode-resolution-runtime.js';
|
|
@@ -59,6 +64,7 @@ import { createBootstrapRuntime } from './lib/opencode/bootstrap-runtime.js';
|
|
|
59
64
|
import { createSessionRuntime } from './lib/opencode/session-runtime.js';
|
|
60
65
|
import { createOpenCodeWatcherRuntime } from './lib/opencode/watcher.js';
|
|
61
66
|
import { createSessionTitleRuntime } from './lib/session-title/runtime.js';
|
|
67
|
+
import { createTitleSessionAccess } from './lib/session-title/session-access.js';
|
|
62
68
|
import { createSessionIndexService } from './lib/session-index/service.js';
|
|
63
69
|
import { createSessionIndexSyncRuntime } from './lib/session-index/sync-runtime.js';
|
|
64
70
|
import { resolveSessionIndexDbPath } from './lib/session-index/resolve-db-path.js';
|
|
@@ -68,8 +74,20 @@ import { resolveTranscriptCacheDbPath } from './lib/transcript-cache/resolve-db-
|
|
|
68
74
|
import { createMessageQueueRuntime } from './lib/message-queue/runtime.js';
|
|
69
75
|
import { resolveMessageQueueDbPath } from './lib/message-queue/resolve-db-path.js';
|
|
70
76
|
import { createOpenChamberEventBroadcaster } from './lib/opencode/feature-routes-runtime.js';
|
|
71
|
-
import {
|
|
77
|
+
import {
|
|
78
|
+
createSessionGoalRuntime,
|
|
79
|
+
withGoalExecutionGeneration,
|
|
80
|
+
} from './lib/session-goal/runtime.js';
|
|
72
81
|
import { createSessionMetadataStore } from './lib/session-metadata/session-metadata-store.js';
|
|
82
|
+
import {
|
|
83
|
+
createSessionArchiveService,
|
|
84
|
+
createUpstreamSessionFetcher,
|
|
85
|
+
} from './lib/session-metadata/session-archive.js';
|
|
86
|
+
import {
|
|
87
|
+
projectSessionLifecyclePayload,
|
|
88
|
+
projectSessionWithHostMetadata,
|
|
89
|
+
projectSessionWithStoredMap,
|
|
90
|
+
} from './lib/session-metadata/session-projection.js';
|
|
73
91
|
import { createScheduledTasksRuntime } from './lib/scheduled-tasks/runtime.js';
|
|
74
92
|
import { createScheduledTaskRunHistoryStore } from './lib/scheduled-tasks/run-history-store.js';
|
|
75
93
|
import { createServerStartupRuntime } from './lib/opencode/server-startup-runtime.js';
|
|
@@ -89,6 +107,7 @@ import { createNotificationTemplateRuntime } from './lib/notifications/template-
|
|
|
89
107
|
import { createPermissionAutoAcceptRuntime } from './lib/permission-auto-accept/runtime.js';
|
|
90
108
|
import { createQuestionAutoDelegateRuntime } from './lib/question-auto-delegate/runtime.js';
|
|
91
109
|
import { createGracefulShutdownRuntime } from './lib/opencode/shutdown-runtime.js';
|
|
110
|
+
import { attachHttpServerConnectionTracker } from './lib/opencode/http-server-connections.js';
|
|
92
111
|
import { createProjectConfigRuntime } from './lib/projects/project-config.js';
|
|
93
112
|
import { createRemoteClientAuthRuntime } from './lib/client-auth/remote-clients.js';
|
|
94
113
|
import { applyRuntimeCorsHeaders } from './lib/request-cors.js';
|
|
@@ -447,6 +466,11 @@ let lastOpenCodeError = null;
|
|
|
447
466
|
let lastOpenCodeLaunchDiagnostics = null;
|
|
448
467
|
let isOpenCodeReady = false;
|
|
449
468
|
let v1Migration = null;
|
|
469
|
+
let openCodeServeVersion = null;
|
|
470
|
+
let openCodeCliVersion = null;
|
|
471
|
+
let runtimeContract = null;
|
|
472
|
+
/** Bumps on start/restart so stale async health cannot re-permit an old instance. */
|
|
473
|
+
let runtimeContractGeneration = 0;
|
|
450
474
|
let openCodeNotReadySince = 0;
|
|
451
475
|
let isExternalOpenCode = false;
|
|
452
476
|
let exitOnShutdown = true;
|
|
@@ -551,6 +575,7 @@ const openCodeAuthStateRuntime = createOpenCodeAuthStateRuntime({
|
|
|
551
575
|
const getOpenCodeAuthHeaders = (...args) => openCodeAuthStateRuntime.getOpenCodeAuthHeaders(...args);
|
|
552
576
|
const isOpenCodeConnectionSecure = (...args) => openCodeAuthStateRuntime.isOpenCodeConnectionSecure(...args);
|
|
553
577
|
const ensureLocalOpenCodeServerPassword = (...args) => openCodeAuthStateRuntime.ensureLocalOpenCodeServerPassword(...args);
|
|
578
|
+
const adoptOpenCodeServerPassword = (...args) => openCodeAuthStateRuntime.adoptOpenCodeServerPassword(...args);
|
|
554
579
|
|
|
555
580
|
const openCodeNetworkState = {};
|
|
556
581
|
Object.defineProperties(openCodeNetworkState, {
|
|
@@ -574,6 +599,15 @@ const buildOpenCodeUrl = (...args) => openCodeNetworkRuntime.buildOpenCodeUrl(..
|
|
|
574
599
|
const ensureOpenCodeApiPrefix = (...args) => openCodeNetworkRuntime.ensureOpenCodeApiPrefix(...args);
|
|
575
600
|
const scheduleOpenCodeApiDetection = (...args) => openCodeNetworkRuntime.scheduleOpenCodeApiDetection(...args);
|
|
576
601
|
|
|
602
|
+
// Host OpenCode transport gate (queue/goal/scheduled/assistants + v2-client).
|
|
603
|
+
// Registered before background runtimes so direct OpenCode writes share proxy admission.
|
|
604
|
+
configureServerOpenCodeFetchGate(() => runtimeContract);
|
|
605
|
+
const serverOpenCodeFetch = createServerOpenCodeFetch({
|
|
606
|
+
buildOpenCodeUrl,
|
|
607
|
+
getOpenCodeAuthHeaders,
|
|
608
|
+
getRuntimeContract: () => runtimeContract,
|
|
609
|
+
});
|
|
610
|
+
|
|
577
611
|
const ENV_CONFIGURED_API_PREFIX = normalizeApiPrefix(
|
|
578
612
|
process.env.OPENCODE_API_PREFIX || process.env.OPENCHAMBER_API_PREFIX || ''
|
|
579
613
|
);
|
|
@@ -624,6 +658,7 @@ const searchPathFor = (...args) => openCodeEnvRuntime.searchPathFor(...args);
|
|
|
624
658
|
const resolveGitBinaryForSpawn = (...args) => openCodeEnvRuntime.resolveGitBinaryForSpawn(...args);
|
|
625
659
|
const resolveManagedOpenCodeLaunchSpec = (...args) => openCodeEnvRuntime.resolveManagedOpenCodeLaunchSpec(...args);
|
|
626
660
|
const clearResolvedOpenCodeBinary = (...args) => openCodeEnvRuntime.clearResolvedOpenCodeBinary(...args);
|
|
661
|
+
const forceResolvedOpenCodeBinary = (...args) => openCodeEnvRuntime.forceResolvedOpenCodeBinary(...args);
|
|
627
662
|
const openCodeResolutionRuntime = createOpenCodeResolutionRuntime({
|
|
628
663
|
path,
|
|
629
664
|
resolveOpencodeCliPath,
|
|
@@ -699,6 +734,8 @@ const getSmallModelService = async () => {
|
|
|
699
734
|
smallModelServiceInstance = createSmallModelService({
|
|
700
735
|
buildOpenCodeUrl,
|
|
701
736
|
getOpenCodeAuthHeaders,
|
|
737
|
+
persistSessionMetadata: persistSessionMetadataToStore,
|
|
738
|
+
onSystemSessionPersisted: hideSystemSessionFromIndex,
|
|
702
739
|
});
|
|
703
740
|
}
|
|
704
741
|
return smallModelServiceInstance;
|
|
@@ -708,6 +745,19 @@ const sessionTitleRuntime = createSessionTitleRuntime({
|
|
|
708
745
|
buildOpenCodeUrl,
|
|
709
746
|
getOpenCodeAuthHeaders,
|
|
710
747
|
getSmallModelService,
|
|
748
|
+
serverOpenCodeFetch,
|
|
749
|
+
sessionAccess: createTitleSessionAccess({
|
|
750
|
+
buildOpenCodeUrl,
|
|
751
|
+
getOpenCodeAuthHeaders,
|
|
752
|
+
readSessionMetadata: (sessionID) => sessionMetadataStore.get(sessionID),
|
|
753
|
+
persistSessionMetadata: (sessionID, patch) => persistSessionMetadataToStore(sessionID, patch),
|
|
754
|
+
publishSession: (session, directory) => {
|
|
755
|
+
const payload = { type: 'session.updated', properties: { info: session, directory } };
|
|
756
|
+
broadcastGlobalUiEvent(payload);
|
|
757
|
+
const changed = sessionIndexServiceRef?.upsertAndReportChange(session);
|
|
758
|
+
if (changed) sessionIndexSyncRuntimeRef?.publishChange();
|
|
759
|
+
},
|
|
760
|
+
}),
|
|
711
761
|
});
|
|
712
762
|
|
|
713
763
|
// Forward declaration: question auto-delegate is created after the event hub;
|
|
@@ -717,10 +767,115 @@ let questionAutoDelegateRuntime = null;
|
|
|
717
767
|
let sessionIndexServiceRef = null;
|
|
718
768
|
|
|
719
769
|
const sessionMetadataStore = createSessionMetadataStore({ dataDir: OPENCHAMBER_DATA_DIR });
|
|
770
|
+
/**
|
|
771
|
+
* load() resolves `{ ok:false }` on read/corrupt failure (does not reject).
|
|
772
|
+
* Callers must check ok / isLoaded — never treat unresolved as empty success.
|
|
773
|
+
*/
|
|
774
|
+
const ensureSessionMetadataReady = async () => {
|
|
775
|
+
try {
|
|
776
|
+
const result = await sessionMetadataStore.load();
|
|
777
|
+
return result?.ok === true && sessionMetadataStore.isLoaded();
|
|
778
|
+
} catch (error) {
|
|
779
|
+
console.warn('[session-metadata] load threw:', error?.message ?? error);
|
|
780
|
+
return false;
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
// Prime without blocking module init; production gates (hub/SSE/routes) await ready.
|
|
784
|
+
void ensureSessionMetadataReady().then((ok) => {
|
|
785
|
+
if (!ok) {
|
|
786
|
+
console.warn(
|
|
787
|
+
'[session-metadata] initial load not ready:',
|
|
788
|
+
sessionMetadataStore.getLoadFailureReason?.() || 'unknown',
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* Goal write through the Host metadata store.
|
|
795
|
+
* Advances executionGeneration on pause/resume/condition changes so late audits
|
|
796
|
+
* cannot commit against a prior execution permit. Broadcasts only after commit.
|
|
797
|
+
*/
|
|
798
|
+
const persistSessionGoalToStore = async (sessionId, _directory, goal) => {
|
|
799
|
+
const result = await sessionMetadataStore.mutateSessionMetadata(sessionId, (current) => {
|
|
800
|
+
const previousGoal = current?.openchamber?.goal && typeof current.openchamber.goal === 'object'
|
|
801
|
+
? current.openchamber.goal
|
|
802
|
+
: null;
|
|
803
|
+
const nextGoal = withGoalExecutionGeneration(previousGoal, goal);
|
|
804
|
+
return { ok: true, patch: { openchamber: { goal: nextGoal } } };
|
|
805
|
+
});
|
|
806
|
+
if (!result?.committed) {
|
|
807
|
+
throw new Error(result?.reason || 'session goal persist was rejected');
|
|
808
|
+
}
|
|
809
|
+
const metadata = result.metadata;
|
|
810
|
+
try {
|
|
811
|
+
broadcastGlobalUiEvent({
|
|
812
|
+
type: 'openchamber:session-metadata',
|
|
813
|
+
properties: { sessionID: sessionId, metadata },
|
|
814
|
+
});
|
|
815
|
+
} catch (error) {
|
|
816
|
+
console.warn('[session-metadata] broadcast failed:', error?.message ?? error);
|
|
817
|
+
}
|
|
818
|
+
return metadata;
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Isolation / Host metadata write. Same store + broadcast seam as goal persist.
|
|
823
|
+
* Callers pass an RFC 7386 merge patch; the store returns the committed object.
|
|
824
|
+
*/
|
|
825
|
+
const persistSessionMetadataToStore = async (sessionId, patch) => {
|
|
826
|
+
const metadata = await sessionMetadataStore.setSessionMetadata(sessionId, patch);
|
|
827
|
+
try {
|
|
828
|
+
broadcastGlobalUiEvent({
|
|
829
|
+
type: 'openchamber:session-metadata',
|
|
830
|
+
properties: { sessionID: sessionId, metadata },
|
|
831
|
+
});
|
|
832
|
+
} catch (error) {
|
|
833
|
+
console.warn('[session-metadata] broadcast failed:', error?.message ?? error);
|
|
834
|
+
}
|
|
835
|
+
return metadata;
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* After Host isolation metadata is committed, drop the session from the
|
|
840
|
+
* sidebar index immediately. Do not wait for the next directory list sync.
|
|
841
|
+
* Reads refs at call time — scheduled-task runtime is constructed before main().
|
|
842
|
+
*/
|
|
843
|
+
const hideSystemSessionFromIndex = ({ sessionID, directory, metadata } = {}) => {
|
|
844
|
+
if (!sessionIndexServiceRef || typeof sessionID !== 'string' || !sessionID) return;
|
|
845
|
+
const changed = sessionIndexServiceRef.upsertAndReportChange({
|
|
846
|
+
id: sessionID,
|
|
847
|
+
directory: directory || '',
|
|
848
|
+
metadata,
|
|
849
|
+
});
|
|
850
|
+
if (changed) {
|
|
851
|
+
sessionIndexSyncRuntimeRef?.publishChange();
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
/** Filled in main() once the session index + broadcast sinks exist. */
|
|
856
|
+
let sessionArchiveServiceRef = null;
|
|
857
|
+
let sessionIndexSyncRuntimeRef = null;
|
|
858
|
+
|
|
859
|
+
const readHostMetadataForSession = (sessionID) => {
|
|
860
|
+
const snap = sessionMetadataStore.getSnapshotSync();
|
|
861
|
+
if (!snap || typeof sessionID !== 'string') return null;
|
|
862
|
+
const host = snap[sessionID];
|
|
863
|
+
return host && typeof host === 'object' && !Array.isArray(host) ? host : null;
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
const projectHostSessionPayload = (payload) => {
|
|
867
|
+
const ready = sessionMetadataStore.isLoaded();
|
|
868
|
+
return projectSessionLifecyclePayload(
|
|
869
|
+
payload,
|
|
870
|
+
readHostMetadataForSession,
|
|
871
|
+
{ hostReady: ready },
|
|
872
|
+
);
|
|
873
|
+
};
|
|
720
874
|
|
|
721
875
|
const sessionGoalRuntime = createSessionGoalRuntime({
|
|
722
876
|
buildOpenCodeUrl,
|
|
723
877
|
getOpenCodeAuthHeaders,
|
|
878
|
+
serverOpenCodeFetch,
|
|
724
879
|
getSmallModelService,
|
|
725
880
|
shouldKeepGoalActiveForQuestion: (sessionId) => (
|
|
726
881
|
questionAutoDelegateRuntime?.isAutoHandling(sessionId) === true
|
|
@@ -732,21 +887,26 @@ const sessionGoalRuntime = createSessionGoalRuntime({
|
|
|
732
887
|
questionAutoDelegateRuntime?.pauseForSessionTree?.(sessionId, directory)
|
|
733
888
|
),
|
|
734
889
|
readSessionMetadata: (sessionId) => sessionMetadataStore.get(sessionId),
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
890
|
+
// Conditional commit on the store's exclusive serial boundary (generation +
|
|
891
|
+
// status preconditions share the lock with persist). Broadcast-only on
|
|
892
|
+
// success — do not feed progress writes back into processPayload.
|
|
893
|
+
mutateSessionMetadata: async (sessionId, decide) => {
|
|
894
|
+
const result = await sessionMetadataStore.mutateSessionMetadata(sessionId, decide);
|
|
895
|
+
if (result?.committed) {
|
|
896
|
+
try {
|
|
897
|
+
broadcastGlobalUiEvent({
|
|
898
|
+
type: 'openchamber:session-metadata',
|
|
899
|
+
properties: { sessionID: sessionId, metadata: result.metadata },
|
|
900
|
+
});
|
|
901
|
+
} catch (error) {
|
|
902
|
+
console.warn('[session-metadata] broadcast failed:', error?.message ?? error);
|
|
903
|
+
}
|
|
748
904
|
}
|
|
749
|
-
return
|
|
905
|
+
return result;
|
|
906
|
+
},
|
|
907
|
+
persistSessionGoal: async (sessionId, directory, goal) => {
|
|
908
|
+
const metadata = await persistSessionGoalToStore(sessionId, directory, goal);
|
|
909
|
+
return metadata?.openchamber?.goal ?? goal;
|
|
750
910
|
},
|
|
751
911
|
emitGoalNotification: async ({ sessionId, directory, status, goal }) => {
|
|
752
912
|
// The goal settle notification replaces the per-turn ready notifications
|
|
@@ -788,6 +948,7 @@ const globalMessageStreamHub = createGlobalMessageStreamHub({
|
|
|
788
948
|
buildOpenCodeUrl,
|
|
789
949
|
getOpenCodeAuthHeaders,
|
|
790
950
|
upstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
|
|
951
|
+
projectOutboundSessionPayload: projectHostSessionPayload,
|
|
791
952
|
});
|
|
792
953
|
|
|
793
954
|
const permissionAutoAcceptRuntime = createPermissionAutoAcceptRuntime({
|
|
@@ -930,6 +1091,9 @@ const serverUtilsRuntime = createServerUtilsRuntime({
|
|
|
930
1091
|
openCodeNotReadySince,
|
|
931
1092
|
isOpenCodeReady,
|
|
932
1093
|
isRestartingOpenCode,
|
|
1094
|
+
v1Migration,
|
|
1095
|
+
runtimeContract,
|
|
1096
|
+
openCodeServeVersion,
|
|
933
1097
|
}),
|
|
934
1098
|
getOpenCodeAuthHeaders,
|
|
935
1099
|
buildOpenCodeUrl,
|
|
@@ -957,6 +1121,12 @@ const serverUtilsRuntime = createServerUtilsRuntime({
|
|
|
957
1121
|
return snapshot.PATH;
|
|
958
1122
|
},
|
|
959
1123
|
getStoredSessionMetadata: () => sessionMetadataStore.getAll(),
|
|
1124
|
+
getStoredSessionMetadataSync: () => sessionMetadataStore.getSnapshotSync(),
|
|
1125
|
+
ensureSessionMetadataReady,
|
|
1126
|
+
onSessionDeleted: (sessionID) => {
|
|
1127
|
+
if (!sessionArchiveServiceRef) return sessionMetadataStore.removeSession(sessionID);
|
|
1128
|
+
return sessionArchiveServiceRef.forgetSession(sessionID);
|
|
1129
|
+
},
|
|
960
1130
|
});
|
|
961
1131
|
|
|
962
1132
|
const setOpenCodePort = (...args) => serverUtilsRuntime.setOpenCodePort(...args);
|
|
@@ -1027,6 +1197,13 @@ Object.defineProperties(openCodeLifecycleState, {
|
|
|
1027
1197
|
lastOpenCodeLaunchDiagnostics: { get: () => lastOpenCodeLaunchDiagnostics, set: (value) => { lastOpenCodeLaunchDiagnostics = value; } },
|
|
1028
1198
|
isOpenCodeReady: { get: () => isOpenCodeReady, set: (value) => { isOpenCodeReady = value; } },
|
|
1029
1199
|
v1Migration: { get: () => v1Migration, set: (value) => { v1Migration = value; } },
|
|
1200
|
+
openCodeServeVersion: { get: () => openCodeServeVersion, set: (value) => { openCodeServeVersion = value; } },
|
|
1201
|
+
openCodeCliVersion: { get: () => openCodeCliVersion, set: (value) => { openCodeCliVersion = value; } },
|
|
1202
|
+
runtimeContract: { get: () => runtimeContract, set: (value) => { runtimeContract = value; } },
|
|
1203
|
+
runtimeContractGeneration: {
|
|
1204
|
+
get: () => runtimeContractGeneration,
|
|
1205
|
+
set: (value) => { runtimeContractGeneration = value; },
|
|
1206
|
+
},
|
|
1030
1207
|
openCodeNotReadySince: { get: () => openCodeNotReadySince, set: (value) => { openCodeNotReadySince = value; } },
|
|
1031
1208
|
isExternalOpenCode: { get: () => isExternalOpenCode, set: (value) => { isExternalOpenCode = value; } },
|
|
1032
1209
|
isShuttingDown: { get: () => isShuttingDown, set: (value) => { isShuttingDown = value; } },
|
|
@@ -1073,6 +1250,8 @@ const openCodeLifecycleRuntime = createOpenCodeLifecycleRuntime({
|
|
|
1073
1250
|
ensureOpencodeCliEnv,
|
|
1074
1251
|
ensurePinnedOpenCode2CliEnv,
|
|
1075
1252
|
ensureLocalOpenCodeServerPassword,
|
|
1253
|
+
adoptOpenCodeServerPassword,
|
|
1254
|
+
sharedService: isSharedServiceEnabled() ? createSharedOpenCodeService() : null,
|
|
1076
1255
|
resolveManagedOpenCodeLaunchSpec,
|
|
1077
1256
|
setOpenCodePort,
|
|
1078
1257
|
setDetectedOpenCodeApiPrefix,
|
|
@@ -1128,20 +1307,9 @@ const scheduledTasksRuntime = createScheduledTasksRuntime({
|
|
|
1128
1307
|
runHistoryStore: scheduledTaskRunHistoryStore,
|
|
1129
1308
|
// Same Host store seam as session-goal / manual UI metadata writes.
|
|
1130
1309
|
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
|
-
},
|
|
1310
|
+
persistSessionMetadata: persistSessionMetadataToStore,
|
|
1311
|
+
onSystemSessionPersisted: hideSystemSessionFromIndex,
|
|
1312
|
+
persistSessionGoal: persistSessionGoalToStore,
|
|
1145
1313
|
// Arm the goal loop after first persist only — do not feed progress writes
|
|
1146
1314
|
// back through processPayload (session-goal runtime already broadcasts those).
|
|
1147
1315
|
onGoalPersisted: ({ sessionID, directory, metadata }) => {
|
|
@@ -1183,7 +1351,19 @@ const ensureGlobalWatcherStarted = async () => {
|
|
|
1183
1351
|
return globalWatcherStartPromise;
|
|
1184
1352
|
}
|
|
1185
1353
|
|
|
1186
|
-
|
|
1354
|
+
// Await Host metadata ready before the internal hub attaches upstream SSE so
|
|
1355
|
+
// session lifecycle frames are projected (not dropped) from the first event.
|
|
1356
|
+
globalWatcherStartPromise = (async () => {
|
|
1357
|
+
const ready = await ensureSessionMetadataReady();
|
|
1358
|
+
if (!ready) {
|
|
1359
|
+
const reason = sessionMetadataStore.getLoadFailureReason?.() || 'not ready';
|
|
1360
|
+
const error = new Error(`session metadata unavailable before global watcher start: ${reason}`);
|
|
1361
|
+
error.code = 'session_metadata_unavailable';
|
|
1362
|
+
error.retryable = true;
|
|
1363
|
+
throw error;
|
|
1364
|
+
}
|
|
1365
|
+
return openCodeWatcherRuntime.start();
|
|
1366
|
+
})().catch((error) => {
|
|
1187
1367
|
globalWatcherStartPromise = null;
|
|
1188
1368
|
throw error;
|
|
1189
1369
|
});
|
|
@@ -1193,15 +1373,30 @@ const ensureGlobalWatcherStarted = async () => {
|
|
|
1193
1373
|
|
|
1194
1374
|
const completeOpenCodeStartup = () => {
|
|
1195
1375
|
scheduleOpenCodeApiDetection();
|
|
1196
|
-
if (
|
|
1376
|
+
if (
|
|
1377
|
+
(openCodeLifecycleState.openCodeProcess && !openCodeLifecycleState.isExternalOpenCode)
|
|
1378
|
+
|| openCodeLifecycleRuntime.isSharedOpenCodeService()
|
|
1379
|
+
) {
|
|
1197
1380
|
startHealthMonitoring();
|
|
1198
1381
|
}
|
|
1199
1382
|
// The global watcher used to start only for desktop notifications; session-title
|
|
1200
1383
|
// and session-goal also ride its event hub, so it now starts unconditionally
|
|
1201
|
-
// once OpenCode is up.
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1384
|
+
// once OpenCode is up. Controlled retry when metadata is not yet ready.
|
|
1385
|
+
const startWatcherWithRetry = (attempt = 0) => {
|
|
1386
|
+
void ensureGlobalWatcherStarted().catch((error) => {
|
|
1387
|
+
const retryable = error?.retryable === true || error?.code === 'session_metadata_unavailable';
|
|
1388
|
+
const delays = [500, 1_500, 3_000, 6_000, 12_000];
|
|
1389
|
+
if (retryable && attempt < delays.length) {
|
|
1390
|
+
console.warn(
|
|
1391
|
+
`Global event watcher deferred (metadata): ${error?.message || error}; retry ${attempt + 1}/${delays.length}`,
|
|
1392
|
+
);
|
|
1393
|
+
setTimeout(() => startWatcherWithRetry(attempt + 1), delays[attempt]);
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
console.warn(`Global event watcher startup failed: ${error?.message || error}`);
|
|
1397
|
+
});
|
|
1398
|
+
};
|
|
1399
|
+
startWatcherWithRetry();
|
|
1205
1400
|
};
|
|
1206
1401
|
|
|
1207
1402
|
const bootstrapOpenCodeAtStartup = async (...args) => {
|
|
@@ -1213,7 +1408,6 @@ const retryOpenCodeStartup = async (...args) => {
|
|
|
1213
1408
|
await openCodeLifecycleRuntime.retryOpenCodeStartup(...args);
|
|
1214
1409
|
completeOpenCodeStartup();
|
|
1215
1410
|
};
|
|
1216
|
-
const killProcessOnPort = (...args) => openCodeLifecycleRuntime.killProcessOnPort(...args);
|
|
1217
1411
|
const waitForPortRelease = (...args) => openCodeLifecycleRuntime.waitForPortRelease(...args);
|
|
1218
1412
|
|
|
1219
1413
|
const fetchAgentsSnapshot = (...args) => serverUtilsRuntime.fetchAgentsSnapshot(...args);
|
|
@@ -1250,7 +1444,6 @@ const gracefulShutdownRuntime = createGracefulShutdownRuntime({
|
|
|
1250
1444
|
setOpenCodeProcess: (value) => {
|
|
1251
1445
|
openCodeProcess = value;
|
|
1252
1446
|
},
|
|
1253
|
-
killProcessOnPort,
|
|
1254
1447
|
waitForPortRelease,
|
|
1255
1448
|
getServer: () => server,
|
|
1256
1449
|
getUiAuthController: () => uiAuthController,
|
|
@@ -1425,6 +1618,14 @@ async function main(options = {}) {
|
|
|
1425
1618
|
buildOpenCodeUrl,
|
|
1426
1619
|
getOpenCodeAuthHeaders,
|
|
1427
1620
|
waitForOpenCodeReady,
|
|
1621
|
+
projectSessions: (sessions) => {
|
|
1622
|
+
const snap = sessionMetadataStore.getSnapshotSync();
|
|
1623
|
+
// Not ready / unavailable — throw so sync keeps prior directory rows.
|
|
1624
|
+
if (!snap) {
|
|
1625
|
+
throw new Error('session metadata is unavailable: Host store not ready');
|
|
1626
|
+
}
|
|
1627
|
+
return sessions.map((session) => projectSessionWithStoredMap(session, snap));
|
|
1628
|
+
},
|
|
1428
1629
|
onRevisionTip: (tip) => {
|
|
1429
1630
|
broadcastOpenChamberEvent({
|
|
1430
1631
|
type: 'openchamber:session-index-changed',
|
|
@@ -1432,8 +1633,44 @@ async function main(options = {}) {
|
|
|
1432
1633
|
});
|
|
1433
1634
|
},
|
|
1434
1635
|
});
|
|
1636
|
+
sessionIndexSyncRuntimeRef = sessionIndexSyncRuntime;
|
|
1637
|
+
|
|
1638
|
+
sessionArchiveServiceRef = createSessionArchiveService({
|
|
1639
|
+
sessionMetadataStore,
|
|
1640
|
+
fetchUpstreamSession: createUpstreamSessionFetcher({
|
|
1641
|
+
buildOpenCodeUrl,
|
|
1642
|
+
getOpenCodeAuthHeaders,
|
|
1643
|
+
}),
|
|
1644
|
+
sessionIndexService,
|
|
1645
|
+
broadcastSessionEvent: (payload, options = {}) => {
|
|
1646
|
+
try {
|
|
1647
|
+
broadcastGlobalUiEvent(payload, options);
|
|
1648
|
+
} catch (error) {
|
|
1649
|
+
console.warn('[session-archive] global UI broadcast failed:', error?.message ?? error);
|
|
1650
|
+
}
|
|
1651
|
+
try {
|
|
1652
|
+
broadcastOpenChamberEvent(payload);
|
|
1653
|
+
} catch (error) {
|
|
1654
|
+
console.warn('[session-archive] openchamber event broadcast failed:', error?.message ?? error);
|
|
1655
|
+
}
|
|
1656
|
+
},
|
|
1657
|
+
onIndexChanged: () => {
|
|
1658
|
+
sessionIndexSyncRuntimeRef?.publishChange();
|
|
1659
|
+
},
|
|
1660
|
+
});
|
|
1661
|
+
|
|
1435
1662
|
const unsubscribeSessionIndexEvents = globalMessageStreamHub.subscribeEvent((event) => {
|
|
1436
|
-
if (applySessionIndexEvent(sessionIndexService, event)
|
|
1663
|
+
if (applySessionIndexEvent(sessionIndexService, event, Date.now(), {
|
|
1664
|
+
isHostReady: () => sessionMetadataStore.isLoaded(),
|
|
1665
|
+
projectSession: (session) => {
|
|
1666
|
+
if (!sessionMetadataStore.isLoaded()) return null;
|
|
1667
|
+
return projectSessionWithHostMetadata(
|
|
1668
|
+
session,
|
|
1669
|
+
readHostMetadataForSession(session?.id),
|
|
1670
|
+
);
|
|
1671
|
+
},
|
|
1672
|
+
onSessionDeleted: (sessionID) => sessionArchiveServiceRef?.forgetSession(sessionID),
|
|
1673
|
+
})) {
|
|
1437
1674
|
sessionIndexSyncRuntime?.publishChange();
|
|
1438
1675
|
}
|
|
1439
1676
|
});
|
|
@@ -1499,6 +1736,9 @@ async function main(options = {}) {
|
|
|
1499
1736
|
}));
|
|
1500
1737
|
expressApp = app;
|
|
1501
1738
|
server = http.createServer(app);
|
|
1739
|
+
// Track server-owned sockets so forceCloseConnections can destroy upgraded
|
|
1740
|
+
// WS/SSE leftovers that closeAllConnections does not release.
|
|
1741
|
+
attachHttpServerConnectionTracker(server);
|
|
1502
1742
|
let realtimeProxyRuntime = { stop: () => {} };
|
|
1503
1743
|
|
|
1504
1744
|
// The relay service is constructed further below (it depends on the active
|
|
@@ -1526,6 +1766,9 @@ async function main(options = {}) {
|
|
|
1526
1766
|
openCodeApiPrefixDetected: true,
|
|
1527
1767
|
isOpenCodeReady,
|
|
1528
1768
|
v1Migration,
|
|
1769
|
+
openCodeServeVersion,
|
|
1770
|
+
openCodeCliVersion,
|
|
1771
|
+
runtimeContract,
|
|
1529
1772
|
lastOpenCodeError,
|
|
1530
1773
|
lastOpenCodeLaunchDiagnostics,
|
|
1531
1774
|
opencodeBinaryResolved: resolvedOpencodeBinary || null,
|
|
@@ -1636,6 +1879,8 @@ async function main(options = {}) {
|
|
|
1636
1879
|
setAutoAcceptSession,
|
|
1637
1880
|
sessionIndexService,
|
|
1638
1881
|
sessionIndexSyncRuntime,
|
|
1882
|
+
// Production snapshot/lookup filter: committed Host archive authority.
|
|
1883
|
+
getCommittedHostMetadata: async () => sessionMetadataStore.getAll(),
|
|
1639
1884
|
transcriptCacheService,
|
|
1640
1885
|
});
|
|
1641
1886
|
uiAuthController = bootstrapResult.uiAuthController;
|
|
@@ -1731,24 +1976,45 @@ async function main(options = {}) {
|
|
|
1731
1976
|
buildOpenCodeUrl,
|
|
1732
1977
|
getOpenCodeAuthHeaders,
|
|
1733
1978
|
getIsExternalOpenCode: () => isExternalOpenCode,
|
|
1979
|
+
getIsSharedOpenCodeService: () => openCodeLifecycleRuntime.isSharedOpenCodeService(),
|
|
1980
|
+
forceResolvedOpenCodeBinary,
|
|
1981
|
+
restartOpenCode,
|
|
1982
|
+
waitForOpenCodeReady,
|
|
1983
|
+
getRuntimeContract: () => runtimeContract,
|
|
1984
|
+
getOpenCodeServeVersion: () => openCodeServeVersion,
|
|
1985
|
+
getOpenCodeCliVersion: () => openCodeCliVersion,
|
|
1986
|
+
getResolvedOpenCodeBinary: () => resolvedOpencodeBinary,
|
|
1987
|
+
getResolvedOpenCodeBinarySource: () => resolvedOpencodeBinarySource,
|
|
1988
|
+
getActiveSessionCount,
|
|
1734
1989
|
sessionMetadataStore,
|
|
1990
|
+
sessionArchiveService: {
|
|
1991
|
+
setArchive: (...args) => {
|
|
1992
|
+
if (!sessionArchiveServiceRef) {
|
|
1993
|
+
const error = new Error('session archive is not configured');
|
|
1994
|
+
error.status = 503;
|
|
1995
|
+
throw error;
|
|
1996
|
+
}
|
|
1997
|
+
return sessionArchiveServiceRef.setArchive(...args);
|
|
1998
|
+
},
|
|
1999
|
+
archiveSession: (...args) => {
|
|
2000
|
+
if (!sessionArchiveServiceRef) {
|
|
2001
|
+
const error = new Error('session archive is not configured');
|
|
2002
|
+
error.status = 503;
|
|
2003
|
+
throw error;
|
|
2004
|
+
}
|
|
2005
|
+
return sessionArchiveServiceRef.archiveSession(...args);
|
|
2006
|
+
},
|
|
2007
|
+
},
|
|
1735
2008
|
// Same store seam as sessionGoalRuntime / scheduledTasksRuntime.
|
|
1736
2009
|
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
|
-
},
|
|
2010
|
+
persistSessionMetadata: persistSessionMetadataToStore,
|
|
2011
|
+
onSystemSessionPersisted: hideSystemSessionFromIndex,
|
|
2012
|
+
persistSessionGoal: persistSessionGoalToStore,
|
|
1751
2013
|
onSessionMetadataWritten: ({ sessionID, directory, metadata }) => {
|
|
2014
|
+
sessionTitleRuntime.processPayload({
|
|
2015
|
+
type: 'openchamber:session-metadata',
|
|
2016
|
+
properties: { sessionID, directory, metadata },
|
|
2017
|
+
}, directory || '');
|
|
1752
2018
|
sessionGoalRuntime.processPayload({
|
|
1753
2019
|
type: 'session.updated',
|
|
1754
2020
|
properties: {
|
|
@@ -1811,6 +2077,8 @@ async function main(options = {}) {
|
|
|
1811
2077
|
getOpenCodeAuthHeaders,
|
|
1812
2078
|
globalEventHub: globalMessageStreamHub,
|
|
1813
2079
|
processForwardedEventPayload,
|
|
2080
|
+
projectOutboundSessionPayload: projectHostSessionPayload,
|
|
2081
|
+
ensureSessionMetadataReady,
|
|
1814
2082
|
messageStreamWsClients: uiNotificationWsClients,
|
|
1815
2083
|
upstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
|
|
1816
2084
|
terminalHeartbeatIntervalMs: TERMINAL_INPUT_WS_HEARTBEAT_INTERVAL_MS,
|
|
@@ -1880,12 +2148,9 @@ async function main(options = {}) {
|
|
|
1880
2148
|
restartOpenCode: () => restartOpenCode(),
|
|
1881
2149
|
getOpenCodeProcessInfo: () => {
|
|
1882
2150
|
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.
|
|
2151
|
+
// Only ever expose pid/port for a server WE manage. Desktop no longer runs a
|
|
2152
|
+
// post-stop detached killer of a pre-captured pid; still withhold non-owned
|
|
2153
|
+
// process identity so diagnostics cannot imply we may kill an external serve.
|
|
1889
2154
|
return {
|
|
1890
2155
|
managed,
|
|
1891
2156
|
pid: managed && typeof openCodeProcess?.pid === 'number' ? openCodeProcess.pid : null,
|
|
@@ -1899,6 +2164,7 @@ async function main(options = {}) {
|
|
|
1899
2164
|
unsubscribeScheduledTaskEvents();
|
|
1900
2165
|
sessionIndexSyncRuntime?.stop();
|
|
1901
2166
|
sessionIndexService?.close();
|
|
2167
|
+
sessionArchiveServiceRef?.stop?.();
|
|
1902
2168
|
} catch {
|
|
1903
2169
|
// The index is a local cache; a failed close must not block shutdown.
|
|
1904
2170
|
}
|
|
@@ -1926,11 +2192,10 @@ async function main(options = {}) {
|
|
|
1926
2192
|
// best-effort shutdown of the dictation worker
|
|
1927
2193
|
}
|
|
1928
2194
|
try {
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
}
|
|
2195
|
+
const { stopLlmTempDirectory } = await import('./lib/llm/temp-directory.js');
|
|
2196
|
+
await stopLlmTempDirectory();
|
|
1932
2197
|
} catch {
|
|
1933
|
-
// best-effort cleanup of the
|
|
2198
|
+
// best-effort cleanup of the LLM generator temp OpenCode directory
|
|
1934
2199
|
}
|
|
1935
2200
|
return gracefulShutdown({
|
|
1936
2201
|
exitProcess: shutdownOptions.exitProcess ?? false,
|