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,291 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { DodoError } from '../errors.js';
|
|
4
|
+
import { newId } from '../util/hash.js';
|
|
5
|
+
import { mintWorkspaceId } from '../workspace/identity.js';
|
|
6
|
+
import { resolveWorkspaceRoot } from '../workspace/root.js';
|
|
7
|
+
import { fileIdentityBigInt, parseFileIdentity } from '../platform/fileIdentity.js';
|
|
8
|
+
export const PROJECT_METADATA_VERSION = 2;
|
|
9
|
+
const MAX_PROJECTS = 1000;
|
|
10
|
+
const PROJECT_ID = /^prj_[0-9a-hjkmnp-tv-z]{8,64}$/;
|
|
11
|
+
const WORKSPACE_ID = /^ws_[a-f0-9]{20}$/;
|
|
12
|
+
function samePath(a, b) {
|
|
13
|
+
return process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
14
|
+
}
|
|
15
|
+
function asFiniteInteger(value) {
|
|
16
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
17
|
+
}
|
|
18
|
+
function asBirthtimeNs(value) {
|
|
19
|
+
if (typeof value !== 'string' || !/^[1-9][0-9]{0,30}$/.test(value))
|
|
20
|
+
return undefined;
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function safeDisplayName(input, root) {
|
|
24
|
+
const name = (input ?? path.basename(root)).trim();
|
|
25
|
+
if (name.length < 1 || name.length > 120 || /[\u0000-\u001f\u007f]/.test(name)) {
|
|
26
|
+
throw new DodoError('INVALID_INPUT', 'project display name must be 1..120 characters without control characters');
|
|
27
|
+
}
|
|
28
|
+
return name;
|
|
29
|
+
}
|
|
30
|
+
function validateProjectId(projectId) {
|
|
31
|
+
if (!PROJECT_ID.test(projectId))
|
|
32
|
+
throw new DodoError('INVALID_INPUT', 'invalid project ID');
|
|
33
|
+
}
|
|
34
|
+
function rawRows(db, includeRemoved) {
|
|
35
|
+
return db.prepare(`SELECT id, workspace_id, canonical_root, display_name, root_dev, root_ino, root_birthtime_ns,
|
|
36
|
+
metadata_version, created_at, updated_at, removed_at
|
|
37
|
+
FROM project_registry
|
|
38
|
+
${includeRemoved ? '' : 'WHERE removed_at IS NULL'}
|
|
39
|
+
ORDER BY updated_at DESC, id ASC
|
|
40
|
+
LIMIT ?`).all(MAX_PROJECTS + 1);
|
|
41
|
+
}
|
|
42
|
+
function inspectAvailability(root, dev, ino, birthtimeNs) {
|
|
43
|
+
let link;
|
|
44
|
+
try {
|
|
45
|
+
link = fs.lstatSync(root);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error.code === 'ENOENT')
|
|
49
|
+
return { availability: 'missing', statusText: 'ไม่พบ path ที่บันทึกไว้' };
|
|
50
|
+
return { availability: 'inaccessible', statusText: 'ไม่สามารถตรวจสอบ path ได้' };
|
|
51
|
+
}
|
|
52
|
+
if (link.isSymbolicLink())
|
|
53
|
+
return { availability: 'symlinked', statusText: 'path ที่บันทึกไว้ถูกแทนด้วย symbolic link' };
|
|
54
|
+
let real;
|
|
55
|
+
let stat;
|
|
56
|
+
try {
|
|
57
|
+
real = fs.realpathSync.native(root);
|
|
58
|
+
stat = fs.statSync(real, { bigint: true });
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return { availability: 'inaccessible', statusText: 'ไม่สามารถตรวจสอบ directory identity ได้' };
|
|
62
|
+
}
|
|
63
|
+
if (!samePath(real, root) ||
|
|
64
|
+
!stat.isDirectory() ||
|
|
65
|
+
stat.dev !== fileIdentityBigInt(dev) ||
|
|
66
|
+
stat.ino !== fileIdentityBigInt(ino) ||
|
|
67
|
+
stat.birthtimeNs.toString() !== birthtimeNs) {
|
|
68
|
+
return { availability: 'replaced', statusText: 'path ชี้ไปยัง directory identity อื่น' };
|
|
69
|
+
}
|
|
70
|
+
return { availability: 'ready', statusText: 'พร้อมใช้งาน' };
|
|
71
|
+
}
|
|
72
|
+
function invalidProject(row) {
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
return {
|
|
75
|
+
schemaVersion: 1,
|
|
76
|
+
projectId: typeof row.id === 'string' ? row.id : 'prj_invalid',
|
|
77
|
+
workspaceId: typeof row.workspace_id === 'string' ? row.workspace_id : 'ws_invalid',
|
|
78
|
+
root: typeof row.canonical_root === 'string' ? row.canonical_root : '(invalid path)',
|
|
79
|
+
displayName: typeof row.display_name === 'string' ? row.display_name : '(invalid project)',
|
|
80
|
+
createdAt: asFiniteInteger(row.created_at) ?? now,
|
|
81
|
+
updatedAt: asFiniteInteger(row.updated_at) ?? now,
|
|
82
|
+
removedAt: row.removed_at === null ? null : asFiniteInteger(row.removed_at) ?? null,
|
|
83
|
+
availability: 'invalid',
|
|
84
|
+
available: false,
|
|
85
|
+
statusText: 'registry metadata ไม่ถูกต้อง; ตรวจสอบและนำรายการนี้ออกก่อนใช้งาน',
|
|
86
|
+
identity: {
|
|
87
|
+
dev: parseFileIdentity(row.root_dev) ?? 0,
|
|
88
|
+
ino: parseFileIdentity(row.root_ino) ?? 0,
|
|
89
|
+
birthtimeNs: asBirthtimeNs(row.root_birthtime_ns) ?? '0',
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function materialize(row) {
|
|
94
|
+
const id = typeof row.id === 'string' && PROJECT_ID.test(row.id) ? row.id : undefined;
|
|
95
|
+
const workspaceId = typeof row.workspace_id === 'string' && WORKSPACE_ID.test(row.workspace_id) ? row.workspace_id : undefined;
|
|
96
|
+
const root = typeof row.canonical_root === 'string' && path.isAbsolute(row.canonical_root) ? row.canonical_root : undefined;
|
|
97
|
+
const displayName = typeof row.display_name === 'string' && row.display_name.length >= 1 && row.display_name.length <= 120 && !/[\u0000-\u001f\u007f]/.test(row.display_name) ? row.display_name : undefined;
|
|
98
|
+
const dev = parseFileIdentity(row.root_dev);
|
|
99
|
+
const ino = parseFileIdentity(row.root_ino);
|
|
100
|
+
const birthtimeNs = asBirthtimeNs(row.root_birthtime_ns);
|
|
101
|
+
const createdAt = asFiniteInteger(row.created_at);
|
|
102
|
+
const updatedAt = asFiniteInteger(row.updated_at);
|
|
103
|
+
const removedAt = row.removed_at === null ? null : asFiniteInteger(row.removed_at);
|
|
104
|
+
if (!id || !workspaceId || !root || !displayName || dev === undefined || ino === undefined || !birthtimeNs || createdAt === undefined || updatedAt === undefined || removedAt === undefined || row.metadata_version !== PROJECT_METADATA_VERSION) {
|
|
105
|
+
return invalidProject(row);
|
|
106
|
+
}
|
|
107
|
+
const status = removedAt === null
|
|
108
|
+
? inspectAvailability(root, dev, ino, birthtimeNs)
|
|
109
|
+
: { availability: 'removed', statusText: 'นำออกจาก registry แล้ว; ไฟล์และประวัติไม่ได้ถูกลบ' };
|
|
110
|
+
return {
|
|
111
|
+
schemaVersion: 1,
|
|
112
|
+
projectId: id,
|
|
113
|
+
workspaceId,
|
|
114
|
+
root,
|
|
115
|
+
displayName,
|
|
116
|
+
createdAt,
|
|
117
|
+
updatedAt,
|
|
118
|
+
removedAt,
|
|
119
|
+
availability: status.availability,
|
|
120
|
+
available: removedAt === null && status.availability === 'ready',
|
|
121
|
+
statusText: status.statusText,
|
|
122
|
+
identity: { dev, ino, birthtimeNs },
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function resolveInput(candidate) {
|
|
126
|
+
if (typeof candidate !== 'string' || candidate.length < 1 || candidate.length > 4096 || candidate.includes('\0') || !path.isAbsolute(candidate)) {
|
|
127
|
+
throw new DodoError('INVALID_INPUT', 'project path must be an absolute path');
|
|
128
|
+
}
|
|
129
|
+
const root = resolveWorkspaceRoot(candidate, { allowUnsafe: false });
|
|
130
|
+
if (!root.birthtimeNs) {
|
|
131
|
+
throw new DodoError('NOT_SUPPORTED', 'project registry requires a filesystem with stable directory birth-time metadata', {
|
|
132
|
+
recovery: 'move the project to a local APFS, ext4, NTFS, or another filesystem that exposes directory birth time',
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return { ...root, birthtimeNs: root.birthtimeNs };
|
|
136
|
+
}
|
|
137
|
+
/** Owner-only installation registry. It never changes workspace authority. */
|
|
138
|
+
export class ProjectRegistry {
|
|
139
|
+
store;
|
|
140
|
+
constructor(store) {
|
|
141
|
+
this.store = store;
|
|
142
|
+
}
|
|
143
|
+
list(options = {}) {
|
|
144
|
+
try {
|
|
145
|
+
const rows = rawRows(this.store.db, options.includeRemoved ?? false);
|
|
146
|
+
if (rows.length > MAX_PROJECTS)
|
|
147
|
+
throw new DodoError('RESOURCE_LIMIT', `project registry exceeds ${MAX_PROJECTS} entries`);
|
|
148
|
+
return rows.map(materialize);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
if (error instanceof DodoError)
|
|
152
|
+
throw error;
|
|
153
|
+
throw registryFailure('read');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
get(projectId, options = {}) {
|
|
157
|
+
validateProjectId(projectId);
|
|
158
|
+
let row;
|
|
159
|
+
try {
|
|
160
|
+
row = this.store.db.prepare(`SELECT id, workspace_id, canonical_root, display_name, root_dev, root_ino, root_birthtime_ns,
|
|
161
|
+
metadata_version, created_at, updated_at, removed_at
|
|
162
|
+
FROM project_registry WHERE id = ? ${options.includeRemoved ? '' : 'AND removed_at IS NULL'}`).get(projectId);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
throw registryFailure('read');
|
|
166
|
+
}
|
|
167
|
+
if (!row)
|
|
168
|
+
throw new DodoError('NOT_FOUND', `project not found: ${projectId}`);
|
|
169
|
+
return materialize(row);
|
|
170
|
+
}
|
|
171
|
+
add(candidate, displayName) {
|
|
172
|
+
const root = resolveInput(candidate);
|
|
173
|
+
const name = safeDisplayName(displayName, root.root);
|
|
174
|
+
const workspaceId = mintWorkspaceId(this.store.installSecret(), root.root);
|
|
175
|
+
let result;
|
|
176
|
+
const tx = this.store.db.transaction(() => {
|
|
177
|
+
const byRoot = this.store.db.prepare('SELECT * FROM project_registry WHERE canonical_root = ? AND removed_at IS NULL').get(root.root);
|
|
178
|
+
if (byRoot) {
|
|
179
|
+
const current = materialize(byRoot);
|
|
180
|
+
if (current.availability === 'invalid')
|
|
181
|
+
throw new DodoError('MIGRATION_REVIEW_REQUIRED', 'project registry row is invalid', { detail: { projectId: current.projectId } });
|
|
182
|
+
if (current.identity.dev !== root.dev || current.identity.ino !== root.ino || current.identity.birthtimeNs !== root.birthtimeNs) {
|
|
183
|
+
throw new DodoError('CONFLICT', 'registered project path now points to another directory identity', {
|
|
184
|
+
recovery: `review ${current.projectId}, remove it explicitly, then add the replacement as a new project`,
|
|
185
|
+
detail: { projectId: current.projectId, availability: current.availability },
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
if (displayName !== undefined && current.displayName !== name) {
|
|
189
|
+
const now = Date.now();
|
|
190
|
+
this.store.db.prepare('UPDATE project_registry SET display_name = ?, updated_at = ? WHERE id = ?').run(name, now, current.projectId);
|
|
191
|
+
result = { changed: true, relocated: false, project: this.get(current.projectId) };
|
|
192
|
+
this.audit(result, 'updated');
|
|
193
|
+
}
|
|
194
|
+
else
|
|
195
|
+
result = { changed: false, relocated: false, project: current };
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const byIdentity = this.store.db.prepare('SELECT * FROM project_registry WHERE root_dev = ? AND root_ino = ? AND removed_at IS NULL').get(root.dev, root.ino);
|
|
199
|
+
if (byIdentity) {
|
|
200
|
+
const current = materialize(byIdentity);
|
|
201
|
+
if (current.availability === 'invalid')
|
|
202
|
+
throw new DodoError('MIGRATION_REVIEW_REQUIRED', 'project registry row is invalid', { detail: { projectId: current.projectId } });
|
|
203
|
+
if (current.identity.birthtimeNs !== root.birthtimeNs) {
|
|
204
|
+
throw new DodoError('CONFLICT', 'a filesystem inode was reused by another directory generation', {
|
|
205
|
+
recovery: `review ${current.projectId}, remove it explicitly, then add the replacement as a new project`,
|
|
206
|
+
detail: { projectId: current.projectId, availability: current.availability },
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (samePath(current.root, root.root)) {
|
|
210
|
+
result = { changed: false, relocated: false, project: current };
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (current.availability !== 'missing') {
|
|
214
|
+
throw new DodoError('CONFLICT', 'the same directory identity is already registered at another active path', { detail: { projectId: current.projectId } });
|
|
215
|
+
}
|
|
216
|
+
const now = Date.now();
|
|
217
|
+
this.store.db.prepare('UPDATE project_registry SET workspace_id = ?, canonical_root = ?, display_name = ?, root_birthtime_ns = ?, updated_at = ? WHERE id = ?')
|
|
218
|
+
.run(workspaceId, root.root, displayName === undefined ? current.displayName : name, root.birthtimeNs, now, current.projectId);
|
|
219
|
+
result = { changed: true, relocated: true, project: this.get(current.projectId) };
|
|
220
|
+
this.audit(result, 'relocated');
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const count = this.store.db.prepare('SELECT COUNT(*) AS count FROM project_registry WHERE removed_at IS NULL').get().count;
|
|
224
|
+
if (count >= MAX_PROJECTS)
|
|
225
|
+
throw new DodoError('RESOURCE_LIMIT', `project registry is limited to ${MAX_PROJECTS} active entries`);
|
|
226
|
+
const now = Date.now();
|
|
227
|
+
const projectId = newId('prj', 12);
|
|
228
|
+
this.store.db.prepare(`INSERT INTO project_registry
|
|
229
|
+
(id, workspace_id, canonical_root, display_name, root_dev, root_ino, root_birthtime_ns, metadata_version, created_at, updated_at, removed_at)
|
|
230
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)`).run(projectId, workspaceId, root.root, name, root.dev, root.ino, root.birthtimeNs, PROJECT_METADATA_VERSION, now, now);
|
|
231
|
+
result = { changed: true, relocated: false, project: this.get(projectId) };
|
|
232
|
+
this.audit(result, 'added');
|
|
233
|
+
});
|
|
234
|
+
try {
|
|
235
|
+
tx.immediate();
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
if (error instanceof DodoError)
|
|
239
|
+
throw error;
|
|
240
|
+
const code = error.code;
|
|
241
|
+
if (code === 'SQLITE_CONSTRAINT_UNIQUE') {
|
|
242
|
+
const existing = this.store.db.prepare('SELECT * FROM project_registry WHERE canonical_root = ? AND removed_at IS NULL').get(root.root);
|
|
243
|
+
if (existing)
|
|
244
|
+
return { changed: false, relocated: false, project: materialize(existing) };
|
|
245
|
+
throw new DodoError('CONFLICT', 'project registry changed concurrently; retry the command');
|
|
246
|
+
}
|
|
247
|
+
throw registryFailure('update');
|
|
248
|
+
}
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
remove(projectId) {
|
|
252
|
+
validateProjectId(projectId);
|
|
253
|
+
const current = this.get(projectId);
|
|
254
|
+
try {
|
|
255
|
+
const tx = this.store.db.transaction(() => {
|
|
256
|
+
const job = this.store.db.prepare("SELECT 1 FROM jobs WHERE workspace_id=? AND status='running' LIMIT 1").get(current.workspaceId);
|
|
257
|
+
const agent = this.store.db.prepare("SELECT 1 FROM ai_runs WHERE workspace_id=? AND status NOT IN ('completed','failed','canceled') LIMIT 1").get(current.workspaceId);
|
|
258
|
+
if (job || agent)
|
|
259
|
+
throw new DodoError('CONFLICT', 'project has unfinished jobs or agent runs; finish or cancel them before removal');
|
|
260
|
+
const now = Date.now();
|
|
261
|
+
const changed = this.store.db.prepare('UPDATE project_registry SET removed_at = ?, updated_at = ? WHERE id = ? AND removed_at IS NULL').run(now, now, projectId);
|
|
262
|
+
if (changed.changes !== 1)
|
|
263
|
+
throw new DodoError('CONFLICT', 'project registry changed concurrently; refresh and retry');
|
|
264
|
+
this.store.audit({ principal: 'local-project-owner', workspaceId: current.workspaceId, tool: 'local.project.remove', paths: [current.root], refId: projectId, result: 'removed' });
|
|
265
|
+
});
|
|
266
|
+
tx.immediate();
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
if (error instanceof DodoError)
|
|
270
|
+
throw error;
|
|
271
|
+
throw registryFailure('update');
|
|
272
|
+
}
|
|
273
|
+
return this.get(projectId, { includeRemoved: true });
|
|
274
|
+
}
|
|
275
|
+
audit(result, outcome) {
|
|
276
|
+
this.store.audit({
|
|
277
|
+
principal: 'local-project-owner',
|
|
278
|
+
workspaceId: result.project.workspaceId,
|
|
279
|
+
tool: 'local.project.add',
|
|
280
|
+
paths: [result.project.root],
|
|
281
|
+
refId: result.project.projectId,
|
|
282
|
+
result: outcome,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function registryFailure(operation) {
|
|
287
|
+
return new DodoError('INTERNAL_ERROR', `project registry ${operation} failed`, {
|
|
288
|
+
recovery: 'the registry was left unchanged; back up the Dodo state directory and run dodo doctor before repairing state.db',
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/projects/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const ACCESS_MODE_META_KEY = 'owner-access-mode';
|
|
2
|
+
/**
|
|
3
|
+
* Personal mode is DODO's single-owner default. OAuth still identifies the
|
|
4
|
+
* installed client and limits token scopes, while registered projects become
|
|
5
|
+
* available without a second per-project ACL/profile ceremony.
|
|
6
|
+
*
|
|
7
|
+
* Managed mode keeps the original project ACL, trust and AI egress allowlists
|
|
8
|
+
* for owners who share one installation between independently trusted clients.
|
|
9
|
+
*/
|
|
10
|
+
export function accessMode(store) {
|
|
11
|
+
return store.getMeta(ACCESS_MODE_META_KEY) === 'managed' ? 'managed' : 'personal';
|
|
12
|
+
}
|
|
13
|
+
export function setAccessMode(store, mode) {
|
|
14
|
+
store.setMeta(ACCESS_MODE_META_KEY, mode);
|
|
15
|
+
}
|
|
16
|
+
export function isPersonalMode(store) {
|
|
17
|
+
return accessMode(store) === 'personal';
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=accessMode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessMode.js","sourceRoot":"","sources":["../../src/security/accessMode.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AAGxD;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,KAAY;IACrC,OAAO,KAAK,CAAC,OAAO,CAAC,oBAAoB,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAY,EAAE,IAAgB;IAC1D,KAAK,CAAC,OAAO,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAY;IACzC,OAAO,UAAU,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DodoError } from '../errors.js';
|
|
2
|
+
import { digestOf } from '../util/hash.js';
|
|
3
|
+
export function actionDigest(req, policyVersion) {
|
|
4
|
+
return digestOf({ tool: req.tool, action: req.action, policyVersion });
|
|
5
|
+
}
|
|
6
|
+
function policyVersionOf(store, workspaceId) {
|
|
7
|
+
const row = store.db.prepare('SELECT COUNT(*) AS c FROM policy_versions WHERE workspace_id = ?').get(workspaceId);
|
|
8
|
+
return row.c;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Gate an action behind a local approval. Either returns (approval found and
|
|
12
|
+
* consumed — proceed) or throws APPROVAL_REQUIRED carrying an opaque request
|
|
13
|
+
* reference the model can surface to the user.
|
|
14
|
+
*/
|
|
15
|
+
export function requireLocalApproval(store, req) {
|
|
16
|
+
const digest = actionDigest(req, policyVersionOf(store, req.workspaceId));
|
|
17
|
+
const existing = store.findPendingActionApproval(req.workspaceId, digest, req.principal);
|
|
18
|
+
if (existing) {
|
|
19
|
+
if (existing.epoch !== req.epoch) {
|
|
20
|
+
// approvals do not survive server restarts (spec §12.3)
|
|
21
|
+
store.setApprovalStatus(existing.id, 'denied');
|
|
22
|
+
}
|
|
23
|
+
else if (existing.status === 'approved') {
|
|
24
|
+
const consumed = store.setApprovalStatus(existing.id, 'consumed');
|
|
25
|
+
if (consumed)
|
|
26
|
+
return { approvalId: existing.id };
|
|
27
|
+
throw new DodoError('APPROVAL_EXPIRED', 'approval expired before use; request again', {
|
|
28
|
+
retryable: true,
|
|
29
|
+
detail: { approvalId: existing.id },
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
else if (existing.status === 'pending') {
|
|
33
|
+
throw new DodoError('APPROVAL_REQUIRED', `local approval pending: run \`dodo approve ${existing.id}\` on the server terminal`, {
|
|
34
|
+
retryable: true,
|
|
35
|
+
recovery: `ask the machine owner to run: dodo approve ${existing.id}`,
|
|
36
|
+
detail: { approvalId: existing.id, summary: req.summary },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const created = store.createApproval({
|
|
41
|
+
kind: 'action',
|
|
42
|
+
workspaceId: req.workspaceId,
|
|
43
|
+
epoch: req.epoch,
|
|
44
|
+
principal: req.principal,
|
|
45
|
+
tool: req.tool,
|
|
46
|
+
digest,
|
|
47
|
+
summary: req.summary,
|
|
48
|
+
ttlMs: req.ttlMs,
|
|
49
|
+
});
|
|
50
|
+
throw new DodoError('APPROVAL_REQUIRED', `local approval required: run \`dodo approve ${created.id}\` on the server terminal, then retry this call with the same arguments`, {
|
|
51
|
+
retryable: true,
|
|
52
|
+
recovery: `ask the machine owner to run: dodo approve ${created.id}`,
|
|
53
|
+
detail: { approvalId: created.id, summary: req.summary },
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=approvals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approvals.js","sourceRoot":"","sources":["../../src/security/approvals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAsB3C,MAAM,UAAU,YAAY,CAAC,GAA6C,EAAE,aAAqB;IAC/F,OAAO,QAAQ,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,eAAe,CAAC,KAAY,EAAE,WAAmB;IACxD,MAAM,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,kEAAkE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAkB,CAAC;IACnI,OAAO,GAAG,CAAC,CAAC,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAY,EAAE,GAAoB;IACrE,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,EAAE,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1E,MAAM,QAAQ,GAAG,KAAK,CAAC,yBAAyB,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IACzF,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,QAAQ,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC;YACjC,wDAAwD;YACxD,KAAK,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QACjD,CAAC;aAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;YAClE,IAAI,QAAQ;gBAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjD,MAAM,IAAI,SAAS,CAAC,kBAAkB,EAAE,4CAA4C,EAAE;gBACpF,SAAS,EAAE,IAAI;gBACf,MAAM,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE;aACpC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACzC,MAAM,IAAI,SAAS,CAAC,mBAAmB,EAAE,8CAA8C,QAAQ,CAAC,EAAE,2BAA2B,EAAE;gBAC7H,SAAS,EAAE,IAAI;gBACf,QAAQ,EAAE,8CAA8C,QAAQ,CAAC,EAAE,EAAE;gBACrE,MAAM,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE;aAC1D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,cAAc,CAAC;QACnC,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,MAAM;QACN,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,GAAG,CAAC,KAAK;KACjB,CAAC,CAAC;IACH,MAAM,IAAI,SAAS,CAAC,mBAAmB,EAAE,+CAA+C,OAAO,CAAC,EAAE,yEAAyE,EAAE;QAC3K,SAAS,EAAE,IAAI;QACf,QAAQ,EAAE,8CAA8C,OAAO,CAAC,EAAE,EAAE;QACpE,MAAM,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE;KACzD,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isWithinPath } from '../platform/pathPolicy.js';
|
|
4
|
+
import { envValue, windowsProgramDataDirectory } from '../platform/system.js';
|
|
5
|
+
/** Child jobs receive a whitelist, not the server's OAuth/config/loader state. */
|
|
6
|
+
const BASE_ALLOWED = ['HOME', 'LANG', 'LC_ALL', 'LC_CTYPE', 'TMPDIR', 'TZ', 'USER', 'LOGNAME', 'SHELL', 'COLORTERM'];
|
|
7
|
+
const WINDOWS_ALLOWED = ['SYSTEMROOT', 'WINDIR', 'SYSTEMDRIVE', 'USERPROFILE', 'HOMEDRIVE', 'HOMEPATH', 'APPDATA', 'LOCALAPPDATA', 'PROGRAMDATA', 'TEMP', 'TMP', 'USERNAME', 'USERDOMAIN', 'PROGRAMFILES', 'PROGRAMFILES(X86)', 'PROGRAMW6432', 'COMMONPROGRAMFILES', 'PROCESSOR_ARCHITECTURE', 'NUMBER_OF_PROCESSORS'];
|
|
8
|
+
const ALWAYS_DENIED = new Set(['NODE_OPTIONS', 'NODE_EXTRA_CA_CERTS', 'LD_PRELOAD', 'DYLD_INSERT_LIBRARIES', 'DYLD_LIBRARY_PATH', 'LD_LIBRARY_PATH', 'PATH', 'TERM', 'COMSPEC', 'PATHEXT', 'NODE_PATH', 'TUNNEL_TOKEN', 'TUNNEL_TOKEN_FILE']);
|
|
9
|
+
export function trustedPath(parentPath, workspaceRoot, platform = process.platform) {
|
|
10
|
+
const p = platform === 'win32' ? path.win32 : path.posix;
|
|
11
|
+
const real = (value) => {
|
|
12
|
+
try {
|
|
13
|
+
return platform === process.platform ? fs.realpathSync.native(value) : value;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const root = real(workspaceRoot);
|
|
20
|
+
const entries = (parentPath ?? '').split(p.delimiter).filter(entry => {
|
|
21
|
+
if (!entry || !p.isAbsolute(entry) || (platform === 'win32' && !/^[a-z]:[\\/]/i.test(entry)))
|
|
22
|
+
return false;
|
|
23
|
+
return !isWithinPath(workspaceRoot, entry, platform) && !isWithinPath(root, real(entry), platform);
|
|
24
|
+
});
|
|
25
|
+
if (entries.length > 0)
|
|
26
|
+
return [...new Set(entries)].join(p.delimiter);
|
|
27
|
+
if (platform === 'win32') {
|
|
28
|
+
const systemRoot = envValue(process.env, 'SystemRoot', 'win32') ?? 'C:\\Windows';
|
|
29
|
+
return [p.join(systemRoot, 'System32'), systemRoot].filter(entry => !isWithinPath(root, entry, platform)).join(';');
|
|
30
|
+
}
|
|
31
|
+
return ['/usr/bin', '/bin', '/usr/sbin', '/sbin'].filter(entry => !isWithinPath(root, real(entry), platform)).join(':');
|
|
32
|
+
}
|
|
33
|
+
export function buildChildEnv(opts) {
|
|
34
|
+
const platform = opts.platform ?? process.platform;
|
|
35
|
+
const out = { PATH: trustedPath(envValue(opts.parentEnv, 'PATH', platform), opts.workspaceRoot, platform), TERM: 'dumb' };
|
|
36
|
+
const names = new Set([...BASE_ALLOWED, ...(platform === 'win32' ? WINDOWS_ALLOWED : []), ...opts.extraAllowlist]);
|
|
37
|
+
for (const name of names) {
|
|
38
|
+
const upper = name.toUpperCase();
|
|
39
|
+
if (ALWAYS_DENIED.has(upper) || upper.startsWith('DODO_'))
|
|
40
|
+
continue;
|
|
41
|
+
const value = envValue(opts.parentEnv, name, platform);
|
|
42
|
+
if (value !== undefined)
|
|
43
|
+
out[platform === 'win32' ? upper : name] = value;
|
|
44
|
+
}
|
|
45
|
+
if (platform === 'win32') {
|
|
46
|
+
if (!out['PROGRAMDATA']) {
|
|
47
|
+
const programData = windowsProgramDataDirectory(opts.parentEnv);
|
|
48
|
+
if (programData)
|
|
49
|
+
out['PROGRAMDATA'] = programData;
|
|
50
|
+
}
|
|
51
|
+
const extensions = (envValue(opts.parentEnv, 'PATHEXT', platform) ?? '.COM;.EXE;.BAT;.CMD').split(';').map(e => e.toUpperCase()).filter(e => ['.EXE', '.COM', '.CMD', '.BAT'].includes(e));
|
|
52
|
+
out['PATHEXT'] = [...new Set(extensions.length ? extensions : ['.EXE', '.COM', '.CMD', '.BAT'])].join(';');
|
|
53
|
+
out['NoDefaultCurrentDirectoryInExePath'] = '1';
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/security/env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { DodoError } from '../errors.js';
|
|
3
|
+
/** One queue per real workspace; nested dispatch shares its ticket, background jobs retain it. */
|
|
4
|
+
export class MutationQueue {
|
|
5
|
+
context = new AsyncLocalStorage();
|
|
6
|
+
active;
|
|
7
|
+
waiters = [];
|
|
8
|
+
get busy() { return this.active !== undefined; }
|
|
9
|
+
get pending() { return this.waiters.length; }
|
|
10
|
+
ticket() {
|
|
11
|
+
const t = { refs: 1, open: true, release: () => {
|
|
12
|
+
if (--t.refs !== 0)
|
|
13
|
+
return;
|
|
14
|
+
if (this.active === t)
|
|
15
|
+
this.active = undefined;
|
|
16
|
+
const next = this.waiters.shift();
|
|
17
|
+
if (next)
|
|
18
|
+
next(this.ticket());
|
|
19
|
+
} };
|
|
20
|
+
this.active = t;
|
|
21
|
+
return t;
|
|
22
|
+
}
|
|
23
|
+
async run(fn, signal) {
|
|
24
|
+
if (signal?.aborted)
|
|
25
|
+
throw new DodoError('CONFLICT', 'queued action was canceled');
|
|
26
|
+
const nested = this.context.getStore();
|
|
27
|
+
if (nested?.open && this.active === nested)
|
|
28
|
+
return fn();
|
|
29
|
+
let ticket;
|
|
30
|
+
if (this.busy) {
|
|
31
|
+
if (this.waiters.length >= 32)
|
|
32
|
+
throw new DodoError('RESOURCE_LIMIT', 'workspace mutation queue is full');
|
|
33
|
+
ticket = await new Promise((resolve, reject) => {
|
|
34
|
+
const waiter = (t) => { signal?.removeEventListener('abort', abort); resolve(t); };
|
|
35
|
+
const abort = () => { const i = this.waiters.indexOf(waiter); if (i >= 0) {
|
|
36
|
+
this.waiters.splice(i, 1);
|
|
37
|
+
reject(new DodoError('CONFLICT', 'queued action was canceled'));
|
|
38
|
+
} };
|
|
39
|
+
this.waiters.push(waiter);
|
|
40
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
41
|
+
if (signal?.aborted)
|
|
42
|
+
abort();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else
|
|
46
|
+
ticket = this.ticket();
|
|
47
|
+
try {
|
|
48
|
+
return await this.context.run(ticket, fn);
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
ticket.open = false;
|
|
52
|
+
ticket.release();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
assertCanStart() {
|
|
56
|
+
const ticket = this.context.getStore();
|
|
57
|
+
if (this.busy && (!ticket?.open || ticket !== this.active))
|
|
58
|
+
throw new DodoError('CONFLICT', 'workspace mutation queue is busy');
|
|
59
|
+
}
|
|
60
|
+
/** Sync producers (schedules) refuse a busy queue; they may retry before claiming a due run. */
|
|
61
|
+
retainJob() {
|
|
62
|
+
let ticket = this.context.getStore();
|
|
63
|
+
if (!ticket?.open || ticket !== this.active) {
|
|
64
|
+
if (this.busy)
|
|
65
|
+
throw new DodoError('CONFLICT', 'workspace mutation queue is busy; wait for the current job');
|
|
66
|
+
ticket = this.ticket();
|
|
67
|
+
ticket.open = false;
|
|
68
|
+
}
|
|
69
|
+
else
|
|
70
|
+
ticket.refs++;
|
|
71
|
+
let done = false;
|
|
72
|
+
return () => { if (!done) {
|
|
73
|
+
done = true;
|
|
74
|
+
ticket.release();
|
|
75
|
+
} };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=mutationQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutationQueue.js","sourceRoot":"","sources":["../../src/security/mutationQueue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const ALL_SCOPES = ['dodo:read', 'dodo:write', 'dodo:exec'];
|
|
2
|
+
export function decide(action, mode) {
|
|
3
|
+
switch (action) {
|
|
4
|
+
case 'read':
|
|
5
|
+
case 'plan':
|
|
6
|
+
case 'job-control':
|
|
7
|
+
return 'allow';
|
|
8
|
+
case 'mutate-files':
|
|
9
|
+
return mode === 'inspect' ? 'approval' : 'allow';
|
|
10
|
+
case 'exec':
|
|
11
|
+
return mode === 'trusted' ? 'allow' : 'approval';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function scopeSatisfied(required, tokenScopes) {
|
|
15
|
+
return tokenScopes.includes(required);
|
|
16
|
+
}
|
|
17
|
+
export const TRUST_MODE_DESCRIPTIONS = {
|
|
18
|
+
inspect: 'read & search allowed; every file change (write_file/edit_file/apply_changes) and every command (run_command/exec_command/run_task/git_commit) needs a per-action local approval',
|
|
19
|
+
edit: 'read & search allowed; file changes (write_file/edit_file/delete_path/move_path/apply_changes) apply directly under this standing consent; running commands still needs per-action local approval',
|
|
20
|
+
trusted: 'file changes and command execution (run_command/exec_command/run_task/git_commit) run directly — the recommended mode when your MCP client confirms every call. Commands run with YOUR OS user privileges — the workspace directory guard is NOT an OS sandbox; test/lint/build scripts can execute arbitrary code and reach files outside the workspace',
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/security/policy.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,UAAU,GAAiB,CAAC,WAAW,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;AAYjF,MAAM,UAAU,MAAM,CAAC,MAAmB,EAAE,IAAe;IACzD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC;QACZ,KAAK,aAAa;YAChB,OAAO,OAAO,CAAC;QACjB,KAAK,cAAc;YACjB,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;QACnD,KAAK,MAAM;YACT,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IACrD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAoB,EAAE,WAAqB;IACxE,OAAO,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAA8B;IAChE,OAAO,EAAE,kLAAkL;IAC3L,IAAI,EAAE,mMAAmM;IACzM,OAAO,EACL,0VAA0V;CAC7V,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { DodoError } from '../errors.js';
|
|
2
|
+
import { isPersonalMode } from './accessMode.js';
|
|
3
|
+
export function isOwner(p) {
|
|
4
|
+
return p.sub === 'owner' && ((p.grantId === 'local-stdio' && p.clientId === 'stdio') || (p.grantId === 'local-config-owner' && p.clientId === 'local-config'));
|
|
5
|
+
}
|
|
6
|
+
/** A delegation can narrow token scopes; live target ACLs and expiry are always re-read. */
|
|
7
|
+
export function projectAuthority(store, p, workspaceId) {
|
|
8
|
+
if (p.projectRestriction && p.projectRestriction !== workspaceId)
|
|
9
|
+
throw new DodoError('FORBIDDEN', 'delegation is restricted to its target project');
|
|
10
|
+
if (p.expiresAt !== undefined && p.expiresAt <= Date.now() / 1000)
|
|
11
|
+
throw new DodoError('AUTH_REQUIRED', 'authorization expired; authenticate and resume');
|
|
12
|
+
if (isOwner(p))
|
|
13
|
+
return { ...p, scopes: [...p.scopes] };
|
|
14
|
+
const grant = store.getGrant(p.grantId);
|
|
15
|
+
if (!grant || grant.revokedAt !== null || grant.clientId !== p.clientId || !store.getOAuthClient(p.clientId))
|
|
16
|
+
throw new DodoError('AUTH_REQUIRED', 'authorization was revoked');
|
|
17
|
+
if ((p.identityGrant === false || store.getMeta(`identity-grant:${p.grantId}`) !== '2') && grant.workspaceId !== workspaceId)
|
|
18
|
+
throw new DodoError('FORBIDDEN', 'authorization is bound to another workspace');
|
|
19
|
+
const allowed = isPersonalMode(store) ? grant.scopes : store.clientAccess(workspaceId, p.clientId);
|
|
20
|
+
return { ...p, scopes: (p.tokenScopes ?? p.scopes).filter(s => grant.scopes.includes(s) && allowed.includes(s)) };
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=projectAuthority.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectAuthority.js","sourceRoot":"","sources":["../../src/security/projectAuthority.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,MAAM,UAAU,OAAO,CAAC,CAAY;IAClC,OAAO,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,aAAa,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,KAAK,oBAAoB,IAAI,CAAC,CAAC,QAAQ,KAAK,cAAc,CAAC,CAAC,CAAC;AACjK,CAAC;AACD,4FAA4F;AAC5F,MAAM,UAAU,gBAAgB,CAAC,KAAY,EAAE,CAAY,EAAE,WAAmB;IAC9E,IAAI,CAAC,CAAC,kBAAkB,IAAI,CAAC,CAAC,kBAAkB,KAAK,WAAW;QAAE,MAAM,IAAI,SAAS,CAAC,WAAW,EAAC,gDAAgD,CAAC,CAAC;IACpJ,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI;QAAE,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE,gDAAgD,CAAC,CAAC;IAC1J,IAAI,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACvD,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI,IAAI,KAAK,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE,2BAA2B,CAAC,CAAC;IAChL,IAAI,CAAC,CAAC,CAAC,aAAa,KAAK,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK,CAAC,WAAW,KAAK,WAAW;QAAE,MAAM,IAAI,SAAS,CAAC,WAAW,EAAE,6CAA6C,CAAC,CAAC;IAC9M,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IACnG,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpH,CAAC"}
|