@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
|
@@ -1,47 +1,72 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import {
|
|
4
|
+
getAncestors,
|
|
5
|
+
findWorktreeRoot,
|
|
4
6
|
CONFIG_FILE,
|
|
5
7
|
AGENT_DIR,
|
|
8
|
+
OPENCODE_CONFIG_DIR,
|
|
6
9
|
AGENT_SCOPE,
|
|
7
10
|
ensureDirs,
|
|
8
11
|
parseMdFile,
|
|
9
12
|
writeMdFile,
|
|
10
13
|
readConfigLayers,
|
|
11
|
-
readConfigFile,
|
|
12
14
|
writeConfig,
|
|
13
15
|
getJsonEntrySource,
|
|
14
|
-
getJsonWriteTarget,
|
|
15
16
|
isPromptFileReference,
|
|
16
17
|
resolvePromptFilePath,
|
|
17
18
|
writePromptFile,
|
|
18
19
|
} from './shared.js';
|
|
20
|
+
import {
|
|
21
|
+
toAgentEntity,
|
|
22
|
+
fromAgentEntity,
|
|
23
|
+
isLegacyAgentFrontmatter,
|
|
24
|
+
writeSectionEntry,
|
|
25
|
+
deleteSectionEntry,
|
|
26
|
+
effectiveAgentRules,
|
|
27
|
+
readGlobalPermissionRules,
|
|
28
|
+
normalizePermissionRules,
|
|
29
|
+
parseModelSelection,
|
|
30
|
+
formatModelSelection,
|
|
31
|
+
isRecord,
|
|
32
|
+
} from './config-v2.js';
|
|
19
33
|
|
|
20
34
|
// ============== AGENT SCOPE HELPERS ==============
|
|
35
|
+
//
|
|
36
|
+
// OpenCode 2 discovers agents from `agent/`, `agents/`, `mode/` and `modes/`.
|
|
37
|
+
// OpenChamber reads every one of those and WRITES only to `agents/`. An agent
|
|
38
|
+
// that already lives in a v1 directory is rewritten in place (v2 fields, same
|
|
39
|
+
// path) so no file silently moves out from under the user.
|
|
21
40
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
41
|
+
const USER_AGENT_DIRS = ['agents', 'agent', 'modes', 'mode'].map((name) => path.join(OPENCODE_CONFIG_DIR, name));
|
|
42
|
+
const PROJECT_AGENT_DIR_NAMES = ['agents', 'agent', 'modes', 'mode'];
|
|
43
|
+
|
|
44
|
+
/** Ensure the v2 project agent directory exists. */
|
|
25
45
|
function ensureProjectAgentDir(workingDirectory) {
|
|
26
46
|
const projectAgentDir = path.join(workingDirectory, '.opencode', 'agents');
|
|
27
47
|
if (!fs.existsSync(projectAgentDir)) {
|
|
28
48
|
fs.mkdirSync(projectAgentDir, { recursive: true });
|
|
29
49
|
}
|
|
30
|
-
const legacyProjectAgentDir = path.join(workingDirectory, '.opencode', 'agent');
|
|
31
|
-
if (!fs.existsSync(legacyProjectAgentDir)) {
|
|
32
|
-
fs.mkdirSync(legacyProjectAgentDir, { recursive: true });
|
|
33
|
-
}
|
|
34
50
|
return projectAgentDir;
|
|
35
51
|
}
|
|
36
52
|
|
|
37
53
|
/**
|
|
38
|
-
*
|
|
54
|
+
* Project-level agent path: an existing v1 file keeps its path, otherwise the
|
|
55
|
+
* v2 `agents/` location.
|
|
39
56
|
*/
|
|
40
57
|
function getProjectAgentPath(workingDirectory, agentName) {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
58
|
+
const preferred = path.join(workingDirectory, '.opencode', 'agents', `${agentName}.md`);
|
|
59
|
+
// OpenCode 2 discovers `.opencode` from the working directory up to the
|
|
60
|
+
// project root, so a definition in a parent directory of a monorepo
|
|
61
|
+
// package counts; nested ids (`team/reviewer`) map onto the path.
|
|
62
|
+
const worktreeRoot = findWorktreeRoot(workingDirectory) || path.resolve(workingDirectory);
|
|
63
|
+
for (const base of getAncestors(workingDirectory, worktreeRoot)) {
|
|
64
|
+
for (const dirName of PROJECT_AGENT_DIR_NAMES) {
|
|
65
|
+
const candidate = path.join(base, '.opencode', dirName, `${agentName}.md`);
|
|
66
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return preferred;
|
|
45
70
|
}
|
|
46
71
|
|
|
47
72
|
/**
|
|
@@ -59,9 +84,7 @@ function buildUserAgentIndex(cache) {
|
|
|
59
84
|
if (cache.userAgentIndexReady) return;
|
|
60
85
|
cache.userAgentIndexReady = true;
|
|
61
86
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const dirsToVisit = [AGENT_DIR];
|
|
87
|
+
const dirsToVisit = USER_AGENT_DIRS.filter((dir) => fs.existsSync(dir));
|
|
65
88
|
while (dirsToVisit.length > 0) {
|
|
66
89
|
const dir = dirsToVisit.pop();
|
|
67
90
|
let entries;
|
|
@@ -102,24 +125,22 @@ function getIndexedUserAgentPath(agentName, cache) {
|
|
|
102
125
|
}
|
|
103
126
|
|
|
104
127
|
/**
|
|
105
|
-
*
|
|
106
|
-
* e.g.
|
|
128
|
+
* User-level agent path — walks subfolders to support grouped layouts
|
|
129
|
+
* (e.g. `~/.config/opencode/agents/business/ceo.md`) and the v1 `agent/` dir.
|
|
130
|
+
* New agents land flat in the v2 `agents/` directory.
|
|
107
131
|
*/
|
|
108
132
|
function getUserAgentPath(agentName, lookupCache = null) {
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (fs.existsSync(legacyPath)) return legacyPath;
|
|
133
|
+
const preferred = path.join(AGENT_DIR, `${agentName}.md`);
|
|
134
|
+
for (const dir of USER_AGENT_DIRS) {
|
|
135
|
+
const candidate = path.join(dir, `${agentName}.md`);
|
|
136
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
137
|
+
}
|
|
115
138
|
|
|
116
|
-
// 2. Lookup subfolders for grouped layout
|
|
117
139
|
const cache = lookupCache || createAgentLookupCache();
|
|
118
140
|
const found = getIndexedUserAgentPath(agentName, cache);
|
|
119
141
|
if (found) return found;
|
|
120
142
|
|
|
121
|
-
|
|
122
|
-
return pluralPath;
|
|
143
|
+
return preferred;
|
|
123
144
|
}
|
|
124
145
|
|
|
125
146
|
/**
|
|
@@ -133,12 +154,12 @@ function getAgentScope(agentName, workingDirectory, lookupCache = null) {
|
|
|
133
154
|
return { scope: AGENT_SCOPE.PROJECT, path: projectPath };
|
|
134
155
|
}
|
|
135
156
|
}
|
|
136
|
-
|
|
157
|
+
|
|
137
158
|
const userPath = getUserAgentPath(agentName, lookupCache);
|
|
138
159
|
if (fs.existsSync(userPath)) {
|
|
139
160
|
return { scope: AGENT_SCOPE.USER, path: userPath };
|
|
140
161
|
}
|
|
141
|
-
|
|
162
|
+
|
|
142
163
|
return { scope: null, path: null };
|
|
143
164
|
}
|
|
144
165
|
|
|
@@ -157,86 +178,41 @@ function getAgentWritePath(agentName, workingDirectory, requestedScope, lookupCa
|
|
|
157
178
|
if (scope === AGENT_SCOPE.PROJECT && workingDirectory) {
|
|
158
179
|
return {
|
|
159
180
|
scope: AGENT_SCOPE.PROJECT,
|
|
160
|
-
path: getProjectAgentPath(workingDirectory, agentName)
|
|
181
|
+
path: getProjectAgentPath(workingDirectory, agentName),
|
|
161
182
|
};
|
|
162
183
|
}
|
|
163
184
|
|
|
164
185
|
return {
|
|
165
186
|
scope: AGENT_SCOPE.USER,
|
|
166
|
-
path: getUserAgentPath(agentName, lookupCache)
|
|
187
|
+
path: getUserAgentPath(agentName, lookupCache),
|
|
167
188
|
};
|
|
168
189
|
}
|
|
169
190
|
|
|
170
|
-
|
|
171
|
-
* Detect where an agent's permission field is currently defined
|
|
172
|
-
* Priority: project .md > user .md > project JSON > user JSON
|
|
173
|
-
* Returns: { source: 'md'|'json'|null, scope: 'project'|'user'|null, path: string|null }
|
|
174
|
-
*/
|
|
175
|
-
function getAgentPermissionSource(agentName, workingDirectory, lookupCache = null) {
|
|
176
|
-
// Check project-level .md first
|
|
177
|
-
if (workingDirectory) {
|
|
178
|
-
const projectMdPath = getProjectAgentPath(workingDirectory, agentName);
|
|
179
|
-
if (fs.existsSync(projectMdPath)) {
|
|
180
|
-
const { frontmatter } = parseMdFile(projectMdPath);
|
|
181
|
-
if (frontmatter.permission !== undefined) {
|
|
182
|
-
return { source: 'md', scope: AGENT_SCOPE.PROJECT, path: projectMdPath };
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Check user-level .md
|
|
188
|
-
const userMdPath = getUserAgentPath(agentName, lookupCache);
|
|
189
|
-
if (fs.existsSync(userMdPath)) {
|
|
190
|
-
const { frontmatter } = parseMdFile(userMdPath);
|
|
191
|
-
if (frontmatter.permission !== undefined) {
|
|
192
|
-
return { source: 'md', scope: AGENT_SCOPE.USER, path: userMdPath };
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Check JSON layers in effective override order. readConfigLayers merges
|
|
197
|
-
// user -> project -> custom, so custom wins over project, project over user.
|
|
198
|
-
const layers = readConfigLayers(workingDirectory);
|
|
199
|
-
|
|
200
|
-
const customJsonPermission = layers.customConfig?.agent?.[agentName]?.permission;
|
|
201
|
-
if (customJsonPermission !== undefined && layers.paths.customPath) {
|
|
202
|
-
return { source: 'json', scope: 'custom', path: layers.paths.customPath };
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const projectJsonPermission = layers.projectConfig?.agent?.[agentName]?.permission;
|
|
206
|
-
if (projectJsonPermission !== undefined && layers.paths.projectPath) {
|
|
207
|
-
return { source: 'json', scope: AGENT_SCOPE.PROJECT, path: layers.paths.projectPath };
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const userJsonPermission = layers.userConfig?.agent?.[agentName]?.permission;
|
|
211
|
-
if (userJsonPermission !== undefined) {
|
|
212
|
-
return { source: 'json', scope: AGENT_SCOPE.USER, path: layers.paths.userPath };
|
|
213
|
-
}
|
|
191
|
+
// ============== READ ==============
|
|
214
192
|
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
193
|
+
function readMdAgent(mdPath) {
|
|
194
|
+
const { frontmatter, body } = parseMdFile(mdPath);
|
|
195
|
+
return {
|
|
196
|
+
entity: toAgentEntity(frontmatter, body),
|
|
197
|
+
frontmatter,
|
|
198
|
+
body,
|
|
199
|
+
legacy: isLegacyAgentFrontmatter(frontmatter),
|
|
200
|
+
};
|
|
224
201
|
}
|
|
225
202
|
|
|
226
203
|
function getAgentSources(agentName, workingDirectory, lookupCache = createAgentLookupCache()) {
|
|
227
204
|
const projectPath = workingDirectory ? getProjectAgentPath(workingDirectory, agentName) : null;
|
|
228
|
-
const projectExists = projectPath && fs.existsSync(projectPath);
|
|
205
|
+
const projectExists = Boolean(projectPath) && fs.existsSync(projectPath);
|
|
229
206
|
|
|
230
207
|
const userPath = getUserAgentPath(agentName, lookupCache);
|
|
231
208
|
const userExists = fs.existsSync(userPath);
|
|
232
209
|
|
|
233
210
|
const mdPath = projectExists ? projectPath : (userExists ? userPath : null);
|
|
234
|
-
const mdExists =
|
|
211
|
+
const mdExists = Boolean(mdPath);
|
|
235
212
|
const mdScope = projectExists ? AGENT_SCOPE.PROJECT : (userExists ? AGENT_SCOPE.USER : null);
|
|
236
213
|
|
|
237
214
|
const layers = readConfigLayers(workingDirectory);
|
|
238
|
-
const jsonSource = getJsonEntrySource(layers, '
|
|
239
|
-
const jsonSection = jsonSource.section;
|
|
215
|
+
const jsonSource = getJsonEntrySource(layers, 'agents', agentName);
|
|
240
216
|
const jsonPath = jsonSource.path || layers.paths.customPath || layers.paths.projectPath || layers.paths.userPath;
|
|
241
217
|
const jsonScope = jsonSource.path === layers.paths.projectPath ? AGENT_SCOPE.PROJECT : AGENT_SCOPE.USER;
|
|
242
218
|
|
|
@@ -245,79 +221,119 @@ function getAgentSources(agentName, workingDirectory, lookupCache = createAgentL
|
|
|
245
221
|
exists: mdExists,
|
|
246
222
|
path: mdPath,
|
|
247
223
|
scope: mdScope,
|
|
248
|
-
|
|
224
|
+
legacy: false,
|
|
225
|
+
fields: [],
|
|
249
226
|
},
|
|
250
227
|
json: {
|
|
251
228
|
exists: jsonSource.exists,
|
|
252
229
|
path: jsonPath,
|
|
253
230
|
scope: jsonSource.exists ? jsonScope : null,
|
|
254
|
-
|
|
231
|
+
sectionKey: jsonSource.sectionKey,
|
|
232
|
+
legacy: Boolean(jsonSource.legacy),
|
|
233
|
+
fields: [],
|
|
255
234
|
},
|
|
256
235
|
projectMd: {
|
|
257
236
|
exists: projectExists,
|
|
258
|
-
path: projectPath
|
|
237
|
+
path: projectPath,
|
|
259
238
|
},
|
|
260
239
|
userMd: {
|
|
261
240
|
exists: userExists,
|
|
262
|
-
path: userPath
|
|
263
|
-
}
|
|
241
|
+
path: userPath,
|
|
242
|
+
},
|
|
264
243
|
};
|
|
265
244
|
|
|
266
245
|
if (mdExists) {
|
|
267
|
-
const
|
|
268
|
-
sources.md.
|
|
269
|
-
|
|
270
|
-
sources.md.fields.push('prompt');
|
|
271
|
-
}
|
|
246
|
+
const md = readMdAgent(mdPath);
|
|
247
|
+
sources.md.legacy = md.legacy;
|
|
248
|
+
sources.md.fields = Object.keys(md.entity);
|
|
272
249
|
}
|
|
273
250
|
|
|
274
|
-
if (
|
|
275
|
-
sources.json.fields = Object.keys(
|
|
251
|
+
if (jsonSource.exists) {
|
|
252
|
+
sources.json.fields = Object.keys(toAgentEntity(jsonSource.section));
|
|
276
253
|
}
|
|
277
254
|
|
|
278
255
|
return sources;
|
|
279
256
|
}
|
|
280
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Canonical v2 agent entity plus where it came from. `config.system` is the
|
|
260
|
+
* markdown body for .md agents; `config.permissions` is always the ordered v2
|
|
261
|
+
* rule array, even when the file still uses a v1 `permission` map.
|
|
262
|
+
*/
|
|
281
263
|
function getAgentConfig(agentName, workingDirectory, lookupCache = createAgentLookupCache()) {
|
|
282
264
|
const projectPath = workingDirectory ? getProjectAgentPath(workingDirectory, agentName) : null;
|
|
283
|
-
const projectExists = projectPath && fs.existsSync(projectPath);
|
|
265
|
+
const projectExists = Boolean(projectPath) && fs.existsSync(projectPath);
|
|
284
266
|
|
|
285
267
|
const userPath = getUserAgentPath(agentName, lookupCache);
|
|
286
268
|
const userExists = fs.existsSync(userPath);
|
|
287
269
|
|
|
288
270
|
if (projectExists || userExists) {
|
|
289
271
|
const mdPath = projectExists ? projectPath : userPath;
|
|
290
|
-
const
|
|
291
|
-
|
|
272
|
+
const md = readMdAgent(mdPath);
|
|
292
273
|
return {
|
|
293
274
|
source: 'md',
|
|
294
275
|
scope: projectExists ? AGENT_SCOPE.PROJECT : AGENT_SCOPE.USER,
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
},
|
|
276
|
+
path: mdPath,
|
|
277
|
+
legacy: md.legacy,
|
|
278
|
+
config: md.entity,
|
|
299
279
|
};
|
|
300
280
|
}
|
|
301
281
|
|
|
302
282
|
const layers = readConfigLayers(workingDirectory);
|
|
303
|
-
const jsonSource = getJsonEntrySource(layers, '
|
|
283
|
+
const jsonSource = getJsonEntrySource(layers, 'agents', agentName);
|
|
304
284
|
|
|
305
|
-
if (jsonSource.exists
|
|
285
|
+
if (jsonSource.exists) {
|
|
306
286
|
const scope = jsonSource.path === layers.paths.projectPath ? AGENT_SCOPE.PROJECT : AGENT_SCOPE.USER;
|
|
307
287
|
return {
|
|
308
288
|
source: 'json',
|
|
309
289
|
scope,
|
|
310
|
-
|
|
290
|
+
path: jsonSource.path,
|
|
291
|
+
legacy: Boolean(jsonSource.legacy),
|
|
292
|
+
config: toAgentEntity(jsonSource.section),
|
|
311
293
|
};
|
|
312
294
|
}
|
|
313
295
|
|
|
314
296
|
return {
|
|
315
297
|
source: 'none',
|
|
316
298
|
scope: null,
|
|
299
|
+
path: null,
|
|
300
|
+
legacy: false,
|
|
317
301
|
config: {},
|
|
318
302
|
};
|
|
319
303
|
}
|
|
320
304
|
|
|
305
|
+
/**
|
|
306
|
+
* The permission rules that apply to an agent, in evaluation order (global
|
|
307
|
+
* rules first, agent rules last; last match wins). Answers the editor question
|
|
308
|
+
* "what applies to this agent".
|
|
309
|
+
*/
|
|
310
|
+
function getAgentPermissions(agentName, workingDirectory, lookupCache = createAgentLookupCache()) {
|
|
311
|
+
const layers = readConfigLayers(workingDirectory);
|
|
312
|
+
const global = [
|
|
313
|
+
...readGlobalPermissionRules(layers.userConfig),
|
|
314
|
+
...readGlobalPermissionRules(layers.projectConfig),
|
|
315
|
+
...readGlobalPermissionRules(layers.customConfig),
|
|
316
|
+
];
|
|
317
|
+
const agent = getAgentConfig(agentName, workingDirectory, lookupCache);
|
|
318
|
+
return {
|
|
319
|
+
global,
|
|
320
|
+
agent: agent.config.permissions ?? [],
|
|
321
|
+
effective: effectiveAgentRules(global, agent.config.permissions ?? []),
|
|
322
|
+
source: agent.source,
|
|
323
|
+
path: agent.path,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ============== WRITE ==============
|
|
328
|
+
|
|
329
|
+
function writeAgentMd(targetPath, entity) {
|
|
330
|
+
const { fields, system } = fromAgentEntity(entity);
|
|
331
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
332
|
+
// Native keys only: a single legacy key routes the whole file through
|
|
333
|
+
// OpenCode's v1 decoder, which would drop the `permissions` array.
|
|
334
|
+
writeMdFile(targetPath, fields, system);
|
|
335
|
+
}
|
|
336
|
+
|
|
321
337
|
function createAgent(agentName, config, workingDirectory, scope) {
|
|
322
338
|
ensureDirs();
|
|
323
339
|
const lookupCache = createAgentLookupCache();
|
|
@@ -334,8 +350,7 @@ function createAgent(agentName, config, workingDirectory, scope) {
|
|
|
334
350
|
}
|
|
335
351
|
|
|
336
352
|
const layers = readConfigLayers(workingDirectory);
|
|
337
|
-
|
|
338
|
-
if (jsonSource.exists) {
|
|
353
|
+
if (getJsonEntrySource(layers, 'agents', agentName).exists) {
|
|
339
354
|
throw new Error(`Agent ${agentName} already exists in opencode.json`);
|
|
340
355
|
}
|
|
341
356
|
|
|
@@ -351,233 +366,122 @@ function createAgent(agentName, config, workingDirectory, scope) {
|
|
|
351
366
|
targetScope = AGENT_SCOPE.USER;
|
|
352
367
|
}
|
|
353
368
|
|
|
354
|
-
const {
|
|
355
|
-
|
|
356
|
-
Object.entries(rawFrontmatter).filter(([, value]) => value !== null && value !== undefined)
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
writeMdFile(targetPath, frontmatter, prompt || '');
|
|
369
|
+
const { scope: _ignoredScope, ...entity } = isRecord(config) ? config : {};
|
|
370
|
+
writeAgentMd(targetPath, entity);
|
|
360
371
|
console.log(`Created new agent: ${agentName} (scope: ${targetScope}, path: ${targetPath})`);
|
|
372
|
+
return { scope: targetScope, path: targetPath };
|
|
361
373
|
}
|
|
362
374
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
375
|
+
// v1 agent fields that do not exist at the top level of a v2 entity any more.
|
|
376
|
+
// A client clearing one of them names the v1 field, so deletion has to reach
|
|
377
|
+
// the v2 location instead of removing a key that was never there.
|
|
378
|
+
const AGENT_REQUEST_BODY_FIELDS = ['temperature', 'top_p'];
|
|
366
379
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const hasJsonFields = jsonSource.exists && jsonSection && Object.keys(jsonSection).length > 0;
|
|
374
|
-
const jsonTarget = jsonSource.exists
|
|
375
|
-
? { config: jsonSource.config, path: jsonSource.path }
|
|
376
|
-
: getJsonWriteTarget(layers, AGENT_SCOPE.USER);
|
|
377
|
-
let config = jsonTarget.config || {};
|
|
378
|
-
|
|
379
|
-
const isBuiltinOverride = !mdExists && !hasJsonFields;
|
|
380
|
+
function deleteRequestBodyField(entity, key) {
|
|
381
|
+
if (!isRecord(entity.request) || !isRecord(entity.request.body)) return;
|
|
382
|
+
delete entity.request.body[key];
|
|
383
|
+
if (Object.keys(entity.request.body).length === 0) delete entity.request.body;
|
|
384
|
+
if (Object.keys(entity.request).length === 0) delete entity.request;
|
|
385
|
+
}
|
|
380
386
|
|
|
381
|
-
|
|
382
|
-
|
|
387
|
+
/** Drop the `#variant` suffix, keeping the provider and model. */
|
|
388
|
+
function stripModelVariant(entity) {
|
|
389
|
+
const parsed = parseModelSelection(entity.model);
|
|
390
|
+
if (!parsed) return;
|
|
391
|
+
const stripped = formatModelSelection({ providerID: parsed.providerID, modelID: parsed.modelID });
|
|
392
|
+
if (stripped) entity.model = stripped;
|
|
393
|
+
}
|
|
383
394
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
395
|
+
function deleteAgentField(entity, field) {
|
|
396
|
+
if (field === 'permission' || field === 'permissions') {
|
|
397
|
+
delete entity.permissions;
|
|
398
|
+
return;
|
|
387
399
|
}
|
|
400
|
+
if (field === 'variant') {
|
|
401
|
+
stripModelVariant(entity);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
if (AGENT_REQUEST_BODY_FIELDS.includes(field)) {
|
|
405
|
+
deleteRequestBodyField(entity, field);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
delete entity[field === 'prompt' ? 'system' : field];
|
|
409
|
+
}
|
|
388
410
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
if (
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
if (isPromptFileReference(jsonSection?.prompt)) {
|
|
410
|
-
const promptFilePath = resolvePromptFilePath(jsonSection.prompt);
|
|
411
|
-
if (!promptFilePath) {
|
|
412
|
-
throw new Error(`Invalid prompt file reference for agent ${agentName}`);
|
|
413
|
-
}
|
|
414
|
-
writePromptFile(promptFilePath, '');
|
|
415
|
-
continue;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (config.agent?.[agentName]) {
|
|
419
|
-
delete config.agent[agentName].prompt;
|
|
420
|
-
|
|
421
|
-
if (Object.keys(config.agent[agentName]).length === 0) {
|
|
422
|
-
delete config.agent[agentName];
|
|
423
|
-
}
|
|
424
|
-
if (Object.keys(config.agent).length === 0) {
|
|
425
|
-
delete config.agent;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
jsonModified = true;
|
|
429
|
-
}
|
|
430
|
-
continue;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
const normalizedValue = typeof value === 'string' ? value : (value == null ? '' : String(value));
|
|
434
|
-
|
|
435
|
-
if (mdExists || creatingNewMd) {
|
|
436
|
-
if (mdData) {
|
|
437
|
-
mdData.body = normalizedValue;
|
|
438
|
-
mdModified = true;
|
|
439
|
-
}
|
|
440
|
-
continue;
|
|
441
|
-
} else if (isPromptFileReference(jsonSection?.prompt)) {
|
|
442
|
-
const promptFilePath = resolvePromptFilePath(jsonSection.prompt);
|
|
443
|
-
if (!promptFilePath) {
|
|
444
|
-
throw new Error(`Invalid prompt file reference for agent ${agentName}`);
|
|
445
|
-
}
|
|
446
|
-
writePromptFile(promptFilePath, normalizedValue);
|
|
447
|
-
continue;
|
|
448
|
-
} else if (isPromptFileReference(normalizedValue)) {
|
|
449
|
-
if (!config.agent) config.agent = {};
|
|
450
|
-
if (!config.agent[agentName]) config.agent[agentName] = {};
|
|
451
|
-
config.agent[agentName].prompt = normalizedValue;
|
|
452
|
-
jsonModified = true;
|
|
453
|
-
continue;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
if (!config.agent) config.agent = {};
|
|
457
|
-
if (!config.agent[agentName]) config.agent[agentName] = {};
|
|
458
|
-
config.agent[agentName].prompt = normalizedValue;
|
|
459
|
-
jsonModified = true;
|
|
411
|
+
/**
|
|
412
|
+
* Merge a partial update into a canonical entity. `null` removes a field,
|
|
413
|
+
* `undefined` leaves it alone.
|
|
414
|
+
*/
|
|
415
|
+
function applyAgentUpdates(entity, updates) {
|
|
416
|
+
// `request` is copied so clearing one overlay field cannot mutate the entity
|
|
417
|
+
// the caller still holds.
|
|
418
|
+
const next = { ...entity };
|
|
419
|
+
if (isRecord(next.request)) {
|
|
420
|
+
const request = { ...next.request };
|
|
421
|
+
if (isRecord(request.body)) request.body = { ...request.body };
|
|
422
|
+
if (isRecord(request.headers)) request.headers = { ...request.headers };
|
|
423
|
+
next.request = request;
|
|
424
|
+
}
|
|
425
|
+
for (const [field, value] of Object.entries(isRecord(updates) ? updates : {})) {
|
|
426
|
+
if (field === 'scope' || value === undefined) continue;
|
|
427
|
+
if (value === null) {
|
|
428
|
+
deleteAgentField(next, field);
|
|
460
429
|
continue;
|
|
461
430
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
// (The old non-wildcard re-merge resurrected rules the user deleted.)
|
|
467
|
-
const newPermission = value && typeof value === 'object' && Object.keys(value).length === 0 ? null : value;
|
|
468
|
-
|
|
469
|
-
if (permissionSource.source === 'md') {
|
|
470
|
-
if (mdData && permissionSource.path === targetPath) {
|
|
471
|
-
applyAgentPermission(mdData.frontmatter, newPermission);
|
|
472
|
-
mdModified = true;
|
|
473
|
-
} else {
|
|
474
|
-
const existingMdData = parseMdFile(permissionSource.path);
|
|
475
|
-
applyAgentPermission(existingMdData.frontmatter, newPermission);
|
|
476
|
-
writeMdFile(permissionSource.path, existingMdData.frontmatter, existingMdData.body);
|
|
477
|
-
console.log(`Updated permission in .md file: ${permissionSource.path}`);
|
|
478
|
-
}
|
|
479
|
-
} else if (permissionSource.source === 'json') {
|
|
480
|
-
if (permissionSource.path === (jsonTarget.path || CONFIG_FILE)) {
|
|
481
|
-
if (!config.agent) config.agent = {};
|
|
482
|
-
if (!config.agent[agentName]) config.agent[agentName] = {};
|
|
483
|
-
applyAgentPermission(config.agent[agentName], newPermission);
|
|
484
|
-
jsonModified = true;
|
|
485
|
-
} else {
|
|
486
|
-
const existingConfig = readConfigFile(permissionSource.path);
|
|
487
|
-
if (!existingConfig.agent) existingConfig.agent = {};
|
|
488
|
-
if (!existingConfig.agent[agentName]) existingConfig.agent[agentName] = {};
|
|
489
|
-
applyAgentPermission(existingConfig.agent[agentName], newPermission);
|
|
490
|
-
writeConfig(existingConfig, permissionSource.path);
|
|
491
|
-
console.log(`Updated permission in JSON: ${permissionSource.path}`);
|
|
492
|
-
}
|
|
493
|
-
} else {
|
|
494
|
-
if (mdExists && mdData) {
|
|
495
|
-
applyAgentPermission(mdData.frontmatter, newPermission);
|
|
496
|
-
mdModified = true;
|
|
497
|
-
} else if (hasJsonFields) {
|
|
498
|
-
if (!config.agent) config.agent = {};
|
|
499
|
-
if (!config.agent[agentName]) config.agent[agentName] = {};
|
|
500
|
-
applyAgentPermission(config.agent[agentName], newPermission);
|
|
501
|
-
jsonModified = true;
|
|
502
|
-
} else {
|
|
503
|
-
const writeTarget = getJsonWriteTarget(layers, AGENT_SCOPE.USER);
|
|
504
|
-
if (!writeTarget.config.agent) writeTarget.config.agent = {};
|
|
505
|
-
if (!writeTarget.config.agent[agentName]) writeTarget.config.agent[agentName] = {};
|
|
506
|
-
applyAgentPermission(writeTarget.config.agent[agentName], newPermission);
|
|
507
|
-
writeConfig(writeTarget.config, writeTarget.path);
|
|
508
|
-
console.log(`Created permission in JSON: ${writeTarget.path}`);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
431
|
+
if (field === 'permission' || field === 'permissions') {
|
|
432
|
+
const rules = normalizePermissionRules(value);
|
|
433
|
+
if (rules.length === 0) delete next.permissions;
|
|
434
|
+
else next.permissions = rules;
|
|
511
435
|
continue;
|
|
512
436
|
}
|
|
437
|
+
// `prompt` is the v1 spelling of `system`; accept it so older clients keep working.
|
|
438
|
+
next[field === 'prompt' ? 'system' : field] = value;
|
|
439
|
+
}
|
|
440
|
+
return toAgentEntity(next);
|
|
441
|
+
}
|
|
513
442
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
if (value === null) {
|
|
518
|
-
if (mdData && inMd) {
|
|
519
|
-
delete mdData.frontmatter[field];
|
|
520
|
-
mdModified = true;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
if (inJson && config.agent?.[agentName]) {
|
|
524
|
-
delete config.agent[agentName][field];
|
|
525
|
-
|
|
526
|
-
if (Object.keys(config.agent[agentName]).length === 0) {
|
|
527
|
-
delete config.agent[agentName];
|
|
528
|
-
}
|
|
529
|
-
if (Object.keys(config.agent).length === 0) {
|
|
530
|
-
delete config.agent;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
jsonModified = true;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
continue;
|
|
537
|
-
}
|
|
443
|
+
function updateAgent(agentName, updates, workingDirectory) {
|
|
444
|
+
ensureDirs();
|
|
445
|
+
const lookupCache = createAgentLookupCache();
|
|
538
446
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
447
|
+
const current = getAgentConfig(agentName, workingDirectory, lookupCache);
|
|
448
|
+
const entity = applyAgentUpdates(current.config, updates);
|
|
449
|
+
|
|
450
|
+
if (current.source === 'md') {
|
|
451
|
+
writeAgentMd(current.path, entity);
|
|
452
|
+
console.log(`Updated agent: ${agentName} (md: ${current.path})`);
|
|
453
|
+
return { source: 'md', scope: current.scope, path: current.path };
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (current.source === 'json') {
|
|
457
|
+
const layers = readConfigLayers(workingDirectory);
|
|
458
|
+
const jsonSource = getJsonEntrySource(layers, 'agents', agentName);
|
|
459
|
+
const config = jsonSource.config || {};
|
|
460
|
+
const rawSystem = jsonSource.section?.system ?? jsonSource.section?.prompt;
|
|
461
|
+
// `{file:...}` substitution still works in OpenCode 2, so an agent whose
|
|
462
|
+
// system prompt lives in a file keeps the reference and the file is edited.
|
|
463
|
+
if (isPromptFileReference(rawSystem)) {
|
|
464
|
+
const promptFilePath = resolvePromptFilePath(rawSystem);
|
|
465
|
+
if (!promptFilePath) {
|
|
466
|
+
throw new Error(`Invalid prompt file reference for agent ${agentName}`);
|
|
548
467
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
mdData.frontmatter[field] = value;
|
|
552
|
-
mdModified = true;
|
|
553
|
-
} else {
|
|
554
|
-
if (!config.agent) config.agent = {};
|
|
555
|
-
if (!config.agent[agentName]) config.agent[agentName] = {};
|
|
556
|
-
config.agent[agentName][field] = value;
|
|
557
|
-
jsonModified = true;
|
|
468
|
+
if (entity.system !== current.config.system) {
|
|
469
|
+
writePromptFile(promptFilePath, entity.system ?? '');
|
|
558
470
|
}
|
|
471
|
+
entity.system = rawSystem;
|
|
559
472
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
console.log(`
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
function deleteJsonAgentEntry(config, agentName) {
|
|
574
|
-
const agentMap = config.agent;
|
|
575
|
-
if (!agentMap || typeof agentMap !== 'object' || Array.isArray(agentMap) || !agentMap[agentName]) return false;
|
|
576
|
-
delete agentMap[agentName];
|
|
577
|
-
if (Object.keys(agentMap).length === 0) {
|
|
578
|
-
delete config.agent;
|
|
579
|
-
}
|
|
580
|
-
return true;
|
|
473
|
+
writeSectionEntry(config, 'agents', agentName, entity);
|
|
474
|
+
const targetPath = jsonSource.path || CONFIG_FILE;
|
|
475
|
+
writeConfig(config, targetPath);
|
|
476
|
+
console.log(`Updated agent: ${agentName} (json: ${targetPath})`);
|
|
477
|
+
return { source: 'json', scope: current.scope, path: targetPath };
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Built-in override: materialize a user-level v2 markdown agent.
|
|
481
|
+
const { scope, path: targetPath } = getAgentWritePath(agentName, workingDirectory, AGENT_SCOPE.USER, lookupCache);
|
|
482
|
+
writeAgentMd(targetPath, entity);
|
|
483
|
+
console.log(`Created agent override: ${agentName} (scope: ${scope}, path: ${targetPath})`);
|
|
484
|
+
return { source: 'md', scope, path: targetPath };
|
|
581
485
|
}
|
|
582
486
|
|
|
583
487
|
function deleteAgent(agentName, workingDirectory, scope) {
|
|
@@ -605,7 +509,7 @@ function deleteAgent(agentName, workingDirectory, scope) {
|
|
|
605
509
|
const layers = readConfigLayers(workingDirectory);
|
|
606
510
|
|
|
607
511
|
if (requestedScope === AGENT_SCOPE.PROJECT) {
|
|
608
|
-
if (layers.paths.projectPath &&
|
|
512
|
+
if (layers.paths.projectPath && deleteSectionEntry(layers.projectConfig, 'agents', agentName)) {
|
|
609
513
|
writeConfig(layers.projectConfig, layers.paths.projectPath);
|
|
610
514
|
console.log(`Removed project-level agent from opencode.json: ${agentName}`);
|
|
611
515
|
return;
|
|
@@ -616,7 +520,7 @@ function deleteAgent(agentName, workingDirectory, scope) {
|
|
|
616
520
|
if (requestedScope === AGENT_SCOPE.USER) {
|
|
617
521
|
const userJsonPath = layers.paths.customPath || layers.paths.userPath;
|
|
618
522
|
const userJsonConfig = layers.paths.customPath ? layers.customConfig : layers.userConfig;
|
|
619
|
-
if (userJsonPath &&
|
|
523
|
+
if (userJsonPath && deleteSectionEntry(userJsonConfig, 'agents', agentName)) {
|
|
620
524
|
writeConfig(userJsonConfig, userJsonPath);
|
|
621
525
|
console.log(`Removed user-level agent from opencode.json: ${agentName}`);
|
|
622
526
|
return;
|
|
@@ -624,8 +528,9 @@ function deleteAgent(agentName, workingDirectory, scope) {
|
|
|
624
528
|
throw new Error(`User agent ${agentName} not found`);
|
|
625
529
|
}
|
|
626
530
|
|
|
627
|
-
const jsonSource = getJsonEntrySource(layers, '
|
|
628
|
-
if (jsonSource.exists && jsonSource.config && jsonSource.path
|
|
531
|
+
const jsonSource = getJsonEntrySource(layers, 'agents', agentName);
|
|
532
|
+
if (jsonSource.exists && jsonSource.config && jsonSource.path
|
|
533
|
+
&& deleteSectionEntry(jsonSource.config, 'agents', agentName)) {
|
|
629
534
|
writeConfig(jsonSource.config, jsonSource.path);
|
|
630
535
|
console.log(`Removed agent from opencode.json: ${agentName}`);
|
|
631
536
|
return;
|
|
@@ -637,6 +542,7 @@ function deleteAgent(agentName, workingDirectory, scope) {
|
|
|
637
542
|
export {
|
|
638
543
|
getAgentSources,
|
|
639
544
|
getAgentConfig,
|
|
545
|
+
getAgentPermissions,
|
|
640
546
|
createAgent,
|
|
641
547
|
updateAgent,
|
|
642
548
|
deleteAgent,
|