@wardby/cli 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +34 -4
- package/README.md +183 -71
- package/dist/claude-coding-worker/driver.d.ts +7 -1
- package/dist/claude-coding-worker/driver.js +31 -2
- package/dist/claude-coding-worker/main.js +5 -2
- package/dist/claude-coding-worker/tool-socket.d.ts +9 -0
- package/dist/claude-coding-worker/tool-socket.js +26 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +13 -4
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +219 -29
- package/dist/coding/collect-exclude.d.ts +25 -0
- package/dist/coding/collect-exclude.js +76 -0
- package/dist/coding/profile.d.ts +67 -22
- package/dist/coding/profile.js +58 -25
- package/dist/coding/protected-path-wording.d.ts +24 -0
- package/dist/coding/protected-path-wording.js +55 -0
- package/dist/coding/protected-paths.d.ts +31 -0
- package/dist/coding/protected-paths.js +48 -0
- package/dist/coding/protocol.d.ts +99 -3
- package/dist/coding/protocol.js +155 -4
- package/dist/coding/registry/adapters.d.ts +2 -0
- package/dist/coding/registry/adapters.js +9 -0
- package/dist/coding/registry/allowlist.d.ts +9 -0
- package/dist/coding/registry/allowlist.js +28 -0
- package/dist/coding/registry/json-scan.d.ts +55 -0
- package/dist/coding/registry/json-scan.js +191 -0
- package/dist/coding/registry/lockfiles.d.ts +6 -0
- package/dist/coding/registry/lockfiles.js +89 -0
- package/dist/coding/registry/npm-lockfile.d.ts +9 -0
- package/dist/coding/registry/npm-lockfile.js +73 -0
- package/dist/coding/registry/npm-plan.d.ts +29 -0
- package/dist/coding/registry/npm-plan.js +289 -0
- package/dist/coding/registry/npm.d.ts +7 -0
- package/dist/coding/registry/npm.js +252 -0
- package/dist/coding/registry/pypi.d.ts +4 -0
- package/dist/coding/registry/pypi.js +210 -0
- package/dist/coding/registry/report.d.ts +37 -0
- package/dist/coding/registry/report.js +31 -0
- package/dist/coding/registry/token.d.ts +4 -0
- package/dist/coding/registry/token.js +7 -0
- package/dist/coding/registry/types.d.ts +286 -0
- package/dist/coding/registry/types.js +19 -0
- package/dist/coding/registry/worker-config.d.ts +14 -0
- package/dist/coding/registry/worker-config.js +31 -0
- package/dist/coding/services/builtins.d.ts +22 -0
- package/dist/coding/services/builtins.js +85 -0
- package/dist/coding/services/catalog.d.ts +443 -0
- package/dist/coding/services/catalog.js +159 -0
- package/dist/coding/services/declaration.d.ts +11 -0
- package/dist/coding/services/declaration.js +114 -0
- package/dist/coding/services/note.d.ts +8 -0
- package/dist/coding/services/note.js +15 -0
- package/dist/coding/services/resolve.d.ts +25 -0
- package/dist/coding/services/resolve.js +50 -0
- package/dist/coding/services/wording.d.ts +25 -0
- package/dist/coding/services/wording.js +70 -0
- package/dist/coding-proxy/main.js +24 -4
- package/dist/coding-worker/artifact.d.ts +18 -0
- package/dist/coding-worker/artifact.js +48 -6
- package/dist/coding-worker/debug-trace.d.ts +37 -0
- package/dist/coding-worker/debug-trace.js +117 -0
- package/dist/coding-worker/driver.d.ts +14 -1
- package/dist/coding-worker/driver.js +106 -14
- package/dist/coding-worker/errors.d.ts +7 -0
- package/dist/coding-worker/errors.js +26 -0
- package/dist/coding-worker/main.js +13 -4
- package/dist/coding-worker/sdk.d.ts +2 -2
- package/dist/coding-worker/sdk.js +7 -2
- package/dist/coding-worker/types.d.ts +3 -0
- package/dist/config/providers.d.ts +41 -0
- package/dist/config/providers.js +66 -0
- package/dist/core/budget-groups.d.ts +109 -6
- package/dist/core/budget-groups.js +125 -19
- package/dist/core/budget-wording.d.ts +22 -0
- package/dist/core/budget-wording.js +55 -0
- package/dist/core/coding-queue.d.ts +1 -1
- package/dist/core/datastores.d.ts +1 -1
- package/dist/core/datastores.js +18 -2
- package/dist/core/db.d.ts +40 -2
- package/dist/core/db.js +75 -2
- package/dist/core/dispatch.d.ts +49 -7
- package/dist/core/dispatch.js +290 -45
- package/dist/core/engine-native.js +27 -10
- package/dist/core/grants.d.ts +86 -0
- package/dist/core/grants.js +126 -0
- package/dist/core/host-events.d.ts +49 -0
- package/dist/core/host-events.js +257 -0
- package/dist/core/host-identity-links.d.ts +54 -0
- package/dist/core/host-identity-links.js +189 -0
- package/dist/core/host-status.d.ts +61 -0
- package/dist/core/host-status.js +211 -0
- package/dist/core/http-runtime.js +3 -4
- package/dist/core/in-flight-runs.d.ts +8 -0
- package/dist/core/in-flight-runs.js +56 -0
- package/dist/core/lease.d.ts +1 -1
- package/dist/core/private-directory.d.ts +20 -0
- package/dist/core/private-directory.js +36 -0
- package/dist/core/provider-wording.d.ts +12 -0
- package/dist/core/provider-wording.js +44 -0
- package/dist/core/reconciler.d.ts +39 -3
- package/dist/core/reconciler.js +86 -2
- package/dist/core/repo-access.d.ts +99 -0
- package/dist/core/repo-access.js +136 -0
- package/dist/core/review-host-checks.d.ts +11 -0
- package/dist/core/review-host-checks.js +41 -0
- package/dist/core/review-host-tools.d.ts +47 -0
- package/dist/core/review-host-tools.js +347 -0
- package/dist/core/run-heartbeat.d.ts +27 -0
- package/dist/core/run-heartbeat.js +54 -0
- package/dist/core/runner.d.ts +31 -9
- package/dist/core/runner.js +237 -40
- package/dist/core/scheduler.d.ts +1 -1
- package/dist/core/secrets.d.ts +12 -3
- package/dist/core/secrets.js +25 -6
- package/dist/core/subagent-memory-tools.d.ts +2 -2
- package/dist/core/subagent-memory-tools.js +16 -3
- package/dist/core/tool-admin.d.ts +81 -0
- package/dist/core/tool-admin.js +129 -0
- package/dist/core/tool-names.d.ts +42 -0
- package/dist/core/tool-names.js +64 -0
- package/dist/core/untrusted-content.d.ts +32 -0
- package/dist/core/untrusted-content.js +72 -0
- package/dist/core/webhooks.d.ts +9 -2
- package/dist/core/webhooks.js +23 -2
- package/dist/generated/prisma/browser.d.ts +328 -0
- package/dist/generated/prisma/browser.js +17 -0
- package/dist/generated/prisma/client.d.ts +347 -0
- package/dist/generated/prisma/client.js +34 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +839 -0
- package/dist/generated/prisma/commonInputTypes.js +10 -0
- package/dist/generated/prisma/enums.d.ts +59 -0
- package/dist/generated/prisma/enums.js +59 -0
- package/dist/generated/prisma/internal/class.d.ts +605 -0
- package/dist/generated/prisma/internal/class.js +49 -0
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +4494 -0
- package/dist/generated/prisma/internal/prismaNamespace.js +628 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +635 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +599 -0
- package/dist/generated/prisma/models/Agent.d.ts +3560 -0
- package/dist/generated/prisma/models/Agent.js +1 -0
- package/dist/generated/prisma/models/AgentDatastore.d.ts +1210 -0
- package/dist/generated/prisma/models/AgentDatastore.js +1 -0
- package/dist/generated/prisma/models/AgentMemory.d.ts +986 -0
- package/dist/generated/prisma/models/AgentMemory.js +1 -0
- package/dist/generated/prisma/models/AgentRepository.d.ts +1425 -0
- package/dist/generated/prisma/models/AgentRepository.js +1 -0
- package/dist/generated/prisma/models/AgentSecret.d.ts +1212 -0
- package/dist/generated/prisma/models/AgentSecret.js +1 -0
- package/dist/generated/prisma/models/AgentSubAgent.d.ts +1217 -0
- package/dist/generated/prisma/models/AgentSubAgent.js +1 -0
- package/dist/generated/prisma/models/AgentTool.d.ts +1403 -0
- package/dist/generated/prisma/models/AgentTool.js +1 -0
- package/dist/generated/prisma/models/AuthFormChallenge.d.ts +1298 -0
- package/dist/generated/prisma/models/AuthFormChallenge.js +1 -0
- package/dist/generated/prisma/models/AuthLoginKey.d.ts +1245 -0
- package/dist/generated/prisma/models/AuthLoginKey.js +1 -0
- package/dist/generated/prisma/models/AuthRateLimit.d.ts +979 -0
- package/dist/generated/prisma/models/AuthRateLimit.js +1 -0
- package/dist/generated/prisma/models/AuthSession.d.ts +1376 -0
- package/dist/generated/prisma/models/AuthSession.js +1 -0
- package/dist/generated/prisma/models/AuthUser.d.ts +1700 -0
- package/dist/generated/prisma/models/AuthUser.js +1 -0
- package/dist/generated/prisma/models/BudgetGroup.d.ts +1548 -0
- package/dist/generated/prisma/models/BudgetGroup.js +1 -0
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +1681 -0
- package/dist/generated/prisma/models/CodingAgentProfile.js +1 -0
- package/dist/generated/prisma/models/CodingProxyRequest.d.ts +1749 -0
- package/dist/generated/prisma/models/CodingProxyRequest.js +1 -0
- package/dist/generated/prisma/models/CodingProxySession.d.ts +1626 -0
- package/dist/generated/prisma/models/CodingProxySession.js +1 -0
- package/dist/generated/prisma/models/CodingRun.d.ts +3583 -0
- package/dist/generated/prisma/models/CodingRun.js +1 -0
- package/dist/generated/prisma/models/CodingService.d.ts +1348 -0
- package/dist/generated/prisma/models/CodingService.js +1 -0
- package/dist/generated/prisma/models/Datastore.d.ts +1434 -0
- package/dist/generated/prisma/models/Datastore.js +1 -0
- package/dist/generated/prisma/models/DatastoreEntry.d.ts +1314 -0
- package/dist/generated/prisma/models/DatastoreEntry.js +1 -0
- package/dist/generated/prisma/models/HostEventDelivery.d.ts +946 -0
- package/dist/generated/prisma/models/HostEventDelivery.js +1 -0
- package/dist/generated/prisma/models/HostIdentity.d.ts +1232 -0
- package/dist/generated/prisma/models/HostIdentity.js +1 -0
- package/dist/generated/prisma/models/HostIdentityLinkRequest.d.ts +1473 -0
- package/dist/generated/prisma/models/HostIdentityLinkRequest.js +1 -0
- package/dist/generated/prisma/models/OAuthAuthorizationCode.d.ts +1526 -0
- package/dist/generated/prisma/models/OAuthAuthorizationCode.js +1 -0
- package/dist/generated/prisma/models/OAuthAuthorizationRequest.d.ts +1350 -0
- package/dist/generated/prisma/models/OAuthAuthorizationRequest.js +1 -0
- package/dist/generated/prisma/models/OAuthClient.d.ts +1289 -0
- package/dist/generated/prisma/models/OAuthClient.js +1 -0
- package/dist/generated/prisma/models/OAuthFamily.d.ts +1540 -0
- package/dist/generated/prisma/models/OAuthFamily.js +1 -0
- package/dist/generated/prisma/models/OAuthGrant.d.ts +1280 -0
- package/dist/generated/prisma/models/OAuthGrant.js +1 -0
- package/dist/generated/prisma/models/Principal.d.ts +2245 -0
- package/dist/generated/prisma/models/Principal.js +1 -0
- package/dist/generated/prisma/models/RegistryAllowance.d.ts +1148 -0
- package/dist/generated/prisma/models/RegistryAllowance.js +1 -0
- package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +1219 -0
- package/dist/generated/prisma/models/RegistryApprovedVersion.js +1 -0
- package/dist/generated/prisma/models/RegistryFetch.d.ts +1428 -0
- package/dist/generated/prisma/models/RegistryFetch.js +1 -0
- package/dist/generated/prisma/models/RegistryPlanRefusal.d.ts +1294 -0
- package/dist/generated/prisma/models/RegistryPlanRefusal.js +1 -0
- package/dist/generated/prisma/models/RegistryVersionFact.d.ts +1085 -0
- package/dist/generated/prisma/models/RegistryVersionFact.js +1 -0
- package/dist/generated/prisma/models/ResourceGrant.d.ts +1437 -0
- package/dist/generated/prisma/models/ResourceGrant.js +1 -0
- package/dist/generated/prisma/models/Run.d.ts +2669 -0
- package/dist/generated/prisma/models/Run.js +1 -0
- package/dist/generated/prisma/models/RunHostCheck.d.ts +1239 -0
- package/dist/generated/prisma/models/RunHostCheck.js +1 -0
- package/dist/generated/prisma/models/RunHostStatus.d.ts +1315 -0
- package/dist/generated/prisma/models/RunHostStatus.js +1 -0
- package/dist/generated/prisma/models/SchedulerLease.d.ts +970 -0
- package/dist/generated/prisma/models/SchedulerLease.js +1 -0
- package/dist/generated/prisma/models/Secret.d.ts +1399 -0
- package/dist/generated/prisma/models/Secret.js +1 -0
- package/dist/generated/prisma/models/SecretElicitationOutcome.d.ts +973 -0
- package/dist/generated/prisma/models/SecretElicitationOutcome.js +1 -0
- package/dist/generated/prisma/models/Task.d.ts +1176 -0
- package/dist/generated/prisma/models/Task.js +1 -0
- package/dist/generated/prisma/models/Tool.d.ts +1490 -0
- package/dist/generated/prisma/models/Tool.js +1 -0
- package/dist/generated/prisma/models/Webhook.d.ts +1386 -0
- package/dist/generated/prisma/models/Webhook.js +1 -0
- package/dist/generated/prisma/models.d.ts +45 -0
- package/dist/generated/prisma/models.js +1 -0
- package/dist/help/build.d.ts +1 -0
- package/dist/help/build.js +9 -0
- package/dist/help/catalog.d.ts +24 -0
- package/dist/help/catalog.js +160 -0
- package/dist/help/cli.d.ts +2 -0
- package/dist/help/cli.js +65 -0
- package/dist/help/runtime.d.ts +3 -0
- package/dist/help/runtime.js +44 -0
- package/dist/help/search.d.ts +9 -0
- package/dist/help/search.js +104 -0
- package/dist/help-index.json +660 -0
- package/dist/import/cli-args.js +3 -2
- package/dist/import/create.d.ts +6 -1
- package/dist/import/create.js +68 -14
- package/dist/import/index.d.ts +1 -1
- package/dist/import/index.js +19 -9
- package/dist/import/neutral-schema.d.ts +11 -11
- package/dist/mcp/auth/access.d.ts +70 -0
- package/dist/mcp/auth/access.js +58 -0
- package/dist/mcp/auth/grants-cli.d.ts +149 -0
- package/dist/mcp/auth/grants-cli.js +518 -0
- package/dist/mcp/auth/host-account-cli.d.ts +2 -0
- package/dist/mcp/auth/host-account-cli.js +47 -0
- package/dist/mcp/auth/ownership.d.ts +37 -63
- package/dist/mcp/auth/ownership.js +19 -14
- package/dist/mcp/auth/principal.d.ts +1 -1
- package/dist/mcp/auth/repo-authorization.d.ts +22 -0
- package/dist/mcp/auth/repo-authorization.js +51 -0
- package/dist/mcp/auth/resource-server.d.ts +32 -3
- package/dist/mcp/auth/resource-server.js +84 -3
- package/dist/mcp/auth/self-hosted/browser.js +22 -8
- package/dist/mcp/auth/self-hosted/cli.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/cli.js +47 -13
- package/dist/mcp/auth/self-hosted/credentials.d.ts +21 -3
- package/dist/mcp/auth/self-hosted/credentials.js +62 -4
- package/dist/mcp/auth/self-hosted/rate-limit.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/session.d.ts +3 -2
- package/dist/mcp/context.d.ts +28 -2
- package/dist/mcp/errors.d.ts +25 -6
- package/dist/mcp/errors.js +98 -0
- package/dist/mcp/host-events/github-ingress.d.ts +36 -0
- package/dist/mcp/host-events/github-ingress.js +92 -0
- package/dist/mcp/host-events/github-user-callback.d.ts +18 -0
- package/dist/mcp/host-events/github-user-callback.js +50 -0
- package/dist/mcp/index.d.ts +8 -1
- package/dist/mcp/index.js +106 -16
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +27 -9
- package/dist/mcp/shared/page-style.d.ts +16 -0
- package/dist/mcp/shared/page-style.js +129 -0
- package/dist/mcp/tasks/manager.d.ts +1 -1
- package/dist/mcp/tools/agents.js +447 -49
- package/dist/mcp/tools/budget-groups.js +3 -3
- package/dist/mcp/tools/datastore.js +23 -16
- package/dist/mcp/tools/grants.d.ts +2 -0
- package/dist/mcp/tools/grants.js +239 -0
- package/dist/mcp/tools/help.d.ts +5 -0
- package/dist/mcp/tools/help.js +67 -0
- package/dist/mcp/tools/host-accounts.d.ts +2 -0
- package/dist/mcp/tools/host-accounts.js +114 -0
- package/dist/mcp/tools/memory.d.ts +7 -1
- package/dist/mcp/tools/memory.js +5 -5
- package/dist/mcp/tools/repositories.d.ts +2 -0
- package/dist/mcp/tools/repositories.js +181 -0
- package/dist/mcp/tools/runs.d.ts +6 -0
- package/dist/mcp/tools/runs.js +60 -6
- package/dist/mcp/tools/scheduling.js +4 -7
- package/dist/mcp/tools/secret-elicitation-form.d.ts +1 -1
- package/dist/mcp/tools/secret-elicitation-form.js +10 -28
- package/dist/mcp/tools/secret-elicitation.d.ts +1 -1
- package/dist/mcp/tools/secrets.js +18 -6
- package/dist/mcp/tools/services.d.ts +2 -0
- package/dist/mcp/tools/services.js +222 -0
- package/dist/mcp/tools/subagents.js +53 -17
- package/dist/mcp/tools/tools.d.ts +41 -0
- package/dist/mcp/tools/tools.js +202 -41
- package/dist/mcp/tools/trigger.js +36 -6
- package/dist/mcp/tools/webhooks.js +15 -4
- package/dist/mcp/transport/streamable-http.d.ts +11 -1
- package/dist/mcp/transport/streamable-http.js +32 -2
- package/dist/mcp/unattended-schedules.d.ts +1 -1
- package/dist/mcp/webhooks/ingress.d.ts +1 -1
- package/dist/providers/auth/delegating.d.ts +19 -0
- package/dist/providers/auth/delegating.js +71 -0
- package/dist/providers/auth/index.d.ts +3 -1
- package/dist/providers/auth/index.js +11 -0
- package/dist/providers/auth/self-hosted.d.ts +4 -3
- package/dist/providers/auth/self-hosted.js +16 -4
- package/dist/providers/auth/types.d.ts +6 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +3 -0
- package/dist/providers/coding-proxy/memory-ledger.js +21 -2
- package/dist/providers/coding-proxy/metering.d.ts +4 -0
- package/dist/providers/coding-proxy/metering.js +28 -2
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +18 -1
- package/dist/providers/coding-proxy/prisma-ledger.js +50 -5
- package/dist/providers/coding-proxy/proxy.d.ts +13 -0
- package/dist/providers/coding-proxy/proxy.js +479 -18
- package/dist/providers/coding-proxy/registry/audit.d.ts +131 -0
- package/dist/providers/coding-proxy/registry/audit.js +380 -0
- package/dist/providers/coding-proxy/registry/bounded-fetch.d.ts +16 -0
- package/dist/providers/coding-proxy/registry/bounded-fetch.js +77 -0
- package/dist/providers/coding-proxy/registry/plan.d.ts +58 -0
- package/dist/providers/coding-proxy/registry/plan.js +304 -0
- package/dist/providers/coding-proxy/registry/prisma-store.d.ts +34 -0
- package/dist/providers/coding-proxy/registry/prisma-store.js +151 -0
- package/dist/providers/coding-proxy/registry/service.d.ts +213 -0
- package/dist/providers/coding-proxy/registry/service.js +1137 -0
- package/dist/providers/coding-proxy/registry/store.d.ts +127 -0
- package/dist/providers/coding-proxy/registry/store.js +70 -0
- package/dist/providers/coding-proxy/runtime.d.ts +18 -1
- package/dist/providers/coding-proxy/runtime.js +63 -0
- package/dist/providers/coding-proxy/secure-fetch.js +0 -1
- package/dist/providers/coding-proxy/server.d.ts +11 -0
- package/dist/providers/coding-proxy/server.js +163 -0
- package/dist/providers/coding-proxy/types.d.ts +15 -0
- package/dist/providers/datastore/postgres.d.ts +1 -1
- package/dist/providers/engine/types.d.ts +10 -0
- package/dist/providers/executor/build.d.ts +3 -3
- package/dist/providers/executor/composition.d.ts +4 -1
- package/dist/providers/executor/composition.js +19 -0
- package/dist/providers/executor/container.d.ts +106 -4
- package/dist/providers/executor/container.js +305 -22
- package/dist/providers/executor/dbos.d.ts +3 -4
- package/dist/providers/executor/in-process.d.ts +2 -3
- package/dist/providers/executor/routing.d.ts +7 -0
- package/dist/providers/executor/routing.js +13 -0
- package/dist/providers/executor/types.d.ts +22 -0
- package/dist/providers/jobs/claude-tool-setup.d.ts +23 -0
- package/dist/providers/jobs/claude-tool-setup.js +50 -0
- package/dist/providers/jobs/collect-prune.d.ts +7 -0
- package/dist/providers/jobs/collect-prune.js +27 -0
- package/dist/providers/jobs/docker-isolation.d.ts +48 -3
- package/dist/providers/jobs/docker-isolation.js +213 -22
- package/dist/providers/jobs/docker-services.d.ts +35 -0
- package/dist/providers/jobs/docker-services.js +191 -0
- package/dist/providers/jobs/docker.d.ts +60 -2
- package/dist/providers/jobs/docker.js +313 -50
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +1 -0
- package/dist/providers/jobs/fake-kubernetes-api.js +12 -3
- package/dist/providers/jobs/kubernetes-isolation.d.ts +17 -2
- package/dist/providers/jobs/kubernetes-isolation.js +238 -57
- package/dist/providers/jobs/kubernetes-platform.d.ts +10 -4
- package/dist/providers/jobs/kubernetes-platform.js +11 -5
- package/dist/providers/jobs/kubernetes-preflight.js +3 -0
- package/dist/providers/jobs/kubernetes.d.ts +21 -2
- package/dist/providers/jobs/kubernetes.js +117 -31
- package/dist/providers/jobs/types.d.ts +20 -0
- package/dist/providers/llm/anthropic.js +6 -2
- package/dist/providers/llm/bedrock.js +2 -1
- package/dist/providers/llm/claude-messages.d.ts +5 -1
- package/dist/providers/llm/claude-messages.js +1 -0
- package/dist/providers/llm/claude-provider.d.ts +3 -1
- package/dist/providers/llm/claude-provider.js +5 -1
- package/dist/providers/llm/index.d.ts +1 -1
- package/dist/providers/llm/index.js +1 -1
- package/dist/providers/llm/pricing-anthropic.d.ts +10 -0
- package/dist/providers/llm/pricing-anthropic.js +32 -14
- package/dist/providers/llm/pricing-bedrock-claude.d.ts +8 -0
- package/dist/providers/llm/pricing-bedrock-claude.js +9 -0
- package/dist/providers/llm/routing.d.ts +10 -1
- package/dist/providers/llm/routing.js +18 -0
- package/dist/providers/llm/types.d.ts +12 -0
- package/dist/providers/llm/types.js +8 -1
- package/dist/providers/memory/postgres.d.ts +1 -1
- package/dist/providers/review-host/diff-lines.d.ts +16 -0
- package/dist/providers/review-host/diff-lines.js +59 -0
- package/dist/providers/review-host/github-events.d.ts +6 -0
- package/dist/providers/review-host/github-events.js +180 -0
- package/dist/providers/review-host/github-user-auth.d.ts +38 -0
- package/dist/providers/review-host/github-user-auth.js +128 -0
- package/dist/providers/review-host/github.d.ts +57 -0
- package/dist/providers/review-host/github.js +567 -0
- package/dist/providers/review-host/index.d.ts +12 -0
- package/dist/providers/review-host/index.js +30 -0
- package/dist/providers/review-host/review-format.d.ts +19 -0
- package/dist/providers/review-host/review-format.js +59 -0
- package/dist/providers/review-host/types.d.ts +284 -0
- package/dist/providers/review-host/types.js +24 -0
- package/dist/providers/vcs/git.d.ts +16 -6
- package/dist/providers/vcs/git.js +79 -14
- package/dist/providers/vcs/github.d.ts +74 -3
- package/dist/providers/vcs/github.js +195 -15
- package/dist/providers/vcs/types.d.ts +42 -4
- package/dist/quickstart/index.js +34 -32
- package/dist/quickstart/migrate.d.ts +23 -0
- package/dist/quickstart/migrate.js +125 -0
- package/dist/sandbox/fetch-policy.d.ts +20 -2
- package/dist/sandbox/fetch-policy.js +64 -3
- package/dist/sandbox/host-functions.d.ts +9 -1
- package/dist/sandbox/host-functions.js +12 -5
- package/dist/serve.js +1 -1
- package/dist/wardby-bin.js +6 -0
- package/docs/README.md +30 -0
- package/docs/architecture-runtime.md +90 -0
- package/docs/assets/brand/wardby-icon-512.png +0 -0
- package/docs/assets/brand/wardby-icon.svg +16 -0
- package/docs/assets/brand/wardby-mascot-profile-512.png +0 -0
- package/docs/assets/brand/wardby-mascot.png +0 -0
- package/docs/assets/brand/wardby-mascot.svg +5 -0
- package/docs/assets/wardby-workflow.svg +106 -0
- package/docs/code-review-agents.md +481 -0
- package/docs/coding-agent-setup.md +172 -0
- package/docs/coding-packages.md +455 -0
- package/docs/coding-services.md +300 -0
- package/docs/coding-worker-byo-images.md +98 -0
- package/docs/coding-worker-isolation.md +1061 -0
- package/docs/getting-started-gke.md +615 -0
- package/docs/getting-started-identity-provider.md +308 -0
- package/docs/getting-started.md +133 -0
- package/docs/observability.md +53 -0
- package/docs/release-verification.md +66 -0
- package/docs/security-deployment.md +657 -0
- package/help/code-review-agents.md +31 -0
- package/help/coding-packages.md +31 -0
- package/help/coding-services.md +71 -0
- package/help/creating-agents.md +68 -0
- package/help/deploy-gke.md +39 -0
- package/help/deployment-targets.md +39 -0
- package/help/errors/budget-group-exhausted.md +25 -0
- package/help/errors/docker-isolation-unsupported.md +26 -0
- package/help/errors/protected-path.md +45 -0
- package/help/errors/repo-access.md +27 -0
- package/help/errors/service-declaration-invalid.md +27 -0
- package/help/errors/service-declaration-unavailable.md +25 -0
- package/help/errors/service-launcher-unsupported.md +30 -0
- package/help/errors/service-not-allowed.md +27 -0
- package/help/errors/service-unknown.md +23 -0
- package/help/errors/service-unready.md +49 -0
- package/help/getting-started.md +31 -0
- package/help/github.md +30 -0
- package/help/identity-and-access.md +39 -0
- package/help/mcp.md +30 -0
- package/help/native-capabilities.md +30 -0
- package/help/observability.md +41 -0
- package/help/operating-agents.md +30 -0
- package/help/security.md +27 -0
- package/help/troubleshooting/budgets.md +26 -0
- package/help/troubleshooting/coding-workers.md +47 -0
- package/help/troubleshooting/repository-access.md +27 -0
- package/package.json +30 -11
- package/prisma/migrate.config.mjs +20 -0
- package/prisma/migrations/20260925010000_coding_collect_exclude/migration.sql +8 -0
- package/prisma/migrations/20260925015000_allowed_egress_default/migration.sql +8 -0
- package/prisma/migrations/20260925020000_coding_package_registry/migration.sql +55 -0
- package/prisma/migrations/20260925030000_tool_name_per_owner/migration.sql +11 -0
- package/prisma/migrations/20260926010000_run_trigger_host_event/migration.sql +7 -0
- package/prisma/migrations/20260926020000_code_review_hosts/migration.sql +53 -0
- package/prisma/migrations/20260926030000_auth_user_roles/migration.sql +9 -0
- package/prisma/migrations/20260926040000_agent_effort/migration.sql +6 -0
- package/prisma/migrations/20260926050000_registry_lockfile_plan/migration.sql +32 -0
- package/prisma/migrations/20260926050000_repo_access_authorization/migration.sql +82 -0
- package/prisma/migrations/20260926060000_registry_plan_refusal/migration.sql +19 -0
- package/prisma/migrations/20260926100000_registry_plan_refusal_published_at/migration.sql +5 -0
- package/prisma/migrations/20260926190000_run_host_status/migration.sql +18 -0
- package/prisma/migrations/20260926210000_run_host_status_at_dispatch/migration.sql +5 -0
- package/prisma/migrations/20260927010000_resource_grants/migration.sql +72 -0
- package/prisma/migrations/20260927020000_proxy_session_budget_exhausted/migration.sql +3 -0
- package/prisma/migrations/20260927030000_coding_debug_trace/migration.sql +4 -0
- package/prisma/migrations/20260927040000_proxy_session_upstream_failure/migration.sql +3 -0
- package/prisma/migrations/20260927050000_coding_run_services/migration.sql +74 -0
- package/prisma/migrations/20260928000000_coding_run_tool_image/migration.sql +5 -0
- package/prisma/schema.prisma +417 -23
|
@@ -1,18 +1,58 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { normalizeCollectExclusions } from "../../coding/collect-exclude.js";
|
|
3
|
+
import { pruneCollectExcluded } from "./collect-prune.js";
|
|
2
4
|
import { spawn } from "node:child_process";
|
|
3
5
|
import { lstat, mkdir, mkdtemp, open, opendir, readdir, readFile, readlink, realpath, rename, rm, unlink, } from "node:fs/promises";
|
|
4
6
|
import { dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
5
7
|
import { logger } from "../../core/logger.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
+
import { ensurePrivateDirectory } from "../../core/private-directory.js";
|
|
9
|
+
import { readBoundedRegularFile } from "../../coding-worker/artifact.js";
|
|
10
|
+
import { parseCodingAgentOutputJson, redactAndTruncate, MAX_CODING_ARTIFACT_BYTES, MAX_CODING_OUTPUT_ISSUES, SAFE_CODING_OUTPUT_ISSUE, } from "../../coding/protocol.js";
|
|
11
|
+
import { assertDockerHostSupportsIsolation, assertClaudeAgentContainerInspection, assertClaudeToolRunnerContainerInspection, assertIsolationNetworkInspection, assertKeeperContainerInspection, assertNetworkKeeperContainerInspection, assertProxyContainerInspection, assertStorageVolumeInspection, assertWorkerContainerInspection, buildDockerIsolationPlan, CLAUDE_TOOL_SETUP_ENV, dockerSupportsServicesFor, } from "./docker-isolation.js";
|
|
12
|
+
import { serviceUnreadyError } from "../../coding/services/wording.js";
|
|
13
|
+
import { assertServiceContainerInspection, buildDockerServicePlan, dockerServiceContainerNames, } from "./docker-services.js";
|
|
14
|
+
import { claudeToolSetup } from "./claude-tool-setup.js";
|
|
8
15
|
import { replaceDirectoryFromStaging } from "./workspace-swap.js";
|
|
9
16
|
const BACKEND = "docker";
|
|
10
17
|
const STATE_SCHEMA_VERSION = 1;
|
|
11
18
|
const MAX_DOCKER_OUTPUT_BYTES = 1024 * 1024;
|
|
12
19
|
const MAX_DOCKER_SEED_DIAGNOSTIC_BYTES = 4 * 1024;
|
|
13
20
|
const MAX_WORKSPACE_ENTRIES = 100_000;
|
|
21
|
+
/** How long one service image pull may take before the run fails as service_unready. */
|
|
22
|
+
export const SERVICE_IMAGE_PULL_TIMEOUT_MS = 300_000;
|
|
23
|
+
/**
|
|
24
|
+
* The default bound on a run's whole service start-up (every service's create, start, inspection and
|
|
25
|
+
* readiness probing; image pulls excluded), matching the Kubernetes launcher's pod-start bound.
|
|
26
|
+
*/
|
|
27
|
+
export const DEFAULT_SERVICE_READY_TIMEOUT_MS = 120_000;
|
|
28
|
+
const MAX_SERVICE_PROBE_OUTPUT_BYTES = 64 * 1024;
|
|
14
29
|
const TERMINAL_PHASES = new Set(["succeeded", "failed", "stopped", "lost", "removed"]);
|
|
15
30
|
export const SAFE_WORKER_DIAGNOSTIC = /^(?:worker_[a-z_]+|coding_[a-z_]+|wardby_[a-z_]+)$/;
|
|
31
|
+
/**
|
|
32
|
+
* Worker output is untrusted: recognizes only the fixed `{"error": code}` line,
|
|
33
|
+
* plus an optional `issues` list whose every entry must pass the shared pattern.
|
|
34
|
+
* A list with any entry that does not is dropped whole rather than filtered, so
|
|
35
|
+
* a malformed worker cannot smuggle a partial value through.
|
|
36
|
+
*/
|
|
37
|
+
export function parseWorkerDiagnosticLine(line) {
|
|
38
|
+
let value;
|
|
39
|
+
try {
|
|
40
|
+
value = JSON.parse(line);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
if (typeof value?.error !== "string" || !SAFE_WORKER_DIAGNOSTIC.test(value.error))
|
|
46
|
+
return undefined;
|
|
47
|
+
const issues = value.issues;
|
|
48
|
+
const safeIssues = Array.isArray(issues) &&
|
|
49
|
+
issues.length > 0 &&
|
|
50
|
+
issues.length <= MAX_CODING_OUTPUT_ISSUES &&
|
|
51
|
+
issues.every((issue) => typeof issue === "string" && SAFE_CODING_OUTPUT_ISSUE.test(issue))
|
|
52
|
+
? issues
|
|
53
|
+
: undefined;
|
|
54
|
+
return { diagnostic: value.error, ...(safeIssues ? { diagnosticIssues: safeIssues } : {}) };
|
|
55
|
+
}
|
|
16
56
|
const dockerLog = logger.child({ module: "docker-jobs" });
|
|
17
57
|
/**
|
|
18
58
|
* Docker failures never include daemon output in their public message -- that
|
|
@@ -54,7 +94,7 @@ export class NodeDockerCommandRunner {
|
|
|
54
94
|
if (args.some((argument) => argument.includes("\0")))
|
|
55
95
|
throw new Error("docker_argument_invalid");
|
|
56
96
|
const extraEnv = options.env ?? {};
|
|
57
|
-
if (Object.keys(extraEnv).some((key) => key !== "WARDBY_RUN_CAPABILITY"))
|
|
97
|
+
if (Object.keys(extraEnv).some((key) => key !== "WARDBY_RUN_CAPABILITY" && key !== CLAUDE_TOOL_SETUP_ENV))
|
|
58
98
|
throw new Error("docker_environment_invalid");
|
|
59
99
|
const env = {
|
|
60
100
|
PATH: this.path,
|
|
@@ -73,6 +113,13 @@ export class NodeDockerCommandRunner {
|
|
|
73
113
|
rejectPromise(new DockerCommandError(null));
|
|
74
114
|
return;
|
|
75
115
|
}
|
|
116
|
+
let timedOut = false;
|
|
117
|
+
const timer = options.timeoutMs === undefined
|
|
118
|
+
? undefined
|
|
119
|
+
: setTimeout(() => {
|
|
120
|
+
timedOut = true;
|
|
121
|
+
child.kill("SIGKILL");
|
|
122
|
+
}, options.timeoutMs);
|
|
76
123
|
const stdout = [];
|
|
77
124
|
const stderr = [];
|
|
78
125
|
let bytes = 0;
|
|
@@ -93,6 +140,11 @@ export class NodeDockerCommandRunner {
|
|
|
93
140
|
spawnFailed = true;
|
|
94
141
|
});
|
|
95
142
|
child.once("close", (code) => {
|
|
143
|
+
if (timer)
|
|
144
|
+
clearTimeout(timer);
|
|
145
|
+
if (timedOut) {
|
|
146
|
+
return rejectPromise(new DockerCommandError(code, false, false, { subcommand: args[0], stderr: "timed out" }));
|
|
147
|
+
}
|
|
96
148
|
if (exceeded)
|
|
97
149
|
return rejectPromise(new DockerCommandError(code, false, true));
|
|
98
150
|
if (spawnFailed)
|
|
@@ -229,7 +281,7 @@ export class NodeDockerArtifactTransfer {
|
|
|
229
281
|
});
|
|
230
282
|
await docker.run(["container", "cp", sourceFile, `${container}:/run/wardby/storage/input/input.json`]);
|
|
231
283
|
}
|
|
232
|
-
async materializeDirectory(container, source, destination, maxBytes) {
|
|
284
|
+
async materializeDirectory(container, source, destination, maxBytes, exclusions) {
|
|
233
285
|
await replaceDirectoryFromStaging(destination, maxBytes, "docker_workspace_destination_invalid", async (staging) => {
|
|
234
286
|
await new NodeDockerCommandRunner({ dockerBinary: this.dockerBinary, homeDir: "/tmp", path: this.path }).run([
|
|
235
287
|
"container",
|
|
@@ -237,6 +289,8 @@ export class NodeDockerArtifactTransfer {
|
|
|
237
289
|
`${container}:${source}/.`,
|
|
238
290
|
staging,
|
|
239
291
|
]);
|
|
292
|
+
// Before replaceDirectoryFromStaging validates: excluded folders never count.
|
|
293
|
+
await pruneCollectExcluded(staging, exclusions);
|
|
240
294
|
});
|
|
241
295
|
}
|
|
242
296
|
}
|
|
@@ -353,6 +407,42 @@ function resourceLabels(record) {
|
|
|
353
407
|
function labelsMatch(actual, expected) {
|
|
354
408
|
return Object.entries(expected).every(([key, value]) => actual?.[key] === value);
|
|
355
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* A run's service start-up budget: `budgetMs` from the start, extended by the time image pulls took,
|
|
412
|
+
* and never past the run's deadline.
|
|
413
|
+
*/
|
|
414
|
+
class ServiceStartBudget {
|
|
415
|
+
now;
|
|
416
|
+
budgetMs;
|
|
417
|
+
deadlineAt;
|
|
418
|
+
startedAt;
|
|
419
|
+
excludedMs = 0;
|
|
420
|
+
constructor(now, budgetMs, deadlineAt) {
|
|
421
|
+
this.now = now;
|
|
422
|
+
this.budgetMs = budgetMs;
|
|
423
|
+
this.deadlineAt = deadlineAt;
|
|
424
|
+
this.startedAt = now();
|
|
425
|
+
}
|
|
426
|
+
/** What is left of the budget, capped by the run's deadline; zero once either runs out. */
|
|
427
|
+
remainingMs() {
|
|
428
|
+
const now = this.now();
|
|
429
|
+
return Math.max(0, Math.min(this.startedAt + this.excludedMs + this.budgetMs - now, this.deadlineAt - now));
|
|
430
|
+
}
|
|
431
|
+
/** What is left before the run's deadline: the only bound (besides its own) on an image pull. */
|
|
432
|
+
untilDeadlineMs() {
|
|
433
|
+
return Math.max(0, this.deadlineAt - this.now());
|
|
434
|
+
}
|
|
435
|
+
exclude(milliseconds) {
|
|
436
|
+
this.excludedMs += Math.max(0, milliseconds);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
/** `coding_service_unready:<name>` (the executor's service_unready), keeping the Docker failure as the operator's cause. */
|
|
440
|
+
function serviceUnready(name, cause) {
|
|
441
|
+
const error = serviceUnreadyError(name);
|
|
442
|
+
if (cause !== undefined)
|
|
443
|
+
error.cause = cause;
|
|
444
|
+
return error;
|
|
445
|
+
}
|
|
356
446
|
function capabilityFromInspection(container) {
|
|
357
447
|
return container.Config?.Env?.find((value) => value.startsWith("WARDBY_RUN_CAPABILITY="))?.slice("WARDBY_RUN_CAPABILITY=".length);
|
|
358
448
|
}
|
|
@@ -390,6 +480,8 @@ export class DockerJobLauncher {
|
|
|
390
480
|
docker;
|
|
391
481
|
transfer;
|
|
392
482
|
now;
|
|
483
|
+
sleep;
|
|
484
|
+
serviceReadyTimeoutMs;
|
|
393
485
|
locks = new Map();
|
|
394
486
|
timers = new Map();
|
|
395
487
|
ready;
|
|
@@ -402,8 +494,17 @@ export class DockerJobLauncher {
|
|
|
402
494
|
this.docker = options.docker ?? new NodeDockerCommandRunner({ homeDir: join(this.stateRoot, ".home") });
|
|
403
495
|
this.transfer = options.transfer ?? new NodeDockerArtifactTransfer();
|
|
404
496
|
this.now = options.now ?? Date.now;
|
|
497
|
+
this.sleep =
|
|
498
|
+
options.sleep ?? ((milliseconds) => new Promise((resolvePromise) => setTimeout(resolvePromise, milliseconds)));
|
|
499
|
+
this.serviceReadyTimeoutMs = options.serviceReadyTimeoutMs ?? DEFAULT_SERVICE_READY_TIMEOUT_MS;
|
|
500
|
+
if (!Number.isFinite(this.serviceReadyTimeoutMs) || this.serviceReadyTimeoutMs <= 0)
|
|
501
|
+
throw new Error("docker_launcher_service_timeout_invalid");
|
|
405
502
|
this.ready = this.initialize();
|
|
406
503
|
}
|
|
504
|
+
/** Starts JobSpec.services (a network keeper plus one hardened container per service) for Codex and Claude Code runs. */
|
|
505
|
+
supportsServicesFor(provider) {
|
|
506
|
+
return dockerSupportsServicesFor(provider);
|
|
507
|
+
}
|
|
407
508
|
async launch(spec) {
|
|
408
509
|
await this.ready;
|
|
409
510
|
return this.withRun(spec.runId, async () => this.launchLocked(spec));
|
|
@@ -440,7 +541,7 @@ export class DockerJobLauncher {
|
|
|
440
541
|
if (current.phase === "failed" && !current.result.diagnostic) {
|
|
441
542
|
const diagnostic = await this.readWorkerFailureDiagnostic(current);
|
|
442
543
|
if (diagnostic) {
|
|
443
|
-
current.result = { ...current.result, diagnostic };
|
|
544
|
+
current.result = { ...current.result, ...diagnostic };
|
|
444
545
|
await this.writeRecord(current);
|
|
445
546
|
}
|
|
446
547
|
}
|
|
@@ -466,7 +567,9 @@ export class DockerJobLauncher {
|
|
|
466
567
|
if (resolve(destination) !== expected || !expected.startsWith(`${this.workspaceRoot}${sep}`)) {
|
|
467
568
|
throw new Error("docker_workspace_destination_invalid");
|
|
468
569
|
}
|
|
469
|
-
await this.transfer.materializeDirectory(this.keeperName(current), "/run/wardby/storage/workspace", expected, current.spec.limits.diskMb * 1024 * 1024
|
|
570
|
+
await this.transfer.materializeDirectory(this.keeperName(current), "/run/wardby/storage/workspace", expected, current.spec.limits.diskMb * 1024 * 1024,
|
|
571
|
+
// Names are always the current built-in list; only the paths come from the spec.
|
|
572
|
+
normalizeCollectExclusions(current.spec.collectExclude?.paths));
|
|
470
573
|
});
|
|
471
574
|
}
|
|
472
575
|
async stop(handle, _reason) {
|
|
@@ -500,7 +603,7 @@ export class DockerJobLauncher {
|
|
|
500
603
|
});
|
|
501
604
|
}
|
|
502
605
|
async initialize() {
|
|
503
|
-
await
|
|
606
|
+
await ensurePrivateDirectory(this.stateRoot);
|
|
504
607
|
await mkdir(join(this.stateRoot, ".home"), { recursive: true, mode: 0o700 });
|
|
505
608
|
await realpath(this.stateRoot);
|
|
506
609
|
const records = await this.allRecords();
|
|
@@ -530,6 +633,7 @@ export class DockerJobLauncher {
|
|
|
530
633
|
}
|
|
531
634
|
async launchLocked(spec) {
|
|
532
635
|
const plan = buildDockerIsolationPlan(spec, this.options.proxyContainer);
|
|
636
|
+
const services = buildDockerServicePlan(spec);
|
|
533
637
|
const specHash = stableSpecHash(spec);
|
|
534
638
|
const existing = await this.readRecord(spec.runId);
|
|
535
639
|
if (existing) {
|
|
@@ -554,7 +658,7 @@ export class DockerJobLauncher {
|
|
|
554
658
|
await this.refresh(existing);
|
|
555
659
|
return clone(existing.handle);
|
|
556
660
|
}
|
|
557
|
-
return this.provision(existing, plan, capability);
|
|
661
|
+
return this.provision(existing, plan, services, capability);
|
|
558
662
|
}
|
|
559
663
|
await this.validateInputArtifact(spec.inputArtifact);
|
|
560
664
|
const capability = ensureCapability(await this.options.resolveCapability(spec.runId));
|
|
@@ -573,7 +677,7 @@ export class DockerJobLauncher {
|
|
|
573
677
|
// This durable record is the idempotency fence before any Docker side effect.
|
|
574
678
|
await this.writeRecord(record);
|
|
575
679
|
try {
|
|
576
|
-
return await this.provision(record, plan, capability);
|
|
680
|
+
return await this.provision(record, plan, services, capability);
|
|
577
681
|
}
|
|
578
682
|
catch (error) {
|
|
579
683
|
await this.options
|
|
@@ -586,7 +690,7 @@ export class DockerJobLauncher {
|
|
|
586
690
|
throw error;
|
|
587
691
|
}
|
|
588
692
|
}
|
|
589
|
-
async provision(record, plan, capability) {
|
|
693
|
+
async provision(record, plan, services, capability) {
|
|
590
694
|
await this.assertHost();
|
|
591
695
|
const labels = resourceLabels(record);
|
|
592
696
|
await this.createAndAssert(appendLabels(plan.networkCreateArgs, labels), ["network", "inspect", plan.names.network], (value) => {
|
|
@@ -613,13 +717,21 @@ export class DockerJobLauncher {
|
|
|
613
717
|
await this.run(plan.proxyNetworkConnectArgs);
|
|
614
718
|
const proxy = await this.inspect(["container", "inspect", this.options.proxyContainer]);
|
|
615
719
|
assertProxyContainerInspection(proxy, record.runId);
|
|
720
|
+
// Built before anything starts, so a setup past the tool runner's bounds fails the launch early.
|
|
721
|
+
const toolSetup = record.spec.provider === "claude-code" ? claudeToolSetup(record.spec, capability) : undefined;
|
|
722
|
+
// Services first (a run with services only): the Codex worker and Claude Code's tool runner join
|
|
723
|
+
// the network keeper's namespace, so it must exist, and every service must pass readiness before
|
|
724
|
+
// anything that runs the run's commands starts.
|
|
725
|
+
const networkKeeperId = plan.networkKeeperCreateArgs
|
|
726
|
+
? await this.startServices(record, plan.networkKeeperCreateArgs, plan.names.networkKeeperContainer, services, labels)
|
|
727
|
+
: undefined;
|
|
616
728
|
if (plan.toolCreateArgs) {
|
|
617
729
|
await this.createAndAssert(appendLabels(plan.toolCreateArgs, labels), ["container", "inspect", plan.names.toolContainer], (value) => {
|
|
618
|
-
assertClaudeToolRunnerContainerInspection(value, record.spec);
|
|
730
|
+
assertClaudeToolRunnerContainerInspection(value, record.spec, toolSetup, networkKeeperId);
|
|
619
731
|
if (!labelsMatch(value.Config?.Labels, labels)) {
|
|
620
732
|
throw new Error("docker_resource_attestation_failed");
|
|
621
733
|
}
|
|
622
|
-
});
|
|
734
|
+
}, { env: { WARDBY_TOOL_SETUP: toolSetup } });
|
|
623
735
|
await this.startContainer(plan.names.toolContainer);
|
|
624
736
|
await this.waitForToolRunner(plan.names.toolContainer);
|
|
625
737
|
}
|
|
@@ -630,7 +742,7 @@ export class DockerJobLauncher {
|
|
|
630
742
|
assertClaudeAgentContainerInspection(inspected, record.spec, capability);
|
|
631
743
|
}
|
|
632
744
|
else {
|
|
633
|
-
assertWorkerContainerInspection(inspected, record.spec, capability);
|
|
745
|
+
assertWorkerContainerInspection(inspected, record.spec, capability, networkKeeperId);
|
|
634
746
|
}
|
|
635
747
|
if (!labelsMatch(inspected.Config?.Labels, labels))
|
|
636
748
|
throw new Error("docker_resource_attestation_failed");
|
|
@@ -641,6 +753,138 @@ export class DockerJobLauncher {
|
|
|
641
753
|
this.scheduleDeadline(record);
|
|
642
754
|
return clone(record.handle);
|
|
643
755
|
}
|
|
756
|
+
/**
|
|
757
|
+
* A run with services (docs/coding-services.md). The network keeper joins the run's internal
|
|
758
|
+
* network and owns the namespace; each service joins it and must pass its catalog readiness
|
|
759
|
+
* command before the next one starts, as Kubernetes starts native sidecars. The whole start-up is
|
|
760
|
+
* bounded (ServiceStartBudget): running out fails as coding_service_unready for the service being
|
|
761
|
+
* waited on. Returns the keeper's container ID, which Docker may report as the services' and
|
|
762
|
+
* worker's network mode.
|
|
763
|
+
*/
|
|
764
|
+
async startServices(record, keeperArgs, keeperName, services, labels) {
|
|
765
|
+
const budget = new ServiceStartBudget(this.now, this.serviceReadyTimeoutMs, record.deadlineAt);
|
|
766
|
+
const keeper = (await this.createAndAssert(appendLabels(keeperArgs, labels), ["container", "inspect", keeperName], (value) => {
|
|
767
|
+
const inspected = value;
|
|
768
|
+
assertNetworkKeeperContainerInspection(inspected, record.spec);
|
|
769
|
+
if (!labelsMatch(inspected.Config?.Labels, labels))
|
|
770
|
+
throw new Error("docker_resource_attestation_failed");
|
|
771
|
+
}));
|
|
772
|
+
const keeperId = keeper.Id;
|
|
773
|
+
if (!keeperId)
|
|
774
|
+
throw new Error("docker_resource_attestation_failed");
|
|
775
|
+
await this.startContainer(keeperName);
|
|
776
|
+
for (const planned of services) {
|
|
777
|
+
const name = planned.service.name;
|
|
778
|
+
if (budget.remainingMs() <= 0)
|
|
779
|
+
throw serviceUnready(name);
|
|
780
|
+
await this.ensureServiceImage(planned, budget);
|
|
781
|
+
if (budget.remainingMs() <= 0)
|
|
782
|
+
throw serviceUnready(name);
|
|
783
|
+
let createFailure;
|
|
784
|
+
try {
|
|
785
|
+
await this.createAndAssert(appendLabels(planned.createArgs, labels), ["container", "inspect", planned.container], (value) => {
|
|
786
|
+
const inspected = value;
|
|
787
|
+
assertServiceContainerInspection(inspected, record.spec, planned.service, keeperId);
|
|
788
|
+
if (!labelsMatch(inspected.Config?.Labels, labels))
|
|
789
|
+
throw new Error("docker_resource_attestation_failed");
|
|
790
|
+
}, undefined, (error) => {
|
|
791
|
+
createFailure = error;
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
catch (error) {
|
|
795
|
+
// createAndAssert tolerates a failed create (a crash retry may find it made), so a service
|
|
796
|
+
// Docker refused to create shows up as a failed inspection; the create's own failure is the
|
|
797
|
+
// useful cause, not that generic "not found". Attestation failures rethrow as is.
|
|
798
|
+
if (error instanceof DockerCommandError)
|
|
799
|
+
throw serviceUnready(name, createFailure ?? error);
|
|
800
|
+
throw error;
|
|
801
|
+
}
|
|
802
|
+
if (budget.remainingMs() <= 0)
|
|
803
|
+
throw serviceUnready(name);
|
|
804
|
+
try {
|
|
805
|
+
await this.startContainer(planned.container);
|
|
806
|
+
}
|
|
807
|
+
catch (error) {
|
|
808
|
+
throw serviceUnready(name, error);
|
|
809
|
+
}
|
|
810
|
+
await this.waitForServiceReady(planned, budget);
|
|
811
|
+
}
|
|
812
|
+
return keeperId;
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* A local copy of the digest-pinned image is used as is; otherwise it is pulled, bounded by its
|
|
816
|
+
* own limit and the run's deadline. Pull time does not count toward the start-up budget.
|
|
817
|
+
*/
|
|
818
|
+
async ensureServiceImage(planned, budget) {
|
|
819
|
+
try {
|
|
820
|
+
await this.run(["image", "inspect", "--format", "{{.Id}}", planned.service.image]);
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
catch {
|
|
824
|
+
// Missing (or unreadable): pull it by its digest below.
|
|
825
|
+
}
|
|
826
|
+
const untilDeadline = budget.untilDeadlineMs();
|
|
827
|
+
if (untilDeadline <= 0)
|
|
828
|
+
throw serviceUnready(planned.service.name);
|
|
829
|
+
const startedAt = this.now();
|
|
830
|
+
try {
|
|
831
|
+
await this.run(["image", "pull", "--quiet", planned.service.image], {
|
|
832
|
+
timeoutMs: Math.min(SERVICE_IMAGE_PULL_TIMEOUT_MS, untilDeadline),
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
catch (error) {
|
|
836
|
+
throw serviceUnready(planned.service.name, error);
|
|
837
|
+
}
|
|
838
|
+
finally {
|
|
839
|
+
budget.exclude(this.now() - startedAt);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* The catalog readiness command, like a Kubernetes startup probe: every periodSeconds, each
|
|
844
|
+
* attempt bounded by timeoutSeconds, failing after failureThreshold consecutive failures. A
|
|
845
|
+
* service that exited or vanished fails at once, and so does one still unready when the start-up
|
|
846
|
+
* budget runs out (each probe and wait is clipped to what is left of it). Probe output is never
|
|
847
|
+
* logged or kept, so these errors carry no cause.
|
|
848
|
+
*/
|
|
849
|
+
async waitForServiceReady(planned, budget) {
|
|
850
|
+
const { command, periodSeconds, timeoutSeconds, failureThreshold } = planned.service.readiness;
|
|
851
|
+
const name = planned.service.name;
|
|
852
|
+
let failures = 0;
|
|
853
|
+
for (;;) {
|
|
854
|
+
if (budget.remainingMs() <= 0)
|
|
855
|
+
throw serviceUnready(name);
|
|
856
|
+
let state;
|
|
857
|
+
try {
|
|
858
|
+
state = await this.inspect(["container", "inspect", planned.container]);
|
|
859
|
+
}
|
|
860
|
+
catch (error) {
|
|
861
|
+
if (error instanceof DockerCommandError)
|
|
862
|
+
throw serviceUnready(name);
|
|
863
|
+
throw error;
|
|
864
|
+
}
|
|
865
|
+
if (state.State?.Running !== true)
|
|
866
|
+
throw serviceUnready(name);
|
|
867
|
+
const remaining = budget.remainingMs();
|
|
868
|
+
if (remaining <= 0)
|
|
869
|
+
throw serviceUnready(name);
|
|
870
|
+
try {
|
|
871
|
+
await this.run(["container", "exec", planned.container, ...command], {
|
|
872
|
+
timeoutMs: Math.min(timeoutSeconds * 1_000, remaining),
|
|
873
|
+
maxOutputBytes: MAX_SERVICE_PROBE_OUTPUT_BYTES,
|
|
874
|
+
});
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
catch {
|
|
878
|
+
failures += 1;
|
|
879
|
+
if (failures >= failureThreshold)
|
|
880
|
+
throw serviceUnready(name);
|
|
881
|
+
}
|
|
882
|
+
const wait = Math.min(periodSeconds * 1_000, budget.remainingMs());
|
|
883
|
+
if (wait <= 0)
|
|
884
|
+
throw serviceUnready(name);
|
|
885
|
+
await this.sleep(wait);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
644
888
|
async refresh(record) {
|
|
645
889
|
if (isTerminal(record))
|
|
646
890
|
return;
|
|
@@ -674,7 +918,7 @@ export class DockerJobLauncher {
|
|
|
674
918
|
"inspect",
|
|
675
919
|
buildDockerIsolationPlan(record.spec, this.options.proxyContainer).names.toolContainer,
|
|
676
920
|
]);
|
|
677
|
-
assertClaudeToolRunnerContainerInspection(tool, record.spec);
|
|
921
|
+
assertClaudeToolRunnerContainerInspection(tool, record.spec, claudeToolSetup(record.spec, capability), await this.attestedNetworkKeeperId(record));
|
|
678
922
|
if (tool.State?.Running !== true || tool.State?.Status !== "running") {
|
|
679
923
|
record.phase = "failed";
|
|
680
924
|
record.result = { exitCode: 1, reason: "failed", diagnostic: "worker_tool_runner_failed" };
|
|
@@ -684,7 +928,7 @@ export class DockerJobLauncher {
|
|
|
684
928
|
}
|
|
685
929
|
}
|
|
686
930
|
else {
|
|
687
|
-
assertWorkerContainerInspection(inspection, record.spec, capability);
|
|
931
|
+
assertWorkerContainerInspection(inspection, record.spec, capability, await this.attestedNetworkKeeperId(record));
|
|
688
932
|
}
|
|
689
933
|
const phase = dockerState(inspection);
|
|
690
934
|
if (!phase || phase === "provisioning" || phase === "active")
|
|
@@ -697,28 +941,27 @@ export class DockerJobLauncher {
|
|
|
697
941
|
async stopRecord(record, timedOut) {
|
|
698
942
|
if (isTerminal(record))
|
|
699
943
|
return;
|
|
700
|
-
|
|
701
|
-
await this.run(["container", "stop", "--time", "10", record.handle.id]);
|
|
702
|
-
}
|
|
703
|
-
catch (error) {
|
|
704
|
-
if (!(error instanceof DockerCommandError && error.notFound))
|
|
705
|
-
throw new Error("docker_stop_failed", { cause: error });
|
|
706
|
-
}
|
|
944
|
+
await this.stopContainer(record.handle.id);
|
|
707
945
|
if (record.spec.provider === "claude-code") {
|
|
708
|
-
|
|
709
|
-
try {
|
|
710
|
-
await this.run(["container", "stop", "--time", "10", tool]);
|
|
711
|
-
}
|
|
712
|
-
catch (error) {
|
|
713
|
-
if (!(error instanceof DockerCommandError && error.notFound))
|
|
714
|
-
throw new Error("docker_stop_failed", { cause: error });
|
|
715
|
-
}
|
|
946
|
+
await this.stopContainer(buildDockerIsolationPlan(record.spec, this.options.proxyContainer).names.toolContainer);
|
|
716
947
|
}
|
|
948
|
+
// Services stop with the run; they (and the network keeper) are removed with its other resources.
|
|
949
|
+
for (const service of dockerServiceContainerNames(record.spec))
|
|
950
|
+
await this.stopContainer(service);
|
|
717
951
|
record.phase = timedOut ? "failed" : "stopped";
|
|
718
952
|
record.result = timedOut ? { exitCode: 124, reason: "timed_out" } : resultFor("stopped");
|
|
719
953
|
await this.writeRecord(record);
|
|
720
954
|
this.clearDeadline(record);
|
|
721
955
|
}
|
|
956
|
+
async stopContainer(name) {
|
|
957
|
+
try {
|
|
958
|
+
await this.run(["container", "stop", "--time", "10", name]);
|
|
959
|
+
}
|
|
960
|
+
catch (error) {
|
|
961
|
+
if (!(error instanceof DockerCommandError && error.notFound))
|
|
962
|
+
throw new Error("docker_stop_failed", { cause: error });
|
|
963
|
+
}
|
|
964
|
+
}
|
|
722
965
|
async sweepExpired(record) {
|
|
723
966
|
// The DB verifier ran immediately before this call; never sweep by label alone.
|
|
724
967
|
try {
|
|
@@ -738,17 +981,26 @@ export class DockerJobLauncher {
|
|
|
738
981
|
await this.removeContainerIfAttested(plan.names.workerContainer, labels);
|
|
739
982
|
if (plan.toolCreateArgs)
|
|
740
983
|
await this.removeContainerIfAttested(plan.names.toolContainer, labels);
|
|
984
|
+
// Services, then the network keeper: nothing (the Codex worker, Claude's tool runner, a service)
|
|
985
|
+
// may still share its namespace when it goes.
|
|
986
|
+
// --volumes: an image VOLUME the attestation rejected must not outlive its container.
|
|
987
|
+
for (const service of dockerServiceContainerNames(record.spec)) {
|
|
988
|
+
await this.removeContainerIfAttested(service, labels, true);
|
|
989
|
+
}
|
|
990
|
+
if (plan.networkKeeperCreateArgs) {
|
|
991
|
+
await this.removeContainerIfAttested(plan.names.networkKeeperContainer, labels);
|
|
992
|
+
}
|
|
741
993
|
await this.runIgnoreMissing(["network", "disconnect", plan.names.network, this.options.proxyContainer]);
|
|
742
994
|
await this.removeContainerIfAttested(plan.names.keeperContainer, labels);
|
|
743
995
|
await this.removeNetworkIfAttested(plan.names.network, labels);
|
|
744
996
|
await this.removeVolumeIfAttested(plan.names.storageVolume, labels);
|
|
745
997
|
}
|
|
746
|
-
async removeContainerIfAttested(name, labels) {
|
|
998
|
+
async removeContainerIfAttested(name, labels, anonymousVolumes = false) {
|
|
747
999
|
try {
|
|
748
1000
|
const inspected = await this.inspect(["container", "inspect", name]);
|
|
749
1001
|
if (!labelsMatch(inspected.Config?.Labels, labels))
|
|
750
1002
|
throw new Error("docker_resource_attestation_failed");
|
|
751
|
-
await this.runIgnoreMissing(["container", "rm", "--force", name]);
|
|
1003
|
+
await this.runIgnoreMissing(["container", "rm", "--force", ...(anonymousVolumes ? ["--volumes"] : []), name]);
|
|
752
1004
|
}
|
|
753
1005
|
catch (error) {
|
|
754
1006
|
if (!(error instanceof DockerCommandError && error.notFound))
|
|
@@ -792,13 +1044,7 @@ export class DockerJobLauncher {
|
|
|
792
1044
|
const target = join(staging, "result.json");
|
|
793
1045
|
try {
|
|
794
1046
|
await this.run(["container", "cp", `${this.keeperName(record)}:/run/wardby/storage/output/result.json`, target]);
|
|
795
|
-
const
|
|
796
|
-
if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size > MAX_CODING_ARTIFACT_BYTES) {
|
|
797
|
-
throw new Error("docker_result_artifact_invalid");
|
|
798
|
-
}
|
|
799
|
-
const raw = await readFile(target, "utf8");
|
|
800
|
-
if (Buffer.byteLength(raw, "utf8") > MAX_CODING_ARTIFACT_BYTES)
|
|
801
|
-
throw new Error("docker_result_artifact_invalid");
|
|
1047
|
+
const raw = await readBoundedRegularFile(target, MAX_CODING_ARTIFACT_BYTES, "docker_result_artifact_invalid");
|
|
802
1048
|
const output = parseCodingAgentOutputJson(raw);
|
|
803
1049
|
if (output.runId !== record.runId)
|
|
804
1050
|
throw new Error("docker_result_run_mismatch");
|
|
@@ -818,14 +1064,9 @@ export class DockerJobLauncher {
|
|
|
818
1064
|
const logs = await this.run(["container", "logs", "--tail", "8", record.handle.id]);
|
|
819
1065
|
const raw = `${logs.stdout}\n${logs.stderr}`;
|
|
820
1066
|
for (const line of raw.split("\n").reverse()) {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
return value.error;
|
|
825
|
-
}
|
|
826
|
-
catch {
|
|
827
|
-
// Worker output is untrusted; only parse one fixed JSON shape.
|
|
828
|
-
}
|
|
1067
|
+
const diagnostic = parseWorkerDiagnosticLine(line);
|
|
1068
|
+
if (diagnostic)
|
|
1069
|
+
return diagnostic;
|
|
829
1070
|
}
|
|
830
1071
|
}
|
|
831
1072
|
catch {
|
|
@@ -836,18 +1077,40 @@ export class DockerJobLauncher {
|
|
|
836
1077
|
keeperName(record) {
|
|
837
1078
|
return buildDockerIsolationPlan(record.spec, this.options.proxyContainer).names.keeperContainer;
|
|
838
1079
|
}
|
|
1080
|
+
/** For a run with services: the attested network keeper's ID, which the worker's network mode may name. */
|
|
1081
|
+
async attestedNetworkKeeperId(record) {
|
|
1082
|
+
if (record.spec.services === undefined)
|
|
1083
|
+
return undefined;
|
|
1084
|
+
const name = buildDockerIsolationPlan(record.spec, this.options.proxyContainer).names.networkKeeperContainer;
|
|
1085
|
+
let keeper;
|
|
1086
|
+
try {
|
|
1087
|
+
keeper = await this.inspect(["container", "inspect", name]);
|
|
1088
|
+
}
|
|
1089
|
+
catch (error) {
|
|
1090
|
+
throw new Error("docker_status_unavailable", { cause: error });
|
|
1091
|
+
}
|
|
1092
|
+
assertNetworkKeeperContainerInspection(keeper, record.spec);
|
|
1093
|
+
if (!labelsMatch(keeper.Config?.Labels, resourceLabels(record)) || !keeper.Id) {
|
|
1094
|
+
throw new Error("docker_resource_attestation_failed");
|
|
1095
|
+
}
|
|
1096
|
+
return keeper.Id;
|
|
1097
|
+
}
|
|
839
1098
|
async assertHost() {
|
|
840
1099
|
const info = await this.inspect(["info", "--format", "{{json .}}"]);
|
|
841
1100
|
assertDockerHostSupportsIsolation(info);
|
|
842
1101
|
}
|
|
843
|
-
async createAndAssert(createArgs, inspectArgs, assert, options) {
|
|
1102
|
+
async createAndAssert(createArgs, inspectArgs, assert, options, onCreateFailure) {
|
|
844
1103
|
try {
|
|
845
1104
|
await this.run(createArgs, options);
|
|
846
1105
|
}
|
|
847
|
-
catch {
|
|
1106
|
+
catch (error) {
|
|
848
1107
|
// A retry may find a resource created before the previous process crashed.
|
|
1108
|
+
if (error instanceof DockerCommandError)
|
|
1109
|
+
onCreateFailure?.(error);
|
|
849
1110
|
}
|
|
850
|
-
|
|
1111
|
+
const inspected = await this.inspect(inspectArgs);
|
|
1112
|
+
assert(inspected);
|
|
1113
|
+
return inspected;
|
|
851
1114
|
}
|
|
852
1115
|
async waitForStorage(keeper) {
|
|
853
1116
|
// The keeper emits this fixed marker only after creating every storage
|
|
@@ -122,8 +122,9 @@ export class FakeKubernetesApi {
|
|
|
122
122
|
}
|
|
123
123
|
async exec(namespace, pod, container, command, options) {
|
|
124
124
|
// Like the real API: exec into a missing pod or an unknown container fails instead of succeeding
|
|
125
|
-
// silently, so no test can pass on behaviour a cluster would reject. (The adapter
|
|
126
|
-
//
|
|
125
|
+
// silently, so no test can pass on behaviour a cluster would reject. (The adapter does not
|
|
126
|
+
// actually enforce timeoutMs itself: tests drive slow execs through onExec directly. The value
|
|
127
|
+
// is still recorded on the call, so a test can assert which timeout the caller configured.)
|
|
127
128
|
const target = this.read("pod", namespace, pod);
|
|
128
129
|
if (!target)
|
|
129
130
|
throw new KubernetesNotFoundError(this.key("pod", namespace, pod));
|
|
@@ -131,7 +132,15 @@ export class FakeKubernetesApi {
|
|
|
131
132
|
if (!containers.some((entry) => entry.name === container)) {
|
|
132
133
|
throw new KubernetesNotFoundError(`${this.key("pod", namespace, pod)}/${container}`);
|
|
133
134
|
}
|
|
134
|
-
const call = {
|
|
135
|
+
const call = {
|
|
136
|
+
namespace,
|
|
137
|
+
pod,
|
|
138
|
+
container,
|
|
139
|
+
command,
|
|
140
|
+
stdin: options.stdin,
|
|
141
|
+
stdout: options.stdout,
|
|
142
|
+
timeoutMs: options.timeoutMs,
|
|
143
|
+
};
|
|
135
144
|
this.execCalls.push(call);
|
|
136
145
|
return this.onExec(call);
|
|
137
146
|
}
|
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
import type { V1NetworkPolicy, V1Pod, V1Secret } from "@kubernetes/client-node";
|
|
2
|
+
import { type ResolvedCodingService } from "../../coding/services/catalog.js";
|
|
2
3
|
import type { JobSpec } from "./types.js";
|
|
3
4
|
import { type KubernetesPlatform } from "./kubernetes-platform.js";
|
|
4
5
|
export declare const KUBERNETES_ISOLATION_ERROR = "kubernetes_isolation_unsupported";
|
|
5
|
-
export declare const KUBERNETES_PROVIDER_UNSUPPORTED = "kubernetes_provider_unsupported";
|
|
6
6
|
/** Extra seconds past timeoutSec before Kubernetes kills the pod (keeper included). */
|
|
7
7
|
export declare const POD_DEADLINE_GRACE_SECONDS = 300;
|
|
8
8
|
export declare const KEEPER_CONTAINER = "keeper";
|
|
9
9
|
export declare const STORAGE_INIT_CONTAINER = "storage-init";
|
|
10
10
|
export declare const WORKER_CONTAINER = "worker";
|
|
11
|
+
/** Claude's credential-free command runner: a native sidecar in the run pod. */
|
|
12
|
+
export declare const TOOL_RUNNER_CONTAINER = "tool-runner";
|
|
13
|
+
/** The run Secret's key holding the tool runner's setup (claude-tool-setup.ts). */
|
|
14
|
+
export declare const TOOL_SETUP_SECRET_KEY = "tool-setup";
|
|
15
|
+
/** Where the tool runner listens and the agent's relay connects (claude-tool-runner/main.mjs). */
|
|
16
|
+
export declare const TOOL_SOCKET_PATH = "/run/wardby/tool/runner.sock";
|
|
17
|
+
/** Every service sidecar's container name starts with this (service-postgres, service-redis, ...). */
|
|
18
|
+
export declare const SERVICE_CONTAINER_PREFIX = "service-";
|
|
19
|
+
/** Disk-backed scratch for each of a service's writablePaths (a socket directory, /tmp). */
|
|
20
|
+
export declare const SERVICE_SCRATCH_MIB = 64;
|
|
21
|
+
export declare function serviceContainerName(name: string): string;
|
|
22
|
+
/** What a service sidecar reserves of the pod's ephemeral storage: its data volume plus its scratch volumes. */
|
|
23
|
+
export declare function serviceEphemeralStorageMib(service: ResolvedCodingService): number;
|
|
11
24
|
export declare const STORAGE_ROOT = "/run/wardby/storage";
|
|
12
25
|
export declare const KEEPER_SEEDED_MARKER = "/run/wardby/storage/input/.seeded";
|
|
13
26
|
export declare const PROXY_POD_LABEL: {
|
|
@@ -53,12 +66,14 @@ export interface RunPodOptions {
|
|
|
53
66
|
namespace: string;
|
|
54
67
|
proxyIp: string;
|
|
55
68
|
runtimeClassName?: string;
|
|
69
|
+
/** Emitted only when set, so an unconfigured launcher submits exactly the pod it always has. */
|
|
70
|
+
priorityClassName?: string;
|
|
56
71
|
/** Which platform's admission rules the emitted resources must already satisfy. Default: "generic". */
|
|
57
72
|
platform?: KubernetesPlatform;
|
|
58
73
|
}
|
|
59
74
|
export declare function buildRunPod(spec: JobSpec, options: RunPodOptions): V1Pod;
|
|
60
75
|
export declare function buildRunNetworkPolicy(spec: JobSpec, namespace: string): V1NetworkPolicy;
|
|
61
|
-
export declare function buildCapabilitySecret(spec: JobSpec, namespace: string, capability: string): V1Secret;
|
|
76
|
+
export declare function buildCapabilitySecret(spec: JobSpec, namespace: string, capability: string, toolSetup?: string): V1Secret;
|
|
62
77
|
/**
|
|
63
78
|
* A copy of `pod` with ONLY the API server's own defaulting and aliasing undone
|
|
64
79
|
* — the same `normalizeSpec` pass `assertRunPodMatches` runs, and nothing else.
|