@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,6 +10,63 @@
|
|
|
10
10
|
import { createRemoteJWKSet, jwtVerify, errors as joseErrors } from "jose";
|
|
11
11
|
import { AudienceError, NotSupportedError } from "./types.js";
|
|
12
12
|
import { requireSubject } from "./subject.js";
|
|
13
|
+
import { ROLE_NAMES, isRoleName } from "../../mcp/auth/resource-server.js";
|
|
14
|
+
/**
|
|
15
|
+
* Parses AUTH_ROLE_MAP. Whitespace around entries and around `=` is ignored;
|
|
16
|
+
* an unknown wardby role, or a malformed or empty entry, is a startup error.
|
|
17
|
+
* The LAST `=` splits an entry (wardby role names never contain one).
|
|
18
|
+
*/
|
|
19
|
+
export function parseRoleMap(value) {
|
|
20
|
+
const map = new Map();
|
|
21
|
+
const entries = value.split(",").map((e) => e.trim());
|
|
22
|
+
if (entries.every((e) => !e))
|
|
23
|
+
throw new Error("AUTH_ROLE_MAP is empty.");
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
if (!entry)
|
|
26
|
+
continue;
|
|
27
|
+
const at = entry.lastIndexOf("=");
|
|
28
|
+
const idpValue = at > 0 ? entry.slice(0, at).trim() : "";
|
|
29
|
+
const role = at > 0 ? entry.slice(at + 1).trim() : "";
|
|
30
|
+
if (!idpValue || !role)
|
|
31
|
+
throw new Error(`AUTH_ROLE_MAP entry "${entry}" must look like idpValue=wardbyRole.`);
|
|
32
|
+
if (!isRoleName(role))
|
|
33
|
+
throw new Error(`AUTH_ROLE_MAP maps "${idpValue}" to unknown role "${role}" (known: ${ROLE_NAMES.join(", ")}).`);
|
|
34
|
+
map.set(idpValue, [...new Set([...(map.get(idpValue) ?? []), role])]);
|
|
35
|
+
}
|
|
36
|
+
return map;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolves `claim` in a verified payload: an exact top-level name wins (claim
|
|
40
|
+
* names may themselves contain dots and slashes), otherwise a dotted path.
|
|
41
|
+
*/
|
|
42
|
+
function resolveClaim(payload, claim) {
|
|
43
|
+
if (Object.prototype.hasOwnProperty.call(payload, claim))
|
|
44
|
+
return payload[claim];
|
|
45
|
+
if (!claim.includes("."))
|
|
46
|
+
return undefined;
|
|
47
|
+
let value = payload;
|
|
48
|
+
for (const part of claim.split(".")) {
|
|
49
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
50
|
+
return undefined;
|
|
51
|
+
if (!Object.prototype.hasOwnProperty.call(value, part))
|
|
52
|
+
return undefined;
|
|
53
|
+
value = value[part];
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Maps a resolved claim (a string, or an array of strings) through the role
|
|
59
|
+
* map; unmapped values are ignored, and any other shape yields no roles.
|
|
60
|
+
*/
|
|
61
|
+
function rolesFromClaim(value, map) {
|
|
62
|
+
const values = typeof value === "string" ? [value] : Array.isArray(value) ? value : [];
|
|
63
|
+
const roles = new Set();
|
|
64
|
+
for (const v of values)
|
|
65
|
+
if (typeof v === "string")
|
|
66
|
+
for (const r of map.get(v) ?? [])
|
|
67
|
+
roles.add(r);
|
|
68
|
+
return [...roles];
|
|
69
|
+
}
|
|
13
70
|
/**
|
|
14
71
|
* Every spelling of the configured audience a token may legitimately carry.
|
|
15
72
|
*
|
|
@@ -53,9 +110,16 @@ export class DelegatingAuthProvider {
|
|
|
53
110
|
config;
|
|
54
111
|
audiences;
|
|
55
112
|
jwks;
|
|
113
|
+
roleMap;
|
|
56
114
|
constructor(config, jwks) {
|
|
57
115
|
if (!config.issuer || !config.audience)
|
|
58
116
|
throw new Error("AUTH_ISSUER and AUTH_AUDIENCE are required.");
|
|
117
|
+
// Half a configuration would silently give everyone no roles while
|
|
118
|
+
// looking configured — refuse to start instead.
|
|
119
|
+
if ((config.roleClaim !== undefined || config.roleMap !== undefined) && (!config.roleClaim || !config.roleMap))
|
|
120
|
+
throw new Error("AUTH_ROLE_CLAIM and AUTH_ROLE_MAP must be set together (or both left unset).");
|
|
121
|
+
if (config.roleMap)
|
|
122
|
+
this.roleMap = parseRoleMap(config.roleMap);
|
|
59
123
|
this.config = config;
|
|
60
124
|
this.audiences = audienceCandidates(config.audience);
|
|
61
125
|
if (jwks) {
|
|
@@ -80,6 +144,13 @@ export class DelegatingAuthProvider {
|
|
|
80
144
|
email: typeof payload.email === "string" ? payload.email : undefined,
|
|
81
145
|
roles: Array.isArray(payload.roles) ? payload.roles.map(String) : [],
|
|
82
146
|
scopes: scopesFromClaim(payload.scope ?? payload.scp),
|
|
147
|
+
// Read from the bearer token validated above for this issuer and
|
|
148
|
+
// audience (signature, expiry too); the IdP should mint that audience
|
|
149
|
+
// only into access tokens. Unconfigured, every caller has no roles
|
|
150
|
+
// and privileged operations are refused.
|
|
151
|
+
wardbyRoles: this.config.roleClaim && this.roleMap
|
|
152
|
+
? rolesFromClaim(resolveClaim(payload, this.config.roleClaim), this.roleMap)
|
|
153
|
+
: [],
|
|
83
154
|
};
|
|
84
155
|
}
|
|
85
156
|
catch (err) {
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
* kind. Both adapters implement the same AuthProvider (incl. verifyBearer),
|
|
4
4
|
* so the resource-server middleware and tool handlers never branch on mode.
|
|
5
5
|
*/
|
|
6
|
-
import type { PrismaClient } from "
|
|
6
|
+
import type { PrismaClient } from "#prisma";
|
|
7
7
|
import type { AuthProviderKind, AuthConfig } from "../../config/providers.js";
|
|
8
8
|
import type { AuthProvider } from "./types.js";
|
|
9
9
|
export { DelegatingAuthProvider } from "./delegating.js";
|
|
10
10
|
export { SelfHostedAuthProvider } from "./self-hosted.js";
|
|
11
|
+
/** Configuration that is valid but almost certainly not what the operator meant. */
|
|
12
|
+
export declare function authConfigWarnings(kind: AuthProviderKind, config: AuthConfig): string[];
|
|
11
13
|
export declare function buildAuthProvider(kind: AuthProviderKind, config: AuthConfig, db: PrismaClient): AuthProvider;
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { DelegatingAuthProvider } from "./delegating.js";
|
|
2
2
|
import { SelfHostedAuthProvider } from "./self-hosted.js";
|
|
3
|
+
import { logger } from "../../core/logger.js";
|
|
3
4
|
export { DelegatingAuthProvider } from "./delegating.js";
|
|
4
5
|
export { SelfHostedAuthProvider } from "./self-hosted.js";
|
|
6
|
+
/** Configuration that is valid but almost certainly not what the operator meant. */
|
|
7
|
+
export function authConfigWarnings(kind, config) {
|
|
8
|
+
const warnings = [];
|
|
9
|
+
if (kind === "self-hosted" && (config.roleClaim || config.roleMap))
|
|
10
|
+
warnings.push("AUTH_ROLE_CLAIM / AUTH_ROLE_MAP are set but ignored with AUTH_PROVIDER=self-hosted: self-hosted roles " +
|
|
11
|
+
"come from the database (`wardby auth user grant --subject <s> --role <role>`).");
|
|
12
|
+
return warnings;
|
|
13
|
+
}
|
|
5
14
|
export function buildAuthProvider(kind, config, db) {
|
|
15
|
+
for (const warning of authConfigWarnings(kind, config))
|
|
16
|
+
logger.warn({ module: "auth" }, warning);
|
|
6
17
|
if (kind === "self-hosted") {
|
|
7
18
|
if (!config.audience || !config.signingKey || !config.credentialHashKey) {
|
|
8
19
|
throw new Error("AUTH_AUDIENCE, AUTH_SIGNING_KEY, and AUTH_CREDENTIAL_HASH_KEY are required.");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PrismaClient } from "
|
|
1
|
+
import type { PrismaClient } from "#prisma";
|
|
2
2
|
import type { AuthProfile, AuthProvider, AuthTokens, VerifiedToken } from "./types.js";
|
|
3
3
|
import { Credentials } from "../../mcp/auth/self-hosted/credentials.js";
|
|
4
4
|
import { Sessions } from "../../mcp/auth/self-hosted/session.js";
|
|
@@ -34,7 +34,7 @@ export declare class SelfHostedAuthProvider implements AuthProvider {
|
|
|
34
34
|
consentPage(sessionToken: string, interactionId: string): Promise<{
|
|
35
35
|
interaction: {
|
|
36
36
|
client: {
|
|
37
|
-
metadata: import("@prisma/client/runtime/
|
|
37
|
+
metadata: import("@prisma/client/runtime/client").JsonValue;
|
|
38
38
|
createdAt: Date;
|
|
39
39
|
clientId: string;
|
|
40
40
|
};
|
|
@@ -42,15 +42,16 @@ export declare class SelfHostedAuthProvider implements AuthProvider {
|
|
|
42
42
|
id: string;
|
|
43
43
|
createdAt: Date;
|
|
44
44
|
state: string | null;
|
|
45
|
+
clientId: string;
|
|
45
46
|
expiresAt: Date;
|
|
46
47
|
resource: string;
|
|
47
|
-
clientId: string;
|
|
48
48
|
consumedAt: Date | null;
|
|
49
49
|
redirectUri: string;
|
|
50
50
|
codeChallenge: string;
|
|
51
51
|
requestedScope: string;
|
|
52
52
|
};
|
|
53
53
|
challenge: string;
|
|
54
|
+
scopes: string[];
|
|
54
55
|
}>;
|
|
55
56
|
consent(sessionToken: string, interactionId: string, challenge: string, approve: boolean): Promise<string>;
|
|
56
57
|
handleToken(params: TokenParams): Promise<TokenResult>;
|
|
@@ -3,7 +3,7 @@ import { SignJWT, jwtVerify } from "jose";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { NotSupportedError } from "./types.js";
|
|
5
5
|
import { requireSubject } from "./subject.js";
|
|
6
|
-
import { SCOPES_SUPPORTED } from "../../mcp/auth/resource-server.js";
|
|
6
|
+
import { SCOPES_SUPPORTED, limitScope } from "../../mcp/auth/resource-server.js";
|
|
7
7
|
import { canonicalUrl } from "../../mcp/transport/http-limits.js";
|
|
8
8
|
import { Credentials, DAY, decodeKey, lockUser } from "../../mcp/auth/self-hosted/credentials.js";
|
|
9
9
|
import { Sessions } from "../../mcp/auth/self-hosted/session.js";
|
|
@@ -106,7 +106,7 @@ export class SelfHostedAuthProvider {
|
|
|
106
106
|
const metadata = client?.metadata;
|
|
107
107
|
if (!metadata?.redirect_uris?.includes(p.redirectUri) || !metadata.grant_types?.includes("authorization_code"))
|
|
108
108
|
throw new Error("Invalid client or redirect.");
|
|
109
|
-
const scope =
|
|
109
|
+
const scope = limitScope(p.scope, SCOPES_SUPPORTED);
|
|
110
110
|
const request = await this.db.oAuthAuthorizationRequest.create({
|
|
111
111
|
data: {
|
|
112
112
|
clientId: p.clientId,
|
|
@@ -129,7 +129,10 @@ export class SelfHostedAuthProvider {
|
|
|
129
129
|
if (!interaction || interaction.consumedAt || interaction.expiresAt.getTime() <= Date.now())
|
|
130
130
|
throw new Error("Invalid interaction.");
|
|
131
131
|
const challenge = await this.sessions.challenge("consent", session.sessionId, interactionId);
|
|
132
|
-
|
|
132
|
+
// Exactly what approving issues: the stored (supported-only) request.
|
|
133
|
+
// It's fixed when the interaction is created, so what the page shows
|
|
134
|
+
// can't drift from what consent() puts on the code.
|
|
135
|
+
return { interaction, challenge, scopes: interaction.requestedScope.split(" ").filter(Boolean) };
|
|
133
136
|
}
|
|
134
137
|
async consent(sessionToken, interactionId, challenge, approve) {
|
|
135
138
|
const first = await this.sessions.get(sessionToken);
|
|
@@ -339,7 +342,16 @@ export class SelfHostedAuthProvider {
|
|
|
339
342
|
family.clientId !== payload.client_id ||
|
|
340
343
|
payload.scope !== family.scope)
|
|
341
344
|
throw new Error("Invalid token.");
|
|
342
|
-
|
|
345
|
+
// Roles are read from the database on every request (no caching), so a
|
|
346
|
+
// grant or revocation applies to live tokens immediately. Scopes stay
|
|
347
|
+
// exactly what the user consented to; roles decide whether the
|
|
348
|
+
// privileged ones are honoured (resource-server.ts requireScope).
|
|
349
|
+
return {
|
|
350
|
+
subject,
|
|
351
|
+
scopes: family.scope.split(/\s+/).filter(Boolean),
|
|
352
|
+
roles: [],
|
|
353
|
+
wardbyRoles: family.user.roles ?? [],
|
|
354
|
+
};
|
|
343
355
|
}
|
|
344
356
|
async cleanup() {
|
|
345
357
|
const now = new Date();
|
|
@@ -32,6 +32,12 @@ export interface VerifiedToken {
|
|
|
32
32
|
scopes: string[];
|
|
33
33
|
email?: string;
|
|
34
34
|
roles?: string[];
|
|
35
|
+
/**
|
|
36
|
+
* wardby roles (not the IdP's raw `roles`), decided by the provider at
|
|
37
|
+
* verification time: self-hosted reads AuthUser.roles live; delegating
|
|
38
|
+
* maps the configured signed claim through AUTH_ROLE_MAP. Absent = none.
|
|
39
|
+
*/
|
|
40
|
+
wardbyRoles?: string[];
|
|
35
41
|
}
|
|
36
42
|
export interface AuthTokens {
|
|
37
43
|
idToken: string;
|
|
@@ -12,6 +12,9 @@ export declare class MemoryProxyLedger implements ProxyLedger {
|
|
|
12
12
|
release(requestId: string, upstreamStatus: number): Promise<void>;
|
|
13
13
|
markUncertain(requestId: string, upstreamStatus?: number): Promise<void>;
|
|
14
14
|
cancelSession(sessionId: string): Promise<void>;
|
|
15
|
+
budgetExhausted(sessionId: string): Promise<boolean>;
|
|
16
|
+
recordUpstreamFailure(sessionId: string, code: string): Promise<void>;
|
|
17
|
+
upstreamFailure(sessionId: string): Promise<string | null>;
|
|
15
18
|
getRequest(requestId: string): Promise<ProxyRequest | null>;
|
|
16
19
|
private requiredRequest;
|
|
17
20
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
function cloneSession(session) {
|
|
2
|
-
return {
|
|
2
|
+
return {
|
|
3
|
+
...session,
|
|
4
|
+
allowedModels: [...session.allowedModels],
|
|
5
|
+
deadlineAt: new Date(session.deadlineAt),
|
|
6
|
+
budgetExhaustedAt: session.budgetExhaustedAt ? new Date(session.budgetExhaustedAt) : null,
|
|
7
|
+
upstreamFailure: session.upstreamFailure ?? null,
|
|
8
|
+
};
|
|
3
9
|
}
|
|
4
10
|
function cloneRequest(request) {
|
|
5
11
|
return {
|
|
@@ -48,8 +54,10 @@ export class MemoryProxyLedger {
|
|
|
48
54
|
if (request.status === "reserved" || request.status === "uncertain")
|
|
49
55
|
committedOrHeld += request.reservationUsd;
|
|
50
56
|
}
|
|
51
|
-
if (committedOrHeld + input.reservationUsd >= session.budgetUsd)
|
|
57
|
+
if (committedOrHeld + input.reservationUsd >= session.budgetUsd) {
|
|
58
|
+
session.budgetExhaustedAt ??= new Date(input.now);
|
|
52
59
|
return { outcome: "budget_exhausted" };
|
|
60
|
+
}
|
|
53
61
|
const request = { ...input, pricing: { ...input.pricing }, status: "reserved" };
|
|
54
62
|
this.requests.set(request.id, request);
|
|
55
63
|
this.requestBySessionKey.set(lookupKey, request.id);
|
|
@@ -90,6 +98,17 @@ export class MemoryProxyLedger {
|
|
|
90
98
|
if (session)
|
|
91
99
|
session.status = "cancelled";
|
|
92
100
|
}
|
|
101
|
+
async budgetExhausted(sessionId) {
|
|
102
|
+
return Boolean(this.sessions.get(sessionId)?.budgetExhaustedAt);
|
|
103
|
+
}
|
|
104
|
+
async recordUpstreamFailure(sessionId, code) {
|
|
105
|
+
const session = this.sessions.get(sessionId);
|
|
106
|
+
if (session)
|
|
107
|
+
session.upstreamFailure ??= code;
|
|
108
|
+
}
|
|
109
|
+
async upstreamFailure(sessionId) {
|
|
110
|
+
return this.sessions.get(sessionId)?.upstreamFailure ?? null;
|
|
111
|
+
}
|
|
93
112
|
async getRequest(requestId) {
|
|
94
113
|
const request = this.requests.get(requestId);
|
|
95
114
|
return request ? cloneRequest(request) : null;
|
|
@@ -8,8 +8,12 @@ export declare function fingerprintRequest(body: string): string;
|
|
|
8
8
|
export interface TerminalUsage {
|
|
9
9
|
terminal: boolean;
|
|
10
10
|
usage?: ProxyUsage;
|
|
11
|
+
/** Set when the upstream ended the response as failed or incomplete: its error code. */
|
|
12
|
+
failure?: string;
|
|
11
13
|
}
|
|
12
14
|
export declare function terminalUsageFromSseFrame(frame: string): TerminalUsage;
|
|
15
|
+
/** The safe error code in an upstream error body (a stream event or a rejected response's JSON), if any. */
|
|
16
|
+
export declare function safeUpstreamErrorCode(record: Record<string, unknown>): string | undefined;
|
|
13
17
|
/** Accumulates Anthropic's split input/output usage until message_stop. */
|
|
14
18
|
export declare class AnthropicSseUsageTracker {
|
|
15
19
|
private startUsage?;
|
|
@@ -74,13 +74,36 @@ export function terminalUsageFromSseFrame(frame) {
|
|
|
74
74
|
if (!event || typeof event !== "object")
|
|
75
75
|
return { terminal: false };
|
|
76
76
|
const record = event;
|
|
77
|
-
|
|
77
|
+
// A stream-level error event (quota, rate limit, server error) ends the response with no usage.
|
|
78
|
+
if (record.type === "error")
|
|
79
|
+
return { terminal: true, failure: upstreamErrorCode(record) };
|
|
80
|
+
const failed = record.type === "response.failed" || record.type === "response.incomplete";
|
|
81
|
+
if (record.type !== "response.completed" && !failed)
|
|
78
82
|
return { terminal: false };
|
|
79
83
|
const response = record.response;
|
|
80
84
|
if (!response || typeof response !== "object")
|
|
81
85
|
throw new Error("invalid_upstream_terminal_event");
|
|
82
86
|
const usage = response.usage;
|
|
83
|
-
return {
|
|
87
|
+
return {
|
|
88
|
+
terminal: true,
|
|
89
|
+
usage: usage == null ? undefined : parseAuthoritativeUsage(usage),
|
|
90
|
+
...(failed ? { failure: upstreamErrorCode(response) } : {}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const SAFE_ERROR_CODE = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
94
|
+
/** The upstream's own error code, never its message: codes are fixed identifiers, messages can echo input. */
|
|
95
|
+
function upstreamErrorCode(record) {
|
|
96
|
+
return safeUpstreamErrorCode(record) ?? "unknown";
|
|
97
|
+
}
|
|
98
|
+
/** The safe error code in an upstream error body (a stream event or a rejected response's JSON), if any. */
|
|
99
|
+
export function safeUpstreamErrorCode(record) {
|
|
100
|
+
const nested = (key) => {
|
|
101
|
+
const value = record[key];
|
|
102
|
+
return value && typeof value === "object" ? value : undefined;
|
|
103
|
+
};
|
|
104
|
+
const candidates = [nested("error")?.code, nested("error")?.type, nested("incomplete_details")?.reason, record.code];
|
|
105
|
+
const code = candidates.find((value) => typeof value === "string" && SAFE_ERROR_CODE.test(value));
|
|
106
|
+
return typeof code === "string" ? code : undefined;
|
|
84
107
|
}
|
|
85
108
|
function sseEvent(frame) {
|
|
86
109
|
const lines = frame.split("\n");
|
|
@@ -118,6 +141,9 @@ export class AnthropicSseUsageTracker {
|
|
|
118
141
|
if (!value)
|
|
119
142
|
return { terminal: false };
|
|
120
143
|
switch (value.type) {
|
|
144
|
+
// A stream-level error event (quota, rate limit, server error) ends the response with no usage.
|
|
145
|
+
case "error":
|
|
146
|
+
return { terminal: true, failure: upstreamErrorCode(value) };
|
|
121
147
|
case "message_start": {
|
|
122
148
|
if (this.startUsage || !value.message || typeof value.message !== "object") {
|
|
123
149
|
throw new Error("invalid_upstream_sse");
|
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
import type { PrismaClient } from "
|
|
1
|
+
import type { PrismaClient } from "#prisma";
|
|
2
2
|
import type { CreateProxySessionInput, ProxyLedger, ProxyRequest, ProxySession, ProxyUsage, ReserveProxyRequestInput, ReserveProxyRequestResult } from "./types.js";
|
|
3
3
|
export type PrismaProxyLedgerDb = Pick<PrismaClient, "$transaction" | "$queryRaw" | "$executeRaw">;
|
|
4
|
+
/** How long a ledger transaction waits for a pool connection (Prisma's
|
|
5
|
+
* default is 2 s). A model request fails outright when this runs out, so it
|
|
6
|
+
* gets more room than the default; its pool is also kept apart from the
|
|
7
|
+
* package registry's (coding-proxy/main.ts). */
|
|
8
|
+
export declare const LEDGER_TRANSACTION_MAX_WAIT_MS = 5000;
|
|
9
|
+
/** How long a ledger transaction may run once started (Prisma's default is
|
|
10
|
+
* 5 s). Each is a handful of small queries, but a proxy busy with package
|
|
11
|
+
* installs (the registry's dependency walk parses large npm documents on the
|
|
12
|
+
* same event loop) can stall between them; a live lockfile install expired
|
|
13
|
+
* one ("A commit cannot be executed on an expired transaction") and failed
|
|
14
|
+
* the model request. The row lock it holds is per session, so a longer
|
|
15
|
+
* window only delays that run's own next request. */
|
|
16
|
+
export declare const LEDGER_TRANSACTION_TIMEOUT_MS = 20000;
|
|
4
17
|
export declare class PrismaProxyLedger implements ProxyLedger {
|
|
5
18
|
private readonly db;
|
|
6
19
|
constructor(db: PrismaProxyLedgerDb);
|
|
20
|
+
private transaction;
|
|
7
21
|
createSession(input: CreateProxySessionInput): Promise<void>;
|
|
8
22
|
findSessionByCapabilityHash(capabilityHash: string): Promise<ProxySession | null>;
|
|
9
23
|
reserve(input: ReserveProxyRequestInput): Promise<ReserveProxyRequestResult>;
|
|
@@ -11,5 +25,8 @@ export declare class PrismaProxyLedger implements ProxyLedger {
|
|
|
11
25
|
release(requestId: string, upstreamStatus: number): Promise<void>;
|
|
12
26
|
markUncertain(requestId: string, upstreamStatus?: number): Promise<void>;
|
|
13
27
|
cancelSession(sessionId: string): Promise<void>;
|
|
28
|
+
budgetExhausted(sessionId: string): Promise<boolean>;
|
|
29
|
+
recordUpstreamFailure(sessionId: string, code: string): Promise<void>;
|
|
30
|
+
upstreamFailure(sessionId: string): Promise<string | null>;
|
|
14
31
|
getRequest(requestId: string): Promise<ProxyRequest | null>;
|
|
15
32
|
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/** How long a ledger transaction waits for a pool connection (Prisma's
|
|
2
|
+
* default is 2 s). A model request fails outright when this runs out, so it
|
|
3
|
+
* gets more room than the default; its pool is also kept apart from the
|
|
4
|
+
* package registry's (coding-proxy/main.ts). */
|
|
5
|
+
export const LEDGER_TRANSACTION_MAX_WAIT_MS = 5_000;
|
|
6
|
+
/** How long a ledger transaction may run once started (Prisma's default is
|
|
7
|
+
* 5 s). Each is a handful of small queries, but a proxy busy with package
|
|
8
|
+
* installs (the registry's dependency walk parses large npm documents on the
|
|
9
|
+
* same event loop) can stall between them; a live lockfile install expired
|
|
10
|
+
* one ("A commit cannot be executed on an expired transaction") and failed
|
|
11
|
+
* the model request. The row lock it holds is per session, so a longer
|
|
12
|
+
* window only delays that run's own next request. */
|
|
13
|
+
export const LEDGER_TRANSACTION_TIMEOUT_MS = 20_000;
|
|
1
14
|
function sessionFromRow(row) {
|
|
2
15
|
if (!Array.isArray(row.allowedModels) || !row.allowedModels.every((model) => typeof model === "string")) {
|
|
3
16
|
throw new Error("invalid_proxy_session_models");
|
|
@@ -15,6 +28,9 @@ function sessionFromRow(row) {
|
|
|
15
28
|
deadlineAt: row.deadlineAt,
|
|
16
29
|
budgetUsd: Number(row.budgetUsd),
|
|
17
30
|
status: row.status,
|
|
31
|
+
registryTokenHash: row.registryTokenHash,
|
|
32
|
+
budgetExhaustedAt: row.budgetExhaustedAt ?? null,
|
|
33
|
+
upstreamFailure: row.upstreamFailure ?? null,
|
|
18
34
|
};
|
|
19
35
|
}
|
|
20
36
|
function requestFromRow(row) {
|
|
@@ -57,26 +73,33 @@ export class PrismaProxyLedger {
|
|
|
57
73
|
constructor(db) {
|
|
58
74
|
this.db = db;
|
|
59
75
|
}
|
|
76
|
+
transaction(fn) {
|
|
77
|
+
return this.db.$transaction(fn, {
|
|
78
|
+
maxWait: LEDGER_TRANSACTION_MAX_WAIT_MS,
|
|
79
|
+
timeout: LEDGER_TRANSACTION_TIMEOUT_MS,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
60
82
|
async createSession(input) {
|
|
61
83
|
const models = JSON.stringify(input.allowedModels);
|
|
62
84
|
await this.db.$executeRaw `
|
|
63
85
|
INSERT INTO "CodingProxySession"
|
|
64
86
|
("id", "runId", "capabilityHash", "credentialRef", "protocol", "allowedModels", "deadlineAt",
|
|
65
|
-
"budgetUsd", "status", "createdAt", "updatedAt")
|
|
87
|
+
"budgetUsd", "status", "registryTokenHash", "createdAt", "updatedAt")
|
|
66
88
|
VALUES
|
|
67
89
|
(${input.id}, ${input.runId}, ${input.capabilityHash}, ${input.credentialRef}, ${input.protocol}, ${models}::jsonb,
|
|
68
|
-
${input.deadlineAt}, ${input.budgetUsd}, 'active', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
|
90
|
+
${input.deadlineAt}, ${input.budgetUsd}, 'active', ${input.registryTokenHash}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
|
69
91
|
`;
|
|
70
92
|
}
|
|
71
93
|
async findSessionByCapabilityHash(capabilityHash) {
|
|
72
94
|
const rows = await this.db.$queryRaw `
|
|
73
|
-
SELECT "id", "runId", "capabilityHash", "credentialRef", "protocol", "allowedModels", "deadlineAt", "budgetUsd", "status"
|
|
95
|
+
SELECT "id", "runId", "capabilityHash", "credentialRef", "protocol", "allowedModels", "deadlineAt", "budgetUsd", "status", "registryTokenHash",
|
|
96
|
+
"budgetExhaustedAt", "upstreamFailure"
|
|
74
97
|
FROM "CodingProxySession" WHERE "capabilityHash" = ${capabilityHash}
|
|
75
98
|
`;
|
|
76
99
|
return rows[0] ? sessionFromRow(rows[0]) : null;
|
|
77
100
|
}
|
|
78
101
|
async reserve(input) {
|
|
79
|
-
return this.
|
|
102
|
+
return this.transaction(async (tx) => {
|
|
80
103
|
const sessions = await tx.$queryRaw `
|
|
81
104
|
SELECT "id", "runId", "capabilityHash", "credentialRef", "protocol", "allowedModels", "deadlineAt", "budgetUsd", "status"
|
|
82
105
|
FROM "CodingProxySession" WHERE "id" = ${input.sessionId} FOR UPDATE
|
|
@@ -107,6 +130,10 @@ export class PrismaProxyLedger {
|
|
|
107
130
|
FROM "CodingProxyRequest" WHERE "sessionId" = ${input.sessionId}
|
|
108
131
|
`;
|
|
109
132
|
if (Number(totals[0]?.held ?? 0) + input.reservationUsd >= Number(row.budgetUsd)) {
|
|
133
|
+
await tx.$executeRaw `
|
|
134
|
+
UPDATE "CodingProxySession" SET "budgetExhaustedAt" = COALESCE("budgetExhaustedAt", ${input.now})
|
|
135
|
+
WHERE "id" = ${input.sessionId}
|
|
136
|
+
`;
|
|
110
137
|
return { outcome: "budget_exhausted" };
|
|
111
138
|
}
|
|
112
139
|
const pricing = JSON.stringify({
|
|
@@ -132,7 +159,7 @@ export class PrismaProxyLedger {
|
|
|
132
159
|
});
|
|
133
160
|
}
|
|
134
161
|
async complete(requestId, usage, actualCostUsd, upstreamStatus) {
|
|
135
|
-
return this.
|
|
162
|
+
return this.transaction(async (tx) => {
|
|
136
163
|
const initial = await requestById(tx, requestId);
|
|
137
164
|
if (!initial)
|
|
138
165
|
throw new Error("unknown_proxy_request");
|
|
@@ -207,6 +234,24 @@ export class PrismaProxyLedger {
|
|
|
207
234
|
WHERE "id" = ${sessionId} AND "status" = 'active'
|
|
208
235
|
`;
|
|
209
236
|
}
|
|
237
|
+
async budgetExhausted(sessionId) {
|
|
238
|
+
const rows = await this.db.$queryRaw `
|
|
239
|
+
SELECT "id" FROM "CodingProxySession" WHERE "id" = ${sessionId} AND "budgetExhaustedAt" IS NOT NULL
|
|
240
|
+
`;
|
|
241
|
+
return rows.length > 0;
|
|
242
|
+
}
|
|
243
|
+
async recordUpstreamFailure(sessionId, code) {
|
|
244
|
+
await this.db.$executeRaw `
|
|
245
|
+
UPDATE "CodingProxySession" SET "upstreamFailure" = ${code}, "updatedAt" = CURRENT_TIMESTAMP
|
|
246
|
+
WHERE "id" = ${sessionId} AND "upstreamFailure" IS NULL
|
|
247
|
+
`;
|
|
248
|
+
}
|
|
249
|
+
async upstreamFailure(sessionId) {
|
|
250
|
+
const rows = await this.db.$queryRaw `
|
|
251
|
+
SELECT "upstreamFailure" FROM "CodingProxySession" WHERE "id" = ${sessionId}
|
|
252
|
+
`;
|
|
253
|
+
return rows[0]?.upstreamFailure ?? null;
|
|
254
|
+
}
|
|
210
255
|
getRequest(requestId) {
|
|
211
256
|
return requestById(this.db, requestId);
|
|
212
257
|
}
|
|
@@ -4,6 +4,12 @@ export declare const PROXY_MAX_BODY_BYTES: number;
|
|
|
4
4
|
export declare const PROXY_MAX_OUTPUT_TOKENS = 1000000;
|
|
5
5
|
export declare const PROXY_DEFAULT_MAX_OUTPUT_TOKENS = 4096;
|
|
6
6
|
export declare const CLAUDE_CODE_ANTHROPIC_BETAS: readonly ["claude-code-20250219", "context-management-2025-06-27", "effort-2025-11-24", "interleaved-thinking-2025-05-14", "mid-conversation-system-2026-04-07", "prompt-caching-scope-2026-01-05", "thinking-token-count-2026-05-13"];
|
|
7
|
+
/**
|
|
8
|
+
* The longest run_command timeout the Claude tool runner offers the model (its MAX_TIMEOUT_MS,
|
|
9
|
+
* src/claude-tool-runner/command.mjs; the proxy tests keep the two equal). A lower limit here let the
|
|
10
|
+
* command run, then refused the next request, which replays that tool call, as unsupported.
|
|
11
|
+
*/
|
|
12
|
+
export declare const MAX_COMMAND_TIMEOUT_MS = 120000;
|
|
7
13
|
export declare class CodingProxyError extends Error {
|
|
8
14
|
readonly status: number;
|
|
9
15
|
readonly code: string;
|
|
@@ -51,6 +57,7 @@ export interface CodingProxyOptions {
|
|
|
51
57
|
pricing?: (model: string, protocol: ProxyProtocol) => ModelPricing;
|
|
52
58
|
pricingVersion?: string;
|
|
53
59
|
}
|
|
60
|
+
export declare function capabilityHash(capability: string): string;
|
|
54
61
|
export declare class CodingProxy {
|
|
55
62
|
private readonly ledger;
|
|
56
63
|
private readonly credentials;
|
|
@@ -64,6 +71,10 @@ export declare class CodingProxy {
|
|
|
64
71
|
constructor(options: CodingProxyOptions);
|
|
65
72
|
createSession(input: CreateCodingProxySession): Promise<CreatedCodingProxySession>;
|
|
66
73
|
cancelSession(sessionId: string): Promise<void>;
|
|
74
|
+
/** Whether this session's run was refused a model request for budget. */
|
|
75
|
+
budgetExhausted(sessionId: string): Promise<boolean>;
|
|
76
|
+
/** The code of the first upstream failure relayed for this session's run, if any. */
|
|
77
|
+
upstreamFailure(sessionId: string): Promise<string | null>;
|
|
67
78
|
execute(input: ExecuteProxyRequest, sink: ProxyResponseSink): Promise<void>;
|
|
68
79
|
private authenticate;
|
|
69
80
|
private trackActive;
|
|
@@ -71,5 +82,7 @@ export declare class CodingProxy {
|
|
|
71
82
|
private complete;
|
|
72
83
|
private forwardJson;
|
|
73
84
|
private forwardStream;
|
|
85
|
+
/** Best effort: the executor reads it to name the failure; it must never break the relay. */
|
|
86
|
+
private recordUpstreamFailure;
|
|
74
87
|
private markUncertain;
|
|
75
88
|
}
|