@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
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Launches, watches, stops, and removes native sandbox workers as Kubernetes pods
|
|
3
|
+
* (docs/native-sandbox.md), from the builders in kubernetes-isolation.ts. Like the Docker
|
|
4
|
+
* launcher it keeps no state of its own: names derive from the run id, state comes from the pod,
|
|
5
|
+
* and sessions live in Postgres, so any replica can act on any run.
|
|
6
|
+
*
|
|
7
|
+
* A pod's NetworkPolicy takes effect a few seconds after the pod starts (the CNI programs it), so
|
|
8
|
+
* the session is created not ready (`networkReadyAtLaunch = false`): the gateway refuses the
|
|
9
|
+
* worker until this launcher has read back the pod and policy it created, then proven from inside
|
|
10
|
+
* the pod that the gateway port answers while the gateway's deny port and an outside address do
|
|
11
|
+
* not — and only then marks the session ready.
|
|
12
|
+
*/
|
|
13
|
+
import { logger } from "../core/logger.js";
|
|
14
|
+
import { DISABLED_POWER, wakeTimeoutMs } from "../core/power.js";
|
|
15
|
+
import { KubernetesAlreadyExistsError } from "../providers/jobs/kubernetes-api.js";
|
|
16
|
+
import { canonicalResources } from "../providers/jobs/kubernetes-isolation.js";
|
|
17
|
+
import { NATIVE_GATEWAY_PORT } from "./docker-isolation.js";
|
|
18
|
+
import { WORKER_TAIL_TIMEOUT_MS, withTimeout, workerTailFields } from "./docker-launcher.js";
|
|
19
|
+
import { createHash } from "node:crypto";
|
|
20
|
+
import { Readable } from "node:stream";
|
|
21
|
+
import { buildNativeInputSecret, buildNativeRunNetworkPolicy, buildNativeRunPod, buildNativeWarmNetworkPolicy, buildNativeWarmPod, NATIVE_PROBE, NATIVE_RUN_SELECTOR, NATIVE_RUN_SHA_LABEL, NATIVE_WARM_SELECTOR, NATIVE_WARM_TOKEN_LABEL, NATIVE_WORKER_CONTAINER, nativeEnforcementProbe, nativeKubernetesNames, nativeWarmWorkerName, } from "./kubernetes-isolation.js";
|
|
22
|
+
import { NATIVE_SANDBOX_LAUNCH_ABANDONED } from "./launch.js";
|
|
23
|
+
import { warmDeliveryCommand } from "./warm-delivery.js";
|
|
24
|
+
import { NATIVE_SANDBOX_WARM_DELIVERY_FAILED } from "./warm-pool.js";
|
|
25
|
+
const k8sLog = logger.child({ module: "native-kubernetes-launcher" });
|
|
26
|
+
export const NATIVE_SANDBOX_NETWORK_UNENFORCED = "native_sandbox_network_unenforced";
|
|
27
|
+
export const NATIVE_SANDBOX_ISOLATION_MISMATCH = "native_sandbox_isolation_mismatch";
|
|
28
|
+
export const NATIVE_SANDBOX_CAPACITY = "native_sandbox_capacity";
|
|
29
|
+
/**
|
|
30
|
+
* A failed worker's log is read this far back before its tail is redacted and cut. The API server
|
|
31
|
+
* applies `limitBytes` from the start of the selected lines, so it would cut the end (the worker's
|
|
32
|
+
* final failure line): it is only a memory cap, far above what the line bound selects in practice.
|
|
33
|
+
*/
|
|
34
|
+
const WORKER_LOG_TAIL_LINES = 100;
|
|
35
|
+
const WORKER_LOG_TAIL_BYTES = 1024 * 1024;
|
|
36
|
+
/** The API server's refusal of a pod the namespace's ResourceQuota has no room for (403 "exceeded quota"). */
|
|
37
|
+
export function isQuotaRejection(err) {
|
|
38
|
+
if (typeof err !== "object" || err === null)
|
|
39
|
+
return false;
|
|
40
|
+
const { code, body, message } = err;
|
|
41
|
+
const text = `${typeof body === "string" ? body : JSON.stringify(body ?? "")} ${typeof message === "string" ? message : ""}`;
|
|
42
|
+
return (code === 403 || code === undefined) && /exceeded quota/i.test(text);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* An object as the API server would store it, for comparison: keys sorted, and missing, undefined,
|
|
46
|
+
* and empty arrays alike (it drops an empty `ingress: []`, which `policyTypes` already makes deny-all).
|
|
47
|
+
*/
|
|
48
|
+
export function canonical(value) {
|
|
49
|
+
if (Array.isArray(value))
|
|
50
|
+
return value.length === 0 ? undefined : value.map(canonical);
|
|
51
|
+
if (value === null || typeof value !== "object")
|
|
52
|
+
return value;
|
|
53
|
+
const out = {};
|
|
54
|
+
for (const key of Object.keys(value).sort()) {
|
|
55
|
+
const item = canonical(value[key]);
|
|
56
|
+
if (item !== undefined)
|
|
57
|
+
out[key] = item;
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
export class KubernetesNativeWorkerLauncher {
|
|
62
|
+
options;
|
|
63
|
+
networkReadyAtLaunch = false;
|
|
64
|
+
gatewayHost;
|
|
65
|
+
power;
|
|
66
|
+
constructor(options) {
|
|
67
|
+
this.options = options;
|
|
68
|
+
this.power = options.power ?? DISABLED_POWER;
|
|
69
|
+
}
|
|
70
|
+
get api() {
|
|
71
|
+
return this.options.api;
|
|
72
|
+
}
|
|
73
|
+
get ns() {
|
|
74
|
+
return this.options.namespace;
|
|
75
|
+
}
|
|
76
|
+
sleep(ms) {
|
|
77
|
+
return (this.options.sleep ?? ((t) => new Promise((resolve) => setTimeout(resolve, t))))(ms);
|
|
78
|
+
}
|
|
79
|
+
/** The gateway Service's ClusterIP: workers dial an address, so they need no DNS egress. */
|
|
80
|
+
resolveGatewayHost() {
|
|
81
|
+
if (this.options.gatewayUrl)
|
|
82
|
+
return Promise.resolve(new URL(this.options.gatewayUrl).hostname);
|
|
83
|
+
this.gatewayHost ??= (async () => {
|
|
84
|
+
const service = await this.api.readService(this.ns, this.options.gatewayService);
|
|
85
|
+
const ip = service?.spec?.clusterIP;
|
|
86
|
+
if (!ip || ip === "None") {
|
|
87
|
+
this.gatewayHost = undefined;
|
|
88
|
+
throw new Error(`native_sandbox_gateway_unavailable: Service "${this.options.gatewayService}" in "${this.ns}" has no ClusterIP.`);
|
|
89
|
+
}
|
|
90
|
+
return ip;
|
|
91
|
+
})();
|
|
92
|
+
return this.gatewayHost;
|
|
93
|
+
}
|
|
94
|
+
async resolveGatewayUrl() {
|
|
95
|
+
if (this.options.gatewayUrl)
|
|
96
|
+
return this.options.gatewayUrl;
|
|
97
|
+
return `http://${await this.resolveGatewayHost()}:${NATIVE_GATEWAY_PORT}/native-gateway/v1/call`;
|
|
98
|
+
}
|
|
99
|
+
async createIfMissing(create) {
|
|
100
|
+
try {
|
|
101
|
+
await create();
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
if (!(err instanceof KubernetesAlreadyExistsError))
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async launch(input, launchOptions = {}) {
|
|
109
|
+
const runId = input.runId;
|
|
110
|
+
// Low-power mode: the gateway may be scaled to zero; wake it before anything is created. Guarded
|
|
111
|
+
// so mode off adds no await.
|
|
112
|
+
if (this.power.enabled) {
|
|
113
|
+
await this.power.ensureAwake("gateway", {
|
|
114
|
+
timeoutMs: wakeTimeoutMs(this.options.readyTimeoutMs ?? 120_000),
|
|
115
|
+
runId,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
// A wake can take minutes: a run stopped meanwhile gets no pod.
|
|
119
|
+
if (launchOptions.stillWanted && !(await launchOptions.stillWanted())) {
|
|
120
|
+
throw new Error(`${NATIVE_SANDBOX_LAUNCH_ABANDONED}: the run ended while its worker was launching; no worker was started.`);
|
|
121
|
+
}
|
|
122
|
+
const names = nativeKubernetesNames(runId);
|
|
123
|
+
if ((await this.inspect(runId)).state === "missing") {
|
|
124
|
+
const pod = buildNativeRunPod({
|
|
125
|
+
runId,
|
|
126
|
+
namespace: this.ns,
|
|
127
|
+
image: this.options.image,
|
|
128
|
+
limits: this.options.limits,
|
|
129
|
+
activeDeadlineSeconds: this.options.deadlineSeconds,
|
|
130
|
+
runtimeClassName: this.options.runtimeClassName,
|
|
131
|
+
platform: this.options.platform,
|
|
132
|
+
priorityClassName: this.options.priorityClassName,
|
|
133
|
+
});
|
|
134
|
+
const policy = buildNativeRunNetworkPolicy(runId, this.ns);
|
|
135
|
+
await this.createIsolated(pod, policy, () => this.remove(runId), {
|
|
136
|
+
// The Secret before the pod that mounts it.
|
|
137
|
+
beforePod: () => this.createIfMissing(() => this.api.createSecret(this.ns, buildNativeInputSecret(input, this.ns))),
|
|
138
|
+
});
|
|
139
|
+
await this.options.onNetworkProven(runId);
|
|
140
|
+
// Read before the exit is reported, so the pod (and its log) still exists.
|
|
141
|
+
return this.handleByName(names.pod, (code) => this.logFailedExit(names.pod, code, input, launchOptions));
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
k8sLog.info({ pod: names.pod }, "native worker pod already exists: attaching, not relaunching");
|
|
145
|
+
}
|
|
146
|
+
return this.handle(runId);
|
|
147
|
+
}
|
|
148
|
+
/** A non-zero exit, with the tail of the worker's log (bounded and redacted: workerTailFields), as the Docker launcher logs it. */
|
|
149
|
+
async logFailedExit(podName, code, input, launchOptions) {
|
|
150
|
+
if (code === 0)
|
|
151
|
+
return;
|
|
152
|
+
// One bound for the whole diagnostic, so a hung read never holds back the exit (and the run's end).
|
|
153
|
+
const by = Date.now() + (this.options.diagnosticTimeoutMs ?? WORKER_TAIL_TIMEOUT_MS);
|
|
154
|
+
let log;
|
|
155
|
+
try {
|
|
156
|
+
log = await withTimeout(this.api.readLogTail(this.ns, podName, NATIVE_WORKER_CONTAINER, WORKER_LOG_TAIL_LINES, WORKER_LOG_TAIL_BYTES), by - Date.now());
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// The pod may already be gone, the read may be refused (no pods/log), or it timed out.
|
|
160
|
+
k8sLog.warn({ pod: podName, code, stderrTailOmitted: "log_read_failed" }, "native worker exited non-zero");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
// The read may always begin mid-text, even with fewer lines than the bound: the kubelet splits
|
|
164
|
+
// a line over 16 KiB into partial records (each counted as a line), and log rotation drops the
|
|
165
|
+
// oldest text, so the start is always masked as cut. The byte cap (counted from the start of
|
|
166
|
+
// the selected lines) cuts the end only when it is met.
|
|
167
|
+
const end = Buffer.byteLength(log) >= WORKER_LOG_TAIL_BYTES - 3;
|
|
168
|
+
const tail = await workerTailFields(log, input, launchOptions.secretValues, { start: true, end }, by - Date.now());
|
|
169
|
+
k8sLog.warn({ pod: podName, code, ...tail }, "native worker exited non-zero");
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Policy first, so the pod never exists without it; then the pod; then attest and prove it. A
|
|
173
|
+
* quota rejection becomes native_sandbox_capacity. Any failure removes what was made.
|
|
174
|
+
*/
|
|
175
|
+
async createIsolated(pod, policy, cleanup, hooks = {}) {
|
|
176
|
+
await this.createIfMissing(() => this.api.createNetworkPolicy(this.ns, policy));
|
|
177
|
+
await hooks.beforePod?.();
|
|
178
|
+
try {
|
|
179
|
+
await this.createIfMissing(() => this.api.createPod(this.ns, pod));
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
if (!isQuotaRejection(err))
|
|
183
|
+
throw err;
|
|
184
|
+
await cleanup().catch(() => { });
|
|
185
|
+
throw new Error(`${NATIVE_SANDBOX_CAPACITY}: the namespace's ResourceQuota has no room for another native worker pod.`, { cause: err });
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
await this.attest(pod, policy);
|
|
189
|
+
await this.proveIsolation(pod.metadata.name);
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
await cleanup().catch(() => { });
|
|
193
|
+
throw err;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/** What the API server stored must still be what was built: an admission change voids the run. */
|
|
197
|
+
async attest(built, builtPolicy) {
|
|
198
|
+
if (!(await this.matches(built, builtPolicy))) {
|
|
199
|
+
throw new Error(`${NATIVE_SANDBOX_ISOLATION_MISMATCH}: the worker pod or its NetworkPolicy as stored differs from what was built.`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async matches(built, builtPolicy) {
|
|
203
|
+
const [pod, policy] = await Promise.all([
|
|
204
|
+
this.api.readPod(this.ns, built.metadata.name),
|
|
205
|
+
this.api.readNetworkPolicy(this.ns, builtPolicy.metadata.name),
|
|
206
|
+
]);
|
|
207
|
+
const stored = pod?.spec;
|
|
208
|
+
const want = built.spec;
|
|
209
|
+
const same = (a, b) => JSON.stringify(canonical(a)) === JSON.stringify(canonical(b));
|
|
210
|
+
const ok = !!stored &&
|
|
211
|
+
!!policy &&
|
|
212
|
+
same(policy.spec, builtPolicy.spec) &&
|
|
213
|
+
stored.automountServiceAccountToken === false &&
|
|
214
|
+
stored.hostNetwork !== true &&
|
|
215
|
+
stored.runtimeClassName === want.runtimeClassName &&
|
|
216
|
+
stored.priorityClassName === want.priorityClassName &&
|
|
217
|
+
stored.containers.length === 1 &&
|
|
218
|
+
stored.containers[0].image === want.containers[0].image &&
|
|
219
|
+
same(stored.containers[0].securityContext, want.containers[0].securityContext) &&
|
|
220
|
+
same(stored.containers[0].env, want.containers[0].env) &&
|
|
221
|
+
same(canonicalResources(stored.containers[0].resources), canonicalResources(want.containers[0].resources)) &&
|
|
222
|
+
(stored.initContainers ?? []).length === 0;
|
|
223
|
+
return ok;
|
|
224
|
+
}
|
|
225
|
+
/** Waits for the pod to run, then proves its egress from inside it (bounded). */
|
|
226
|
+
async proveIsolation(podName) {
|
|
227
|
+
const pollMs = this.options.pollMs ?? 1_000;
|
|
228
|
+
const readyBy = Date.now() + (this.options.readyTimeoutMs ?? 120_000);
|
|
229
|
+
for (;;) {
|
|
230
|
+
const pod = await this.api.readPod(this.ns, podName);
|
|
231
|
+
if (!pod)
|
|
232
|
+
throw new Error("native_sandbox_worker_lost: the worker pod disappeared before it was ready.");
|
|
233
|
+
const phase = pod.status?.phase ?? "Pending";
|
|
234
|
+
if (phase === "Running")
|
|
235
|
+
break;
|
|
236
|
+
if (phase === "Succeeded" || phase === "Failed") {
|
|
237
|
+
throw new Error(`native_sandbox_worker_exited: the worker pod ended before it was ready (${phase}).`);
|
|
238
|
+
}
|
|
239
|
+
if (Date.now() >= readyBy)
|
|
240
|
+
throw new Error("native_sandbox_worker_unready: the worker pod did not start in time.");
|
|
241
|
+
await this.sleep(pollMs);
|
|
242
|
+
}
|
|
243
|
+
const command = nativeEnforcementProbe(await this.resolveGatewayHost());
|
|
244
|
+
const provenBy = Date.now() + (this.options.enforcementTimeoutMs ?? 30_000);
|
|
245
|
+
let last;
|
|
246
|
+
for (;;) {
|
|
247
|
+
last = await this.api
|
|
248
|
+
.exec(this.ns, podName, NATIVE_WORKER_CONTAINER, command, { timeoutMs: 20_000 })
|
|
249
|
+
.catch(() => NATIVE_PROBE.gatewayUnreachable);
|
|
250
|
+
if (last === NATIVE_PROBE.proven)
|
|
251
|
+
return;
|
|
252
|
+
if (Date.now() >= provenBy)
|
|
253
|
+
break;
|
|
254
|
+
await this.sleep(pollMs);
|
|
255
|
+
}
|
|
256
|
+
const why = last === NATIVE_PROBE.denyReachable
|
|
257
|
+
? "the gateway's deny port was reachable"
|
|
258
|
+
: last === NATIVE_PROBE.outsideReachable
|
|
259
|
+
? "an outside address was reachable"
|
|
260
|
+
: "the gateway was unreachable";
|
|
261
|
+
throw new Error(`${NATIVE_SANDBOX_NETWORK_UNENFORCED}: the worker pod's isolation could not be proven (${why}).`);
|
|
262
|
+
}
|
|
263
|
+
handle(runId) {
|
|
264
|
+
return this.handleByName(nativeKubernetesNames(runId).pod);
|
|
265
|
+
}
|
|
266
|
+
handleByName(podName, onExit) {
|
|
267
|
+
const exited = (async () => {
|
|
268
|
+
for (;;) {
|
|
269
|
+
const state = await this.inspectByName(podName);
|
|
270
|
+
if (state.state === "exited") {
|
|
271
|
+
await onExit?.(state.exitCode).catch(() => { });
|
|
272
|
+
return state.exitCode;
|
|
273
|
+
}
|
|
274
|
+
if (state.state === "missing")
|
|
275
|
+
return null;
|
|
276
|
+
await this.sleep(this.options.pollMs ?? 1_000);
|
|
277
|
+
}
|
|
278
|
+
})();
|
|
279
|
+
return { exited, kill: () => void this.api.deletePod(this.ns, podName, 0) };
|
|
280
|
+
}
|
|
281
|
+
async inspect(runId) {
|
|
282
|
+
return this.inspectByName(nativeKubernetesNames(runId).pod);
|
|
283
|
+
}
|
|
284
|
+
async inspectByName(podName) {
|
|
285
|
+
const pod = await this.api.readPod(this.ns, podName);
|
|
286
|
+
if (!pod)
|
|
287
|
+
return { state: "missing" };
|
|
288
|
+
const phase = pod.status?.phase;
|
|
289
|
+
if (phase === "Succeeded" || phase === "Failed") {
|
|
290
|
+
const terminated = pod.status?.containerStatuses?.find((c) => c.name === NATIVE_WORKER_CONTAINER)?.state
|
|
291
|
+
?.terminated;
|
|
292
|
+
return { state: "exited", exitCode: terminated?.exitCode ?? 137 };
|
|
293
|
+
}
|
|
294
|
+
return { state: "running" };
|
|
295
|
+
}
|
|
296
|
+
async kill(runId) {
|
|
297
|
+
await this.api.deletePod(this.ns, nativeKubernetesNames(runId).pod, 0);
|
|
298
|
+
}
|
|
299
|
+
async remove(runId) {
|
|
300
|
+
await this.removeByWorkerName(nativeKubernetesNames(runId).pod);
|
|
301
|
+
}
|
|
302
|
+
async listWorkers() {
|
|
303
|
+
const pods = await this.api.listPods(this.ns, NATIVE_RUN_SELECTOR);
|
|
304
|
+
return pods
|
|
305
|
+
.map((pod) => ({ name: pod.metadata?.name ?? "", runHash: pod.metadata?.labels?.[NATIVE_RUN_SHA_LABEL] ?? "" }))
|
|
306
|
+
.filter((worker) => worker.name && worker.runHash);
|
|
307
|
+
}
|
|
308
|
+
async removeByWorkerName(name) {
|
|
309
|
+
if (!/^wardby-native-[0-9a-f]{20}$/.test(name))
|
|
310
|
+
return;
|
|
311
|
+
await this.api.deletePod(this.ns, name, 0);
|
|
312
|
+
await this.api.deleteSecret(this.ns, `${name}-input`);
|
|
313
|
+
await this.api.deleteNetworkPolicy(this.ns, name);
|
|
314
|
+
}
|
|
315
|
+
// --- Warm pool workers (native sandbox phase 6) ---
|
|
316
|
+
warmPod(token, waitMs) {
|
|
317
|
+
return buildNativeWarmPod({
|
|
318
|
+
token,
|
|
319
|
+
waitMs,
|
|
320
|
+
namespace: this.ns,
|
|
321
|
+
image: this.options.image,
|
|
322
|
+
limits: this.options.limits,
|
|
323
|
+
// A claimed worker keeps the run's whole deadline however long it waited.
|
|
324
|
+
activeDeadlineSeconds: Math.ceil(waitMs / 1000) + this.options.deadlineSeconds,
|
|
325
|
+
runtimeClassName: this.options.runtimeClassName,
|
|
326
|
+
platform: this.options.platform,
|
|
327
|
+
priorityClassName: this.options.priorityClassName,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
warmSpecHash(waitMs) {
|
|
331
|
+
const { image, limits, runtimeClassName, platform, priorityClassName, gatewayService, gatewayUrl } = this.options;
|
|
332
|
+
const spec = { launcher: "kubernetes", ns: this.ns, image, limits, runtimeClassName, platform, priorityClassName };
|
|
333
|
+
return createHash("sha256")
|
|
334
|
+
.update(JSON.stringify({ ...spec, gatewayService, gatewayUrl, waitMs }))
|
|
335
|
+
.digest("hex");
|
|
336
|
+
}
|
|
337
|
+
async startWarm(token, waitMs) {
|
|
338
|
+
await this.createIsolated(this.warmPod(token, waitMs), buildNativeWarmNetworkPolicy(token, this.ns), () => this.removeWarm(token));
|
|
339
|
+
}
|
|
340
|
+
async reattestWarm(token, waitMs) {
|
|
341
|
+
const pod = await this.api.readPod(this.ns, nativeWarmWorkerName(token));
|
|
342
|
+
if (pod?.status?.phase !== "Running")
|
|
343
|
+
return false;
|
|
344
|
+
return this.matches(this.warmPod(token, waitMs), buildNativeWarmNetworkPolicy(token, this.ns));
|
|
345
|
+
}
|
|
346
|
+
async deliver(token, input) {
|
|
347
|
+
const code = await this.api.exec(this.ns, nativeWarmWorkerName(token), NATIVE_WORKER_CONTAINER, warmDeliveryCommand(), {
|
|
348
|
+
timeoutMs: 20_000,
|
|
349
|
+
stdin: Readable.from([`${JSON.stringify(input)}\n`]),
|
|
350
|
+
});
|
|
351
|
+
if (code !== 0) {
|
|
352
|
+
throw new Error(`${NATIVE_SANDBOX_WARM_DELIVERY_FAILED}: delivering the run's input exited ${code}.`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
warmHandle(token) {
|
|
356
|
+
return this.handleByName(nativeWarmWorkerName(token));
|
|
357
|
+
}
|
|
358
|
+
inspectWarm(token) {
|
|
359
|
+
return this.inspectByName(nativeWarmWorkerName(token));
|
|
360
|
+
}
|
|
361
|
+
async killWarm(token) {
|
|
362
|
+
await this.api.deletePod(this.ns, nativeWarmWorkerName(token), 0);
|
|
363
|
+
}
|
|
364
|
+
async removeWarm(token) {
|
|
365
|
+
const name = nativeWarmWorkerName(token);
|
|
366
|
+
await this.api.deletePod(this.ns, name, 0);
|
|
367
|
+
await this.api.deleteNetworkPolicy(this.ns, name);
|
|
368
|
+
}
|
|
369
|
+
async listWarm() {
|
|
370
|
+
const pods = await this.api.listPods(this.ns, NATIVE_WARM_SELECTOR);
|
|
371
|
+
return pods
|
|
372
|
+
.map((pod) => pod.metadata?.labels?.[NATIVE_WARM_TOKEN_LABEL] ?? "")
|
|
373
|
+
.filter((token) => /^[0-9a-f]{20}$/.test(token));
|
|
374
|
+
}
|
|
375
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Starting a sandbox-mode run against the HTTP gateway (native sandbox phase 3):
|
|
3
|
+
* create its gateway session, launch a worker with the session's one-time
|
|
4
|
+
* capability on its stdin, and return. Nothing waits on the worker — whichever
|
|
5
|
+
* gateway replica serves its `finish` makes the terminal write. Phase 4's
|
|
6
|
+
* executors launch the worker in a container or pod; `processWorkerLauncher`
|
|
7
|
+
* runs it as a local child process.
|
|
8
|
+
*/
|
|
9
|
+
import { type NativeRunProviders, type RunnerDb } from "../core/runner.js";
|
|
10
|
+
import type { Run } from "#prisma";
|
|
11
|
+
import { PrismaGatewayLedger } from "./ledger.js";
|
|
12
|
+
import type { WorkerInput } from "./protocol.js";
|
|
13
|
+
import type { WorkerProcessSpec } from "./stdio.js";
|
|
14
|
+
export interface WorkerHandle {
|
|
15
|
+
/** Resolves with the worker's exit code (null when it was killed or never started). */
|
|
16
|
+
exited: Promise<number | null>;
|
|
17
|
+
kill(): void;
|
|
18
|
+
}
|
|
19
|
+
export interface WorkerLaunchOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Asked after any slow wait (a low-power wake) and before a worker is created: false means the
|
|
22
|
+
* run ended meanwhile, and the launch stops with NATIVE_SANDBOX_LAUNCH_ABANDONED, creating nothing.
|
|
23
|
+
*/
|
|
24
|
+
stillWanted?: () => Promise<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* Every secret value the worker may be handed (each user tool's readable or brokered secrets),
|
|
27
|
+
* for masking a failed worker's output tail before the launcher logs it; the run's capability is
|
|
28
|
+
* masked from the input itself. Rejects when any read fails. Absent or rejected: no tail is
|
|
29
|
+
* logged (fail closed).
|
|
30
|
+
*/
|
|
31
|
+
secretValues?: () => Promise<readonly string[]>;
|
|
32
|
+
}
|
|
33
|
+
/** The run ended while its worker was launching, so none was created. */
|
|
34
|
+
export declare const NATIVE_SANDBOX_LAUNCH_ABANDONED = "native_sandbox_launch_abandoned";
|
|
35
|
+
/** Starts a worker for an HTTP-gateway input and returns at once. */
|
|
36
|
+
export interface DetachedWorkerLauncher {
|
|
37
|
+
launch(input: WorkerInput, options?: WorkerLaunchOptions): Promise<WorkerHandle>;
|
|
38
|
+
/**
|
|
39
|
+
* False when the worker's network isolation only takes effect after it starts (a Kubernetes
|
|
40
|
+
* NetworkPolicy): its session is then created not ready, and the launcher marks it ready once
|
|
41
|
+
* proven. Absent or true: ready at creation (Docker's network exists before the container).
|
|
42
|
+
*/
|
|
43
|
+
readonly networkReadyAtLaunch?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** The worker as a local child process with an empty environment (by default), its input on stdin. */
|
|
46
|
+
export declare function processWorkerLauncher(spec: WorkerProcessSpec): DetachedWorkerLauncher;
|
|
47
|
+
export type StartSandboxRunOutcome = {
|
|
48
|
+
kind: "launched";
|
|
49
|
+
sessionId: string;
|
|
50
|
+
handle: WorkerHandle;
|
|
51
|
+
} | {
|
|
52
|
+
kind: "ended";
|
|
53
|
+
run: Run;
|
|
54
|
+
};
|
|
55
|
+
export declare function startSandboxRun(options: {
|
|
56
|
+
runId: string;
|
|
57
|
+
providers: NativeRunProviders;
|
|
58
|
+
db: RunnerDb & ConstructorParameters<typeof PrismaGatewayLedger>[0];
|
|
59
|
+
gatewayUrl: string;
|
|
60
|
+
launcher: DetachedWorkerLauncher;
|
|
61
|
+
stillWanted?: () => Promise<boolean>;
|
|
62
|
+
}): Promise<StartSandboxRunOutcome>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Starting a sandbox-mode run against the HTTP gateway (native sandbox phase 3):
|
|
3
|
+
* create its gateway session, launch a worker with the session's one-time
|
|
4
|
+
* capability on its stdin, and return. Nothing waits on the worker — whichever
|
|
5
|
+
* gateway replica serves its `finish` makes the terminal write. Phase 4's
|
|
6
|
+
* executors launch the worker in a container or pod; `processWorkerLauncher`
|
|
7
|
+
* runs it as a local child process.
|
|
8
|
+
*/
|
|
9
|
+
import { spawn } from "node:child_process";
|
|
10
|
+
import { createSandboxSession } from "../core/runner.js";
|
|
11
|
+
import { PrismaGatewayLedger } from "./ledger.js";
|
|
12
|
+
/** The run ended while its worker was launching, so none was created. */
|
|
13
|
+
export const NATIVE_SANDBOX_LAUNCH_ABANDONED = "native_sandbox_launch_abandoned";
|
|
14
|
+
/** The worker as a local child process with an empty environment (by default), its input on stdin. */
|
|
15
|
+
export function processWorkerLauncher(spec) {
|
|
16
|
+
return {
|
|
17
|
+
async launch(input) {
|
|
18
|
+
const child = spawn(spec.command, spec.args, {
|
|
19
|
+
env: spec.env ?? {},
|
|
20
|
+
cwd: spec.cwd,
|
|
21
|
+
stdio: ["pipe", "ignore", "inherit"],
|
|
22
|
+
});
|
|
23
|
+
const exited = new Promise((resolve) => {
|
|
24
|
+
child.on("error", () => resolve(null));
|
|
25
|
+
child.on("exit", (code) => resolve(code));
|
|
26
|
+
});
|
|
27
|
+
child.stdin.on("error", () => { });
|
|
28
|
+
child.stdin.end(`${JSON.stringify(input)}\n`);
|
|
29
|
+
return { exited, kill: () => child.kill("SIGKILL") };
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export async function startSandboxRun(options) {
|
|
34
|
+
const session = await createSandboxSession({
|
|
35
|
+
runId: options.runId,
|
|
36
|
+
providers: options.providers,
|
|
37
|
+
db: options.db,
|
|
38
|
+
ledger: new PrismaGatewayLedger(options.db),
|
|
39
|
+
gatewayUrl: options.gatewayUrl,
|
|
40
|
+
networkReady: options.launcher.networkReadyAtLaunch !== false,
|
|
41
|
+
});
|
|
42
|
+
if (session.kind === "ended")
|
|
43
|
+
return session;
|
|
44
|
+
const handle = await options.launcher.launch(session.input, {
|
|
45
|
+
...(options.stillWanted ? { stillWanted: options.stillWanted } : {}),
|
|
46
|
+
secretValues: session.secretValues,
|
|
47
|
+
});
|
|
48
|
+
return { kind: "launched", sessionId: session.sessionId, handle };
|
|
49
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The native sandbox gateway's durable state (native sandbox phase 3): one
|
|
3
|
+
* session per sandbox-mode run, and one call row per worker callId. Modelled on
|
|
4
|
+
* the coding proxy's PrismaProxyLedger — a model call reserves against the
|
|
5
|
+
* session budget under a row lock on the session before the provider is
|
|
6
|
+
* called, and is settled at its actual cost after — so any control-plane
|
|
7
|
+
* replica can serve any call, and a restart loses nothing.
|
|
8
|
+
*/
|
|
9
|
+
import type { Prisma, PrismaClient } from "#prisma";
|
|
10
|
+
import { ReviewReadLedger } from "../core/review-reads.js";
|
|
11
|
+
export type GatewayLedgerDb = Pick<PrismaClient, "$transaction" | "$queryRaw" | "nativeGatewaySession" | "nativeGatewayCall">;
|
|
12
|
+
export interface GatewaySessionRecord {
|
|
13
|
+
id: string;
|
|
14
|
+
runId: string;
|
|
15
|
+
status: "active" | "finished" | "cancelled";
|
|
16
|
+
deadlineAt: Date;
|
|
17
|
+
budgetUsd: number;
|
|
18
|
+
snapshot: unknown;
|
|
19
|
+
networkReadyAt: Date | null;
|
|
20
|
+
/** The run's saved review reads (ReviewReadsState), or null before it reads a pull request. */
|
|
21
|
+
reviewReads?: unknown;
|
|
22
|
+
}
|
|
23
|
+
export interface CreateGatewaySessionInput {
|
|
24
|
+
runId: string;
|
|
25
|
+
capabilityHash: string;
|
|
26
|
+
deadlineAt: Date;
|
|
27
|
+
budgetUsd: number;
|
|
28
|
+
snapshot: Prisma.InputJsonValue;
|
|
29
|
+
/** Set at creation when the launcher's isolation exists before the worker does (Docker). */
|
|
30
|
+
networkReadyAt?: Date | null;
|
|
31
|
+
}
|
|
32
|
+
export type ReserveOutcome = {
|
|
33
|
+
outcome: "reserved";
|
|
34
|
+
} | {
|
|
35
|
+
outcome: "duplicate";
|
|
36
|
+
} | {
|
|
37
|
+
outcome: "inactive";
|
|
38
|
+
reason: "ended" | "expired";
|
|
39
|
+
} | {
|
|
40
|
+
outcome: "budget_exhausted";
|
|
41
|
+
};
|
|
42
|
+
export interface SettledUsage {
|
|
43
|
+
inputTokens: number;
|
|
44
|
+
outputTokens: number;
|
|
45
|
+
cachedInputTokens: number;
|
|
46
|
+
cacheWriteTokens: number;
|
|
47
|
+
costUsd: number;
|
|
48
|
+
}
|
|
49
|
+
export interface GatewayTotals {
|
|
50
|
+
tokensIn: number;
|
|
51
|
+
tokensOut: number;
|
|
52
|
+
costUsd: number;
|
|
53
|
+
cachedInputTokens: number;
|
|
54
|
+
cacheWriteTokens: number;
|
|
55
|
+
/** Settled cost plus every live (reserved or uncertain) reservation: what the budget is checked against. */
|
|
56
|
+
heldUsd: number;
|
|
57
|
+
}
|
|
58
|
+
export type ClaimOutcome = {
|
|
59
|
+
outcome: "claimed";
|
|
60
|
+
} | {
|
|
61
|
+
outcome: "in_flight";
|
|
62
|
+
} | {
|
|
63
|
+
outcome: "done";
|
|
64
|
+
result: unknown;
|
|
65
|
+
};
|
|
66
|
+
export interface DelegationState {
|
|
67
|
+
status: "pending" | "waiting_budget" | "completed";
|
|
68
|
+
childRunId: string | null;
|
|
69
|
+
childAgentId: string | null;
|
|
70
|
+
/** When the delegation was first called: its wait bounds count from here. */
|
|
71
|
+
createdAt: Date;
|
|
72
|
+
}
|
|
73
|
+
export declare class PrismaGatewayLedger {
|
|
74
|
+
private readonly db;
|
|
75
|
+
constructor(db: GatewayLedgerDb);
|
|
76
|
+
createSession(input: CreateGatewaySessionInput): Promise<GatewaySessionRecord>;
|
|
77
|
+
/** The session a capability belongs to, whatever its status; the caller decides what each status allows. */
|
|
78
|
+
findSessionByCapabilityHash(capabilityHash: string): Promise<GatewaySessionRecord | null>;
|
|
79
|
+
/** Records that the worker's network isolation was proven: the gateway serves it from now on. */
|
|
80
|
+
markNetworkReady(sessionId: string, at?: Date): Promise<void>;
|
|
81
|
+
/** markNetworkReady by the session's run (a launcher knows the run, not the session). */
|
|
82
|
+
markNetworkReadyForRun(runId: string, at?: Date): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Adds one request's review reads to the session's saved ones, under the session's row lock:
|
|
85
|
+
* reads only add, so parallel tool calls of one run each keep what they read.
|
|
86
|
+
*/
|
|
87
|
+
mergeReviewReads(sessionId: string, reads: ReviewReadLedger): Promise<void>;
|
|
88
|
+
endSession(sessionId: string, status: "finished" | "cancelled"): Promise<void>;
|
|
89
|
+
/** Reserves `reservationUsd` for a model call, or says why not. Serialized per session. */
|
|
90
|
+
reserve(input: {
|
|
91
|
+
sessionId: string;
|
|
92
|
+
callId: string;
|
|
93
|
+
reservationUsd: number;
|
|
94
|
+
now: Date;
|
|
95
|
+
}): Promise<ReserveOutcome>;
|
|
96
|
+
/** Settles a reserved (or uncertain) model call at what it actually cost. */
|
|
97
|
+
complete(sessionId: string, callId: string, usage: SettledUsage): Promise<void>;
|
|
98
|
+
/** Frees a reservation the provider never billed (it refused the request). */
|
|
99
|
+
release(sessionId: string, callId: string): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* The outcome is unknown (the connection broke mid-call). Without an estimate the
|
|
102
|
+
* reservation stays held; with one, the call counts at the estimate instead.
|
|
103
|
+
*/
|
|
104
|
+
markUncertain(sessionId: string, callId: string, estimate?: SettledUsage): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Median output tokens of the session's completed model calls (all on the run's one model), or
|
|
107
|
+
* undefined before the first one: the output of a call cut with nothing streamed.
|
|
108
|
+
*/
|
|
109
|
+
medianOutputTokens(sessionId: string): Promise<number | undefined>;
|
|
110
|
+
totals(sessionId: string): Promise<GatewayTotals>;
|
|
111
|
+
/** Claims a one-shot call by callId: the first claimant runs it, a repeat waits or replays. */
|
|
112
|
+
claim(sessionId: string, callId: string, method: string): Promise<ClaimOutcome>;
|
|
113
|
+
recordResult(sessionId: string, callId: string, result: Prisma.InputJsonValue): Promise<void>;
|
|
114
|
+
/** A delegation's durable progress: its sub-agent, whether it waits for budget, and its child run once started. */
|
|
115
|
+
setDelegation(sessionId: string, callId: string, state: {
|
|
116
|
+
status: "pending" | "waiting_budget";
|
|
117
|
+
childAgentId: string;
|
|
118
|
+
childRunId?: string;
|
|
119
|
+
}): Promise<void>;
|
|
120
|
+
delegation(sessionId: string, callId: string): Promise<DelegationState | null>;
|
|
121
|
+
/** The sub-agents other delegations of this run are waiting for budget to start. */
|
|
122
|
+
waitingChildAgentIds(sessionId: string, exceptCallId: string): Promise<string[]>;
|
|
123
|
+
/** Delegations of this session whose child run is started and not yet reported. */
|
|
124
|
+
openDelegationChildren(sessionId: string): Promise<string[]>;
|
|
125
|
+
}
|