@vantran-se/openchamber-web 1.24.3 → 2.0.1
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 +2 -8
- package/bin/lib/commands-connect-url.js +3 -8
- package/bin/lib/commands-tunnel.js +3 -0
- package/dist/assets/{CodeMirrorCommentWidgets-BjJHrzmU.js → CodeMirrorCommentWidgets-ntXIbhV2.js} +1 -1
- package/dist/assets/DiffView-CjxUovbM.js +4 -0
- package/dist/assets/FilesView-DFWD0RQR.js +17 -0
- package/dist/assets/{GitView-CDOJy5Ay.js → GitView-BWa7e5vw.js} +4 -4
- package/dist/assets/{GuestAttachDialog-D3S0Rjic.js → GuestAttachDialog-DdOuyZzp.js} +1 -1
- package/dist/assets/GuestSurfacePane-DDfzid3U.js +1 -0
- package/dist/assets/{JsonTreeView-D0C9nU7K.js → JsonTreeView-3sGwqexh.js} +1 -1
- package/dist/assets/LinearIssuesView-C6dpIdjw.js +1 -0
- package/dist/assets/MarkdownImageGallery-Q7YR_tl4.js +1 -0
- package/dist/assets/MarkdownRendererImpl-DxDV56bL.js +12 -0
- package/dist/assets/OnboardingScreen-rK4Stg__.js +1 -0
- package/dist/assets/{PatchDiff-DnEhjXcC.js → PatchDiff-DS-IMU1j.js} +1 -1
- package/dist/assets/{PierreDiffViewer-DyxZVVVR.js → PierreDiffViewer-DW23KWKZ.js} +1 -1
- package/dist/assets/PlanView-BCk_VobP.js +5 -0
- package/dist/assets/PluginPane-BPP1dbck.js +3 -0
- package/dist/assets/SettingsView-kMmrpn43.js +29 -0
- package/dist/assets/SettingsWindow-BpvD6IYQ.js +1 -0
- package/dist/assets/SubmoduleDiffSummary-BLttSS1X.js +1 -0
- package/dist/assets/ToolOutputDialog-CtqDqbyr.js +15 -0
- package/dist/assets/ToolPartDiffPreview-5FcKdyRy.js +8 -0
- package/dist/assets/{VirtualizedFileDiff-0pyr_mHY.js → VirtualizedFileDiff-C763hNCR.js} +4 -4
- package/dist/assets/{WalkthroughView-yNj4nOP5.js → WalkthroughView-lap5btCF.js} +2 -2
- package/dist/assets/appThemeRegistry-u4zw1l0B.js +1 -0
- package/dist/assets/{commitAndPush-DvJKa3Ks.js → commitAndPush-CwGJfJG-.js} +1 -1
- package/dist/assets/{computeVirtualFileMetrics-DxTBMuu-.js → computeVirtualFileMetrics-DW5jjX4n.js} +1 -1
- package/dist/assets/de-CndEg67T.js +10 -0
- package/dist/assets/es-DglvPlaC.js +16 -0
- package/dist/assets/fr-DejPCpbS.js +14 -0
- package/dist/assets/index-C2r64QfD.js +1 -0
- package/dist/assets/index-CLcM8HKx.css +1 -0
- package/dist/assets/index-CvLgnuNI.js +41 -0
- package/dist/assets/{isDiffPlainText-D7FkBMP6.js → isDiffPlainText-D47a6hMP.js} +1 -1
- package/dist/assets/{isFilePlainText-CL2vsrIZ.js → isFilePlainText-B-mGgeKl.js} +1 -1
- package/dist/assets/ja-CVpQawCd.js +16 -0
- package/dist/assets/ko-Bw446h9j.js +16 -0
- package/dist/assets/main-Bz4WWXbr.js +2 -0
- package/dist/assets/main-oreqDsOV.js +896 -0
- package/dist/assets/{markdownCore-Dh7WEsdM.js → markdownCore-D2e5sp9y.js} +4 -4
- package/dist/assets/miniChat-D1v2gsBI.js +2 -0
- package/dist/assets/mobile-DBj3lCf2.js +2 -0
- package/dist/assets/{patchFileDiff-Bsba8KFp.js → patchFileDiff-BpeUOV91.js} +3 -3
- package/dist/assets/pl-BYNlPdhm.js +16 -0
- package/dist/assets/pt-BR-CL-Yfv9H.js +16 -0
- package/dist/assets/renderElectronMiniChatApp-DVtfEB2z.js +2 -0
- package/dist/assets/renderMobileApp-DFp9-xbG.js +25 -0
- package/dist/assets/runtimeEndpointReset-CsIpUep1.js +27 -0
- package/dist/assets/scheduledTasksApi-B5OHVpPM.js +1 -0
- package/dist/assets/{shikiHighlight-8_3csmr6.js → shikiHighlight-DNm2Z_Jc.js} +1 -1
- package/dist/assets/{textMateThemeFromAppTheme-CHo2fCgW.js → textMateThemeFromAppTheme-DGF2kG7g.js} +1 -1
- package/dist/assets/tr-DzmbxLy-.js +7 -0
- package/dist/assets/uk-C7vQnwro.js +16 -0
- package/dist/assets/useAppFontEffects-Ci3FEaPf.js +7337 -0
- package/dist/assets/{useInlineCommentController-DkQ_gqpn.js → useInlineCommentController-CuUuakrt.js} +2 -2
- package/dist/assets/useRootScrollLock-CQIsyERq.js +2 -0
- package/dist/assets/{vendor-codemirror-language-data-CdzUmUyZ.js → vendor-codemirror-language-data-CQa7_1cr.js} +2 -2
- package/dist/assets/vendor-cron-parser-CjvYVigk.js +2 -0
- package/dist/assets/vendor-opencode-client-_BAHQo4R.js +12 -0
- package/dist/assets/{vendor-remixicon-react-BDmGmFCA.js → vendor-remixicon-react-D6dZ0UwF.js} +1 -1
- package/dist/assets/{vendor-zod-CgAdXWZO.js → vendor-zod-Gea9uBlY.js} +1 -1
- package/dist/assets/{web-components-B8IcVQAA.js → web-components-B6tKQyJN.js} +2 -2
- package/dist/assets/zh-CN-Cl0srS-z.js +16 -0
- package/dist/assets/zh-TW-DtII5bDb.js +16 -0
- package/dist/index.html +13 -7
- package/dist/mini-chat.html +5 -5
- package/dist/mobile.html +5 -5
- package/package.json +6 -5
- package/server/index.d.ts +1 -0
- package/server/index.js +246 -91
- package/server/lib/agent-tool/DOCUMENTATION.md +32 -15
- package/server/lib/agent-tool/runtime.js +135 -54
- package/server/lib/agent-tool/runtime.test.js +155 -87
- package/server/lib/browser-control/DOCUMENTATION.md +37 -2
- package/server/lib/browser-control/provider.js +217 -0
- package/server/lib/browser-control/provider.test.js +251 -0
- package/server/lib/context-obligatory/runtime.js +61 -50
- package/server/lib/context-obligatory/runtime.test.js +62 -162
- package/server/lib/event-stream/DOCUMENTATION.md +12 -1
- package/server/lib/event-stream/delta-coalescer.js +0 -0
- package/server/lib/event-stream/delta-coalescer.test.js +68 -57
- package/server/lib/event-stream/directory-ws-bridge.js +1 -1
- package/server/lib/event-stream/global-hub.js +10 -1
- package/server/lib/event-stream/global-hub.test.js +27 -26
- package/server/lib/event-stream/index.js +6 -0
- package/server/lib/event-stream/protocol.js +26 -19
- package/server/lib/event-stream/protocol.test.js +18 -7
- package/server/lib/event-stream/rebind.test.js +5 -5
- package/server/lib/event-stream/runtime.test.js +17 -15
- package/server/lib/event-stream/translate-v2.js +313 -0
- package/server/lib/event-stream/translate-v2.test.js +209 -0
- package/server/lib/event-stream/upstream-reader.test.js +16 -16
- package/server/lib/fs/DOCUMENTATION.md +4 -2
- package/server/lib/fs/byte-range.js +35 -0
- package/server/lib/fs/byte-range.test.js +31 -0
- package/server/lib/fs/routes.js +47 -42
- package/server/lib/fs/routes.test.js +123 -18
- package/server/lib/git/service.js +12 -0
- package/server/lib/github/DOCUMENTATION.md +1 -1
- package/server/lib/github/pr-status.js +22 -2
- package/server/lib/github/pr-status.test.js +27 -14
- package/server/lib/guests/DOCUMENTATION.md +13 -0
- package/server/lib/guests/catalog.js +12 -0
- package/server/lib/guests/catalog.test.js +33 -0
- package/server/lib/guests/routes.js +10 -1
- package/server/lib/guests/service.js +192 -14
- package/server/lib/guests/service.test.js +201 -1
- package/server/lib/guests/surface.js +630 -0
- package/server/lib/guests/surface.test.js +486 -0
- package/server/lib/markdown-image-grants/routes.js +18 -5
- package/server/lib/markdown-image-grants/routes.test.js +9 -6
- package/server/lib/message-queue/DOCUMENTATION.md +33 -22
- package/server/lib/message-queue/runtime.js +155 -100
- package/server/lib/message-queue/runtime.test.js +168 -82
- package/server/lib/notifications/DOCUMENTATION.md +28 -0
- package/server/lib/notifications/control-stream.http.test.js +68 -0
- package/server/lib/notifications/emitter-runtime.js +15 -0
- package/server/lib/notifications/emitter-runtime.test.js +32 -0
- package/server/lib/notifications/push-runtime.js +5 -1
- package/server/lib/notifications/push-runtime.test.js +2 -2
- package/server/lib/notifications/routes.js +1 -1
- package/server/lib/notifications/runtime.js +115 -26
- package/server/lib/notifications/template-runtime.js +13 -15
- package/server/lib/notifications/template-runtime.test.js +16 -9
- package/server/lib/notifications/trigger-runtime.test.js +187 -0
- package/server/lib/openchamber-control/DOCUMENTATION.md +10 -0
- package/server/lib/openchamber-control/actions.js +3 -2
- package/server/lib/openchamber-control/error.js +1 -1
- package/server/lib/openchamber-control/file-open.js +59 -0
- package/server/lib/openchamber-control/file-open.test.js +57 -0
- package/server/lib/openchamber-control/routes.test.js +12 -0
- package/server/lib/openchamber-control/service.js +102 -49
- package/server/lib/openchamber-control/service.test.js +84 -44
- package/server/lib/openchamber-sessions/archive-store.js +224 -0
- package/server/lib/openchamber-sessions/archive-store.test.js +187 -0
- package/server/lib/openchamber-sessions/opencode-client.js +22 -0
- package/server/lib/openchamber-sessions/routes.js +398 -328
- package/server/lib/openchamber-sessions/routes.test.js +777 -740
- package/server/lib/openchamber-sessions/session-metadata-store.js +285 -0
- package/server/lib/openchamber-sessions/session-metadata-store.test.js +259 -0
- package/server/lib/opencode/DOCUMENTATION.md +449 -29
- package/server/lib/opencode/agents.js +233 -327
- package/server/lib/opencode/auth.js +41 -44
- package/server/lib/opencode/auth.test.js +92 -0
- package/server/lib/opencode/cli-upgrade.d.ts +4 -0
- package/server/lib/opencode/cli-upgrade.js +18 -0
- package/server/lib/opencode/cli-upgrade.test.js +36 -0
- package/server/lib/opencode/commands.js +164 -145
- package/server/lib/opencode/compatibility.d.ts +16 -0
- package/server/lib/opencode/compatibility.js +88 -0
- package/server/lib/opencode/compatibility.test.js +62 -0
- package/server/lib/opencode/config-entity-routes.js +58 -29
- package/server/lib/opencode/config-entity-v2.test.js +290 -0
- package/server/lib/opencode/config-mutation-response.js +17 -7
- package/server/lib/opencode/config-mutation-response.test.js +4 -7
- package/server/lib/opencode/config-paths.test.js +2 -2
- package/server/lib/opencode/config-v2.d.ts +183 -0
- package/server/lib/opencode/config-v2.js +801 -0
- package/server/lib/opencode/config-v2.test.js +466 -0
- package/server/lib/opencode/credential-db.js +144 -0
- package/server/lib/opencode/credential-db.test.js +104 -0
- package/server/lib/opencode/env-runtime.js +48 -9
- package/server/lib/opencode/env-runtime.test.js +45 -0
- package/server/lib/opencode/feature-routes-runtime.js +15 -5
- package/server/lib/opencode/lifecycle-process.test.js +7 -4
- package/server/lib/opencode/lifecycle.js +85 -30
- package/server/lib/opencode/lifecycle.test.js +80 -8
- package/server/lib/opencode/login-shell-env.js +27 -0
- package/server/lib/opencode/managed-config-file.js +119 -0
- package/server/lib/opencode/managed-config-file.test.js +152 -0
- package/server/lib/opencode/managed-plugin-config.js +33 -13
- package/server/lib/opencode/mcp.js +43 -149
- package/server/lib/opencode/network-runtime.js +6 -7
- package/server/lib/opencode/openchamber-routes.test.js +2 -5
- package/server/lib/opencode/plugin-routes.js +3 -3
- package/server/lib/opencode/plugin-routes.test.js +6 -24
- package/server/lib/opencode/plugins.js +91 -40
- package/server/lib/opencode/plugins.test.js +28 -15
- package/server/lib/opencode/providers.js +63 -83
- package/server/lib/opencode/providers.test.js +128 -59
- package/server/lib/opencode/proxy-agent-wiring.test.js +4 -2
- package/server/lib/opencode/proxy.js +179 -129
- package/server/lib/opencode/pwa-manifest-routes.js +4 -2
- package/server/lib/opencode/pwa-manifest-routes.test.js +3 -2
- package/server/lib/opencode/response-envelope.js +14 -0
- package/server/lib/opencode/response-envelope.test.js +23 -0
- package/server/lib/opencode/routes-upgrade.test.js +73 -116
- package/server/lib/opencode/routes.js +121 -428
- package/server/lib/opencode/server-utils-runtime.js +10 -4
- package/server/lib/opencode/session-activity.js +78 -0
- package/server/lib/opencode/session-runtime.js +21 -10
- package/server/lib/opencode/session-runtime.test.js +9 -9
- package/server/lib/opencode/settings-helpers.js +9 -9
- package/server/lib/opencode/settings-helpers.test.js +7 -12
- package/server/lib/opencode/settings-registry.json +6 -8
- package/server/lib/opencode/settings-runtime.js +18 -1
- package/server/lib/opencode/settings-runtime.test.js +31 -2
- package/server/lib/opencode/shared.js +54 -22
- package/server/lib/opencode/shared.test.js +8 -4
- package/server/lib/opencode/shutdown-runtime.js +54 -7
- package/server/lib/opencode/shutdown-runtime.test.js +224 -30
- package/server/lib/opencode/skill-routes.js +23 -24
- package/server/lib/opencode/skills.js +7 -5
- package/server/lib/opencode/tunnel-wiring-runtime.js +2 -1
- package/server/lib/opencode/upgrade-capability.test.js +1 -1
- package/server/lib/opencode/v1-migration-topup.js +288 -0
- package/server/lib/opencode/v1-migration-topup.test.js +266 -0
- package/server/lib/opencode/v2-install.d.ts +8 -0
- package/server/lib/opencode/v2-install.js +158 -0
- package/server/lib/opencode/v2-install.test.js +124 -0
- package/server/lib/opencode/watcher.js +10 -3
- package/server/lib/opencode/watcher.test.js +17 -21
- package/server/lib/opencode/websearch-config.js +66 -0
- package/server/lib/package-manager.js +55 -68
- package/server/lib/package-manager.test.js +241 -75
- package/server/lib/permission-auto-accept/runtime.js +38 -22
- package/server/lib/permission-auto-accept/runtime.test.js +39 -17
- package/server/lib/quota/DOCUMENTATION.md +4 -0
- package/server/lib/quota/providers/xai.js +4 -4
- package/server/lib/relay/tunnel-host.js +4 -1
- package/server/lib/relay/tunnel-host.test.js +7 -0
- package/server/lib/routing/DOCUMENTATION.md +52 -21
- package/server/lib/routing/defaults.js +23 -6
- package/server/lib/routing/jev.js +17 -7
- package/server/lib/routing/routes.http.test.js +68 -33
- package/server/lib/routing/routes.js +65 -22
- package/server/lib/routing/runtime.js +145 -48
- package/server/lib/routing/runtime.test.js +79 -55
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +4 -0
- package/server/lib/scheduled-tasks/issue-2710-double-execution.test.js +51 -46
- package/server/lib/scheduled-tasks/runtime.js +81 -74
- package/server/lib/scheduled-tasks/runtime.test.js +53 -1
- package/server/lib/session-assist/DOCUMENTATION.md +8 -3
- package/server/lib/session-assist/context.js +122 -46
- package/server/lib/session-assist/context.test.js +117 -49
- package/server/lib/session-assist/runtime.js +52 -22
- package/server/lib/session-assist/runtime.test.js +145 -173
- package/server/lib/session-goal/DOCUMENTATION.md +23 -15
- package/server/lib/session-goal/create.js +9 -12
- package/server/lib/session-goal/create.test.js +27 -28
- package/server/lib/session-goal/runtime.js +164 -77
- package/server/lib/session-goal/runtime.test.js +271 -519
- package/server/lib/session-knowledge/DOCUMENTATION.md +5 -0
- package/server/lib/session-knowledge/runtime.js +59 -41
- package/server/lib/session-knowledge/runtime.test.js +90 -20
- package/server/lib/small-model/DOCUMENTATION.md +154 -208
- package/server/lib/small-model/client.js +113 -0
- package/server/lib/small-model/index.js +296 -158
- package/server/lib/small-model/index.test.js +423 -256
- package/server/lib/small-model/routes.js +1 -1
- package/server/lib/spaces/DOCUMENTATION.md +807 -0
- package/server/lib/spaces/code-in-bait.js +185 -0
- package/server/lib/spaces/code-in.js +641 -0
- package/server/lib/spaces/code-in.test.js +1048 -0
- package/server/lib/spaces/errors.js +8 -0
- package/server/lib/spaces/exec-http.js +94 -0
- package/server/lib/spaces/gatekeeper-channel.js +202 -0
- package/server/lib/spaces/gatekeeper-channel.test.js +215 -0
- package/server/lib/spaces/gatekeeper-program.cjs +914 -0
- package/server/lib/spaces/gatekeeper-program.test.js +1391 -0
- package/server/lib/spaces/hardening.js +457 -0
- package/server/lib/spaces/hardening.test.js +368 -0
- package/server/lib/spaces/host-git.js +127 -0
- package/server/lib/spaces/host-git.test.js +137 -0
- package/server/lib/spaces/labels.js +234 -0
- package/server/lib/spaces/labels.test.js +219 -0
- package/server/lib/spaces/layout.js +184 -0
- package/server/lib/spaces/layout.test.js +30 -0
- package/server/lib/spaces/manager.js +82 -0
- package/server/lib/spaces/manager.test.js +114 -0
- package/server/lib/spaces/places/code-in.docker.live.test.js +216 -0
- package/server/lib/spaces/places/contract-suite.js +156 -0
- package/server/lib/spaces/places/contract.docker.live.test.js +7 -0
- package/server/lib/spaces/places/contract.test.js +6 -0
- package/server/lib/spaces/places/docker-engine.js +126 -0
- package/server/lib/spaces/places/docker-live-support.js +202 -0
- package/server/lib/spaces/places/docker-tools.js +186 -0
- package/server/lib/spaces/places/docker.js +587 -0
- package/server/lib/spaces/places/docker.test.js +1610 -0
- package/server/lib/spaces/places/escape-suite.js +1018 -0
- package/server/lib/spaces/places/escape.docker.live.test.js +7 -0
- package/server/lib/spaces/places/fake-docker.js +375 -0
- package/server/lib/spaces/places/memory-place.js +103 -0
- package/server/lib/spaces/places/packed.docker.live.test.js +77 -0
- package/server/lib/spaces/places/registry.js +43 -0
- package/server/lib/spaces/places/registry.test.js +50 -0
- package/server/lib/spaces/places/server.docker.live.test.js +225 -0
- package/server/lib/spaces/run-command.js +261 -0
- package/server/lib/spaces/run-command.test.js +396 -0
- package/server/lib/spaces/space-server.js +190 -0
- package/server/lib/spaces/space-server.test.js +335 -0
- package/server/lib/spaces/tools-filler.js +82 -0
- package/server/lib/spaces/tools-filler.test.js +148 -0
- package/server/lib/spaces/tools-pack.js +49 -0
- package/server/lib/spaces/tools-pack.test.js +57 -0
- package/server/lib/spaces/tools.js +138 -0
- package/server/lib/spaces/tools.test.js +153 -0
- package/server/lib/tts/openai-sdk.js +11 -0
- package/server/lib/tts/service.js +7 -5
- package/server/lib/tts/stt.js +3 -2
- package/server/lib/tunnels/DOCUMENTATION.md +2 -0
- package/server/lib/tunnels/routes.js +7 -0
- package/server/lib/tunnels/routes.test.js +55 -0
- package/server/lib/ui-auth/ui-auth.js +38 -2
- package/server/lib/ui-auth/ui-auth.test.js +42 -0
- package/server/lib/ui-auth/ui-passkeys.js +12 -10
- package/server/lib/walkthrough/DOCUMENTATION.md +10 -1
- package/server/lib/walkthrough/pull-request.js +61 -8
- package/server/lib/walkthrough/pull-request.test.js +54 -1
- package/server/lib/walkthrough/routes.js +20 -0
- package/server/lib/walkthrough/routes.test.js +19 -0
- package/server/opencode-proxy.test.js +190 -166
- package/server/opencode-worktree-readiness.test.js +5 -4
- package/dist/assets/DiffView-COVQhWGd.js +0 -4
- package/dist/assets/FilesView-B1V5JxFX.js +0 -13
- package/dist/assets/LinearIssuesView-D7FKg1XJ.js +0 -1
- package/dist/assets/MarkdownImageGallery-BrFjAVEf.js +0 -1
- package/dist/assets/MarkdownRendererImpl-DWepTafh.js +0 -12
- package/dist/assets/OnboardingScreen-Dyxxiqdt.js +0 -1
- package/dist/assets/PlanView-LW2z_EAP.js +0 -5
- package/dist/assets/PluginPane-B4tKno2h.js +0 -3
- package/dist/assets/SettingsView-DEaMulN9.js +0 -29
- package/dist/assets/SettingsWindow-FLDJXOgQ.js +0 -1
- package/dist/assets/SubmoduleDiffSummary-CvVwD-Vi.js +0 -1
- package/dist/assets/ToolOutputDialog-BiP0x2Rw.js +0 -15
- package/dist/assets/ToolPartDiffPreview-CkR4msKP.js +0 -8
- package/dist/assets/appThemeRegistry-BuUKhbYQ.js +0 -1
- package/dist/assets/de-DgxgFyGG.js +0 -10
- package/dist/assets/es-BFsZj5F_.js +0 -16
- package/dist/assets/fr-jdZ5KKQi.js +0 -14
- package/dist/assets/index-CKHjPKbq.js +0 -1
- package/dist/assets/index-Cbci4i1W.js +0 -40
- package/dist/assets/index-DqaMWNrC.css +0 -1
- package/dist/assets/ja-C5kKrhO4.js +0 -16
- package/dist/assets/ko-DXDTT_0O.js +0 -16
- package/dist/assets/main-CZALtVek.js +0 -896
- package/dist/assets/main-CgXMBNvG.js +0 -2
- package/dist/assets/miniChat-CwTmDixi.js +0 -2
- package/dist/assets/mobile-CLf2vCtO.js +0 -2
- package/dist/assets/pl-D-7x4Y8Q.js +0 -16
- package/dist/assets/pt-BR-CSBZrHa8.js +0 -16
- package/dist/assets/renderElectronMiniChatApp-C5gAFBk0.js +0 -2
- package/dist/assets/renderMobileApp-V4hYd32H.js +0 -25
- package/dist/assets/runtimeEndpointReset-DhlHCn-2.js +0 -25
- package/dist/assets/scheduledTasksApi-DzjbLd8P.js +0 -1
- package/dist/assets/tr-Dr-oJ22L.js +0 -7
- package/dist/assets/uk-9Nx83UcI.js +0 -16
- package/dist/assets/useAppFontEffects-khZXpFL_.js +0 -7333
- package/dist/assets/useRootScrollLock-DdvHf9Pt.js +0 -2
- package/dist/assets/vendor-cron-parser-CUcP7OfX.js +0 -2
- package/dist/assets/vendor-opencode-sdk-BJ73u-bH.js +0 -7
- package/dist/assets/zh-CN-Bxy_Hj3r.js +0 -16
- package/dist/assets/zh-TW-0BB4gpHM.js +0 -16
- package/server/lib/opencode/mcp-oauth-callback.test.js +0 -111
- package/server/lib/routing/feature-flag.js +0 -11
- package/server/lib/small-model/call.js +0 -851
- package/server/lib/small-model/call.test.js +0 -1292
- package/server/lib/small-model/catalog.js +0 -13
- package/server/lib/small-model/resolve.js +0 -131
- package/server/lib/small-model/resolve.test.js +0 -197
- package/server/lib/small-model/runtime-providers.js +0 -164
- package/server/lib/small-model/runtime-providers.test.js +0 -118
- package/server/lib/system-prompt/DOCUMENTATION.md +0 -36
- package/server/lib/system-prompt/runtime.js +0 -49
- package/server/lib/system-prompt/runtime.test.js +0 -76
- package/server/lib/walkthrough/reproduce-2607.test.js +0 -148
|
@@ -22,6 +22,8 @@ export const createServerUtilsRuntime = (dependencies) => {
|
|
|
22
22
|
setOpenCodeNotReadySince,
|
|
23
23
|
clearLastOpenCodeError,
|
|
24
24
|
getLoginShellPath,
|
|
25
|
+
getArchivedSessions = null,
|
|
26
|
+
getStoredSessionMetadata = null,
|
|
25
27
|
} = dependencies;
|
|
26
28
|
|
|
27
29
|
const setOpenCodePort = (port) => {
|
|
@@ -191,16 +193,18 @@ export const createServerUtilsRuntime = (dependencies) => {
|
|
|
191
193
|
throw new Error(`Failed to fetch ${invalidMessage} (status ${response.status})`);
|
|
192
194
|
}
|
|
193
195
|
|
|
194
|
-
|
|
196
|
+
// OpenCode 2.x answers `/api/*` with `{ location, data }`.
|
|
197
|
+
const body = await response.json().catch(() => null);
|
|
198
|
+
const payload = Array.isArray(body) ? body : body?.data;
|
|
195
199
|
if (!Array.isArray(payload)) {
|
|
196
200
|
throw new Error(`Invalid ${invalidMessage} payload from OpenCode`);
|
|
197
201
|
}
|
|
198
202
|
return payload;
|
|
199
203
|
};
|
|
200
204
|
|
|
201
|
-
const fetchAgentsSnapshot = () => fetchArraySnapshot('/agent', 'agents snapshot');
|
|
202
|
-
const fetchProvidersSnapshot = () => fetchArraySnapshot('/provider', 'providers snapshot');
|
|
203
|
-
const fetchModelsSnapshot = () => fetchArraySnapshot('/model', 'models snapshot');
|
|
205
|
+
const fetchAgentsSnapshot = () => fetchArraySnapshot('/api/agent', 'agents snapshot');
|
|
206
|
+
const fetchProvidersSnapshot = () => fetchArraySnapshot('/api/provider', 'providers snapshot');
|
|
207
|
+
const fetchModelsSnapshot = () => fetchArraySnapshot('/api/model', 'models snapshot');
|
|
204
208
|
|
|
205
209
|
const setupProxy = (app) => {
|
|
206
210
|
registerOpenCodeProxy(app, {
|
|
@@ -215,6 +219,8 @@ export const createServerUtilsRuntime = (dependencies) => {
|
|
|
215
219
|
ensureOpenCodeApiPrefix,
|
|
216
220
|
getSseUpstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
|
|
217
221
|
getUiNotificationClients,
|
|
222
|
+
getArchivedSessions,
|
|
223
|
+
getStoredSessionMetadata,
|
|
218
224
|
});
|
|
219
225
|
};
|
|
220
226
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a session's turn has really ended.
|
|
3
|
+
*
|
|
4
|
+
* A parent session goes idle while a background subagent keeps working in a
|
|
5
|
+
* child session. When the child finishes, OpenCode delivers its result to the
|
|
6
|
+
* parent, which runs again and goes idle a second time. So the parent's first
|
|
7
|
+
* idle is a pause, not the end of the turn: anything that treats idle as
|
|
8
|
+
* "done" (goal audits, ready notifications) has to check the children too.
|
|
9
|
+
*
|
|
10
|
+
* Every read answers `null` when OpenCode could not be asked: "could not look"
|
|
11
|
+
* must never pass for "nothing is running".
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { unwrapOpenCodeResponse } from './response-envelope.js';
|
|
15
|
+
|
|
16
|
+
const CHILDREN_PAGE_SIZE = 50;
|
|
17
|
+
const CHILDREN_MAX_PAGES = 8;
|
|
18
|
+
|
|
19
|
+
export const createSessionActivityProbe = ({ buildOpenCodeUrl, getOpenCodeAuthHeaders, timeoutMs = 10_000, fetchImpl = fetch }) => {
|
|
20
|
+
const openCodeGet = async (fetchPath, query) => {
|
|
21
|
+
const base = buildOpenCodeUrl(fetchPath, '');
|
|
22
|
+
const search = new URLSearchParams(query || {}).toString();
|
|
23
|
+
const response = await fetchImpl(search ? `${base}?${search}` : base, {
|
|
24
|
+
method: 'GET',
|
|
25
|
+
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() },
|
|
26
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new Error(`OpenCode GET ${fetchPath} failed with ${response.status}`);
|
|
30
|
+
}
|
|
31
|
+
return unwrapOpenCodeResponse(await response.json().catch(() => null));
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* `/api/session/active` is global and lists only the sessions running right
|
|
36
|
+
* now (`{ data: { [id]: status } }`), so an absent id is idle.
|
|
37
|
+
*/
|
|
38
|
+
const fetchActiveSessionStatuses = async () => {
|
|
39
|
+
const statuses = await openCodeGet('/api/session/active').catch(() => null);
|
|
40
|
+
return statuses && typeof statuses === 'object' && !Array.isArray(statuses) ? statuses : null;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* v2 has no `/session/{id}/children`; `GET /api/session?parentID=` lists a
|
|
45
|
+
* parent's subagent sessions, newest first, in cursor pages. Later pages
|
|
46
|
+
* carry the filter inside the cursor, so only the cursor and the limit
|
|
47
|
+
* travel. A parent with more subagents than this walks is unknown (`null`).
|
|
48
|
+
*/
|
|
49
|
+
const fetchChildSessionIds = async (sessionId) => {
|
|
50
|
+
const ids = [];
|
|
51
|
+
const seenCursors = new Set();
|
|
52
|
+
let cursor;
|
|
53
|
+
for (let pageNumber = 0; pageNumber < CHILDREN_MAX_PAGES; pageNumber += 1) {
|
|
54
|
+
const page = await openCodeGet('/api/session', {
|
|
55
|
+
limit: String(CHILDREN_PAGE_SIZE),
|
|
56
|
+
...(cursor ? { cursor } : { parentID: sessionId }),
|
|
57
|
+
}).catch(() => null);
|
|
58
|
+
if (!Array.isArray(page?.data)) return null;
|
|
59
|
+
for (const child of page.data) {
|
|
60
|
+
if (typeof child?.id === 'string' && child.id) ids.push(child.id);
|
|
61
|
+
}
|
|
62
|
+
const next = page.cursor?.next;
|
|
63
|
+
if (!next || page.data.length === 0 || seenCursors.has(next)) return ids;
|
|
64
|
+
seenCursors.add(next);
|
|
65
|
+
cursor = next;
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/** True when a subagent of the session is still running; null when unknown. */
|
|
71
|
+
const hasWorkingChildren = async (sessionId, statuses) => {
|
|
72
|
+
const children = await fetchChildSessionIds(sessionId);
|
|
73
|
+
if (!children) return null;
|
|
74
|
+
return children.some((id) => Boolean(statuses[id]));
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return { fetchActiveSessionStatuses, fetchChildSessionIds, hasWorkingChildren };
|
|
78
|
+
};
|
|
@@ -45,10 +45,10 @@ export const createSessionRuntime = ({ writeSseEvent, getNotificationClients, br
|
|
|
45
45
|
const sessionActivityCooldowns = new Map();
|
|
46
46
|
const sessionStates = new Map();
|
|
47
47
|
const sessionAttentionStates = new Map();
|
|
48
|
-
// Pending permission and
|
|
48
|
+
// Pending permission requests and forms per session, kept from the same
|
|
49
49
|
// upstream stream. Clients that do not initialize a directory cannot read
|
|
50
|
-
// its pending list from OpenCode (that read creates
|
|
51
|
-
//
|
|
50
|
+
// its pending list from OpenCode (that read creates a location), so this map
|
|
51
|
+
// is their seed. Entries live until the matching reply, the session's
|
|
52
52
|
// deletion, or an OpenCode restart, which drops every pending request.
|
|
53
53
|
const pendingRequestsBySession = new Map();
|
|
54
54
|
let activeSessionCount = 0;
|
|
@@ -56,7 +56,7 @@ export const createSessionRuntime = ({ writeSseEvent, getNotificationClients, br
|
|
|
56
56
|
const getOrCreatePendingRequests = (sessionId) => {
|
|
57
57
|
let entry = pendingRequestsBySession.get(sessionId);
|
|
58
58
|
if (!entry) {
|
|
59
|
-
entry = { permissions: new Map(),
|
|
59
|
+
entry = { permissions: new Map(), forms: new Map() };
|
|
60
60
|
pendingRequestsBySession.set(sessionId, entry);
|
|
61
61
|
}
|
|
62
62
|
return entry;
|
|
@@ -69,25 +69,36 @@ export const createSessionRuntime = ({ writeSseEvent, getNotificationClients, br
|
|
|
69
69
|
// pending request of that kind we can still vouch for.
|
|
70
70
|
if (requestId) entry[kind].delete(requestId);
|
|
71
71
|
else entry[kind].clear();
|
|
72
|
-
if (entry.permissions.size === 0 && entry.
|
|
72
|
+
if (entry.permissions.size === 0 && entry.forms.size === 0) pendingRequestsBySession.delete(sessionId);
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
const processBlockingRequestPayload = (payload) => {
|
|
76
76
|
if (!payload || typeof payload.type !== 'string') return;
|
|
77
77
|
const properties = payload.properties && typeof payload.properties === 'object' ? payload.properties : {};
|
|
78
|
-
if (payload.type === 'permission.asked'
|
|
78
|
+
if (payload.type === 'permission.asked') {
|
|
79
79
|
const sessionId = readRequestId(properties.sessionID);
|
|
80
80
|
const requestId = readRequestId(properties.id);
|
|
81
81
|
if (!sessionId || !requestId) return;
|
|
82
|
-
getOrCreatePendingRequests(sessionId)
|
|
82
|
+
getOrCreatePendingRequests(sessionId).permissions.set(requestId, properties);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// v2 replaced the question tool with forms; the request itself rides in
|
|
86
|
+
// `properties.form`, so that object is what clients receive.
|
|
87
|
+
if (payload.type === 'form.created') {
|
|
88
|
+
const form = properties.form && typeof properties.form === 'object' ? properties.form : null;
|
|
89
|
+
if (!form) return;
|
|
90
|
+
const sessionId = readRequestId(form.sessionID) || readRequestId(properties.sessionID);
|
|
91
|
+
const requestId = readRequestId(form.id);
|
|
92
|
+
if (!sessionId || !requestId) return;
|
|
93
|
+
getOrCreatePendingRequests(sessionId).forms.set(requestId, form);
|
|
83
94
|
return;
|
|
84
95
|
}
|
|
85
96
|
if (payload.type === 'permission.replied') {
|
|
86
97
|
settlePendingRequest('permissions', readRequestId(properties.sessionID), readRequestId(properties.requestID));
|
|
87
98
|
return;
|
|
88
99
|
}
|
|
89
|
-
if (payload.type === '
|
|
90
|
-
settlePendingRequest('
|
|
100
|
+
if (payload.type === 'form.settled') {
|
|
101
|
+
settlePendingRequest('forms', readRequestId(properties.sessionID), readRequestId(properties.formID));
|
|
91
102
|
return;
|
|
92
103
|
}
|
|
93
104
|
if (payload.type === 'session.deleted') {
|
|
@@ -102,7 +113,7 @@ export const createSessionRuntime = ({ writeSseEvent, getNotificationClients, br
|
|
|
102
113
|
for (const [sessionId, entry] of pendingRequestsBySession) {
|
|
103
114
|
result[sessionId] = {
|
|
104
115
|
permissions: [...entry.permissions.values()],
|
|
105
|
-
|
|
116
|
+
forms: [...entry.forms.values()],
|
|
106
117
|
};
|
|
107
118
|
}
|
|
108
119
|
return result;
|
|
@@ -12,26 +12,26 @@ describe('session runtime', () => {
|
|
|
12
12
|
runtimes.length = 0;
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
it('keeps pending permission and
|
|
15
|
+
it('keeps pending permission requests and forms until they are answered', () => {
|
|
16
16
|
const runtime = createSessionRuntime({
|
|
17
17
|
writeSseEvent() {},
|
|
18
18
|
getNotificationClients: () => new Set(),
|
|
19
19
|
broadcastEvent: () => {},
|
|
20
20
|
});
|
|
21
21
|
runtimes.push(runtime);
|
|
22
|
-
const permission = { id: 'perm-1', sessionID: 'session-1',
|
|
23
|
-
const
|
|
22
|
+
const permission = { id: 'perm-1', sessionID: 'session-1', action: 'bash', resources: ['rm *'], metadata: {} };
|
|
23
|
+
const form = { id: 'form-1', sessionID: 'session-2', title: 'Pick one', fields: {} };
|
|
24
24
|
|
|
25
25
|
runtime.processOpenCodeSsePayload({ type: 'permission.asked', properties: permission });
|
|
26
26
|
runtime.processOpenCodeSsePayload({ type: 'permission.asked', properties: permission });
|
|
27
|
-
runtime.processOpenCodeSsePayload({ type: '
|
|
27
|
+
runtime.processOpenCodeSsePayload({ type: 'form.created', properties: { sessionID: 'session-2', form } });
|
|
28
28
|
expect(runtime.getPendingBlockingRequestsSnapshot()).toEqual({
|
|
29
|
-
'session-1': { permissions: [permission],
|
|
30
|
-
'session-2': { permissions: [],
|
|
29
|
+
'session-1': { permissions: [permission], forms: [] },
|
|
30
|
+
'session-2': { permissions: [], forms: [form] },
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
runtime.processOpenCodeSsePayload({ type: 'permission.replied', properties: { sessionID: 'session-1', requestID: 'perm-1' } });
|
|
34
|
-
runtime.processOpenCodeSsePayload({ type: '
|
|
34
|
+
runtime.processOpenCodeSsePayload({ type: 'form.settled', properties: { sessionID: 'session-2' } });
|
|
35
35
|
expect(runtime.getPendingBlockingRequestsSnapshot()).toEqual({});
|
|
36
36
|
});
|
|
37
37
|
|
|
@@ -43,12 +43,12 @@ describe('session runtime', () => {
|
|
|
43
43
|
});
|
|
44
44
|
runtimes.push(runtime);
|
|
45
45
|
const ask = (sessionID, id) => runtime.processOpenCodeSsePayload({
|
|
46
|
-
type: 'permission.asked', properties: { id, sessionID,
|
|
46
|
+
type: 'permission.asked', properties: { id, sessionID, action: 'edit', resources: [], metadata: {} },
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
ask('session-1', 'perm-1');
|
|
50
50
|
ask('session-2', 'perm-2');
|
|
51
|
-
runtime.processOpenCodeSsePayload({ type: 'session.deleted', properties: { info: { id: 'session-1' } } });
|
|
51
|
+
runtime.processOpenCodeSsePayload({ type: 'session.deleted', properties: { sessionID: 'session-1', info: { id: 'session-1' } } });
|
|
52
52
|
expect(Object.keys(runtime.getPendingBlockingRequestsSnapshot())).toEqual(['session-2']);
|
|
53
53
|
|
|
54
54
|
runtime.interruptBusySessionsAfterRestart();
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
2
|
|
|
3
3
|
import { isAgentMemoryFeatureAvailable } from '../agent-memory/feature-flag.js';
|
|
4
|
-
import { isRoutingFeatureAvailable } from '../routing/feature-flag.js';
|
|
5
4
|
|
|
6
5
|
// Generated from packages/ui/src/lib/settings/registry.ts by
|
|
7
6
|
// `bun run settings-registry:generate`; `registry.test.ts` fails when stale.
|
|
@@ -64,7 +63,7 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
64
63
|
const MOBILE_KEYBOARD_MODE_VALUES = new Set(['native', 'resize-content']);
|
|
65
64
|
const TERMINAL_SHELL_VALUES = new Set(['auto', 'bash', 'zsh', 'sh', 'fish', 'pwsh', 'powershell', 'cmd', 'dash', 'ksh', 'nu']);
|
|
66
65
|
const SIDEBAR_PROJECT_DISPLAY_MODE_VALUES = new Set(['all', 'single']);
|
|
67
|
-
const
|
|
66
|
+
const SIDEBAR_VIEW_MODE_VALUES = new Set(['projects', 'timeline']);
|
|
68
67
|
const SIDEBAR_PROJECT_SORT_ORDER_VALUES = new Set(['manual', 'a-z', 'z-a', 'date-added', 'recent']);
|
|
69
68
|
const HIDDEN_MODELS_MAX = 1024;
|
|
70
69
|
const RECENT_EFFORTS_MAX_KEYS = 128;
|
|
@@ -297,8 +296,8 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
297
296
|
if (SIDEBAR_PROJECT_DISPLAY_MODE_VALUES.has(candidate.sidebarProjectDisplayMode)) {
|
|
298
297
|
result.sidebarProjectDisplayMode = candidate.sidebarProjectDisplayMode;
|
|
299
298
|
}
|
|
300
|
-
if (
|
|
301
|
-
result.
|
|
299
|
+
if (SIDEBAR_VIEW_MODE_VALUES.has(candidate.sidebarViewMode)) {
|
|
300
|
+
result.sidebarViewMode = candidate.sidebarViewMode;
|
|
302
301
|
}
|
|
303
302
|
if (SIDEBAR_PROJECT_SORT_ORDER_VALUES.has(candidate.sidebarProjectSortOrder)) {
|
|
304
303
|
result.sidebarProjectSortOrder = candidate.sidebarProjectSortOrder;
|
|
@@ -599,15 +598,15 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
599
598
|
if (typeof candidate.agentWebToolEnabled === 'boolean') {
|
|
600
599
|
result.agentWebToolEnabled = candidate.agentWebToolEnabled;
|
|
601
600
|
}
|
|
601
|
+
if (typeof candidate.browserProvider === 'string' && candidate.browserProvider.trim()) {
|
|
602
|
+
result.browserProvider = candidate.browserProvider.trim();
|
|
603
|
+
}
|
|
602
604
|
if (typeof candidate.agentControlToolEnabled === 'boolean') {
|
|
603
605
|
result.agentControlToolEnabled = candidate.agentControlToolEnabled;
|
|
604
606
|
}
|
|
605
607
|
if (typeof candidate.agentMemoryToolEnabled === 'boolean') {
|
|
606
608
|
result.agentMemoryToolEnabled = candidate.agentMemoryToolEnabled;
|
|
607
609
|
}
|
|
608
|
-
if (typeof candidate.optimizeSystemPrompt === 'boolean') {
|
|
609
|
-
result.optimizeSystemPrompt = candidate.optimizeSystemPrompt;
|
|
610
|
-
}
|
|
611
610
|
if (typeof candidate.openCodeUpdateToastDismissedVersion === 'string') {
|
|
612
611
|
const version = candidate.openCodeUpdateToastDismissedVersion.trim();
|
|
613
612
|
result.openCodeUpdateToastDismissedVersion = version.slice(0, VERSION_STRING_MAX_LENGTH);
|
|
@@ -1014,8 +1013,9 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
1014
1013
|
// Tells the client whether agent memory exists in this build at all, so
|
|
1015
1014
|
// its settings row and panel tab can be absent rather than merely off.
|
|
1016
1015
|
agentMemoryFeatureAvailable: isAgentMemoryFeatureAvailable(),
|
|
1017
|
-
//
|
|
1018
|
-
|
|
1016
|
+
// Jev routing needs the OpenChamber server, so it is present here and
|
|
1017
|
+
// absent wherever this payload does not come from one (VS Code).
|
|
1018
|
+
routingFeatureAvailable: true,
|
|
1019
1019
|
...(pwaAppName ? { pwaAppName } : {}),
|
|
1020
1020
|
pwaOrientation,
|
|
1021
1021
|
mobileKeyboardMode,
|
|
@@ -175,18 +175,18 @@ describe('settings helpers', () => {
|
|
|
175
175
|
|
|
176
176
|
expect(helpers.sanitizeSettingsUpdate({
|
|
177
177
|
sidebarProjectDisplayMode: 'single',
|
|
178
|
-
|
|
178
|
+
sidebarViewMode: 'timeline',
|
|
179
179
|
sidebarProjectSortOrder: 'z-a',
|
|
180
180
|
sidebarShowRecentSection: false,
|
|
181
181
|
})).toEqual({
|
|
182
182
|
sidebarProjectDisplayMode: 'single',
|
|
183
|
-
|
|
183
|
+
sidebarViewMode: 'timeline',
|
|
184
184
|
sidebarProjectSortOrder: 'z-a',
|
|
185
185
|
sidebarShowRecentSection: false,
|
|
186
186
|
});
|
|
187
187
|
expect(helpers.sanitizeSettingsUpdate({
|
|
188
188
|
sidebarProjectDisplayMode: 'grid',
|
|
189
|
-
|
|
189
|
+
sidebarViewMode: 'grid',
|
|
190
190
|
sidebarProjectSortOrder: 'random',
|
|
191
191
|
sidebarShowRecentSection: 'false',
|
|
192
192
|
})).toEqual({});
|
|
@@ -667,9 +667,6 @@ describe('settings helpers', () => {
|
|
|
667
667
|
it('persists only boolean system prompt optimization values', () => {
|
|
668
668
|
const helpers = createTestHelpersWithRealSanitizers();
|
|
669
669
|
|
|
670
|
-
expect(helpers.sanitizeSettingsUpdate({ optimizeSystemPrompt: true })).toEqual({ optimizeSystemPrompt: true });
|
|
671
|
-
expect(helpers.sanitizeSettingsUpdate({ optimizeSystemPrompt: false })).toEqual({ optimizeSystemPrompt: false });
|
|
672
|
-
expect(helpers.sanitizeSettingsUpdate({ optimizeSystemPrompt: 'true' })).toEqual({});
|
|
673
670
|
});
|
|
674
671
|
|
|
675
672
|
it('survives a full settings.json payload containing all four previously-dropped fields (regression)', () => {
|
|
@@ -767,13 +764,13 @@ describe('settings registry gate', () => {
|
|
|
767
764
|
desktopLanAccessEnabled: true, desktopKeepAwakeEnabled: true, desktopMinimizeToTrayEnabled: true, desktopMacMenuBarEnabled: true,
|
|
768
765
|
desktopUiPassword: 'secret', githubClientId: 'client', githubScopes: 'repo', skillCatalogs: [{ id: 'c', label: 'C', source: 'https://x' }],
|
|
769
766
|
defaultGitIdentityId: 'global', permissionAutoAccept: { sessions: { s: true }, revision: 1 },
|
|
770
|
-
agentControlToolEnabled: true, agentWebToolEnabled: true, agentMemoryToolEnabled: true, openCodeUpdateToastDismissedVersion: '1.0.0',
|
|
767
|
+
agentControlToolEnabled: true, agentWebToolEnabled: true, browserProvider: 'builtin', agentMemoryToolEnabled: true, openCodeUpdateToastDismissedVersion: '1.0.0',
|
|
771
768
|
autoDeleteEnabled: true, autoDeleteAfterDays: 30, sessionRetentionOnlyArchived: false, sessionRetentionAction: 'archive', terminalShell: 'zsh', terminalLoginShells: ['zsh'],
|
|
772
769
|
openInAppId: 'vscode', dictationEnabled: true, sttProvider: 'local', sttServerUrl: 'http://localhost:8001/v1', sttModel: 'm', sttLocalModel: 'm', sttLanguage: 'en',
|
|
773
770
|
tunnelProvider: 'cloudflare', tunnelMode: 'quick', tunnelBootstrapTtlMs: 600000, tunnelSessionTtlMs: 86400000, managedLocalTunnelConfigPath: '/tmp/x',
|
|
774
771
|
managedRemoteTunnelHostname: 'x.example', managedRemoteTunnelToken: 'token', managedRemoteTunnelPresets: [{ id: 'a', name: 'A', hostname: 'a.example' }],
|
|
775
772
|
managedRemoteTunnelSelectedPresetId: 'a', managedRemoteTunnelPresetTokens: { a: 'token' },
|
|
776
|
-
sidebarProjectDisplayMode: 'all',
|
|
773
|
+
sidebarProjectDisplayMode: 'all', sidebarViewMode: 'timeline', sidebarProjectSortOrder: 'manual', sidebarShowRecentSection: true,
|
|
777
774
|
workStatusPanelEnabled: true, workStatusHiddenSections: ['mcp'], workStatusHiddenSectionsExplicit: true, workStatusSectionOrder: ['mcp', 'session'],
|
|
778
775
|
showReasoningTraces: true, streamingAutoFollowEnabled: true, collapsibleThinkingBlocks: true, showTextJustificationActivity: true,
|
|
779
776
|
chatRenderMode: 'live', activityRenderMode: 'summary', mermaidRenderingMode: 'svg', userMessageRenderingMode: 'markdown', collapsibleUserMessages: true,
|
|
@@ -781,7 +778,7 @@ describe('settings registry gate', () => {
|
|
|
781
778
|
codeBlockLineWrap: true, showTurnChangedFiles: true, showExpandedBashTools: true, showExpandedEditTools: true, toolJsonViewMode: 'raw',
|
|
782
779
|
timeFormatPreference: '24h', weekStartPreference: 'monday', messageStreamTransport: 'ws', diffLayoutPreference: 'inline', diffWrapLines: true,
|
|
783
780
|
gitChangesViewMode: 'tree', gitmojiEnabled: true, defaultFileViewerPreview: true, directoryShowHidden: true, filesViewShowGitignored: true,
|
|
784
|
-
fileEditorKeymap: 'vim', autoSaveEnabled: true, autoCreateWorktree: true, sessionTabsEnabled: true,
|
|
781
|
+
fileEditorKeymap: 'vim', autoSaveEnabled: true, autoCreateWorktree: true, sessionTabsEnabled: true,
|
|
785
782
|
allowPromptingSubagentSessions: true, inputSpellcheckEnabled: true, enterToSend: true, enterToSendConfigured: true, persistChatDraft: true,
|
|
786
783
|
largeTextPasteBehavior: 'attach', followUpBehavior: 'steer', queueModeEnabled: true, inputHistoryScope: 'global', inputHistoryLimit: 40,
|
|
787
784
|
draftStarters: [{ type: 'command', name: 'plan-feature' }], draftStartersVisible: true, draftStartersCraftGoalAdded: true, draftStartersScheduleTaskAdded: true,
|
|
@@ -797,7 +794,7 @@ describe('settings registry gate', () => {
|
|
|
797
794
|
notificationTemplates: { completion: { title: 't', message: 'm' } }, showOpenCodeUpdateNotifications: true, reportUsage: true,
|
|
798
795
|
usageDisplayMode: 'usage', usageDropdownProviders: ['anthropic'], usageSelectedModels: { anthropic: ['claude'] }, usageCollapsedFamilies: { anthropic: ['f'] },
|
|
799
796
|
usageExpandedFamilies: { anthropic: ['f'] }, usageModelGroups: { anthropic: { customGroups: [{ id: 'g', label: 'G', models: ['claude'], order: 0 }] } },
|
|
800
|
-
globalBehaviorPrompt: 'Be brief.', responseStyleEnabled: true, responseStylePreset: 'concise', responseStyleCustomInstructions: 'x',
|
|
797
|
+
globalBehaviorPrompt: 'Be brief.', responseStyleEnabled: true, responseStylePreset: 'concise', responseStyleCustomInstructions: 'x',
|
|
801
798
|
pwaAppName: 'OpenChamber', pwaOrientation: 'portrait', mobileKeyboardMode: 'native', desktopWindowControlsPosition: 'left', desktopWindowControlsStyle: 'classic',
|
|
802
799
|
inputBarOffset: 10,
|
|
803
800
|
};
|
|
@@ -879,7 +876,6 @@ describe('settings registry gate', () => {
|
|
|
879
876
|
largeTextPasteBehavior: 'inline',
|
|
880
877
|
fileEditorKeymap: 'vim',
|
|
881
878
|
allowPromptingSubagentSessions: true,
|
|
882
|
-
showOpenCodeRestartConfirm: false,
|
|
883
879
|
codeBlockLineWrap: true,
|
|
884
880
|
streamingAutoFollowEnabled: false,
|
|
885
881
|
autoSaveEnabled: false,
|
|
@@ -890,7 +886,6 @@ describe('settings registry gate', () => {
|
|
|
890
886
|
largeTextPasteBehavior: 'inline',
|
|
891
887
|
fileEditorKeymap: 'vim',
|
|
892
888
|
allowPromptingSubagentSessions: true,
|
|
893
|
-
showOpenCodeRestartConfirm: false,
|
|
894
889
|
codeBlockLineWrap: true,
|
|
895
890
|
streamingAutoFollowEnabled: false,
|
|
896
891
|
autoSaveEnabled: false,
|
|
@@ -120,6 +120,9 @@
|
|
|
120
120
|
"agentWebToolEnabled": {
|
|
121
121
|
"scope": "instance"
|
|
122
122
|
},
|
|
123
|
+
"browserProvider": {
|
|
124
|
+
"scope": "instance"
|
|
125
|
+
},
|
|
123
126
|
"agentMemoryToolEnabled": {
|
|
124
127
|
"scope": "instance"
|
|
125
128
|
},
|
|
@@ -212,8 +215,9 @@
|
|
|
212
215
|
"sidebarProjectDisplayMode": {
|
|
213
216
|
"scope": "profile"
|
|
214
217
|
},
|
|
215
|
-
"
|
|
216
|
-
"scope": "profile"
|
|
218
|
+
"sidebarViewMode": {
|
|
219
|
+
"scope": "profile",
|
|
220
|
+
"perSurface": true
|
|
217
221
|
},
|
|
218
222
|
"sidebarProjectSortOrder": {
|
|
219
223
|
"scope": "profile"
|
|
@@ -341,9 +345,6 @@
|
|
|
341
345
|
"vscode"
|
|
342
346
|
]
|
|
343
347
|
},
|
|
344
|
-
"showOpenCodeRestartConfirm": {
|
|
345
|
-
"scope": "profile"
|
|
346
|
-
},
|
|
347
348
|
"allowPromptingSubagentSessions": {
|
|
348
349
|
"scope": "profile"
|
|
349
350
|
},
|
|
@@ -544,9 +545,6 @@
|
|
|
544
545
|
"responseStyleCustomInstructions": {
|
|
545
546
|
"scope": "profile"
|
|
546
547
|
},
|
|
547
|
-
"optimizeSystemPrompt": {
|
|
548
|
-
"scope": "profile"
|
|
549
|
-
},
|
|
550
548
|
"pwaAppName": {
|
|
551
549
|
"scope": "instance",
|
|
552
550
|
"surfaces": [
|
|
@@ -40,6 +40,13 @@ const ensureNotificationTemplateShape = (templates) => {
|
|
|
40
40
|
return { templates: next, changed };
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
+
/** Settings that decide which OpenChamber plugins the managed OpenCode loads. */
|
|
44
|
+
const MANAGED_PLUGIN_SETTINGS_KEYS = new Set([
|
|
45
|
+
'agentControlToolEnabled',
|
|
46
|
+
'agentWebToolEnabled',
|
|
47
|
+
'agentMemoryToolEnabled',
|
|
48
|
+
]);
|
|
49
|
+
|
|
43
50
|
export const createSettingsRuntime = (deps) => {
|
|
44
51
|
const {
|
|
45
52
|
fsPromises,
|
|
@@ -58,6 +65,7 @@ export const createSettingsRuntime = (deps) => {
|
|
|
58
65
|
normalizeManagedRemoteTunnelPresetTokens,
|
|
59
66
|
syncManagedRemoteTunnelConfigWithPresets,
|
|
60
67
|
upsertManagedRemoteTunnelToken,
|
|
68
|
+
onManagedPluginSettingsChanged = async () => {},
|
|
61
69
|
} = deps;
|
|
62
70
|
|
|
63
71
|
let persistSettingsLock = Promise.resolve();
|
|
@@ -1110,7 +1118,16 @@ export const createSettingsRuntime = (deps) => {
|
|
|
1110
1118
|
}
|
|
1111
1119
|
}
|
|
1112
1120
|
|
|
1113
|
-
|
|
1121
|
+
const changedKeys = Object.keys(sanitized);
|
|
1122
|
+
await writeSettingsToDisk(next, { surface, changedKeys });
|
|
1123
|
+
// OpenChamber's own OpenCode plugins live in a config file OpenCode
|
|
1124
|
+
// watches, so flipping one of these switches takes effect in the running
|
|
1125
|
+
// process instead of waiting for a restart.
|
|
1126
|
+
if (changedKeys.some((key) => MANAGED_PLUGIN_SETTINGS_KEYS.has(key))) {
|
|
1127
|
+
await Promise.resolve(onManagedPluginSettingsChanged(next)).catch((error) => {
|
|
1128
|
+
console.warn('Failed to refresh the managed OpenCode config:', error?.message ?? error);
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1114
1131
|
return formatSettingsResponse(next);
|
|
1115
1132
|
});
|
|
1116
1133
|
|
|
@@ -6,7 +6,10 @@ import path from 'path';
|
|
|
6
6
|
import { createProjectIdFromPath, projectConfigFileStemOf } from '../projects/project-id.js';
|
|
7
7
|
import { createSettingsRuntime } from './settings-runtime.js';
|
|
8
8
|
|
|
9
|
-
const createRuntime = async ({
|
|
9
|
+
const createRuntime = async ({
|
|
10
|
+
mergePersistedSettings = (_current, changes) => changes,
|
|
11
|
+
onManagedPluginSettingsChanged = undefined,
|
|
12
|
+
} = {}) => {
|
|
10
13
|
const tempRoot = await fsPromises.mkdtemp(path.join(os.tmpdir(), 'oc-settings-runtime-'));
|
|
11
14
|
const settingsFilePath = path.join(tempRoot, 'settings.json');
|
|
12
15
|
const runtime = createSettingsRuntime({
|
|
@@ -26,6 +29,7 @@ const createRuntime = async ({ mergePersistedSettings = (_current, changes) => c
|
|
|
26
29
|
normalizeManagedRemoteTunnelPresetTokens: (value) => value,
|
|
27
30
|
syncManagedRemoteTunnelConfigWithPresets: async () => {},
|
|
28
31
|
upsertManagedRemoteTunnelToken: async () => {},
|
|
32
|
+
onManagedPluginSettingsChanged,
|
|
29
33
|
});
|
|
30
34
|
|
|
31
35
|
return {
|
|
@@ -39,6 +43,31 @@ const createRuntime = async ({ mergePersistedSettings = (_current, changes) => c
|
|
|
39
43
|
};
|
|
40
44
|
|
|
41
45
|
describe('settings runtime', () => {
|
|
46
|
+
it('refreshes the managed OpenCode config only when a managed plugin setting changed', async () => {
|
|
47
|
+
const onManagedPluginSettingsChanged = vi.fn(async () => {});
|
|
48
|
+
const { runtime, cleanup } = await createRuntime({ onManagedPluginSettingsChanged });
|
|
49
|
+
try {
|
|
50
|
+
await runtime.persistSettings({ lightThemeId: 'flexoki-light' });
|
|
51
|
+
expect(onManagedPluginSettingsChanged).not.toHaveBeenCalled();
|
|
52
|
+
|
|
53
|
+
await runtime.persistSettings({ agentWebToolEnabled: false });
|
|
54
|
+
expect(onManagedPluginSettingsChanged).toHaveBeenCalledTimes(1);
|
|
55
|
+
} finally {
|
|
56
|
+
await cleanup();
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('still answers the settings write when the managed config refresh fails', async () => {
|
|
61
|
+
const onManagedPluginSettingsChanged = vi.fn(async () => { throw new Error('disk full'); });
|
|
62
|
+
const { runtime, cleanup } = await createRuntime({ onManagedPluginSettingsChanged });
|
|
63
|
+
try {
|
|
64
|
+
await expect(runtime.persistSettings({ agentMemoryToolEnabled: true }))
|
|
65
|
+
.resolves.toMatchObject({ agentMemoryToolEnabled: true });
|
|
66
|
+
} finally {
|
|
67
|
+
await cleanup();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
42
71
|
it('round-trips both archived-only retention states through instance settings', async () => {
|
|
43
72
|
const { runtime, settingsFilePath, cleanup } = await createRuntime();
|
|
44
73
|
try {
|
|
@@ -86,7 +115,7 @@ describe('settings runtime', () => {
|
|
|
86
115
|
const { runtime, settingsFilePath, tempRoot, cleanup } = await createRuntime();
|
|
87
116
|
const preferences = {
|
|
88
117
|
sidebarProjectDisplayMode: 'single',
|
|
89
|
-
|
|
118
|
+
sidebarViewMode: 'timeline',
|
|
90
119
|
sidebarProjectSortOrder: 'date-added',
|
|
91
120
|
sidebarShowRecentSection: false,
|
|
92
121
|
};
|