@wardby/cli 0.5.3 → 0.7.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 +33 -0
- package/README.md +25 -14
- package/deploy/local/docker-compose.quickstart-coding.yml +13 -0
- package/dist/claude-coding-worker/context.d.ts +22 -0
- package/dist/claude-coding-worker/context.js +92 -0
- package/dist/claude-coding-worker/driver.d.ts +27 -3
- package/dist/claude-coding-worker/driver.js +161 -20
- package/dist/claude-coding-worker/main.js +34 -6
- package/dist/claude-coding-worker/sdk.js +25 -5
- package/dist/claude-coding-worker/tool-socket.d.ts +27 -0
- package/dist/claude-coding-worker/tool-socket.js +111 -0
- package/dist/claude-coding-worker/transcript.d.ts +18 -0
- package/dist/claude-coding-worker/transcript.js +77 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +6 -2
- package/dist/cli-native-mode.d.ts +9 -0
- package/dist/cli-native-mode.js +20 -0
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +161 -11
- package/dist/coding/claude-context.d.ts +45 -0
- package/dist/coding/claude-context.js +434 -0
- package/dist/coding/continuation-wording.d.ts +35 -0
- package/dist/coding/continuation-wording.js +73 -0
- package/dist/coding/linked-issue-note.d.ts +23 -0
- package/dist/coding/linked-issue-note.js +47 -0
- package/dist/coding/merge-wording.d.ts +28 -0
- package/dist/coding/merge-wording.js +78 -0
- package/dist/coding/pr-description-note.d.ts +9 -0
- package/dist/coding/pr-description-note.js +32 -0
- package/dist/coding/profile.d.ts +50 -118
- package/dist/coding/profile.js +51 -4
- package/dist/coding/protected-path-wording.d.ts +8 -0
- package/dist/coding/protected-path-wording.js +1 -1
- package/dist/coding/protocol.d.ts +292 -270
- package/dist/coding/protocol.js +322 -15
- package/dist/coding/redact.d.ts +3 -0
- package/dist/coding/redact.js +12 -0
- package/dist/coding/registry/allowlist.d.ts +12 -0
- package/dist/coding/registry/allowlist.js +14 -1
- package/dist/coding/registry/audit-mode.d.ts +153 -0
- package/dist/coding/registry/audit-mode.js +304 -0
- package/dist/coding/registry/lockfile-shared.d.ts +36 -0
- package/dist/coding/registry/lockfile-shared.js +128 -0
- package/dist/coding/registry/lockfiles.js +1 -1
- package/dist/coding/registry/npm-lockfile-formats.d.ts +11 -0
- package/dist/coding/registry/npm-lockfile-formats.js +41 -0
- package/dist/coding/registry/npm-lockfile.d.ts +8 -4
- package/dist/coding/registry/npm-lockfile.js +4 -6
- package/dist/coding/registry/npm.js +78 -8
- package/dist/coding/registry/pnpm-lockfile.d.ts +17 -0
- package/dist/coding/registry/pnpm-lockfile.js +189 -0
- package/dist/coding/registry/pypi-plan.d.ts +50 -0
- package/dist/coding/registry/pypi-plan.js +406 -0
- package/dist/coding/registry/pypi-requirements.d.ts +58 -0
- package/dist/coding/registry/pypi-requirements.js +155 -0
- package/dist/coding/registry/pypi.d.ts +3 -27
- package/dist/coding/registry/pypi.js +40 -154
- package/dist/coding/registry/refusal-hints.d.ts +20 -0
- package/dist/coding/registry/refusal-hints.js +61 -0
- package/dist/coding/registry/refusal-wording.d.ts +11 -0
- package/dist/coding/registry/refusal-wording.js +56 -0
- package/dist/coding/registry/report.d.ts +70 -8
- package/dist/coding/registry/report.js +112 -5
- package/dist/coding/registry/types.d.ts +58 -8
- package/dist/coding/registry/yarn-lockfile.d.ts +30 -0
- package/dist/coding/registry/yarn-lockfile.js +367 -0
- package/dist/coding/services/catalog.d.ts +37 -351
- package/dist/coding/transcript/claude-code.d.ts +13 -0
- package/dist/coding/transcript/claude-code.js +273 -0
- package/dist/coding/transcript/download-protocol.d.ts +30 -0
- package/dist/coding/transcript/download-protocol.js +18 -0
- package/dist/coding/transcript/format.d.ts +20 -0
- package/dist/coding/transcript/format.js +32 -0
- package/dist/coding/transcript/recorder.d.ts +51 -0
- package/dist/coding/transcript/recorder.js +225 -0
- package/dist/coding/transcript/resume/checkout.d.ts +31 -0
- package/dist/coding/transcript/resume/checkout.js +203 -0
- package/dist/coding/transcript/resume/command.d.ts +17 -0
- package/dist/coding/transcript/resume/command.js +176 -0
- package/dist/coding/transcript/resume/download.d.ts +20 -0
- package/dist/coding/transcript/resume/download.js +153 -0
- package/dist/coding/transcript/resume/launch.d.ts +38 -0
- package/dist/coding/transcript/resume/launch.js +128 -0
- package/dist/coding/transcript/resume/session-file.d.ts +13 -0
- package/dist/coding/transcript/resume/session-file.js +79 -0
- package/dist/coding/transcript/resume/stand-in.d.ts +11 -0
- package/dist/coding/transcript/resume/stand-in.js +49 -0
- package/dist/coding-worker/artifact.d.ts +16 -3
- package/dist/coding-worker/artifact.js +5 -3
- package/dist/coding-worker/debug-trace.d.ts +6 -5
- package/dist/coding-worker/debug-trace.js +13 -18
- package/dist/coding-worker/dependency-cache.d.mts +229 -0
- package/dist/coding-worker/dependency-cache.mjs +2123 -0
- package/dist/coding-worker/driver.d.ts +4 -3
- package/dist/coding-worker/driver.js +118 -38
- package/dist/coding-worker/errors.d.ts +1 -0
- package/dist/coding-worker/errors.js +32 -0
- package/dist/coding-worker/sdk.d.ts +6 -0
- package/dist/coding-worker/sdk.js +1 -0
- package/dist/coding-worker/skills.d.ts +23 -0
- package/dist/coding-worker/skills.js +117 -0
- package/dist/coding-worker/task-note.d.ts +11 -0
- package/dist/coding-worker/task-note.js +13 -0
- package/dist/coding-worker/types.d.ts +13 -0
- package/dist/config/dependency-cache.d.ts +23 -0
- package/dist/config/dependency-cache.js +32 -0
- package/dist/config/github-allowed-accounts.d.ts +15 -0
- package/dist/config/github-allowed-accounts.js +36 -0
- package/dist/config/low-power.d.ts +12 -0
- package/dist/config/low-power.js +18 -0
- package/dist/config/mobile.d.ts +12 -0
- package/dist/config/mobile.js +18 -0
- package/dist/config/providers.d.ts +65 -3
- package/dist/config/providers.js +147 -11
- package/dist/config/test-simulators.d.ts +82 -0
- package/dist/config/test-simulators.js +305 -0
- package/dist/core/async-context.d.ts +2 -0
- package/dist/core/async-context.js +12 -0
- package/dist/core/budget-events.d.ts +108 -0
- package/dist/core/budget-events.js +346 -0
- package/dist/core/budget-groups.d.ts +50 -1
- package/dist/core/budget-groups.js +236 -27
- package/dist/core/budget-stopped-head.d.ts +46 -0
- package/dist/core/budget-stopped-head.js +81 -0
- package/dist/core/budget-topup.d.ts +51 -0
- package/dist/core/budget-topup.js +156 -0
- package/dist/core/budget-wording.d.ts +16 -2
- package/dist/core/budget-wording.js +40 -2
- package/dist/core/coding-queue.d.ts +2 -1
- package/dist/core/coding-queue.js +7 -0
- package/dist/core/cron.d.ts +19 -1
- package/dist/core/cron.js +17 -0
- package/dist/core/datastores.js +1 -1
- package/dist/core/db.d.ts +16 -6
- package/dist/core/db.js +12 -10
- package/dist/core/deferred-coding.d.ts +14 -0
- package/dist/core/deferred-coding.js +62 -0
- package/dist/core/delegation-child.d.ts +25 -0
- package/dist/core/delegation-child.js +37 -0
- package/dist/core/dispatch.d.ts +53 -0
- package/dist/core/dispatch.js +167 -57
- package/dist/core/engine-native.js +10 -6
- package/dist/core/error-code.d.ts +38 -0
- package/dist/core/error-code.js +168 -0
- package/dist/core/grants.d.ts +19 -6
- package/dist/core/grants.js +55 -6
- package/dist/core/host-events.d.ts +67 -5
- package/dist/core/host-events.js +571 -37
- package/dist/core/host-status.d.ts +85 -3
- package/dist/core/host-status.js +298 -20
- package/dist/core/issue-bridge.d.ts +50 -6
- package/dist/core/issue-bridge.js +151 -20
- package/dist/core/issue-events.d.ts +1 -1
- package/dist/core/issue-events.js +16 -11
- package/dist/core/issue-status.d.ts +1 -1
- package/dist/core/issue-status.js +68 -29
- package/dist/core/logger.d.ts +5 -0
- package/dist/core/logger.js +14 -1
- package/dist/core/lost-run-children.d.ts +6 -0
- package/dist/core/lost-run-children.js +32 -0
- package/dist/core/mark-ready.d.ts +34 -0
- package/dist/core/mark-ready.js +152 -0
- package/dist/core/markdown-code.d.ts +8 -0
- package/dist/core/markdown-code.js +107 -0
- package/dist/core/memory-tools.js +7 -0
- package/dist/core/merge-order-check.d.ts +130 -0
- package/dist/core/merge-order-check.js +343 -0
- package/dist/core/notification-dispatcher.d.ts +70 -0
- package/dist/core/notification-dispatcher.js +368 -0
- package/dist/core/notification-templates.d.ts +19 -0
- package/dist/core/notification-templates.js +139 -0
- package/dist/core/notifications.d.ts +10 -0
- package/dist/core/notifications.js +38 -0
- package/dist/core/pg-auth.d.ts +22 -0
- package/dist/core/pg-auth.js +152 -0
- package/dist/core/power-composition.d.ts +16 -0
- package/dist/core/power-composition.js +37 -0
- package/dist/core/power-idle.d.ts +14 -0
- package/dist/core/power-idle.js +30 -0
- package/dist/core/power.d.ts +71 -0
- package/dist/core/power.js +202 -0
- package/dist/core/pull-request-state-sync.js +2 -2
- package/dist/core/reconciler.d.ts +8 -5
- package/dist/core/reconciler.js +37 -6
- package/dist/core/related-pull-requests.d.ts +59 -7
- package/dist/core/related-pull-requests.js +140 -25
- package/dist/core/reply-parts.d.ts +21 -0
- package/dist/core/reply-parts.js +73 -0
- package/dist/core/repo-access.d.ts +15 -0
- package/dist/core/repo-access.js +66 -0
- package/dist/core/review-fix.d.ts +38 -1
- package/dist/core/review-fix.js +209 -7
- package/dist/core/review-host-checks.d.ts +1 -1
- package/dist/core/review-host-tools.d.ts +23 -0
- package/dist/core/review-host-tools.js +156 -14
- package/dist/core/review-reads.d.ts +55 -0
- package/dist/core/review-reads.js +233 -0
- package/dist/core/run-status.d.ts +12 -0
- package/dist/core/run-status.js +12 -0
- package/dist/core/runner.d.ts +384 -5
- package/dist/core/runner.js +1244 -372
- package/dist/core/schedule-start.d.ts +12 -0
- package/dist/core/schedule-start.js +14 -0
- package/dist/core/secret-broker-config.d.ts +39 -0
- package/dist/core/secret-broker-config.js +112 -0
- package/dist/core/secret-guard.d.ts +46 -0
- package/dist/core/secret-guard.js +104 -0
- package/dist/core/secret-guarded-stores.d.ts +12 -0
- package/dist/core/secret-guarded-stores.js +41 -0
- package/dist/core/secret-spans.d.ts +50 -0
- package/dist/core/secret-spans.js +94 -0
- package/dist/core/secrets.d.ts +39 -4
- package/dist/core/secrets.js +148 -40
- package/dist/core/stop-run.d.ts +46 -0
- package/dist/core/stop-run.js +61 -0
- package/dist/core/workflow-event-recorder.d.ts +14 -0
- package/dist/core/workflow-event-recorder.js +120 -0
- package/dist/core/workflow-events.d.ts +94 -0
- package/dist/core/workflow-events.js +48 -0
- package/dist/core/workflow-run-events.d.ts +18 -0
- package/dist/core/workflow-run-events.js +75 -0
- package/dist/core/zod-json-schema.d.ts +4 -0
- package/dist/core/zod-json-schema.js +39 -0
- package/dist/core/zod3-window.d.ts +35 -0
- package/dist/core/zod3-window.js +124 -0
- package/dist/generated/prisma/browser.d.ts +92 -3
- package/dist/generated/prisma/client.d.ts +92 -3
- package/dist/generated/prisma/commonInputTypes.d.ts +364 -54
- package/dist/generated/prisma/enums.d.ts +37 -0
- package/dist/generated/prisma/enums.js +31 -0
- package/dist/generated/prisma/internal/class.d.ts +132 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +1332 -142
- package/dist/generated/prisma/internal/prismaNamespace.js +227 -5
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +234 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +227 -5
- package/dist/generated/prisma/models/Agent.d.ts +464 -7
- package/dist/generated/prisma/models/AgentRepository.d.ts +42 -1
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +301 -1
- package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
- package/dist/generated/prisma/models/CodingProxySession.d.ts +114 -1
- package/dist/generated/prisma/models/CodingRun.d.ts +1841 -1
- package/dist/generated/prisma/models/DeferredReview.d.ts +78 -1
- package/dist/generated/prisma/models/DependencySnapshot.d.ts +1668 -0
- package/dist/generated/prisma/models/DependencySnapshot.js +1 -0
- package/dist/generated/prisma/models/IssuePullRequest.d.ts +6 -2
- package/dist/generated/prisma/models/LocalReview.d.ts +40 -1
- package/dist/generated/prisma/models/NativeGatewayCall.d.ts +1713 -0
- package/dist/generated/prisma/models/NativeGatewayCall.js +1 -0
- package/dist/generated/prisma/models/NativeGatewaySession.d.ts +1551 -0
- package/dist/generated/prisma/models/NativeGatewaySession.js +1 -0
- package/dist/generated/prisma/models/NativeWarmWorker.d.ts +1296 -0
- package/dist/generated/prisma/models/NativeWarmWorker.js +1 -0
- package/dist/generated/prisma/models/NotificationChannel.d.ts +1543 -0
- package/dist/generated/prisma/models/NotificationChannel.js +1 -0
- package/dist/generated/prisma/models/NotificationDelivery.d.ts +1502 -0
- package/dist/generated/prisma/models/NotificationDelivery.js +1 -0
- package/dist/generated/prisma/models/NotificationThread.d.ts +1090 -0
- package/dist/generated/prisma/models/NotificationThread.js +1 -0
- package/dist/generated/prisma/models/RegistryAllowance.d.ts +41 -1
- package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +75 -1
- package/dist/generated/prisma/models/RegistryAuditRecord.d.ts +1364 -0
- package/dist/generated/prisma/models/RegistryAuditRecord.js +1 -0
- package/dist/generated/prisma/models/Run.d.ts +1619 -58
- package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
- package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
- package/dist/generated/prisma/models/RunHostCheck.d.ts +36 -1
- package/dist/generated/prisma/models/RunTranscript.d.ts +1339 -0
- package/dist/generated/prisma/models/RunTranscript.js +1 -0
- package/dist/generated/prisma/models/Secret.d.ts +37 -1
- package/dist/generated/prisma/models/SecretBrokerChange.d.ts +1101 -0
- package/dist/generated/prisma/models/SecretBrokerChange.js +1 -0
- package/dist/generated/prisma/models/WorkflowEvent.d.ts +1422 -0
- package/dist/generated/prisma/models/WorkflowEvent.js +1 -0
- package/dist/generated/prisma/models.d.ts +12 -0
- package/dist/help/build.js +4 -2
- package/dist/help/catalog.d.ts +1 -1
- package/dist/help/catalog.js +31 -6
- package/dist/help-index.json +2584 -146
- package/dist/import/create.js +49 -3
- package/dist/import/neutral-schema.d.ts +50 -277
- package/dist/import/neutral-schema.js +7 -4
- package/dist/knowledge/check.d.ts +1 -1
- package/dist/knowledge/cli.d.ts +11 -1
- package/dist/knowledge/cli.js +37 -4
- package/dist/knowledge/concept.d.ts +3 -19
- package/dist/knowledge/location.d.ts +31 -0
- package/dist/knowledge/location.js +78 -0
- package/dist/mcp/auth/access.d.ts +11 -2
- package/dist/mcp/auth/access.js +15 -1
- package/dist/mcp/auth/ownership.d.ts +7 -7
- package/dist/mcp/auth/repo-authorization.js +14 -0
- package/dist/mcp/auth/resource-server.d.ts +2 -1
- package/dist/mcp/auth/resource-server.js +7 -2
- package/dist/mcp/auth/self-hosted/browser.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/browser.js +19 -6
- package/dist/mcp/auth/self-hosted/credentials.d.ts +3 -3
- package/dist/mcp/auth/self-hosted/session.d.ts +2 -2
- package/dist/mcp/context.d.ts +6 -0
- package/dist/mcp/host-events/github-ingress.d.ts +25 -1
- package/dist/mcp/host-events/github-ingress.js +70 -1
- package/dist/mcp/index.d.ts +19 -0
- package/dist/mcp/index.js +117 -20
- package/dist/mcp/server.d.ts +13 -0
- package/dist/mcp/server.js +33 -14
- package/dist/mcp/tools/agents.d.ts +4 -0
- package/dist/mcp/tools/agents.js +277 -24
- package/dist/mcp/tools/datastore.js +17 -8
- package/dist/mcp/tools/grants.js +9 -3
- package/dist/mcp/tools/memory.js +11 -1
- package/dist/mcp/tools/notification-channels.d.ts +2 -0
- package/dist/mcp/tools/notification-channels.js +293 -0
- package/dist/mcp/tools/packages.d.ts +2 -0
- package/dist/mcp/tools/packages.js +195 -0
- package/dist/mcp/tools/power.d.ts +2 -0
- package/dist/mcp/tools/power.js +77 -0
- package/dist/mcp/tools/repositories.js +18 -5
- package/dist/mcp/tools/run-access.d.ts +16 -0
- package/dist/mcp/tools/run-access.js +25 -0
- package/dist/mcp/tools/run-transcript-download.d.ts +30 -0
- package/dist/mcp/tools/run-transcript-download.js +129 -0
- package/dist/mcp/tools/run-transcript.d.ts +19 -0
- package/dist/mcp/tools/run-transcript.js +70 -0
- package/dist/mcp/tools/runs.d.ts +0 -6
- package/dist/mcp/tools/runs.js +41 -14
- package/dist/mcp/tools/scheduling.js +3 -1
- package/dist/mcp/tools/secret-broker-compat.d.ts +12 -0
- package/dist/mcp/tools/secret-broker-compat.js +23 -0
- package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -2
- package/dist/mcp/tools/secret-elicitation-form.js +205 -10
- package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
- package/dist/mcp/tools/secret-elicitation-server.js +10 -54
- package/dist/mcp/tools/secret-elicitation.d.ts +38 -3
- package/dist/mcp/tools/secret-elicitation.js +110 -12
- package/dist/mcp/tools/secrets.js +186 -9
- package/dist/mcp/tools/stop-run.d.ts +2 -0
- package/dist/mcp/tools/stop-run.js +82 -0
- package/dist/mcp/tools/subagents.js +2 -2
- package/dist/mcp/tools/tools.d.ts +2 -2
- package/dist/mcp/tools/tools.js +47 -11
- package/dist/mcp/transport/stdio-link-host.d.ts +20 -0
- package/dist/mcp/transport/stdio-link-host.js +67 -0
- package/dist/mcp/transport/streamable-http.d.ts +13 -0
- package/dist/mcp/transport/streamable-http.js +41 -1
- package/dist/native-worker/composition.d.ts +23 -0
- package/dist/native-worker/composition.js +77 -0
- package/dist/native-worker/docker-isolation.d.ts +65 -0
- package/dist/native-worker/docker-isolation.js +183 -0
- package/dist/native-worker/docker-launcher.d.ts +110 -0
- package/dist/native-worker/docker-launcher.js +297 -0
- package/dist/native-worker/gateway-server.d.ts +77 -0
- package/dist/native-worker/gateway-server.js +412 -0
- package/dist/native-worker/gateway.d.ts +70 -0
- package/dist/native-worker/gateway.js +263 -0
- package/dist/native-worker/http-server.d.ts +24 -0
- package/dist/native-worker/http-server.js +113 -0
- package/dist/native-worker/http-transport.d.ts +17 -0
- package/dist/native-worker/http-transport.js +88 -0
- package/dist/native-worker/kubernetes-isolation.d.ts +90 -0
- package/dist/native-worker/kubernetes-isolation.js +218 -0
- package/dist/native-worker/kubernetes-launcher.d.ts +106 -0
- package/dist/native-worker/kubernetes-launcher.js +375 -0
- package/dist/native-worker/launch.d.ts +62 -0
- package/dist/native-worker/launch.js +49 -0
- package/dist/native-worker/ledger.d.ts +125 -0
- package/dist/native-worker/ledger.js +245 -0
- package/dist/native-worker/loopback.d.ts +12 -0
- package/dist/native-worker/loopback.js +44 -0
- package/dist/native-worker/main.d.ts +8 -0
- package/dist/native-worker/main.js +85 -0
- package/dist/native-worker/protocol.d.ts +296 -0
- package/dist/native-worker/protocol.js +246 -0
- package/dist/native-worker/sandbox-executor.d.ts +83 -0
- package/dist/native-worker/sandbox-executor.js +284 -0
- package/dist/native-worker/stderr-redaction.d.ts +77 -0
- package/dist/native-worker/stderr-redaction.js +237 -0
- package/dist/native-worker/stdio.d.ts +29 -0
- package/dist/native-worker/stdio.js +189 -0
- package/dist/native-worker/warm-delivery.d.ts +16 -0
- package/dist/native-worker/warm-delivery.js +33 -0
- package/dist/native-worker/warm-pool-ledger.d.ts +39 -0
- package/dist/native-worker/warm-pool-ledger.js +73 -0
- package/dist/native-worker/warm-pool.d.ts +107 -0
- package/dist/native-worker/warm-pool.js +283 -0
- package/dist/native-worker/worker.d.ts +17 -0
- package/dist/native-worker/worker.js +141 -0
- package/dist/observability/metrics.js +6 -1
- package/dist/providers/auth/authorization-server.d.ts +3 -0
- package/dist/providers/auth/index.js +2 -0
- package/dist/providers/auth/self-hosted.d.ts +14 -2
- package/dist/providers/auth/self-hosted.js +54 -4
- package/dist/providers/chat/fake.d.ts +46 -0
- package/dist/providers/chat/fake.js +39 -0
- package/dist/providers/chat/index.d.ts +4 -0
- package/dist/providers/chat/index.js +8 -0
- package/dist/providers/chat/slack.d.ts +37 -0
- package/dist/providers/chat/slack.js +105 -0
- package/dist/providers/chat/types.d.ts +42 -0
- package/dist/providers/chat/types.js +19 -0
- package/dist/providers/coding-proxy/dependency-cache/eviction.d.ts +29 -0
- package/dist/providers/coding-proxy/dependency-cache/eviction.js +87 -0
- package/dist/providers/coding-proxy/dependency-cache/key.d.ts +33 -0
- package/dist/providers/coding-proxy/dependency-cache/key.js +86 -0
- package/dist/providers/coding-proxy/dependency-cache/model-request-seal.d.ts +18 -0
- package/dist/providers/coding-proxy/dependency-cache/model-request-seal.js +40 -0
- package/dist/providers/coding-proxy/dependency-cache/prisma-store.d.ts +25 -0
- package/dist/providers/coding-proxy/dependency-cache/prisma-store.js +131 -0
- package/dist/providers/coding-proxy/dependency-cache/service.d.ts +70 -0
- package/dist/providers/coding-proxy/dependency-cache/service.js +409 -0
- package/dist/providers/coding-proxy/dependency-cache/store.d.ts +85 -0
- package/dist/providers/coding-proxy/dependency-cache/store.js +95 -0
- package/dist/providers/coding-proxy/hold.d.ts +32 -0
- package/dist/providers/coding-proxy/hold.js +86 -0
- package/dist/providers/coding-proxy/interrupted.d.ts +70 -0
- package/dist/providers/coding-proxy/interrupted.js +104 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +15 -2
- package/dist/providers/coding-proxy/memory-ledger.js +84 -8
- package/dist/providers/coding-proxy/metering.d.ts +16 -0
- package/dist/providers/coding-proxy/metering.js +27 -4
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -2
- package/dist/providers/coding-proxy/prisma-ledger.js +179 -67
- package/dist/providers/coding-proxy/proxy.d.ts +14 -1
- package/dist/providers/coding-proxy/proxy.js +166 -14
- package/dist/providers/coding-proxy/registry/audit.d.ts +53 -10
- package/dist/providers/coding-proxy/registry/audit.js +94 -17
- package/dist/providers/coding-proxy/registry/lockfile-parse-worker.d.ts +36 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse-worker.js +67 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse.d.ts +16 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse.js +110 -0
- package/dist/providers/coding-proxy/registry/plan.d.ts +9 -0
- package/dist/providers/coding-proxy/registry/plan.js +201 -48
- package/dist/providers/coding-proxy/registry/prisma-store.d.ts +11 -5
- package/dist/providers/coding-proxy/registry/prisma-store.js +120 -17
- package/dist/providers/coding-proxy/registry/service.d.ts +97 -16
- package/dist/providers/coding-proxy/registry/service.js +579 -112
- package/dist/providers/coding-proxy/registry/store.d.ts +84 -9
- package/dist/providers/coding-proxy/registry/store.js +54 -1
- package/dist/providers/coding-proxy/runtime.d.ts +4 -0
- package/dist/providers/coding-proxy/runtime.js +78 -16
- package/dist/providers/coding-proxy/server.d.ts +6 -1
- package/dist/providers/coding-proxy/server.js +45 -1
- package/dist/providers/coding-proxy/types.d.ts +65 -1
- package/dist/providers/datastore/types.d.ts +5 -0
- package/dist/providers/engine/types.d.ts +36 -2
- package/dist/providers/engine/types.js +39 -0
- package/dist/providers/executor/composition.d.ts +31 -1
- package/dist/providers/executor/composition.js +81 -8
- package/dist/providers/executor/container.d.ts +385 -9
- package/dist/providers/executor/container.js +1234 -99
- package/dist/providers/executor/dbos-status.d.ts +31 -0
- package/dist/providers/executor/dbos-status.js +64 -0
- package/dist/providers/executor/dbos.d.ts +91 -0
- package/dist/providers/executor/dbos.js +319 -26
- package/dist/providers/executor/deferred.d.ts +44 -0
- package/dist/providers/executor/deferred.js +100 -0
- package/dist/providers/executor/in-process.d.ts +9 -1
- package/dist/providers/executor/in-process.js +14 -4
- package/dist/providers/executor/linked-issue-reader.d.ts +16 -0
- package/dist/providers/executor/linked-issue-reader.js +30 -0
- package/dist/providers/executor/routing.d.ts +39 -10
- package/dist/providers/executor/routing.js +77 -32
- package/dist/providers/executor/types.d.ts +25 -0
- package/dist/providers/index.d.ts +2 -1
- package/dist/providers/issue-tracker/types.d.ts +17 -0
- package/dist/providers/issue-tracker/types.js +39 -1
- package/dist/providers/jobs/claude-tool-setup.d.ts +4 -0
- package/dist/providers/jobs/claude-tool-setup.js +5 -2
- package/dist/providers/jobs/docker-isolation.d.ts +8 -0
- package/dist/providers/jobs/docker-isolation.js +17 -0
- package/dist/providers/jobs/docker.d.ts +1 -0
- package/dist/providers/jobs/docker.js +29 -4
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +23 -2
- package/dist/providers/jobs/fake-kubernetes-api.js +45 -1
- package/dist/providers/jobs/kubernetes-api.d.ts +25 -1
- package/dist/providers/jobs/kubernetes-api.js +17 -0
- package/dist/providers/jobs/kubernetes-client.d.ts +10 -1
- package/dist/providers/jobs/kubernetes-client.js +61 -3
- package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +6 -1
- package/dist/providers/jobs/kubernetes-dry-run-fixture.js +6 -3
- package/dist/providers/jobs/kubernetes-isolation.d.ts +5 -1
- package/dist/providers/jobs/kubernetes-isolation.js +23 -1
- package/dist/providers/jobs/kubernetes-platform.d.ts +4 -1
- package/dist/providers/jobs/kubernetes-platform.js +38 -1
- package/dist/providers/jobs/kubernetes-preflight.d.ts +2 -1
- package/dist/providers/jobs/kubernetes-preflight.js +4 -2
- package/dist/providers/jobs/kubernetes.d.ts +42 -2
- package/dist/providers/jobs/kubernetes.js +178 -19
- package/dist/providers/jobs/metadata-probes.d.ts +11 -0
- package/dist/providers/jobs/metadata-probes.js +13 -0
- package/dist/providers/jobs/types.d.ts +42 -0
- package/dist/providers/jobs/types.js +13 -1
- package/dist/providers/llm/anthropic.js +5 -1
- package/dist/providers/llm/bedrock.d.ts +0 -12
- package/dist/providers/llm/bedrock.js +4 -0
- package/dist/providers/llm/claude-messages.d.ts +3 -1
- package/dist/providers/llm/claude-messages.js +4 -1
- package/dist/providers/llm/claude-provider.d.ts +2 -2
- package/dist/providers/llm/claude-provider.js +2 -2
- package/dist/providers/llm/openai.d.ts +2 -2
- package/dist/providers/llm/openai.js +6 -2
- package/dist/providers/llm/routing.d.ts +2 -2
- package/dist/providers/llm/routing.js +2 -2
- package/dist/providers/llm/types.d.ts +12 -2
- package/dist/providers/review-host/github-events.d.ts +9 -1
- package/dist/providers/review-host/github-events.js +34 -12
- package/dist/providers/review-host/github.d.ts +39 -2
- package/dist/providers/review-host/github.js +274 -29
- package/dist/providers/review-host/local.d.ts +8 -4
- package/dist/providers/review-host/local.js +49 -31
- package/dist/providers/review-host/patch-pages.d.ts +41 -0
- package/dist/providers/review-host/patch-pages.js +176 -0
- package/dist/providers/review-host/review-format.d.ts +19 -1
- package/dist/providers/review-host/review-format.js +38 -7
- package/dist/providers/review-host/types.d.ts +157 -2
- package/dist/providers/review-host/types.js +8 -0
- package/dist/providers/storage/gcs.d.ts +63 -0
- package/dist/providers/storage/gcs.js +69 -0
- package/dist/providers/storage/index.d.ts +15 -0
- package/dist/providers/storage/index.js +14 -0
- package/dist/providers/storage/local.d.ts +24 -0
- package/dist/providers/storage/local.js +92 -0
- package/dist/providers/storage/meter.d.ts +14 -0
- package/dist/providers/storage/meter.js +34 -0
- package/dist/providers/storage/s3.d.ts +41 -0
- package/dist/providers/storage/s3.js +107 -0
- package/dist/providers/storage/types.d.ts +37 -3
- package/dist/providers/storage/types.js +21 -4
- package/dist/providers/vcs/git.d.ts +33 -2
- package/dist/providers/vcs/git.js +324 -22
- package/dist/providers/vcs/github-remote.d.ts +26 -3
- package/dist/providers/vcs/github-remote.js +124 -14
- package/dist/providers/vcs/github.d.ts +246 -12
- package/dist/providers/vcs/github.js +521 -61
- package/dist/providers/vcs/index.js +8 -1
- package/dist/providers/vcs/pr-description.d.ts +127 -0
- package/dist/providers/vcs/pr-description.js +270 -0
- package/dist/providers/vcs/remote.d.ts +33 -1
- package/dist/providers/vcs/routing.d.ts +4 -2
- package/dist/providers/vcs/routing.js +6 -0
- package/dist/providers/vcs/types.d.ts +80 -3
- package/dist/quickstart/coding-seed.d.ts +21 -3
- package/dist/quickstart/coding-seed.js +283 -3
- package/dist/quickstart/images.d.ts +2 -0
- package/dist/quickstart/images.js +7 -1
- package/dist/quickstart/reviewer-prompt.d.ts +1 -1
- package/dist/quickstart/reviewer-prompt.js +6 -6
- package/dist/quickstart-images.json +1 -1
- package/dist/sandbox/brokered-fetch.d.ts +23 -0
- package/dist/sandbox/brokered-fetch.js +37 -0
- package/dist/sandbox/generated/zod.bundle.js +62 -1
- package/dist/sandbox/generated/zod3.bundle.js +5 -0
- package/dist/sandbox/host-functions.d.ts +35 -0
- package/dist/sandbox/host-functions.js +150 -91
- package/dist/sandbox/prelude.js +7 -1
- package/dist/sandbox/run-in-sandbox.d.ts +19 -0
- package/dist/sandbox/run-in-sandbox.js +28 -10
- package/dist/sandbox/safe-fetch.d.ts +2 -0
- package/dist/sandbox/safe-fetch.js +3 -1
- package/dist/sandbox/secret-broker-sigv4.d.ts +2 -0
- package/dist/sandbox/secret-broker-sigv4.js +49 -0
- package/dist/sandbox/secret-broker.d.ts +34 -0
- package/dist/sandbox/secret-broker.js +161 -0
- package/dist/sandbox/tool-capabilities.d.ts +10 -30
- package/dist/sandbox/user-tool.d.ts +14 -0
- package/dist/sandbox/user-tool.js +32 -0
- package/dist/sandbox/zod-params.d.ts +37 -5
- package/dist/sandbox/zod-params.js +181 -26
- package/dist/serve.js +25 -0
- package/dist/viewer/api-schema.d.ts +372 -2454
- package/dist/viewer/api-schema.js +29 -0
- package/dist/viewer/build-schemas.js +10 -3
- package/dist/viewer/event-bus.d.ts +6 -0
- package/dist/viewer/event-bus.js +16 -7
- package/dist/viewer/graph.d.ts +5 -2
- package/dist/viewer/graph.js +7 -2
- package/dist/viewer/http.d.ts +0 -1
- package/dist/viewer/http.js +2 -2
- package/dist/viewer/infra.js +25 -2
- package/dist/viewer/limits.d.ts +4 -0
- package/dist/viewer/limits.js +4 -0
- package/dist/viewer/openapi.d.ts +15 -0
- package/dist/viewer/openapi.js +170 -0
- package/dist/wardby-bin.js +10 -0
- package/docs/README.md +7 -0
- package/docs/agent-recipes.md +114 -27
- package/docs/architecture-runtime.md +16 -1
- package/docs/code-review-agents.md +689 -45
- package/docs/coding-agent-setup.md +602 -12
- package/docs/coding-packages.md +1037 -92
- package/docs/coding-services.md +30 -13
- package/docs/coding-worker-byo-images.md +218 -6
- package/docs/coding-worker-isolation.md +173 -44
- package/docs/getting-started-gke.md +332 -129
- package/docs/getting-started-identity-provider.md +31 -11
- package/docs/getting-started.md +14 -4
- package/docs/jira-agents.md +22 -9
- package/docs/knowledge/blob-not-found-semantics.md +41 -0
- package/docs/knowledge/bounded-file-descriptor.md +52 -0
- package/docs/knowledge/delegation-admission-slots.md +52 -0
- package/docs/knowledge/http-dispatcher-bootstrap.md +61 -0
- package/docs/knowledge/import-rename-target.md +52 -0
- package/docs/knowledge/index.md +57 -0
- package/docs/knowledge/log.md +9 -0
- package/docs/knowledge/mcp-cancelled-task-precedence.md +41 -0
- package/docs/knowledge/mcp-http-prompt-discovery.md +41 -0
- package/docs/knowledge/mcp-schema-module-boundary.md +41 -0
- package/docs/knowledge/nullable-tool-uniqueness.md +52 -0
- package/docs/knowledge/overview-cli.md +74 -0
- package/docs/knowledge/overview-coding-proxy.md +72 -0
- package/docs/knowledge/overview-coding.md +72 -0
- package/docs/knowledge/overview-config.md +60 -0
- package/docs/knowledge/overview-core.md +72 -0
- package/docs/knowledge/overview-deploy.md +83 -0
- package/docs/knowledge/overview-mcp.md +61 -0
- package/docs/knowledge/overview-prisma.md +72 -0
- package/docs/knowledge/overview-providers.md +89 -0
- package/docs/knowledge/overview-sandbox.md +83 -0
- package/docs/knowledge/overview-surfaces.md +83 -0
- package/docs/knowledge/private-datastore-shared-boundary.md +54 -0
- package/docs/knowledge/proxy-settlement-projections.md +41 -0
- package/docs/knowledge/run-pricing-first-writer.md +43 -0
- package/docs/knowledge/schedule-claim-transaction.md +41 -0
- package/docs/knowledge/secret-entry-replica-contract.md +52 -0
- package/docs/knowledge/terminal-run-first-writer.md +41 -0
- package/docs/knowledge/transactional-agent-authorization.md +52 -0
- package/docs/knowledge/viewer-notify-write-isolation.md +30 -0
- package/docs/knowledge/warm-input-publication.md +30 -0
- package/docs/knowledge/workspace-staging-failure.md +54 -0
- package/docs/knowledge.md +54 -14
- package/docs/native-sandbox.md +731 -0
- package/docs/observability.md +4 -0
- package/docs/release-verification.md +9 -0
- package/docs/security-deployment.md +146 -14
- package/docs/slack-notifications.md +268 -0
- package/docs/tool-secrets.md +284 -0
- package/docs/viewer-api.md +46 -5
- package/docs/viewer-api.openapi.yml +1404 -0
- package/help/admin-viewer.md +29 -3
- package/help/agent-recipes.md +27 -0
- package/help/architecture-agent.md +11 -6
- package/help/brokered-secrets.md +79 -0
- package/help/build-claude-code-image.md +131 -0
- package/help/build-worker-image.md +6 -7
- package/help/builder-agent.md +19 -6
- package/help/code-review-agents.md +243 -10
- package/help/coding-packages.md +156 -6
- package/help/cost-attribution.md +9 -5
- package/help/creating-agents.md +14 -1
- package/help/dependency-cache.md +143 -0
- package/help/deploy-gke.md +23 -9
- package/help/deployment-targets.md +25 -14
- package/help/errors/budget-exhausted.md +187 -0
- package/help/errors/budget-group-exhausted.md +5 -1
- package/help/errors/coding-provider-not-configured.md +2 -2
- package/help/errors/coding-stream-quota-exceeded.md +33 -0
- package/help/errors/coding-workspace-disk-exceeds-limit.md +39 -0
- package/help/errors/continuation-closed.md +9 -12
- package/help/errors/database-auth-invalid.md +28 -0
- package/help/errors/delegation-conflict.md +24 -0
- package/help/errors/file-list-truncated.md +45 -0
- package/help/errors/full-read-required.md +49 -0
- package/help/errors/github-account-not-allowed.md +29 -0
- package/help/errors/graph-incomplete.md +43 -0
- package/help/errors/graph-limit.md +43 -0
- package/help/errors/low-power-disabled.md +29 -0
- package/help/errors/low-power-scale-forbidden.md +35 -0
- package/help/errors/low-power-wake-timeout.md +30 -0
- package/help/errors/merge-conflict.md +49 -0
- package/help/errors/mobile-disabled.md +31 -0
- package/help/errors/native-sandbox-capacity.md +22 -0
- package/help/errors/native-sandbox-deadline-exceeded.md +19 -0
- package/help/errors/native-sandbox-docker-failed.md +20 -0
- package/help/errors/native-sandbox-gateway-error.md +20 -0
- package/help/errors/native-sandbox-gateway-unavailable.md +21 -0
- package/help/errors/native-sandbox-image-not-pinned.md +19 -0
- package/help/errors/native-sandbox-isolation-mismatch.md +20 -0
- package/help/errors/native-sandbox-launch-abandoned.md +21 -0
- package/help/errors/native-sandbox-network-unenforced.md +22 -0
- package/help/errors/native-sandbox-requires-catalog.md +31 -0
- package/help/errors/native-sandbox-unavailable.md +19 -0
- package/help/errors/native-sandbox-warm-delivery-failed.md +21 -0
- package/help/errors/native-sandbox-worker-exited.md +21 -0
- package/help/errors/native-sandbox-worker-lost.md +20 -0
- package/help/errors/native-sandbox-worker-unready.md +22 -0
- package/help/errors/package-not-allowed-pending.md +52 -0
- package/help/errors/package-not-allowed.md +51 -0
- package/help/errors/package-refusals.md +43 -0
- package/help/errors/patch-cursor-malformed.md +31 -0
- package/help/errors/run-lost.md +39 -0
- package/help/errors/run-transcript-download.md +44 -0
- package/help/errors/secret-broker-body-invalid.md +26 -0
- package/help/errors/secret-broker-changed.md +20 -0
- package/help/errors/secret-broker-config-invalid.md +30 -0
- package/help/errors/secret-broker-conflict.md +27 -0
- package/help/errors/secret-broker-destination-denied.md +28 -0
- package/help/errors/secret-broker-value-invalid.md +28 -0
- package/help/errors/secret-brokered.md +24 -0
- package/help/errors/secret-in-value.md +69 -0
- package/help/errors/secret-not-brokered.md +25 -0
- package/help/errors/slack-auth-failed.md +48 -0
- package/help/errors/slack-channel-unreachable.md +39 -0
- package/help/errors/slack-not-configured.md +33 -0
- package/help/errors/target-merge.md +40 -0
- package/help/fix-merge-conflicts.md +73 -0
- package/help/getting-started.md +4 -5
- package/help/github-app-setup.md +132 -0
- package/help/github.md +40 -1
- package/help/identity-and-access.md +7 -1
- package/help/jira.md +23 -6
- package/help/knowledge.md +16 -7
- package/help/local-repositories.md +3 -4
- package/help/low-power-mode.md +131 -0
- package/help/merge-order-check.md +122 -0
- package/help/mobile-app.md +54 -0
- package/help/native-capabilities.md +29 -1
- package/help/native-sandbox.md +150 -0
- package/help/observability.md +8 -0
- package/help/operating-agents.md +5 -0
- package/help/package-audit-mode.md +91 -0
- package/help/related-pull-requests.md +80 -16
- package/help/repo-instructions-and-skills.md +91 -0
- package/help/resume-runs-locally.md +131 -0
- package/help/review-fix-rounds.md +43 -1
- package/help/sharing-agents.md +59 -0
- package/help/slack-notifications.md +76 -0
- package/help/status-comments.md +31 -0
- package/help/stop-run.md +58 -0
- package/help/troubleshooting/budgets.md +28 -0
- package/help/troubleshooting/coding-workers.md +99 -7
- package/package.json +27 -13
- package/prisma/migrations/20261009000003_native_execution_mode/migration.sql +12 -0
- package/prisma/migrations/20261009000004_native_gateway_ledger/migration.sql +65 -0
- package/prisma/migrations/20261009000005_native_gateway_call_child_agent/migration.sql +5 -0
- package/prisma/migrations/20261009000006_run_deferred_start_stop/migration.sql +14 -0
- package/prisma/migrations/20261009000007_native_gateway_network_ready/migration.sql +5 -0
- package/prisma/migrations/20261010000001_workflow_notifications/migration.sql +99 -0
- package/prisma/migrations/20261011000001_native_gateway_session_status_index/migration.sql +2 -0
- package/prisma/migrations/20261012000001_native_warm_worker/migration.sql +32 -0
- package/prisma/migrations/20261013000001_coding_run_merge_order/migration.sql +2 -0
- package/prisma/migrations/20261013000001_secret_broker/migration.sql +17 -0
- package/prisma/migrations/20261013000002_deferred_review_request/migration.sql +4 -0
- package/prisma/migrations/20261014000000_repo_skills/migration.sql +15 -0
- package/prisma/migrations/20261015000001_coding_run_merge_order_index/migration.sql +2 -0
- package/prisma/migrations/20261015000002_no_change_rereview/migration.sql +2 -0
- package/prisma/migrations/20261016000000_registry_approved_accepted_advisories/migration.sql +3 -0
- package/prisma/migrations/20261016000001_mark_ready_when_passing/migration.sql +3 -0
- package/prisma/migrations/20261017000000_debug_trace_max_mb/migration.sql +4 -0
- package/prisma/migrations/20261018000000_dependency_cache/migration.sql +53 -0
- package/prisma/migrations/20261019000000_claude_max_output_tokens/migration.sql +5 -0
- package/prisma/migrations/20261021000000_pr_description_hash/migration.sql +4 -0
- package/prisma/migrations/20261022000000_dependency_snapshot_validation_metadata/migration.sql +4 -0
- package/prisma/migrations/20261023000000_package_audit_mode/migration.sql +27 -0
- package/prisma/migrations/20261024000000_budget_events/migration.sql +26 -0
- package/prisma/migrations/20261025000000_cache_aware_holds/migration.sql +9 -0
- package/prisma/migrations/20261026000000_budget_overrun/migration.sql +4 -0
- package/prisma/migrations/20261027000000_coding_run_request/migration.sql +1 -0
- package/prisma/migrations/20261028000000_native_gateway_review_reads/migration.sql +6 -0
- package/prisma/migrations/20261029000000_lead_survives_deploy/migration.sql +6 -0
- package/prisma/migrations/20261030000000_local_review_covered_sha/migration.sql +2 -0
- package/prisma/migrations/20261031000000_coding_run_budget_limit/migration.sql +9 -0
- package/prisma/migrations/20261101000000_run_transcripts/migration.sql +22 -0
- package/prisma/schema.prisma +631 -146
- package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
|
@@ -66,6 +66,18 @@ function isOrderedBefore(run, other) {
|
|
|
66
66
|
* returned with a null cap. One query at the widest configured window
|
|
67
67
|
* (month contains week contains day), bucketed in JS, rather than a
|
|
68
68
|
* separate DB round trip per period.
|
|
69
|
+
*
|
|
70
|
+
* A delegated run tree is held once, at its root. A sub-run whose tree root
|
|
71
|
+
* is a counted run of this group with a live, counted hold spends inside the
|
|
72
|
+
* root's hold, so it holds nothing (its cost still counts as spent), and the
|
|
73
|
+
* root holds its reservation minus the cost of every run in its tree, or the
|
|
74
|
+
* unspent holds of its tree's live runs when that is more (a coding run's
|
|
75
|
+
* grant can grow past the root's budget through overrun top-ups). A sub-run
|
|
76
|
+
* whose root is in another group, has finished, or whose hold is left out
|
|
77
|
+
* here (excludeReservationRunIds, holdsBefore) holds its own reservation. So
|
|
78
|
+
* does a sub-run in a period its root did not start in (a root that started
|
|
79
|
+
* yesterday, a child today: today's daily cap still holds the child's own
|
|
80
|
+
* reservation, since the root's hold falls in yesterday's bucket).
|
|
69
81
|
*/
|
|
70
82
|
export async function computeGroupSpend(db, group, members, now = new Date(), options = {}) {
|
|
71
83
|
const caps = [
|
|
@@ -97,33 +109,142 @@ export async function computeGroupSpend(db, group, members, now = new Date(), op
|
|
|
97
109
|
costUsd: true,
|
|
98
110
|
startedAt: true,
|
|
99
111
|
heartbeatAt: true,
|
|
112
|
+
parentRunId: true,
|
|
100
113
|
codingRun: { select: { budgetReservedUsd: true, timeoutSec: true } },
|
|
101
114
|
},
|
|
102
115
|
});
|
|
103
116
|
const counted = runs.filter((r) => !dropped.has(r.id));
|
|
117
|
+
const countedById = new Map(counted.map((r) => [r.id, r]));
|
|
118
|
+
const holds = (r) => !excluded.has(r.id) &&
|
|
119
|
+
(options.holdsBefore === undefined || isOrderedBefore(r, options.holdsBefore)) &&
|
|
120
|
+
isHoldLive(r, now, queueTimeoutSec);
|
|
121
|
+
// A coding run holds exactly what dispatch reserved. A native run (or a
|
|
122
|
+
// coding run whose CodingRun row is missing) holds its agent's per-run
|
|
123
|
+
// budget: never less than what it can actually spend.
|
|
124
|
+
const reservationOf = (r) => r.codingRun != null ? Number(r.codingRun.budgetReservedUsd) : (memberBudgets.get(r.agentId) ?? 0);
|
|
125
|
+
// A run inside the tree of a counted, holding root in this group spends
|
|
126
|
+
// inside that root's hold, so it holds nothing of its own.
|
|
127
|
+
const rootOf = await resolveRootRunIds(db, counted);
|
|
128
|
+
const heldRoots = new Set();
|
|
129
|
+
for (const r of counted) {
|
|
130
|
+
const rootId = rootOf.get(r.id);
|
|
131
|
+
if (rootId === undefined || rootId === r.id)
|
|
132
|
+
continue;
|
|
133
|
+
const root = countedById.get(rootId);
|
|
134
|
+
if (root && holds(root))
|
|
135
|
+
heldRoots.add(rootId);
|
|
136
|
+
}
|
|
137
|
+
// Such a root holds its reservation minus the cost of its whole tree, every
|
|
138
|
+
// run in it included (also runs in other groups: they spend the tree too).
|
|
139
|
+
// The runs below it may hold more than that: a coding run's grant takes
|
|
140
|
+
// top-ups from the root agent's overrun, and dispatch sized it beside its live
|
|
141
|
+
// siblings' holds. So the root holds at least the unspent holds of every live run below
|
|
142
|
+
// it, each held as in siblingHoldsUsd.
|
|
143
|
+
const treeHoldByRoot = new Map();
|
|
144
|
+
for (const rootId of heldRoots) {
|
|
145
|
+
const treeRunIds = await collectTreeRunIds(db, rootId);
|
|
146
|
+
const treeRuns = await db.run.findMany({
|
|
147
|
+
where: { id: { in: treeRunIds } },
|
|
148
|
+
select: {
|
|
149
|
+
id: true,
|
|
150
|
+
status: true,
|
|
151
|
+
costUsd: true,
|
|
152
|
+
startedAt: true,
|
|
153
|
+
heartbeatAt: true,
|
|
154
|
+
agent: { select: { budgetUsd: true } },
|
|
155
|
+
codingRun: { select: { budgetReservedUsd: true, timeoutSec: true } },
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
const treeCostUsd = treeRuns.reduce((sum, t) => sum + Number(t.costUsd), 0);
|
|
159
|
+
const childHoldsUsd = treeRuns
|
|
160
|
+
.filter((t) => t.id !== rootId && !excluded.has(t.id) && isHoldLive(t, now, queueTimeoutSec))
|
|
161
|
+
.reduce((sum, t) => {
|
|
162
|
+
const reservation = t.codingRun ? Number(t.codingRun.budgetReservedUsd) : Number(t.agent.budgetUsd);
|
|
163
|
+
return sum + Math.max(0, reservation - Number(t.costUsd));
|
|
164
|
+
}, 0);
|
|
165
|
+
const root = countedById.get(rootId);
|
|
166
|
+
treeHoldByRoot.set(rootId, Math.max(reservationOf(root) - treeCostUsd, childHoldsUsd));
|
|
167
|
+
}
|
|
104
168
|
const accounted = counted.map((r) => {
|
|
105
169
|
const costUsd = Number(r.costUsd);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// per-run budget: never less than what it can actually spend.
|
|
114
|
-
const reservation = r.codingRun != null ? Number(r.codingRun.budgetReservedUsd) : (memberBudgets.get(r.agentId) ?? 0);
|
|
115
|
-
reservedUsd = Math.max(0, reservation - costUsd);
|
|
170
|
+
const rootId = rootOf.get(r.id);
|
|
171
|
+
let ownReservedUsd = 0;
|
|
172
|
+
if (heldRoots.has(r.id)) {
|
|
173
|
+
ownReservedUsd = Math.max(0, treeHoldByRoot.get(r.id) ?? 0);
|
|
174
|
+
}
|
|
175
|
+
else if (holds(r)) {
|
|
176
|
+
ownReservedUsd = Math.max(0, reservationOf(r) - costUsd);
|
|
116
177
|
}
|
|
117
|
-
|
|
178
|
+
// Set when the run spends inside its root's hold: the root's startedAt.
|
|
179
|
+
const heldRootStartedAt = rootId !== undefined && rootId !== r.id && heldRoots.has(rootId) ? countedById.get(rootId).startedAt : null;
|
|
180
|
+
return { startedAt: r.startedAt, costUsd, ownReservedUsd, heldRootStartedAt };
|
|
118
181
|
});
|
|
119
182
|
return configured.map(({ period, capUsd }) => {
|
|
120
183
|
const start = periodStart(period, now);
|
|
121
|
-
|
|
184
|
+
// A run inside a held tree holds nothing in a period only when its root's
|
|
185
|
+
// hold is counted in that period too (the root started in it); otherwise
|
|
186
|
+
// the period would see the run's spend but no hold for it.
|
|
187
|
+
const inPeriod = accounted
|
|
188
|
+
.filter((r) => r.startedAt >= start)
|
|
189
|
+
.map((r) => ({
|
|
190
|
+
costUsd: r.costUsd,
|
|
191
|
+
reservedUsd: r.heldRootStartedAt !== null && r.heldRootStartedAt >= start ? 0 : r.ownReservedUsd,
|
|
192
|
+
}));
|
|
122
193
|
const spentUsd = inPeriod.reduce((sum, r) => sum + r.costUsd, 0);
|
|
123
194
|
const reservedUsd = inPeriod.reduce((sum, r) => sum + r.reservedUsd, 0);
|
|
124
|
-
|
|
195
|
+
const heldRuns = inPeriod.filter((r) => r.reservedUsd > 0).length;
|
|
196
|
+
return {
|
|
197
|
+
period,
|
|
198
|
+
capUsd,
|
|
199
|
+
spentUsd,
|
|
200
|
+
reservedUsd,
|
|
201
|
+
remainingUsd: Math.max(0, capUsd - spentUsd - reservedUsd),
|
|
202
|
+
heldRuns,
|
|
203
|
+
};
|
|
125
204
|
});
|
|
126
205
|
}
|
|
206
|
+
/** Deepest parentRunId chain resolveRootRunIds follows: a guard against a cycle. */
|
|
207
|
+
const MAX_TREE_DEPTH = 32;
|
|
208
|
+
/**
|
|
209
|
+
* Each run's tree root (the ancestor with parentRunId null), walking
|
|
210
|
+
* parentRunId upward in one batched query per level. A run whose chain cannot
|
|
211
|
+
* be resolved (a missing ancestor, or deeper than MAX_TREE_DEPTH) is left out.
|
|
212
|
+
*/
|
|
213
|
+
async function resolveRootRunIds(db, runs) {
|
|
214
|
+
const parentOf = new Map(runs.map((r) => [r.id, r.parentRunId ?? null]));
|
|
215
|
+
const missing = new Set();
|
|
216
|
+
for (let level = 0; level < MAX_TREE_DEPTH; level++) {
|
|
217
|
+
const unresolved = new Set();
|
|
218
|
+
for (const parentId of parentOf.values()) {
|
|
219
|
+
if (parentId !== null && !parentOf.has(parentId) && !missing.has(parentId))
|
|
220
|
+
unresolved.add(parentId);
|
|
221
|
+
}
|
|
222
|
+
if (unresolved.size === 0)
|
|
223
|
+
break;
|
|
224
|
+
const parents = await db.run.findMany({
|
|
225
|
+
where: { id: { in: [...unresolved] } },
|
|
226
|
+
select: { id: true, parentRunId: true, agentId: true },
|
|
227
|
+
});
|
|
228
|
+
for (const p of parents)
|
|
229
|
+
parentOf.set(p.id, p.parentRunId ?? null);
|
|
230
|
+
for (const id of unresolved)
|
|
231
|
+
if (!parentOf.has(id))
|
|
232
|
+
missing.add(id);
|
|
233
|
+
}
|
|
234
|
+
const rootOf = new Map();
|
|
235
|
+
for (const r of runs) {
|
|
236
|
+
let id = r.id;
|
|
237
|
+
let parentId = parentOf.get(id);
|
|
238
|
+
for (let depth = 0; parentId != null && depth < MAX_TREE_DEPTH; depth++) {
|
|
239
|
+
id = parentId;
|
|
240
|
+
parentId = parentOf.get(id);
|
|
241
|
+
}
|
|
242
|
+
// parentId undefined: a missing ancestor; non-null: too deep or a cycle.
|
|
243
|
+
if (parentId === null)
|
|
244
|
+
rootOf.set(r.id, id);
|
|
245
|
+
}
|
|
246
|
+
return rootOf;
|
|
247
|
+
}
|
|
127
248
|
/** Walks parentRunId upward from `runId` to the tree's root (parentRunId null). */
|
|
128
249
|
async function findRootRun(db, runId) {
|
|
129
250
|
let current = await db.run.findUniqueOrThrow({
|
|
@@ -204,7 +325,13 @@ function siblingHoldsUsd(rows, parentRunId, now, self) {
|
|
|
204
325
|
}
|
|
205
326
|
return total;
|
|
206
327
|
}
|
|
207
|
-
|
|
328
|
+
/**
|
|
329
|
+
* With `withOverrun` (a coding run's top-up, codingTopUpRoom), the tree's
|
|
330
|
+
* ceiling is the root agent's budgetUsd raised by its own
|
|
331
|
+
* allowedOverrunPercent, still capped by the root's budget group; without it
|
|
332
|
+
* (dispatch and native callers), the root's budgetUsd: what the tree holds.
|
|
333
|
+
*/
|
|
334
|
+
async function runTreeSpend(db, parentRunId, now, self, withOverrun = false) {
|
|
208
335
|
const root = await findRootRun(db, parentRunId);
|
|
209
336
|
const treeRunIds = await collectTreeRunIds(db, root.id);
|
|
210
337
|
const rows = await db.run.findMany({
|
|
@@ -224,15 +351,12 @@ async function runTreeSpend(db, parentRunId, now, self) {
|
|
|
224
351
|
const heldUsd = siblingHoldsUsd(rows, parentRunId, now, self);
|
|
225
352
|
const rootAgent = await db.agent.findUniqueOrThrow({
|
|
226
353
|
where: { id: root.agentId },
|
|
227
|
-
select: { id: true, budgetGroupId: true, budgetUsd: true },
|
|
354
|
+
select: { id: true, budgetGroupId: true, budgetUsd: true, allowedOverrunPercent: true },
|
|
228
355
|
});
|
|
229
356
|
const rootOrder = { id: root.id, startedAt: root.startedAt };
|
|
230
357
|
// Root has no parentRunId of its own, so this terminates in one level —
|
|
231
358
|
// no unbounded recursion regardless of how deep `parentRunId` itself was.
|
|
232
|
-
const rootCeiling = await groupCappedBudget(db, rootAgent, now, {
|
|
233
|
-
excludeRunIds: treeRunIds,
|
|
234
|
-
holdsBefore: rootOrder,
|
|
235
|
-
});
|
|
359
|
+
const rootCeiling = await groupCappedBudget(db, rootAgent, now, { excludeRunIds: treeRunIds, holdsBefore: rootOrder }, undefined, withOverrun ? rootAgent.allowedOverrunPercent : undefined);
|
|
236
360
|
const capUsd = rootCeiling.effectiveBudgetUsd;
|
|
237
361
|
return {
|
|
238
362
|
rootRunId: root.id,
|
|
@@ -263,7 +387,7 @@ async function runTreeSpend(db, parentRunId, now, self) {
|
|
|
263
387
|
* the tree's included.
|
|
264
388
|
*/
|
|
265
389
|
export async function effectiveBudgetForRun(db, agent, now = new Date(), parentRunId, options = {}) {
|
|
266
|
-
const self = options
|
|
390
|
+
const { self } = options;
|
|
267
391
|
const ownSpend = { excludeReservationRunIds: self ? [self.id] : [], holdsBefore: self };
|
|
268
392
|
if (!parentRunId)
|
|
269
393
|
return groupCappedBudget(db, agent, now, ownSpend);
|
|
@@ -272,10 +396,21 @@ export async function effectiveBudgetForRun(db, agent, now = new Date(), parentR
|
|
|
272
396
|
const spend = sharesRootGroup
|
|
273
397
|
? { excludeReservationRunIds: [...tree.treeRunIds, ...(self ? [self.id] : [])], holdsBefore: tree.root }
|
|
274
398
|
: ownSpend;
|
|
275
|
-
return groupCappedBudget(db, agent, now, spend, {
|
|
399
|
+
return groupCappedBudget(db, agent, now, spend, {
|
|
400
|
+
value: tree.remainingUsd,
|
|
401
|
+
reason: "run-tree",
|
|
402
|
+
detail: {
|
|
403
|
+
capUsd: tree.capUsd,
|
|
404
|
+
spentUsd: tree.spentUsd,
|
|
405
|
+
heldUsd: tree.capUsd - tree.spentUsd - tree.remainingUsd,
|
|
406
|
+
heldRuns: 0,
|
|
407
|
+
},
|
|
408
|
+
});
|
|
276
409
|
}
|
|
277
|
-
async function groupCappedBudget(db, agent, now, spendOptions, extra) {
|
|
410
|
+
async function groupCappedBudget(db, agent, now, spendOptions, extra, overrunPercent) {
|
|
278
411
|
const ownBudgetUsd = Number(agent.budgetUsd);
|
|
412
|
+
// The ceiling the candidates tighten: own raised by the overrun, when one is given (a run tree's raised cap).
|
|
413
|
+
const ownLimitUsd = overrunPercent === undefined ? ownBudgetUsd : (ownBudgetUsd * (100 + overrunPercent)) / 100;
|
|
279
414
|
const candidates = [];
|
|
280
415
|
if (agent.budgetGroupId) {
|
|
281
416
|
const group = await db.budgetGroup.findUnique({
|
|
@@ -286,7 +421,11 @@ async function groupCappedBudget(db, agent, now, spendOptions, extra) {
|
|
|
286
421
|
const spend = await computeGroupSpend(db, group, group.agents, now, spendOptions);
|
|
287
422
|
const warnThresholdRatio = Number(group.warnThresholdRatio);
|
|
288
423
|
for (const s of spend) {
|
|
289
|
-
candidates.push({
|
|
424
|
+
candidates.push({
|
|
425
|
+
value: s.remainingUsd,
|
|
426
|
+
reason: s.period,
|
|
427
|
+
detail: { capUsd: s.capUsd, spentUsd: s.spentUsd, heldUsd: s.reservedUsd, heldRuns: s.heldRuns },
|
|
428
|
+
});
|
|
290
429
|
if (s.spentUsd >= s.capUsd * warnThresholdRatio) {
|
|
291
430
|
budgetGroupLog.warn({ groupId: group.id, groupName: group.name, period: s.period, capUsd: s.capUsd, spentUsd: s.spentUsd }, `budget group "${group.name}"'s ${s.period} spend ($${s.spentUsd.toFixed(4)}) has reached ` +
|
|
292
431
|
`${(warnThresholdRatio * 100).toFixed(0)}% of its $${s.capUsd.toFixed(4)} cap`);
|
|
@@ -297,10 +436,80 @@ async function groupCappedBudget(db, agent, now, spendOptions, extra) {
|
|
|
297
436
|
if (extra)
|
|
298
437
|
candidates.push(extra);
|
|
299
438
|
if (candidates.length === 0)
|
|
300
|
-
return { effectiveBudgetUsd:
|
|
301
|
-
const
|
|
302
|
-
const
|
|
439
|
+
return { effectiveBudgetUsd: ownLimitUsd, constrainedBy: [] };
|
|
440
|
+
const values = candidates.map((c) => c.value);
|
|
441
|
+
const constrainedBy = candidates.filter((c) => c.value < ownLimitUsd).map((c) => c.reason);
|
|
442
|
+
const effectiveBudgetUsd = Math.min(ownLimitUsd, ...values);
|
|
303
443
|
// Less than the smallest reservable amount is nothing left.
|
|
304
444
|
const exhausted = candidates.find((c) => c.value < MIN_RESERVATION_USD);
|
|
305
|
-
|
|
445
|
+
const limiting = effectiveBudgetUsd < ownLimitUsd ? candidates.find((c) => c.value === effectiveBudgetUsd) : undefined;
|
|
446
|
+
return {
|
|
447
|
+
effectiveBudgetUsd,
|
|
448
|
+
constrainedBy,
|
|
449
|
+
...(limiting ? { limitedBy: limiting.reason } : {}),
|
|
450
|
+
...(exhausted ? { exhaustedBy: exhausted.reason, exhaustedDetail: exhausted.detail } : {}),
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Room for a coding run's overrun top-up (budget-topup.ts): the least of what
|
|
455
|
+
* its budget group, its run tree's root group, and its run tree's
|
|
456
|
+
* overrun-raised ceiling have left right now. Each group is seen whole: every
|
|
457
|
+
* live hold counts, this run's own grant (or its tree's hold) included, with
|
|
458
|
+
* no first-come-first-served ordering, because a top-up is new money that runs
|
|
459
|
+
* started later did not count when they reserved. A grant of at most roomUsd
|
|
460
|
+
* raises each group's and the tree's committed total by at most that much, so
|
|
461
|
+
* caps and ceilings stay hard. Callers hold the group dispatch lock.
|
|
462
|
+
*/
|
|
463
|
+
export async function codingTopUpRoom(db, runId, now = new Date()) {
|
|
464
|
+
const run = await db.run.findUniqueOrThrow({
|
|
465
|
+
where: { id: runId },
|
|
466
|
+
select: { parentRunId: true, agent: { select: { budgetGroupId: true } } },
|
|
467
|
+
});
|
|
468
|
+
const candidates = [];
|
|
469
|
+
const groupIds = new Set();
|
|
470
|
+
if (run.agent.budgetGroupId)
|
|
471
|
+
groupIds.add(run.agent.budgetGroupId);
|
|
472
|
+
if (run.parentRunId) {
|
|
473
|
+
// Every live run in the tree off the ancestor chain holds its grant, this run's included.
|
|
474
|
+
const tree = await runTreeSpend(db, run.parentRunId, now, undefined, true);
|
|
475
|
+
candidates.push({
|
|
476
|
+
value: tree.remainingUsd,
|
|
477
|
+
reason: "run-tree",
|
|
478
|
+
detail: {
|
|
479
|
+
capUsd: tree.capUsd,
|
|
480
|
+
spentUsd: tree.spentUsd,
|
|
481
|
+
heldUsd: tree.capUsd - tree.spentUsd - tree.remainingUsd,
|
|
482
|
+
heldRuns: 0,
|
|
483
|
+
},
|
|
484
|
+
});
|
|
485
|
+
// The root's group holds the tree, this run's grant included, wherever this run's own group is.
|
|
486
|
+
if (tree.rootBudgetGroupId)
|
|
487
|
+
groupIds.add(tree.rootBudgetGroupId);
|
|
488
|
+
}
|
|
489
|
+
for (const groupId of groupIds) {
|
|
490
|
+
const group = await db.budgetGroup.findUnique({
|
|
491
|
+
where: { id: groupId },
|
|
492
|
+
include: { agents: { select: { id: true, budgetUsd: true } } },
|
|
493
|
+
});
|
|
494
|
+
if (!group)
|
|
495
|
+
continue;
|
|
496
|
+
for (const s of await computeGroupSpend(db, group, group.agents, now)) {
|
|
497
|
+
candidates.push({
|
|
498
|
+
value: s.remainingUsd,
|
|
499
|
+
reason: s.period,
|
|
500
|
+
detail: { capUsd: s.capUsd, spentUsd: s.spentUsd, heldUsd: s.reservedUsd, heldRuns: s.heldRuns },
|
|
501
|
+
groupName: group.name,
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
if (candidates.length === 0)
|
|
506
|
+
return { roomUsd: Infinity };
|
|
507
|
+
const least = candidates.reduce((min, c) => (c.value < min.value ? c : min));
|
|
508
|
+
const { capUsd, spentUsd, heldUsd } = least.detail;
|
|
509
|
+
return {
|
|
510
|
+
roomUsd: Math.max(0, least.value),
|
|
511
|
+
limitedBy: least.reason,
|
|
512
|
+
detail: { capUsd, spentUsd, heldUsd },
|
|
513
|
+
...(least.groupName !== undefined ? { groupName: least.groupName } : {}),
|
|
514
|
+
};
|
|
306
515
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which run last pushed to a pull request a coding run opened, and whether that push was work a
|
|
3
|
+
* run stopped at its budget left unfinished. Mark-ready keeps such a draft a draft; the review
|
|
4
|
+
* check skips it while its head is still that push (a person's later commit is reviewed).
|
|
5
|
+
*/
|
|
6
|
+
import type { PrismaClient } from "#prisma";
|
|
7
|
+
export type BudgetStoppedHeadDb = Pick<PrismaClient, "codingRun">;
|
|
8
|
+
/** The run that pushed last: its status and the commit it pushed (result.commitSha). */
|
|
9
|
+
export interface LastPusher {
|
|
10
|
+
status: string | undefined;
|
|
11
|
+
commitSha: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The newest continuation of `root` (by createdAt) whose result names pull request `prNumber`,
|
|
15
|
+
* else the root itself.
|
|
16
|
+
*/
|
|
17
|
+
export declare function lastPusher(db: BudgetStoppedHeadDb, root: {
|
|
18
|
+
runId: string;
|
|
19
|
+
result: unknown;
|
|
20
|
+
run: {
|
|
21
|
+
status?: string;
|
|
22
|
+
} | null;
|
|
23
|
+
}, prNumber: number): Promise<LastPusher>;
|
|
24
|
+
/**
|
|
25
|
+
* True when the pull request's head is the push of a run that stopped at its budget: the marker
|
|
26
|
+
* run resolves (through rootCodingRunId) to a root coding run in `repository` recorded as this
|
|
27
|
+
* pull request, and its last pusher stopped at its budget with `headSha` as its commit. Any
|
|
28
|
+
* lookup failure is false, so the pull request is reviewed as usual.
|
|
29
|
+
*/
|
|
30
|
+
export declare function headStoppedAtBudget(db: BudgetStoppedHeadDb, input: {
|
|
31
|
+
markerRunId: string | null | undefined;
|
|
32
|
+
repository: string;
|
|
33
|
+
prNumber: number;
|
|
34
|
+
headSha: string;
|
|
35
|
+
}): Promise<boolean>;
|
|
36
|
+
/**
|
|
37
|
+
* The coding run that may be pushing to the pull request right now: the marker's root coding
|
|
38
|
+
* run (in `repository`) while it is pending or running, else its newest continuation that is.
|
|
39
|
+
* Its result, and so whether it stopped at its budget, is recorded only after its push lands,
|
|
40
|
+
* so a review of the head waits for it. Null when none is in flight or the marker resolves to
|
|
41
|
+
* nothing.
|
|
42
|
+
*/
|
|
43
|
+
export declare function pushingRunInFlight(db: BudgetStoppedHeadDb, input: {
|
|
44
|
+
markerRunId: string | null | undefined;
|
|
45
|
+
repository: string;
|
|
46
|
+
}): Promise<string | null>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { pullRequestOutcome } from "./host-status.js";
|
|
2
|
+
const commitShaOf = (result) => {
|
|
3
|
+
if (!result || typeof result !== "object")
|
|
4
|
+
return undefined;
|
|
5
|
+
const sha = result.commitSha;
|
|
6
|
+
return typeof sha === "string" ? sha : undefined;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* The newest continuation of `root` (by createdAt) whose result names pull request `prNumber`,
|
|
10
|
+
* else the root itself.
|
|
11
|
+
*/
|
|
12
|
+
export async function lastPusher(db, root, prNumber) {
|
|
13
|
+
const continuations = await db.codingRun.findMany({
|
|
14
|
+
where: { rootCodingRunId: root.runId },
|
|
15
|
+
select: { result: true, run: { select: { status: true } } },
|
|
16
|
+
orderBy: { createdAt: "desc" },
|
|
17
|
+
});
|
|
18
|
+
const last = continuations.find((c) => pullRequestOutcome(c.result)?.pullRequestNumber === prNumber) ?? root;
|
|
19
|
+
return { status: last.run?.status, commitSha: commitShaOf(last.result) };
|
|
20
|
+
}
|
|
21
|
+
const ROOT_SELECT = {
|
|
22
|
+
runId: true,
|
|
23
|
+
repository: true,
|
|
24
|
+
rootCodingRunId: true,
|
|
25
|
+
result: true,
|
|
26
|
+
run: { select: { status: true } },
|
|
27
|
+
};
|
|
28
|
+
/** The marker run's root coding run (rootCodingRunId, else itself), only when it is in `repository`. */
|
|
29
|
+
async function markerRoot(db, markerRunId, repository) {
|
|
30
|
+
const marked = await db.codingRun.findUnique({ where: { runId: markerRunId }, select: ROOT_SELECT });
|
|
31
|
+
if (!marked)
|
|
32
|
+
return null;
|
|
33
|
+
const root = marked.rootCodingRunId
|
|
34
|
+
? await db.codingRun.findUnique({ where: { runId: marked.rootCodingRunId }, select: ROOT_SELECT })
|
|
35
|
+
: marked;
|
|
36
|
+
return root && root.repository.toLowerCase() === repository.toLowerCase() ? root : null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* True when the pull request's head is the push of a run that stopped at its budget: the marker
|
|
40
|
+
* run resolves (through rootCodingRunId) to a root coding run in `repository` recorded as this
|
|
41
|
+
* pull request, and its last pusher stopped at its budget with `headSha` as its commit. Any
|
|
42
|
+
* lookup failure is false, so the pull request is reviewed as usual.
|
|
43
|
+
*/
|
|
44
|
+
export async function headStoppedAtBudget(db, input) {
|
|
45
|
+
try {
|
|
46
|
+
if (!input.markerRunId)
|
|
47
|
+
return false;
|
|
48
|
+
const root = await markerRoot(db, input.markerRunId, input.repository);
|
|
49
|
+
if (!root || pullRequestOutcome(root.result)?.pullRequestNumber !== input.prNumber)
|
|
50
|
+
return false;
|
|
51
|
+
const last = await lastPusher(db, root, input.prNumber);
|
|
52
|
+
return last.status === "budget_exhausted" && last.commitSha === input.headSha;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Run statuses of a coding run that may still push (its result is not recorded yet). */
|
|
59
|
+
const IN_FLIGHT = ["pending", "running"];
|
|
60
|
+
/**
|
|
61
|
+
* The coding run that may be pushing to the pull request right now: the marker's root coding
|
|
62
|
+
* run (in `repository`) while it is pending or running, else its newest continuation that is.
|
|
63
|
+
* Its result, and so whether it stopped at its budget, is recorded only after its push lands,
|
|
64
|
+
* so a review of the head waits for it. Null when none is in flight or the marker resolves to
|
|
65
|
+
* nothing.
|
|
66
|
+
*/
|
|
67
|
+
export async function pushingRunInFlight(db, input) {
|
|
68
|
+
if (!input.markerRunId)
|
|
69
|
+
return null;
|
|
70
|
+
const root = await markerRoot(db, input.markerRunId, input.repository);
|
|
71
|
+
if (!root)
|
|
72
|
+
return null;
|
|
73
|
+
if (root.run && IN_FLIGHT.includes(root.run.status))
|
|
74
|
+
return root.runId;
|
|
75
|
+
const continuation = await db.codingRun.findFirst({
|
|
76
|
+
where: { rootCodingRunId: root.runId, run: { status: { in: [...IN_FLIGHT] } } },
|
|
77
|
+
select: { runId: true },
|
|
78
|
+
orderBy: { createdAt: "desc" },
|
|
79
|
+
});
|
|
80
|
+
return continuation?.runId ?? null;
|
|
81
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Overrun from available room: a coding run reserves only its base budget at
|
|
3
|
+
* dispatch, and may spend past it, up to its limit (CodingRun.budgetLimitUsd,
|
|
4
|
+
* the base raised by the agent's allowedOverrunPercent), only out of room its
|
|
5
|
+
* budget group and run tree still have when it needs it. Overrun is
|
|
6
|
+
* permission, not a reservation.
|
|
7
|
+
*
|
|
8
|
+
* The control plane grants top-ups, never the proxy: the executor's per-run
|
|
9
|
+
* monitor loop calls topUpCodingBudget while the run's job is running. A run
|
|
10
|
+
* close to its grant (spent + held within its headroom of it: two of its
|
|
11
|
+
* largest request holds, or 20% of its base if more) is granted one step, under the same group dispatch lock dispatch takes, by
|
|
12
|
+
* raising CodingRun.budgetReservedUsd (what groups and run trees hold) and
|
|
13
|
+
* CodingProxySession.budgetUsd (what the proxy enforces, re-read on every
|
|
14
|
+
* request) together. When the group or tree has no room left, the run records
|
|
15
|
+
* an overrun_unavailable budget event and never asks again; the proxy then
|
|
16
|
+
* refuses it at its grant as it always has.
|
|
17
|
+
*/
|
|
18
|
+
import type { PrismaClient } from "#prisma";
|
|
19
|
+
/**
|
|
20
|
+
* not_needed: the run is not close to its grant yet. granted: one step was
|
|
21
|
+
* added. unavailable: its group or run tree had no room; recorded once, and
|
|
22
|
+
* the run stops asking. closed: nothing more to ask for (no limit, the limit
|
|
23
|
+
* reached, already refused once, or the run or its proxy session is not active).
|
|
24
|
+
*/
|
|
25
|
+
export type TopUpOutcome = "not_needed" | "granted" | "unavailable" | "closed";
|
|
26
|
+
export interface TopUpResult {
|
|
27
|
+
outcome: TopUpOutcome;
|
|
28
|
+
/** The run's grant after this call, when it has a limit. */
|
|
29
|
+
grantedUsd?: number;
|
|
30
|
+
/**
|
|
31
|
+
* The run is within twice its headroom of its grant: the caller should ask
|
|
32
|
+
* again soon (the executor polls faster), since a top-up must land while the
|
|
33
|
+
* request before the one that would not fit is still in flight.
|
|
34
|
+
*/
|
|
35
|
+
near?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** Share of the base one step adds, unless one maximum request hold is more. */
|
|
38
|
+
export declare const TOP_UP_STEP_SHARE = 0.1;
|
|
39
|
+
/** Headroom: the share of the base, or this many of the run's largest request holds if more. */
|
|
40
|
+
export declare const TOP_UP_HEADROOM_SHARE = 0.2;
|
|
41
|
+
export declare const TOP_UP_HEADROOM_HOLDS = 2;
|
|
42
|
+
/**
|
|
43
|
+
* Grants the run one overrun step when it is close to its grant and its
|
|
44
|
+
* budget group and run tree have room. Cheap when it is not close: that is
|
|
45
|
+
* read without the lock. One attempt per call, so a poll never blocks on
|
|
46
|
+
* retries: a serialization conflict (or a lock not had in time) answers
|
|
47
|
+
* not_needed and near, and the caller's next poll, soon, asks again.
|
|
48
|
+
*/
|
|
49
|
+
export declare function topUpCodingBudget(db: PrismaClient, runId: string, now?: Date): Promise<TopUpResult>;
|
|
50
|
+
/** How long one top-up waits to start its transaction: short, so a poll (and its heartbeat) is never held long. */
|
|
51
|
+
export declare const TOP_UP_TX_MAX_WAIT_MS = 2000;
|