@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
|
@@ -10,9 +10,30 @@
|
|
|
10
10
|
* enforces that tightened ceiling with no changes of its own: a group
|
|
11
11
|
* whose period budget is already exhausted simply produces an effective
|
|
12
12
|
* budget of 0, which the engine's turn-1 gate already refuses exactly
|
|
13
|
-
* like any other zero/negative budget.
|
|
13
|
+
* like any other zero/negative budget. A coding run gets the same effective
|
|
14
|
+
* budget at dispatch (dispatch.ts), where it becomes the run's reservation.
|
|
15
|
+
*
|
|
16
|
+
* Spend is the real cost of the period's runs plus the unspent part of every
|
|
17
|
+
* live run still in flight (pending or running): its hold, minus what it has
|
|
18
|
+
* spent so far, never below zero. A coding run's hold is its
|
|
19
|
+
* CodingRun.budgetReservedUsd; a native run's is its agent's current
|
|
20
|
+
* per-run budgetUsd, an upper bound on the effective budget it pinned at load.
|
|
21
|
+
* Counting holds is what stops concurrent runs from each claiming the
|
|
22
|
+
* same remainder (security review E-04).
|
|
23
|
+
*
|
|
24
|
+
* Only live runs hold anything (see isHoldLive): a run that stopped
|
|
25
|
+
* heartbeating (a crashed process, a Ctrl-C'd `wardby run`) or a coding run
|
|
26
|
+
* past its queue + run timeout releases its hold even while its row still
|
|
27
|
+
* says pending/running, so a zombie row cannot pin a group for a whole period.
|
|
28
|
+
*
|
|
29
|
+
* A native run asks for its budget at load, after its row already exists, and
|
|
30
|
+
* counts only the holds of runs that started before it (startedAt, then id):
|
|
31
|
+
* first come, first served. Two members dispatched on the same tick never
|
|
32
|
+
* both see the other's hold and starve each other; the earlier one gets the
|
|
33
|
+
* remainder and the later one gets what the earlier one leaves. A coding
|
|
34
|
+
* dispatch has no row yet, so it counts every live hold.
|
|
14
35
|
*/
|
|
15
|
-
import type { Agent, BudgetGroup, PrismaClient } from "
|
|
36
|
+
import type { Agent, BudgetGroup, PrismaClient } from "#prisma";
|
|
16
37
|
export type Period = "day" | "week" | "month";
|
|
17
38
|
export type BudgetGroupsDb = Pick<PrismaClient, "budgetGroup" | "run" | "agent">;
|
|
18
39
|
/**
|
|
@@ -24,9 +45,69 @@ export declare function periodStart(period: Period, now: Date): Date;
|
|
|
24
45
|
export interface PeriodSpend {
|
|
25
46
|
period: Period;
|
|
26
47
|
capUsd: number;
|
|
48
|
+
/** Real cost recorded by the period's runs, finished or not. */
|
|
27
49
|
spentUsd: number;
|
|
50
|
+
/** Unspent reservations of the period's in-flight (pending/running) runs. */
|
|
51
|
+
reservedUsd: number;
|
|
52
|
+
/** capUsd - spentUsd - reservedUsd, never below zero. */
|
|
28
53
|
remainingUsd: number;
|
|
29
54
|
}
|
|
55
|
+
/** A group member as computeGroupSpend needs it: a native run in flight holds its agent's budgetUsd. */
|
|
56
|
+
export interface GroupMember {
|
|
57
|
+
id: string;
|
|
58
|
+
budgetUsd: unknown;
|
|
59
|
+
}
|
|
60
|
+
/** A run's position in first-come-first-served order: startedAt, then id. */
|
|
61
|
+
export interface RunOrder {
|
|
62
|
+
id: string;
|
|
63
|
+
startedAt: Date;
|
|
64
|
+
}
|
|
65
|
+
export interface SpendOptions {
|
|
66
|
+
/**
|
|
67
|
+
* Runs whose unspent hold is left out (their real cost still counts): the
|
|
68
|
+
* run asking for its own budget, and the run tree a sub-agent spends from,
|
|
69
|
+
* whose hold already covers it.
|
|
70
|
+
*/
|
|
71
|
+
excludeReservationRunIds?: readonly string[];
|
|
72
|
+
/**
|
|
73
|
+
* First come, first served: count only the holds of runs ordered strictly
|
|
74
|
+
* before this one. Unset (a coding dispatch, whose row does not exist yet)
|
|
75
|
+
* counts every live hold.
|
|
76
|
+
*/
|
|
77
|
+
holdsBefore?: RunOrder;
|
|
78
|
+
/** CODING_QUEUE_TIMEOUT_SEC; read from the environment when omitted. */
|
|
79
|
+
codingQueueTimeoutSec?: number;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* How long a run's last heartbeat keeps its hold alive: the reconciler's
|
|
83
|
+
* heartbeat timeout plus one reconcile interval, so a managed run is reaped
|
|
84
|
+
* (or re-claimed, which refreshes heartbeatAt) before its hold lapses.
|
|
85
|
+
* Managed native runs beat every HEARTBEAT_INTERVAL_MS (InProcessExecutor,
|
|
86
|
+
* DbosExecutor), as do `wardby run` and native sub-agent children
|
|
87
|
+
* (withRunHeartbeat); a coding run beats while its job is polled.
|
|
88
|
+
*/
|
|
89
|
+
export declare const HOLD_HEARTBEAT_TTL_MS: number;
|
|
90
|
+
/** Slack past a coding run's queue + run timeout before its hold lapses (matches the sub-agent wait grace). */
|
|
91
|
+
export declare const CODING_HOLD_GRACE_SEC = 60;
|
|
92
|
+
/** Smallest amount worth holding or reserving: CodingRun.budgetReservedUsd has 6 decimal places. */
|
|
93
|
+
export declare const MIN_RESERVATION_USD = 0.000001;
|
|
94
|
+
interface HoldRow {
|
|
95
|
+
id: string;
|
|
96
|
+
status: string;
|
|
97
|
+
startedAt: Date;
|
|
98
|
+
heartbeatAt: Date | null;
|
|
99
|
+
codingRun: {
|
|
100
|
+
timeoutSec: number;
|
|
101
|
+
} | null;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Whether an in-flight row still holds budget. A run holds while its last
|
|
105
|
+
* sign of life (heartbeatAt, or startedAt before its first beat) is within
|
|
106
|
+
* HOLD_HEARTBEAT_TTL_MS. A coding run also holds, beat or not, until its
|
|
107
|
+
* queue timeout + run timeout + grace have passed since dispatch: a queued
|
|
108
|
+
* coding run does not beat, and nothing can legitimately spend past that.
|
|
109
|
+
*/
|
|
110
|
+
export declare function isHoldLive(run: HoldRow, now: Date, codingQueueTimeoutSec: number): boolean;
|
|
30
111
|
/**
|
|
31
112
|
* Live per-period spend for whichever of a group's daily/weekly/monthly
|
|
32
113
|
* caps are actually set -- unset periods are omitted from the result, not
|
|
@@ -34,7 +115,7 @@ export interface PeriodSpend {
|
|
|
34
115
|
* (month contains week contains day), bucketed in JS, rather than a
|
|
35
116
|
* separate DB round trip per period.
|
|
36
117
|
*/
|
|
37
|
-
export declare function computeGroupSpend(db: BudgetGroupsDb, group: Pick<BudgetGroup, "dailyBudgetUsd" | "weeklyBudgetUsd" | "monthlyBudgetUsd">,
|
|
118
|
+
export declare function computeGroupSpend(db: BudgetGroupsDb, group: Pick<BudgetGroup, "dailyBudgetUsd" | "weeklyBudgetUsd" | "monthlyBudgetUsd">, members: readonly GroupMember[], now?: Date, options?: SpendOptions): Promise<PeriodSpend[]>;
|
|
38
119
|
export interface RunTreeSpend {
|
|
39
120
|
rootRunId: string;
|
|
40
121
|
capUsd: number;
|
|
@@ -49,13 +130,28 @@ export interface RunTreeSpend {
|
|
|
49
130
|
* spent so far. The root's ceiling is recomputed fresh here, not pinned
|
|
50
131
|
* from whatever it was when the root run started — consistent with
|
|
51
132
|
* BudgetGroup periods already always being live-recomputed rather than
|
|
52
|
-
* snapshotted.
|
|
133
|
+
* snapshotted. That group check sees the group as the root did when it
|
|
134
|
+
* loaded: the tree's own holds are left out (the tree spends inside the
|
|
135
|
+
* root's hold, so counting it again would leave the tree nothing), and so
|
|
136
|
+
* are holds of runs that started after the root (they already counted the
|
|
137
|
+
* root's hold).
|
|
53
138
|
*/
|
|
54
139
|
export declare function computeRunTreeSpend(db: BudgetGroupsDb, parentRunId: string, now?: Date): Promise<RunTreeSpend>;
|
|
140
|
+
export type BudgetConstraint = Period | "run-tree";
|
|
55
141
|
export interface EffectiveBudgetResult {
|
|
56
142
|
effectiveBudgetUsd: number;
|
|
57
143
|
/** Which constraint(s), if any, are tighter than the agent's own budgetUsd right now. */
|
|
58
|
-
constrainedBy:
|
|
144
|
+
constrainedBy: BudgetConstraint[];
|
|
145
|
+
/** The first constraint with nothing left (< MIN_RESERVATION_USD), set only when there is one. */
|
|
146
|
+
exhaustedBy?: BudgetConstraint;
|
|
147
|
+
}
|
|
148
|
+
export interface EffectiveBudgetOptions {
|
|
149
|
+
/**
|
|
150
|
+
* The run this budget is for, when its row already exists (a native run's
|
|
151
|
+
* load step): its own hold is not counted against itself, and neither are
|
|
152
|
+
* the holds of runs that started after it (first come, first served).
|
|
153
|
+
*/
|
|
154
|
+
self?: RunOrder;
|
|
59
155
|
}
|
|
60
156
|
/**
|
|
61
157
|
* The per-run budget ceiling to actually use for `agent`: its own
|
|
@@ -68,5 +164,12 @@ export interface EffectiveBudgetResult {
|
|
|
68
164
|
* with no caps configured is returned unchanged. Also logs a warning
|
|
69
165
|
* (never blocks, never throws) once a period's spend crosses the group's
|
|
70
166
|
* own warnThresholdRatio.
|
|
167
|
+
*
|
|
168
|
+
* A sub-agent in the root's own budget group spends inside the root's hold,
|
|
169
|
+
* so its group check is the root's: the tree's holds and the holds of runs
|
|
170
|
+
* after the root are left out. A sub-agent in any other group is an
|
|
171
|
+
* ordinary member of that group and counts every earlier live hold there,
|
|
172
|
+
* the tree's included.
|
|
71
173
|
*/
|
|
72
|
-
export declare function effectiveBudgetForRun(db: BudgetGroupsDb, agent: Pick<Agent, "id" | "budgetGroupId" | "budgetUsd">, now?: Date, parentRunId?: string): Promise<EffectiveBudgetResult>;
|
|
174
|
+
export declare function effectiveBudgetForRun(db: BudgetGroupsDb, agent: Pick<Agent, "id" | "budgetGroupId" | "budgetUsd">, now?: Date, parentRunId?: string, options?: EffectiveBudgetOptions): Promise<EffectiveBudgetResult>;
|
|
175
|
+
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { loadCodingConcurrencyConfig } from "../config/providers.js";
|
|
1
2
|
import { logger } from "./logger.js";
|
|
3
|
+
import { HEARTBEAT_TIMEOUT_MS, RECONCILE_INTERVAL_MS } from "./timing.js";
|
|
2
4
|
const budgetGroupLog = logger.child({ module: "budget-groups" });
|
|
3
5
|
/**
|
|
4
6
|
* Calendar-aligned UTC period start. "week" is the ISO week: Monday 00:00
|
|
@@ -20,6 +22,44 @@ export function periodStart(period, now) {
|
|
|
20
22
|
function toNullableNumber(value) {
|
|
21
23
|
return value === null || value === undefined ? null : Number(value);
|
|
22
24
|
}
|
|
25
|
+
const IN_FLIGHT = new Set(["pending", "running"]);
|
|
26
|
+
/**
|
|
27
|
+
* How long a run's last heartbeat keeps its hold alive: the reconciler's
|
|
28
|
+
* heartbeat timeout plus one reconcile interval, so a managed run is reaped
|
|
29
|
+
* (or re-claimed, which refreshes heartbeatAt) before its hold lapses.
|
|
30
|
+
* Managed native runs beat every HEARTBEAT_INTERVAL_MS (InProcessExecutor,
|
|
31
|
+
* DbosExecutor), as do `wardby run` and native sub-agent children
|
|
32
|
+
* (withRunHeartbeat); a coding run beats while its job is polled.
|
|
33
|
+
*/
|
|
34
|
+
export const HOLD_HEARTBEAT_TTL_MS = HEARTBEAT_TIMEOUT_MS + RECONCILE_INTERVAL_MS;
|
|
35
|
+
/** Slack past a coding run's queue + run timeout before its hold lapses (matches the sub-agent wait grace). */
|
|
36
|
+
export const CODING_HOLD_GRACE_SEC = 60;
|
|
37
|
+
/** Smallest amount worth holding or reserving: CodingRun.budgetReservedUsd has 6 decimal places. */
|
|
38
|
+
export const MIN_RESERVATION_USD = 0.000001;
|
|
39
|
+
/**
|
|
40
|
+
* Whether an in-flight row still holds budget. A run holds while its last
|
|
41
|
+
* sign of life (heartbeatAt, or startedAt before its first beat) is within
|
|
42
|
+
* HOLD_HEARTBEAT_TTL_MS. A coding run also holds, beat or not, until its
|
|
43
|
+
* queue timeout + run timeout + grace have passed since dispatch: a queued
|
|
44
|
+
* coding run does not beat, and nothing can legitimately spend past that.
|
|
45
|
+
*/
|
|
46
|
+
export function isHoldLive(run, now, codingQueueTimeoutSec) {
|
|
47
|
+
if (!IN_FLIGHT.has(run.status))
|
|
48
|
+
return false;
|
|
49
|
+
const lastSign = (run.heartbeatAt ?? run.startedAt).getTime();
|
|
50
|
+
if (now.getTime() - lastSign <= HOLD_HEARTBEAT_TTL_MS)
|
|
51
|
+
return true;
|
|
52
|
+
if (run.codingRun) {
|
|
53
|
+
const deadlineMs = run.startedAt.getTime() + (codingQueueTimeoutSec + run.codingRun.timeoutSec + CODING_HOLD_GRACE_SEC) * 1000;
|
|
54
|
+
return now.getTime() <= deadlineMs;
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
function isOrderedBefore(run, other) {
|
|
59
|
+
const a = run.startedAt.getTime();
|
|
60
|
+
const b = other.startedAt.getTime();
|
|
61
|
+
return a < b || (a === b && run.id < other.id);
|
|
62
|
+
}
|
|
23
63
|
/**
|
|
24
64
|
* Live per-period spend for whichever of a group's daily/weekly/monthly
|
|
25
65
|
* caps are actually set -- unset periods are omitted from the result, not
|
|
@@ -27,7 +67,7 @@ function toNullableNumber(value) {
|
|
|
27
67
|
* (month contains week contains day), bucketed in JS, rather than a
|
|
28
68
|
* separate DB round trip per period.
|
|
29
69
|
*/
|
|
30
|
-
export async function computeGroupSpend(db, group,
|
|
70
|
+
export async function computeGroupSpend(db, group, members, now = new Date(), options = {}) {
|
|
31
71
|
const caps = [
|
|
32
72
|
{ period: "day", capUsd: toNullableNumber(group.dailyBudgetUsd) },
|
|
33
73
|
{ period: "week", capUsd: toNullableNumber(group.weeklyBudgetUsd) },
|
|
@@ -42,28 +82,56 @@ export async function computeGroupSpend(db, group, memberAgentIds, now = new Dat
|
|
|
42
82
|
// query itself as a cheap no-op; an empty `agentId: { in: [] }` would
|
|
43
83
|
// match nothing anyway.
|
|
44
84
|
const widestStart = periodStart("month", now);
|
|
45
|
-
const
|
|
85
|
+
const memberBudgets = new Map(members.map((m) => [m.id, Number(m.budgetUsd)]));
|
|
86
|
+
const excluded = new Set(options.excludeReservationRunIds ?? []);
|
|
87
|
+
const queueTimeoutSec = options.codingQueueTimeoutSec ?? loadCodingConcurrencyConfig().queueTimeoutSec;
|
|
88
|
+
const runs = members.length === 0
|
|
46
89
|
? []
|
|
47
90
|
: await db.run.findMany({
|
|
48
|
-
where: { agentId: { in:
|
|
49
|
-
select: {
|
|
91
|
+
where: { agentId: { in: [...memberBudgets.keys()] }, startedAt: { gte: widestStart } },
|
|
92
|
+
select: {
|
|
93
|
+
id: true,
|
|
94
|
+
agentId: true,
|
|
95
|
+
status: true,
|
|
96
|
+
costUsd: true,
|
|
97
|
+
startedAt: true,
|
|
98
|
+
heartbeatAt: true,
|
|
99
|
+
codingRun: { select: { budgetReservedUsd: true, timeoutSec: true } },
|
|
100
|
+
},
|
|
50
101
|
});
|
|
102
|
+
const accounted = runs.map((r) => {
|
|
103
|
+
const costUsd = Number(r.costUsd);
|
|
104
|
+
let reservedUsd = 0;
|
|
105
|
+
const holds = !excluded.has(r.id) &&
|
|
106
|
+
(options.holdsBefore === undefined || isOrderedBefore(r, options.holdsBefore)) &&
|
|
107
|
+
isHoldLive(r, now, queueTimeoutSec);
|
|
108
|
+
if (holds) {
|
|
109
|
+
// A coding run holds exactly what dispatch reserved. A native run (or
|
|
110
|
+
// a coding run whose CodingRun row is missing) holds its agent's
|
|
111
|
+
// per-run budget: never less than what it can actually spend.
|
|
112
|
+
const reservation = r.codingRun != null ? Number(r.codingRun.budgetReservedUsd) : (memberBudgets.get(r.agentId) ?? 0);
|
|
113
|
+
reservedUsd = Math.max(0, reservation - costUsd);
|
|
114
|
+
}
|
|
115
|
+
return { startedAt: r.startedAt, costUsd, reservedUsd };
|
|
116
|
+
});
|
|
51
117
|
return configured.map(({ period, capUsd }) => {
|
|
52
118
|
const start = periodStart(period, now);
|
|
53
|
-
const
|
|
54
|
-
|
|
119
|
+
const inPeriod = accounted.filter((r) => r.startedAt >= start);
|
|
120
|
+
const spentUsd = inPeriod.reduce((sum, r) => sum + r.costUsd, 0);
|
|
121
|
+
const reservedUsd = inPeriod.reduce((sum, r) => sum + r.reservedUsd, 0);
|
|
122
|
+
return { period, capUsd, spentUsd, reservedUsd, remainingUsd: Math.max(0, capUsd - spentUsd - reservedUsd) };
|
|
55
123
|
});
|
|
56
124
|
}
|
|
57
125
|
/** Walks parentRunId upward from `runId` to the tree's root (parentRunId null). */
|
|
58
126
|
async function findRootRun(db, runId) {
|
|
59
127
|
let current = await db.run.findUniqueOrThrow({
|
|
60
128
|
where: { id: runId },
|
|
61
|
-
select: { id: true, agentId: true, parentRunId: true },
|
|
129
|
+
select: { id: true, agentId: true, parentRunId: true, startedAt: true },
|
|
62
130
|
});
|
|
63
131
|
while (current.parentRunId) {
|
|
64
132
|
current = await db.run.findUniqueOrThrow({
|
|
65
133
|
where: { id: current.parentRunId },
|
|
66
|
-
select: { id: true, agentId: true, parentRunId: true },
|
|
134
|
+
select: { id: true, agentId: true, parentRunId: true, startedAt: true },
|
|
67
135
|
});
|
|
68
136
|
}
|
|
69
137
|
return current;
|
|
@@ -88,9 +156,17 @@ async function collectTreeRunIds(db, rootRunId) {
|
|
|
88
156
|
* spent so far. The root's ceiling is recomputed fresh here, not pinned
|
|
89
157
|
* from whatever it was when the root run started — consistent with
|
|
90
158
|
* BudgetGroup periods already always being live-recomputed rather than
|
|
91
|
-
* snapshotted.
|
|
159
|
+
* snapshotted. That group check sees the group as the root did when it
|
|
160
|
+
* loaded: the tree's own holds are left out (the tree spends inside the
|
|
161
|
+
* root's hold, so counting it again would leave the tree nothing), and so
|
|
162
|
+
* are holds of runs that started after the root (they already counted the
|
|
163
|
+
* root's hold).
|
|
92
164
|
*/
|
|
93
165
|
export async function computeRunTreeSpend(db, parentRunId, now = new Date()) {
|
|
166
|
+
const { rootRunId, capUsd, spentUsd, remainingUsd } = await runTreeSpend(db, parentRunId, now);
|
|
167
|
+
return { rootRunId, capUsd, spentUsd, remainingUsd };
|
|
168
|
+
}
|
|
169
|
+
async function runTreeSpend(db, parentRunId, now) {
|
|
94
170
|
const root = await findRootRun(db, parentRunId);
|
|
95
171
|
const treeRunIds = await collectTreeRunIds(db, root.id);
|
|
96
172
|
const rows = await db.run.findMany({ where: { id: { in: treeRunIds } }, select: { costUsd: true } });
|
|
@@ -99,11 +175,23 @@ export async function computeRunTreeSpend(db, parentRunId, now = new Date()) {
|
|
|
99
175
|
where: { id: root.agentId },
|
|
100
176
|
select: { id: true, budgetGroupId: true, budgetUsd: true },
|
|
101
177
|
});
|
|
178
|
+
const rootOrder = { id: root.id, startedAt: root.startedAt };
|
|
102
179
|
// Root has no parentRunId of its own, so this terminates in one level —
|
|
103
180
|
// no unbounded recursion regardless of how deep `parentRunId` itself was.
|
|
104
|
-
const rootCeiling = await
|
|
181
|
+
const rootCeiling = await groupCappedBudget(db, rootAgent, now, {
|
|
182
|
+
excludeReservationRunIds: treeRunIds,
|
|
183
|
+
holdsBefore: rootOrder,
|
|
184
|
+
});
|
|
105
185
|
const capUsd = rootCeiling.effectiveBudgetUsd;
|
|
106
|
-
return {
|
|
186
|
+
return {
|
|
187
|
+
rootRunId: root.id,
|
|
188
|
+
capUsd,
|
|
189
|
+
spentUsd,
|
|
190
|
+
remainingUsd: Math.max(0, capUsd - spentUsd),
|
|
191
|
+
treeRunIds,
|
|
192
|
+
root: rootOrder,
|
|
193
|
+
rootBudgetGroupId: rootAgent.budgetGroupId,
|
|
194
|
+
};
|
|
107
195
|
}
|
|
108
196
|
/**
|
|
109
197
|
* The per-run budget ceiling to actually use for `agent`: its own
|
|
@@ -116,17 +204,35 @@ export async function computeRunTreeSpend(db, parentRunId, now = new Date()) {
|
|
|
116
204
|
* with no caps configured is returned unchanged. Also logs a warning
|
|
117
205
|
* (never blocks, never throws) once a period's spend crosses the group's
|
|
118
206
|
* own warnThresholdRatio.
|
|
207
|
+
*
|
|
208
|
+
* A sub-agent in the root's own budget group spends inside the root's hold,
|
|
209
|
+
* so its group check is the root's: the tree's holds and the holds of runs
|
|
210
|
+
* after the root are left out. A sub-agent in any other group is an
|
|
211
|
+
* ordinary member of that group and counts every earlier live hold there,
|
|
212
|
+
* the tree's included.
|
|
119
213
|
*/
|
|
120
|
-
export async function effectiveBudgetForRun(db, agent, now = new Date(), parentRunId) {
|
|
214
|
+
export async function effectiveBudgetForRun(db, agent, now = new Date(), parentRunId, options = {}) {
|
|
215
|
+
const self = options.self;
|
|
216
|
+
const ownSpend = { excludeReservationRunIds: self ? [self.id] : [], holdsBefore: self };
|
|
217
|
+
if (!parentRunId)
|
|
218
|
+
return groupCappedBudget(db, agent, now, ownSpend);
|
|
219
|
+
const tree = await runTreeSpend(db, parentRunId, now);
|
|
220
|
+
const sharesRootGroup = agent.budgetGroupId !== null && agent.budgetGroupId === tree.rootBudgetGroupId;
|
|
221
|
+
const spend = sharesRootGroup
|
|
222
|
+
? { excludeReservationRunIds: [...tree.treeRunIds, ...(self ? [self.id] : [])], holdsBefore: tree.root }
|
|
223
|
+
: ownSpend;
|
|
224
|
+
return groupCappedBudget(db, agent, now, spend, { value: tree.remainingUsd, reason: "run-tree" });
|
|
225
|
+
}
|
|
226
|
+
async function groupCappedBudget(db, agent, now, spendOptions, extra) {
|
|
121
227
|
const ownBudgetUsd = Number(agent.budgetUsd);
|
|
122
228
|
const candidates = [];
|
|
123
229
|
if (agent.budgetGroupId) {
|
|
124
230
|
const group = await db.budgetGroup.findUnique({
|
|
125
231
|
where: { id: agent.budgetGroupId },
|
|
126
|
-
include: { agents: { select: { id: true } } },
|
|
232
|
+
include: { agents: { select: { id: true, budgetUsd: true } } },
|
|
127
233
|
});
|
|
128
234
|
if (group) {
|
|
129
|
-
const spend = await computeGroupSpend(db, group, group.agents
|
|
235
|
+
const spend = await computeGroupSpend(db, group, group.agents, now, spendOptions);
|
|
130
236
|
const warnThresholdRatio = Number(group.warnThresholdRatio);
|
|
131
237
|
for (const s of spend) {
|
|
132
238
|
candidates.push({ value: s.remainingUsd, reason: s.period });
|
|
@@ -137,13 +243,13 @@ export async function effectiveBudgetForRun(db, agent, now = new Date(), parentR
|
|
|
137
243
|
}
|
|
138
244
|
}
|
|
139
245
|
}
|
|
140
|
-
if (
|
|
141
|
-
|
|
142
|
-
candidates.push({ value: tree.remainingUsd, reason: "run-tree" });
|
|
143
|
-
}
|
|
246
|
+
if (extra)
|
|
247
|
+
candidates.push(extra);
|
|
144
248
|
if (candidates.length === 0)
|
|
145
249
|
return { effectiveBudgetUsd: ownBudgetUsd, constrainedBy: [] };
|
|
146
250
|
const constrainedBy = candidates.filter((c) => c.value < ownBudgetUsd).map((c) => c.reason);
|
|
147
251
|
const effectiveBudgetUsd = Math.min(ownBudgetUsd, ...candidates.map((c) => c.value));
|
|
148
|
-
|
|
252
|
+
// Less than the smallest reservable amount is nothing left.
|
|
253
|
+
const exhausted = candidates.find((c) => c.value < MIN_RESERVATION_USD);
|
|
254
|
+
return { effectiveBudgetUsd, constrainedBy, ...(exhausted ? { exhaustedBy: exhausted.reason } : {}) };
|
|
149
255
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one sentence a host (a PR comment, a check summary) is told when a run
|
|
3
|
+
* ran out of budget, or could not start for lack of it. Public repositories
|
|
4
|
+
* read these, so it names amounts and the budget group only: never error
|
|
5
|
+
* text, token counts, or ids.
|
|
6
|
+
*/
|
|
7
|
+
import type { PrismaClient } from "#prisma";
|
|
8
|
+
export interface BudgetFacts {
|
|
9
|
+
/** The run's own budget (a coding run's reservation); falls back to the agent's. */
|
|
10
|
+
runBudgetUsd?: number | null;
|
|
11
|
+
agentBudgetUsd: number;
|
|
12
|
+
budgetGroupName?: string | null;
|
|
13
|
+
/** The run was refused before it started. */
|
|
14
|
+
refused?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function budgetSentence(facts: BudgetFacts): string;
|
|
17
|
+
/**
|
|
18
|
+
* The sentence for a finished run, read from the database: a coding run's
|
|
19
|
+
* reserved budget, otherwise the agent's. Falls back to a sentence without
|
|
20
|
+
* amounts when they cannot be read. Never throws.
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadBudgetSentence(db: Pick<PrismaClient, "run">, runId: string, status: string): Promise<string>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const MAX_GROUP_NAME_CHARS = 64;
|
|
2
|
+
const usd = (amount) => `$${amount.toFixed(2)}`;
|
|
3
|
+
/** A group name is operator-chosen text; keep it to one short, quote-free line. */
|
|
4
|
+
function groupName(name) {
|
|
5
|
+
const cleaned = (name ?? "").replace(/["`]/g, "").replace(/\s+/g, " ").trim().slice(0, MAX_GROUP_NAME_CHARS);
|
|
6
|
+
return cleaned || null;
|
|
7
|
+
}
|
|
8
|
+
export function budgetSentence(facts) {
|
|
9
|
+
const group = groupName(facts.budgetGroupName);
|
|
10
|
+
if (facts.refused) {
|
|
11
|
+
const within = `this run could not start within its ${usd(facts.runBudgetUsd ?? facts.agentBudgetUsd)} budget`;
|
|
12
|
+
return group
|
|
13
|
+
? `Out of budget: ${within} or what the "${group}" budget group had left of its limit.`
|
|
14
|
+
: `Out of budget: ${within}.`;
|
|
15
|
+
}
|
|
16
|
+
const runBudget = facts.runBudgetUsd ?? facts.agentBudgetUsd;
|
|
17
|
+
const used = `Out of budget: this run's ${usd(runBudget)} budget was used up`;
|
|
18
|
+
// A run reserved less than the agent's own budget: its group had only that much left.
|
|
19
|
+
if (group && runBudget < facts.agentBudgetUsd) {
|
|
20
|
+
return `${used} (the "${group}" budget group had only that much left of its limit).`;
|
|
21
|
+
}
|
|
22
|
+
return `${used}.`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The sentence for a finished run, read from the database: a coding run's
|
|
26
|
+
* reserved budget, otherwise the agent's. Falls back to a sentence without
|
|
27
|
+
* amounts when they cannot be read. Never throws.
|
|
28
|
+
*/
|
|
29
|
+
export async function loadBudgetSentence(db, runId, status) {
|
|
30
|
+
const refused = status === "refused";
|
|
31
|
+
try {
|
|
32
|
+
const row = await db.run.findUnique({
|
|
33
|
+
where: { id: runId },
|
|
34
|
+
select: {
|
|
35
|
+
agent: { select: { budgetUsd: true, budgetGroup: { select: { name: true } } } },
|
|
36
|
+
codingRun: { select: { budgetReservedUsd: true } },
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
const agentBudgetUsd = Number(row?.agent?.budgetUsd);
|
|
40
|
+
if (!row?.agent || !Number.isFinite(agentBudgetUsd))
|
|
41
|
+
throw new Error("budget_facts_unavailable");
|
|
42
|
+
const reserved = row.codingRun ? Number(row.codingRun.budgetReservedUsd) : NaN;
|
|
43
|
+
return budgetSentence({
|
|
44
|
+
runBudgetUsd: Number.isFinite(reserved) ? reserved : null,
|
|
45
|
+
agentBudgetUsd,
|
|
46
|
+
budgetGroupName: row.agent.budgetGroup?.name ?? null,
|
|
47
|
+
refused,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return refused
|
|
52
|
+
? "Out of budget: this run could not start within its budget."
|
|
53
|
+
: "Out of budget: this run's budget was used up.";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* Called on the scheduler leader's tick and immediately in any process
|
|
15
15
|
* whose coding run just finished (ContainerExecutor onSlotReleased).
|
|
16
16
|
*/
|
|
17
|
-
import type { PrismaClient } from "
|
|
17
|
+
import type { PrismaClient } from "#prisma";
|
|
18
18
|
import type { Executor } from "../providers/executor/types.js";
|
|
19
19
|
export declare const CODING_QUEUE_TIMEOUT_ERROR = "coding_queue_timeout";
|
|
20
20
|
export type CodingQueueDb = Pick<PrismaClient, "run" | "codingRun" | "$transaction">;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* by a per-attachment `boundName` (sharedDatastore.get(boundName, key)) —
|
|
5
5
|
* same boundName convention as AgentSecret.
|
|
6
6
|
*/
|
|
7
|
-
import type { PrismaClient, Datastore as DatastoreRow } from "
|
|
7
|
+
import type { PrismaClient, Datastore as DatastoreRow } from "#prisma";
|
|
8
8
|
import type { Datastore, DatastoreSetOptions, DatastoreValue } from "../providers/datastore/types.js";
|
|
9
9
|
export type DatastoreMetadata = Pick<DatastoreRow, "id" | "name" | "ownerId" | "createdAt" | "updatedAt">;
|
|
10
10
|
export interface SharedDatastoreAccessor {
|
package/dist/core/datastores.js
CHANGED
|
@@ -25,9 +25,25 @@ export async function attachDatastore(agentId, datastoreId, db, boundName) {
|
|
|
25
25
|
export async function detachDatastore(agentId, boundName, db) {
|
|
26
26
|
await db.agentDatastore.deleteMany({ where: { agentId, boundName } });
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Owner rule (resource-sharing grants spec §3.4.1): a binding resolves only
|
|
30
|
+
* while the datastore's owner is the agent's CURRENT owner, both non-null.
|
|
31
|
+
* A cross-owner binding (written before that rule, or left behind by
|
|
32
|
+
* make_owner) and every binding on an owner-less agent resolve like an
|
|
33
|
+
* unattached boundName, so one owner's store never reaches another owner's
|
|
34
|
+
* agent (A2/S2-2, R2-1).
|
|
35
|
+
*/
|
|
28
36
|
async function resolveDatastoreId(agentId, boundName, db) {
|
|
29
|
-
const attachment = await db.agentDatastore.findFirst({
|
|
30
|
-
|
|
37
|
+
const attachment = await db.agentDatastore.findFirst({
|
|
38
|
+
where: { agentId, boundName },
|
|
39
|
+
include: { datastore: { select: { ownerId: true } }, agent: { select: { ownerId: true } } },
|
|
40
|
+
});
|
|
41
|
+
if (!attachment)
|
|
42
|
+
return undefined;
|
|
43
|
+
const owner = attachment.agent.ownerId;
|
|
44
|
+
if (owner === null || attachment.datastore.ownerId !== owner)
|
|
45
|
+
return undefined;
|
|
46
|
+
return attachment.datastoreId;
|
|
31
47
|
}
|
|
32
48
|
/**
|
|
33
49
|
* Resolves `boundName` to the Datastore attached to this agent under that
|
package/dist/core/db.d.ts
CHANGED
|
@@ -1,2 +1,40 @@
|
|
|
1
|
-
import { PrismaClient } from "
|
|
2
|
-
|
|
1
|
+
import { PrismaClient } from "#prisma";
|
|
2
|
+
/**
|
|
3
|
+
* Connection-pool sizing for the node-postgres pool behind @prisma/adapter-pg.
|
|
4
|
+
*
|
|
5
|
+
* Prisma 6's query engine owned the pool: `connection_limit` defaulted to
|
|
6
|
+
* cpus * 2 + 1 and a caller waited at most `pool_timeout` = 10 s for a free
|
|
7
|
+
* connection (then P2024). Prisma 7 hands the pool to `pg`, whose defaults are
|
|
8
|
+
* max = 10 and connectionTimeoutMillis = 0 — wait for a connection *forever*,
|
|
9
|
+
* so a saturated pool would hang requests instead of failing them. Both values
|
|
10
|
+
* are therefore set explicitly, to Prisma 6's defaults:
|
|
11
|
+
*
|
|
12
|
+
* - max: availableParallelism() * 2 + 1 (Prisma 6 counted physical cores; the
|
|
13
|
+
* logical count is the closest portable Node equivalent).
|
|
14
|
+
* - connectionTimeoutMillis: 10 000 (Prisma 6's pool_timeout). A timeout now
|
|
15
|
+
* surfaces as a pg "timeout exceeded when trying to connect" error, not P2024.
|
|
16
|
+
*
|
|
17
|
+
* `pg` ignores Prisma's own URL parameters, so the two that tuned these same
|
|
18
|
+
* knobs (`connection_limit`, `pool_timeout` in seconds) are still honoured here
|
|
19
|
+
* for URLs that set them. idleTimeoutMillis stays at pg's 10 s default.
|
|
20
|
+
*
|
|
21
|
+
* TLS is whatever the URL asks for (`sslmode`, `sslrootcert`, ...); certificate
|
|
22
|
+
* validation is never disabled here.
|
|
23
|
+
*/
|
|
24
|
+
export declare const DEFAULT_POOL_TIMEOUT_MS = 10000;
|
|
25
|
+
export declare function defaultPoolMax(): number;
|
|
26
|
+
export interface PoolSettings {
|
|
27
|
+
max: number;
|
|
28
|
+
connectionTimeoutMillis: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function poolSettings(connectionString: string): PoolSettings;
|
|
31
|
+
/**
|
|
32
|
+
* The one way wardby builds a Prisma client. `url` defaults to DATABASE_URL
|
|
33
|
+
* as read at call time.
|
|
34
|
+
*/
|
|
35
|
+
/** `poolMax` overrides the pool size for a caller that sizes its own pools
|
|
36
|
+
* (the coding proxy keeps its ledger and its package registry apart). */
|
|
37
|
+
export declare function createPrismaClient(url?: string | undefined, options?: {
|
|
38
|
+
poolMax?: number;
|
|
39
|
+
}): PrismaClient;
|
|
40
|
+
export declare const prisma: PrismaClient;
|
package/dist/core/db.js
CHANGED
|
@@ -1,2 +1,75 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { availableParallelism } from "node:os";
|
|
2
|
+
import { PrismaPg } from "@prisma/adapter-pg";
|
|
3
|
+
import { PrismaClient } from "#prisma";
|
|
4
|
+
/**
|
|
5
|
+
* Connection-pool sizing for the node-postgres pool behind @prisma/adapter-pg.
|
|
6
|
+
*
|
|
7
|
+
* Prisma 6's query engine owned the pool: `connection_limit` defaulted to
|
|
8
|
+
* cpus * 2 + 1 and a caller waited at most `pool_timeout` = 10 s for a free
|
|
9
|
+
* connection (then P2024). Prisma 7 hands the pool to `pg`, whose defaults are
|
|
10
|
+
* max = 10 and connectionTimeoutMillis = 0 — wait for a connection *forever*,
|
|
11
|
+
* so a saturated pool would hang requests instead of failing them. Both values
|
|
12
|
+
* are therefore set explicitly, to Prisma 6's defaults:
|
|
13
|
+
*
|
|
14
|
+
* - max: availableParallelism() * 2 + 1 (Prisma 6 counted physical cores; the
|
|
15
|
+
* logical count is the closest portable Node equivalent).
|
|
16
|
+
* - connectionTimeoutMillis: 10 000 (Prisma 6's pool_timeout). A timeout now
|
|
17
|
+
* surfaces as a pg "timeout exceeded when trying to connect" error, not P2024.
|
|
18
|
+
*
|
|
19
|
+
* `pg` ignores Prisma's own URL parameters, so the two that tuned these same
|
|
20
|
+
* knobs (`connection_limit`, `pool_timeout` in seconds) are still honoured here
|
|
21
|
+
* for URLs that set them. idleTimeoutMillis stays at pg's 10 s default.
|
|
22
|
+
*
|
|
23
|
+
* TLS is whatever the URL asks for (`sslmode`, `sslrootcert`, ...); certificate
|
|
24
|
+
* validation is never disabled here.
|
|
25
|
+
*/
|
|
26
|
+
export const DEFAULT_POOL_TIMEOUT_MS = 10_000;
|
|
27
|
+
export function defaultPoolMax() {
|
|
28
|
+
return availableParallelism() * 2 + 1;
|
|
29
|
+
}
|
|
30
|
+
export function poolSettings(connectionString) {
|
|
31
|
+
const settings = { max: defaultPoolMax(), connectionTimeoutMillis: DEFAULT_POOL_TIMEOUT_MS };
|
|
32
|
+
let params;
|
|
33
|
+
try {
|
|
34
|
+
params = new URL(connectionString).searchParams;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return settings;
|
|
38
|
+
}
|
|
39
|
+
const limit = Number(params.get("connection_limit"));
|
|
40
|
+
if (Number.isInteger(limit) && limit > 0)
|
|
41
|
+
settings.max = limit;
|
|
42
|
+
const timeout = params.get("pool_timeout");
|
|
43
|
+
if (timeout !== null && timeout !== "" && Number.isFinite(Number(timeout)) && Number(timeout) >= 0) {
|
|
44
|
+
// Prisma's pool_timeout=0 meant "no timeout"; pg's 0 means the same.
|
|
45
|
+
settings.connectionTimeoutMillis = Number(timeout) * 1000;
|
|
46
|
+
}
|
|
47
|
+
return settings;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Without a URL, pg would silently fall back to PGHOST/localhost:5432 as the
|
|
51
|
+
* OS user. Prisma 6 failed the first query instead ("Environment variable not
|
|
52
|
+
* found: DATABASE_URL"); keep that: construction succeeds, connecting fails.
|
|
53
|
+
*/
|
|
54
|
+
class MissingUrlAdapter extends PrismaPg {
|
|
55
|
+
async connect() {
|
|
56
|
+
throw new Error("DATABASE_URL is not set: cannot connect to the database.");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The one way wardby builds a Prisma client. `url` defaults to DATABASE_URL
|
|
61
|
+
* as read at call time.
|
|
62
|
+
*/
|
|
63
|
+
/** `poolMax` overrides the pool size for a caller that sizes its own pools
|
|
64
|
+
* (the coding proxy keeps its ledger and its package registry apart). */
|
|
65
|
+
export function createPrismaClient(url = process.env.DATABASE_URL, options = {}) {
|
|
66
|
+
const adapter = url
|
|
67
|
+
? new PrismaPg({
|
|
68
|
+
connectionString: url,
|
|
69
|
+
...poolSettings(url),
|
|
70
|
+
...(options.poolMax !== undefined ? { max: options.poolMax } : {}),
|
|
71
|
+
})
|
|
72
|
+
: new MissingUrlAdapter({ connectionString: "" });
|
|
73
|
+
return new PrismaClient({ adapter });
|
|
74
|
+
}
|
|
75
|
+
export const prisma = createPrismaClient();
|