@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
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** Agent ids are cuids; anything else could break out of the HTML comment. */
|
|
2
|
+
export const SAFE_AGENT_MARKER = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
|
|
3
|
+
const SAFE_SHA = /^[0-9a-f]{40}$/;
|
|
4
|
+
const MARKER_PREFIX = "<!-- wardby:review:";
|
|
5
|
+
function assertMarker(agentMarker) {
|
|
6
|
+
if (!SAFE_AGENT_MARKER.test(agentMarker))
|
|
7
|
+
throw new Error("review_marker_invalid");
|
|
8
|
+
}
|
|
9
|
+
export function reviewMarker(agentMarker, headSha) {
|
|
10
|
+
assertMarker(agentMarker);
|
|
11
|
+
if (!SAFE_SHA.test(headSha))
|
|
12
|
+
throw new Error("review_marker_invalid");
|
|
13
|
+
return `${MARKER_PREFIX}${agentMarker} sha=${headSha} -->`;
|
|
14
|
+
}
|
|
15
|
+
export function hasReviewMarker(body, agentMarker) {
|
|
16
|
+
assertMarker(agentMarker);
|
|
17
|
+
return body.includes(`${MARKER_PREFIX}${agentMarker} sha=`);
|
|
18
|
+
}
|
|
19
|
+
export function parseReviewMarker(body, agentMarker) {
|
|
20
|
+
assertMarker(agentMarker);
|
|
21
|
+
const match = new RegExp(`${MARKER_PREFIX}${agentMarker} sha=([0-9a-f]{40}) -->`).exec(body);
|
|
22
|
+
return match ? match[1] : null;
|
|
23
|
+
}
|
|
24
|
+
export function verdictConclusion(verdict) {
|
|
25
|
+
if (verdict === "APPROVE")
|
|
26
|
+
return "success";
|
|
27
|
+
if (verdict === "CHANGES_REQUESTED")
|
|
28
|
+
return "failure";
|
|
29
|
+
return "neutral";
|
|
30
|
+
}
|
|
31
|
+
const BADGES = {
|
|
32
|
+
APPROVE: "✅ **Approved**",
|
|
33
|
+
CHANGES_REQUESTED: "❌ **Changes requested**",
|
|
34
|
+
COMMENT: "💬 **Comments**",
|
|
35
|
+
};
|
|
36
|
+
const FINDING_PREFIX = "<!-- wardby:finding:";
|
|
37
|
+
/** Tags an inline comment with the agent that wrote it, so only that agent resolves its thread. */
|
|
38
|
+
export function findingMarker(agentMarker) {
|
|
39
|
+
assertMarker(agentMarker);
|
|
40
|
+
return `${FINDING_PREFIX}${agentMarker} -->`;
|
|
41
|
+
}
|
|
42
|
+
export function hasFindingMarker(body, agentMarker) {
|
|
43
|
+
return body.includes(findingMarker(agentMarker));
|
|
44
|
+
}
|
|
45
|
+
export function renderInlineComment(comment, agentMarker) {
|
|
46
|
+
return `**[${comment.severity}]** ${comment.body}\n\n${findingMarker(agentMarker)}`;
|
|
47
|
+
}
|
|
48
|
+
export function renderSummaryComment(input) {
|
|
49
|
+
const sections = [
|
|
50
|
+
reviewMarker(input.agentMarker, input.headSha),
|
|
51
|
+
`${BADGES[input.verdict]} — reviewed \`${input.headSha.slice(0, 7)}\``,
|
|
52
|
+
input.summary,
|
|
53
|
+
input.body,
|
|
54
|
+
];
|
|
55
|
+
if (input.outside.length > 0) {
|
|
56
|
+
sections.push(["## Outside the diff", ...input.outside.map((c) => `- **[${c.severity}] ${c.path}:${c.line}** ${c.body}`)].join("\n"));
|
|
57
|
+
}
|
|
58
|
+
return sections.join("\n\n");
|
|
59
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-neutral code-review surface for native agents. GitHub is the first
|
|
3
|
+
* implementation (./github.ts); Bitbucket Cloud is anticipated. Every method
|
|
4
|
+
* takes the repository and mints its own least-permission credential — no
|
|
5
|
+
* method accepts a token or a permission. See
|
|
6
|
+
* docs/private/2026-09-25-code-review-host-design.md §5.
|
|
7
|
+
*/
|
|
8
|
+
export type ReviewHostProvider = "github";
|
|
9
|
+
export declare const REVIEW_HOST_PROVIDERS: readonly ReviewHostProvider[];
|
|
10
|
+
export type ReviewVerdict = "APPROVE" | "CHANGES_REQUESTED" | "COMMENT";
|
|
11
|
+
export type CheckConclusion = "success" | "failure" | "neutral";
|
|
12
|
+
export type CommentSide = "LEFT" | "RIGHT";
|
|
13
|
+
export interface PullRequestFileView {
|
|
14
|
+
filename: string;
|
|
15
|
+
status: string;
|
|
16
|
+
additions: number;
|
|
17
|
+
deletions: number;
|
|
18
|
+
previousFilename?: string;
|
|
19
|
+
patch: string;
|
|
20
|
+
patchTruncated: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** One of this agent's own review threads that is still unresolved. */
|
|
23
|
+
export interface ReviewThreadView {
|
|
24
|
+
/** Opaque host id; pass it back in PublishReviewInput.resolveThreadIds. */
|
|
25
|
+
id: string;
|
|
26
|
+
path: string;
|
|
27
|
+
/** The line in the current head, or null when the thread is outdated (its line no longer exists). */
|
|
28
|
+
line: number | null;
|
|
29
|
+
outdated: boolean;
|
|
30
|
+
/** The finding as posted, without its marker, capped at 1,000 characters. */
|
|
31
|
+
body: string;
|
|
32
|
+
}
|
|
33
|
+
export interface PullRequestView {
|
|
34
|
+
number: number;
|
|
35
|
+
title: string;
|
|
36
|
+
body: string;
|
|
37
|
+
author: string | null;
|
|
38
|
+
state: string;
|
|
39
|
+
merged: boolean;
|
|
40
|
+
draft: boolean;
|
|
41
|
+
baseRef: string;
|
|
42
|
+
headRef: string;
|
|
43
|
+
headSha: string;
|
|
44
|
+
isFork: boolean;
|
|
45
|
+
htmlUrl: string;
|
|
46
|
+
/** Head sha recorded in this agent's summary comment, if it reviewed before. */
|
|
47
|
+
lastReviewedSha: string | null;
|
|
48
|
+
/** Set when `files` is the compare of `comparedFrom...headSha` rather than the whole PR. */
|
|
49
|
+
comparedFrom: string | null;
|
|
50
|
+
/**
|
|
51
|
+
* The base branch was merged into the PR since `comparedFrom`: `files` is
|
|
52
|
+
* then the PR's own diff (against its base), limited to files that changed
|
|
53
|
+
* since `comparedFrom`, so base-branch changes are left out.
|
|
54
|
+
*/
|
|
55
|
+
baseMergedSince: boolean;
|
|
56
|
+
files: PullRequestFileView[];
|
|
57
|
+
/** This agent's own unresolved review threads on the PR (the first 100 threads are searched). */
|
|
58
|
+
openThreads: ReviewThreadView[];
|
|
59
|
+
}
|
|
60
|
+
export interface PullRequestHead {
|
|
61
|
+
headSha: string;
|
|
62
|
+
isFork: boolean;
|
|
63
|
+
state: string;
|
|
64
|
+
}
|
|
65
|
+
export type FileReadResult = {
|
|
66
|
+
kind: "file";
|
|
67
|
+
path: string;
|
|
68
|
+
ref: string;
|
|
69
|
+
totalLines: number;
|
|
70
|
+
startLine: number;
|
|
71
|
+
endLine: number;
|
|
72
|
+
truncated: boolean;
|
|
73
|
+
content: string;
|
|
74
|
+
} | {
|
|
75
|
+
kind: "directory";
|
|
76
|
+
path: string;
|
|
77
|
+
entries: string[];
|
|
78
|
+
} | {
|
|
79
|
+
kind: "not_found";
|
|
80
|
+
path: string;
|
|
81
|
+
};
|
|
82
|
+
export interface FileListView {
|
|
83
|
+
ref: string;
|
|
84
|
+
count: number;
|
|
85
|
+
truncated: boolean;
|
|
86
|
+
files: string[];
|
|
87
|
+
}
|
|
88
|
+
export interface InlineComment {
|
|
89
|
+
path: string;
|
|
90
|
+
line: number;
|
|
91
|
+
side: CommentSide;
|
|
92
|
+
severity: string;
|
|
93
|
+
body: string;
|
|
94
|
+
}
|
|
95
|
+
export interface PublishReviewInput {
|
|
96
|
+
prNumber: number;
|
|
97
|
+
headSha: string;
|
|
98
|
+
verdict: ReviewVerdict;
|
|
99
|
+
summary: string;
|
|
100
|
+
body: string;
|
|
101
|
+
comments: InlineComment[];
|
|
102
|
+
/** Identifies this agent's summary comment; the agent id. */
|
|
103
|
+
agentMarker: string;
|
|
104
|
+
/**
|
|
105
|
+
* Names a completed check to create when no checkId is supplied (a run not
|
|
106
|
+
* started by a host event). With neither, no check is created.
|
|
107
|
+
*/
|
|
108
|
+
checkName?: string;
|
|
109
|
+
/** The run's own in-progress check, when the control plane started one. */
|
|
110
|
+
checkId?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Threads to resolve because this head fixes them. Only this agent's own
|
|
113
|
+
* unresolved threads on this PR are resolved; any other id is skipped.
|
|
114
|
+
*/
|
|
115
|
+
resolveThreadIds?: string[];
|
|
116
|
+
}
|
|
117
|
+
export type PublishReviewResult = {
|
|
118
|
+
published: true;
|
|
119
|
+
reviewUrl: string | null;
|
|
120
|
+
summaryCommentUrl: string;
|
|
121
|
+
/** Null when no check was completed or created (neither checkId nor checkName). */
|
|
122
|
+
checkId: string | null;
|
|
123
|
+
/** The verdict's check mapping — informational when checkId is null. */
|
|
124
|
+
checkConclusion: CheckConclusion;
|
|
125
|
+
inlineCount: number;
|
|
126
|
+
outsideDiffCount: number;
|
|
127
|
+
resolvedThreadIds: string[];
|
|
128
|
+
/** Requested ids that were not resolved: not this agent's open thread on this PR, or the host refused. */
|
|
129
|
+
skippedThreadIds: string[];
|
|
130
|
+
} | {
|
|
131
|
+
published: false;
|
|
132
|
+
reason: "stale_head";
|
|
133
|
+
currentHeadSha: string;
|
|
134
|
+
};
|
|
135
|
+
export interface CommentInput {
|
|
136
|
+
number: number;
|
|
137
|
+
body: string;
|
|
138
|
+
replyToReviewCommentId?: string;
|
|
139
|
+
}
|
|
140
|
+
/** A comment the App wrote, to edit later: a conversation comment or a reply in a review thread. */
|
|
141
|
+
export interface EditCommentInput {
|
|
142
|
+
kind: "conversation" | "inline";
|
|
143
|
+
id: string;
|
|
144
|
+
body: string;
|
|
145
|
+
}
|
|
146
|
+
export interface CommentRef {
|
|
147
|
+
/**
|
|
148
|
+
* "conversation" = a top-level comment on an issue/PR conversation; "inline" = a comment on a diff line (review
|
|
149
|
+
* thread); "subject" = the issue or PR itself (its title/description), with `id` its number.
|
|
150
|
+
*/
|
|
151
|
+
kind: "conversation" | "inline" | "subject";
|
|
152
|
+
id: string;
|
|
153
|
+
}
|
|
154
|
+
export interface StartCheckInput {
|
|
155
|
+
headSha: string;
|
|
156
|
+
name: string;
|
|
157
|
+
}
|
|
158
|
+
export interface CompleteCheckInput {
|
|
159
|
+
checkId: string;
|
|
160
|
+
conclusion: CheckConclusion;
|
|
161
|
+
title: string;
|
|
162
|
+
summary: string;
|
|
163
|
+
text?: string;
|
|
164
|
+
detailsUrl?: string;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* A user's effective permission on one repository, host-neutral and ranked
|
|
168
|
+
* none < read < triage < write < maintain < admin. GitHub maps its
|
|
169
|
+
* collaborator permission onto these directly; GitLab would map reporter ->
|
|
170
|
+
* read, developer -> write, maintainer -> maintain, owner -> admin.
|
|
171
|
+
*/
|
|
172
|
+
export type HostPermission = "none" | "read" | "triage" | "write" | "maintain" | "admin";
|
|
173
|
+
export declare const HOST_PERMISSION_RANK: Readonly<Record<HostPermission, number>>;
|
|
174
|
+
/** A host user, by its immutable numeric id (as text) and its current login. */
|
|
175
|
+
export interface HostUser {
|
|
176
|
+
id: string;
|
|
177
|
+
login: string;
|
|
178
|
+
}
|
|
179
|
+
export interface CodeReviewHost {
|
|
180
|
+
readonly provider: ReviewHostProvider;
|
|
181
|
+
/**
|
|
182
|
+
* The user's effective permission on `repository`, asked with the App's own
|
|
183
|
+
* installation credential (never a user token). Answers only for the user
|
|
184
|
+
* with this id: a login that now names someone else is re-resolved by id,
|
|
185
|
+
* and `login` in the result is the user's current login.
|
|
186
|
+
*/
|
|
187
|
+
repositoryPermission(repository: string, user: HostUser): Promise<{
|
|
188
|
+
level: HostPermission;
|
|
189
|
+
login: string;
|
|
190
|
+
}>;
|
|
191
|
+
readPullRequest(repository: string, prNumber: number, opts: {
|
|
192
|
+
sinceSha?: string;
|
|
193
|
+
maxPatchChars: number;
|
|
194
|
+
agentMarker: string;
|
|
195
|
+
}): Promise<PullRequestView>;
|
|
196
|
+
pullRequestHead(repository: string, prNumber: number): Promise<PullRequestHead>;
|
|
197
|
+
readFile(repository: string, path: string, ref: string | undefined, window: {
|
|
198
|
+
startLine: number;
|
|
199
|
+
maxLines: number;
|
|
200
|
+
}): Promise<FileReadResult>;
|
|
201
|
+
listFiles(repository: string, ref: string | undefined, pathPrefix?: string): Promise<FileListView>;
|
|
202
|
+
publishReview(repository: string, input: PublishReviewInput): Promise<PublishReviewResult>;
|
|
203
|
+
/** `id` identifies the new comment for editComment; a reply is an "inline" comment, anything else "conversation". */
|
|
204
|
+
comment(repository: string, input: CommentInput): Promise<{
|
|
205
|
+
url: string;
|
|
206
|
+
id: string;
|
|
207
|
+
}>;
|
|
208
|
+
/** Replaces the body of a comment the App wrote. */
|
|
209
|
+
editComment(repository: string, input: EditCommentInput): Promise<void>;
|
|
210
|
+
/** Marks a comment as picked up (GitHub: a 👀 reaction); a host without reactions may do nothing. */
|
|
211
|
+
acknowledge(repository: string, target: CommentRef): Promise<void>;
|
|
212
|
+
startCheck(repository: string, input: StartCheckInput): Promise<{
|
|
213
|
+
checkId: string;
|
|
214
|
+
}>;
|
|
215
|
+
completeCheck(repository: string, input: CompleteCheckInput): Promise<void>;
|
|
216
|
+
}
|
|
217
|
+
export type ReviewHostErrorCode = "host_not_installed" | "host_permission_missing" | "host_api_error" | "host_invalid_response";
|
|
218
|
+
export declare class ReviewHostError extends Error {
|
|
219
|
+
readonly code: ReviewHostErrorCode;
|
|
220
|
+
constructor(code: ReviewHostErrorCode, message?: string);
|
|
221
|
+
}
|
|
222
|
+
export type ReviewHostRegistry = Partial<Record<ReviewHostProvider, CodeReviewHost>>;
|
|
223
|
+
/**
|
|
224
|
+
* A host's user-authorization (OAuth web) flow, used only to learn who a
|
|
225
|
+
* wardby principal is on the host. Implementations never store or return the
|
|
226
|
+
* user token: `complete` reads the user and revokes the token at once.
|
|
227
|
+
*/
|
|
228
|
+
export interface HostUserAuthorizer {
|
|
229
|
+
readonly provider: ReviewHostProvider;
|
|
230
|
+
authorizeUrl(input: {
|
|
231
|
+
state: string;
|
|
232
|
+
codeChallenge: string;
|
|
233
|
+
redirectUri: string;
|
|
234
|
+
}): string;
|
|
235
|
+
complete(input: {
|
|
236
|
+
code: string;
|
|
237
|
+
codeVerifier: string;
|
|
238
|
+
redirectUri: string;
|
|
239
|
+
}): Promise<{
|
|
240
|
+
hostUserId: string;
|
|
241
|
+
login: string;
|
|
242
|
+
}>;
|
|
243
|
+
}
|
|
244
|
+
export type HostUserAuthorizerRegistry = Partial<Record<ReviewHostProvider, HostUserAuthorizer>>;
|
|
245
|
+
/**
|
|
246
|
+
* Host-neutral shape a webhook adapter (github-events.ts) normalises its
|
|
247
|
+
* provider payload into, for src/core/host-events.ts to route.
|
|
248
|
+
*/
|
|
249
|
+
export type HostEvent = {
|
|
250
|
+
kind: "pr_updated";
|
|
251
|
+
provider: ReviewHostProvider;
|
|
252
|
+
repository: string;
|
|
253
|
+
prNumber: number;
|
|
254
|
+
headSha: string;
|
|
255
|
+
isFork: boolean;
|
|
256
|
+
} | {
|
|
257
|
+
kind: "check_rerun";
|
|
258
|
+
provider: ReviewHostProvider;
|
|
259
|
+
repository: string;
|
|
260
|
+
prNumber: number;
|
|
261
|
+
headSha: string;
|
|
262
|
+
checkName: string;
|
|
263
|
+
} | {
|
|
264
|
+
kind: "mention";
|
|
265
|
+
provider: ReviewHostProvider;
|
|
266
|
+
repository: string;
|
|
267
|
+
number: number;
|
|
268
|
+
isPullRequest: boolean;
|
|
269
|
+
comment: CommentRef;
|
|
270
|
+
/** Set when the mention is inside an inline review thread. */
|
|
271
|
+
replyToReviewCommentId?: string;
|
|
272
|
+
/** The comment text; for a "subject" mention, the issue/PR description. */
|
|
273
|
+
body: string;
|
|
274
|
+
author: string;
|
|
275
|
+
/** The author's immutable numeric host user id, as text; their permission is checked by it. */
|
|
276
|
+
authorId: string;
|
|
277
|
+
/** The issue or PR the mention is on, when the payload carries it. */
|
|
278
|
+
subject?: {
|
|
279
|
+
title: string;
|
|
280
|
+
body: string;
|
|
281
|
+
};
|
|
282
|
+
/** The run that opened this PR, when its description carries a valid run marker. */
|
|
283
|
+
priorRunId?: string;
|
|
284
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-neutral code-review surface for native agents. GitHub is the first
|
|
3
|
+
* implementation (./github.ts); Bitbucket Cloud is anticipated. Every method
|
|
4
|
+
* takes the repository and mints its own least-permission credential — no
|
|
5
|
+
* method accepts a token or a permission. See
|
|
6
|
+
* docs/private/2026-09-25-code-review-host-design.md §5.
|
|
7
|
+
*/
|
|
8
|
+
export const REVIEW_HOST_PROVIDERS = ["github"];
|
|
9
|
+
export const HOST_PERMISSION_RANK = {
|
|
10
|
+
none: 0,
|
|
11
|
+
read: 1,
|
|
12
|
+
triage: 2,
|
|
13
|
+
write: 3,
|
|
14
|
+
maintain: 4,
|
|
15
|
+
admin: 5,
|
|
16
|
+
};
|
|
17
|
+
export class ReviewHostError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
constructor(code, message = code) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.code = code;
|
|
22
|
+
this.name = "ReviewHostError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type GitHubRepositoryAccess } from "./github.js";
|
|
2
|
-
import type { FinalizeChangesDetails, FinalizeChangesResult, PreparedWorkspace, VcsPrepareInput, VcsProvider } from "./types.js";
|
|
1
|
+
import { type GitHubRepositoryAccess, type RepositoryFileInput } from "./github.js";
|
|
2
|
+
import type { ContinuationFinishedDetails, ContinuationOutcome, FinalizeChangesDetails, FinalizeChangesResult, PreparedWorkspace, VcsPrepareInput, VcsProvider } from "./types.js";
|
|
3
3
|
export declare const DEFAULT_MAX_CHANGED_FILES = 1000;
|
|
4
4
|
export declare const DEFAULT_MAX_DIFF_BYTES: number;
|
|
5
5
|
export interface GitCommandOptions {
|
|
@@ -43,6 +43,18 @@ export interface GitVcsProviderOptions {
|
|
|
43
43
|
/** Test-only transport override; production composition always uses github.com. */
|
|
44
44
|
cloneUrlForRepository?: (repository: string) => string;
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Whether a changed path is protected, in this order: the WARDBY_PROTECTED_PATHS
|
|
48
|
+
* baseline's exception (.wardby/services.yaml, which a builder may propose; it
|
|
49
|
+
* takes effect only after merge, docs/coding-services.md) is never protected;
|
|
50
|
+
* anything else under the baseline (.wardby/**) always is, whatever the agent's
|
|
51
|
+
* exceptions say; any other path is protected when it matches one of the
|
|
52
|
+
* agent's `patterns` and is not one of its exceptions (entries with a leading
|
|
53
|
+
* "!", each a literal path, so order does not matter). The baseline is applied
|
|
54
|
+
* here, at enforcement, rather than stored, so every existing agent and
|
|
55
|
+
* in-flight run gets it.
|
|
56
|
+
*/
|
|
57
|
+
export declare function protectedPathMatcher(patterns: readonly string[]): (path: string) => boolean;
|
|
46
58
|
export declare class GitVcsProvider implements VcsProvider {
|
|
47
59
|
private readonly options;
|
|
48
60
|
private readonly rootDir;
|
|
@@ -74,10 +86,8 @@ export declare class GitVcsProvider implements VcsProvider {
|
|
|
74
86
|
* github.ts). Safe to call more than once for the same run. Same
|
|
75
87
|
* never-throw contract as notifyContinuationStarted.
|
|
76
88
|
*/
|
|
77
|
-
notifyContinuationFinished(workspace: PreparedWorkspace, outcome:
|
|
78
|
-
|
|
79
|
-
agentName?: string;
|
|
80
|
-
}): Promise<void>;
|
|
89
|
+
notifyContinuationFinished(workspace: PreparedWorkspace, outcome: ContinuationOutcome, details?: ContinuationFinishedDetails): Promise<void>;
|
|
90
|
+
readRepositoryFile(input: RepositoryFileInput): Promise<string | null>;
|
|
81
91
|
private validateInput;
|
|
82
92
|
private expectedPaths;
|
|
83
93
|
private validatePrepared;
|
|
@@ -2,6 +2,9 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { lstat, mkdir, opendir, readFile, readlink, realpath, rm } from "node:fs/promises";
|
|
3
3
|
import { isAbsolute, resolve, sep } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { gitExcludePathspecs, normalizeCollectExclusions } from "../../coding/collect-exclude.js";
|
|
6
|
+
import { WARDBY_PROTECTED_PATHS, isProtectedPathException, isWellFormedProtectedPath, protectedPathBody, protectsSomePath, } from "../../coding/protected-paths.js";
|
|
7
|
+
import { ensurePrivateDirectory } from "../../core/private-directory.js";
|
|
5
8
|
import { MAX_REDACTED_SPAN, redactTokenShapedValues, normalizeGitHubRepository, normalizeGitRef, } from "../../coding/protocol.js";
|
|
6
9
|
import { isSafeGitHubInstallationToken } from "./github.js";
|
|
7
10
|
export const DEFAULT_MAX_CHANGED_FILES = 1_000;
|
|
@@ -138,14 +141,10 @@ export class NodeGitCommandRunner {
|
|
|
138
141
|
});
|
|
139
142
|
}
|
|
140
143
|
}
|
|
144
|
+
/** Validates one protectedPaths entry; a leading "!" makes it an exception (see protectedPathMatcher). */
|
|
141
145
|
function validateProtectedPath(value) {
|
|
142
146
|
const path = value.trim();
|
|
143
|
-
if (!path
|
|
144
|
-
Buffer.byteLength(path, "utf8") > 512 ||
|
|
145
|
-
path.startsWith("/") ||
|
|
146
|
-
path.startsWith("./") ||
|
|
147
|
-
path.includes("\\") ||
|
|
148
|
-
path.split("/").some((part) => !part || part === "." || part === "..")) {
|
|
147
|
+
if (Buffer.byteLength(path, "utf8") > 512 || !isWellFormedProtectedPath(path)) {
|
|
149
148
|
throw new Error("vcs_protected_path_invalid");
|
|
150
149
|
}
|
|
151
150
|
return path;
|
|
@@ -172,6 +171,33 @@ function globRegex(pattern) {
|
|
|
172
171
|
}
|
|
173
172
|
return new RegExp(`${source}$`);
|
|
174
173
|
}
|
|
174
|
+
/** The fixed baseline, split once: its literal exceptions and its protected globs. */
|
|
175
|
+
const WARDBY_UNPROTECTED = new Set(WARDBY_PROTECTED_PATHS.filter(isProtectedPathException).map(protectedPathBody));
|
|
176
|
+
const WARDBY_PROTECTED = WARDBY_PROTECTED_PATHS.filter((pattern) => !isProtectedPathException(pattern)).map((pattern) => globRegex(pattern));
|
|
177
|
+
/**
|
|
178
|
+
* Whether a changed path is protected, in this order: the WARDBY_PROTECTED_PATHS
|
|
179
|
+
* baseline's exception (.wardby/services.yaml, which a builder may propose; it
|
|
180
|
+
* takes effect only after merge, docs/coding-services.md) is never protected;
|
|
181
|
+
* anything else under the baseline (.wardby/**) always is, whatever the agent's
|
|
182
|
+
* exceptions say; any other path is protected when it matches one of the
|
|
183
|
+
* agent's `patterns` and is not one of its exceptions (entries with a leading
|
|
184
|
+
* "!", each a literal path, so order does not matter). The baseline is applied
|
|
185
|
+
* here, at enforcement, rather than stored, so every existing agent and
|
|
186
|
+
* in-flight run gets it.
|
|
187
|
+
*/
|
|
188
|
+
export function protectedPathMatcher(patterns) {
|
|
189
|
+
const exceptions = new Set(patterns.filter(isProtectedPathException).map(protectedPathBody));
|
|
190
|
+
const protectedPatterns = patterns
|
|
191
|
+
.filter((pattern) => !isProtectedPathException(pattern))
|
|
192
|
+
.map((pattern) => globRegex(pattern));
|
|
193
|
+
return (path) => {
|
|
194
|
+
if (WARDBY_UNPROTECTED.has(path))
|
|
195
|
+
return false;
|
|
196
|
+
if (WARDBY_PROTECTED.some((matcher) => matcher.test(path)))
|
|
197
|
+
return true;
|
|
198
|
+
return protectedPatterns.some((matcher) => matcher.test(path)) && !exceptions.has(path);
|
|
199
|
+
};
|
|
200
|
+
}
|
|
175
201
|
function validateChangedPath(path) {
|
|
176
202
|
if (!path ||
|
|
177
203
|
isAbsolute(path) ||
|
|
@@ -220,7 +246,7 @@ export class GitVcsProvider {
|
|
|
220
246
|
}
|
|
221
247
|
async prepareWorkspace(input) {
|
|
222
248
|
const normalized = this.validateInput(input);
|
|
223
|
-
await
|
|
249
|
+
await ensurePrivateDirectory(this.rootDir);
|
|
224
250
|
await mkdir(resolve(this.rootDir, ".home"), { recursive: true, mode: 0o700 });
|
|
225
251
|
const runRoot = resolve(this.rootDir, normalized.runId);
|
|
226
252
|
if (!directChild(this.rootDir, runRoot))
|
|
@@ -351,7 +377,15 @@ export class GitVcsProvider {
|
|
|
351
377
|
await this.inspectWorkspace(prepared.workspacePath);
|
|
352
378
|
await this.assertRemote(prepared);
|
|
353
379
|
await this.assertSafeLocalConfig(prepared.gitMetadataPath);
|
|
354
|
-
|
|
380
|
+
// Excluded paths (src/coding/collect-exclude.ts) are never collected from the worker, so
|
|
381
|
+
// they are also neither added nor deleted here: tracked files under them stay untouched.
|
|
382
|
+
await this.gitFor(prepared, [
|
|
383
|
+
"add",
|
|
384
|
+
"--all",
|
|
385
|
+
"--",
|
|
386
|
+
":/",
|
|
387
|
+
...gitExcludePathspecs(normalizeCollectExclusions(prepared.collectExclude)),
|
|
388
|
+
]);
|
|
355
389
|
const changed = nullSeparated((await this.gitFor(prepared, [
|
|
356
390
|
"diff",
|
|
357
391
|
"--cached",
|
|
@@ -363,8 +397,7 @@ export class GitVcsProvider {
|
|
|
363
397
|
])).stdout);
|
|
364
398
|
if (changed.length > this.maxChangedFiles)
|
|
365
399
|
throw new Error("vcs_changed_file_limit");
|
|
366
|
-
const
|
|
367
|
-
const protectedChange = changed.find((path) => protectedMatchers.some(({ matcher }) => matcher.test(path)));
|
|
400
|
+
const protectedChange = changed.find(protectedPathMatcher(prepared.protectedPaths));
|
|
368
401
|
if (protectedChange)
|
|
369
402
|
throw new Error(`vcs_protected_path:${protectedChange}`);
|
|
370
403
|
let diff;
|
|
@@ -411,15 +444,20 @@ export class GitVcsProvider {
|
|
|
411
444
|
// run's id), not this run's own -- this finds the existing open PR and
|
|
412
445
|
// returns it rather than creating a new one, since headRef/baseRef
|
|
413
446
|
// already match it exactly. No other change needed here: pushing a new
|
|
414
|
-
// commit onto that branch already updates the PR natively
|
|
447
|
+
// commit onto that branch already updates the PR natively -- which is
|
|
448
|
+
// also why a PR a person has since marked ready for review is accepted
|
|
449
|
+
// (acceptReadyForReview) rather than failing an already-pushed run.
|
|
415
450
|
const pullRequest = await this.options.github.createOrFindDraftPullRequest({
|
|
416
451
|
runId: prepared.continuation?.rootRunId ?? prepared.runId,
|
|
452
|
+
...(prepared.continuation ? { acceptReadyForReview: true } : {}),
|
|
417
453
|
repository: prepared.repository,
|
|
418
454
|
baseRef: prepared.baseRef,
|
|
419
455
|
headRef: prepared.headRef,
|
|
420
456
|
summary: details?.summary,
|
|
421
457
|
tests: details?.tests,
|
|
422
458
|
tag: details?.tag,
|
|
459
|
+
packages: details?.packages,
|
|
460
|
+
packageRefusals: details?.packageRefusals,
|
|
423
461
|
});
|
|
424
462
|
return {
|
|
425
463
|
outcome: prepared.continuation ? "pull_request_updated" : "pull_request_opened",
|
|
@@ -497,14 +535,25 @@ export class GitVcsProvider {
|
|
|
497
535
|
};
|
|
498
536
|
const label = runLabel(details?.agentName, workspace.runId);
|
|
499
537
|
const summarySuffix = details?.summary ? `\n\n${details.summary}` : "";
|
|
500
|
-
const
|
|
538
|
+
const budgetSuffix = details?.budgetSentence ? ` ${details.budgetSentence}` : "";
|
|
539
|
+
const body = outcome === "succeeded"
|
|
540
|
+
? `✅ ${label} finished.${summarySuffix}`
|
|
541
|
+
: outcome === "budget_exhausted"
|
|
542
|
+
? `❌ ${label} ran out of budget.${budgetSuffix}${summarySuffix}`
|
|
543
|
+
: details?.serviceSentence
|
|
544
|
+
? `❌ ${label} could not start: ${details.serviceSentence}${summarySuffix}`
|
|
545
|
+
: details?.providerSentence
|
|
546
|
+
? `❌ ${label} could not run: ${details.providerSentence}${summarySuffix}`
|
|
547
|
+
: details?.protectedPathSentence
|
|
548
|
+
? `❌ ${label} could not open its changes: ${details.protectedPathSentence}${summarySuffix}`
|
|
549
|
+
: `❌ ${label} failed.${summarySuffix}`;
|
|
501
550
|
await Promise.allSettled([
|
|
502
551
|
this.options.github.updateContinuationStatusComment({ ...identity, body }),
|
|
503
552
|
this.options.github.completeContinuationCheckRun({
|
|
504
553
|
repository: workspace.repository,
|
|
505
554
|
headSha: workspace.baseCommit,
|
|
506
555
|
runId: workspace.runId,
|
|
507
|
-
outcome,
|
|
556
|
+
outcome: outcome === "succeeded" ? "succeeded" : "failed",
|
|
508
557
|
}),
|
|
509
558
|
]);
|
|
510
559
|
}
|
|
@@ -512,6 +561,17 @@ export class GitVcsProvider {
|
|
|
512
561
|
// Best-effort observability only -- must never affect the real run.
|
|
513
562
|
}
|
|
514
563
|
}
|
|
564
|
+
async readRepositoryFile(input) {
|
|
565
|
+
const github = this.options.github;
|
|
566
|
+
if (!github.readFileAtRef)
|
|
567
|
+
throw new Error("vcs_read_file_unsupported");
|
|
568
|
+
return github.readFileAtRef({
|
|
569
|
+
repository: normalizeGitHubRepository(input.repository),
|
|
570
|
+
ref: normalizeGitRef(input.ref),
|
|
571
|
+
path: validateChangedPath(input.path),
|
|
572
|
+
maxBytes: input.maxBytes,
|
|
573
|
+
});
|
|
574
|
+
}
|
|
515
575
|
validateInput(input) {
|
|
516
576
|
if (!SAFE_RUN_ID.test(input.runId))
|
|
517
577
|
throw new Error("vcs_run_id_invalid");
|
|
@@ -539,7 +599,10 @@ export class GitVcsProvider {
|
|
|
539
599
|
const protectedPaths = [...new Set(input.protectedPaths.map(validateProtectedPath))];
|
|
540
600
|
if (protectedPaths.length === 0 || protectedPaths.length > 128)
|
|
541
601
|
throw new Error("vcs_protected_paths_invalid");
|
|
542
|
-
|
|
602
|
+
if (!protectsSomePath(protectedPaths))
|
|
603
|
+
throw new Error("vcs_protected_paths_invalid");
|
|
604
|
+
const collectExclude = [...normalizeCollectExclusions(input.collectExclude ?? []).paths];
|
|
605
|
+
return { runId: input.runId, repository, baseRef, headRef, protectedPaths, collectExclude, continuation };
|
|
543
606
|
}
|
|
544
607
|
expectedPaths(runId) {
|
|
545
608
|
if (!SAFE_RUN_ID.test(runId))
|
|
@@ -565,6 +628,8 @@ export class GitVcsProvider {
|
|
|
565
628
|
workspace.gitMetadataPath !== expected.gitMetadataPath ||
|
|
566
629
|
workspace.protectedPaths.length !== normalized.protectedPaths.length ||
|
|
567
630
|
workspace.protectedPaths.some((path, index) => path !== normalized.protectedPaths[index]) ||
|
|
631
|
+
workspace.collectExclude.length !== normalized.collectExclude.length ||
|
|
632
|
+
workspace.collectExclude.some((path, index) => path !== normalized.collectExclude[index]) ||
|
|
568
633
|
workspace.continuation?.rootRunId !== normalized.continuation?.rootRunId) {
|
|
569
634
|
throw new Error("vcs_workspace_handle_invalid");
|
|
570
635
|
}
|