@vantran-se/openchamber-web 1.24.4 → 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-B4a0JkUz.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-Byu2DY7s.js → GitView-BWa7e5vw.js} +4 -4
- package/dist/assets/{GuestAttachDialog-B808E0-d.js → GuestAttachDialog-DdOuyZzp.js} +1 -1
- package/dist/assets/GuestSurfacePane-DDfzid3U.js +1 -0
- package/dist/assets/{JsonTreeView-VW_7czo3.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-DCjGhlYV.js → PatchDiff-DS-IMU1j.js} +1 -1
- package/dist/assets/{PierreDiffViewer-CEDZNkU2.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-NU0FHFhT.js → VirtualizedFileDiff-C763hNCR.js} +4 -4
- package/dist/assets/{WalkthroughView-BZyjhqHv.js → WalkthroughView-lap5btCF.js} +2 -2
- package/dist/assets/appThemeRegistry-u4zw1l0B.js +1 -0
- package/dist/assets/{commitAndPush-BDftrjr6.js → commitAndPush-CwGJfJG-.js} +1 -1
- package/dist/assets/{computeVirtualFileMetrics-DlWlEM3x.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-CO4e5J_S.js → isDiffPlainText-D47a6hMP.js} +1 -1
- package/dist/assets/{isFilePlainText-ue6kCou7.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-CK48LG0z.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-D7QVlovD.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-BPu3JiQs.js → shikiHighlight-DNm2Z_Jc.js} +1 -1
- package/dist/assets/{textMateThemeFromAppTheme-DWqRPo9A.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-CgS0fnw_.js → useInlineCommentController-CuUuakrt.js} +2 -2
- package/dist/assets/useRootScrollLock-CQIsyERq.js +2 -0
- package/dist/assets/{vendor-codemirror-language-data-Bx2EHc1O.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-DxX8bZ1o.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-B2CD9wC8.js +0 -4
- package/dist/assets/FilesView-C4vMFclc.js +0 -13
- package/dist/assets/LinearIssuesView-EzGNCGrd.js +0 -1
- package/dist/assets/MarkdownImageGallery-B2YUDFaB.js +0 -1
- package/dist/assets/MarkdownRendererImpl-B4ikIzR3.js +0 -12
- package/dist/assets/OnboardingScreen-CQHBSTEi.js +0 -1
- package/dist/assets/PlanView-D3x-pTkZ.js +0 -5
- package/dist/assets/PluginPane-DEcgDQ9h.js +0 -3
- package/dist/assets/SettingsView-CSinuH-1.js +0 -29
- package/dist/assets/SettingsWindow-B5CHoJFZ.js +0 -1
- package/dist/assets/SubmoduleDiffSummary-oxeACCWs.js +0 -1
- package/dist/assets/ToolOutputDialog-tLNWmfcW.js +0 -15
- package/dist/assets/ToolPartDiffPreview-CflzmK-x.js +0 -8
- package/dist/assets/appThemeRegistry-DLicw4dH.js +0 -1
- package/dist/assets/de-Bro6_zyl.js +0 -10
- package/dist/assets/es-Bb9XQZvd.js +0 -16
- package/dist/assets/fr-Dgfzn-IL.js +0 -14
- package/dist/assets/index-CtQNmqUL.js +0 -1
- package/dist/assets/index-DqaMWNrC.css +0 -1
- package/dist/assets/index-Dqc6USl3.js +0 -40
- package/dist/assets/ja-BYsakGFh.js +0 -16
- package/dist/assets/ko-BSaQz9aN.js +0 -16
- package/dist/assets/main-B62_pjL5.js +0 -2
- package/dist/assets/main-BEdcOI2P.js +0 -896
- package/dist/assets/miniChat-LT8Rqofr.js +0 -2
- package/dist/assets/mobile-CqarEynh.js +0 -2
- package/dist/assets/pl-OIviPdoj.js +0 -16
- package/dist/assets/pt-BR-Cltg-E6s.js +0 -16
- package/dist/assets/renderElectronMiniChatApp-COyLTtZx.js +0 -2
- package/dist/assets/renderMobileApp-BC1MHg6g.js +0 -25
- package/dist/assets/runtimeEndpointReset-DdrazOVH.js +0 -25
- package/dist/assets/scheduledTasksApi-B2SWMGEU.js +0 -1
- package/dist/assets/tr-CQI-KPre.js +0 -7
- package/dist/assets/uk-CqW7R4DA.js +0 -16
- package/dist/assets/useAppFontEffects-ne84JBVL.js +0 -7333
- package/dist/assets/useRootScrollLock-Cpf1qoGp.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-CVZG_o_J.js +0 -16
- package/dist/assets/zh-TW-D5ZxzCZp.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
|
@@ -6,13 +6,18 @@ This module exposes OpenChamber to agents as typed OpenCode custom tools. There
|
|
|
6
6
|
are two, because controlling sessions and driving a page are separate intents
|
|
7
7
|
the user can want independently:
|
|
8
8
|
|
|
9
|
-
- `openchamber` — projects, sessions, worktrees,
|
|
10
|
-
|
|
9
|
+
- `openchamber` — projects, sessions, worktrees, scheduled tasks, and showing
|
|
10
|
+
a file to the user (`file.open`). Enabled while the persisted
|
|
11
|
+
`agentControlToolEnabled` setting is not `false`.
|
|
11
12
|
- `openchamber_web` — looking at and interacting with the page in OpenChamber's
|
|
12
13
|
browser panel. Enabled while `agentWebToolEnabled` is not `false`.
|
|
13
14
|
|
|
14
|
-
Both default to on, are toggled in Settings → General → OpenCode CLI, and
|
|
15
|
-
|
|
15
|
+
Both default to on, are toggled in Settings → General → OpenCode CLI, and take
|
|
16
|
+
effect in the running OpenCode within a couple of seconds — OpenChamber rewrites
|
|
17
|
+
the managed config file OpenCode watches (see
|
|
18
|
+
`lib/opencode/managed-config-file.js`). Installs where the user's own
|
|
19
|
+
environment sets `OPENCODE_CONFIG` fall back to `OPENCODE_CONFIG_CONTENT` and
|
|
20
|
+
still need a restart for a toggle. Each tool carries only its own actions and
|
|
16
21
|
only the parameters those actions use, so turning one off removes its inputs
|
|
17
22
|
from the schema rather than leaving them visible. The plugin is injected only
|
|
18
23
|
when OpenChamber launches and owns the OpenCode process, and not at all when
|
|
@@ -27,15 +32,19 @@ both settings are `false`.
|
|
|
27
32
|
## Runtime flow
|
|
28
33
|
|
|
29
34
|
1. The OpenChamber HTTP listener binds and publishes its authoritative port.
|
|
30
|
-
2. `
|
|
31
|
-
`<openchamber-data-dir>/agent-tool/` and
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
2. `materializePlugin()` writes the plugin under
|
|
36
|
+
`<openchamber-data-dir>/agent-tool/` and returns its directory; the managed
|
|
37
|
+
config layer lists that directory in `<data-dir>/opencode.managed.json` and
|
|
38
|
+
rewrites the file whenever a tool setting changes.
|
|
39
|
+
3. `createChildEnv()` adds a random per-child token and the callback URL to the
|
|
40
|
+
managed OpenCode child environment. They are present even while every tool
|
|
41
|
+
is off, so a tool switched on later can call back without a restart. The URL
|
|
42
|
+
points at loopback, except when the listener is bound to one concrete
|
|
43
|
+
address (`--host <ip>`): that socket does not answer on loopback, so the URL
|
|
44
|
+
uses the bound address instead.
|
|
37
45
|
4. The plugin calls `POST /api/openchamber/agent-tool` with its typed input and
|
|
38
|
-
OpenCode
|
|
46
|
+
the session id OpenCode gives the tool; OpenChamber resolves the session's
|
|
47
|
+
directory on its own side.
|
|
39
48
|
5. The route delegates the fixed action allowlist directly to the shared
|
|
40
49
|
OpenChamber control service. The CLI uses the same service through its
|
|
41
50
|
authenticated HTTP adapter, so Goal Mode ordering, wait behavior,
|
|
@@ -63,8 +72,11 @@ both settings are `false`.
|
|
|
63
72
|
`schedule.list` already returns scheduler status, and enable/disable are one
|
|
64
73
|
`schedule.toggle` action driven by the `disabled` boolean.
|
|
65
74
|
- The tool description frames intent: created sessions and scheduled tasks are
|
|
66
|
-
user-facing work the user follows up with
|
|
67
|
-
delegate parts of its
|
|
75
|
+
user-facing work the user follows up with. The agent must not decide on its
|
|
76
|
+
own to delegate parts of its current task, but an explicit user request to
|
|
77
|
+
create, send, or schedule always wins, even when it relates to the current
|
|
78
|
+
task (strict models otherwise read the old unconditional "never delegate" as
|
|
79
|
+
a hard ban and refused user-requested sends).
|
|
68
80
|
- Optional behavior switches (`worktree`, `goal`, `agent`, `variant`, `wait`)
|
|
69
81
|
state their default and an explicit "only when the user asks" rule so agents
|
|
70
82
|
do not invent worktrees, goal mode, or waits the user never requested.
|
|
@@ -89,7 +101,12 @@ both settings are `false`.
|
|
|
89
101
|
- Inputs map to a fixed action and parameter allowlist. There is no arbitrary
|
|
90
102
|
CLI, shell, route, or URL forwarding.
|
|
91
103
|
- Session/worktree deletion and project-path registration are not exposed.
|
|
92
|
-
-
|
|
104
|
+
- A cancelled turn aborts the session's in-flight actions. OpenCode 2 gives a
|
|
105
|
+
plugin tool no abort signal and the plugin's request stays open, so the
|
|
106
|
+
server tracks in-flight actions per session and `abortSession(sessionID)` is
|
|
107
|
+
called from the event dispatch in `server/index.js` when the stream reports
|
|
108
|
+
`session.idle` with `aborted: true`; the abort signal then reaches the
|
|
109
|
+
shared service as before. A dropped HTTP request still aborts as well.
|
|
93
110
|
|
|
94
111
|
## Result contract
|
|
95
112
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { pathToFileURL } from 'node:url';
|
|
2
|
-
import { appendManagedPlugin } from '../opencode/managed-plugin-config.js';
|
|
3
1
|
import {
|
|
4
2
|
OPENCHAMBER_AGENT_TOOL_ACTION_DEFINITIONS,
|
|
5
3
|
OPENCHAMBER_AGENT_TOOL_ACTIONS,
|
|
@@ -11,6 +9,7 @@ import {
|
|
|
11
9
|
} from '../openchamber-control/actions.js';
|
|
12
10
|
|
|
13
11
|
const TOOL_SCHEMA_VERSION = 1;
|
|
12
|
+
const PLUGIN_ID = 'openchamber-agent-tool';
|
|
14
13
|
// Everything either managed tool may ask for; the agent allowlist stays
|
|
15
14
|
// narrower than the full control surface.
|
|
16
15
|
const ACTIONS = new Set([...OPENCHAMBER_AGENT_TOOL_ACTIONS, ...OPENCHAMBER_WEB_ACTIONS, ...OPENCHAMBER_MEMORY_ACTIONS]);
|
|
@@ -79,6 +78,7 @@ const ALL_PARAMETER_PROPERTIES = {
|
|
|
79
78
|
cron: { type: 'string', description: 'Cron expression' },
|
|
80
79
|
timezone: { type: 'string', description: 'IANA timezone' },
|
|
81
80
|
disabled: { type: 'boolean', description: 'true disables and false enables; required for schedule.toggle' },
|
|
81
|
+
path: { type: 'string', description: 'File to show for file.open; absolute, or relative to the session directory' },
|
|
82
82
|
url: { type: 'string', description: 'http(s) URL for browser.open' },
|
|
83
83
|
selector: { type: 'string', description: 'CSS selector from a browser.snapshot result' },
|
|
84
84
|
text: { type: 'string', description: 'Visible label to match when no selector is given' },
|
|
@@ -108,11 +108,11 @@ const MEMORY_PARAMETER_PROPERTIES = {
|
|
|
108
108
|
...MEMORY_PARAMETER_OVERRIDES,
|
|
109
109
|
};
|
|
110
110
|
|
|
111
|
-
const CONTROL_TOOL_DESCRIPTION = "Control OpenChamber projects, sessions, and scheduled tasks on the user's behalf. Sessions and scheduled tasks you create are for the user to follow and interact with
|
|
111
|
+
const CONTROL_TOOL_DESCRIPTION = "Control OpenChamber projects, sessions, and scheduled tasks on the user's behalf. Sessions and scheduled tasks you create are for the user to follow and interact with. Do not decide on your own to hand parts of your current task to another session; when the user asks you to create a session, send a prompt to one, or schedule a task, do it, including when the work relates to your current task. Use one action per call. Scope with projectId or directory; omit both to use the current session directory. Session dispatches return immediately by default and you receive no notification when a dispatched session finishes, so never promise to report back on it; the user follows it in OpenChamber; a dispatched session needs no follow-up from you. If the user later asks how it went, use session.messages (add wait to block until it is idle, lastAssistant for just the final answer) — session.send always sends a NEW prompt and never just waits. Set wait only when the user asks or the next step requires the completed result. Session and worktree deletion are unavailable.";
|
|
112
112
|
|
|
113
113
|
const WEB_TOOL_DESCRIPTION = "Look at and interact with a web page in OpenChamber's browser panel, so you can check your own work rather than describing what you expect. Use one action per call. Open a page, snapshot it to read its text and its interactive elements, then click, type or scroll using the selectors the snapshot returned; snapshots also report any errors the page logged. Pass a selector to browser.snapshot to read one part of a long page. browser.inspect returns computed styles when the question is how something renders. Set viewport to check a layout at mobile, tablet or desktop size. The page runs with the user's real logins, so treat what you see as their live session.";
|
|
114
114
|
|
|
115
|
-
const MEMORY_TOOL_DESCRIPTION = "Keep what you learn across sessions, so the user does not have to explain the same thing twice. Use one action per call. The session already lists the titles of what is stored. A title is an abbreviation, not the memory: read the entry with memory.read before acting on it, because titles leave out the conditions and exceptions that decide how the memory applies, and the ones that look self-explanatory hide them most often. Save something only when it will still be true in a later session — a stable preference, a project convention, a decision and its reason, or a hard-won pointer. Do not save one-off task state, anything you can read from the code, secrets or credentials, or anything the user asked you not to keep. Choose the scope deliberately: global is about the user and reaches every project, so put a project's conventions in project scope.
|
|
115
|
+
const MEMORY_TOOL_DESCRIPTION = "Keep what you learn across sessions, so the user does not have to explain the same thing twice. Use one action per call. The session already lists the titles of what is stored. A title is an abbreviation, not the memory: read the entry with memory.read once before acting on it (it then stays in your context; do not re-read it on later turns), because titles leave out the conditions and exceptions that decide how the memory applies, and the ones that look self-explanatory hide them most often. Save something only when it will still be true in a later session — a stable preference, a project convention, a decision and its reason, or a hard-won pointer. Do not save one-off task state, anything you can read from the code, secrets or credentials, or anything the user asked you not to keep; when the user explicitly asks you to remember something, save it, unless it is a secret or credential. Choose the scope deliberately: global is about the user and reaches every project, so put a project's conventions in project scope. Save in the moment, without asking first, when the user corrects how you work or states a preference, confirms that a non-obvious approach worked, or when you learn a project fact that took real effort to find. One fact per entry. The user can review and remove what you save, so save when it fits and mention it briefly.";
|
|
116
116
|
|
|
117
117
|
const asNonEmptyString = (value) => {
|
|
118
118
|
if (typeof value !== 'string') return null;
|
|
@@ -157,16 +157,29 @@ const resolveConcreteBoundAddress = (value) => {
|
|
|
157
157
|
* keeps the transport, metadata and failure handling identical, which is what
|
|
158
158
|
* the caller depends on.
|
|
159
159
|
*
|
|
160
|
+
* OpenCode 2 takes a tool's `input` as plain JSON Schema, so the generated file
|
|
161
|
+
* needs no imports at all — which it must not have, because OpenCode loads the
|
|
162
|
+
* entrypoint with a bare dynamic import and nothing resolves from the generated
|
|
163
|
+
* directory.
|
|
164
|
+
*
|
|
160
165
|
* The action schema carries `oneOf` only. A node combining `enum` and `oneOf`
|
|
161
166
|
* is valid JSON Schema, but some OpenAI-compatible gateways reject it and
|
|
162
167
|
* answer with an empty completion instead of an error, and the `oneOf` branches
|
|
163
168
|
* are what carry the per-action descriptions the model reads.
|
|
164
169
|
*/
|
|
165
|
-
const createToolEntry = ({ name, description, definitions, parameters }) => String.raw`
|
|
170
|
+
const createToolEntry = ({ name, description, definitions, parameters }) => String.raw` tools.add({
|
|
171
|
+
name: ${JSON.stringify(name)},
|
|
166
172
|
description: ${JSON.stringify(description)},
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
173
|
+
input: {
|
|
174
|
+
type: "object",
|
|
175
|
+
properties: {
|
|
176
|
+
action: { type: "string", oneOf: ${JSON.stringify(definitions.map((entry) => ({ const: entry.action, description: entry.description })))}, description: "OpenChamber action to perform" },
|
|
177
|
+
parameters: { type: "object", properties: ${JSON.stringify(parameters)}, additionalProperties: false, description: "Inputs for the action; use an empty object when none are needed" },
|
|
178
|
+
},
|
|
179
|
+
required: ["action"],
|
|
180
|
+
// Models routinely put the inputs next to the action; the schema has to
|
|
181
|
+
// let that reach execute() instead of rejecting the call.
|
|
182
|
+
additionalProperties: true,
|
|
170
183
|
},
|
|
171
184
|
async execute(input, context) {
|
|
172
185
|
// Models routinely put the inputs next to the action instead of inside
|
|
@@ -177,21 +190,22 @@ const createToolEntry = ({ name, description, definitions, parameters }) => Stri
|
|
|
177
190
|
const args = { ...flattened, ...(parameters ?? {}), action: requestedAction }
|
|
178
191
|
const actionTitles = ${JSON.stringify(AGENT_TOOL_ACTION_TITLES)}
|
|
179
192
|
const title = Object.hasOwn(actionTitles, args.action) ? actionTitles[args.action] : args.action
|
|
180
|
-
context.
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
description: title,
|
|
187
|
-
},
|
|
193
|
+
const progress = (extra) => context.progress({
|
|
194
|
+
${name}: {
|
|
195
|
+
schemaVersion: ${TOOL_SCHEMA_VERSION},
|
|
196
|
+
action: args.action,
|
|
197
|
+
description: title,
|
|
198
|
+
...extra,
|
|
188
199
|
},
|
|
189
200
|
})
|
|
201
|
+
await progress()
|
|
190
202
|
const endpoint = process.env.OPENCHAMBER_AGENT_TOOL_URL
|
|
191
203
|
const token = process.env.OPENCHAMBER_AGENT_TOOL_TOKEN
|
|
204
|
+
// No output schema is declared, so a result must never carry an output
|
|
205
|
+
// field: OpenCode rejects that with "Tool result declared output
|
|
206
|
+
// without an output schema". The envelope travels as text content.
|
|
192
207
|
const failure = (payload) => ({
|
|
193
|
-
|
|
194
|
-
output: JSON.stringify(payload),
|
|
208
|
+
content: JSON.stringify(payload),
|
|
195
209
|
metadata: { openchamber: { schemaVersion: ${TOOL_SCHEMA_VERSION}, action: args.action, description: title, ok: false } },
|
|
196
210
|
})
|
|
197
211
|
if (!endpoint || !token) {
|
|
@@ -205,32 +219,25 @@ const createToolEntry = ({ name, description, definitions, parameters }) => Stri
|
|
|
205
219
|
authorization: "Bearer " + token,
|
|
206
220
|
"content-type": "application/json",
|
|
207
221
|
},
|
|
208
|
-
|
|
209
|
-
|
|
222
|
+
// OpenCode 2 no longer hands a tool its session directory, so the
|
|
223
|
+
// session id goes over instead and OpenChamber resolves the
|
|
224
|
+
// directory on its own side. The signal fires when the session is
|
|
225
|
+
// aborted, so the OpenChamber side stops the action too.
|
|
226
|
+
body: JSON.stringify({ input: args, sessionID: context.sessionID, tool: ${JSON.stringify(name)} }),
|
|
227
|
+
signal: context.signal,
|
|
210
228
|
})
|
|
211
|
-
const
|
|
229
|
+
const content = await response.text()
|
|
212
230
|
let result = null
|
|
213
|
-
try { result = JSON.parse(
|
|
231
|
+
try { result = JSON.parse(content) } catch {}
|
|
214
232
|
const valid = result?.schemaVersion === ${TOOL_SCHEMA_VERSION} && typeof result?.ok === "boolean" && typeof result?.action === "string"
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
metadata: {
|
|
218
|
-
${name}: {
|
|
219
|
-
schemaVersion: ${TOOL_SCHEMA_VERSION},
|
|
220
|
-
action: args.action,
|
|
221
|
-
description: title,
|
|
222
|
-
ok: valid && result.ok === true,
|
|
223
|
-
},
|
|
224
|
-
},
|
|
225
|
-
})
|
|
226
|
-
if (valid) return { title, output, metadata: { openchamber: { schemaVersion: ${TOOL_SCHEMA_VERSION}, action: args.action, description: title, ok: result.ok === true } } }
|
|
233
|
+
await progress({ ok: valid && result.ok === true })
|
|
234
|
+
if (valid) return { content, metadata: { openchamber: { schemaVersion: ${TOOL_SCHEMA_VERSION}, action: args.action, description: title, ok: result.ok === true } } }
|
|
227
235
|
return failure({ schemaVersion: ${TOOL_SCHEMA_VERSION}, ok: false, action: args.action, error: { message: "OpenChamber returned an invalid response", kind: "runtime", status: response.status } })
|
|
228
236
|
} catch (error) {
|
|
229
|
-
if (context.abort.aborted) throw error
|
|
230
237
|
return failure({ schemaVersion: ${TOOL_SCHEMA_VERSION}, ok: false, action: args.action, error: { message: error instanceof Error ? error.message : String(error), kind: "runtime" } })
|
|
231
238
|
}
|
|
232
239
|
},
|
|
233
|
-
}
|
|
240
|
+
})
|
|
234
241
|
`;
|
|
235
242
|
|
|
236
243
|
const createPluginSource = ({ includeControl, includeWeb, includeMemory }) => {
|
|
@@ -275,16 +282,27 @@ const createPluginSource = ({ includeControl, includeWeb, includeMemory }) => {
|
|
|
275
282
|
}
|
|
276
283
|
}
|
|
277
284
|
|
|
278
|
-
export
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
285
|
+
export default {
|
|
286
|
+
id: ${JSON.stringify(PLUGIN_ID)},
|
|
287
|
+
setup: async (ctx) => {
|
|
288
|
+
exemptCallbackFromProxy()
|
|
289
|
+
await ctx.tool.transform((tools) => {
|
|
290
|
+
${entries.join('')} })
|
|
291
|
+
},
|
|
284
292
|
}
|
|
285
293
|
`;
|
|
286
294
|
};
|
|
287
295
|
|
|
296
|
+
// A configured plugin has to be a directory carrying a package.json that
|
|
297
|
+
// resolves an entrypoint; OpenCode skips a plain .js path.
|
|
298
|
+
const PLUGIN_PACKAGE_JSON = `${JSON.stringify({
|
|
299
|
+
name: 'openchamber-agent-tool',
|
|
300
|
+
version: '0.0.0',
|
|
301
|
+
private: true,
|
|
302
|
+
type: 'module',
|
|
303
|
+
exports: { '.': './index.js' },
|
|
304
|
+
}, null, 2)}\n`;
|
|
305
|
+
|
|
288
306
|
export const createAgentToolRuntime = (dependencies) => {
|
|
289
307
|
const {
|
|
290
308
|
crypto,
|
|
@@ -294,30 +312,51 @@ export const createAgentToolRuntime = (dependencies) => {
|
|
|
294
312
|
getActivePort,
|
|
295
313
|
getActiveHost = () => null,
|
|
296
314
|
executeAction,
|
|
297
|
-
|
|
315
|
+
resolveSessionDirectory,
|
|
298
316
|
} = dependencies;
|
|
299
|
-
const
|
|
300
|
-
const
|
|
317
|
+
const pluginRoot = path.join(dataDir, 'agent-tool');
|
|
318
|
+
const pluginDirectory = path.join(pluginRoot, PLUGIN_ID);
|
|
319
|
+
const pluginPath = path.join(pluginDirectory, 'index.js');
|
|
320
|
+
const pluginManifestPath = path.join(pluginDirectory, 'package.json');
|
|
301
321
|
let activeToken = null;
|
|
302
322
|
|
|
303
323
|
const getConcreteBoundAddress = () => resolveConcreteBoundAddress(getActiveHost());
|
|
304
324
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
325
|
+
/**
|
|
326
|
+
* Write the plugin for the requested tool set and return its directory.
|
|
327
|
+
*
|
|
328
|
+
* Called both before a managed child starts and whenever the tool settings
|
|
329
|
+
* change while it runs, so the source on disk always matches the settings —
|
|
330
|
+
* the running OpenCode reloads the directory it already has configured.
|
|
331
|
+
*/
|
|
332
|
+
const materializePlugin = async ({ includeControl = true, includeWeb = true, includeMemory = true } = {}) => {
|
|
310
333
|
if (!includeControl && !includeWeb && !includeMemory) {
|
|
311
334
|
throw new Error('At least one OpenChamber managed tool must be enabled to inject the plugin');
|
|
312
335
|
}
|
|
313
336
|
await fsPromises.mkdir(pluginDirectory, { recursive: true });
|
|
337
|
+
await fsPromises.writeFile(pluginManifestPath, PLUGIN_PACKAGE_JSON, { mode: 0o600 });
|
|
314
338
|
await fsPromises.writeFile(pluginPath, createPluginSource({ includeControl, includeWeb, includeMemory }), { mode: 0o600 });
|
|
339
|
+
return pluginDirectory;
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Callback URL and a fresh per-child token for a managed OpenCode process.
|
|
344
|
+
*
|
|
345
|
+
* These are always part of the child environment, including when every tool
|
|
346
|
+
* is currently off: a tool switched on later reaches a process that already
|
|
347
|
+
* knows where and how to call back, so the toggle needs no restart.
|
|
348
|
+
*/
|
|
349
|
+
const createChildEnv = () => {
|
|
350
|
+
const port = getActivePort();
|
|
351
|
+
if (!Number.isInteger(port) || port <= 0) {
|
|
352
|
+
throw new Error('OpenChamber listener port is unavailable for managed tool injection');
|
|
353
|
+
}
|
|
315
354
|
activeToken = crypto.randomBytes(32).toString('base64url');
|
|
316
|
-
|
|
355
|
+
// A listener bound to one concrete address does not answer on loopback,
|
|
356
|
+
// so the callback has to point at the bound address instead.
|
|
317
357
|
const callbackAddress = getConcreteBoundAddress() || '127.0.0.1';
|
|
318
358
|
const callbackHost = callbackAddress.includes(':') ? `[${callbackAddress}]` : callbackAddress;
|
|
319
359
|
return {
|
|
320
|
-
OPENCODE_CONFIG_CONTENT: appendManagedPlugin(env.OPENCODE_CONFIG_CONTENT, pluginUrl, 'managed tool'),
|
|
321
360
|
OPENCHAMBER_AGENT_TOOL_URL: `http://${callbackHost}:${port}/api/openchamber/agent-tool`,
|
|
322
361
|
OPENCHAMBER_AGENT_TOOL_TOKEN: activeToken,
|
|
323
362
|
};
|
|
@@ -357,8 +396,22 @@ export const createAgentToolRuntime = (dependencies) => {
|
|
|
357
396
|
if (typeof executeAction !== 'function') {
|
|
358
397
|
return createResult({ ok: false, action, error: { message: 'OpenChamber control service is unavailable', kind: 'runtime' } });
|
|
359
398
|
}
|
|
399
|
+
// OpenCode 2 tools no longer receive a directory, so the plugin sends the
|
|
400
|
+
// session id and the directory is resolved here. An unresolvable session
|
|
401
|
+
// falls through with no directory, exactly like the old "no directory" path.
|
|
402
|
+
let contextDirectory = asNonEmptyString(payload.contextDirectory) ?? undefined;
|
|
403
|
+
const sessionID = asNonEmptyString(payload.sessionID);
|
|
404
|
+
if (!contextDirectory && sessionID && typeof resolveSessionDirectory === 'function') {
|
|
405
|
+
contextDirectory = await Promise.resolve(resolveSessionDirectory(sessionID))
|
|
406
|
+
.then((value) => asNonEmptyString(value) ?? undefined)
|
|
407
|
+
.catch(() => undefined);
|
|
408
|
+
}
|
|
360
409
|
try {
|
|
361
|
-
|
|
410
|
+
// The calling session scopes browser actions to that session's page.
|
|
411
|
+
const contextSessionId = asNonEmptyString(payload.contextSessionId) ?? sessionID;
|
|
412
|
+
const data = await executeAction(action, { ...payload.input, action }, contextDirectory, contextSessionId
|
|
413
|
+
? { ...options, contextSessionId }
|
|
414
|
+
: options);
|
|
362
415
|
return createResult({ ok: true, action, data });
|
|
363
416
|
} catch (error) {
|
|
364
417
|
return createResult({
|
|
@@ -378,6 +431,29 @@ export const createAgentToolRuntime = (dependencies) => {
|
|
|
378
431
|
}
|
|
379
432
|
};
|
|
380
433
|
|
|
434
|
+
// In-flight actions per session. The plugin forwards OpenCode's abort
|
|
435
|
+
// signal (2.0.12+), which closes its request and aborts the action here.
|
|
436
|
+
// Before that release the request stayed open after the user cancelled the
|
|
437
|
+
// turn, so the server also listens for the cancel on the event stream
|
|
438
|
+
// (`session.idle` with `aborted: true`) and aborts the actions itself.
|
|
439
|
+
const inflightBySession = new Map();
|
|
440
|
+
const trackInflight = (sessionID, controller) => {
|
|
441
|
+
if (!sessionID) return () => {};
|
|
442
|
+
const set = inflightBySession.get(sessionID) ?? new Set();
|
|
443
|
+
set.add(controller);
|
|
444
|
+
inflightBySession.set(sessionID, set);
|
|
445
|
+
return () => {
|
|
446
|
+
set.delete(controller);
|
|
447
|
+
if (set.size === 0) inflightBySession.delete(sessionID);
|
|
448
|
+
};
|
|
449
|
+
};
|
|
450
|
+
const abortSession = (sessionID) => {
|
|
451
|
+
const set = inflightBySession.get(asNonEmptyString(sessionID));
|
|
452
|
+
if (!set) return 0;
|
|
453
|
+
for (const controller of set) controller.abort();
|
|
454
|
+
return set.size;
|
|
455
|
+
};
|
|
456
|
+
|
|
381
457
|
const registerRoutes = (app, express) => {
|
|
382
458
|
app.post('/api/openchamber/agent-tool', express.json({ limit: '1mb' }), async (req, res) => {
|
|
383
459
|
if (!authorize(req)) return res.status(401).json({ error: 'Unauthorized' });
|
|
@@ -387,6 +463,7 @@ export const createAgentToolRuntime = (dependencies) => {
|
|
|
387
463
|
};
|
|
388
464
|
req.once('aborted', abortOnDisconnect);
|
|
389
465
|
res.once('close', abortOnDisconnect);
|
|
466
|
+
const untrack = trackInflight(asNonEmptyString(req.body?.sessionID), controller);
|
|
390
467
|
try {
|
|
391
468
|
return res.json(await execute(req.body, { signal: controller.signal }));
|
|
392
469
|
} catch (error) {
|
|
@@ -396,6 +473,7 @@ export const createAgentToolRuntime = (dependencies) => {
|
|
|
396
473
|
error: { message: error instanceof Error ? error.message : String(error), kind: 'runtime' },
|
|
397
474
|
}));
|
|
398
475
|
} finally {
|
|
476
|
+
untrack();
|
|
399
477
|
req.off('aborted', abortOnDisconnect);
|
|
400
478
|
res.off('close', abortOnDisconnect);
|
|
401
479
|
}
|
|
@@ -403,8 +481,11 @@ export const createAgentToolRuntime = (dependencies) => {
|
|
|
403
481
|
};
|
|
404
482
|
|
|
405
483
|
return {
|
|
406
|
-
|
|
484
|
+
pluginDirectory,
|
|
485
|
+
materializePlugin,
|
|
486
|
+
createChildEnv,
|
|
407
487
|
registerRoutes,
|
|
408
488
|
execute,
|
|
489
|
+
abortSession,
|
|
409
490
|
};
|
|
410
491
|
};
|