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,212 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import AppKit
|
|
3
|
+
import ApplicationServices
|
|
4
|
+
import ScreenCaptureKit
|
|
5
|
+
import Vision
|
|
6
|
+
|
|
7
|
+
// One bounded JSON request on stdin, one JSON response on stdout. No shell,
|
|
8
|
+
// network, clipboard, filesystem output, or arbitrary AppleScript execution.
|
|
9
|
+
struct Failure: Error { let code: String; let message: String }
|
|
10
|
+
func fail(_ code: String, _ message: String) throws -> Never { throw Failure(code: code, message: message) }
|
|
11
|
+
func integer(_ o: [String: Any], _ k: String) throws -> Int {
|
|
12
|
+
guard let n = o[k] as? NSNumber, CFGetTypeID(n) != CFBooleanGetTypeID(), n.doubleValue.isFinite, n.doubleValue.rounded() == n.doubleValue else { try fail("INVALID_INPUT", "invalid integer: \(k)") }
|
|
13
|
+
return n.intValue
|
|
14
|
+
}
|
|
15
|
+
func number(_ o: [String: Any], _ k: String) throws -> Double {
|
|
16
|
+
guard let n = o[k] as? NSNumber, CFGetTypeID(n) != CFBooleanGetTypeID(), n.doubleValue.isFinite else { try fail("INVALID_INPUT", "invalid number: \(k)") }
|
|
17
|
+
return n.doubleValue
|
|
18
|
+
}
|
|
19
|
+
func clipped(_ s: String, _ max: Int) -> String { String(decoding: s.utf16.prefix(max), as: UTF16.self) }
|
|
20
|
+
func frameJSON(_ r: CGRect) -> [String: Double] { ["x":r.minX,"y":r.minY,"width":r.width,"height":r.height] }
|
|
21
|
+
func screenPermission() throws { if !CGPreflightScreenCaptureAccess() { try fail("FORBIDDEN", "Screen Recording permission is required; use dodo desktop setup --request-permissions locally") } }
|
|
22
|
+
func controlPermission() throws { if !AXIsProcessTrusted() { try fail("FORBIDDEN", "Accessibility permission is required; use dodo desktop setup --request-permissions locally") } }
|
|
23
|
+
func bounds(_ w: [String: Any]) -> CGRect { CGRect(dictionaryRepresentation: (w[kCGWindowBounds as String] as? [String: Any] ?? [:]) as CFDictionary) ?? .zero }
|
|
24
|
+
func windowRows() -> [[String: Any]] { CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) as? [[String: Any]] ?? [] }
|
|
25
|
+
func appID(_ pid: Int32) -> String? { NSRunningApplication(processIdentifier: pid)?.bundleIdentifier }
|
|
26
|
+
func allowedApps(_ req: [String: Any]) throws -> [String] {
|
|
27
|
+
guard let apps=req["allowedApps"] as? [String], !apps.isEmpty, apps.count <= 20, apps.allSatisfy({ $0.count <= 200 && $0.contains(".") && !$0.contains("*") }) else { try fail("FORBIDDEN", "explicit allowed applications are required") }
|
|
28
|
+
return apps
|
|
29
|
+
}
|
|
30
|
+
func window(_ id: Int, apps: [String]) throws -> [String: Any] {
|
|
31
|
+
guard let w=windowRows().first(where: { ($0[kCGWindowNumber as String] as? Int)==id && ($0[kCGWindowLayer as String] as? Int)==0 }), let pid=w[kCGWindowOwnerPID as String] as? Int32, let app=appID(pid), apps.contains(app) else { try fail("FORBIDDEN", "window is unavailable or outside the allowed applications") }
|
|
32
|
+
let r=bounds(w)
|
|
33
|
+
guard r.width >= 10 && r.height >= 10 else { try fail("INVALID_INPUT", "window has no capturable area") }
|
|
34
|
+
return w
|
|
35
|
+
}
|
|
36
|
+
func describe(_ w: [String: Any]) -> [String: Any] {
|
|
37
|
+
let pid=w[kCGWindowOwnerPID as String] as? Int32 ?? 0
|
|
38
|
+
return ["windowId":w[kCGWindowNumber as String] as? Int ?? 0,"pid":pid,"appId":appID(pid) ?? "", "title":clipped(w[kCGWindowName as String] as? String ?? "",300),"bounds":frameJSON(bounds(w))]
|
|
39
|
+
}
|
|
40
|
+
func validTarget(_ req: [String: Any], foreground: Bool) throws -> [String: Any] {
|
|
41
|
+
guard let target=req["target"] as? [String: Any], let old=target["bounds"] as? [String: Any] else { try fail("INVALID_INPUT", "target required") }
|
|
42
|
+
let w=try window(integer(target,"windowId"),apps:allowedApps(req)), r=bounds(w)
|
|
43
|
+
guard try integer(target,"pid") == (w[kCGWindowOwnerPID as String] as? Int), target["appId"] as? String == appID(w[kCGWindowOwnerPID as String] as? Int32 ?? 0),
|
|
44
|
+
abs(r.minX-(try number(old,"x"))) < 0.5, abs(r.minY-(try number(old,"y"))) < 0.5,
|
|
45
|
+
abs(r.width-(try number(old,"width"))) < 0.5, abs(r.height-(try number(old,"height"))) < 0.5 else { try fail("STALE_WORKSPACE", "window moved, resized or changed; capture it again") }
|
|
46
|
+
if let deadline=req["deadline"] as? Double, Date().timeIntervalSince1970*1000 > deadline { try fail("STALE_WORKSPACE", "desktop authorization expired") }
|
|
47
|
+
if foreground {
|
|
48
|
+
let first=windowRows().first { ($0[kCGWindowLayer as String] as? Int)==0 }
|
|
49
|
+
guard NSWorkspace.shared.frontmostApplication?.processIdentifier == (w[kCGWindowOwnerPID as String] as? Int32), first?[kCGWindowNumber as String] as? Int == w[kCGWindowNumber as String] as? Int else { try fail("CONFLICT", "target must be the frontmost window; focus it then capture again") }
|
|
50
|
+
}
|
|
51
|
+
return w
|
|
52
|
+
}
|
|
53
|
+
func point(_ a: [String: Any], _ x: String, _ y: String, req: [String: Any], rect: CGRect) throws -> CGPoint {
|
|
54
|
+
guard let target=req["target"] as? [String: Any] else { try fail("INVALID_INPUT", "target missing") }
|
|
55
|
+
let px=try number(a,x), py=try number(a,y), width=try number(target,"imageWidth"), height=try number(target,"imageHeight")
|
|
56
|
+
guard width > 0 && height > 0 && px >= 0 && py >= 0 && px < width && py < height else { try fail("INVALID_INPUT", "coordinates must be inside the captured image") }
|
|
57
|
+
return CGPoint(x:rect.minX+px/width*rect.width,y:rect.minY+py/height*rect.height)
|
|
58
|
+
}
|
|
59
|
+
let keyCodes: [String: CGKeyCode] = ["enter":36,"tab":48,"space":49,"backspace":51,"escape":53,"delete":117,"left":123,"right":124,"down":125,"up":126,"home":115,"end":119,"pageup":116,"pagedown":121,"a":0,"b":11,"c":8,"d":2,"e":14,"f":3,"g":5,"h":4,"i":34,"j":38,"k":40,"l":37,"m":46,"n":45,"o":31,"p":35,"q":12,"r":15,"s":1,"t":17,"u":32,"v":9,"w":13,"x":7,"y":16,"z":6,"0":29,"1":18,"2":19,"3":20,"4":21,"5":23,"6":22,"7":26,"8":28,"9":25,"f1":122,"f2":120,"f3":99,"f4":118,"f5":96,"f6":97,"f7":98,"f8":100,"f9":101,"f10":109,"f11":103,"f12":111]
|
|
60
|
+
func flags(_ a: [String: Any]) throws -> CGEventFlags {
|
|
61
|
+
let names=a["modifiers"] as? [String] ?? []; var result:CGEventFlags=[]
|
|
62
|
+
for n in names { switch n { case "command":result.insert(.maskCommand);case "control":result.insert(.maskControl);case "option":result.insert(.maskAlternate);case "shift":result.insert(.maskShift);default:try fail("INVALID_INPUT","invalid modifier") } }
|
|
63
|
+
return result
|
|
64
|
+
}
|
|
65
|
+
func unoccluded(_ point: CGPoint, target: [String: Any]) throws {
|
|
66
|
+
for row in windowRows() {
|
|
67
|
+
if row[kCGWindowNumber as String] as? Int == target[kCGWindowNumber as String] as? Int { return }
|
|
68
|
+
if (row[kCGWindowAlpha as String] as? Double ?? 1) > 0.01 && bounds(row).contains(point) {
|
|
69
|
+
try fail("CONFLICT", "another window or overlay covers the target point; capture again")
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
try fail("CONFLICT", "target window disappeared")
|
|
73
|
+
}
|
|
74
|
+
func emitMouse(_ type: CGEventType, _ p: CGPoint, _ button: CGMouseButton, _ click: Int64=1) throws {
|
|
75
|
+
guard let e=CGEvent(mouseEventSource:CGEventSource(stateID:.privateState),mouseType:type,mouseCursorPosition:p,mouseButton:button) else { try fail("INTERNAL_ERROR","cannot create mouse event") }
|
|
76
|
+
e.setIntegerValueField(.mouseEventClickState,value:click);e.post(tap:.cghidEventTap)
|
|
77
|
+
}
|
|
78
|
+
func ax(_ e: AXUIElement,_ attribute: String) -> CFTypeRef? { var v:CFTypeRef?;guard AXUIElementCopyAttributeValue(e,attribute as CFString,&v) == .success else{return nil};return v }
|
|
79
|
+
func axWindow(_ w:[String:Any]) -> AXUIElement? {
|
|
80
|
+
let app=AXUIElementCreateApplication(w[kCGWindowOwnerPID as String] as? Int32 ?? 0)
|
|
81
|
+
AXUIElementSetMessagingTimeout(app,0.3)
|
|
82
|
+
let target=bounds(w)
|
|
83
|
+
for item in (ax(app,kAXWindowsAttribute) as? [AXUIElement] ?? []) {
|
|
84
|
+
guard let p=ax(item,kAXPositionAttribute), let s=ax(item,kAXSizeAttribute),CFGetTypeID(p)==AXValueGetTypeID(),CFGetTypeID(s)==AXValueGetTypeID() else{continue}
|
|
85
|
+
var point=CGPoint.zero;var size=CGSize.zero
|
|
86
|
+
AXValueGetValue(p as! AXValue,.cgPoint,&point);AXValueGetValue(s as! AXValue,.cgSize,&size)
|
|
87
|
+
if abs(point.x-target.minX)<1 && abs(point.y-target.minY)<1 && abs(size.width-target.width)<1 && abs(size.height-target.height)<1{return item}
|
|
88
|
+
};return nil
|
|
89
|
+
}
|
|
90
|
+
func perform(_ req:[String:Any]) throws -> [String:Any] {
|
|
91
|
+
try screenPermission();try controlPermission()
|
|
92
|
+
guard let a=req["action"] as? [String:Any],let kind=a["kind"] as? String else{try fail("INVALID_INPUT","action required")}
|
|
93
|
+
let w=try validTarget(req,foreground:kind != "focus"),rect=bounds(w)
|
|
94
|
+
if kind == "focus" {
|
|
95
|
+
guard let element=axWindow(w), let app=NSRunningApplication(processIdentifier:w[kCGWindowOwnerPID as String] as? Int32 ?? 0) else{try fail("CONFLICT","cannot identify the accessibility window")}
|
|
96
|
+
guard AXUIElementPerformAction(element,kAXRaiseAction as CFString) == .success else{try fail("FORBIDDEN","application refused window focus")}
|
|
97
|
+
guard app.activate(options:[]) else{try fail("FORBIDDEN","application refused activation")}
|
|
98
|
+
return ["posted":true,"note":"focus requested; capture again before input"]
|
|
99
|
+
}
|
|
100
|
+
switch kind {
|
|
101
|
+
case "move", "click":
|
|
102
|
+
let p=try point(a,"x","y",req:req,rect:rect)
|
|
103
|
+
try unoccluded(p,target:w)
|
|
104
|
+
if kind == "move" {try emitMouse(.mouseMoved,p,.left)} else {
|
|
105
|
+
let right=(a["button"] as? String) == "right",button:CGMouseButton=right ? .right:.left,down:CGEventType=right ? .rightMouseDown:.leftMouseDown,up:CGEventType=right ? .rightMouseUp:.leftMouseUp
|
|
106
|
+
let count=try integer(a,"count");guard (1...2).contains(count) else{try fail("INVALID_INPUT","invalid click count")}
|
|
107
|
+
for i in 1...count { _=try validTarget(req,foreground:true);try emitMouse(down,p,button,Int64(i));try emitMouse(up,p,button,Int64(i)) }
|
|
108
|
+
}
|
|
109
|
+
case "drag":
|
|
110
|
+
let from=try point(a,"x","y",req:req,rect:rect),to=try point(a,"toX","toY",req:req,rect:rect)
|
|
111
|
+
try unoccluded(from,target:w);try unoccluded(to,target:w)
|
|
112
|
+
try emitMouse(.leftMouseDown,from,.left)
|
|
113
|
+
defer { try? emitMouse(.leftMouseUp,to,.left) }
|
|
114
|
+
for i in 1...10 { _=try validTarget(req,foreground:true);let t=Double(i)/10;try emitMouse(.leftMouseDragged,CGPoint(x:from.x+(to.x-from.x)*t,y:from.y+(to.y-from.y)*t),.left);Thread.sleep(forTimeInterval:0.01) }
|
|
115
|
+
case "scroll":
|
|
116
|
+
let p=try point(a,"x","y",req:req,rect:rect),dx=try integer(a,"deltaX"),dy=try integer(a,"deltaY")
|
|
117
|
+
guard dx >= -1000 && dx <= 1000 && dy >= -1000 && dy <= 1000 else{try fail("INVALID_INPUT","scroll exceeds limit")}
|
|
118
|
+
try unoccluded(p,target:w);try emitMouse(.mouseMoved,p,.left)
|
|
119
|
+
guard let e=CGEvent(scrollWheelEvent2Source:CGEventSource(stateID:.privateState),units:.pixel,wheelCount:2,wheel1:Int32(dy),wheel2:Int32(dx),wheel3:0) else{try fail("INTERNAL_ERROR","cannot create scroll event")}
|
|
120
|
+
e.location=p;e.post(tap:.cghidEventTap)
|
|
121
|
+
case "key":
|
|
122
|
+
guard let key=a["key"] as? String,let code=keyCodes[key] else{try fail("INVALID_INPUT","unsupported key")}
|
|
123
|
+
let modifiers=try flags(a)
|
|
124
|
+
for down in [true,false] {guard let e=CGEvent(keyboardEventSource:CGEventSource(stateID:.privateState),virtualKey:code,keyDown:down) else{try fail("INTERNAL_ERROR","cannot create keyboard event")};e.flags=modifiers;e.post(tap:.cghidEventTap)}
|
|
125
|
+
case "type":
|
|
126
|
+
guard let text=a["text"] as? String,!text.isEmpty,text.utf16.count<=2000 else{try fail("INVALID_INPUT","text exceeds 2000 UTF-16 units")}
|
|
127
|
+
// Bounded UTF-16 chunks preserve surrogate pairs; no clipboard changes.
|
|
128
|
+
var chunks:[[UInt16]]=[],current:[UInt16]=[]
|
|
129
|
+
for scalar in text.unicodeScalars {
|
|
130
|
+
let units=Array(String(scalar).utf16)
|
|
131
|
+
if current.count+units.count>16 {chunks.append(current);current=[]}
|
|
132
|
+
current.append(contentsOf:units)
|
|
133
|
+
}
|
|
134
|
+
if !current.isEmpty {chunks.append(current)}
|
|
135
|
+
for units in chunks {
|
|
136
|
+
_=try validTarget(req,foreground:true)
|
|
137
|
+
for down in [true,false] {
|
|
138
|
+
guard let e=CGEvent(keyboardEventSource:CGEventSource(stateID:.privateState),virtualKey:0,keyDown:down) else{try fail("INTERNAL_ERROR","cannot create Unicode event")}
|
|
139
|
+
units.withUnsafeBufferPointer {e.keyboardSetUnicodeString(stringLength:units.count,unicodeString:$0.baseAddress!)}
|
|
140
|
+
e.post(tap:.cghidEventTap)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
default:try fail("INVALID_INPUT","unsupported action")
|
|
144
|
+
}
|
|
145
|
+
return ["posted":true,"note":"OS events posted; capture again to verify the application result"]
|
|
146
|
+
}
|
|
147
|
+
@available(macOS 14.0, *)
|
|
148
|
+
func capture(_ req:[String:Any]) async throws -> [String:Any] {
|
|
149
|
+
try screenPermission();let apps=try allowedApps(req),id=try integer(req,"windowId"),row=try window(id,apps:apps)
|
|
150
|
+
let content=try await SCShareableContent.excludingDesktopWindows(true,onScreenWindowsOnly:true)
|
|
151
|
+
guard let win=content.windows.first(where: {Int($0.windowID)==id && $0.owningApplication?.processID == row[kCGWindowOwnerPID as String] as? Int32}) else{try fail("CONFLICT","window is no longer capturable")}
|
|
152
|
+
let r=bounds(row),edge=try integer(req,"maxEdge");guard (320...2000).contains(edge) else{try fail("INVALID_INPUT","invalid image size")}
|
|
153
|
+
let scale=min(1,Double(edge)/max(r.width,r.height));let config=SCStreamConfiguration()
|
|
154
|
+
config.width=max(1,Int(r.width*scale));config.height=max(1,Int(r.height*scale));config.showsCursor=false;config.ignoreShadowsSingleWindow=true
|
|
155
|
+
let image=try await SCScreenshotManager.captureImage(contentFilter:SCContentFilter(desktopIndependentWindow:win),configuration:config)
|
|
156
|
+
let now=try window(id,apps:apps)
|
|
157
|
+
guard bounds(now)==r else{try fail("CONFLICT","window changed during capture")}
|
|
158
|
+
let bitmap=NSBitmapImageRep(cgImage:image)
|
|
159
|
+
guard let bytes=bitmap.representation(using:.jpeg,properties:[.compressionFactor:0.75]),bytes.count<=3*1024*1024 else{try fail("RESOURCE_LIMIT","captured image exceeds 3 MiB")}
|
|
160
|
+
var result=describe(now);result["imageWidth"]=image.width;result["imageHeight"]=image.height;result["mimeType"]="image/jpeg";result["image"]=bytes.base64EncodedString()
|
|
161
|
+
if req["ocr"] as? Bool == true {
|
|
162
|
+
let request=VNRecognizeTextRequest();request.recognitionLevel = .accurate;request.usesLanguageCorrection=false
|
|
163
|
+
try VNImageRequestHandler(cgImage:image,options:[:]).perform([request])
|
|
164
|
+
let observations=request.results ?? []
|
|
165
|
+
result["ocr"]=observations.prefix(150).compactMap { o -> [String:Any]? in
|
|
166
|
+
guard let c=o.topCandidates(1).first else{return nil};let b=o.boundingBox
|
|
167
|
+
return ["text":clipped(c.string,500),"confidence":c.confidence,"x":b.minX*Double(image.width),"y":(1-b.maxY)*Double(image.height),"width":b.width*Double(image.width),"height":b.height*Double(image.height)]
|
|
168
|
+
}
|
|
169
|
+
result["ocrTruncated"]=observations.count>150
|
|
170
|
+
}
|
|
171
|
+
return result
|
|
172
|
+
}
|
|
173
|
+
func accessibility(_ req:[String:Any]) throws -> [String:Any] {
|
|
174
|
+
try screenPermission();try controlPermission();let w=try validTarget(req,foreground:false)
|
|
175
|
+
guard let root=axWindow(w) else{try fail("NOT_SUPPORTED","application does not expose this window through Accessibility")}
|
|
176
|
+
var queue:[(AXUIElement,Int)]=[(root,0)],rows:[[String:Any]]=[];let started=Date()
|
|
177
|
+
while !queue.isEmpty && rows.count<100 && Date().timeIntervalSince(started)<1.5 {
|
|
178
|
+
let (e,depth)=queue.removeFirst();AXUIElementSetMessagingTimeout(e,0.15)
|
|
179
|
+
let role=ax(e,kAXRoleAttribute) as? String ?? "unknown",subrole=ax(e,kAXSubroleAttribute) as? String ?? ""
|
|
180
|
+
// Never read value/title/children of secure text fields.
|
|
181
|
+
if subrole == kAXSecureTextFieldSubrole as String {rows.append(["role":role,"redacted":true,"depth":depth]);continue}
|
|
182
|
+
var row:[String:Any]=["role":role,"depth":depth]
|
|
183
|
+
for (key,attr) in [("title",kAXTitleAttribute),("description",kAXDescriptionAttribute),("value",kAXValueAttribute)] {if let s=ax(e,attr) as? String {row[key]=clipped(s,300)}}
|
|
184
|
+
rows.append(row)
|
|
185
|
+
if depth<6 {for child in (ax(e,kAXChildrenAttribute) as? [AXUIElement] ?? []).prefix(max(0,100-queue.count-rows.count)) {queue.append((child,depth+1))}}
|
|
186
|
+
}
|
|
187
|
+
return ["elements":rows,"truncated":!queue.isEmpty]
|
|
188
|
+
}
|
|
189
|
+
@main struct DesktopHelper {
|
|
190
|
+
static func main() async {
|
|
191
|
+
do {
|
|
192
|
+
let bytes=FileHandle.standardInput.readDataToEndOfFile()
|
|
193
|
+
guard bytes.count <= 64*1024,let req=try JSONSerialization.jsonObject(with:bytes) as? [String:Any],let op=req["op"] as? String else{try fail("INVALID_INPUT","invalid desktop request")}
|
|
194
|
+
var data:[String:Any]
|
|
195
|
+
switch op {
|
|
196
|
+
case "status","requestPermissions":
|
|
197
|
+
if op == "requestPermissions" {_=CGRequestScreenCaptureAccess();let options=[kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String:true] as CFDictionary;_=AXIsProcessTrustedWithOptions(options)}
|
|
198
|
+
data=["screenRecording":CGPreflightScreenCaptureAccess(),"accessibility":AXIsProcessTrusted(),"platform":"darwin","backend":"ScreenCaptureKit/CGEvent/AX/Vision"]
|
|
199
|
+
case "windows":try screenPermission();let apps=try allowedApps(req);let rows=windowRows().filter { w in guard let pid=w[kCGWindowOwnerPID as String] as? Int32,let app=appID(pid) else{return false};return apps.contains(app) && (w[kCGWindowLayer as String] as? Int)==0 && bounds(w).width>=10 && bounds(w).height>=10 };data=["windows":rows.prefix(100).map(describe),"truncated":rows.count>100]
|
|
200
|
+
case "capture":if #available(macOS 14.0, *){data=try await capture(req)}else{try fail("NOT_SUPPORTED","macOS 14 or newer required")}
|
|
201
|
+
case "action":data=try perform(req)
|
|
202
|
+
case "accessibility":data=try accessibility(req)
|
|
203
|
+
default:try fail("INVALID_INPUT","unknown operation")
|
|
204
|
+
}
|
|
205
|
+
let out=try JSONSerialization.data(withJSONObject:["ok":true,"data":data],options:[.sortedKeys]);FileHandle.standardOutput.write(out)
|
|
206
|
+
} catch {
|
|
207
|
+
let f=error as? Failure ?? Failure(code:"INTERNAL_ERROR",message:"macOS desktop operation failed; check permissions and capture again")
|
|
208
|
+
let out=(try? JSONSerialization.data(withJSONObject:["ok":false,"error":["code":f.code,"message":f.message]])) ?? Data();FileHandle.standardOutput.write(out)
|
|
209
|
+
exit(1)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dodo-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "Arthittakun",
|
|
5
|
+
"description": "DODO — local-first MCP server with multi-project coding, AI providers, sub-agents, context, memory, media and workflow tools; embedded OAuth and workspace permissions.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=22.12.0"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"dodo": "dist/cli/main.js",
|
|
13
|
+
"dodo-media-setup": "scripts/setup-multimodal.mjs"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"schemas",
|
|
21
|
+
"examples",
|
|
22
|
+
"docs/ARCHITECTURE.md",
|
|
23
|
+
"docs/ASSISTANCE.md",
|
|
24
|
+
"docs/AGENT_RUNTIME.md",
|
|
25
|
+
"docs/AI_PROVIDERS.md",
|
|
26
|
+
"docs/AUTH.md",
|
|
27
|
+
"docs/BRAIN.md",
|
|
28
|
+
"docs/COMPATIBILITY.md",
|
|
29
|
+
"docs/CONTEXT.md",
|
|
30
|
+
"docs/CONFIRMATION.md",
|
|
31
|
+
"docs/DESKTOP.md",
|
|
32
|
+
"docs/EVALUATION.md",
|
|
33
|
+
"docs/LARGE_INPUTS.md",
|
|
34
|
+
"docs/LSP.md",
|
|
35
|
+
"docs/MANUAL_ACCEPTANCE.md",
|
|
36
|
+
"docs/MEMORY.md",
|
|
37
|
+
"docs/MULTIMODAL.md",
|
|
38
|
+
"docs/PROJECTS.md",
|
|
39
|
+
"docs/RESOURCES.md",
|
|
40
|
+
"docs/RUNTIME.md",
|
|
41
|
+
"docs/RELEASE_1.0.0.md",
|
|
42
|
+
"docs/RELEASE_NOTES.md",
|
|
43
|
+
"docs/SCHEDULES.md",
|
|
44
|
+
"docs/SECURITY.md",
|
|
45
|
+
"docs/TEST_REPORT.md",
|
|
46
|
+
"docs/TUNNEL.md",
|
|
47
|
+
"docs/WEB_CLIENTS.md",
|
|
48
|
+
"docs/WINDOWS.md",
|
|
49
|
+
"docs/adr",
|
|
50
|
+
"README.md",
|
|
51
|
+
"LICENSE",
|
|
52
|
+
"native",
|
|
53
|
+
"scripts/setup-multimodal.mjs",
|
|
54
|
+
"scripts/guard-publish.mjs"
|
|
55
|
+
],
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "node scripts/clean-build-artifacts.mjs && tsc -p tsconfig.build.json && node scripts/emit-schemas.mjs && node scripts/vendor-ui.mjs && node scripts/copy-ui.mjs",
|
|
58
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
59
|
+
"lint": "eslint src tests scripts",
|
|
60
|
+
"test:unit": "vitest run tests/unit",
|
|
61
|
+
"test:integration": "vitest run tests/integration",
|
|
62
|
+
"test:security": "vitest run tests/security",
|
|
63
|
+
"test:compat": "vitest run tests/compatibility",
|
|
64
|
+
"test:pack": "vitest run tests/packaging",
|
|
65
|
+
"test:bench": "node scripts/dodo-bench.mjs",
|
|
66
|
+
"test:linux:docker": "node scripts/test-linux-docker.mjs",
|
|
67
|
+
"bench": "npm run build && node scripts/dodo-bench.mjs",
|
|
68
|
+
"test:windows": "vitest run tests/unit/windowsPlatform.test.ts tests/unit/windowsAclContract.test.ts tests/integration/windowsRuntime.test.ts tests/security/windowsNative.test.ts tests/security/windowsAclOwner.test.ts tests/security/ipcAuthentication.test.ts tests/security/rollbackPathPolicy.test.ts",
|
|
69
|
+
"test:all": "npm run typecheck && npm run lint && vitest run tests/unit tests/integration tests/security tests/compatibility && npm run test:pack",
|
|
70
|
+
"release:gate": "node scripts/release-gate.mjs --allow-dirty",
|
|
71
|
+
"release:gate:ci": "node scripts/release-gate.mjs",
|
|
72
|
+
"release:gate:strict": "node scripts/release-gate.mjs --release",
|
|
73
|
+
"prepublishOnly": "node scripts/guard-publish.mjs",
|
|
74
|
+
"desktop:setup": "node dist/cli/main.js desktop setup",
|
|
75
|
+
"multimodal:setup": "node scripts/setup-multimodal.mjs",
|
|
76
|
+
"test:desktop:native": "npm run build && node scripts/test-desktop-native.mjs"
|
|
77
|
+
},
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"@modelcontextprotocol/express": "2.0.0",
|
|
80
|
+
"@modelcontextprotocol/node": "2.0.0",
|
|
81
|
+
"@modelcontextprotocol/server": "2.0.0",
|
|
82
|
+
"better-sqlite3": "13.0.3",
|
|
83
|
+
"commander": "15.0.0",
|
|
84
|
+
"cron-parser": "5.10.0",
|
|
85
|
+
"diff": "^9.0.0",
|
|
86
|
+
"express": "5.2.1",
|
|
87
|
+
"ignore": "^7.0.9",
|
|
88
|
+
"jose": "6.2.12",
|
|
89
|
+
"oidc-provider": "9.12.2",
|
|
90
|
+
"picomatch": "^4.0.7",
|
|
91
|
+
"playwright": "1.63.0",
|
|
92
|
+
"sharp": "0.35.4",
|
|
93
|
+
"typescript": "5.9.3",
|
|
94
|
+
"zod": "^4.2.0"
|
|
95
|
+
},
|
|
96
|
+
"devDependencies": {
|
|
97
|
+
"@modelcontextprotocol/client": "2.0.0",
|
|
98
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
99
|
+
"@types/diff": "^7.0.2",
|
|
100
|
+
"@types/express": "^5.0.0",
|
|
101
|
+
"@types/node": "^22.15.0",
|
|
102
|
+
"@types/oidc-provider": "^9.1.0",
|
|
103
|
+
"@types/picomatch": "^4.0.3",
|
|
104
|
+
"eslint": "^9.39.0",
|
|
105
|
+
"pyright": "^1.1.413",
|
|
106
|
+
"sweetalert2": "11.26.25",
|
|
107
|
+
"typescript-eslint": "^8.70.0",
|
|
108
|
+
"vitest": "5.0.0"
|
|
109
|
+
},
|
|
110
|
+
"keywords": [
|
|
111
|
+
"dodo",
|
|
112
|
+
"mcp",
|
|
113
|
+
"mcp-server",
|
|
114
|
+
"model-context-protocol",
|
|
115
|
+
"coding-tools",
|
|
116
|
+
"ai-coding",
|
|
117
|
+
"developer-tools",
|
|
118
|
+
"local-first",
|
|
119
|
+
"stdio",
|
|
120
|
+
"oauth",
|
|
121
|
+
"chatgpt",
|
|
122
|
+
"codex",
|
|
123
|
+
"typescript",
|
|
124
|
+
"semantic-search",
|
|
125
|
+
"project-memory",
|
|
126
|
+
"code-editing",
|
|
127
|
+
"parallel-jobs",
|
|
128
|
+
"cron",
|
|
129
|
+
"scheduled-tasks",
|
|
130
|
+
"owner-consent",
|
|
131
|
+
"multimodal",
|
|
132
|
+
"browser-automation",
|
|
133
|
+
"video",
|
|
134
|
+
"speech-to-text",
|
|
135
|
+
"workflow"
|
|
136
|
+
],
|
|
137
|
+
"repository": {
|
|
138
|
+
"type": "git",
|
|
139
|
+
"url": "git+https://github.com/arthittakun/dodo-mcp.git"
|
|
140
|
+
},
|
|
141
|
+
"homepage": "https://github.com/arthittakun/dodo-mcp#readme",
|
|
142
|
+
"bugs": {
|
|
143
|
+
"url": "https://github.com/arthittakun/dodo-mcp/issues"
|
|
144
|
+
}
|
|
145
|
+
}
|