@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
|
@@ -45,6 +45,7 @@ const createRuntime = (updateScheduledTaskState, overrides = {}) => createSchedu
|
|
|
45
45
|
waitForOpenCodeReady: vi.fn(async () => {
|
|
46
46
|
throw new Error('OpenCode unavailable');
|
|
47
47
|
}),
|
|
48
|
+
persistSessionMetadata: vi.fn(async () => ({})),
|
|
48
49
|
logger: { info: vi.fn(), warn: vi.fn() },
|
|
49
50
|
...overrides,
|
|
50
51
|
});
|
|
@@ -443,12 +444,16 @@ describe('scheduled-tasks run history and session lifecycle', () => {
|
|
|
443
444
|
it('creates session with Scheduled title and location, attaches history, then prompts via session.prompt', async () => {
|
|
444
445
|
const history = createHistoryStore();
|
|
445
446
|
const client = createSuccessfulClient();
|
|
447
|
+
const persistSessionMetadata = vi.fn(async () => ({}));
|
|
448
|
+
const onSystemSessionPersisted = vi.fn();
|
|
446
449
|
|
|
447
450
|
const updateScheduledTaskState = vi.fn(async (_projectID, _taskID, state) => ({
|
|
448
451
|
task: { ...scheduledTask, state: { ...scheduledTask.state, ...state } },
|
|
449
452
|
}));
|
|
450
453
|
const runtime = createRuntime(updateScheduledTaskState, {
|
|
451
454
|
runHistoryStore: history,
|
|
455
|
+
persistSessionMetadata,
|
|
456
|
+
onSystemSessionPersisted,
|
|
452
457
|
waitForOpenCodeReady: vi.fn(async () => {}),
|
|
453
458
|
});
|
|
454
459
|
await runtime.syncProject('project-1');
|
|
@@ -474,9 +479,37 @@ describe('scheduled-tasks run history and session lifecycle', () => {
|
|
|
474
479
|
location: { directory: '/tmp/project-1' },
|
|
475
480
|
title: expect.stringMatching(/^\[Scheduled\] Task /),
|
|
476
481
|
model: { id: 'gpt-4.1', providerID: 'openai' },
|
|
482
|
+
metadata: {
|
|
483
|
+
openchamber: {
|
|
484
|
+
scheduledTask: expect.objectContaining({
|
|
485
|
+
projectID: 'project-1',
|
|
486
|
+
taskID: 'task-1',
|
|
487
|
+
runID: started.id,
|
|
488
|
+
name: 'Task',
|
|
489
|
+
}),
|
|
490
|
+
},
|
|
491
|
+
},
|
|
477
492
|
}), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
|
478
|
-
expect(client.create.mock.calls[0][0].metadata).toBeUndefined();
|
|
479
493
|
expect(client.create.mock.calls[0][0].directory).toBeUndefined();
|
|
494
|
+
expect(persistSessionMetadata).toHaveBeenCalledWith('ses_1', {
|
|
495
|
+
openchamber: {
|
|
496
|
+
scheduledTask: expect.objectContaining({
|
|
497
|
+
projectID: 'project-1',
|
|
498
|
+
taskID: 'task-1',
|
|
499
|
+
runID: started.id,
|
|
500
|
+
name: 'Task',
|
|
501
|
+
}),
|
|
502
|
+
},
|
|
503
|
+
});
|
|
504
|
+
expect(onSystemSessionPersisted).toHaveBeenCalledWith({
|
|
505
|
+
sessionID: 'ses_1',
|
|
506
|
+
directory: '/tmp/project-1',
|
|
507
|
+
metadata: expect.objectContaining({
|
|
508
|
+
openchamber: expect.objectContaining({
|
|
509
|
+
scheduledTask: expect.objectContaining({ taskID: 'task-1' }),
|
|
510
|
+
}),
|
|
511
|
+
}),
|
|
512
|
+
});
|
|
480
513
|
expect(history.attachSession).toHaveBeenCalledWith(started.id, 'ses_1');
|
|
481
514
|
expect(client.prompt).toHaveBeenCalledWith({
|
|
482
515
|
sessionID: 'ses_1',
|
|
@@ -492,6 +525,48 @@ describe('scheduled-tasks run history and session lifecycle', () => {
|
|
|
492
525
|
expect(client.active.mock.invocationCallOrder[0]).toBeGreaterThan(client.prompt.mock.invocationCallOrder[0]);
|
|
493
526
|
});
|
|
494
527
|
|
|
528
|
+
it('refuses before session create when Host metadata persist is not configured', async () => {
|
|
529
|
+
const history = createHistoryStore();
|
|
530
|
+
const client = createSuccessfulClient();
|
|
531
|
+
const updateScheduledTaskState = vi.fn(async (_projectID, _taskID, state) => ({
|
|
532
|
+
task: { ...scheduledTask, state: { ...scheduledTask.state, ...state } },
|
|
533
|
+
}));
|
|
534
|
+
const runtime = createRuntime(updateScheduledTaskState, {
|
|
535
|
+
runHistoryStore: history,
|
|
536
|
+
persistSessionMetadata: null,
|
|
537
|
+
waitForOpenCodeReady: vi.fn(async () => {}),
|
|
538
|
+
});
|
|
539
|
+
await runtime.syncProject('project-1');
|
|
540
|
+
const result = await runtime.runNow('project-1', 'task-1');
|
|
541
|
+
|
|
542
|
+
expect(result.ok).toBe(false);
|
|
543
|
+
expect(result.error).toMatch(/session metadata persist is not configured/);
|
|
544
|
+
expect(client.create).not.toHaveBeenCalled();
|
|
545
|
+
expect(client.prompt).not.toHaveBeenCalled();
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
it('fails the run before prompt when Host metadata persist throws', async () => {
|
|
549
|
+
const history = createHistoryStore();
|
|
550
|
+
const client = createSuccessfulClient();
|
|
551
|
+
const updateScheduledTaskState = vi.fn(async (_projectID, _taskID, state) => ({
|
|
552
|
+
task: { ...scheduledTask, state: { ...scheduledTask.state, ...state } },
|
|
553
|
+
}));
|
|
554
|
+
const runtime = createRuntime(updateScheduledTaskState, {
|
|
555
|
+
runHistoryStore: history,
|
|
556
|
+
persistSessionMetadata: vi.fn(async () => {
|
|
557
|
+
throw new Error('store unavailable');
|
|
558
|
+
}),
|
|
559
|
+
waitForOpenCodeReady: vi.fn(async () => {}),
|
|
560
|
+
});
|
|
561
|
+
await runtime.syncProject('project-1');
|
|
562
|
+
const result = await runtime.runNow('project-1', 'task-1');
|
|
563
|
+
|
|
564
|
+
expect(result.ok).toBe(false);
|
|
565
|
+
expect(result.error).toMatch(/store unavailable/);
|
|
566
|
+
expect(client.create).toHaveBeenCalled();
|
|
567
|
+
expect(client.prompt).not.toHaveBeenCalled();
|
|
568
|
+
});
|
|
569
|
+
|
|
495
570
|
it('records error outcome and real duration when the assistant turn fails after admission', async () => {
|
|
496
571
|
const history = createHistoryStore();
|
|
497
572
|
const client = createSuccessfulClient({ settlement: 'assistant-error' });
|
|
@@ -763,6 +838,7 @@ describe('scheduled-tasks run history and session lifecycle', () => {
|
|
|
763
838
|
buildOpenCodeUrl: vi.fn(() => 'http://127.0.0.1:4096'),
|
|
764
839
|
getOpenCodeAuthHeaders: vi.fn(() => ({})),
|
|
765
840
|
waitForOpenCodeReady: vi.fn(async () => {}),
|
|
841
|
+
persistSessionMetadata: vi.fn(async () => ({})),
|
|
766
842
|
logger: { info: vi.fn(), warn: vi.fn() },
|
|
767
843
|
runHistoryStore: history,
|
|
768
844
|
maxRunDurationMs: 500,
|
|
@@ -948,6 +1024,7 @@ describe('scheduled-tasks run history and session lifecycle', () => {
|
|
|
948
1024
|
buildOpenCodeUrl: vi.fn(() => 'http://127.0.0.1:4096'),
|
|
949
1025
|
getOpenCodeAuthHeaders: vi.fn(() => ({})),
|
|
950
1026
|
waitForOpenCodeReady: vi.fn(async () => {}),
|
|
1027
|
+
persistSessionMetadata: vi.fn(async () => ({})),
|
|
951
1028
|
logger: { info: vi.fn(), warn: vi.fn() },
|
|
952
1029
|
runHistoryStore: history,
|
|
953
1030
|
persistSessionGoal,
|
|
@@ -1016,6 +1093,7 @@ describe('scheduled-tasks run history and session lifecycle', () => {
|
|
|
1016
1093
|
buildOpenCodeUrl: vi.fn(() => 'http://127.0.0.1:4096'),
|
|
1017
1094
|
getOpenCodeAuthHeaders: vi.fn(() => ({})),
|
|
1018
1095
|
waitForOpenCodeReady: vi.fn(async () => {}),
|
|
1096
|
+
persistSessionMetadata: vi.fn(async () => ({})),
|
|
1019
1097
|
logger: { info: vi.fn(), warn: vi.fn() },
|
|
1020
1098
|
runHistoryStore: history,
|
|
1021
1099
|
persistSessionGoal,
|
|
@@ -1581,6 +1659,7 @@ describe('scheduled-tasks cross-process slot occupancy', () => {
|
|
|
1581
1659
|
waitForOpenCodeReady: vi.fn(async () => {
|
|
1582
1660
|
throw new Error('OpenCode unavailable');
|
|
1583
1661
|
}),
|
|
1662
|
+
persistSessionMetadata: vi.fn(async () => ({})),
|
|
1584
1663
|
logger: { info: vi.fn(), warn: vi.fn() },
|
|
1585
1664
|
runHistoryStore: store,
|
|
1586
1665
|
notifyTaskRun,
|
|
@@ -16,14 +16,23 @@ PATCH. Goal progress therefore belongs in the Host
|
|
|
16
16
|
`packages/web/server/lib/session-metadata/` store (merge-patched under
|
|
17
17
|
`openchamber.goal`), not an OpenCode `PATCH /session/:id`.
|
|
18
18
|
|
|
19
|
-
`createSessionGoalRuntime` accepts optional seams
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
`createSessionGoalRuntime` accepts optional seams:
|
|
20
|
+
|
|
21
|
+
| Seam | Role |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `readSessionMetadata` | Read Host metadata for the session |
|
|
24
|
+
| `persistSessionGoal` | Full goal replace (routes / scheduled create) |
|
|
25
|
+
| `mutateSessionMetadata` | Preferred conditional commit: `decide(committed) → { ok, patch }` on the store lock |
|
|
26
|
+
|
|
27
|
+
When `mutateSessionMetadata` is present, runtime goal commits use it exclusively
|
|
28
|
+
(no OpenCode PATCH). When only `readSessionMetadata` + `persistSessionGoal` are
|
|
29
|
+
present, the runtime falls back to read-then-persist. When neither store path is
|
|
30
|
+
wired, the legacy OpenCode PATCH path remains (tests / unwired servers).
|
|
23
31
|
|
|
24
32
|
Those seams, the proxy overlay, and `PUT /api/openchamber/sessions/:id/metadata`
|
|
25
33
|
are wired in `server/index.js`. A UI metadata write notifies the runtime with
|
|
26
|
-
a synthetic `session.updated` so create/resume can arm the loop.
|
|
34
|
+
a synthetic `session.updated` so create/resume can arm the loop. Metadata PUT
|
|
35
|
+
normalizes `executionGeneration` for goal patches inside the store mutate lock.
|
|
27
36
|
|
|
28
37
|
**Capability is open** (`supported === true`). Scheduled-task goal create and
|
|
29
38
|
`POST /api/goals/:sessionId` persist an active goal into the same store as
|
|
@@ -42,14 +51,52 @@ synthetic `session.updated` so the loop can arm.
|
|
|
42
51
|
tokensUsed, // tokensCommitted + current segment (snapshot - baseline)
|
|
43
52
|
tokensBaseline, // segment start snapshot (pre-goal turn; 0 after compaction)
|
|
44
53
|
tokensCommitted, // closed segments' total (one segment per compaction)
|
|
45
|
-
turnsUsed, // auto-
|
|
54
|
+
turnsUsed, // auto-continuation attempts committed (capped at MAX_AUTO_TURNS)
|
|
46
55
|
blockedStreak, // consecutive blocked audit verdicts
|
|
47
56
|
auditFailStreak, // consecutive failed/unavailable audit calls
|
|
48
57
|
note, // latest audit progress note, <= 280 chars
|
|
49
58
|
statusReason, // why settled; 'resumed' is a kickoff signal from UI
|
|
50
59
|
lastAccountedMessageID, // incremental accounting cursor
|
|
60
|
+
executionGeneration, // execution permit generation (see pause boundary)
|
|
61
|
+
pendingContinuation, // durable admission (ticket 10); null when idle
|
|
51
62
|
createdAt, updatedAt
|
|
52
63
|
}
|
|
64
|
+
|
|
65
|
+
### Durable continuation admission (`pendingContinuation`)
|
|
66
|
+
|
|
67
|
+
Minimal Host-metadata field (not a parallel store). Written only through the
|
|
68
|
+
same conditional goal owner as other goal commits:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
{
|
|
72
|
+
messageID, // msg_goalc_<goalId>_<generation>_<turnsUsed>
|
|
73
|
+
goalId, generation, turnsUsed,
|
|
74
|
+
phase, // reserved | transport | uncertain | accepted
|
|
75
|
+
text, // fixed prompt payload for legal same-id re-dispatch
|
|
76
|
+
providerID, modelID, variant?, agent?,
|
|
77
|
+
error?, at
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Rules:
|
|
82
|
+
|
|
83
|
+
1. **Reserve before send** — persist fixed `messageID` + prompt/selection
|
|
84
|
+
identity with `phase: reserved` **without** bumping `turnsUsed`.
|
|
85
|
+
2. **Accept commit** — `turnsUsed` increment and `pendingContinuation: null`
|
|
86
|
+
share one conditional write after upstream accept (or reconcile `found`).
|
|
87
|
+
3. **Selection / pre-prompt drop** — pause or switchAgent/switchModel failure
|
|
88
|
+
clears reserved pending; **0 count**.
|
|
89
|
+
4. **Uncertain transport** — keep durable identity; pause auto-continue with a
|
|
90
|
+
user-visible `statusReason` (reuses blocked/pause reason UI). Reconcile via
|
|
91
|
+
official `session.inbox.list` / `session.message.get` (or projected list);
|
|
92
|
+
fetch failure is **unavailable**, never authoritative empty.
|
|
93
|
+
5. **Already received** — count once, clear pending; do not invent a new id.
|
|
94
|
+
6. **pause → resume / goal replace** — reserved pending cleared on pause;
|
|
95
|
+
transport/uncertain/accepted identity retained (no claim of upstream revoke).
|
|
96
|
+
Stale `goalId` / superseded `generation` never overwrite newer user ops;
|
|
97
|
+
found-under-stale-gen still counts once.
|
|
98
|
+
7. **Reboot** — restore pending from metadata, reconcile first, then same-id
|
|
99
|
+
fixed-payload re-dispatch only when still absent and generation matches.
|
|
53
100
|
```
|
|
54
101
|
|
|
55
102
|
The UI writes goals (create/edit/pause/resume/clear) by patching this
|
|
@@ -62,8 +109,49 @@ content, since "Implement this plan: X" alone gives the audit nothing to
|
|
|
62
109
|
judge against. The armed send also attaches a synthetic system-reminder
|
|
63
110
|
part telling the agent goal mode is active and that each turn should end
|
|
64
111
|
with a factual done/verified/remaining statement for the independent audit.
|
|
65
|
-
|
|
66
|
-
|
|
112
|
+
|
|
113
|
+
### Execution generation and pause/commit boundary
|
|
114
|
+
|
|
115
|
+
`executionGeneration` is the durable execution permit. It starts at `0` on
|
|
116
|
+
create and advances on:
|
|
117
|
+
|
|
118
|
+
- pause (user, abort, question) while status was `active`
|
|
119
|
+
- resume (`paused`/`blocked`/… → `active`)
|
|
120
|
+
- execution-condition edits (`tokenBudget`, `objective`, `objectiveFile`)
|
|
121
|
+
|
|
122
|
+
Settle paths (`active` → `complete` / `blocked` / `budgetLimited`) keep the
|
|
123
|
+
same generation. Writers go through `withGoalExecutionGeneration` (metadata
|
|
124
|
+
PUT, `persistSessionGoal` Host wiring) or the runtime's `advanceGeneration`
|
|
125
|
+
flag so UI patches that omit the field still bump correctly.
|
|
126
|
+
|
|
127
|
+
Runtime commits (continue accounting, settle, pause) validate **goal id +
|
|
128
|
+
expected generation + applicable status** on one serial boundary when the
|
|
129
|
+
Host `mutateSessionMetadata` seam is wired. A late audit that returns
|
|
130
|
+
`continue` / `complete` / `blocked` after pause cannot overwrite the paused
|
|
131
|
+
snapshot or start a new `session.prompt` continuation.
|
|
132
|
+
|
|
133
|
+
Local (in-process) ordering:
|
|
134
|
+
|
|
135
|
+
1. Pause / stop / `session.updated` paused → bump dispatch epoch + abort
|
|
136
|
+
in-flight audit controller + clear idle timer (**before** awaiting durable
|
|
137
|
+
write).
|
|
138
|
+
2. Tick captures epoch at start; re-checks before continue commit and before
|
|
139
|
+
dispatch.
|
|
140
|
+
3. `sendContinuation` re-validates **epoch + shutdown recovery + stopped** after
|
|
141
|
+
every await (`switchAgent` / `switchModel` / generation re-read) and again
|
|
142
|
+
immediately before `session.prompt`. It also re-reads durable goal
|
|
143
|
+
generation/status at the prompt boundary. A pause or shutdown that lands
|
|
144
|
+
during selection must drop with `uncertain: false` and **zero** prompt.
|
|
145
|
+
4. Continuation identity `{ goalId, generation, turnsUsed }` and
|
|
146
|
+
`phase: transport` are recorded **only at the actual prompt boundary** —
|
|
147
|
+
not before selection. Selection failures (agent/model switch) must **not**
|
|
148
|
+
be reported as prompt-uncertain. Uncertain applies only after prompt left
|
|
149
|
+
the process and transport failed; the identity is kept for reconcile. The
|
|
150
|
+
runtime does **not** claim full revoke of a request already handed upstream.
|
|
151
|
+
Explicit stop of the upstream turn remains the existing abort/stop operation.
|
|
152
|
+
|
|
153
|
+
Public seams for tests / controlled async: `runTick`, `pauseGoal`,
|
|
154
|
+
`getDispatchEpoch`, `getDispatchedContinuation`.
|
|
67
155
|
|
|
68
156
|
## File-backed objectives
|
|
69
157
|
|
|
@@ -168,11 +256,23 @@ before touching the filesystem). Rationale: metadata rides every
|
|
|
168
256
|
audit unavailable") — resumable, and settling resets the streak so
|
|
169
257
|
Resume gets fresh tolerance. A dead small model can never drive the
|
|
170
258
|
loop blind to the turn cap;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
259
|
+
- continue (ticket 10 durable admission): persist accounting +
|
|
260
|
+
`pendingContinuation` (`phase: reserved`, fixed `msg_goalc_…` id +
|
|
261
|
+
prompt/selection payload) **without** bumping `turnsUsed`; re-check
|
|
262
|
+
tail; then `session.switchAgent` / `session.switchModel` +
|
|
263
|
+
`session.prompt` with that stable id. Accept → one conditional commit
|
|
264
|
+
of `turnsUsed + 1` and clear pending. Selection/pre-prompt pause or
|
|
265
|
+
failure clears reserved pending (0 count). Uncertain transport keeps
|
|
266
|
+
durable identity and pauses auto-continue with a readable
|
|
267
|
+
`statusReason`; next tick / reboot reconciles via inbox / exact
|
|
268
|
+
message (fail ≠ empty) before any new id. Already-received counts
|
|
269
|
+
once. Synthetic is metadata-only (`goalContinuation`).
|
|
270
|
+
- **Shutdown recovery (ticket 07):** `session.execution.interrupted` with
|
|
271
|
+
`reason: shutdown` clears the idle timer and sets a **local** recovery
|
|
272
|
+
pending marker (not a parallel durable store). Auto-continue / tick stay
|
|
273
|
+
gated until authoritative `session.status` idle or a non-shutdown
|
|
274
|
+
execution terminal clears the marker. Goal status itself is unchanged.
|
|
275
|
+
|
|
176
276
|
4. Settling (`complete`/`blocked`/`budgetLimited`) fires the injected
|
|
177
277
|
`emitGoalNotification` so the user hears about it even with the UI closed.
|
|
178
278
|
The same settle also notifies a registered Assistant contact reporter
|
|
@@ -62,6 +62,8 @@ const buildActiveGoalRecord = ({
|
|
|
62
62
|
note: '',
|
|
63
63
|
statusReason: typeof statusReason === 'string' ? statusReason : '',
|
|
64
64
|
lastAccountedMessageID: '',
|
|
65
|
+
// Fresh goal starts a new execution generation (0). Resume / pause bump it.
|
|
66
|
+
executionGeneration: 0,
|
|
65
67
|
createdAt: now,
|
|
66
68
|
updatedAt: now,
|
|
67
69
|
};
|
|
@@ -204,10 +206,17 @@ export function registerSessionGoalRoutes(app, deps = {}) {
|
|
|
204
206
|
}
|
|
205
207
|
|
|
206
208
|
const now = Date.now();
|
|
209
|
+
const priorGeneration = Number.isFinite(currentGoal.executionGeneration)
|
|
210
|
+
&& currentGoal.executionGeneration >= 0
|
|
211
|
+
? Math.floor(currentGoal.executionGeneration)
|
|
212
|
+
: 0;
|
|
207
213
|
const goal = {
|
|
208
214
|
...currentGoal,
|
|
209
215
|
status: 'active',
|
|
210
216
|
statusReason: 'resumed',
|
|
217
|
+
// Resume opens a new execution generation so late audits from the prior
|
|
218
|
+
// active period cannot commit continue/settle.
|
|
219
|
+
executionGeneration: priorGeneration + 1,
|
|
211
220
|
updatedAt: now,
|
|
212
221
|
};
|
|
213
222
|
|