@wardby/cli 0.2.0 → 0.3.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/.env.example +34 -4
- package/README.md +183 -71
- package/dist/claude-coding-worker/driver.d.ts +7 -1
- package/dist/claude-coding-worker/driver.js +31 -2
- package/dist/claude-coding-worker/main.js +5 -2
- package/dist/claude-coding-worker/tool-socket.d.ts +9 -0
- package/dist/claude-coding-worker/tool-socket.js +26 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +13 -4
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +219 -29
- package/dist/coding/collect-exclude.d.ts +25 -0
- package/dist/coding/collect-exclude.js +76 -0
- package/dist/coding/profile.d.ts +67 -22
- package/dist/coding/profile.js +58 -25
- package/dist/coding/protected-path-wording.d.ts +24 -0
- package/dist/coding/protected-path-wording.js +55 -0
- package/dist/coding/protected-paths.d.ts +31 -0
- package/dist/coding/protected-paths.js +48 -0
- package/dist/coding/protocol.d.ts +99 -3
- package/dist/coding/protocol.js +155 -4
- package/dist/coding/registry/adapters.d.ts +2 -0
- package/dist/coding/registry/adapters.js +9 -0
- package/dist/coding/registry/allowlist.d.ts +9 -0
- package/dist/coding/registry/allowlist.js +28 -0
- package/dist/coding/registry/json-scan.d.ts +55 -0
- package/dist/coding/registry/json-scan.js +191 -0
- package/dist/coding/registry/lockfiles.d.ts +6 -0
- package/dist/coding/registry/lockfiles.js +89 -0
- package/dist/coding/registry/npm-lockfile.d.ts +9 -0
- package/dist/coding/registry/npm-lockfile.js +73 -0
- package/dist/coding/registry/npm-plan.d.ts +29 -0
- package/dist/coding/registry/npm-plan.js +289 -0
- package/dist/coding/registry/npm.d.ts +7 -0
- package/dist/coding/registry/npm.js +252 -0
- package/dist/coding/registry/pypi.d.ts +4 -0
- package/dist/coding/registry/pypi.js +210 -0
- package/dist/coding/registry/report.d.ts +37 -0
- package/dist/coding/registry/report.js +31 -0
- package/dist/coding/registry/token.d.ts +4 -0
- package/dist/coding/registry/token.js +7 -0
- package/dist/coding/registry/types.d.ts +286 -0
- package/dist/coding/registry/types.js +19 -0
- package/dist/coding/registry/worker-config.d.ts +14 -0
- package/dist/coding/registry/worker-config.js +31 -0
- package/dist/coding/services/builtins.d.ts +22 -0
- package/dist/coding/services/builtins.js +85 -0
- package/dist/coding/services/catalog.d.ts +443 -0
- package/dist/coding/services/catalog.js +159 -0
- package/dist/coding/services/declaration.d.ts +11 -0
- package/dist/coding/services/declaration.js +114 -0
- package/dist/coding/services/note.d.ts +8 -0
- package/dist/coding/services/note.js +15 -0
- package/dist/coding/services/resolve.d.ts +25 -0
- package/dist/coding/services/resolve.js +50 -0
- package/dist/coding/services/wording.d.ts +25 -0
- package/dist/coding/services/wording.js +70 -0
- package/dist/coding-proxy/main.js +24 -4
- package/dist/coding-worker/artifact.d.ts +18 -0
- package/dist/coding-worker/artifact.js +48 -6
- package/dist/coding-worker/debug-trace.d.ts +37 -0
- package/dist/coding-worker/debug-trace.js +117 -0
- package/dist/coding-worker/driver.d.ts +14 -1
- package/dist/coding-worker/driver.js +106 -14
- package/dist/coding-worker/errors.d.ts +7 -0
- package/dist/coding-worker/errors.js +26 -0
- package/dist/coding-worker/main.js +13 -4
- package/dist/coding-worker/sdk.d.ts +2 -2
- package/dist/coding-worker/sdk.js +7 -2
- package/dist/coding-worker/types.d.ts +3 -0
- package/dist/config/providers.d.ts +41 -0
- package/dist/config/providers.js +66 -0
- package/dist/core/budget-groups.d.ts +109 -6
- package/dist/core/budget-groups.js +125 -19
- package/dist/core/budget-wording.d.ts +22 -0
- package/dist/core/budget-wording.js +55 -0
- package/dist/core/coding-queue.d.ts +1 -1
- package/dist/core/datastores.d.ts +1 -1
- package/dist/core/datastores.js +18 -2
- package/dist/core/db.d.ts +40 -2
- package/dist/core/db.js +75 -2
- package/dist/core/dispatch.d.ts +49 -7
- package/dist/core/dispatch.js +290 -45
- package/dist/core/engine-native.js +27 -10
- package/dist/core/grants.d.ts +86 -0
- package/dist/core/grants.js +126 -0
- package/dist/core/host-events.d.ts +49 -0
- package/dist/core/host-events.js +257 -0
- package/dist/core/host-identity-links.d.ts +54 -0
- package/dist/core/host-identity-links.js +189 -0
- package/dist/core/host-status.d.ts +61 -0
- package/dist/core/host-status.js +211 -0
- package/dist/core/http-runtime.js +3 -4
- package/dist/core/in-flight-runs.d.ts +8 -0
- package/dist/core/in-flight-runs.js +56 -0
- package/dist/core/lease.d.ts +1 -1
- package/dist/core/private-directory.d.ts +20 -0
- package/dist/core/private-directory.js +36 -0
- package/dist/core/provider-wording.d.ts +12 -0
- package/dist/core/provider-wording.js +44 -0
- package/dist/core/reconciler.d.ts +39 -3
- package/dist/core/reconciler.js +86 -2
- package/dist/core/repo-access.d.ts +99 -0
- package/dist/core/repo-access.js +136 -0
- package/dist/core/review-host-checks.d.ts +11 -0
- package/dist/core/review-host-checks.js +41 -0
- package/dist/core/review-host-tools.d.ts +47 -0
- package/dist/core/review-host-tools.js +347 -0
- package/dist/core/run-heartbeat.d.ts +27 -0
- package/dist/core/run-heartbeat.js +54 -0
- package/dist/core/runner.d.ts +31 -9
- package/dist/core/runner.js +237 -40
- package/dist/core/scheduler.d.ts +1 -1
- package/dist/core/secrets.d.ts +12 -3
- package/dist/core/secrets.js +25 -6
- package/dist/core/subagent-memory-tools.d.ts +2 -2
- package/dist/core/subagent-memory-tools.js +16 -3
- package/dist/core/tool-admin.d.ts +81 -0
- package/dist/core/tool-admin.js +129 -0
- package/dist/core/tool-names.d.ts +42 -0
- package/dist/core/tool-names.js +64 -0
- package/dist/core/untrusted-content.d.ts +32 -0
- package/dist/core/untrusted-content.js +72 -0
- package/dist/core/webhooks.d.ts +9 -2
- package/dist/core/webhooks.js +23 -2
- package/dist/generated/prisma/browser.d.ts +328 -0
- package/dist/generated/prisma/browser.js +17 -0
- package/dist/generated/prisma/client.d.ts +347 -0
- package/dist/generated/prisma/client.js +34 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +839 -0
- package/dist/generated/prisma/commonInputTypes.js +10 -0
- package/dist/generated/prisma/enums.d.ts +59 -0
- package/dist/generated/prisma/enums.js +59 -0
- package/dist/generated/prisma/internal/class.d.ts +605 -0
- package/dist/generated/prisma/internal/class.js +49 -0
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +4494 -0
- package/dist/generated/prisma/internal/prismaNamespace.js +628 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +635 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +599 -0
- package/dist/generated/prisma/models/Agent.d.ts +3560 -0
- package/dist/generated/prisma/models/Agent.js +1 -0
- package/dist/generated/prisma/models/AgentDatastore.d.ts +1210 -0
- package/dist/generated/prisma/models/AgentDatastore.js +1 -0
- package/dist/generated/prisma/models/AgentMemory.d.ts +986 -0
- package/dist/generated/prisma/models/AgentMemory.js +1 -0
- package/dist/generated/prisma/models/AgentRepository.d.ts +1425 -0
- package/dist/generated/prisma/models/AgentRepository.js +1 -0
- package/dist/generated/prisma/models/AgentSecret.d.ts +1212 -0
- package/dist/generated/prisma/models/AgentSecret.js +1 -0
- package/dist/generated/prisma/models/AgentSubAgent.d.ts +1217 -0
- package/dist/generated/prisma/models/AgentSubAgent.js +1 -0
- package/dist/generated/prisma/models/AgentTool.d.ts +1403 -0
- package/dist/generated/prisma/models/AgentTool.js +1 -0
- package/dist/generated/prisma/models/AuthFormChallenge.d.ts +1298 -0
- package/dist/generated/prisma/models/AuthFormChallenge.js +1 -0
- package/dist/generated/prisma/models/AuthLoginKey.d.ts +1245 -0
- package/dist/generated/prisma/models/AuthLoginKey.js +1 -0
- package/dist/generated/prisma/models/AuthRateLimit.d.ts +979 -0
- package/dist/generated/prisma/models/AuthRateLimit.js +1 -0
- package/dist/generated/prisma/models/AuthSession.d.ts +1376 -0
- package/dist/generated/prisma/models/AuthSession.js +1 -0
- package/dist/generated/prisma/models/AuthUser.d.ts +1700 -0
- package/dist/generated/prisma/models/AuthUser.js +1 -0
- package/dist/generated/prisma/models/BudgetGroup.d.ts +1548 -0
- package/dist/generated/prisma/models/BudgetGroup.js +1 -0
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +1681 -0
- package/dist/generated/prisma/models/CodingAgentProfile.js +1 -0
- package/dist/generated/prisma/models/CodingProxyRequest.d.ts +1749 -0
- package/dist/generated/prisma/models/CodingProxyRequest.js +1 -0
- package/dist/generated/prisma/models/CodingProxySession.d.ts +1626 -0
- package/dist/generated/prisma/models/CodingProxySession.js +1 -0
- package/dist/generated/prisma/models/CodingRun.d.ts +3583 -0
- package/dist/generated/prisma/models/CodingRun.js +1 -0
- package/dist/generated/prisma/models/CodingService.d.ts +1348 -0
- package/dist/generated/prisma/models/CodingService.js +1 -0
- package/dist/generated/prisma/models/Datastore.d.ts +1434 -0
- package/dist/generated/prisma/models/Datastore.js +1 -0
- package/dist/generated/prisma/models/DatastoreEntry.d.ts +1314 -0
- package/dist/generated/prisma/models/DatastoreEntry.js +1 -0
- package/dist/generated/prisma/models/HostEventDelivery.d.ts +946 -0
- package/dist/generated/prisma/models/HostEventDelivery.js +1 -0
- package/dist/generated/prisma/models/HostIdentity.d.ts +1232 -0
- package/dist/generated/prisma/models/HostIdentity.js +1 -0
- package/dist/generated/prisma/models/HostIdentityLinkRequest.d.ts +1473 -0
- package/dist/generated/prisma/models/HostIdentityLinkRequest.js +1 -0
- package/dist/generated/prisma/models/OAuthAuthorizationCode.d.ts +1526 -0
- package/dist/generated/prisma/models/OAuthAuthorizationCode.js +1 -0
- package/dist/generated/prisma/models/OAuthAuthorizationRequest.d.ts +1350 -0
- package/dist/generated/prisma/models/OAuthAuthorizationRequest.js +1 -0
- package/dist/generated/prisma/models/OAuthClient.d.ts +1289 -0
- package/dist/generated/prisma/models/OAuthClient.js +1 -0
- package/dist/generated/prisma/models/OAuthFamily.d.ts +1540 -0
- package/dist/generated/prisma/models/OAuthFamily.js +1 -0
- package/dist/generated/prisma/models/OAuthGrant.d.ts +1280 -0
- package/dist/generated/prisma/models/OAuthGrant.js +1 -0
- package/dist/generated/prisma/models/Principal.d.ts +2245 -0
- package/dist/generated/prisma/models/Principal.js +1 -0
- package/dist/generated/prisma/models/RegistryAllowance.d.ts +1148 -0
- package/dist/generated/prisma/models/RegistryAllowance.js +1 -0
- package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +1219 -0
- package/dist/generated/prisma/models/RegistryApprovedVersion.js +1 -0
- package/dist/generated/prisma/models/RegistryFetch.d.ts +1428 -0
- package/dist/generated/prisma/models/RegistryFetch.js +1 -0
- package/dist/generated/prisma/models/RegistryPlanRefusal.d.ts +1294 -0
- package/dist/generated/prisma/models/RegistryPlanRefusal.js +1 -0
- package/dist/generated/prisma/models/RegistryVersionFact.d.ts +1085 -0
- package/dist/generated/prisma/models/RegistryVersionFact.js +1 -0
- package/dist/generated/prisma/models/ResourceGrant.d.ts +1437 -0
- package/dist/generated/prisma/models/ResourceGrant.js +1 -0
- package/dist/generated/prisma/models/Run.d.ts +2669 -0
- package/dist/generated/prisma/models/Run.js +1 -0
- package/dist/generated/prisma/models/RunHostCheck.d.ts +1239 -0
- package/dist/generated/prisma/models/RunHostCheck.js +1 -0
- package/dist/generated/prisma/models/RunHostStatus.d.ts +1315 -0
- package/dist/generated/prisma/models/RunHostStatus.js +1 -0
- package/dist/generated/prisma/models/SchedulerLease.d.ts +970 -0
- package/dist/generated/prisma/models/SchedulerLease.js +1 -0
- package/dist/generated/prisma/models/Secret.d.ts +1399 -0
- package/dist/generated/prisma/models/Secret.js +1 -0
- package/dist/generated/prisma/models/SecretElicitationOutcome.d.ts +973 -0
- package/dist/generated/prisma/models/SecretElicitationOutcome.js +1 -0
- package/dist/generated/prisma/models/Task.d.ts +1176 -0
- package/dist/generated/prisma/models/Task.js +1 -0
- package/dist/generated/prisma/models/Tool.d.ts +1490 -0
- package/dist/generated/prisma/models/Tool.js +1 -0
- package/dist/generated/prisma/models/Webhook.d.ts +1386 -0
- package/dist/generated/prisma/models/Webhook.js +1 -0
- package/dist/generated/prisma/models.d.ts +45 -0
- package/dist/generated/prisma/models.js +1 -0
- package/dist/help/build.d.ts +1 -0
- package/dist/help/build.js +9 -0
- package/dist/help/catalog.d.ts +24 -0
- package/dist/help/catalog.js +160 -0
- package/dist/help/cli.d.ts +2 -0
- package/dist/help/cli.js +65 -0
- package/dist/help/runtime.d.ts +3 -0
- package/dist/help/runtime.js +44 -0
- package/dist/help/search.d.ts +9 -0
- package/dist/help/search.js +104 -0
- package/dist/help-index.json +660 -0
- package/dist/import/cli-args.js +3 -2
- package/dist/import/create.d.ts +6 -1
- package/dist/import/create.js +68 -14
- package/dist/import/index.d.ts +1 -1
- package/dist/import/index.js +19 -9
- package/dist/import/neutral-schema.d.ts +11 -11
- package/dist/mcp/auth/access.d.ts +70 -0
- package/dist/mcp/auth/access.js +58 -0
- package/dist/mcp/auth/grants-cli.d.ts +149 -0
- package/dist/mcp/auth/grants-cli.js +518 -0
- package/dist/mcp/auth/host-account-cli.d.ts +2 -0
- package/dist/mcp/auth/host-account-cli.js +47 -0
- package/dist/mcp/auth/ownership.d.ts +37 -63
- package/dist/mcp/auth/ownership.js +19 -14
- package/dist/mcp/auth/principal.d.ts +1 -1
- package/dist/mcp/auth/repo-authorization.d.ts +22 -0
- package/dist/mcp/auth/repo-authorization.js +51 -0
- package/dist/mcp/auth/resource-server.d.ts +32 -3
- package/dist/mcp/auth/resource-server.js +84 -3
- package/dist/mcp/auth/self-hosted/browser.js +22 -8
- package/dist/mcp/auth/self-hosted/cli.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/cli.js +47 -13
- package/dist/mcp/auth/self-hosted/credentials.d.ts +21 -3
- package/dist/mcp/auth/self-hosted/credentials.js +62 -4
- package/dist/mcp/auth/self-hosted/rate-limit.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/session.d.ts +3 -2
- package/dist/mcp/context.d.ts +28 -2
- package/dist/mcp/errors.d.ts +25 -6
- package/dist/mcp/errors.js +98 -0
- package/dist/mcp/host-events/github-ingress.d.ts +36 -0
- package/dist/mcp/host-events/github-ingress.js +92 -0
- package/dist/mcp/host-events/github-user-callback.d.ts +18 -0
- package/dist/mcp/host-events/github-user-callback.js +50 -0
- package/dist/mcp/index.d.ts +8 -1
- package/dist/mcp/index.js +106 -16
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +27 -9
- package/dist/mcp/shared/page-style.d.ts +16 -0
- package/dist/mcp/shared/page-style.js +129 -0
- package/dist/mcp/tasks/manager.d.ts +1 -1
- package/dist/mcp/tools/agents.js +447 -49
- package/dist/mcp/tools/budget-groups.js +3 -3
- package/dist/mcp/tools/datastore.js +23 -16
- package/dist/mcp/tools/grants.d.ts +2 -0
- package/dist/mcp/tools/grants.js +239 -0
- package/dist/mcp/tools/help.d.ts +5 -0
- package/dist/mcp/tools/help.js +67 -0
- package/dist/mcp/tools/host-accounts.d.ts +2 -0
- package/dist/mcp/tools/host-accounts.js +114 -0
- package/dist/mcp/tools/memory.d.ts +7 -1
- package/dist/mcp/tools/memory.js +5 -5
- package/dist/mcp/tools/repositories.d.ts +2 -0
- package/dist/mcp/tools/repositories.js +181 -0
- package/dist/mcp/tools/runs.d.ts +6 -0
- package/dist/mcp/tools/runs.js +60 -6
- package/dist/mcp/tools/scheduling.js +4 -7
- package/dist/mcp/tools/secret-elicitation-form.d.ts +1 -1
- package/dist/mcp/tools/secret-elicitation-form.js +10 -28
- package/dist/mcp/tools/secret-elicitation.d.ts +1 -1
- package/dist/mcp/tools/secrets.js +18 -6
- package/dist/mcp/tools/services.d.ts +2 -0
- package/dist/mcp/tools/services.js +222 -0
- package/dist/mcp/tools/subagents.js +53 -17
- package/dist/mcp/tools/tools.d.ts +41 -0
- package/dist/mcp/tools/tools.js +202 -41
- package/dist/mcp/tools/trigger.js +36 -6
- package/dist/mcp/tools/webhooks.js +15 -4
- package/dist/mcp/transport/streamable-http.d.ts +11 -1
- package/dist/mcp/transport/streamable-http.js +32 -2
- package/dist/mcp/unattended-schedules.d.ts +1 -1
- package/dist/mcp/webhooks/ingress.d.ts +1 -1
- package/dist/providers/auth/delegating.d.ts +19 -0
- package/dist/providers/auth/delegating.js +71 -0
- package/dist/providers/auth/index.d.ts +3 -1
- package/dist/providers/auth/index.js +11 -0
- package/dist/providers/auth/self-hosted.d.ts +4 -3
- package/dist/providers/auth/self-hosted.js +16 -4
- package/dist/providers/auth/types.d.ts +6 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +3 -0
- package/dist/providers/coding-proxy/memory-ledger.js +21 -2
- package/dist/providers/coding-proxy/metering.d.ts +4 -0
- package/dist/providers/coding-proxy/metering.js +28 -2
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +18 -1
- package/dist/providers/coding-proxy/prisma-ledger.js +50 -5
- package/dist/providers/coding-proxy/proxy.d.ts +13 -0
- package/dist/providers/coding-proxy/proxy.js +479 -18
- package/dist/providers/coding-proxy/registry/audit.d.ts +131 -0
- package/dist/providers/coding-proxy/registry/audit.js +380 -0
- package/dist/providers/coding-proxy/registry/bounded-fetch.d.ts +16 -0
- package/dist/providers/coding-proxy/registry/bounded-fetch.js +77 -0
- package/dist/providers/coding-proxy/registry/plan.d.ts +58 -0
- package/dist/providers/coding-proxy/registry/plan.js +304 -0
- package/dist/providers/coding-proxy/registry/prisma-store.d.ts +34 -0
- package/dist/providers/coding-proxy/registry/prisma-store.js +151 -0
- package/dist/providers/coding-proxy/registry/service.d.ts +213 -0
- package/dist/providers/coding-proxy/registry/service.js +1137 -0
- package/dist/providers/coding-proxy/registry/store.d.ts +127 -0
- package/dist/providers/coding-proxy/registry/store.js +70 -0
- package/dist/providers/coding-proxy/runtime.d.ts +18 -1
- package/dist/providers/coding-proxy/runtime.js +63 -0
- package/dist/providers/coding-proxy/secure-fetch.js +0 -1
- package/dist/providers/coding-proxy/server.d.ts +11 -0
- package/dist/providers/coding-proxy/server.js +163 -0
- package/dist/providers/coding-proxy/types.d.ts +15 -0
- package/dist/providers/datastore/postgres.d.ts +1 -1
- package/dist/providers/engine/types.d.ts +10 -0
- package/dist/providers/executor/build.d.ts +3 -3
- package/dist/providers/executor/composition.d.ts +4 -1
- package/dist/providers/executor/composition.js +19 -0
- package/dist/providers/executor/container.d.ts +106 -4
- package/dist/providers/executor/container.js +305 -22
- package/dist/providers/executor/dbos.d.ts +3 -4
- package/dist/providers/executor/in-process.d.ts +2 -3
- package/dist/providers/executor/routing.d.ts +7 -0
- package/dist/providers/executor/routing.js +13 -0
- package/dist/providers/executor/types.d.ts +22 -0
- package/dist/providers/jobs/claude-tool-setup.d.ts +23 -0
- package/dist/providers/jobs/claude-tool-setup.js +50 -0
- package/dist/providers/jobs/collect-prune.d.ts +7 -0
- package/dist/providers/jobs/collect-prune.js +27 -0
- package/dist/providers/jobs/docker-isolation.d.ts +48 -3
- package/dist/providers/jobs/docker-isolation.js +213 -22
- package/dist/providers/jobs/docker-services.d.ts +35 -0
- package/dist/providers/jobs/docker-services.js +191 -0
- package/dist/providers/jobs/docker.d.ts +60 -2
- package/dist/providers/jobs/docker.js +313 -50
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +1 -0
- package/dist/providers/jobs/fake-kubernetes-api.js +12 -3
- package/dist/providers/jobs/kubernetes-isolation.d.ts +17 -2
- package/dist/providers/jobs/kubernetes-isolation.js +238 -57
- package/dist/providers/jobs/kubernetes-platform.d.ts +10 -4
- package/dist/providers/jobs/kubernetes-platform.js +11 -5
- package/dist/providers/jobs/kubernetes-preflight.js +3 -0
- package/dist/providers/jobs/kubernetes.d.ts +21 -2
- package/dist/providers/jobs/kubernetes.js +117 -31
- package/dist/providers/jobs/types.d.ts +20 -0
- package/dist/providers/llm/anthropic.js +6 -2
- package/dist/providers/llm/bedrock.js +2 -1
- package/dist/providers/llm/claude-messages.d.ts +5 -1
- package/dist/providers/llm/claude-messages.js +1 -0
- package/dist/providers/llm/claude-provider.d.ts +3 -1
- package/dist/providers/llm/claude-provider.js +5 -1
- package/dist/providers/llm/index.d.ts +1 -1
- package/dist/providers/llm/index.js +1 -1
- package/dist/providers/llm/pricing-anthropic.d.ts +10 -0
- package/dist/providers/llm/pricing-anthropic.js +32 -14
- package/dist/providers/llm/pricing-bedrock-claude.d.ts +8 -0
- package/dist/providers/llm/pricing-bedrock-claude.js +9 -0
- package/dist/providers/llm/routing.d.ts +10 -1
- package/dist/providers/llm/routing.js +18 -0
- package/dist/providers/llm/types.d.ts +12 -0
- package/dist/providers/llm/types.js +8 -1
- package/dist/providers/memory/postgres.d.ts +1 -1
- package/dist/providers/review-host/diff-lines.d.ts +16 -0
- package/dist/providers/review-host/diff-lines.js +59 -0
- package/dist/providers/review-host/github-events.d.ts +6 -0
- package/dist/providers/review-host/github-events.js +180 -0
- package/dist/providers/review-host/github-user-auth.d.ts +38 -0
- package/dist/providers/review-host/github-user-auth.js +128 -0
- package/dist/providers/review-host/github.d.ts +57 -0
- package/dist/providers/review-host/github.js +567 -0
- package/dist/providers/review-host/index.d.ts +12 -0
- package/dist/providers/review-host/index.js +30 -0
- package/dist/providers/review-host/review-format.d.ts +19 -0
- package/dist/providers/review-host/review-format.js +59 -0
- package/dist/providers/review-host/types.d.ts +284 -0
- package/dist/providers/review-host/types.js +24 -0
- package/dist/providers/vcs/git.d.ts +16 -6
- package/dist/providers/vcs/git.js +79 -14
- package/dist/providers/vcs/github.d.ts +74 -3
- package/dist/providers/vcs/github.js +195 -15
- package/dist/providers/vcs/types.d.ts +42 -4
- package/dist/quickstart/index.js +34 -32
- package/dist/quickstart/migrate.d.ts +23 -0
- package/dist/quickstart/migrate.js +125 -0
- package/dist/sandbox/fetch-policy.d.ts +20 -2
- package/dist/sandbox/fetch-policy.js +64 -3
- package/dist/sandbox/host-functions.d.ts +9 -1
- package/dist/sandbox/host-functions.js +12 -5
- package/dist/serve.js +1 -1
- package/dist/wardby-bin.js +6 -0
- package/docs/README.md +30 -0
- package/docs/architecture-runtime.md +90 -0
- package/docs/assets/brand/wardby-icon-512.png +0 -0
- package/docs/assets/brand/wardby-icon.svg +16 -0
- package/docs/assets/brand/wardby-mascot-profile-512.png +0 -0
- package/docs/assets/brand/wardby-mascot.png +0 -0
- package/docs/assets/brand/wardby-mascot.svg +5 -0
- package/docs/assets/wardby-workflow.svg +106 -0
- package/docs/code-review-agents.md +481 -0
- package/docs/coding-agent-setup.md +172 -0
- package/docs/coding-packages.md +455 -0
- package/docs/coding-services.md +300 -0
- package/docs/coding-worker-byo-images.md +98 -0
- package/docs/coding-worker-isolation.md +1061 -0
- package/docs/getting-started-gke.md +615 -0
- package/docs/getting-started-identity-provider.md +308 -0
- package/docs/getting-started.md +133 -0
- package/docs/observability.md +53 -0
- package/docs/release-verification.md +66 -0
- package/docs/security-deployment.md +657 -0
- package/help/code-review-agents.md +31 -0
- package/help/coding-packages.md +31 -0
- package/help/coding-services.md +71 -0
- package/help/creating-agents.md +68 -0
- package/help/deploy-gke.md +39 -0
- package/help/deployment-targets.md +39 -0
- package/help/errors/budget-group-exhausted.md +25 -0
- package/help/errors/docker-isolation-unsupported.md +26 -0
- package/help/errors/protected-path.md +45 -0
- package/help/errors/repo-access.md +27 -0
- package/help/errors/service-declaration-invalid.md +27 -0
- package/help/errors/service-declaration-unavailable.md +25 -0
- package/help/errors/service-launcher-unsupported.md +30 -0
- package/help/errors/service-not-allowed.md +27 -0
- package/help/errors/service-unknown.md +23 -0
- package/help/errors/service-unready.md +49 -0
- package/help/getting-started.md +31 -0
- package/help/github.md +30 -0
- package/help/identity-and-access.md +39 -0
- package/help/mcp.md +30 -0
- package/help/native-capabilities.md +30 -0
- package/help/observability.md +41 -0
- package/help/operating-agents.md +30 -0
- package/help/security.md +27 -0
- package/help/troubleshooting/budgets.md +26 -0
- package/help/troubleshooting/coding-workers.md +47 -0
- package/help/troubleshooting/repository-access.md +27 -0
- package/package.json +30 -11
- package/prisma/migrate.config.mjs +20 -0
- package/prisma/migrations/20260925010000_coding_collect_exclude/migration.sql +8 -0
- package/prisma/migrations/20260925015000_allowed_egress_default/migration.sql +8 -0
- package/prisma/migrations/20260925020000_coding_package_registry/migration.sql +55 -0
- package/prisma/migrations/20260925030000_tool_name_per_owner/migration.sql +11 -0
- package/prisma/migrations/20260926010000_run_trigger_host_event/migration.sql +7 -0
- package/prisma/migrations/20260926020000_code_review_hosts/migration.sql +53 -0
- package/prisma/migrations/20260926030000_auth_user_roles/migration.sql +9 -0
- package/prisma/migrations/20260926040000_agent_effort/migration.sql +6 -0
- package/prisma/migrations/20260926050000_registry_lockfile_plan/migration.sql +32 -0
- package/prisma/migrations/20260926050000_repo_access_authorization/migration.sql +82 -0
- package/prisma/migrations/20260926060000_registry_plan_refusal/migration.sql +19 -0
- package/prisma/migrations/20260926100000_registry_plan_refusal_published_at/migration.sql +5 -0
- package/prisma/migrations/20260926190000_run_host_status/migration.sql +18 -0
- package/prisma/migrations/20260926210000_run_host_status_at_dispatch/migration.sql +5 -0
- package/prisma/migrations/20260927010000_resource_grants/migration.sql +72 -0
- package/prisma/migrations/20260927020000_proxy_session_budget_exhausted/migration.sql +3 -0
- package/prisma/migrations/20260927030000_coding_debug_trace/migration.sql +4 -0
- package/prisma/migrations/20260927040000_proxy_session_upstream_failure/migration.sql +3 -0
- package/prisma/migrations/20260927050000_coding_run_services/migration.sql +74 -0
- package/prisma/migrations/20260928000000_coding_run_tool_image/migration.sql +5 -0
- package/prisma/schema.prisma +417 -23
|
@@ -107,13 +107,13 @@ export function registerBudgetGroupTools(mcp) {
|
|
|
107
107
|
handler: async (args, ctx) => {
|
|
108
108
|
const group = await ctx.db.budgetGroup.findUnique({
|
|
109
109
|
where: { id: args.id },
|
|
110
|
-
include: { agents: { select: { id: true, name: true } } },
|
|
110
|
+
include: { agents: { select: { id: true, name: true, budgetUsd: true } } },
|
|
111
111
|
});
|
|
112
112
|
if (!group || !canRead(group.ownerId, ctx.principal.id)) {
|
|
113
113
|
throw new McpError(404, `Budget group "${args.id}" not found.`);
|
|
114
114
|
}
|
|
115
|
-
const spend = await computeGroupSpend(ctx.db, group, group.agents
|
|
116
|
-
return textResult({ ...group, spend });
|
|
115
|
+
const spend = await computeGroupSpend(ctx.db, group, group.agents, new Date());
|
|
116
|
+
return textResult({ ...group, agents: group.agents.map(({ id, name }) => ({ id, name })), spend });
|
|
117
117
|
},
|
|
118
118
|
});
|
|
119
119
|
mcp.registerTool({
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import { Prisma } from "
|
|
2
|
-
import {
|
|
1
|
+
import { Prisma } from "#prisma";
|
|
2
|
+
import { requireOwnedDatastore, canRead, assertCanMutate } from "../auth/ownership.js";
|
|
3
|
+
import { requireAgentAccess, requireBindingOwner } from "../auth/access.js";
|
|
3
4
|
import { createDatastore, listDatastores, deleteDatastore, attachDatastore, detachDatastore, buildSharedDatastoreAccessor, } from "../../core/datastores.js";
|
|
4
5
|
import { McpError } from "../errors.js";
|
|
5
6
|
import { textResult } from "./text-result.js";
|
|
6
7
|
/**
|
|
7
8
|
* A `boundName` names an *attachment* (agentId, boundName) -> Datastore.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* Datastore's full read/write access to every other principal, with no
|
|
13
|
-
* sandbox mediation. So every boundName branch additionally checks the
|
|
14
|
-
* underlying Datastore's own ownership. When no attachment exists under
|
|
9
|
+
* Agent data (the private store and bound stores) is owner-only (resource-
|
|
10
|
+
* sharing grants spec §3.4.6), and a binding only resolves while the
|
|
11
|
+
* datastore's owner is the agent's owner (core/datastores.ts). These checks
|
|
12
|
+
* on the underlying Datastore's own ownership stay as defence in depth. When no attachment exists under
|
|
15
13
|
* that boundName, this resolves to `undefined` and callers fall through to
|
|
16
14
|
* today's unchanged behavior (miss for reads, throw for writes) — this
|
|
17
15
|
* check only ever narrows access when an attachment IS found, it never
|
|
@@ -97,8 +95,15 @@ export function registerDatastoreTools(mcp) {
|
|
|
97
95
|
required: ["agentId", "datastoreId"],
|
|
98
96
|
},
|
|
99
97
|
handler: async (args, ctx) => {
|
|
100
|
-
|
|
98
|
+
// A binding hands the datastore to every tool the agent's owner lets
|
|
99
|
+
// read it: strictly the agent owner's own datastore on the owner's
|
|
100
|
+
// own agent (A2/S2-2). Not even the stdio operator crosses owners.
|
|
101
|
+
const { agent } = await requireAgentAccess(ctx, args.agentId, "read");
|
|
102
|
+
requireBindingOwner(ctx, agent);
|
|
101
103
|
const datastore = await requireOwnedDatastore(ctx.db, args.datastoreId, ctx.principal.id);
|
|
104
|
+
if (datastore.ownerId !== agent.ownerId) {
|
|
105
|
+
throw new McpError(403, "Only a datastore owned by the agent's owner can be attached to it.");
|
|
106
|
+
}
|
|
102
107
|
const boundName = args.boundName ?? datastore.name;
|
|
103
108
|
try {
|
|
104
109
|
await attachDatastore(args.agentId, args.datastoreId, ctx.db, boundName);
|
|
@@ -121,8 +126,10 @@ export function registerDatastoreTools(mcp) {
|
|
|
121
126
|
required: ["agentId", "boundName"],
|
|
122
127
|
},
|
|
123
128
|
handler: async (args, ctx) => {
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
// The agent's owner may remove any binding from it, including one to
|
|
130
|
+
// another owner's datastore left behind by a transfer.
|
|
131
|
+
const { agent } = await requireAgentAccess(ctx, args.agentId, "read");
|
|
132
|
+
requireBindingOwner(ctx, agent);
|
|
126
133
|
await detachDatastore(args.agentId, args.boundName, ctx.db);
|
|
127
134
|
return textResult({ detached: true });
|
|
128
135
|
},
|
|
@@ -136,7 +143,7 @@ export function registerDatastoreTools(mcp) {
|
|
|
136
143
|
required: ["agentId", "key"],
|
|
137
144
|
},
|
|
138
145
|
handler: async (args, ctx) => {
|
|
139
|
-
await
|
|
146
|
+
await requireAgentAccess(ctx, args.agentId, "owner");
|
|
140
147
|
if (args.boundName) {
|
|
141
148
|
await requireReadableSharedDatastore(ctx.db, args.agentId, args.boundName, ctx.principal.id);
|
|
142
149
|
const accessor = buildSharedDatastoreAccessor(args.agentId, ctx.providers.datastore, ctx.db);
|
|
@@ -156,7 +163,7 @@ export function registerDatastoreTools(mcp) {
|
|
|
156
163
|
required: ["agentId"],
|
|
157
164
|
},
|
|
158
165
|
handler: async (args, ctx) => {
|
|
159
|
-
await
|
|
166
|
+
await requireAgentAccess(ctx, args.agentId, "owner");
|
|
160
167
|
if (args.boundName) {
|
|
161
168
|
await requireReadableSharedDatastore(ctx.db, args.agentId, args.boundName, ctx.principal.id);
|
|
162
169
|
const accessor = buildSharedDatastoreAccessor(args.agentId, ctx.providers.datastore, ctx.db);
|
|
@@ -183,7 +190,7 @@ export function registerDatastoreTools(mcp) {
|
|
|
183
190
|
required: ["agentId", "key", "value"],
|
|
184
191
|
},
|
|
185
192
|
handler: async (args, ctx) => {
|
|
186
|
-
await
|
|
193
|
+
await requireAgentAccess(ctx, args.agentId, "owner");
|
|
187
194
|
if (args.boundName) {
|
|
188
195
|
await requireMutableSharedDatastore(ctx.db, args.agentId, args.boundName, ctx.principal.id);
|
|
189
196
|
const accessor = buildSharedDatastoreAccessor(args.agentId, ctx.providers.datastore, ctx.db);
|
|
@@ -203,7 +210,7 @@ export function registerDatastoreTools(mcp) {
|
|
|
203
210
|
required: ["agentId", "key"],
|
|
204
211
|
},
|
|
205
212
|
handler: async (args, ctx) => {
|
|
206
|
-
await
|
|
213
|
+
await requireAgentAccess(ctx, args.agentId, "owner");
|
|
207
214
|
if (args.boundName) {
|
|
208
215
|
await requireMutableSharedDatastore(ctx.db, args.agentId, args.boundName, ctx.principal.id);
|
|
209
216
|
const accessor = buildSharedDatastoreAccessor(args.agentId, ctx.providers.datastore, ctx.db);
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* grant_access / revoke_access / list_access: the owner's sharing controls
|
|
3
|
+
* (resource-sharing grants spec §3.11). Phase 1 shares agents only; other
|
|
4
|
+
* resource types are refused as "not shareable yet".
|
|
5
|
+
*
|
|
6
|
+
* - Only the resource's owner (or the stdio operator) grants and revokes.
|
|
7
|
+
* Admins get no implicit access: they may only list_access, for incident
|
|
8
|
+
* response ("who can reach this?"), and reassign with make_owner.
|
|
9
|
+
* - One grant per resource and grantee, so granting again replaces the
|
|
10
|
+
* level (also downgrades). Everyone grants are capped below write.
|
|
11
|
+
* - Takes effect on the next check; runs already in flight keep going.
|
|
12
|
+
*/
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
import { Prisma } from "#prisma";
|
|
15
|
+
import { EVERYONE_KEY, EVERYONE_MAX, LEVELS, SHAREABLE_TYPES, accessRank, atLeast, isLevel, isResourceType, principalGranteeKey, } from "../../core/grants.js";
|
|
16
|
+
import { agentNotFound, assertAgentAccess, agentAccess } from "../auth/access.js";
|
|
17
|
+
import { permissionsOf } from "../auth/resource-server.js";
|
|
18
|
+
import { McpError } from "../errors.js";
|
|
19
|
+
import { textResult } from "./text-result.js";
|
|
20
|
+
const GranteeSchema = z.union([
|
|
21
|
+
z.literal("everyone"),
|
|
22
|
+
z.object({ subject: z.string().min(1).max(512) }).strict(),
|
|
23
|
+
z.object({ principalId: z.string().min(1).max(128) }).strict(),
|
|
24
|
+
]);
|
|
25
|
+
const TargetSchema = z.object({
|
|
26
|
+
resourceType: z.string().min(1).max(64),
|
|
27
|
+
resourceId: z.string().min(1).max(128),
|
|
28
|
+
});
|
|
29
|
+
const GrantSchema = TargetSchema.extend({ grantee: GranteeSchema, level: z.string().min(1).max(64) }).strict();
|
|
30
|
+
const RevokeSchema = TargetSchema.extend({ grantee: GranteeSchema }).strict();
|
|
31
|
+
const ListSchema = TargetSchema.strict();
|
|
32
|
+
function parse(schema, label, args) {
|
|
33
|
+
const result = schema.safeParse(args);
|
|
34
|
+
if (result.success)
|
|
35
|
+
return result.data;
|
|
36
|
+
const details = result.error.issues.map((i) => `${i.path.join(".") || "input"}: ${i.message}`).join("; ");
|
|
37
|
+
throw new McpError(400, `Invalid ${label} arguments: ${details}`);
|
|
38
|
+
}
|
|
39
|
+
function shareableType(value) {
|
|
40
|
+
if (!isResourceType(value) || !SHAREABLE_TYPES.includes(value)) {
|
|
41
|
+
throw new McpError(400, `Resource type "${value}" is not shareable yet (shareable: ${SHAREABLE_TYPES.join(", ")}).`);
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
/** The grantee's principal (must have signed in once: never created here), or null for everyone. */
|
|
46
|
+
async function resolveGrantee(db, grantee) {
|
|
47
|
+
if (grantee === "everyone")
|
|
48
|
+
return null;
|
|
49
|
+
const principal = "subject" in grantee
|
|
50
|
+
? await db.principal.findUnique({ where: { subject: grantee.subject } })
|
|
51
|
+
: await db.principal.findUnique({ where: { id: grantee.principalId } });
|
|
52
|
+
if (!principal) {
|
|
53
|
+
throw new McpError(404, "Grantee not found: they must have signed in to wardby at least once.");
|
|
54
|
+
}
|
|
55
|
+
return principal;
|
|
56
|
+
}
|
|
57
|
+
/** Grant management is the owner's (or the stdio operator's). Phase 1: agents. */
|
|
58
|
+
async function requireOwnedResource(ctx, db, type, id) {
|
|
59
|
+
// Only "agent" reaches here in Phase 1 (shareableType).
|
|
60
|
+
void type;
|
|
61
|
+
const row = await db.agent.findUnique({ where: { id } });
|
|
62
|
+
return (await assertAgentAccess(ctx, row, id, "owner", db)).agent;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The ownership check and the write in one Serializable transaction (review
|
|
66
|
+
* M3): a concurrent make_owner, which resets grants in its own transaction,
|
|
67
|
+
* conflicts instead of letting the old owner's grant land on the new
|
|
68
|
+
* owner's agent.
|
|
69
|
+
*/
|
|
70
|
+
function inSerializable(ctx, fn) {
|
|
71
|
+
return ctx.db.$transaction((tx) => fn(tx), { isolationLevel: Prisma.TransactionIsolationLevel.Serializable });
|
|
72
|
+
}
|
|
73
|
+
function isAdmin(ctx) {
|
|
74
|
+
return ctx.scopes.has("agents:admin") && permissionsOf(ctx.roles).has("agents:admin");
|
|
75
|
+
}
|
|
76
|
+
const TYPE_PROPERTIES = {
|
|
77
|
+
// No enum: another type gets a clear "not shareable yet" from the handler.
|
|
78
|
+
resourceType: { type: "string", description: 'Only "agent" is shareable today.' },
|
|
79
|
+
resourceId: { type: "string" },
|
|
80
|
+
};
|
|
81
|
+
const GRANTEE_PROPERTY = {
|
|
82
|
+
description: 'One principal, as {"subject": "<IdP subject>"} or {"principalId": "<id>"}, or "everyone".',
|
|
83
|
+
anyOf: [
|
|
84
|
+
{ type: "string", enum: ["everyone"] },
|
|
85
|
+
{
|
|
86
|
+
type: "object",
|
|
87
|
+
additionalProperties: false,
|
|
88
|
+
properties: { subject: { type: "string" } },
|
|
89
|
+
required: ["subject"],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
type: "object",
|
|
93
|
+
additionalProperties: false,
|
|
94
|
+
properties: { principalId: { type: "string" } },
|
|
95
|
+
required: ["principalId"],
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
export function registerGrantTools(mcp) {
|
|
100
|
+
mcp.registerTool({
|
|
101
|
+
name: "grant_access",
|
|
102
|
+
scope: "agents:write",
|
|
103
|
+
description: "Shares an agent you own with one principal or with everyone, at a level: " +
|
|
104
|
+
"read (see its config, never secret values or other owners' tool code); " +
|
|
105
|
+
"execute (also trigger runs and see the runs they triggered); " +
|
|
106
|
+
"write (also change its name, prompt, model, budget amount, max turns, effort, memory on/off and schedule, attach tools they can use and detach tools, and create webhooks). " +
|
|
107
|
+
"Owner-only whatever the level: the coding profile (task, base ref, protected paths, task-override opt-in, image, packages, limits), kind, budget group, sub-agents, secret/datastore/repository bindings, tool capabilities, memory and datastore contents, grants, delete. " +
|
|
108
|
+
"Consequences: execute lets them run your agent with your tools, secrets, datastores and repository, and every run shares the agent's memory; they supply no task text unless it's a coding agent with allowWebhookTaskOverride. " +
|
|
109
|
+
"Write lets them rewrite what those runs do: the prompt can make a run use everything the agent can already reach (the capabilities you granted, its memory, its linked repositories), and on a coding agent the prompt is part of every coding task, so write directs work done with your GitHub access. " +
|
|
110
|
+
"Granting again replaces the level. Everyone is capped at execute. The grantee must have signed in once.",
|
|
111
|
+
inputSchema: {
|
|
112
|
+
type: "object",
|
|
113
|
+
additionalProperties: false,
|
|
114
|
+
properties: {
|
|
115
|
+
...TYPE_PROPERTIES,
|
|
116
|
+
grantee: GRANTEE_PROPERTY,
|
|
117
|
+
level: { type: "string", description: "Agents: read < execute < write." },
|
|
118
|
+
},
|
|
119
|
+
required: ["resourceType", "resourceId", "grantee", "level"],
|
|
120
|
+
},
|
|
121
|
+
handler: async (rawArgs, ctx) => {
|
|
122
|
+
const args = parse(GrantSchema, "grant_access", rawArgs);
|
|
123
|
+
const type = shareableType(args.resourceType);
|
|
124
|
+
if (!isLevel(type, args.level)) {
|
|
125
|
+
throw new McpError(400, `Level "${args.level}" is not valid for ${type} (${LEVELS[type].join(" < ")}).`);
|
|
126
|
+
}
|
|
127
|
+
const { resource, principal, grant } = await inSerializable(ctx, async (tx) => {
|
|
128
|
+
const resource = await requireOwnedResource(ctx, tx, type, args.resourceId);
|
|
129
|
+
const principal = await resolveGrantee(tx, args.grantee);
|
|
130
|
+
if (principal && (principal.id === resource.ownerId || principal.id === ctx.principal.id)) {
|
|
131
|
+
throw new McpError(400, "The owner already has full access; a grant to yourself or the owner changes nothing.");
|
|
132
|
+
}
|
|
133
|
+
if (!principal && accessRank(type, args.level) > accessRank(type, EVERYONE_MAX[type])) {
|
|
134
|
+
throw new McpError(400, `An everyone grant can be at most ${EVERYONE_MAX[type]}: write for everyone would let anyone rewrite an agent that holds your tools and secrets.`);
|
|
135
|
+
}
|
|
136
|
+
const granteeKey = principal ? principalGranteeKey(principal.id) : EVERYONE_KEY;
|
|
137
|
+
const grant = await tx.resourceGrant.upsert({
|
|
138
|
+
where: { resourceType_resourceId_granteeKey: { resourceType: type, resourceId: resource.id, granteeKey } },
|
|
139
|
+
create: {
|
|
140
|
+
resourceType: type,
|
|
141
|
+
resourceId: resource.id,
|
|
142
|
+
granteeKind: principal ? "principal" : "everyone",
|
|
143
|
+
granteePrincipalId: principal?.id ?? null,
|
|
144
|
+
granteeKey,
|
|
145
|
+
level: args.level,
|
|
146
|
+
source: "owner",
|
|
147
|
+
grantedById: ctx.principal.id,
|
|
148
|
+
},
|
|
149
|
+
update: { level: args.level, source: "owner", grantedById: ctx.principal.id },
|
|
150
|
+
});
|
|
151
|
+
return { resource, principal, grant };
|
|
152
|
+
});
|
|
153
|
+
return textResult({
|
|
154
|
+
granted: true,
|
|
155
|
+
resourceType: type,
|
|
156
|
+
resourceId: resource.id,
|
|
157
|
+
// Echo only what the caller supplied: a principalId never reveals a subject (review M4).
|
|
158
|
+
grantee: !principal
|
|
159
|
+
? "everyone"
|
|
160
|
+
: args.grantee !== "everyone" && "subject" in args.grantee
|
|
161
|
+
? { principalId: principal.id, subject: principal.subject }
|
|
162
|
+
: { principalId: principal.id },
|
|
163
|
+
level: grant.level,
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
mcp.registerTool({
|
|
168
|
+
name: "revoke_access",
|
|
169
|
+
scope: "agents:write",
|
|
170
|
+
description: "Removes a grant on an agent you own. Idempotent. Takes effect on the next check (trigger, delegation, webhook fire); runs already in flight keep going.",
|
|
171
|
+
inputSchema: {
|
|
172
|
+
type: "object",
|
|
173
|
+
additionalProperties: false,
|
|
174
|
+
properties: { ...TYPE_PROPERTIES, grantee: GRANTEE_PROPERTY },
|
|
175
|
+
required: ["resourceType", "resourceId", "grantee"],
|
|
176
|
+
},
|
|
177
|
+
handler: async (rawArgs, ctx) => {
|
|
178
|
+
const args = parse(RevokeSchema, "revoke_access", rawArgs);
|
|
179
|
+
const type = shareableType(args.resourceType);
|
|
180
|
+
const { count } = await inSerializable(ctx, async (tx) => {
|
|
181
|
+
const resource = await requireOwnedResource(ctx, tx, type, args.resourceId);
|
|
182
|
+
const granteeKey = args.grantee === "everyone"
|
|
183
|
+
? EVERYONE_KEY
|
|
184
|
+
: principalGranteeKey((await resolveGrantee(tx, args.grantee)).id);
|
|
185
|
+
return tx.resourceGrant.deleteMany({ where: { resourceType: type, resourceId: resource.id, granteeKey } });
|
|
186
|
+
});
|
|
187
|
+
return textResult({ revoked: count > 0 });
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
mcp.registerTool({
|
|
191
|
+
name: "list_access",
|
|
192
|
+
scope: "agents:read",
|
|
193
|
+
description: "Lists who an agent is shared with (grant metadata only). For its owner, the stdio operator, and admins (incident response).",
|
|
194
|
+
inputSchema: {
|
|
195
|
+
type: "object",
|
|
196
|
+
additionalProperties: false,
|
|
197
|
+
properties: TYPE_PROPERTIES,
|
|
198
|
+
required: ["resourceType", "resourceId"],
|
|
199
|
+
},
|
|
200
|
+
handler: async (rawArgs, ctx) => {
|
|
201
|
+
const args = parse(ListSchema, "list_access", rawArgs);
|
|
202
|
+
const type = shareableType(args.resourceType);
|
|
203
|
+
const resource = await ctx.db.agent.findUnique({ where: { id: args.resourceId } });
|
|
204
|
+
if (!resource)
|
|
205
|
+
throw agentNotFound(args.resourceId);
|
|
206
|
+
if (!isAdmin(ctx)) {
|
|
207
|
+
const access = await agentAccess(ctx, resource);
|
|
208
|
+
if (!atLeast("agent", access, "read"))
|
|
209
|
+
throw agentNotFound(args.resourceId);
|
|
210
|
+
if (access !== "owner") {
|
|
211
|
+
throw new McpError(403, `Agent "${resource.id}": only its owner (or an admin) can list who it is shared with.`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const grants = await ctx.db.resourceGrant.findMany({
|
|
215
|
+
where: { resourceType: type, resourceId: resource.id },
|
|
216
|
+
orderBy: { createdAt: "asc" },
|
|
217
|
+
});
|
|
218
|
+
const principalIds = grants.flatMap((g) => (g.granteePrincipalId ? [g.granteePrincipalId] : []));
|
|
219
|
+
const principals = principalIds.length
|
|
220
|
+
? await ctx.db.principal.findMany({ where: { id: { in: principalIds } } })
|
|
221
|
+
: [];
|
|
222
|
+
const subjectOf = new Map(principals.map((p) => [p.id, p.subject]));
|
|
223
|
+
return textResult({
|
|
224
|
+
resourceType: type,
|
|
225
|
+
resourceId: resource.id,
|
|
226
|
+
ownerId: resource.ownerId,
|
|
227
|
+
grants: grants.map((g) => ({
|
|
228
|
+
grantee: g.granteePrincipalId
|
|
229
|
+
? { principalId: g.granteePrincipalId, subject: subjectOf.get(g.granteePrincipalId) ?? null }
|
|
230
|
+
: "everyone",
|
|
231
|
+
level: g.level,
|
|
232
|
+
source: g.source,
|
|
233
|
+
grantedById: g.grantedById,
|
|
234
|
+
updatedAt: g.updatedAt,
|
|
235
|
+
})),
|
|
236
|
+
});
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { HelpCatalog } from "../../help/catalog.js";
|
|
2
|
+
import type { WardbyMcpServer } from "../server.js";
|
|
3
|
+
export type HelpCatalogLoader = () => Promise<HelpCatalog>;
|
|
4
|
+
/** Registers release-bundled, read-only help without exposing any instance data or credentials. */
|
|
5
|
+
export declare function registerHelpTools(mcp: WardbyMcpServer, loadCatalog?: HelpCatalogLoader): void;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { loadBundledHelpCatalog } from "../../help/runtime.js";
|
|
2
|
+
import { searchHelp } from "../../help/search.js";
|
|
3
|
+
import { McpError } from "../errors.js";
|
|
4
|
+
import { textResult } from "./text-result.js";
|
|
5
|
+
function publicArticle(page) {
|
|
6
|
+
return {
|
|
7
|
+
id: page.id,
|
|
8
|
+
title: page.title,
|
|
9
|
+
summary: page.summary,
|
|
10
|
+
audience: page.audience,
|
|
11
|
+
tags: page.tags,
|
|
12
|
+
appliesTo: page.appliesTo,
|
|
13
|
+
headings: page.headings,
|
|
14
|
+
markdown: page.markdown,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** Registers release-bundled, read-only help without exposing any instance data or credentials. */
|
|
18
|
+
export function registerHelpTools(mcp, loadCatalog = loadBundledHelpCatalog) {
|
|
19
|
+
mcp.registerTool({
|
|
20
|
+
name: "search_help",
|
|
21
|
+
description: "Search Wardby's bundled self-hosted documentation with offline fuzzy matching.",
|
|
22
|
+
scope: "agents:read",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: { query: { type: "string", minLength: 1, maxLength: 200 } },
|
|
26
|
+
required: ["query"],
|
|
27
|
+
additionalProperties: false,
|
|
28
|
+
},
|
|
29
|
+
handler: async (args) => {
|
|
30
|
+
const query = args.query.trim();
|
|
31
|
+
if (!query)
|
|
32
|
+
throw new McpError(400, "search_help requires a non-empty query.");
|
|
33
|
+
const results = searchHelp(await loadCatalog(), query).slice(0, 10);
|
|
34
|
+
return textResult({
|
|
35
|
+
results: results.map((result) => ({
|
|
36
|
+
id: result.page.id,
|
|
37
|
+
title: result.page.title,
|
|
38
|
+
summary: result.page.summary,
|
|
39
|
+
audience: result.page.audience,
|
|
40
|
+
tags: result.page.tags,
|
|
41
|
+
...(result.matchedHeading ? { matchedHeading: result.matchedHeading.text } : {}),
|
|
42
|
+
excerpt: result.excerpt,
|
|
43
|
+
})),
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
mcp.registerTool({
|
|
48
|
+
name: "get_help_article",
|
|
49
|
+
description: "Read one complete Wardby self-hosted help article by its id.",
|
|
50
|
+
scope: "agents:read",
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: "object",
|
|
53
|
+
properties: { id: { type: "string", minLength: 1, maxLength: 120 } },
|
|
54
|
+
required: ["id"],
|
|
55
|
+
additionalProperties: false,
|
|
56
|
+
},
|
|
57
|
+
handler: async (args) => {
|
|
58
|
+
const id = args.id.trim();
|
|
59
|
+
if (!id)
|
|
60
|
+
throw new McpError(400, "get_help_article requires a non-empty id.");
|
|
61
|
+
const page = (await loadCatalog()).pages.find((candidate) => candidate.id === id);
|
|
62
|
+
if (!page)
|
|
63
|
+
throw new McpError(404, `Help article "${id}" not found.`);
|
|
64
|
+
return textResult(publicArticle(page));
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A principal's own code-review host identity (GitHub today). Repository
|
|
3
|
+
* authorization checks the agent owner's access through this identity (see
|
|
4
|
+
* core/repo-access.ts), so linking it is the first step before linking a
|
|
5
|
+
* repository or setting a coding agent's repository. Each tool acts only on
|
|
6
|
+
* the caller; an operator can list and unlink anyone's with
|
|
7
|
+
* `wardby auth host-account`.
|
|
8
|
+
*/
|
|
9
|
+
import { REVIEW_HOST_PROVIDERS } from "../../providers/review-host/types.js";
|
|
10
|
+
import { confirmHostIdentityLink, HostLinkError, startHostIdentityLink, userCallbackPath, } from "../../core/host-identity-links.js";
|
|
11
|
+
import { McpError } from "../errors.js";
|
|
12
|
+
import { canonicalUrl } from "../transport/http-limits.js";
|
|
13
|
+
import { textResult } from "./text-result.js";
|
|
14
|
+
const PROVIDER_PROP = { type: "string", enum: [...REVIEW_HOST_PROVIDERS] };
|
|
15
|
+
function asMcpError(err) {
|
|
16
|
+
return err instanceof HostLinkError ? new McpError(err.status, err.message) : err;
|
|
17
|
+
}
|
|
18
|
+
/** The HTTP origin the host's browser callback must reach, or null over stdio (no canonical URI). */
|
|
19
|
+
function callbackOrigin(canonicalUri) {
|
|
20
|
+
try {
|
|
21
|
+
return canonicalUrl(canonicalUri).origin;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function registerHostAccountTools(mcp) {
|
|
28
|
+
mcp.registerTool({
|
|
29
|
+
name: "link_host_account",
|
|
30
|
+
scope: "agents:write",
|
|
31
|
+
description: "Links your GitHub account to your wardby identity, so agents you own can be given repositories your GitHub account can access. " +
|
|
32
|
+
"Call it with no confirmationCode to get an authorizeUrl; open that in a browser signed in to GitHub. The page you land on shows a " +
|
|
33
|
+
"one-time code: call link_host_account again with confirmationCode set to it (within 10 minutes).",
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: "object",
|
|
36
|
+
additionalProperties: false,
|
|
37
|
+
properties: {
|
|
38
|
+
provider: PROVIDER_PROP,
|
|
39
|
+
confirmationCode: { type: "string", minLength: 1, maxLength: 32 },
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
handler: async (args, ctx) => {
|
|
43
|
+
const provider = args.provider ?? "github";
|
|
44
|
+
try {
|
|
45
|
+
if (args.confirmationCode !== undefined) {
|
|
46
|
+
const linked = await confirmHostIdentityLink({
|
|
47
|
+
db: ctx.db,
|
|
48
|
+
principalId: ctx.principal.id,
|
|
49
|
+
provider,
|
|
50
|
+
confirmationCode: args.confirmationCode,
|
|
51
|
+
});
|
|
52
|
+
return textResult({ linked: true, provider, login: linked.login });
|
|
53
|
+
}
|
|
54
|
+
const authorizer = ctx.providers.hostUserAuthorizers?.[provider];
|
|
55
|
+
if (!authorizer) {
|
|
56
|
+
throw new McpError(400, "GitHub account linking is not configured on this deployment: an operator must set GITHUB_APP_CLIENT_ID and " +
|
|
57
|
+
"GITHUB_APP_CLIENT_SECRET (see docs/code-review-agents.md).");
|
|
58
|
+
}
|
|
59
|
+
const origin = callbackOrigin(ctx.canonicalUri);
|
|
60
|
+
if (!origin) {
|
|
61
|
+
throw new McpError(400, "Linking needs wardby's HTTP transport (the GitHub callback is served at MCP_CANONICAL_URI); " +
|
|
62
|
+
"use an MCP client connected over HTTP, or ask an operator.");
|
|
63
|
+
}
|
|
64
|
+
const started = await startHostIdentityLink({
|
|
65
|
+
db: ctx.db,
|
|
66
|
+
authorizer,
|
|
67
|
+
principalId: ctx.principal.id,
|
|
68
|
+
redirectUri: `${origin}${userCallbackPath(provider)}`,
|
|
69
|
+
});
|
|
70
|
+
return textResult({
|
|
71
|
+
authorizeUrl: started.authorizeUrl,
|
|
72
|
+
expiresAt: started.expiresAt.toISOString(),
|
|
73
|
+
next: "Open authorizeUrl in a browser signed in to the GitHub account to link. Then call link_host_account " +
|
|
74
|
+
"with confirmationCode set to the code the page shows.",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
throw asMcpError(err);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
mcp.registerTool({
|
|
83
|
+
name: "get_host_account",
|
|
84
|
+
scope: "agents:read",
|
|
85
|
+
description: "Shows the GitHub account linked to your wardby identity, if any.",
|
|
86
|
+
inputSchema: { type: "object", additionalProperties: false, properties: {} },
|
|
87
|
+
handler: async (_args, ctx) => {
|
|
88
|
+
const identities = await ctx.db.hostIdentity.findMany({
|
|
89
|
+
where: { principalId: ctx.principal.id },
|
|
90
|
+
orderBy: { provider: "asc" },
|
|
91
|
+
});
|
|
92
|
+
return textResult({
|
|
93
|
+
accounts: identities.map((i) => ({
|
|
94
|
+
provider: i.provider,
|
|
95
|
+
login: i.login,
|
|
96
|
+
hostUserId: i.hostUserId,
|
|
97
|
+
linkedAt: i.linkedAt,
|
|
98
|
+
})),
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
mcp.registerTool({
|
|
103
|
+
name: "unlink_host_account",
|
|
104
|
+
scope: "agents:write",
|
|
105
|
+
description: "Unlinks your GitHub account. Repositories your agents were given through its access stop working until you link again.",
|
|
106
|
+
inputSchema: { type: "object", additionalProperties: false, properties: { provider: PROVIDER_PROP } },
|
|
107
|
+
handler: async (args, ctx) => {
|
|
108
|
+
const provider = args.provider ?? "github";
|
|
109
|
+
const { count } = await ctx.db.hostIdentity.deleteMany({ where: { principalId: ctx.principal.id, provider } });
|
|
110
|
+
await ctx.db.hostIdentityLinkRequest.deleteMany({ where: { principalId: ctx.principal.id, provider } });
|
|
111
|
+
return textResult({ unlinked: count > 0 });
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Operator inspection of agent memory, mirroring the Datastore MCP tools
|
|
3
|
+
* (`./datastore.ts`). Memory is agent *data*, written by every triggerer's
|
|
4
|
+
* runs, so every tool here is owner-only whatever the grants (resource-
|
|
5
|
+
* sharing grants spec §3.4.6): showing it at read or execute would leak one
|
|
6
|
+
* triggerer's run output to another (A6 through memory).
|
|
7
|
+
*/
|
|
2
8
|
import type { WardbyMcpServer } from "../server.js";
|
|
3
9
|
export declare function registerMemoryTools(mcp: WardbyMcpServer): void;
|
package/dist/mcp/tools/memory.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { requireAgentAccess } from "../auth/access.js";
|
|
2
2
|
import { textResult } from "./text-result.js";
|
|
3
3
|
export function registerMemoryTools(mcp) {
|
|
4
4
|
mcp.registerTool({
|
|
@@ -10,7 +10,7 @@ export function registerMemoryTools(mcp) {
|
|
|
10
10
|
required: ["agentId", "key"],
|
|
11
11
|
},
|
|
12
12
|
handler: async (args, ctx) => {
|
|
13
|
-
await
|
|
13
|
+
await requireAgentAccess(ctx, args.agentId, "owner");
|
|
14
14
|
const content = await ctx.providers.memory.get(args.agentId, args.key);
|
|
15
15
|
return textResult({ content: content ?? null });
|
|
16
16
|
},
|
|
@@ -24,7 +24,7 @@ export function registerMemoryTools(mcp) {
|
|
|
24
24
|
required: ["agentId"],
|
|
25
25
|
},
|
|
26
26
|
handler: async (args, ctx) => {
|
|
27
|
-
await
|
|
27
|
+
await requireAgentAccess(ctx, args.agentId, "owner");
|
|
28
28
|
const keys = await ctx.providers.memory.list(args.agentId);
|
|
29
29
|
return textResult(keys);
|
|
30
30
|
},
|
|
@@ -38,7 +38,7 @@ export function registerMemoryTools(mcp) {
|
|
|
38
38
|
required: ["agentId", "key", "content"],
|
|
39
39
|
},
|
|
40
40
|
handler: async (args, ctx) => {
|
|
41
|
-
await
|
|
41
|
+
await requireAgentAccess(ctx, args.agentId, "owner");
|
|
42
42
|
await ctx.providers.memory.set(args.agentId, args.key, args.content);
|
|
43
43
|
return textResult({ ok: true });
|
|
44
44
|
},
|
|
@@ -52,7 +52,7 @@ export function registerMemoryTools(mcp) {
|
|
|
52
52
|
required: ["agentId", "key"],
|
|
53
53
|
},
|
|
54
54
|
handler: async (args, ctx) => {
|
|
55
|
-
await
|
|
55
|
+
await requireAgentAccess(ctx, args.agentId, "owner");
|
|
56
56
|
await ctx.providers.memory.delete(args.agentId, args.key);
|
|
57
57
|
return textResult({ ok: true });
|
|
58
58
|
},
|