@openchambery/web 2.0.0-beta.1 → 2.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -11
- package/bin/cli-opencode.test.js +4 -4
- package/bin/cli.js +1 -1
- package/bin/lib/cli-startup.js +1 -1
- package/bin/lib/cli-startup.test.js +18 -4
- package/dist/assets/{AgentAvatar-CLWWNu_Q.js → AgentAvatar-Q1SmFRx2.js} +1 -1
- package/dist/assets/AssistantView-CwXkiCAd.js +3 -0
- package/dist/assets/{DiagramView-xuSJTnv7.js → DiagramView-BW92schO.js} +1 -1
- package/dist/assets/{FadeInOnReveal-Ov0D96d0.js → FadeInOnReveal-BZmwl-zE.js} +1 -1
- package/dist/assets/{Icon-DD-BuMfZ.js → Icon-AQPvxMiU.js} +1 -1
- package/dist/assets/{MarkdownRenderer-bc_p1H7l.js → MarkdownRenderer-Bv05iDZZ.js} +2 -2
- package/dist/assets/{MarkdownRendererImpl-SKi4oG0c.js → MarkdownRendererImpl-C81xqYib.js} +3 -3
- package/dist/assets/MarkstreamRendererImpl-CXUCQuKJ.js +3 -0
- package/dist/assets/{MobileDetailNavigation-Bnx59U_J.js → MobileDetailNavigation-BMgIu7zc.js} +1 -1
- package/dist/assets/{MobileShareBridge-BQlP4J-F.js → MobileShareBridge-BOXGNHmC.js} +2 -2
- package/dist/assets/MobileSurface-xuc_z0_G.js +2 -0
- package/dist/assets/{MultiRunWindow-ChZGob0v.js → MultiRunWindow-B5At2Z95.js} +1 -1
- package/dist/assets/{OnboardingScreen-DtQJxZG-.js → OnboardingScreen-bsPLgz4r.js} +1 -1
- package/dist/assets/OverlayScrollbar-4wp4migh.js +2 -0
- package/dist/assets/SettingsView-CJ6tcH5_.js +25 -0
- package/dist/assets/{SettingsWindow-DfnsFa8y.js → SettingsWindow-CMtX2bMl.js} +1 -1
- package/dist/assets/{TerminalView-Dh9MWCpS.js → TerminalView-Dvr-ysTS.js} +1 -1
- package/dist/assets/{ToolOutputDialog-BejmjrRk.js → ToolOutputDialog-uH1ZZDSS.js} +2 -2
- package/dist/assets/appThemeRegistry-DK7q2juD.js +1 -0
- package/dist/assets/{assistant-attachment-cache-C0aRnFkj.js → assistant-attachment-cache-DphJleHr.js} +1 -1
- package/dist/assets/{button-D-rATN7w.js → button-CcNJUxUd.js} +1 -1
- package/dist/assets/collapsible-ZmZ6rLWs.js +3 -0
- package/dist/assets/context-menu-B2LXJgXL.js +1 -0
- package/dist/assets/{desktopHosts-B1ixEylr.js → desktopHosts-C6HrP0jq.js} +1 -1
- package/dist/assets/{desktopRelayRestore-4JmFUw8r.js → desktopRelayRestore-DdVBp45U.js} +1 -1
- package/dist/assets/{diagram-DQf7Y_uR.js → diagram-CxTs9hCQ.js} +1 -1
- package/dist/assets/{dialog-bfbvR4VH.js → dialog-KMVL9QKF.js} +1 -1
- package/dist/assets/es-CN3E_zXj.js +15 -0
- package/dist/assets/{fileMentionTouchSelection-BvrNCroG.js → fileMentionTouchSelection-7RIwlpkB.js} +1 -1
- package/dist/assets/{fileQueries-DQc8EJUf.js → fileQueries-CjdBRy8y.js} +1 -1
- package/dist/assets/fr-9zZvQZD2.js +13 -0
- package/dist/assets/gitApi-yuWg9BN4.js +10 -0
- package/dist/assets/{imageSource-BlAJJUEI.js → imageSource-9vQBq3zp.js} +1 -1
- package/dist/assets/{input-8r6F_Fza.js → input-CrIvk3HZ.js} +1 -1
- package/dist/assets/insertionBoundaries-BiUCSkx-.js +1 -0
- package/dist/assets/ja-Dnjk_82N.js +15 -0
- package/dist/assets/ko-BxCEE99C.js +15 -0
- package/dist/assets/{main-CCE_4y5F.js → main-C9mIBo77.js} +2 -2
- package/dist/assets/main-DiL6w6KF.js +169 -0
- package/dist/assets/markdown-worker-bS5OgGO3.js +2 -0
- package/dist/assets/{markdownHeightCache-1Qo6y6IJ.js → markdownHeightCache-BmXVY_gc.js} +1 -1
- package/dist/assets/{markdownTheme-DOfGg-A7.js → markdownTheme-CKac3wKC.js} +1 -1
- package/dist/assets/mcpQueries-C7jknHV8.js +1 -0
- package/dist/assets/miniChat-CwtUaElU.js +2 -0
- package/dist/assets/mobile-DB-6--ws.js +2 -0
- package/dist/assets/multirun-TAsxFI8e.js +4 -0
- package/dist/assets/{persistence-Ce3AnpEr.js → persistence-56kq8Z4V.js} +2 -2
- package/dist/assets/pl-CNNsWnPM.js +15 -0
- package/dist/assets/platform-C13fMVEs.js +6 -0
- package/dist/assets/pt-BR-BZB2DJMp.js +15 -0
- package/dist/assets/{relay-image-stream-DM7atqJs.js → relay-image-stream-DrdVj99c.js} +1 -1
- package/dist/assets/renderElectronMiniChatApp-CGj0MNRU.js +2 -0
- package/dist/assets/renderMobileApp-CGMMqbsO.js +28 -0
- package/dist/assets/runtime-fetch-Fs9ZV2V8.js +1 -0
- package/dist/assets/{runtimeConfig-BMvqa5we.js → runtimeConfig-BEANkvOd.js} +1 -1
- package/dist/assets/runtimeEndpointReset-A_ZBUJFS.js +147 -0
- package/dist/assets/sessionChangeSummary-qOLrP9fw.js +2 -0
- package/dist/assets/{sessionLookup-gh-hVRIc.js → sessionLookup-34XFmP9C.js} +1 -1
- package/dist/assets/{sortable-tabs-strip-CudoSgV4.js → sortable-tabs-strip-DyEV0Heg.js} +1 -1
- package/dist/assets/src-ubCWXZhR.css +2 -0
- package/dist/assets/store-DLCiZaA6.js +15 -0
- package/dist/assets/{terminalApi-DiF6JmBP.js → terminalApi-CXaBEoa_.js} +1 -1
- package/dist/assets/textarea-BBOlRI9O.js +1 -0
- package/dist/assets/{tooltip-CQvpK-UV.js → tooltip-CPI4fr1a.js} +1 -1
- package/dist/assets/uk-rwQrxeYM.js +15 -0
- package/dist/assets/{url-_z7evzdK.js → url-DRDQXjyX.js} +1 -1
- package/dist/assets/{useAppFontEffects-Cpmpo7Wb.js → useAppFontEffects-CiDe42I5.js} +57 -43
- package/dist/assets/{useAssistantUIStore-CMutVh9B.js → useAssistantUIStore-asNG6K7n.js} +1 -1
- package/dist/assets/useDesktopWindowControlsLayout-BlizAlOt.js +1 -0
- package/dist/assets/useEffectiveDirectory-C_CouL5v.js +1 -0
- package/dist/assets/{useFontPreferences-DcbXQOkc.js → useFontPreferences-B0oUZAiB.js} +1 -1
- package/dist/assets/useMobileNavigationStore-DfPClaW-.js +414 -0
- package/dist/assets/{useRuntimeAPIs-DSLXJybW.js → useRuntimeAPIs-DwLtO0c_.js} +1 -1
- package/dist/assets/useSessionAutoCleanup-DtrfbxAp.js +2 -0
- package/dist/assets/{useThemeSystem-DMzWVJaW.js → useThemeSystem-BlNUWH47.js} +1 -1
- package/dist/assets/useUIStore-CQYKJnrg.js +1 -0
- package/dist/assets/{useWorkerHighlightedLines-Bqn4AiBL.js → useWorkerHighlightedLines-CPNYz6Wf.js} +2 -2
- package/dist/assets/{vendor-base-ui-CnHfUmDN.js → vendor-base-ui-CDjyofeD.js} +1 -1
- package/dist/assets/{vendor-cmdk-CeAGfrLo.js → vendor-cmdk-BFH0UpXX.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-accessibility-BY5LhhUB.js → vendor-dnd-kit-accessibility-BrR3AKvM.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-core-CvWxUPdb.js → vendor-dnd-kit-core-CNfdvk6H.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-sortable-hHdP9lLb.js → vendor-dnd-kit-sortable-DQUaTeGj.js} +1 -1
- package/dist/assets/{vendor-framer-motion-DFy_BSVd.js → vendor-framer-motion-4dogsUk3.js} +1 -1
- package/dist/assets/{vendor-legendapp-list-WE32lwNk.js → vendor-legendapp-list-BU7MdPZR.js} +1 -1
- package/dist/assets/{vendor-markstream-react-DX55XLGO.js → vendor-markstream-react-qHC2FykU.js} +3 -3
- package/dist/assets/{vendor-pierre-diffs-DX7XTPG3.js → vendor-pierre-diffs-CUfqC003.js} +1 -1
- package/dist/assets/{vendor-react-DLPElpoQ.js → vendor-react-C94A0AHl.js} +1 -1
- package/dist/assets/{vendor-react-drawio-ECtEwvbc.js → vendor-react-drawio-FVlWqKVE.js} +1 -1
- package/dist/assets/{vendor-reactuses-core-BnW6GxJt.js → vendor-reactuses-core-C2A3EjUi.js} +1 -1
- package/dist/assets/{vendor-sonner-DVzioF3d.js → vendor-sonner-DNqHmUQs.js} +1 -1
- package/dist/assets/{vendor-stream-diffs-DWy3xSmp.js → vendor-stream-diffs-CwbKsmlv.js} +2 -2
- package/dist/assets/{vendor-tanstack-react-query-D7pys_c9.js → vendor-tanstack-react-query-D0iFK57C.js} +1 -1
- package/dist/assets/{vendor-tanstack-react-virtual-tlDgH6PG.js → vendor-tanstack-react-virtual-B2kV6cnT.js} +1 -1
- package/dist/assets/{vendor-zustand-B4dlGEM2.js → vendor-zustand-BqLKf6ZY.js} +1 -1
- package/dist/assets/zh-CN-BvmBDnkD.js +15 -0
- package/dist/assets/zh-TW-9wcHTX0y.js +15 -0
- package/dist/index.html +13 -13
- package/dist/mini-chat.html +13 -13
- package/dist/mobile.html +13 -13
- package/package.json +1 -1
- package/server/index.js +327 -62
- package/server/lib/assistants/DOCUMENTATION.md +14 -9
- package/server/lib/assistants/contracts.js +11 -1
- package/server/lib/assistants/projection-history.test.js +265 -18
- package/server/lib/assistants/routes.js +6 -0
- package/server/lib/assistants/service.js +417 -231
- package/server/lib/assistants/service.test.js +392 -148
- package/server/lib/conversations/DOCUMENTATION.md +1 -1
- package/server/lib/conversations/service.js +1 -0
- package/server/lib/conversations/service.test.js +16 -0
- package/server/lib/conversations/validation.js +11 -1
- package/server/lib/event-stream/DOCUMENTATION.md +3 -1
- package/server/lib/event-stream/directory-ws-bridge.js +13 -2
- package/server/lib/event-stream/global-hub.js +49 -4
- package/server/lib/event-stream/reasoning-projection.js +16 -1
- package/server/lib/event-stream/reasoning-projection.test.js +15 -0
- package/server/lib/event-stream/runtime.js +57 -20
- package/server/lib/event-stream/runtime.test.js +112 -0
- package/server/lib/llm/DOCUMENTATION.md +33 -9
- package/server/lib/llm/catalog.js +1 -1
- package/server/lib/llm/completions.js +5 -1
- package/server/lib/llm/completions.test.js +3 -3
- package/server/lib/llm/generate.js +237 -145
- package/server/lib/llm/generate.test.js +201 -46
- package/server/lib/llm/routes.js +2 -0
- package/server/lib/message-queue/runtime.js +15 -2
- package/server/lib/notifications/runtime.js +23 -5
- package/server/lib/notifications/runtime.test.js +11 -0
- package/server/lib/opencode/DOCUMENTATION.md +85 -17
- package/server/lib/opencode/agent-document.d.ts +28 -0
- package/server/lib/opencode/agent-document.js +280 -0
- package/server/lib/opencode/agent-document.test.js +137 -0
- package/server/lib/opencode/agents.js +96 -0
- package/server/lib/opencode/auth-state-runtime.js +5 -0
- package/server/lib/opencode/bootstrap-runtime.js +2 -0
- package/server/lib/opencode/config-entity-routes.js +42 -99
- package/server/lib/opencode/config-entity-routes.test.js +107 -0
- package/server/lib/opencode/config-hot-reload.integration.test.js +105 -0
- package/server/lib/opencode/ensure-cli.js +1 -2
- package/server/lib/opencode/env-runtime.js +40 -26
- package/server/lib/opencode/env-runtime.test.js +10 -17
- package/server/lib/opencode/feature-routes-runtime.js +43 -4
- package/server/lib/opencode/feature-routes-runtime.test.js +18 -0
- package/server/lib/opencode/http-server-connections.js +98 -0
- package/server/lib/opencode/http-server-connections.test.js +321 -0
- package/server/lib/opencode/lifecycle.js +349 -39
- package/server/lib/opencode/lifecycle.test.js +322 -0
- package/server/lib/opencode/managed-capabilities-runtime.js +15 -2
- package/server/lib/opencode/managed-capabilities-runtime.test.js +1 -0
- package/server/lib/opencode/openchamber-routes.js +7 -1
- package/server/lib/opencode/opencode2-pin.js +4 -4
- package/server/lib/opencode/opencode2-pin.test.js +1 -0
- package/server/lib/opencode/opencode2-sidecar.e2e.test.js +127 -4
- package/server/lib/opencode/owned-runtime-upgrade.js +431 -0
- package/server/lib/opencode/owned-runtime-upgrade.test.js +160 -0
- package/server/lib/opencode/plugin-routes.js +3 -18
- package/server/lib/opencode/plugin-routes.test.js +9 -9
- package/server/lib/opencode/provider-catalog.js +58 -12
- package/server/lib/opencode/provider-catalog.test.js +48 -0
- package/server/lib/opencode/proxy.js +252 -46
- package/server/lib/opencode/proxy.test.js +235 -2
- package/server/lib/opencode/routes.js +296 -62
- package/server/lib/opencode/routes.test.js +278 -12
- package/server/lib/opencode/runtime-contract.js +401 -0
- package/server/lib/opencode/runtime-contract.test.js +214 -0
- package/server/lib/opencode/server-opencode-fetch.js +242 -0
- package/server/lib/opencode/server-opencode-fetch.test.js +130 -0
- package/server/lib/opencode/server-utils-runtime.js +33 -0
- package/server/lib/opencode/shared-service.integration.test.js +66 -0
- package/server/lib/opencode/shared-service.js +147 -0
- package/server/lib/opencode/shared-service.test.js +93 -0
- package/server/lib/opencode/shared.js +3 -3
- package/server/lib/opencode/shutdown-runtime.js +15 -6
- package/server/lib/opencode/shutdown-runtime.test.js +49 -1
- package/server/lib/opencode/skill-routes.js +20 -33
- package/server/lib/opencode/skill-routes.test.js +35 -2
- package/server/lib/opencode/skills.test.js +15 -0
- package/server/lib/opencode/startup-pipeline-runtime.js +4 -0
- package/server/lib/opencode/static-routes-runtime.js +3 -1
- package/server/lib/opencode/static-routes-runtime.test.js +33 -0
- package/server/lib/opencode/v2-client.js +14 -3
- package/server/lib/opencode/v2-plugin-host-shim/index.mjs +155 -0
- package/server/lib/opencode/v2-plugin-host-shim/package.json +4 -0
- package/server/lib/permission-auto-accept/DOCUMENTATION.md +5 -5
- package/server/lib/permission-auto-accept/runtime.js +14 -7
- package/server/lib/permission-auto-accept/runtime.test.js +27 -12
- package/server/lib/relay/reasoning-projection.e2e.test.ts +22 -7
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +8 -0
- package/server/lib/scheduled-tasks/runtime.js +52 -4
- package/server/lib/scheduled-tasks/runtime.test.js +80 -1
- package/server/lib/session-goal/DOCUMENTATION.md +113 -13
- package/server/lib/session-goal/routes.js +9 -0
- package/server/lib/session-goal/runtime.js +1579 -117
- package/server/lib/session-goal/runtime.test.js +1453 -84
- package/server/lib/session-index/DOCUMENTATION.md +18 -15
- package/server/lib/session-index/event-ingest.js +89 -16
- package/server/lib/session-index/event-ingest.test.js +73 -0
- package/server/lib/session-index/host-authority-snapshot.js +92 -0
- package/server/lib/session-index/routes.host-archive.test.js +201 -0
- package/server/lib/session-index/routes.js +63 -10
- package/server/lib/session-index/routes.test.js +8 -8
- package/server/lib/session-index/service.js +7 -1
- package/server/lib/session-index/sync-runtime.js +161 -34
- package/server/lib/session-index/sync-runtime.test.js +155 -1
- package/server/lib/session-metadata/DOCUMENTATION.md +61 -16
- package/server/lib/session-metadata/routes.js +108 -9
- package/server/lib/session-metadata/routes.test.js +47 -2
- package/server/lib/session-metadata/session-archive.d.ts +73 -0
- package/server/lib/session-metadata/session-archive.js +654 -0
- package/server/lib/session-metadata/session-archive.test.js +359 -0
- package/server/lib/session-metadata/session-metadata-store.d.ts +36 -0
- package/server/lib/session-metadata/session-metadata-store.js +212 -72
- package/server/lib/session-metadata/session-metadata-store.test.js +205 -10
- package/server/lib/session-metadata/session-projection.d.ts +41 -0
- package/server/lib/session-metadata/session-projection.js +255 -0
- package/server/lib/session-metadata/session-projection.test.js +64 -0
- package/server/lib/session-metadata/system-session.js +55 -0
- package/server/lib/session-metadata/system-session.test.js +55 -0
- package/server/lib/session-title/DOCUMENTATION.md +40 -7
- package/server/lib/session-title/native-runtime.test.js +167 -0
- package/server/lib/session-title/runtime.js +67 -42
- package/server/lib/session-title/session-access.js +46 -0
- package/server/lib/session-title/session-access.test.js +91 -0
- package/server/lib/session-turn-pages/DOCUMENTATION.md +9 -8
- package/server/lib/session-turn-pages/routes.js +17 -102
- package/server/lib/session-turn-pages/routes.test.js +281 -0
- package/server/lib/session-turn-pages/session-message-projection.d.ts +13 -0
- package/server/lib/session-turn-pages/session-message-projection.js +281 -0
- package/server/lib/small-model/DOCUMENTATION.md +101 -147
- package/server/lib/small-model/catalog.js +31 -51
- package/server/lib/small-model/catalog.test.js +65 -10
- package/server/lib/small-model/custom-api.js +68 -0
- package/server/lib/small-model/custom-api.test.js +64 -0
- package/server/lib/small-model/index.js +124 -240
- package/server/lib/small-model/resolve.js +35 -120
- package/server/lib/small-model/resolve.test.js +20 -110
- package/server/lib/small-model/routes.js +1 -3
- package/server/lib/small-model/summary-settings.test.js +157 -253
- package/server/opencode-proxy.test.js +2 -0
- package/dist/assets/AssistantView-BTCkm8yk.js +0 -3
- package/dist/assets/MarkstreamRendererImpl-CnkodGJW.js +0 -3
- package/dist/assets/MobileSurface-BXLeiZ4d.js +0 -2
- package/dist/assets/OverlayScrollbar-pMwxaCca.js +0 -2
- package/dist/assets/SettingsView-B5I0KDTZ.js +0 -25
- package/dist/assets/appThemeRegistry-COGfxTFV.js +0 -1
- package/dist/assets/collapsible-BXRd5_Hr.js +0 -1
- package/dist/assets/context-menu-jGtH6fR9.js +0 -1
- package/dist/assets/es-c52LTHHe.js +0 -15
- package/dist/assets/fr-PisFbUE8.js +0 -13
- package/dist/assets/gitApi-ButwzQ0N.js +0 -9
- package/dist/assets/insertionBoundaries-DGs7S5zv.js +0 -1
- package/dist/assets/ja-C8Ikun3Z.js +0 -15
- package/dist/assets/ko-ClFys5o2.js +0 -15
- package/dist/assets/main-Dn9rpsgl.js +0 -169
- package/dist/assets/markdown-worker-CptoICmq.js +0 -2
- package/dist/assets/miniChat-BpjxVqgg.js +0 -2
- package/dist/assets/mobile-nMJCaNq1.js +0 -2
- package/dist/assets/multirun-BvSG94mW.js +0 -4
- package/dist/assets/pl-CnaKWN5F.js +0 -15
- package/dist/assets/platform-CWTIp02q.js +0 -4
- package/dist/assets/projectMeta-DOe49dM_.js +0 -3
- package/dist/assets/pt-BR-s8OpfRI6.js +0 -15
- package/dist/assets/renderElectronMiniChatApp-R6dKh79f.js +0 -2
- package/dist/assets/renderMobileApp-y-S8y8v_.js +0 -28
- package/dist/assets/runtime-fetch-zIalUnbb.js +0 -1
- package/dist/assets/runtimeEndpointReset-B6BxhvR0.js +0 -147
- package/dist/assets/sessionChangeSummary-VVBlEXuh.js +0 -2
- package/dist/assets/src-BzX5UI-c.css +0 -2
- package/dist/assets/store-DJczmczv.js +0 -15
- package/dist/assets/textarea-3XR8sUfy.js +0 -1
- package/dist/assets/uk-CaX0iqkB.js +0 -15
- package/dist/assets/useDesktopWindowControlsLayout-B1GX59-L.js +0 -1
- package/dist/assets/useEffectiveDirectory-CN6JoCFw.js +0 -1
- package/dist/assets/useMobileNavigationStore-BVjFtXSy.js +0 -414
- package/dist/assets/useSessionAutoCleanup-BLjymaFt.js +0 -2
- package/dist/assets/useUIStore-Bxv3f23A.js +0 -1
- package/dist/assets/zh-CN-20MYEjha.js +0 -15
- package/dist/assets/zh-TW-DiN04qTw.js +0 -15
- package/server/lib/small-model/call.js +0 -427
- package/server/lib/small-model/call.test.js +0 -382
- package/server/lib/small-model/opencode-session.js +0 -183
- package/server/lib/small-model/opencode-session.test.js +0 -147
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { applyNativePatch, convertAgentConfig, inspectAgentConfig, writeAgentDocument } from './agent-document.js';
|
|
4
|
+
|
|
5
|
+
describe('inspectAgentConfig', () => {
|
|
6
|
+
it('treats a native file as current', () => {
|
|
7
|
+
expect(inspectAgentConfig({
|
|
8
|
+
description: 'Reviewer',
|
|
9
|
+
mode: 'subagent',
|
|
10
|
+
model: 'openai/gpt-5#high',
|
|
11
|
+
hidden: true,
|
|
12
|
+
color: '#ff6b6b',
|
|
13
|
+
steps: 5,
|
|
14
|
+
permissions: [{ action: 'shell', resource: '*', effect: 'ask' }],
|
|
15
|
+
})).toEqual({ legacy: false, dropped: [] });
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('reports fields the next request does not use', () => {
|
|
19
|
+
const inspection = inspectAgentConfig({
|
|
20
|
+
temperature: 0.2,
|
|
21
|
+
top_p: 0.9,
|
|
22
|
+
options: { reasoningEffort: 'high' },
|
|
23
|
+
prompt: '{file:./prompt.md}',
|
|
24
|
+
color: 'red',
|
|
25
|
+
variant: 'high',
|
|
26
|
+
extra: true,
|
|
27
|
+
});
|
|
28
|
+
expect(inspection.legacy).toBe(true);
|
|
29
|
+
expect(inspection.dropped).toEqual([
|
|
30
|
+
{ key: 'temperature', reason: 'generation' },
|
|
31
|
+
{ key: 'top_p', reason: 'generation' },
|
|
32
|
+
{ key: 'options', reason: 'unknown' },
|
|
33
|
+
{ key: 'prompt', reason: 'prompt-file' },
|
|
34
|
+
{ key: 'color', reason: 'color' },
|
|
35
|
+
{ key: 'variant', reason: 'variant' },
|
|
36
|
+
{ key: 'extra', reason: 'unknown' },
|
|
37
|
+
]);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('convertAgentConfig', () => {
|
|
42
|
+
it('folds a legacy agent into native markdown fields', () => {
|
|
43
|
+
const converted = convertAgentConfig({
|
|
44
|
+
description: 'Reviewer',
|
|
45
|
+
mode: 'subagent',
|
|
46
|
+
model: 'openai/gpt-5',
|
|
47
|
+
variant: 'high',
|
|
48
|
+
temperature: 0.2,
|
|
49
|
+
prompt: 'Be careful.',
|
|
50
|
+
permission: { bash: 'ask', task: 'allow', write: 'deny' },
|
|
51
|
+
tools: { write: false },
|
|
52
|
+
maxSteps: 4,
|
|
53
|
+
disable: true,
|
|
54
|
+
color: '#112233',
|
|
55
|
+
request: { body: { temperature: 0.2 } },
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
expect(converted.legacy).toBe(true);
|
|
59
|
+
expect(converted.body).toBe('Be careful.');
|
|
60
|
+
expect(converted.frontmatter).toMatchObject({
|
|
61
|
+
description: 'Reviewer',
|
|
62
|
+
mode: 'subagent',
|
|
63
|
+
model: 'openai/gpt-5#high',
|
|
64
|
+
steps: 4,
|
|
65
|
+
disabled: true,
|
|
66
|
+
color: '#112233',
|
|
67
|
+
request: { body: { temperature: 0.2 } },
|
|
68
|
+
});
|
|
69
|
+
expect(converted.frontmatter).not.toHaveProperty('temperature');
|
|
70
|
+
expect(converted.frontmatter).not.toHaveProperty('hidden');
|
|
71
|
+
expect(converted.frontmatter.permissions).toEqual(expect.arrayContaining([
|
|
72
|
+
{ action: 'shell', resource: '*', effect: 'ask' },
|
|
73
|
+
{ action: 'subagent', resource: '*', effect: 'allow' },
|
|
74
|
+
{ action: 'edit', resource: '*', effect: 'deny' },
|
|
75
|
+
]));
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('applyNativePatch', () => {
|
|
80
|
+
it('patches only the keys present in the update', () => {
|
|
81
|
+
const next = applyNativePatch({
|
|
82
|
+
frontmatter: {
|
|
83
|
+
model: 'openai/gpt-5',
|
|
84
|
+
hidden: true,
|
|
85
|
+
permissions: [{ action: 'read', resource: '*', effect: 'allow' }],
|
|
86
|
+
variant: 'high',
|
|
87
|
+
temperature: 1,
|
|
88
|
+
},
|
|
89
|
+
body: 'old',
|
|
90
|
+
}, {
|
|
91
|
+
model: null,
|
|
92
|
+
hidden: false,
|
|
93
|
+
permissions: [],
|
|
94
|
+
system: null,
|
|
95
|
+
steps: 0,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
expect(next.body).toBe('');
|
|
99
|
+
expect(next.frontmatter).toEqual({
|
|
100
|
+
temperature: 1,
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('writeAgentDocument', () => {
|
|
106
|
+
it('leaves unmentioned fields alone on a prompt-only patch', () => {
|
|
107
|
+
const next = writeAgentDocument({
|
|
108
|
+
frontmatter: {
|
|
109
|
+
temperature: 1,
|
|
110
|
+
permission: { bash: 'allow' },
|
|
111
|
+
},
|
|
112
|
+
body: 'legacy prompt',
|
|
113
|
+
}, {
|
|
114
|
+
system: 'Only the prompt changed.',
|
|
115
|
+
}, false);
|
|
116
|
+
|
|
117
|
+
expect(next.body).toBe('Only the prompt changed.');
|
|
118
|
+
expect(next.frontmatter.temperature).toBe(1);
|
|
119
|
+
expect(next.frontmatter.permission).toEqual({ bash: 'allow' });
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('drops legacy fields when confirmDrop is true', () => {
|
|
123
|
+
const next = writeAgentDocument({
|
|
124
|
+
frontmatter: {
|
|
125
|
+
temperature: 1,
|
|
126
|
+
permission: { bash: 'allow' },
|
|
127
|
+
},
|
|
128
|
+
body: 'legacy prompt',
|
|
129
|
+
}, {
|
|
130
|
+
system: 'Only the prompt changed.',
|
|
131
|
+
}, true);
|
|
132
|
+
|
|
133
|
+
expect(next.body).toBe('Only the prompt changed.');
|
|
134
|
+
expect(next.frontmatter.temperature).toBeUndefined();
|
|
135
|
+
expect(next.frontmatter.permission).toEqual({ bash: 'allow' });
|
|
136
|
+
});
|
|
137
|
+
});
|
|
@@ -16,6 +16,10 @@ import {
|
|
|
16
16
|
resolvePromptFilePath,
|
|
17
17
|
writePromptFile,
|
|
18
18
|
} from './shared.js';
|
|
19
|
+
import {
|
|
20
|
+
inspectAgentConfig,
|
|
21
|
+
writeAgentDocument,
|
|
22
|
+
} from './agent-document.js';
|
|
19
23
|
|
|
20
24
|
// ============== AGENT SCOPE HELPERS ==============
|
|
21
25
|
|
|
@@ -321,21 +325,100 @@ function getAgentSources(agentName, workingDirectory, lookupCache = createAgentL
|
|
|
321
325
|
}
|
|
322
326
|
};
|
|
323
327
|
|
|
328
|
+
const stored = {};
|
|
329
|
+
if (jsonSection && typeof jsonSection === 'object') {
|
|
330
|
+
Object.assign(stored, jsonSection);
|
|
331
|
+
}
|
|
324
332
|
if (mdExists) {
|
|
325
333
|
const { frontmatter, body } = parseMdFile(mdPath);
|
|
326
334
|
sources.md.fields = Object.keys(frontmatter);
|
|
327
335
|
if (body) {
|
|
328
336
|
sources.md.fields.push('prompt');
|
|
329
337
|
}
|
|
338
|
+
Object.assign(stored, frontmatter);
|
|
339
|
+
if (typeof body === 'string' && body.trim()) stored.prompt = body.trim();
|
|
330
340
|
}
|
|
331
341
|
|
|
332
342
|
if (jsonSection) {
|
|
333
343
|
sources.json.fields = Object.keys(jsonSection);
|
|
334
344
|
}
|
|
345
|
+
sources.document = inspectAgentConfig(stored);
|
|
335
346
|
|
|
336
347
|
return sources;
|
|
337
348
|
}
|
|
338
349
|
|
|
350
|
+
function listDisabledAgentOverrides(workingDirectory) {
|
|
351
|
+
/** @type {Array<{ name: string, scope: string, description?: string, mode?: string }>} */
|
|
352
|
+
const found = [];
|
|
353
|
+
const visit = (directory, scope) => {
|
|
354
|
+
if (!directory || !fs.existsSync(directory)) return;
|
|
355
|
+
const walk = (current, prefix) => {
|
|
356
|
+
let entries = [];
|
|
357
|
+
try {
|
|
358
|
+
entries = fs.readdirSync(current, { withFileTypes: true });
|
|
359
|
+
} catch {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
for (const entry of entries) {
|
|
363
|
+
if (found.length >= 200) return;
|
|
364
|
+
const full = path.join(current, entry.name);
|
|
365
|
+
if (entry.isDirectory()) {
|
|
366
|
+
walk(full, prefix ? `${prefix}/${entry.name}` : entry.name);
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
|
|
370
|
+
const base = entry.name.slice(0, -3);
|
|
371
|
+
const name = prefix ? `${prefix}/${base}` : base;
|
|
372
|
+
let frontmatter = {};
|
|
373
|
+
try {
|
|
374
|
+
frontmatter = parseMdFile(full).frontmatter || {};
|
|
375
|
+
} catch {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if (frontmatter.disabled !== true && frontmatter.disable !== true) continue;
|
|
379
|
+
found.push({
|
|
380
|
+
name,
|
|
381
|
+
scope,
|
|
382
|
+
...(typeof frontmatter.description === 'string' ? { description: frontmatter.description } : {}),
|
|
383
|
+
...(frontmatter.mode === 'primary' || frontmatter.mode === 'subagent' || frontmatter.mode === 'all'
|
|
384
|
+
? { mode: frontmatter.mode }
|
|
385
|
+
: {}),
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
walk(directory, '');
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
visit(AGENT_DIR, AGENT_SCOPE.USER);
|
|
393
|
+
if (workingDirectory) {
|
|
394
|
+
visit(path.join(workingDirectory, '.opencode', 'agents'), AGENT_SCOPE.PROJECT);
|
|
395
|
+
visit(path.join(workingDirectory, '.opencode', 'agent'), AGENT_SCOPE.PROJECT);
|
|
396
|
+
}
|
|
397
|
+
return found;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function nativeWritePath(agentName, workingDirectory, scope, lookupCache) {
|
|
401
|
+
if (scope === AGENT_SCOPE.PROJECT && workingDirectory) {
|
|
402
|
+
ensureProjectAgentDir(workingDirectory);
|
|
403
|
+
return getProjectAgentPath(workingDirectory, agentName);
|
|
404
|
+
}
|
|
405
|
+
if (scope === AGENT_SCOPE.USER) {
|
|
406
|
+
return getUserAgentPath(agentName, lookupCache);
|
|
407
|
+
}
|
|
408
|
+
const existing = getAgentWritePath(agentName, workingDirectory, undefined, lookupCache);
|
|
409
|
+
if (existing.path && fs.existsSync(existing.path)) return existing.path;
|
|
410
|
+
return getUserAgentPath(agentName, lookupCache);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function writeNativeAgent(agentName, patch, workingDirectory, scope, confirmDrop) {
|
|
414
|
+
ensureDirs();
|
|
415
|
+
const lookupCache = createAgentLookupCache();
|
|
416
|
+
const targetPath = nativeWritePath(agentName, workingDirectory, scope, lookupCache);
|
|
417
|
+
const existing = fs.existsSync(targetPath) ? parseMdFile(targetPath) : { frontmatter: {}, body: '' };
|
|
418
|
+
const next = writeAgentDocument(existing, patch && typeof patch === 'object' ? patch : {}, confirmDrop === true);
|
|
419
|
+
writeMdFile(targetPath, next.frontmatter, next.body);
|
|
420
|
+
}
|
|
421
|
+
|
|
339
422
|
function getAgentConfig(agentName, workingDirectory, lookupCache = createAgentLookupCache()) {
|
|
340
423
|
const projectPath = workingDirectory ? getProjectAgentPath(workingDirectory, agentName) : null;
|
|
341
424
|
const projectExists = projectPath && fs.existsSync(projectPath);
|
|
@@ -409,6 +492,12 @@ function createAgent(agentName, config, workingDirectory, scope) {
|
|
|
409
492
|
targetScope = AGENT_SCOPE.USER;
|
|
410
493
|
}
|
|
411
494
|
|
|
495
|
+
if (config && Object.prototype.hasOwnProperty.call(config, 'native')) {
|
|
496
|
+
writeNativeAgent(agentName, config.native, workingDirectory, targetScope, config.confirmDrop === true);
|
|
497
|
+
console.log(`Created new agent: ${agentName} (scope: ${targetScope})`);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
|
|
412
501
|
const { prompt, scope: _scopeFromConfig, ...rawFrontmatter } = config;
|
|
413
502
|
const frontmatter = Object.fromEntries(
|
|
414
503
|
Object.entries(rawFrontmatter).filter(([, value]) => value !== null && value !== undefined)
|
|
@@ -419,6 +508,12 @@ function createAgent(agentName, config, workingDirectory, scope) {
|
|
|
419
508
|
}
|
|
420
509
|
|
|
421
510
|
function updateAgent(agentName, updates, workingDirectory) {
|
|
511
|
+
if (updates && Object.prototype.hasOwnProperty.call(updates, 'native')) {
|
|
512
|
+
writeNativeAgent(agentName, updates.native, workingDirectory, updates.scope, updates.confirmDrop === true);
|
|
513
|
+
console.log(`Updated agent: ${agentName}`);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
|
|
422
517
|
ensureDirs();
|
|
423
518
|
const lookupCache = createAgentLookupCache();
|
|
424
519
|
|
|
@@ -693,6 +788,7 @@ function deleteAgent(agentName, workingDirectory, scope) {
|
|
|
693
788
|
export {
|
|
694
789
|
getAgentSources,
|
|
695
790
|
getAgentConfig,
|
|
791
|
+
listDisabledAgentOverrides,
|
|
696
792
|
createAgent,
|
|
697
793
|
updateAgent,
|
|
698
794
|
deleteAgent,
|
|
@@ -81,9 +81,14 @@ export const createOpenCodeAuthStateRuntime = (dependencies) => {
|
|
|
81
81
|
return generatedPassword;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
// A server OpenChamber does not own (the shared official service) keeps its
|
|
85
|
+
// own password; adopt it instead of generating one.
|
|
86
|
+
const adoptOpenCodeServerPassword = (password, source) => setOpenCodeAuthState(password, source);
|
|
87
|
+
|
|
84
88
|
return {
|
|
85
89
|
getOpenCodeAuthHeaders,
|
|
86
90
|
isOpenCodeConnectionSecure,
|
|
87
91
|
ensureLocalOpenCodeServerPassword,
|
|
92
|
+
adoptOpenCodeServerPassword,
|
|
88
93
|
};
|
|
89
94
|
};
|
|
@@ -64,6 +64,7 @@ export const createBootstrapRuntime = (dependencies) => {
|
|
|
64
64
|
setAutoAcceptSession,
|
|
65
65
|
sessionIndexService,
|
|
66
66
|
sessionIndexSyncRuntime,
|
|
67
|
+
getCommittedHostMetadata = null,
|
|
67
68
|
transcriptCacheService,
|
|
68
69
|
} = options;
|
|
69
70
|
|
|
@@ -156,6 +157,7 @@ export const createBootstrapRuntime = (dependencies) => {
|
|
|
156
157
|
getCachedZenModels,
|
|
157
158
|
sessionIndexService,
|
|
158
159
|
sessionIndexSyncRuntime,
|
|
160
|
+
getCommittedHostMetadata,
|
|
159
161
|
transcriptCacheService,
|
|
160
162
|
express,
|
|
161
163
|
});
|
|
@@ -14,9 +14,11 @@ const composeV2ProviderCatalogSource = (providers, models, defaultModel) => {
|
|
|
14
14
|
for (const model of models) {
|
|
15
15
|
if (!model || typeof model !== 'object') continue;
|
|
16
16
|
const providerID = typeof model.providerID === 'string' ? model.providerID : '';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
// ModelInfo.id is the external model id used in generate/session refs.
|
|
18
|
+
// ModelInfo.modelID is a separate internal field and must not be preferred.
|
|
19
|
+
const modelID = typeof model.id === 'string' && model.id
|
|
20
|
+
? model.id
|
|
21
|
+
: (typeof model.modelID === 'string' ? model.modelID : '');
|
|
20
22
|
if (!providerID || !modelID) continue;
|
|
21
23
|
if (!modelsByProvider.has(providerID)) modelsByProvider.set(providerID, Object.create(null));
|
|
22
24
|
const entry = { id: modelID };
|
|
@@ -24,10 +26,9 @@ const composeV2ProviderCatalogSource = (providers, models, defaultModel) => {
|
|
|
24
26
|
if (typeof model.family === 'string' && model.family) entry.family = model.family;
|
|
25
27
|
if (model.limit && typeof model.limit === 'object') entry.limit = model.limit;
|
|
26
28
|
if (model.capabilities) entry.capabilities = model.capabilities;
|
|
27
|
-
|
|
28
|
-
if (model.
|
|
29
|
-
|
|
30
|
-
}
|
|
29
|
+
// v2 cost is a tier array; v2 variants are `{ id }[]`. Projection owns the safe shape.
|
|
30
|
+
if (model.cost && typeof model.cost === 'object') entry.cost = model.cost;
|
|
31
|
+
if (model.variants && typeof model.variants === 'object') entry.variants = model.variants;
|
|
31
32
|
if (typeof model.time?.released === 'number' && Number.isFinite(model.time.released)) {
|
|
32
33
|
entry.release_date = new Date(model.time.released).toISOString().slice(0, 10);
|
|
33
34
|
}
|
|
@@ -45,8 +46,11 @@ const composeV2ProviderCatalogSource = (providers, models, defaultModel) => {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
const defaults = Object.create(null);
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
const defaultModelID = typeof defaultModel?.id === 'string' && defaultModel.id
|
|
50
|
+
? defaultModel.id
|
|
51
|
+
: (typeof defaultModel?.modelID === 'string' ? defaultModel.modelID : '');
|
|
52
|
+
if (defaultModel && typeof defaultModel.providerID === 'string' && defaultModelID) {
|
|
53
|
+
defaults[defaultModel.providerID] = defaultModelID;
|
|
50
54
|
}
|
|
51
55
|
return { providers: list, default: defaults };
|
|
52
56
|
};
|
|
@@ -130,11 +134,10 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
130
134
|
const {
|
|
131
135
|
resolveProjectDirectory,
|
|
132
136
|
resolveOptionalProjectDirectory,
|
|
133
|
-
refreshOpenCodeAfterConfigChange,
|
|
134
|
-
clientReloadDelayMs,
|
|
135
137
|
waitForOpenCodeReady,
|
|
136
138
|
getAgentSources,
|
|
137
139
|
getAgentConfig,
|
|
140
|
+
listDisabledAgentOverrides,
|
|
138
141
|
createAgent,
|
|
139
142
|
updateAgent,
|
|
140
143
|
deleteAgent,
|
|
@@ -259,7 +262,8 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
259
262
|
target: req.params.target,
|
|
260
263
|
fileName: target.fileName,
|
|
261
264
|
content,
|
|
262
|
-
requiresManualRestart:
|
|
265
|
+
requiresManualRestart: req.params.target !== 'opencode',
|
|
266
|
+
application: req.params.target === 'opencode' ? 'watch' : 'manual',
|
|
263
267
|
});
|
|
264
268
|
} catch (error) {
|
|
265
269
|
console.error('Failed to write global configuration:', error);
|
|
@@ -267,29 +271,9 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
267
271
|
}
|
|
268
272
|
});
|
|
269
273
|
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
|
|
273
|
-
// server will not serve it until the user restarts that server. We must not
|
|
274
|
-
// report a clean "reloading" success in that case, otherwise the UI silently
|
|
275
|
-
// reverts the edit to the stale value on the next refresh.
|
|
276
|
-
const buildConfigMutationResponse = (refreshResult, { liveMessage, manualRestartMessage }) => {
|
|
277
|
-
if (refreshResult && refreshResult.external) {
|
|
278
|
-
return {
|
|
279
|
-
success: true,
|
|
280
|
-
requiresReload: false,
|
|
281
|
-
requiresManualRestart: true,
|
|
282
|
-
message: manualRestartMessage,
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return {
|
|
287
|
-
success: true,
|
|
288
|
-
requiresReload: true,
|
|
289
|
-
message: liveMessage,
|
|
290
|
-
reloadDelayMs: clientReloadDelayMs,
|
|
291
|
-
};
|
|
292
|
-
};
|
|
274
|
+
// A receipt confirms persistence, not runtime activation. V2 watches local
|
|
275
|
+
// configuration; domain events confirm changes without rebuilding locations.
|
|
276
|
+
const configSaved = () => ({ success: true, requiresReload: false, application: 'watch' });
|
|
293
277
|
|
|
294
278
|
const readMutationBody = (req) => (
|
|
295
279
|
req.body && typeof req.body === 'object' && !Array.isArray(req.body) ? req.body : {}
|
|
@@ -298,24 +282,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
298
282
|
const completeMcpMutation = async (res, action, name, applyChange) => {
|
|
299
283
|
applyChange();
|
|
300
284
|
|
|
301
|
-
|
|
302
|
-
await refreshOpenCodeAfterConfigChange(`mcp ${action}`);
|
|
303
|
-
return res.json({
|
|
304
|
-
success: true,
|
|
305
|
-
requiresReload: true,
|
|
306
|
-
message: `MCP server "${name}" ${action}d. Reloading interface…`,
|
|
307
|
-
reloadDelayMs: clientReloadDelayMs,
|
|
308
|
-
});
|
|
309
|
-
} catch (error) {
|
|
310
|
-
console.error(`[API:MCP ${action}] Reload failed after config write:`, error);
|
|
311
|
-
return res.json({
|
|
312
|
-
success: true,
|
|
313
|
-
requiresReload: false,
|
|
314
|
-
reloadFailed: true,
|
|
315
|
-
message: `MCP server "${name}" ${action}d, but OpenCode reload failed.`,
|
|
316
|
-
warning: error.message || 'OpenCode reload failed after the MCP configuration changed',
|
|
317
|
-
});
|
|
318
|
-
}
|
|
285
|
+
return res.json({ ...configSaved(), message: `MCP server "${name}" ${action}d.` });
|
|
319
286
|
};
|
|
320
287
|
|
|
321
288
|
app.post('/api/config/agents/metadata', async (req, res) => {
|
|
@@ -345,7 +312,10 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
345
312
|
sources,
|
|
346
313
|
};
|
|
347
314
|
}
|
|
348
|
-
|
|
315
|
+
const disabled = typeof listDisabledAgentOverrides === 'function'
|
|
316
|
+
? listDisabledAgentOverrides(directory)
|
|
317
|
+
: [];
|
|
318
|
+
return res.json(disabled.length > 0 ? { agents, disabled } : { agents });
|
|
349
319
|
} catch (error) {
|
|
350
320
|
console.error('Failed to get agent metadata batch:', error);
|
|
351
321
|
return res.status(500).json({ error: 'Failed to get agent configuration metadata' });
|
|
@@ -405,15 +375,11 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
405
375
|
console.log('[Server] Creating agent');
|
|
406
376
|
|
|
407
377
|
createAgent(agentName, config, directory, scope);
|
|
408
|
-
|
|
409
|
-
agentName
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
res.json(buildConfigMutationResponse(refreshResult, {
|
|
413
|
-
liveMessage: `Agent ${agentName} created successfully. Reloading interface…`,
|
|
414
|
-
manualRestartMessage: `Agent ${agentName} saved. Restart your connected OpenCode server to apply the change.`,
|
|
415
|
-
}));
|
|
378
|
+
res.json(configSaved());
|
|
416
379
|
} catch (error) {
|
|
380
|
+
if (error?.code === 'drop-confirmation') {
|
|
381
|
+
return res.status(409).json({ code: 'drop-confirmation', dropped: error.dropped, error: error.message });
|
|
382
|
+
}
|
|
417
383
|
console.error('Failed to create agent');
|
|
418
384
|
res.status(500).json({ error: error.message || 'Failed to create agent' });
|
|
419
385
|
}
|
|
@@ -431,15 +397,14 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
431
397
|
console.log('[Server] Updating agent');
|
|
432
398
|
|
|
433
399
|
updateAgent(agentName, updates, directory);
|
|
434
|
-
const refreshResult = await refreshOpenCodeAfterConfigChange('agent update');
|
|
435
400
|
|
|
436
401
|
console.log('[Server] Agent updated successfully');
|
|
437
402
|
|
|
438
|
-
res.json(
|
|
439
|
-
liveMessage: `Agent ${agentName} updated successfully. Reloading interface…`,
|
|
440
|
-
manualRestartMessage: `Agent ${agentName} saved. Restart your connected OpenCode server to apply the change.`,
|
|
441
|
-
}));
|
|
403
|
+
res.json(configSaved());
|
|
442
404
|
} catch (error) {
|
|
405
|
+
if (error?.code === 'drop-confirmation') {
|
|
406
|
+
return res.status(409).json({ code: 'drop-confirmation', dropped: error.dropped, error: error.message });
|
|
407
|
+
}
|
|
443
408
|
console.error('[Server] Failed to update agent');
|
|
444
409
|
res.status(500).json({ error: error.message || 'Failed to update agent' });
|
|
445
410
|
}
|
|
@@ -455,12 +420,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
455
420
|
|
|
456
421
|
const scope = req.body?.scope;
|
|
457
422
|
deleteAgent(agentName, directory, scope);
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
res.json(buildConfigMutationResponse(refreshResult, {
|
|
461
|
-
liveMessage: `Agent ${agentName} deleted successfully. Reloading interface…`,
|
|
462
|
-
manualRestartMessage: `Agent ${agentName} deleted. Restart your connected OpenCode server to apply the change.`,
|
|
463
|
-
}));
|
|
423
|
+
res.json(configSaved());
|
|
464
424
|
} catch (error) {
|
|
465
425
|
console.error('Failed to delete agent');
|
|
466
426
|
res.status(500).json({ error: error.message || 'Failed to delete agent' });
|
|
@@ -571,7 +531,12 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
571
531
|
const client = createOpenCodeClient({
|
|
572
532
|
baseUrl: buildOpenCodeUrl('/', '').replace(/\/$/, ''),
|
|
573
533
|
headers: getOpenCodeAuthHeaders(),
|
|
574
|
-
fetch: (request) => fetch(request, {
|
|
534
|
+
fetch: (request, init) => fetch(request, {
|
|
535
|
+
...init,
|
|
536
|
+
signal: init?.signal
|
|
537
|
+
? AbortSignal.any([init.signal, AbortSignal.timeout(8_000)])
|
|
538
|
+
: AbortSignal.timeout(8_000),
|
|
539
|
+
}),
|
|
575
540
|
});
|
|
576
541
|
const response = await client.command.list({ location: { directory } });
|
|
577
542
|
if (!Array.isArray(response?.data)) {
|
|
@@ -669,16 +634,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
669
634
|
console.log('[Server] Creating command');
|
|
670
635
|
|
|
671
636
|
createCommand(commandName, config, directory, scope);
|
|
672
|
-
|
|
673
|
-
commandName
|
|
674
|
-
});
|
|
675
|
-
|
|
676
|
-
res.json({
|
|
677
|
-
success: true,
|
|
678
|
-
requiresReload: true,
|
|
679
|
-
message: `Command ${commandName} created successfully. Reloading interface…`,
|
|
680
|
-
reloadDelayMs: clientReloadDelayMs,
|
|
681
|
-
});
|
|
637
|
+
res.json(configSaved());
|
|
682
638
|
} catch (error) {
|
|
683
639
|
console.error('Failed to create command');
|
|
684
640
|
res.status(500).json({ error: error.message || 'Failed to create command' });
|
|
@@ -697,16 +653,10 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
697
653
|
console.log('[Server] Updating command');
|
|
698
654
|
|
|
699
655
|
updateCommand(commandName, updates, directory);
|
|
700
|
-
await refreshOpenCodeAfterConfigChange('command update');
|
|
701
656
|
|
|
702
657
|
console.log('[Server] Command updated successfully');
|
|
703
658
|
|
|
704
|
-
res.json(
|
|
705
|
-
success: true,
|
|
706
|
-
requiresReload: true,
|
|
707
|
-
message: `Command ${commandName} updated successfully. Reloading interface…`,
|
|
708
|
-
reloadDelayMs: clientReloadDelayMs,
|
|
709
|
-
});
|
|
659
|
+
res.json(configSaved());
|
|
710
660
|
} catch (error) {
|
|
711
661
|
console.error('[Server] Failed to update command');
|
|
712
662
|
res.status(500).json({ error: error.message || 'Failed to update command' });
|
|
@@ -722,14 +672,7 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
|
|
722
672
|
}
|
|
723
673
|
|
|
724
674
|
deleteCommand(commandName, directory);
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
res.json({
|
|
728
|
-
success: true,
|
|
729
|
-
requiresReload: true,
|
|
730
|
-
message: `Command ${commandName} deleted successfully. Reloading interface…`,
|
|
731
|
-
reloadDelayMs: clientReloadDelayMs,
|
|
732
|
-
});
|
|
675
|
+
res.json(configSaved());
|
|
733
676
|
} catch (error) {
|
|
734
677
|
console.error('Failed to delete command');
|
|
735
678
|
res.status(500).json({ error: error.message || 'Failed to delete command' });
|