dodo-mcp 1.0.0
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/LICENSE +21 -0
- package/README.md +425 -0
- package/dist/auth/adapter.js +43 -0
- package/dist/auth/adapter.js.map +1 -0
- package/dist/auth/clientDeletion.js +45 -0
- package/dist/auth/clientDeletion.js.map +1 -0
- package/dist/auth/clients.js +55 -0
- package/dist/auth/clients.js.map +1 -0
- package/dist/auth/constants.js +10 -0
- package/dist/auth/constants.js.map +1 -0
- package/dist/auth/interactions.js +184 -0
- package/dist/auth/interactions.js.map +1 -0
- package/dist/auth/keys.js +56 -0
- package/dist/auth/keys.js.map +1 -0
- package/dist/auth/provider.js +131 -0
- package/dist/auth/provider.js.map +1 -0
- package/dist/auth/verifier.js +74 -0
- package/dist/auth/verifier.js.map +1 -0
- package/dist/cli/kill.js +124 -0
- package/dist/cli/kill.js.map +1 -0
- package/dist/cli/main.js +1393 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/menu.js +127 -0
- package/dist/cli/menu.js.map +1 -0
- package/dist/cli/terminal.js +30 -0
- package/dist/cli/terminal.js.map +1 -0
- package/dist/config/globalConfig.js +144 -0
- package/dist/config/globalConfig.js.map +1 -0
- package/dist/config/limits.js +42 -0
- package/dist/config/limits.js.map +1 -0
- package/dist/config/paths.js +94 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/projectConfig.js +63 -0
- package/dist/config/projectConfig.js.map +1 -0
- package/dist/config/stateImport.js +306 -0
- package/dist/config/stateImport.js.map +1 -0
- package/dist/config/tunnelConfig.js +23 -0
- package/dist/config/tunnelConfig.js.map +1 -0
- package/dist/errors.js +82 -0
- package/dist/errors.js.map +1 -0
- package/dist/evaluation/contracts.js +86 -0
- package/dist/evaluation/contracts.js.map +1 -0
- package/dist/evaluation/dodoBench.js +69 -0
- package/dist/evaluation/dodoBench.js.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/ipc/authentication.js +117 -0
- package/dist/ipc/authentication.js.map +1 -0
- package/dist/ipc/client.js +86 -0
- package/dist/ipc/client.js.map +1 -0
- package/dist/ipc/installationClient.js +83 -0
- package/dist/ipc/installationClient.js.map +1 -0
- package/dist/ipc/ownerControl.js +46 -0
- package/dist/ipc/ownerControl.js.map +1 -0
- package/dist/ipc/protocol.js +2 -0
- package/dist/ipc/protocol.js.map +1 -0
- package/dist/ipc/server.js +108 -0
- package/dist/ipc/server.js.map +1 -0
- package/dist/platform/execResolve.js +64 -0
- package/dist/platform/execResolve.js.map +1 -0
- package/dist/platform/fileIdentity.js +26 -0
- package/dist/platform/fileIdentity.js.map +1 -0
- package/dist/platform/fsRetry.js +22 -0
- package/dist/platform/fsRetry.js.map +1 -0
- package/dist/platform/pathPolicy.js +29 -0
- package/dist/platform/pathPolicy.js.map +1 -0
- package/dist/platform/privateFs.js +116 -0
- package/dist/platform/privateFs.js.map +1 -0
- package/dist/platform/processTree.js +31 -0
- package/dist/platform/processTree.js.map +1 -0
- package/dist/platform/shell.js +74 -0
- package/dist/platform/shell.js.map +1 -0
- package/dist/platform/speech.js +94 -0
- package/dist/platform/speech.js.map +1 -0
- package/dist/platform/system.js +28 -0
- package/dist/platform/system.js.map +1 -0
- package/dist/platform/windowsSandbox.js +129 -0
- package/dist/platform/windowsSandbox.js.map +1 -0
- package/dist/projects/federation.js +312 -0
- package/dist/projects/federation.js.map +1 -0
- package/dist/projects/registry.js +291 -0
- package/dist/projects/registry.js.map +1 -0
- package/dist/security/accessMode.js +19 -0
- package/dist/security/accessMode.js.map +1 -0
- package/dist/security/approvals.js +56 -0
- package/dist/security/approvals.js.map +1 -0
- package/dist/security/env.js +57 -0
- package/dist/security/env.js.map +1 -0
- package/dist/security/mutationQueue.js +78 -0
- package/dist/security/mutationQueue.js.map +1 -0
- package/dist/security/policy.js +22 -0
- package/dist/security/policy.js.map +1 -0
- package/dist/security/projectAuthority.js +22 -0
- package/dist/security/projectAuthority.js.map +1 -0
- package/dist/security/redact.js +30 -0
- package/dist/security/redact.js.map +1 -0
- package/dist/server/aiAdmin.js +201 -0
- package/dist/server/aiAdmin.js.map +1 -0
- package/dist/server/appServer.js +461 -0
- package/dist/server/appServer.js.map +1 -0
- package/dist/server/bootstrap.js +185 -0
- package/dist/server/bootstrap.js.map +1 -0
- package/dist/server/configUi/app.css +347 -0
- package/dist/server/configUi/app.js +958 -0
- package/dist/server/configUi/index.html +379 -0
- package/dist/server/configUi/ui/alerts.js +92 -0
- package/dist/server/configUi/ui/dom.js +19 -0
- package/dist/server/configUi/ui/tooltips.js +115 -0
- package/dist/server/configUi/vendor/VERSION.txt +1 -0
- package/dist/server/configUi/vendor/sweetalert2.min.css +1 -0
- package/dist/server/configUi/vendor/sweetalert2.min.js +5 -0
- package/dist/server/configUi/workbench.css +62 -0
- package/dist/server/configUi/workbench.js +394 -0
- package/dist/server/installationRuntime.js +155 -0
- package/dist/server/installationRuntime.js.map +1 -0
- package/dist/server/instructions.js +17 -0
- package/dist/server/instructions.js.map +1 -0
- package/dist/server/ipcDispatch.js +225 -0
- package/dist/server/ipcDispatch.js.map +1 -0
- package/dist/server/localConfig.js +561 -0
- package/dist/server/localConfig.js.map +1 -0
- package/dist/server/optionalServices.js +30 -0
- package/dist/server/optionalServices.js.map +1 -0
- package/dist/server/projectLease.js +46 -0
- package/dist/server/projectLease.js.map +1 -0
- package/dist/server/stdioServer.js +75 -0
- package/dist/server/stdioServer.js.map +1 -0
- package/dist/server/version.js +13 -0
- package/dist/server/version.js.map +1 -0
- package/dist/server/workspaceHost.js +194 -0
- package/dist/server/workspaceHost.js.map +1 -0
- package/dist/services/agent/agentService.js +598 -0
- package/dist/services/agent/agentService.js.map +1 -0
- package/dist/services/agent/contracts.js +102 -0
- package/dist/services/agent/contracts.js.map +1 -0
- package/dist/services/ai/adapters.js +287 -0
- package/dist/services/ai/adapters.js.map +1 -0
- package/dist/services/ai/contracts.js +39 -0
- package/dist/services/ai/contracts.js.map +1 -0
- package/dist/services/ai/credentials.js +77 -0
- package/dist/services/ai/credentials.js.map +1 -0
- package/dist/services/ai/network.js +113 -0
- package/dist/services/ai/network.js.map +1 -0
- package/dist/services/ai/settings.js +178 -0
- package/dist/services/ai/settings.js.map +1 -0
- package/dist/services/ai/subagents.js +468 -0
- package/dist/services/ai/subagents.js.map +1 -0
- package/dist/services/assistance/analysis.js +352 -0
- package/dist/services/assistance/analysis.js.map +1 -0
- package/dist/services/assistance/contracts.js +54 -0
- package/dist/services/assistance/contracts.js.map +1 -0
- package/dist/services/assistance/verification.js +274 -0
- package/dist/services/assistance/verification.js.map +1 -0
- package/dist/services/brain/brainParser.js +97 -0
- package/dist/services/brain/brainParser.js.map +1 -0
- package/dist/services/brain/brainService.js +733 -0
- package/dist/services/brain/brainService.js.map +1 -0
- package/dist/services/brain/brainWorker.js +212 -0
- package/dist/services/brain/brainWorker.js.map +1 -0
- package/dist/services/brain/contracts.js +154 -0
- package/dist/services/brain/contracts.js.map +1 -0
- package/dist/services/brain/protocol.js +2 -0
- package/dist/services/brain/protocol.js.map +1 -0
- package/dist/services/changes/applier.js +544 -0
- package/dist/services/changes/applier.js.map +1 -0
- package/dist/services/changes/contentBudget.js +11 -0
- package/dist/services/changes/contentBudget.js.map +1 -0
- package/dist/services/changes/planner.js +284 -0
- package/dist/services/changes/planner.js.map +1 -0
- package/dist/services/changes/types.js +3 -0
- package/dist/services/changes/types.js.map +1 -0
- package/dist/services/context/contextEngine.js +746 -0
- package/dist/services/context/contextEngine.js.map +1 -0
- package/dist/services/context/contracts.js +88 -0
- package/dist/services/context/contracts.js.map +1 -0
- package/dist/services/desktop/desktopPolicy.js +76 -0
- package/dist/services/desktop/desktopPolicy.js.map +1 -0
- package/dist/services/desktop/desktopService.js +130 -0
- package/dist/services/desktop/desktopService.js.map +1 -0
- package/dist/services/desktop/nativeBackend.js +174 -0
- package/dist/services/desktop/nativeBackend.js.map +1 -0
- package/dist/services/desktop/protocol.js +32 -0
- package/dist/services/desktop/protocol.js.map +1 -0
- package/dist/services/files/readService.js +136 -0
- package/dist/services/files/readService.js.map +1 -0
- package/dist/services/git/gitService.js +369 -0
- package/dist/services/git/gitService.js.map +1 -0
- package/dist/services/intelligence/intelService.js +136 -0
- package/dist/services/intelligence/intelService.js.map +1 -0
- package/dist/services/intelligence/protocol.js +2 -0
- package/dist/services/intelligence/protocol.js.map +1 -0
- package/dist/services/intelligence/tsWorker.js +419 -0
- package/dist/services/intelligence/tsWorker.js.map +1 -0
- package/dist/services/jobs/commandInput.js +34 -0
- package/dist/services/jobs/commandInput.js.map +1 -0
- package/dist/services/jobs/jobManager.js +398 -0
- package/dist/services/jobs/jobManager.js.map +1 -0
- package/dist/services/jobs/sandbox.js +156 -0
- package/dist/services/jobs/sandbox.js.map +1 -0
- package/dist/services/jobs/sandboxWiring.js +37 -0
- package/dist/services/jobs/sandboxWiring.js.map +1 -0
- package/dist/services/jobs/spool.js +112 -0
- package/dist/services/jobs/spool.js.map +1 -0
- package/dist/services/jobs/windowsSandboxChild.js +24 -0
- package/dist/services/jobs/windowsSandboxChild.js.map +1 -0
- package/dist/services/jobs/windowsSandboxWorker.js +155 -0
- package/dist/services/jobs/windowsSandboxWorker.js.map +1 -0
- package/dist/services/lsp/documentUri.js +16 -0
- package/dist/services/lsp/documentUri.js.map +1 -0
- package/dist/services/lsp/jsonrpc.js +382 -0
- package/dist/services/lsp/jsonrpc.js.map +1 -0
- package/dist/services/lsp/lspService.js +1051 -0
- package/dist/services/lsp/lspService.js.map +1 -0
- package/dist/services/memory/contracts.js +94 -0
- package/dist/services/memory/contracts.js.map +1 -0
- package/dist/services/memory/memoryService.js +683 -0
- package/dist/services/memory/memoryService.js.map +1 -0
- package/dist/services/multimodal/browserService.js +407 -0
- package/dist/services/multimodal/browserService.js.map +1 -0
- package/dist/services/multimodal/byteRange.js +31 -0
- package/dist/services/multimodal/byteRange.js.map +1 -0
- package/dist/services/multimodal/contracts.js +59 -0
- package/dist/services/multimodal/contracts.js.map +1 -0
- package/dist/services/multimodal/gameService.js +95 -0
- package/dist/services/multimodal/gameService.js.map +1 -0
- package/dist/services/multimodal/images.js +107 -0
- package/dist/services/multimodal/images.js.map +1 -0
- package/dist/services/multimodal/mediaService.js +279 -0
- package/dist/services/multimodal/mediaService.js.map +1 -0
- package/dist/services/multimodal/mediaWorker.js +143 -0
- package/dist/services/multimodal/mediaWorker.js.map +1 -0
- package/dist/services/multimodal/multimodalService.js +51 -0
- package/dist/services/multimodal/multimodalService.js.map +1 -0
- package/dist/services/multimodal/network.js +69 -0
- package/dist/services/multimodal/network.js.map +1 -0
- package/dist/services/multimodal/operations.js +40 -0
- package/dist/services/multimodal/operations.js.map +1 -0
- package/dist/services/multimodal/storage.js +160 -0
- package/dist/services/multimodal/storage.js.map +1 -0
- package/dist/services/multimodal/workflowService.js +179 -0
- package/dist/services/multimodal/workflowService.js.map +1 -0
- package/dist/services/overview.js +284 -0
- package/dist/services/overview.js.map +1 -0
- package/dist/services/resources/casStore.js +304 -0
- package/dist/services/resources/casStore.js.map +1 -0
- package/dist/services/resources/contracts.js +75 -0
- package/dist/services/resources/contracts.js.map +1 -0
- package/dist/services/resources/mime.js +77 -0
- package/dist/services/resources/mime.js.map +1 -0
- package/dist/services/resources/providerRegistry.js +22 -0
- package/dist/services/resources/providerRegistry.js.map +1 -0
- package/dist/services/resources/providers.js +120 -0
- package/dist/services/resources/providers.js.map +1 -0
- package/dist/services/resources/resourceService.js +282 -0
- package/dist/services/resources/resourceService.js.map +1 -0
- package/dist/services/runtime/contracts.js +65 -0
- package/dist/services/runtime/contracts.js.map +1 -0
- package/dist/services/runtime/runtimeService.js +364 -0
- package/dist/services/runtime/runtimeService.js.map +1 -0
- package/dist/services/schedules/scheduleService.js +198 -0
- package/dist/services/schedules/scheduleService.js.map +1 -0
- package/dist/services/search/searchService.js +434 -0
- package/dist/services/search/searchService.js.map +1 -0
- package/dist/services/search/searchWorker.js +58 -0
- package/dist/services/search/searchWorker.js.map +1 -0
- package/dist/setup/componentProbes.js +259 -0
- package/dist/setup/componentProbes.js.map +1 -0
- package/dist/setup/download.js +139 -0
- package/dist/setup/download.js.map +1 -0
- package/dist/setup/managedTools.js +118 -0
- package/dist/setup/managedTools.js.map +1 -0
- package/dist/setup/sandboxProbe.js +172 -0
- package/dist/setup/sandboxProbe.js.map +1 -0
- package/dist/setup/setup.js +522 -0
- package/dist/setup/setup.js.map +1 -0
- package/dist/setup/windowsChromiumAcl.js +56 -0
- package/dist/setup/windowsChromiumAcl.js.map +1 -0
- package/dist/setup/windowsSandboxInstall.js +94 -0
- package/dist/setup/windowsSandboxInstall.js.map +1 -0
- package/dist/setup/windowsSpeechInstall.js +86 -0
- package/dist/setup/windowsSpeechInstall.js.map +1 -0
- package/dist/store/db.js +711 -0
- package/dist/store/db.js.map +1 -0
- package/dist/store/scopeEncoding.js +15 -0
- package/dist/store/scopeEncoding.js.map +1 -0
- package/dist/store/store.js +467 -0
- package/dist/store/store.js.map +1 -0
- package/dist/tools/agentRuntimeTools.js +216 -0
- package/dist/tools/agentRuntimeTools.js.map +1 -0
- package/dist/tools/agentTools.js +317 -0
- package/dist/tools/agentTools.js.map +1 -0
- package/dist/tools/assistanceTools.js +126 -0
- package/dist/tools/assistanceTools.js.map +1 -0
- package/dist/tools/brainTools.js +130 -0
- package/dist/tools/brainTools.js.map +1 -0
- package/dist/tools/catalog.js +30 -0
- package/dist/tools/catalog.js.map +1 -0
- package/dist/tools/changeTools.js +188 -0
- package/dist/tools/changeTools.js.map +1 -0
- package/dist/tools/context.js +243 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/contextTools.js +57 -0
- package/dist/tools/contextTools.js.map +1 -0
- package/dist/tools/coreCatalog.js +82 -0
- package/dist/tools/coreCatalog.js.map +1 -0
- package/dist/tools/desktopTools.js +41 -0
- package/dist/tools/desktopTools.js.map +1 -0
- package/dist/tools/directTools.js +273 -0
- package/dist/tools/directTools.js.map +1 -0
- package/dist/tools/envelope.js +71 -0
- package/dist/tools/envelope.js.map +1 -0
- package/dist/tools/extraTools.js +298 -0
- package/dist/tools/extraTools.js.map +1 -0
- package/dist/tools/gitTools.js +93 -0
- package/dist/tools/gitTools.js.map +1 -0
- package/dist/tools/jobTools.js +454 -0
- package/dist/tools/jobTools.js.map +1 -0
- package/dist/tools/memoryTools.js +102 -0
- package/dist/tools/memoryTools.js.map +1 -0
- package/dist/tools/metaTools.js +153 -0
- package/dist/tools/metaTools.js.map +1 -0
- package/dist/tools/multimodalTools.js +262 -0
- package/dist/tools/multimodalTools.js.map +1 -0
- package/dist/tools/projectTools.js +261 -0
- package/dist/tools/projectTools.js.map +1 -0
- package/dist/tools/resourceTools.js +81 -0
- package/dist/tools/resourceTools.js.map +1 -0
- package/dist/tools/runtimeTools.js +137 -0
- package/dist/tools/runtimeTools.js.map +1 -0
- package/dist/tools/scheduleTools.js +10 -0
- package/dist/tools/scheduleTools.js.map +1 -0
- package/dist/tools/semanticTools.js +141 -0
- package/dist/tools/semanticTools.js.map +1 -0
- package/dist/tools/subagentTools.js +32 -0
- package/dist/tools/subagentTools.js.map +1 -0
- package/dist/tools/surface.js +644 -0
- package/dist/tools/surface.js.map +1 -0
- package/dist/tunnel/control.js +113 -0
- package/dist/tunnel/control.js.map +1 -0
- package/dist/tunnel/credentials.js +392 -0
- package/dist/tunnel/credentials.js.map +1 -0
- package/dist/tunnel/log.js +84 -0
- package/dist/tunnel/log.js.map +1 -0
- package/dist/tunnel/runtime.js +55 -0
- package/dist/tunnel/runtime.js.map +1 -0
- package/dist/tunnel/supervisor.js +280 -0
- package/dist/tunnel/supervisor.js.map +1 -0
- package/dist/util/bytes.js +53 -0
- package/dist/util/bytes.js.map +1 -0
- package/dist/util/hash.js +53 -0
- package/dist/util/hash.js.map +1 -0
- package/dist/workspace/fs.js +305 -0
- package/dist/workspace/fs.js.map +1 -0
- package/dist/workspace/identity.js +17 -0
- package/dist/workspace/identity.js.map +1 -0
- package/dist/workspace/ignores.js +173 -0
- package/dist/workspace/ignores.js.map +1 -0
- package/dist/workspace/root.js +59 -0
- package/dist/workspace/root.js.map +1 -0
- package/docs/AGENT_RUNTIME.md +154 -0
- package/docs/AI_PROVIDERS.md +110 -0
- package/docs/ARCHITECTURE.md +331 -0
- package/docs/ASSISTANCE.md +31 -0
- package/docs/AUTH.md +59 -0
- package/docs/BRAIN.md +92 -0
- package/docs/COMPATIBILITY.md +92 -0
- package/docs/CONFIRMATION.md +13 -0
- package/docs/CONTEXT.md +87 -0
- package/docs/DESKTOP.md +35 -0
- package/docs/EVALUATION.md +86 -0
- package/docs/LARGE_INPUTS.md +21 -0
- package/docs/LSP.md +21 -0
- package/docs/MANUAL_ACCEPTANCE.md +283 -0
- package/docs/MEMORY.md +128 -0
- package/docs/MULTIMODAL.md +32 -0
- package/docs/PROJECTS.md +146 -0
- package/docs/RELEASE_1.0.0.md +111 -0
- package/docs/RELEASE_NOTES.md +92 -0
- package/docs/RESOURCES.md +83 -0
- package/docs/RUNTIME.md +125 -0
- package/docs/SCHEDULES.md +23 -0
- package/docs/SECURITY.md +250 -0
- package/docs/TEST_REPORT.md +312 -0
- package/docs/TUNNEL.md +86 -0
- package/docs/WEB_CLIENTS.md +43 -0
- package/docs/WINDOWS.md +79 -0
- package/docs/adr/001-one-process-one-workspace.md +22 -0
- package/docs/adr/002-external-tunnel.md +19 -0
- package/docs/adr/003-sdk-v2-legacy-stateless.md +20 -0
- package/docs/adr/004-embedded-oauth-provider.md +19 -0
- package/docs/adr/005-static-client-baseline.md +19 -0
- package/docs/adr/006-guarded-fs-explicit-exec.md +16 -0
- package/docs/adr/007-preview-hash-journal.md +18 -0
- package/docs/adr/008-ts-js-semantics-first.md +17 -0
- package/docs/adr/009-jobs-polling.md +18 -0
- package/docs/adr/010-sqlite-better-sqlite3.md +18 -0
- package/docs/adr/011-env-example-secure-default.md +19 -0
- package/docs/adr/012-workspace-scope-grant.md +24 -0
- package/docs/adr/013-loopback-proxy-trust.md +18 -0
- package/docs/adr/014-direct-coding-tier.md +48 -0
- package/docs/adr/015-coding-agent-parity.md +56 -0
- package/docs/adr/016-oidc-openid-consent.md +15 -0
- package/docs/adr/017-installation-identity-local-config.md +44 -0
- package/docs/adr/018-access-scope-encoding.md +11 -0
- package/docs/adr/019-runtime-workspace-switch.md +59 -0
- package/docs/adr/020-desktop-access.md +50 -0
- package/docs/adr/021-persistent-desktop-consent.md +39 -0
- package/docs/adr/022-owner-kill-preserves-login.md +30 -0
- package/docs/adr/023-large-coding-inputs.md +49 -0
- package/docs/adr/024-usage-rounds-and-schedules.md +72 -0
- package/docs/adr/025-owner-chat-whitelist.md +53 -0
- package/docs/adr/026-remove-conversation-confirmation.md +35 -0
- package/docs/adr/027-workspace-client-list.md +20 -0
- package/docs/adr/028-owner-client-deletion.md +25 -0
- package/docs/adr/029-compact-tool-surface.md +121 -0
- package/docs/adr/030-windows-native-candidate.md +71 -0
- package/docs/adr/031-owner-selected-tunnel-supervision.md +13 -0
- package/docs/adr/032-owner-project-registry.md +43 -0
- package/docs/adr/033-read-only-project-federation.md +61 -0
- package/docs/adr/034-universal-resource-cas.md +60 -0
- package/docs/adr/035-project-brain-incremental-index.md +51 -0
- package/docs/adr/036-context-engine-evidence.md +53 -0
- package/docs/adr/037-owner-reviewed-memory.md +46 -0
- package/docs/adr/038-runtime-intelligence.md +46 -0
- package/docs/adr/039-advanced-agent-runtime.md +57 -0
- package/docs/adr/040-dodobench-release-gate.md +43 -0
- package/docs/adr/041-local-macos-docker-linux-gates.md +32 -0
- package/docs/adr/042-project-directory-generation-identity.md +36 -0
- package/docs/adr/043-trusted-self-hosted-platform-gates.md +38 -0
- package/docs/adr/044-global-launcher-and-cli-menu.md +43 -0
- package/docs/adr/045-ai-providers-multiproject.md +56 -0
- package/docs/adr/046-personal-access-mode.md +32 -0
- package/docs/adr/README.md +64 -0
- package/examples/.dodo.json.example +20 -0
- package/examples/cloudflared.yml +23 -0
- package/examples/reverse-proxy-fixture.mjs +37 -0
- package/native/desktop-linux.py +387 -0
- package/native/desktop-windows.cs +180 -0
- package/native/desktop.swift +212 -0
- package/package.json +145 -0
- package/schemas/global-config.schema.json +497 -0
- package/schemas/project-config.schema.json +75 -0
- package/schemas/tools.compact.json +3236 -0
- package/schemas/tools.hybrid.json +8194 -0
- package/schemas/tools.json +34518 -0
- package/scripts/guard-publish.mjs +12 -0
- package/scripts/setup-multimodal.mjs +70 -0
|
@@ -0,0 +1,644 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { DodoError, fromErrorInfo } from '../errors.js';
|
|
3
|
+
import { digestOf } from '../util/hash.js';
|
|
4
|
+
import { TOOL_CATALOG } from './catalog.js';
|
|
5
|
+
import { defineTool, registerTool, invokeToolDefinition, toolInputShape, } from './context.js';
|
|
6
|
+
import { envelopeSchema } from './envelope.js';
|
|
7
|
+
const SUBAGENT_OPERATION_NAMES = new Set(['subagent_spawn', 'subagent_status', 'subagent_result', 'subagent_control']);
|
|
8
|
+
/**
|
|
9
|
+
* Operation allowlists. Every full-catalog tool except the shared
|
|
10
|
+
* `project_overview` bootstrap is reachable through exactly one gateway;
|
|
11
|
+
* gateways, owner controls and private state are NOT operations.
|
|
12
|
+
*/
|
|
13
|
+
const GATEWAY_SPECS = [
|
|
14
|
+
{
|
|
15
|
+
name: 'dodo_read',
|
|
16
|
+
title: 'Read workspace state',
|
|
17
|
+
domain: 'code',
|
|
18
|
+
summary: 'read-only workspace access: files, search, symbols, jobs, history and agent notes',
|
|
19
|
+
operations: [
|
|
20
|
+
'list_files',
|
|
21
|
+
'read_files',
|
|
22
|
+
'read_image',
|
|
23
|
+
'read_instructions',
|
|
24
|
+
'search_code',
|
|
25
|
+
'glob_files',
|
|
26
|
+
'symbols',
|
|
27
|
+
'references',
|
|
28
|
+
'diagnostics',
|
|
29
|
+
'change_history',
|
|
30
|
+
'approval_status',
|
|
31
|
+
'environment_info',
|
|
32
|
+
'todo_read',
|
|
33
|
+
'handoff_read',
|
|
34
|
+
'job_status',
|
|
35
|
+
'job_output',
|
|
36
|
+
'job_wait',
|
|
37
|
+
'list_jobs',
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'dodo_write',
|
|
42
|
+
title: 'Change workspace files',
|
|
43
|
+
domain: 'code',
|
|
44
|
+
summary: 'hash-verified, journaled file changes: write/edit/patch, preview→apply→rollback, todos and handoff',
|
|
45
|
+
operations: [
|
|
46
|
+
'write_file',
|
|
47
|
+
'edit_file',
|
|
48
|
+
'apply_patch',
|
|
49
|
+
'replace_in_files',
|
|
50
|
+
'delete_path',
|
|
51
|
+
'move_path',
|
|
52
|
+
'make_directory',
|
|
53
|
+
'preview_changes',
|
|
54
|
+
'apply_changes',
|
|
55
|
+
'rollback_changes',
|
|
56
|
+
'preview_rename',
|
|
57
|
+
'todo_write',
|
|
58
|
+
'handoff_write',
|
|
59
|
+
'agent_write',
|
|
60
|
+
'agent_snapshot_rollback',
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'dodo_exec',
|
|
65
|
+
title: 'Run commands and control jobs',
|
|
66
|
+
domain: 'exec',
|
|
67
|
+
summary: 'shell/argv commands, task recipes, and stdin/cancel for owned background jobs',
|
|
68
|
+
operations: ['run_command', 'run_commands', 'run_task', 'exec_command', 'job_input', 'job_cancel', 'runtime_task_start', 'runtime_task_cancel', 'agent_exec'],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'dodo_git_read',
|
|
72
|
+
title: 'Inspect git state',
|
|
73
|
+
domain: 'git',
|
|
74
|
+
summary: 'git status, diff and log for the workspace repository',
|
|
75
|
+
operations: ['git_status', 'git_diff', 'git_log'],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'dodo_git_write',
|
|
79
|
+
title: 'Commit to git',
|
|
80
|
+
domain: 'git',
|
|
81
|
+
summary: 'create a git commit from staged DODO changes (never pushes)',
|
|
82
|
+
operations: ['git_commit'],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'dodo_desktop_view',
|
|
86
|
+
title: 'View permitted desktop windows',
|
|
87
|
+
domain: 'desktop',
|
|
88
|
+
summary: 'status, window list, capture and accessibility text for owner-permitted apps only',
|
|
89
|
+
operations: ['desktop_status', 'desktop_windows', 'desktop_capture', 'desktop_accessibility'],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'dodo_desktop_control',
|
|
93
|
+
title: 'Act in a permitted desktop window',
|
|
94
|
+
domain: 'desktop',
|
|
95
|
+
summary: 'one bounded input action (focus/click/type/key/scroll/drag) in an owner-permitted window',
|
|
96
|
+
operations: ['desktop_action'],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'dodo_assist_read',
|
|
100
|
+
title: 'Coding-task analysis',
|
|
101
|
+
domain: 'code',
|
|
102
|
+
summary: 'goal-driven context, owner-reviewed memory, static analysis, symbol reads and source-verified project graph queries',
|
|
103
|
+
operations: ['subagent_status', 'subagent_result', 'context_for_task', 'analyze_impact', 'read_symbol', 'context_query', 'context_evidence', 'context_status', 'memory_search', 'memory_inspect', 'memory_status', 'runtime_session_status', 'runtime_task_observe', 'runtime_snapshot', 'runtime_evidence', 'runtime_diagnose', 'agent_run_status', 'agent_read', 'agent_snapshot_create', 'agent_snapshot_compare', 'agent_skill_search', 'agent_skill_inspect', 'brain_status', 'brain_query', 'brain_symbol'],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'dodo_assist_change',
|
|
107
|
+
title: 'Refactor previews and verification',
|
|
108
|
+
domain: 'code',
|
|
109
|
+
summary: 'preview-only refactors, memory/learning proposals, explicit verification and owner-controlled Project Brain maintenance',
|
|
110
|
+
operations: ['subagent_spawn', 'subagent_control', 'preview_refactor', 'verify_changes', 'memory_propose', 'memory_learning_propose', 'runtime_session_open', 'runtime_session_close', 'agent_run_open', 'agent_plan_set', 'agent_hypothesis_open', 'agent_intent_acquire', 'agent_intent_release', 'agent_hypothesis_judge', 'agent_skill_propose', 'agent_run_control', 'brain_rebuild', 'brain_pause', 'brain_cancel'],
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'dodo_media',
|
|
114
|
+
title: 'Screen, image, media and speech',
|
|
115
|
+
domain: 'media',
|
|
116
|
+
summary: 'bounded screen/image views, local video/audio evidence, transcription, subtitles and local speech synthesis',
|
|
117
|
+
operations: [
|
|
118
|
+
'multimodal_status',
|
|
119
|
+
'screen_observe',
|
|
120
|
+
'image_view',
|
|
121
|
+
'media_open',
|
|
122
|
+
'media_extract',
|
|
123
|
+
'media_transcribe',
|
|
124
|
+
'media_subtitles',
|
|
125
|
+
'media_search',
|
|
126
|
+
'media_read',
|
|
127
|
+
'media_job',
|
|
128
|
+
'media_close',
|
|
129
|
+
'speech_synthesize',
|
|
130
|
+
'resource_inspect',
|
|
131
|
+
'resource_read',
|
|
132
|
+
'resource_read_range',
|
|
133
|
+
'resource_preview',
|
|
134
|
+
'resource_extract',
|
|
135
|
+
'resource_transform',
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'dodo_browser',
|
|
140
|
+
title: 'Isolated browser',
|
|
141
|
+
domain: 'browser',
|
|
142
|
+
summary: 'open/observe/act in the isolated local Chromium session',
|
|
143
|
+
operations: ['browser_session', 'browser_observe', 'browser_action', 'runtime_browser_collect'],
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: 'dodo_game',
|
|
147
|
+
title: 'Turn-based visual game',
|
|
148
|
+
domain: 'game',
|
|
149
|
+
summary: 'step-based visual game sessions with fresh observations per move',
|
|
150
|
+
operations: ['game_session', 'game_step'],
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: 'dodo_workflow_read',
|
|
154
|
+
title: 'Find remembered procedures',
|
|
155
|
+
domain: 'workflow',
|
|
156
|
+
summary: 'search or read revisioned demonstration workflows',
|
|
157
|
+
operations: ['workflow_search'],
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: 'dodo_workflow_write',
|
|
161
|
+
title: 'Save a demonstrated procedure',
|
|
162
|
+
domain: 'workflow',
|
|
163
|
+
summary: 'save or revise a demonstration workflow (never executes it)',
|
|
164
|
+
operations: ['workflow_save'],
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'dodo_workflow_run',
|
|
168
|
+
title: 'Run a remembered procedure',
|
|
169
|
+
domain: 'workflow',
|
|
170
|
+
summary: 'apply a saved workflow one checked step at a time',
|
|
171
|
+
operations: ['workflow_run'],
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: 'dodo_schedule',
|
|
175
|
+
title: 'Propose a scheduled command',
|
|
176
|
+
domain: 'schedule',
|
|
177
|
+
summary: 'propose an immutable scheduled command; the owner approves it locally before it ever runs',
|
|
178
|
+
operations: ['schedule_propose'],
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: 'dodo_web',
|
|
182
|
+
title: 'Fetch a public URL',
|
|
183
|
+
domain: 'web',
|
|
184
|
+
summary: 'SSRF-guarded outbound HTTPS fetch (only when the owner enabled allowWebFetch)',
|
|
185
|
+
operations: ['fetch_url'],
|
|
186
|
+
},
|
|
187
|
+
];
|
|
188
|
+
const SCOPE_RANK = { 'dodo:read': 0, 'dodo:write': 1, 'dodo:exec': 2 };
|
|
189
|
+
const byName = new Map(TOOL_CATALOG.map((d) => [d.name, d]));
|
|
190
|
+
function gatewaySpecsFor(features) {
|
|
191
|
+
if (features.subagents)
|
|
192
|
+
return GATEWAY_SPECS;
|
|
193
|
+
return GATEWAY_SPECS.map((spec) => ({
|
|
194
|
+
...spec,
|
|
195
|
+
operations: spec.operations.filter((operation) => !SUBAGENT_OPERATION_NAMES.has(operation)),
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
function targetOf(operation) {
|
|
199
|
+
const def = byName.get(operation);
|
|
200
|
+
/* istanbul ignore next -- construction invariant, validated at module load */
|
|
201
|
+
if (!def)
|
|
202
|
+
throw new Error(`compact surface references unknown operation ${operation}`);
|
|
203
|
+
return def;
|
|
204
|
+
}
|
|
205
|
+
// ---- construction-time invariants (fail the build/tests, never runtime) ----
|
|
206
|
+
{
|
|
207
|
+
const seen = new Set();
|
|
208
|
+
for (const spec of GATEWAY_SPECS) {
|
|
209
|
+
for (const op of spec.operations) {
|
|
210
|
+
if (op === 'project_overview' || op.startsWith('dodo_'))
|
|
211
|
+
throw new Error(`gateway ${spec.name} must not expose ${op}`);
|
|
212
|
+
if (seen.has(op))
|
|
213
|
+
throw new Error(`operation ${op} is exposed by two gateways`);
|
|
214
|
+
if (!byName.has(op))
|
|
215
|
+
throw new Error(`gateway ${spec.name} references unknown tool ${op}`);
|
|
216
|
+
seen.add(op);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
for (const def of TOOL_CATALOG) {
|
|
220
|
+
if (def.name !== 'project_overview' && !seen.has(def.name)) {
|
|
221
|
+
throw new Error(`full-catalog tool ${def.name} is not reachable from any compact gateway`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/** operation → gateway lookup used by discover and tests. */
|
|
226
|
+
export const OPERATION_TO_GATEWAY = new Map(GATEWAY_SPECS.flatMap((spec) => spec.operations.map((op) => [op, spec.name])));
|
|
227
|
+
const looseData = z.looseObject({});
|
|
228
|
+
function minScope(operations) {
|
|
229
|
+
let min = 'dodo:exec';
|
|
230
|
+
for (const op of operations) {
|
|
231
|
+
const scope = targetOf(op).requiredScope;
|
|
232
|
+
if (SCOPE_RANK[scope] < SCOPE_RANK[min])
|
|
233
|
+
min = scope;
|
|
234
|
+
}
|
|
235
|
+
return min;
|
|
236
|
+
}
|
|
237
|
+
function dominantAction(operations) {
|
|
238
|
+
const actions = new Set(operations.map((op) => targetOf(op).action));
|
|
239
|
+
if (actions.has('exec'))
|
|
240
|
+
return 'exec';
|
|
241
|
+
if (actions.has('mutate-files'))
|
|
242
|
+
return 'mutate-files';
|
|
243
|
+
if (actions.has('plan'))
|
|
244
|
+
return 'plan';
|
|
245
|
+
if (actions.has('job-control'))
|
|
246
|
+
return 'job-control';
|
|
247
|
+
return 'read';
|
|
248
|
+
}
|
|
249
|
+
function buildGateway(spec) {
|
|
250
|
+
const operations = [...spec.operations];
|
|
251
|
+
const scope = minScope(spec.operations);
|
|
252
|
+
const targets = spec.operations.map((op) => targetOf(op));
|
|
253
|
+
return defineTool({
|
|
254
|
+
name: spec.name,
|
|
255
|
+
title: spec.title,
|
|
256
|
+
description: `Gateway: ${spec.summary}. Set operation to one of: ${spec.operations.join(', ')}. ` +
|
|
257
|
+
`Put that operation's own arguments in args (never workspaceId/workspaceEpoch — they come from the top level only). ` +
|
|
258
|
+
`Identical authorization to calling the operation directly: its own OAuth scope, workspace access, trust policy, local approvals, path/secret guards, hash checks and audit all apply. ` +
|
|
259
|
+
`Call dodo_discover with operation="<name>" for the exact input schema.`,
|
|
260
|
+
input: {
|
|
261
|
+
operation: z.enum(operations).describe('Target operation to invoke'),
|
|
262
|
+
args: z
|
|
263
|
+
.record(z.string(), z.unknown())
|
|
264
|
+
.default({})
|
|
265
|
+
.describe("The selected operation's own arguments, exactly as its schema defines (dodo_discover returns it). Never include workspaceId/workspaceEpoch here."),
|
|
266
|
+
},
|
|
267
|
+
output: looseData,
|
|
268
|
+
annotations: {
|
|
269
|
+
readOnlyHint: targets.every((t) => t.annotations.readOnlyHint === true),
|
|
270
|
+
destructiveHint: targets.some((t) => t.annotations.destructiveHint === true),
|
|
271
|
+
idempotentHint: false,
|
|
272
|
+
openWorldHint: targets.some((t) => t.annotations.openWorldHint === true),
|
|
273
|
+
},
|
|
274
|
+
requiredScope: scope,
|
|
275
|
+
action: dominantAction(spec.operations),
|
|
276
|
+
handler: async (args, ctx) => {
|
|
277
|
+
const target = targetOf(args.operation);
|
|
278
|
+
const raw = (args.args ?? {});
|
|
279
|
+
if ('workspaceId' in raw || 'workspaceEpoch' in raw || 'targetProjectId' in raw) {
|
|
280
|
+
throw new DodoError('INVALID_INPUT', 'args must not carry workspaceId/workspaceEpoch; the gateway takes them from its top-level fields', {
|
|
281
|
+
recovery: 'remove workspaceId and workspaceEpoch from args; keep them only at the top level of the gateway call',
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
const merged = target.noWorkspaceContext
|
|
285
|
+
? { ...raw }
|
|
286
|
+
: { ...raw, workspaceId: args['workspaceId'], workspaceEpoch: args['workspaceEpoch'] };
|
|
287
|
+
const { envelope, extraBlocks } = await invokeToolDefinition({
|
|
288
|
+
def: target,
|
|
289
|
+
services: ctx.services,
|
|
290
|
+
principal: ctx.principal,
|
|
291
|
+
args: merged,
|
|
292
|
+
});
|
|
293
|
+
if (!envelope.ok)
|
|
294
|
+
throw fromErrorInfo(envelope.error);
|
|
295
|
+
return {
|
|
296
|
+
data: envelope.data,
|
|
297
|
+
warnings: envelope.warnings,
|
|
298
|
+
truncated: envelope.truncated,
|
|
299
|
+
nextCursor: envelope.nextCursor,
|
|
300
|
+
...(extraBlocks.length > 0 ? { contentBlocks: extraBlocks } : {}),
|
|
301
|
+
};
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
// --------------------------------------------------------------- discover --
|
|
306
|
+
const DISCOVER_DOMAINS = ['code', 'exec', 'git', 'desktop', 'media', 'browser', 'game', 'workflow', 'schedule', 'web'];
|
|
307
|
+
function buildOperationIndex(specs, exposedCatalog) {
|
|
308
|
+
const order = new Map(exposedCatalog.map((d, i) => [d.name, i]));
|
|
309
|
+
return specs.flatMap((spec) => spec.operations.map((op) => {
|
|
310
|
+
const def = targetOf(op);
|
|
311
|
+
return {
|
|
312
|
+
operation: op,
|
|
313
|
+
gateway: spec.name,
|
|
314
|
+
domain: spec.domain,
|
|
315
|
+
requiredScope: def.requiredScope,
|
|
316
|
+
action: def.action,
|
|
317
|
+
description: def.description.slice(0, 200),
|
|
318
|
+
haystack: `${op} ${def.title} ${def.description}`.toLowerCase(),
|
|
319
|
+
order: order.get(op) ?? 999,
|
|
320
|
+
};
|
|
321
|
+
})).sort((a, b) => a.order - b.order);
|
|
322
|
+
}
|
|
323
|
+
// Gateways can have the same public name with different feature-filtered
|
|
324
|
+
// definitions. Cache by definition identity so an enabled schema can never
|
|
325
|
+
// leak into a disabled live surface (or vice versa).
|
|
326
|
+
const schemaCache = new WeakMap();
|
|
327
|
+
/** Deterministic JSON Schema + hash for one tool's full registered input contract. */
|
|
328
|
+
export function operationSchema(def) {
|
|
329
|
+
let cached = schemaCache.get(def);
|
|
330
|
+
if (!cached) {
|
|
331
|
+
const inputSchema = z.toJSONSchema(z.object(toolInputShape(def)).strict(), { target: 'draft-2020-12' });
|
|
332
|
+
cached = { inputSchema, schemaHash: digestOf(inputSchema) };
|
|
333
|
+
schemaCache.set(def, cached);
|
|
334
|
+
}
|
|
335
|
+
return cached;
|
|
336
|
+
}
|
|
337
|
+
const argsSchemaCache = new WeakMap();
|
|
338
|
+
/**
|
|
339
|
+
* Deterministic JSON Schema + hash for the operation's `args` payload as the
|
|
340
|
+
* GATEWAY accepts it: the tool's own fields WITHOUT workspaceId/workspaceEpoch
|
|
341
|
+
* (those travel at the gateway's top level and are rejected inside args).
|
|
342
|
+
*/
|
|
343
|
+
export function operationArgsSchema(def) {
|
|
344
|
+
let cached = argsSchemaCache.get(def);
|
|
345
|
+
if (!cached) {
|
|
346
|
+
const argsSchema = z.toJSONSchema(z.object(def.input).strict(), { target: 'draft-2020-12' });
|
|
347
|
+
cached = { argsSchema, schemaHash: digestOf(argsSchema) };
|
|
348
|
+
argsSchemaCache.set(def, cached);
|
|
349
|
+
}
|
|
350
|
+
return cached;
|
|
351
|
+
}
|
|
352
|
+
function usageNotes(def) {
|
|
353
|
+
const notes = [`requires the ${def.requiredScope} scope`];
|
|
354
|
+
switch (def.action) {
|
|
355
|
+
case 'mutate-files':
|
|
356
|
+
notes.push('file mutation: journaled with backups; in inspect trust mode each call needs a local owner approval');
|
|
357
|
+
break;
|
|
358
|
+
case 'exec':
|
|
359
|
+
notes.push('effectful: local trust policy applies (owner approval unless trusted mode) and runs with OS-user privileges unless sandboxed');
|
|
360
|
+
break;
|
|
361
|
+
case 'plan':
|
|
362
|
+
notes.push('creates a preview/plan only; nothing is written until apply');
|
|
363
|
+
break;
|
|
364
|
+
default:
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
const shape = toolInputShape(def);
|
|
368
|
+
if ('idempotencyKey' in shape) {
|
|
369
|
+
notes.push('supports idempotencyKey: reuse the SAME key when retrying the SAME arguments; never auto-repeat an uncertain effect with a fresh key');
|
|
370
|
+
}
|
|
371
|
+
if ('expectedHash' in shape) {
|
|
372
|
+
notes.push('pass expectedHash from read_files so a concurrently changed file fails closed (FILE_CHANGED)');
|
|
373
|
+
}
|
|
374
|
+
return notes;
|
|
375
|
+
}
|
|
376
|
+
function buildDiscoverTool(specs, exposedCatalog) {
|
|
377
|
+
const operationIndex = buildOperationIndex(specs, exposedCatalog);
|
|
378
|
+
return defineTool({
|
|
379
|
+
name: 'dodo_discover',
|
|
380
|
+
title: 'Discover operations behind the compact gateways',
|
|
381
|
+
description: 'Find which gateway operation covers a capability. With query/domain it returns matching operations (name, gateway, scope, short description — no schemas). With operation="<name>" it returns that operation\'s full input JSON Schema, deterministic schemaHash, required scope, action class and usage notes. Discovery never grants permissions and never reveals tokens, grants or owner state.',
|
|
382
|
+
input: {
|
|
383
|
+
query: z.string().max(200).optional().describe('Free-text capability search, e.g. "edit a TypeScript file"'),
|
|
384
|
+
domain: z.enum(DISCOVER_DOMAINS).optional().describe('Restrict matches to one capability domain'),
|
|
385
|
+
operation: z.string().max(64).optional().describe('Exact operation name for full schema detail'),
|
|
386
|
+
limit: z.number().int().min(1).max(25).default(8),
|
|
387
|
+
cursor: z.string().max(32).optional().describe('nextCursor from a previous dodo_discover result'),
|
|
388
|
+
},
|
|
389
|
+
output: looseData,
|
|
390
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
391
|
+
requiredScope: 'dodo:read',
|
|
392
|
+
action: 'read',
|
|
393
|
+
handler: async (args) => {
|
|
394
|
+
if (args.operation !== undefined) {
|
|
395
|
+
const entry = operationIndex.find((e) => e.operation === args.operation);
|
|
396
|
+
if (!entry) {
|
|
397
|
+
throw new DodoError('NOT_FOUND', `unknown operation ${args.operation}`, {
|
|
398
|
+
recovery: 'call dodo_discover with a query (no operation) to list available operations',
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
const def = targetOf(entry.operation);
|
|
402
|
+
const { argsSchema, schemaHash } = operationArgsSchema(def);
|
|
403
|
+
return {
|
|
404
|
+
data: {
|
|
405
|
+
operation: entry.operation,
|
|
406
|
+
gateway: entry.gateway,
|
|
407
|
+
domain: entry.domain,
|
|
408
|
+
requiredScope: entry.requiredScope,
|
|
409
|
+
action: entry.action,
|
|
410
|
+
description: def.description,
|
|
411
|
+
// The schema of the gateway's args payload for this operation.
|
|
412
|
+
// workspaceId/workspaceEpoch are intentionally NOT part of it.
|
|
413
|
+
inputSchema: argsSchema,
|
|
414
|
+
schemaHash,
|
|
415
|
+
callShape: {
|
|
416
|
+
gateway: entry.gateway,
|
|
417
|
+
example: { workspaceId: '<from project_overview>', workspaceEpoch: '<from project_overview>', operation: entry.operation, args: '<object matching inputSchema>' },
|
|
418
|
+
},
|
|
419
|
+
notes: [`pass workspaceId/workspaceEpoch at the TOP LEVEL of the ${entry.gateway} call, never inside args`, ...usageNotes(def)],
|
|
420
|
+
},
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
const tokens = (args.query ?? '')
|
|
424
|
+
.toLowerCase()
|
|
425
|
+
.split(/[^a-z0-9_]+/)
|
|
426
|
+
.filter((t) => t.length > 1);
|
|
427
|
+
let entries = operationIndex.filter((e) => args.domain === undefined || e.domain === args.domain);
|
|
428
|
+
if (tokens.length > 0) {
|
|
429
|
+
const scored = entries
|
|
430
|
+
.map((e) => {
|
|
431
|
+
let score = 0;
|
|
432
|
+
for (const t of tokens) {
|
|
433
|
+
if (e.operation.includes(t))
|
|
434
|
+
score += 3;
|
|
435
|
+
if (e.haystack.includes(t))
|
|
436
|
+
score += 1;
|
|
437
|
+
}
|
|
438
|
+
return { e, score };
|
|
439
|
+
})
|
|
440
|
+
.filter((s) => s.score > 0)
|
|
441
|
+
.sort((a, b) => b.score - a.score || a.e.order - b.e.order);
|
|
442
|
+
entries = scored.map((s) => s.e);
|
|
443
|
+
}
|
|
444
|
+
let offset = 0;
|
|
445
|
+
if (args.cursor !== undefined) {
|
|
446
|
+
const m = /^c(\d{1,6})$/.exec(args.cursor);
|
|
447
|
+
if (!m)
|
|
448
|
+
throw new DodoError('INVALID_INPUT', 'invalid cursor');
|
|
449
|
+
offset = Number(m[1]);
|
|
450
|
+
}
|
|
451
|
+
const page = entries.slice(offset, offset + args.limit);
|
|
452
|
+
const next = offset + args.limit < entries.length ? `c${offset + args.limit}` : null;
|
|
453
|
+
return {
|
|
454
|
+
data: {
|
|
455
|
+
matches: page.map((e) => ({
|
|
456
|
+
operation: e.operation,
|
|
457
|
+
gateway: e.gateway,
|
|
458
|
+
domain: e.domain,
|
|
459
|
+
requiredScope: e.requiredScope,
|
|
460
|
+
action: e.action,
|
|
461
|
+
description: e.description,
|
|
462
|
+
})),
|
|
463
|
+
totalMatches: entries.length,
|
|
464
|
+
},
|
|
465
|
+
truncated: next !== null,
|
|
466
|
+
nextCursor: next,
|
|
467
|
+
};
|
|
468
|
+
},
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
// ------------------------------------------------------ compact overview --
|
|
472
|
+
const fullOverview = targetOf('project_overview');
|
|
473
|
+
function overviewDataForExposure(data, subagents) {
|
|
474
|
+
if (subagents)
|
|
475
|
+
return data;
|
|
476
|
+
const ai = data['ai'];
|
|
477
|
+
return {
|
|
478
|
+
...data,
|
|
479
|
+
...(ai && typeof ai === 'object' && !Array.isArray(ai)
|
|
480
|
+
? { ai: { ...ai, note: 'Sub-agent MCP operations are hidden by the owner. Agent profiles remain available through the private Local Config web workbench.' } }
|
|
481
|
+
: {}),
|
|
482
|
+
mcpSubagentsEnabled: false,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
const fullOverviewWithoutSubagents = defineTool({
|
|
486
|
+
...fullOverview,
|
|
487
|
+
handler: async (args, ctx) => {
|
|
488
|
+
const result = await fullOverview.handler(args, ctx);
|
|
489
|
+
return { ...result, data: overviewDataForExposure(result.data, false) };
|
|
490
|
+
},
|
|
491
|
+
});
|
|
492
|
+
function overviewFor(surface, counts, subagents) {
|
|
493
|
+
const hint = surface === 'compact'
|
|
494
|
+
? ' This connection uses the COMPACT tool surface: capabilities are invoked through dodo_* gateway tools; call dodo_discover to find an operation and its exact schema.'
|
|
495
|
+
: ' This connection uses the HYBRID tool surface: common coding tools are available directly, and every other capability is invoked through the dodo_* gateway tools; call dodo_discover to find an operation and its exact schema.';
|
|
496
|
+
return defineTool({
|
|
497
|
+
...fullOverview,
|
|
498
|
+
description: fullOverview.description + hint,
|
|
499
|
+
handler: async (args, ctx) => {
|
|
500
|
+
const result = await fullOverview.handler(args, ctx);
|
|
501
|
+
const data = overviewDataForExposure(result.data, subagents);
|
|
502
|
+
return {
|
|
503
|
+
...result,
|
|
504
|
+
data: {
|
|
505
|
+
...data,
|
|
506
|
+
toolSurface: surface,
|
|
507
|
+
// Public compact-surface field names are stable protocol contract.
|
|
508
|
+
compactToolCount: counts.compact,
|
|
509
|
+
fullToolCount: counts.full,
|
|
510
|
+
...(surface === 'hybrid' ? { hybridToolCount: counts.hybrid } : {}),
|
|
511
|
+
mcpSubagentsEnabled: subagents,
|
|
512
|
+
},
|
|
513
|
+
};
|
|
514
|
+
},
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
const ALL_FEATURES = { subagents: true };
|
|
518
|
+
const DEFAULT_FEATURES = { subagents: false };
|
|
519
|
+
const ALL_COUNTS = { compact: 2 + GATEWAY_SPECS.length, full: TOOL_CATALOG.length, hybrid: 2 + GATEWAY_SPECS.length + 30 };
|
|
520
|
+
const GATEWAYS = GATEWAY_SPECS.map(buildGateway);
|
|
521
|
+
const discoverTool = buildDiscoverTool(GATEWAY_SPECS, TOOL_CATALOG);
|
|
522
|
+
/** The compact catalog in a fixed, stable order (overview → discover → gateways). */
|
|
523
|
+
export const COMPACT_CATALOG = [overviewFor('compact', ALL_COUNTS, true), discoverTool, ...GATEWAYS];
|
|
524
|
+
/**
|
|
525
|
+
* Hybrid surface (ADR-029 addendum): for clients that cap the tool
|
|
526
|
+
* count near ~50, the coverage core comes FIRST (overview, discover, all 17
|
|
527
|
+
* gateways — identical to compact, so any client-side truncation can only
|
|
528
|
+
* drop direct-tool duplicates, never capabilities), followed by the 30 most
|
|
529
|
+
* used direct coding tools with their original names and schemas. 49 tools
|
|
530
|
+
* total; permissions unchanged in every path.
|
|
531
|
+
*/
|
|
532
|
+
export const HYBRID_DIRECT_OPERATIONS = [
|
|
533
|
+
'list_files',
|
|
534
|
+
'read_files',
|
|
535
|
+
'read_instructions',
|
|
536
|
+
'search_code',
|
|
537
|
+
'glob_files',
|
|
538
|
+
'write_file',
|
|
539
|
+
'edit_file',
|
|
540
|
+
'apply_patch',
|
|
541
|
+
'replace_in_files',
|
|
542
|
+
'delete_path',
|
|
543
|
+
'move_path',
|
|
544
|
+
'make_directory',
|
|
545
|
+
'symbols',
|
|
546
|
+
'references',
|
|
547
|
+
'preview_changes',
|
|
548
|
+
'apply_changes',
|
|
549
|
+
'rollback_changes',
|
|
550
|
+
'git_status',
|
|
551
|
+
'git_diff',
|
|
552
|
+
'git_log',
|
|
553
|
+
'git_commit',
|
|
554
|
+
'run_command',
|
|
555
|
+
'run_commands',
|
|
556
|
+
'run_task',
|
|
557
|
+
'exec_command',
|
|
558
|
+
'job_status',
|
|
559
|
+
'job_output',
|
|
560
|
+
'job_wait',
|
|
561
|
+
'job_cancel',
|
|
562
|
+
'list_jobs',
|
|
563
|
+
];
|
|
564
|
+
export const HYBRID_CATALOG = [overviewFor('hybrid', ALL_COUNTS, true), discoverTool, ...GATEWAYS, ...HYBRID_DIRECT_OPERATIONS.map(targetOf)];
|
|
565
|
+
{
|
|
566
|
+
const names = new Set(HYBRID_CATALOG.map((d) => d.name));
|
|
567
|
+
if (names.size !== HYBRID_CATALOG.length)
|
|
568
|
+
throw new Error('hybrid surface has duplicate tool names');
|
|
569
|
+
if (HYBRID_CATALOG.length > 49)
|
|
570
|
+
throw new Error(`hybrid surface exceeds the 49-tool budget (${HYBRID_CATALOG.length})`);
|
|
571
|
+
for (const op of HYBRID_DIRECT_OPERATIONS) {
|
|
572
|
+
if (!OPERATION_TO_GATEWAY.has(op))
|
|
573
|
+
throw new Error(`hybrid direct tool ${op} is not gateway-covered`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
const MCP_TOOL_CATALOG_WITHOUT_SUBAGENTS = TOOL_CATALOG
|
|
577
|
+
.filter((def) => !SUBAGENT_OPERATION_NAMES.has(def.name))
|
|
578
|
+
.map((def) => def.name === 'project_overview' ? fullOverviewWithoutSubagents : def);
|
|
579
|
+
const GATEWAY_SPECS_WITHOUT_SUBAGENTS = gatewaySpecsFor(DEFAULT_FEATURES);
|
|
580
|
+
const GATEWAYS_WITHOUT_SUBAGENTS = GATEWAY_SPECS_WITHOUT_SUBAGENTS.map(buildGateway);
|
|
581
|
+
const COUNTS_WITHOUT_SUBAGENTS = {
|
|
582
|
+
compact: 2 + GATEWAY_SPECS_WITHOUT_SUBAGENTS.length,
|
|
583
|
+
full: MCP_TOOL_CATALOG_WITHOUT_SUBAGENTS.length,
|
|
584
|
+
hybrid: 2 + GATEWAY_SPECS_WITHOUT_SUBAGENTS.length + HYBRID_DIRECT_OPERATIONS.length,
|
|
585
|
+
};
|
|
586
|
+
const DISCOVER_WITHOUT_SUBAGENTS = buildDiscoverTool(GATEWAY_SPECS_WITHOUT_SUBAGENTS, MCP_TOOL_CATALOG_WITHOUT_SUBAGENTS);
|
|
587
|
+
const COMPACT_CATALOG_WITHOUT_SUBAGENTS = [
|
|
588
|
+
overviewFor('compact', COUNTS_WITHOUT_SUBAGENTS, false),
|
|
589
|
+
DISCOVER_WITHOUT_SUBAGENTS,
|
|
590
|
+
...GATEWAYS_WITHOUT_SUBAGENTS,
|
|
591
|
+
];
|
|
592
|
+
const HYBRID_CATALOG_WITHOUT_SUBAGENTS = [
|
|
593
|
+
overviewFor('hybrid', COUNTS_WITHOUT_SUBAGENTS, false),
|
|
594
|
+
DISCOVER_WITHOUT_SUBAGENTS,
|
|
595
|
+
...GATEWAYS_WITHOUT_SUBAGENTS,
|
|
596
|
+
...HYBRID_DIRECT_OPERATIONS.map(targetOf),
|
|
597
|
+
];
|
|
598
|
+
// ------------------------------------------------------------- surface API --
|
|
599
|
+
export function surfaceCatalog(surface, features = ALL_FEATURES) {
|
|
600
|
+
if (features.subagents) {
|
|
601
|
+
if (surface === 'compact')
|
|
602
|
+
return COMPACT_CATALOG;
|
|
603
|
+
if (surface === 'hybrid')
|
|
604
|
+
return HYBRID_CATALOG;
|
|
605
|
+
return TOOL_CATALOG;
|
|
606
|
+
}
|
|
607
|
+
if (surface === 'compact')
|
|
608
|
+
return COMPACT_CATALOG_WITHOUT_SUBAGENTS;
|
|
609
|
+
if (surface === 'hybrid')
|
|
610
|
+
return HYBRID_CATALOG_WITHOUT_SUBAGENTS;
|
|
611
|
+
return MCP_TOOL_CATALOG_WITHOUT_SUBAGENTS;
|
|
612
|
+
}
|
|
613
|
+
export function registerSurface(server, services, surface, features = ALL_FEATURES) {
|
|
614
|
+
for (const def of surfaceCatalog(surface, features))
|
|
615
|
+
registerTool(server, services, def);
|
|
616
|
+
}
|
|
617
|
+
const statsCache = new Map();
|
|
618
|
+
/**
|
|
619
|
+
* Deterministic size evidence for one surface: tool count plus the UTF-8 byte
|
|
620
|
+
* length of the serialized tools/list-equivalent payload — name, title,
|
|
621
|
+
* description, annotations, input schema AND the envelope output schema of
|
|
622
|
+
* every tool, matching what the MCP SDK serves a client at connection time.
|
|
623
|
+
* Never includes request data or tokens.
|
|
624
|
+
*/
|
|
625
|
+
export function surfaceStats(surface, features = ALL_FEATURES) {
|
|
626
|
+
const cacheKey = `${surface}:${features.subagents ? 'subagents' : 'no-subagents'}`;
|
|
627
|
+
let cached = statsCache.get(cacheKey);
|
|
628
|
+
if (!cached) {
|
|
629
|
+
const tools = surfaceCatalog(surface, features).map((def) => ({
|
|
630
|
+
name: def.name,
|
|
631
|
+
title: def.title,
|
|
632
|
+
description: def.description,
|
|
633
|
+
annotations: def.annotations,
|
|
634
|
+
inputSchema: operationSchema(def).inputSchema,
|
|
635
|
+
outputSchema: z.toJSONSchema(envelopeSchema(def.output), { target: 'draft-2020-12' }),
|
|
636
|
+
}));
|
|
637
|
+
cached = { toolCount: tools.length, schemaBytes: Buffer.byteLength(JSON.stringify(tools), 'utf8') };
|
|
638
|
+
statsCache.set(cacheKey, cached);
|
|
639
|
+
}
|
|
640
|
+
return cached;
|
|
641
|
+
}
|
|
642
|
+
/** Gateway specs exported for schema emission and tests (names + allowlists only). */
|
|
643
|
+
export const GATEWAY_OPERATIONS = GATEWAY_SPECS.map((s) => ({ name: s.name, domain: s.domain, operations: s.operations }));
|
|
644
|
+
//# sourceMappingURL=surface.js.map
|