@wardby/cli 0.6.0 → 0.8.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 +5 -5
- package/README.md +6 -1
- package/deploy/local/docker-compose.quickstart-coding.yml +19 -0
- package/dist/claude-coding-worker/driver.d.ts +33 -3
- package/dist/claude-coding-worker/driver.js +151 -21
- package/dist/claude-coding-worker/main.js +38 -6
- package/dist/claude-coding-worker/sdk.js +29 -2
- 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/claude-plugin/command.d.ts +61 -0
- package/dist/claude-plugin/command.js +376 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +3 -1
- package/dist/cli.js +71 -13
- package/dist/coding/code-host.d.ts +16 -0
- package/dist/coding/code-host.js +60 -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/mcp-token.d.ts +12 -0
- package/dist/coding/mcp-token.js +26 -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 +46 -126
- package/dist/coding/profile.js +45 -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 +264 -346
- package/dist/coding/protocol.js +237 -12
- package/dist/coding/redact.d.ts +3 -0
- package/dist/coding/redact.js +17 -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 +52 -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 +8 -3
- package/dist/coding-worker/artifact.js +3 -1
- package/dist/coding-worker/debug-trace.d.ts +9 -6
- package/dist/coding-worker/debug-trace.js +16 -19
- 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 +124 -39
- package/dist/coding-worker/errors.d.ts +1 -0
- package/dist/coding-worker/errors.js +32 -0
- package/dist/coding-worker/main.js +5 -1
- package/dist/coding-worker/mcp-config.d.ts +27 -0
- package/dist/coding-worker/mcp-config.js +32 -0
- package/dist/coding-worker/sdk.d.ts +36 -0
- package/dist/coding-worker/sdk.js +28 -1
- 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 +15 -0
- package/dist/config/dependency-cache.d.ts +23 -0
- package/dist/config/dependency-cache.js +32 -0
- package/dist/config/mcp-call-limit.d.ts +8 -0
- package/dist/config/mcp-call-limit.js +18 -0
- package/dist/config/mcp-servers.d.ts +8 -0
- package/dist/config/mcp-servers.js +12 -0
- package/dist/config/providers.d.ts +12 -3
- package/dist/config/providers.js +55 -5
- package/dist/config/test-simulators.d.ts +92 -0
- package/dist/config/test-simulators.js +333 -0
- package/dist/config/tool-timeout.d.ts +1 -0
- package/dist/config/tool-timeout.js +18 -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-mcp.d.ts +36 -0
- package/dist/core/coding-mcp.js +253 -0
- package/dist/core/coding-queue.d.ts +2 -1
- package/dist/core/coding-queue.js +7 -0
- package/dist/core/coding-repository.d.ts +46 -0
- package/dist/core/coding-repository.js +92 -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/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/delegation-slots.d.ts +27 -0
- package/dist/core/delegation-slots.js +44 -0
- package/dist/core/dispatch.d.ts +48 -2
- package/dist/core/dispatch.js +166 -66
- package/dist/core/engine-native.js +1 -1
- package/dist/core/error-code.d.ts +38 -0
- package/dist/core/error-code.js +169 -0
- package/dist/core/grants.d.ts +46 -8
- package/dist/core/grants.js +99 -8
- package/dist/core/host-events.d.ts +18 -2
- package/dist/core/host-events.js +291 -27
- package/dist/core/host-status.d.ts +85 -3
- package/dist/core/host-status.js +300 -22
- package/dist/core/issue-bridge.d.ts +50 -6
- package/dist/core/issue-bridge.js +124 -33
- package/dist/core/issue-events.d.ts +1 -1
- package/dist/core/issue-events.js +4 -10
- package/dist/core/issue-status.d.ts +1 -1
- package/dist/core/issue-status.js +58 -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/mcp-client/client.d.ts +47 -0
- package/dist/core/mcp-client/client.js +141 -0
- package/dist/core/mcp-client/jsonrpc.d.ts +15 -0
- package/dist/core/mcp-client/jsonrpc.js +54 -0
- package/dist/core/mcp-client/results.d.ts +13 -0
- package/dist/core/mcp-client/results.js +42 -0
- package/dist/core/mcp-servers.d.ts +90 -0
- package/dist/core/mcp-servers.js +230 -0
- package/dist/core/mcp-tools.d.ts +108 -0
- package/dist/core/mcp-tools.js +287 -0
- package/dist/core/memory-tools.js +7 -0
- package/dist/core/merge-order-check.d.ts +2 -1
- package/dist/core/merge-order-check.js +44 -18
- package/dist/core/notification-dispatcher.js +2 -1
- package/dist/core/notification-templates.d.ts +1 -7
- package/dist/core/notification-templates.js +36 -2
- package/dist/core/pull-request-state-sync.js +2 -2
- package/dist/core/reconciler.d.ts +4 -3
- package/dist/core/reconciler.js +8 -1
- package/dist/core/related-pull-requests.d.ts +11 -3
- package/dist/core/related-pull-requests.js +49 -20
- package/dist/core/reply-parts.d.ts +21 -0
- package/dist/core/reply-parts.js +73 -0
- package/dist/core/review-fix.d.ts +1 -1
- package/dist/core/review-fix.js +4 -3
- package/dist/core/review-host-checks.d.ts +1 -1
- package/dist/core/review-host-tools.d.ts +3 -0
- package/dist/core/review-host-tools.js +102 -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 +145 -49
- package/dist/core/runner.js +719 -216
- 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 +12 -74
- package/dist/core/secret-broker-config.js +1 -1
- package/dist/core/secret-guard.d.ts +49 -0
- package/dist/core/secret-guard.js +119 -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 +11 -1
- package/dist/core/secrets.js +27 -1
- package/dist/core/serializable-retry.d.ts +18 -0
- package/dist/core/serializable-retry.js +43 -0
- package/dist/core/stop-run.d.ts +46 -0
- package/dist/core/stop-run.js +61 -0
- package/dist/core/tool-admin.d.ts +5 -1
- package/dist/core/tool-admin.js +7 -2
- package/dist/core/tool-names.d.ts +13 -0
- package/dist/core/tool-names.js +20 -0
- package/dist/core/webhooks.d.ts +4 -0
- package/dist/core/webhooks.js +68 -49
- package/dist/core/workflow-events.d.ts +14 -2
- package/dist/core/workflow-events.js +4 -0
- package/dist/core/workflow-run-events.d.ts +5 -3
- package/dist/core/workflow-run-events.js +45 -9
- 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 +65 -3
- package/dist/generated/prisma/client.d.ts +65 -3
- package/dist/generated/prisma/commonInputTypes.d.ts +266 -106
- package/dist/generated/prisma/enums.d.ts +10 -0
- package/dist/generated/prisma/enums.js +8 -0
- package/dist/generated/prisma/internal/class.d.ts +110 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +957 -9
- package/dist/generated/prisma/internal/prismaNamespace.js +166 -2
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +174 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +166 -2
- package/dist/generated/prisma/models/Agent.d.ts +377 -8
- package/dist/generated/prisma/models/AgentMcpServer.d.ts +1412 -0
- package/dist/generated/prisma/models/AgentMcpServer.js +1 -0
- package/dist/generated/prisma/models/AgentRepository.d.ts +81 -1
- package/dist/generated/prisma/models/AuthUser.d.ts +1 -1
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +228 -7
- package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
- package/dist/generated/prisma/models/CodingProxySession.d.ts +232 -2
- package/dist/generated/prisma/models/CodingRun.d.ts +1712 -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/HostProvider.d.ts +2176 -0
- package/dist/generated/prisma/models/HostProvider.js +1 -0
- package/dist/generated/prisma/models/HostProviderCredential.d.ts +1285 -0
- package/dist/generated/prisma/models/HostProviderCredential.js +1 -0
- package/dist/generated/prisma/models/HostProviderOperation.d.ts +1470 -0
- package/dist/generated/prisma/models/HostProviderOperation.js +1 -0
- package/dist/generated/prisma/models/HostProviderTrustedAccount.d.ts +1145 -0
- package/dist/generated/prisma/models/HostProviderTrustedAccount.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/McpServer.d.ts +1500 -0
- package/dist/generated/prisma/models/McpServer.js +1 -0
- package/dist/generated/prisma/models/NativeGatewayCall.d.ts +77 -1
- package/dist/generated/prisma/models/NativeGatewaySession.d.ts +35 -1
- package/dist/generated/prisma/models/Principal.d.ts +167 -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/ResourceGrant.d.ts +1 -1
- package/dist/generated/prisma/models/Run.d.ts +738 -2
- package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
- package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
- 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 +387 -0
- package/dist/generated/prisma/models/Tool.d.ts +223 -1
- package/dist/generated/prisma/models.d.ts +10 -0
- package/dist/help/search.js +12 -3
- package/dist/help-index.json +2033 -110
- package/dist/import/create.js +48 -4
- package/dist/import/neutral-schema.d.ts +51 -281
- 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 +10 -2
- package/dist/mcp/auth/access.js +15 -1
- package/dist/mcp/auth/grants-cli.d.ts +6 -4
- package/dist/mcp/auth/grants-cli.js +42 -3
- package/dist/mcp/auth/ownership.d.ts +7 -7
- package/dist/mcp/auth/resource-server.d.ts +3 -1
- package/dist/mcp/auth/resource-server.js +17 -2
- 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 +3 -0
- package/dist/mcp/host-events/github-ingress.d.ts +2 -0
- package/dist/mcp/host-events/github-ingress.js +2 -1
- package/dist/mcp/index.d.ts +6 -0
- package/dist/mcp/index.js +69 -10
- 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 +295 -28
- package/dist/mcp/tools/datastore.js +17 -8
- package/dist/mcp/tools/grants.js +73 -29
- package/dist/mcp/tools/host-providers.d.ts +2 -0
- package/dist/mcp/tools/host-providers.js +215 -0
- package/dist/mcp/tools/mcp-servers.d.ts +26 -0
- package/dist/mcp/tools/mcp-servers.js +481 -0
- package/dist/mcp/tools/memory.js +11 -1
- package/dist/mcp/tools/notification-channels.js +2 -2
- package/dist/mcp/tools/packages.d.ts +2 -0
- package/dist/mcp/tools/packages.js +195 -0
- package/dist/mcp/tools/repositories.js +65 -12
- 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.js +209 -27
- package/dist/mcp/tools/scheduling.js +3 -1
- package/dist/mcp/tools/secret-elicitation-form.js +5 -0
- package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
- package/dist/mcp/tools/secret-elicitation-server.js +10 -61
- package/dist/mcp/tools/secret-elicitation.d.ts +2 -0
- package/dist/mcp/tools/secret-elicitation.js +25 -2
- package/dist/mcp/tools/secrets.js +40 -6
- 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 +7 -5
- package/dist/mcp/tools/tools.js +64 -16
- package/dist/mcp/tools/trigger.js +28 -6
- package/dist/mcp/transport/http-limits.d.ts +2 -0
- package/dist/mcp/transport/http-limits.js +6 -2
- 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/mcp/webhooks/ingress.js +10 -0
- package/dist/native-worker/docker-launcher.d.ts +38 -2
- package/dist/native-worker/docker-launcher.js +65 -5
- package/dist/native-worker/gateway-server.d.ts +55 -3
- package/dist/native-worker/gateway-server.js +152 -34
- package/dist/native-worker/gateway.d.ts +29 -1
- package/dist/native-worker/gateway.js +74 -4
- package/dist/native-worker/http-server.d.ts +7 -1
- package/dist/native-worker/http-server.js +62 -7
- package/dist/native-worker/http-transport.js +1 -1
- package/dist/native-worker/kubernetes-launcher.d.ts +7 -3
- package/dist/native-worker/kubernetes-launcher.js +43 -3
- package/dist/native-worker/launch.d.ts +18 -1
- package/dist/native-worker/launch.js +6 -1
- package/dist/native-worker/ledger.d.ts +24 -4
- package/dist/native-worker/ledger.js +62 -8
- package/dist/native-worker/loopback.js +3 -8
- package/dist/native-worker/main.d.ts +2 -1
- package/dist/native-worker/main.js +14 -3
- package/dist/native-worker/protocol.d.ts +130 -577
- package/dist/native-worker/protocol.js +51 -2
- package/dist/native-worker/sandbox-executor.d.ts +17 -2
- package/dist/native-worker/sandbox-executor.js +78 -4
- 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 +1 -1
- package/dist/native-worker/stdio.js +6 -5
- package/dist/native-worker/warm-pool.d.ts +2 -2
- package/dist/native-worker/warm-pool.js +4 -4
- package/dist/native-worker/worker.js +28 -2
- package/dist/observability/metrics.js +6 -1
- package/dist/providers/auth/self-hosted.d.ts +1 -1
- package/dist/providers/coding-proxy/capability-hash.d.ts +2 -0
- package/dist/providers/coding-proxy/capability-hash.js +5 -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/mcp-route.d.ts +34 -0
- package/dist/providers/coding-proxy/mcp-route.js +166 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +17 -2
- package/dist/providers/coding-proxy/memory-ledger.js +99 -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 +16 -2
- package/dist/providers/coding-proxy/prisma-ledger.js +209 -69
- package/dist/providers/coding-proxy/proxy.d.ts +21 -2
- package/dist/providers/coding-proxy/proxy.js +300 -48
- 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 +10 -0
- package/dist/providers/coding-proxy/runtime.js +109 -16
- package/dist/providers/coding-proxy/server.d.ts +9 -1
- package/dist/providers/coding-proxy/server.js +55 -1
- package/dist/providers/coding-proxy/types.d.ts +78 -1
- package/dist/providers/datastore/types.d.ts +5 -0
- package/dist/providers/engine/types.d.ts +17 -2
- package/dist/providers/engine/types.js +17 -0
- package/dist/providers/executor/composition.d.ts +10 -3
- package/dist/providers/executor/composition.js +52 -7
- package/dist/providers/executor/container.d.ts +394 -9
- package/dist/providers/executor/container.js +1210 -96
- 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 +50 -1
- package/dist/providers/executor/dbos.js +207 -20
- package/dist/providers/executor/deferred.d.ts +12 -24
- package/dist/providers/executor/deferred.js +10 -29
- 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 +2 -0
- package/dist/providers/executor/routing.js +4 -0
- package/dist/providers/executor/types.d.ts +13 -0
- package/dist/providers/host-tools/invoke.d.ts +37 -0
- package/dist/providers/host-tools/invoke.js +117 -0
- package/dist/providers/host-tools/operations.d.ts +65 -0
- package/dist/providers/host-tools/operations.js +149 -0
- package/dist/providers/host-tools/registry.d.ts +79 -0
- package/dist/providers/host-tools/registry.js +362 -0
- package/dist/providers/host-tools/request-guard.d.ts +17 -0
- package/dist/providers/host-tools/request-guard.js +99 -0
- package/dist/providers/host-tools/self-test.d.ts +64 -0
- package/dist/providers/host-tools/self-test.js +142 -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 +10 -2
- package/dist/providers/jobs/docker-isolation.js +47 -8
- package/dist/providers/jobs/docker.d.ts +9 -0
- package/dist/providers/jobs/docker.js +60 -11
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +2 -0
- package/dist/providers/jobs/fake-kubernetes-api.js +3 -0
- package/dist/providers/jobs/kubernetes-api.d.ts +8 -0
- package/dist/providers/jobs/kubernetes-api.js +10 -0
- package/dist/providers/jobs/kubernetes-client.js +10 -1
- package/dist/providers/jobs/kubernetes-isolation.d.ts +5 -1
- package/dist/providers/jobs/kubernetes-isolation.js +32 -3
- package/dist/providers/jobs/kubernetes.d.ts +11 -1
- package/dist/providers/jobs/kubernetes.js +111 -17
- package/dist/providers/jobs/types.d.ts +39 -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 +29 -2
- package/dist/providers/review-host/github.js +224 -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 +140 -6
- package/dist/providers/review-host/types.js +9 -1
- 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 +39 -4
- package/dist/providers/vcs/git.js +339 -26
- 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 +183 -44
- package/dist/providers/vcs/github.js +455 -56
- package/dist/providers/vcs/index.d.ts +1 -1
- package/dist/providers/vcs/index.js +9 -2
- 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 +37 -1
- package/dist/providers/vcs/remote.js +7 -1
- package/dist/providers/vcs/routing.d.ts +16 -8
- package/dist/providers/vcs/routing.js +27 -6
- package/dist/providers/vcs/types.d.ts +150 -5
- package/dist/quickstart/coding-seed.d.ts +14 -3
- package/dist/quickstart/coding-seed.js +213 -4
- package/dist/quickstart/index.d.ts +5 -0
- package/dist/quickstart/index.js +21 -0
- 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/eval-core.d.ts +12 -2
- package/dist/sandbox/eval-core.js +20 -4
- 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 +5 -0
- package/dist/sandbox/host-functions.js +13 -13
- package/dist/sandbox/limits.d.ts +4 -1
- package/dist/sandbox/limits.js +4 -1
- package/dist/sandbox/run-in-sandbox.d.ts +6 -0
- package/dist/sandbox/run-in-sandbox.js +14 -2
- package/dist/sandbox/safe-fetch.d.ts +2 -0
- package/dist/sandbox/safe-fetch.js +1 -1
- package/dist/sandbox/secret-broker.d.ts +1 -0
- package/dist/sandbox/secret-broker.js +4 -5
- package/dist/sandbox/tool-capabilities.d.ts +10 -30
- package/dist/sandbox/tool-timeout.d.ts +32 -0
- package/dist/sandbox/tool-timeout.js +52 -0
- package/dist/sandbox/user-tool.d.ts +8 -1
- package/dist/sandbox/user-tool.js +9 -3
- package/dist/sandbox/zod-params.d.ts +37 -5
- package/dist/sandbox/zod-params.js +181 -26
- package/dist/serve.js +8 -1
- package/dist/viewer/api-schema.d.ts +349 -2627
- package/dist/viewer/api-schema.js +7 -0
- package/dist/viewer/build-schemas.js +6 -2
- package/dist/viewer/graph.js +2 -1
- package/dist/viewer/openapi.js +2 -4
- package/dist/wardby-bin.js +15 -0
- package/docs/README.md +11 -1
- package/docs/agent-recipes.md +95 -24
- package/docs/architecture-runtime.md +1 -1
- package/docs/claude-code-plugin.md +164 -0
- package/docs/code-review-agents.md +557 -41
- package/docs/coding-agent-setup.md +566 -8
- package/docs/coding-packages.md +1033 -90
- package/docs/coding-services.md +27 -12
- package/docs/coding-worker-byo-images.md +24 -2
- package/docs/coding-worker-isolation.md +183 -37
- package/docs/debugging-agent-runs.md +242 -0
- package/docs/getting-started-gke.md +129 -141
- package/docs/getting-started-identity-provider.md +53 -38
- package/docs/getting-started.md +17 -0
- package/docs/host-providers.md +294 -0
- package/docs/jira-agents.md +17 -8
- 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/mcp-servers.md +254 -0
- package/docs/native-sandbox.md +143 -31
- package/docs/observability.md +4 -0
- package/docs/security-deployment.md +139 -29
- package/docs/slack-notifications.md +35 -19
- package/docs/tool-secrets.md +45 -10
- package/docs/viewer-api.md +6 -0
- package/docs/viewer-api.openapi.yml +1 -1
- package/help/admin-viewer.md +28 -2
- package/help/agent-recipes.md +33 -2
- package/help/architecture-agent.md +11 -6
- package/help/brokered-secrets.md +3 -0
- package/help/build-claude-code-image.md +1 -1
- package/help/build-worker-image.md +3 -1
- package/help/builder-agent.md +19 -6
- package/help/claude-code-run-pane.md +40 -0
- package/help/code-review-agents.md +177 -6
- 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 +15 -8
- package/help/errors/budget-exhausted.md +187 -0
- package/help/errors/budget-group-exhausted.md +5 -1
- package/help/errors/coding-mcp-pins-unavailable.md +35 -0
- 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 +1 -1
- 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 +4 -0
- package/help/errors/graph-incomplete.md +43 -0
- package/help/errors/graph-limit.md +43 -0
- package/help/errors/host-provider-error.md +40 -0
- package/help/errors/host-tool-failed.md +36 -0
- package/help/errors/mcp-call-limit.md +22 -0
- package/help/errors/mcp-call-timeout.md +22 -0
- package/help/errors/mcp-server-auth-failed.md +22 -0
- package/help/errors/mcp-server-credentials-unavailable.md +45 -0
- package/help/errors/mcp-server-error.md +28 -0
- package/help/errors/mcp-server-unreachable.md +22 -0
- package/help/errors/mcp-servers-off.md +21 -0
- package/help/errors/mcp-tool-not-allowed.md +26 -0
- package/help/errors/mcp-tool-removed.md +22 -0
- package/help/errors/mcp-unavailable.md +25 -0
- package/help/errors/merge-conflict.md +49 -0
- package/help/errors/native-sandbox-capacity.md +1 -1
- package/help/errors/native-sandbox-deadline-exceeded.md +1 -1
- package/help/errors/native-sandbox-docker-failed.md +1 -1
- package/help/errors/native-sandbox-gateway-error.md +20 -0
- package/help/errors/native-sandbox-gateway-unavailable.md +1 -1
- package/help/errors/native-sandbox-image-not-pinned.md +1 -1
- package/help/errors/native-sandbox-isolation-mismatch.md +1 -1
- package/help/errors/native-sandbox-launch-abandoned.md +21 -0
- package/help/errors/native-sandbox-network-unenforced.md +1 -1
- package/help/errors/native-sandbox-requires-catalog.md +1 -1
- package/help/errors/native-sandbox-unavailable.md +1 -1
- package/help/errors/native-sandbox-warm-delivery-failed.md +1 -1
- package/help/errors/native-sandbox-worker-exited.md +4 -3
- package/help/errors/native-sandbox-worker-lost.md +1 -1
- package/help/errors/native-sandbox-worker-unready.md +1 -1
- 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/repository-not-listed.md +36 -0
- package/help/errors/repository-required.md +36 -0
- package/help/errors/run-lost.md +39 -0
- package/help/errors/run-transcript-download.md +44 -0
- package/help/errors/secret-in-value.md +69 -0
- package/help/errors/target-merge.md +40 -0
- package/help/errors/tool-timeout.md +38 -0
- package/help/fix-merge-conflicts.md +73 -0
- package/help/github-app-setup.md +132 -0
- package/help/github.md +22 -0
- package/help/host-providers.md +40 -0
- package/help/identity-and-access.md +6 -1
- package/help/jira.md +23 -6
- package/help/knowledge.md +16 -7
- package/help/local-repositories.md +1 -1
- package/help/low-power-mode.md +7 -1
- package/help/mcp-servers.md +73 -0
- package/help/mcp.md +7 -2
- package/help/merge-order-check.md +5 -0
- package/help/native-capabilities.md +55 -1
- package/help/native-sandbox.md +16 -2
- package/help/operating-agents.md +21 -0
- package/help/package-audit-mode.md +91 -0
- package/help/related-pull-requests.md +17 -10
- package/help/repo-instructions-and-skills.md +3 -1
- package/help/resume-runs-locally.md +134 -0
- package/help/review-fix-rounds.md +33 -1
- package/help/sharing-agents.md +59 -0
- package/help/slack-notifications.md +19 -5
- 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 +86 -7
- package/help/troubleshooting/debugging-agent-runs.md +29 -0
- package/package.json +18 -10
- 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/migrations/20261102000000_host_providers/migration.sql +56 -0
- package/prisma/migrations/20261104000000_coding_agent_repository_list/migration.sql +5 -0
- package/prisma/migrations/20261106000000_tool_timeout/migration.sql +4 -0
- package/prisma/migrations/20261107000000_mcp_servers/migration.sql +33 -0
- package/prisma/migrations/20261108000000_coding_mcp/migration.sql +5 -0
- package/prisma/migrations/20261109000000_task_run_index/migration.sql +3 -0
- package/prisma/schema.prisma +468 -109
- package/scripts/git-askpass.sh +1 -1
- package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { codeProviderOf, normalizeHostedRepository } from "../../coding/code-host.js";
|
|
2
|
+
import { loadTestSimulators, simulatorHostFetch } from "../../config/test-simulators.js";
|
|
3
|
+
import { parseSecretBrokerConfig } from "../../core/secret-broker-config.js";
|
|
4
|
+
import { safeFetch } from "../../sandbox/safe-fetch.js";
|
|
5
|
+
import { invokeHostTool } from "./invoke.js";
|
|
6
|
+
import { HOST_OPERATIONS, isHostOperation } from "./operations.js";
|
|
7
|
+
import { findCredential } from "./registry.js";
|
|
8
|
+
import { effectiveToolTimeoutMs } from "../../sandbox/tool-timeout.js";
|
|
9
|
+
import { loadToolMaxTimeoutMs } from "../../config/tool-timeout.js";
|
|
10
|
+
/**
|
|
11
|
+
* The fetch for bound tools: the real one, or under WARDBY_TEST_SIMULATORS the simulator's. Under
|
|
12
|
+
* the switch only `sim-` credentials are sent, as the switch refuses every other real credential.
|
|
13
|
+
*/
|
|
14
|
+
export function hostToolFetch(env = process.env) {
|
|
15
|
+
const simulators = loadTestSimulators(env);
|
|
16
|
+
return simulators ? { fetchImpl: simulatorHostFetch(simulators, safeFetch), simulated: true } : { simulated: false };
|
|
17
|
+
}
|
|
18
|
+
export async function loadProviderForCalls(db, name) {
|
|
19
|
+
const row = await db.hostProvider.findUnique({
|
|
20
|
+
where: { name },
|
|
21
|
+
include: { permissionSecret: true, credentials: { include: { secret: true } }, operations: true },
|
|
22
|
+
});
|
|
23
|
+
if (!row)
|
|
24
|
+
return null;
|
|
25
|
+
return {
|
|
26
|
+
name: row.name,
|
|
27
|
+
apiHosts: row.apiHosts,
|
|
28
|
+
repositoryApiPath: row.repositoryApiPath,
|
|
29
|
+
permissionApiPath: row.permissionApiPath,
|
|
30
|
+
permissionSecret: row.permissionSecret,
|
|
31
|
+
credentials: row.credentials,
|
|
32
|
+
operations: row.operations,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// No URL-encoding: callHostOperation only takes a repository in its normalized form, which admits only [A-Za-z0-9._-], and the request guard compares a raw prefix.
|
|
36
|
+
function encodePath(template, fields) {
|
|
37
|
+
return template.replace(/\{([a-z]+)\}/g, (_m, field) => fields[field]);
|
|
38
|
+
}
|
|
39
|
+
/** The repository is compared in its normalized form, so callers must pass one. */
|
|
40
|
+
export async function callHostOperation(provider, cipher, repository, operation, fields, options = {}) {
|
|
41
|
+
let ours = false;
|
|
42
|
+
try {
|
|
43
|
+
ours = normalizeHostedRepository(repository) === repository && codeProviderOf(repository) === provider.name;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Not a repository we can name: denied below.
|
|
47
|
+
}
|
|
48
|
+
if (!ours)
|
|
49
|
+
return { ok: false, code: "host_tool_request_denied" };
|
|
50
|
+
const snapshot = provider.operations.find((o) => o.operation === operation);
|
|
51
|
+
if (!snapshot)
|
|
52
|
+
return { ok: false, code: "host_tool_failed" };
|
|
53
|
+
const path = repository.slice(`${provider.name}:`.length);
|
|
54
|
+
const [workspace, repo] = path.split("/");
|
|
55
|
+
const permission = HOST_OPERATIONS[operation].credential === "permission";
|
|
56
|
+
const stored = permission ? provider.permissionSecret : (findCredential(provider.credentials, path)?.secret ?? null);
|
|
57
|
+
const template = permission ? provider.permissionApiPath : provider.repositoryApiPath;
|
|
58
|
+
if (!stored || !template)
|
|
59
|
+
return { ok: false, code: "host_tool_no_credential" };
|
|
60
|
+
const credential = async () => {
|
|
61
|
+
const value = await cipher.decrypt(stored.ciphertext);
|
|
62
|
+
if (options.simulated && !value.startsWith("sim-"))
|
|
63
|
+
return undefined;
|
|
64
|
+
return { value, broker: parseSecretBrokerConfig(stored.broker) };
|
|
65
|
+
};
|
|
66
|
+
return invokeHostTool({
|
|
67
|
+
provider: provider.name,
|
|
68
|
+
operation,
|
|
69
|
+
snapshot,
|
|
70
|
+
params: { ...fields, workspace, repo, repository: path },
|
|
71
|
+
apiHosts: provider.apiHosts,
|
|
72
|
+
pathPrefix: encodePath(template, { repository: path, workspace, repo }),
|
|
73
|
+
credential,
|
|
74
|
+
fetchImpl: options.fetchImpl,
|
|
75
|
+
timeoutMs: effectiveToolTimeoutMs(snapshot.timeoutMs, loadToolMaxTimeoutMs()),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
export async function selfTestHostProvider(provider, cipher, input, options = {}) {
|
|
79
|
+
const repository = normalizeHostedRepository(input.repository);
|
|
80
|
+
if (codeProviderOf(repository) !== provider.name)
|
|
81
|
+
throw new Error("host_provider_repository_mismatch");
|
|
82
|
+
const results = [];
|
|
83
|
+
const skip = (operation, code) => results.push({ operation, outcome: "skipped", code });
|
|
84
|
+
const check = async (operation, fields) => {
|
|
85
|
+
const result = await callHostOperation(provider, cipher, repository, operation, fields, options);
|
|
86
|
+
results.push(result.ok ? { operation, outcome: "pass" } : { operation, outcome: "fail", code: result.code });
|
|
87
|
+
return result;
|
|
88
|
+
};
|
|
89
|
+
const bound = (name) => provider.operations.some((o) => o.operation === name);
|
|
90
|
+
// The pull request comes first: its head is the ref for the checks that need one.
|
|
91
|
+
let ref = input.ref;
|
|
92
|
+
const number = input.pullRequest;
|
|
93
|
+
if (!bound("getPullRequest"))
|
|
94
|
+
skip("getPullRequest", "not_bound");
|
|
95
|
+
else if (number === undefined)
|
|
96
|
+
skip("getPullRequest", "needs_pull_request");
|
|
97
|
+
else {
|
|
98
|
+
const pr = await check("getPullRequest", { number });
|
|
99
|
+
if (pr.ok)
|
|
100
|
+
ref ??= pr.value.headSha;
|
|
101
|
+
}
|
|
102
|
+
for (const operation of ["listPullRequestFiles", "getDiff", "listComments"]) {
|
|
103
|
+
if (!bound(operation))
|
|
104
|
+
skip(operation, "not_bound");
|
|
105
|
+
else if (number === undefined)
|
|
106
|
+
skip(operation, "needs_pull_request");
|
|
107
|
+
else
|
|
108
|
+
await check(operation, { number });
|
|
109
|
+
}
|
|
110
|
+
if (!bound("findPullRequest"))
|
|
111
|
+
skip("findPullRequest", "not_bound");
|
|
112
|
+
else if (input.headRef === undefined)
|
|
113
|
+
skip("findPullRequest", "needs_head_ref");
|
|
114
|
+
else
|
|
115
|
+
await check("findPullRequest", { headRef: input.headRef });
|
|
116
|
+
for (const [operation, fields] of [
|
|
117
|
+
["readFile", { path: "README.md" }],
|
|
118
|
+
["listFiles", { path: "" }],
|
|
119
|
+
["listCommitStatuses", {}],
|
|
120
|
+
]) {
|
|
121
|
+
if (!bound(operation))
|
|
122
|
+
skip(operation, "not_bound");
|
|
123
|
+
else if (ref === undefined)
|
|
124
|
+
skip(operation, "needs_ref");
|
|
125
|
+
else
|
|
126
|
+
await check(operation, { ref, ...fields });
|
|
127
|
+
}
|
|
128
|
+
const mode = provider.permissionSecret ? "permission" : "allowlist";
|
|
129
|
+
if (mode === "allowlist")
|
|
130
|
+
skip("getRepositoryPermission", "allowlist_mode");
|
|
131
|
+
else if (!bound("getRepositoryPermission"))
|
|
132
|
+
skip("getRepositoryPermission", "not_bound");
|
|
133
|
+
else if (input.accountId === undefined)
|
|
134
|
+
skip("getRepositoryPermission", "needs_account");
|
|
135
|
+
else
|
|
136
|
+
await check("getRepositoryPermission", { accountId: input.accountId });
|
|
137
|
+
for (const { operation } of provider.operations) {
|
|
138
|
+
if (isHostOperation(operation) && !HOST_OPERATIONS[operation].readOnly)
|
|
139
|
+
skip(operation, "not_read_only");
|
|
140
|
+
}
|
|
141
|
+
return { provider: provider.name, repository, mode, results };
|
|
142
|
+
}
|
|
@@ -34,7 +34,8 @@ export interface ProviderRegistry {
|
|
|
34
34
|
llm: LlmProvider;
|
|
35
35
|
secrets: SecretCipher;
|
|
36
36
|
auth: AuthProvider;
|
|
37
|
-
|
|
37
|
+
/** Absent unless BLOB_STORE is configured. */
|
|
38
|
+
storage?: BlobStore;
|
|
38
39
|
executor: Executor;
|
|
39
40
|
datastore: Datastore;
|
|
40
41
|
memory: AgentMemoryStore;
|
|
@@ -264,6 +264,23 @@ export interface IssueEvent {
|
|
|
264
264
|
}
|
|
265
265
|
/** Shared by the ingress and the tools: a Jira issue key, e.g. PROJ-123. */
|
|
266
266
|
export declare const ISSUE_KEY: RegExp;
|
|
267
|
+
/** A GitHub issue's recorded key (githubIssueKey): "<owner>/<repo>#<number>", the repository normalised to lowercase. */
|
|
268
|
+
export declare const GITHUB_ISSUE_KEY: RegExp;
|
|
269
|
+
/** The product name of each system an issue can be recorded from (CodingRun / IssuePullRequest issueProvider). */
|
|
270
|
+
export declare const ISSUE_SOURCE_NAMES: Readonly<Record<string, string>>;
|
|
271
|
+
/**
|
|
272
|
+
* A recorded issue (CodingRun / IssuePullRequest issueProvider + issueKey) as
|
|
273
|
+
* people see it: the key re-validated for its provider, the system's name and
|
|
274
|
+
* the issue's page. A GitHub issue's page comes from its key; a tracker
|
|
275
|
+
* issue's from `trackerUrl` (the tracker's issueUrl), dropped when it throws
|
|
276
|
+
* or is not https. Undefined for an unknown provider or a malformed key.
|
|
277
|
+
*/
|
|
278
|
+
export declare function issueReference(provider: string, key: string, trackerUrl?: (key: string) => string | undefined): {
|
|
279
|
+
key: string;
|
|
280
|
+
url?: string;
|
|
281
|
+
trackerName: string;
|
|
282
|
+
} | undefined;
|
|
267
283
|
/** A Jira project key. */
|
|
268
284
|
export declare const PROJECT_KEY: RegExp;
|
|
285
|
+
/** An issue key's project: a Jira key's project key ("PROJ-123" → "PROJ"); a GitHub issue key's repository ("owner/repo#5" → "owner/repo"). */
|
|
269
286
|
export declare const projectOf: (issueKey: string) => string;
|
|
@@ -11,6 +11,44 @@ export class IssueTrackerError extends Error {
|
|
|
11
11
|
}
|
|
12
12
|
/** Shared by the ingress and the tools: a Jira issue key, e.g. PROJ-123. */
|
|
13
13
|
export const ISSUE_KEY = /^[A-Z][A-Z0-9_]{0,254}-[1-9]\d{0,9}$/;
|
|
14
|
+
/** A GitHub issue's recorded key (githubIssueKey): "<owner>/<repo>#<number>", the repository normalised to lowercase. */
|
|
15
|
+
export const GITHUB_ISSUE_KEY = /^[a-z0-9](?:[a-z0-9-]{0,37}[a-z0-9])?\/[a-z0-9._-]{1,100}#[1-9]\d{0,9}$/;
|
|
16
|
+
/** The product name of each system an issue can be recorded from (CodingRun / IssuePullRequest issueProvider). */
|
|
17
|
+
export const ISSUE_SOURCE_NAMES = { ...ISSUE_TRACKER_NAMES, github: "GitHub" };
|
|
18
|
+
/**
|
|
19
|
+
* A recorded issue (CodingRun / IssuePullRequest issueProvider + issueKey) as
|
|
20
|
+
* people see it: the key re-validated for its provider, the system's name and
|
|
21
|
+
* the issue's page. A GitHub issue's page comes from its key; a tracker
|
|
22
|
+
* issue's from `trackerUrl` (the tracker's issueUrl), dropped when it throws
|
|
23
|
+
* or is not https. Undefined for an unknown provider or a malformed key.
|
|
24
|
+
*/
|
|
25
|
+
export function issueReference(provider, key, trackerUrl) {
|
|
26
|
+
let url;
|
|
27
|
+
if (provider === "github") {
|
|
28
|
+
if (!GITHUB_ISSUE_KEY.test(key))
|
|
29
|
+
return undefined;
|
|
30
|
+
const hash = key.lastIndexOf("#");
|
|
31
|
+
url = `https://github.com/${key.slice(0, hash)}/issues/${key.slice(hash + 1)}`;
|
|
32
|
+
}
|
|
33
|
+
else if (provider === "jira") {
|
|
34
|
+
if (!ISSUE_KEY.test(key))
|
|
35
|
+
return undefined;
|
|
36
|
+
try {
|
|
37
|
+
url = trackerUrl?.(key);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
url = undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
return { key, ...(url?.startsWith("https://") ? { url } : {}), trackerName: ISSUE_SOURCE_NAMES[provider] };
|
|
47
|
+
}
|
|
14
48
|
/** A Jira project key. */
|
|
15
49
|
export const PROJECT_KEY = /^[A-Z][A-Z0-9_]{0,254}$/;
|
|
16
|
-
|
|
50
|
+
/** An issue key's project: a Jira key's project key ("PROJ-123" → "PROJ"); a GitHub issue key's repository ("owner/repo#5" → "owner/repo"). */
|
|
51
|
+
export const projectOf = (issueKey) => {
|
|
52
|
+
const hash = issueKey.lastIndexOf("#");
|
|
53
|
+
return issueKey.slice(0, hash >= 0 ? hash : issueKey.lastIndexOf("-"));
|
|
54
|
+
};
|
|
@@ -19,5 +19,9 @@ export interface ClaudeToolSetup {
|
|
|
19
19
|
content: string;
|
|
20
20
|
mode: number;
|
|
21
21
|
}[];
|
|
22
|
+
/** Present only when the run's dependency cache is on, so older tool runners see an unchanged setup. */
|
|
23
|
+
dependencyCache?: true;
|
|
24
|
+
/** With dependencyCache only: the workspace volume size (limits.diskMb) the cache must stay inside. */
|
|
25
|
+
diskMb?: number;
|
|
22
26
|
}
|
|
23
27
|
export declare function claudeToolSetup(spec: JobSpec, capability: string): string;
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* What Claude Code's tool runner (the credential-free container that runs commands in the
|
|
3
3
|
* repository) needs from the trusted launcher: the package-registry settings every Codex shell
|
|
4
4
|
* gets, built from the run's registry-only token (deriveRegistryToken, never the capability), and
|
|
5
|
-
* the run's service test variables
|
|
6
|
-
*
|
|
5
|
+
* the run's service test variables, and whether the run's dependency cache is on. Delivered as the
|
|
6
|
+
* WARDBY_TOOL_SETUP environment variable (CLAUDE_TOOL_SETUP_ENV, docker-isolation.ts; a test keeps it
|
|
7
|
+
* equal to the tool runner's TOOL_SETUP_ENV): a Kubernetes Secret key, or `docker create --env NAME`
|
|
8
|
+
* with the value in the CLI's own environment.
|
|
7
9
|
*/
|
|
8
10
|
import { serviceEnvironment } from "../../coding-worker/driver.js";
|
|
9
11
|
import { registryWorkerSetup } from "../../coding/registry/worker-config.js";
|
|
@@ -35,6 +37,7 @@ export function claudeToolSetup(spec, capability) {
|
|
|
35
37
|
// Same precedence as the Codex driver: the registry's own settings win over a service's.
|
|
36
38
|
env: { ...serviceEnvironment(spec.services), ...registry.env },
|
|
37
39
|
files: registry.files,
|
|
40
|
+
...(spec.dependencyCache ? { dependencyCache: true, diskMb: spec.limits.diskMb } : {}),
|
|
38
41
|
};
|
|
39
42
|
const raw = JSON.stringify(setup);
|
|
40
43
|
const limits = CLAUDE_TOOL_SETUP_LIMITS;
|
|
@@ -25,6 +25,14 @@ export declare const CLAUDE_TOOL_SETUP_ENV = "WARDBY_TOOL_SETUP";
|
|
|
25
25
|
export declare const CODING_PROXY_DENY_PORT = 8788;
|
|
26
26
|
export declare const DOCKER_ISOLATION_ERROR = "docker_isolation_unsupported";
|
|
27
27
|
export declare const WORKER_STOP_GRACE_SECONDS = 10;
|
|
28
|
+
/** The Claude worker's SDK config dir (claude-coding-worker/driver.ts CLAUDE_CONFIG_DIR). */
|
|
29
|
+
export declare const CLAUDE_CONFIG_PATH = "/tmp/claude-config";
|
|
30
|
+
/**
|
|
31
|
+
* Its own memory-backed scratch on a session-resume run: room for a session file up to the largest the
|
|
32
|
+
* control plane reads (coding/protocol.ts MAX_RAW_TRANSCRIPT_BYTES, 64 MiB) plus the SDK's small config
|
|
33
|
+
* files. Past it the SDK's writes there fail with ENOSPC, as /tmp's would; /tmp itself keeps its room.
|
|
34
|
+
*/
|
|
35
|
+
export declare const CLAUDE_CONFIG_SCRATCH_MIB = 80;
|
|
28
36
|
export declare const WORKER_PATHS: {
|
|
29
37
|
readonly workspace: "/workspace";
|
|
30
38
|
readonly git: "/workspace/.git";
|
|
@@ -206,6 +214,6 @@ export declare function assertStorageVolumeInspection(volume: DockerVolumeInspec
|
|
|
206
214
|
export declare function assertKeeperContainerInspection(container: DockerContainerInspection, spec: JobSpec): void;
|
|
207
215
|
export declare function assertNetworkKeeperContainerInspection(container: DockerContainerInspection, spec: JobSpec): void;
|
|
208
216
|
export declare function assertProxyContainerInspection(container: DockerContainerInspection, runId: string): void;
|
|
209
|
-
export declare function assertWorkerContainerInspection(container: DockerContainerInspection, spec: JobSpec, expectedCapability: string, networkKeeperId?: string): void;
|
|
210
|
-
export declare function assertClaudeAgentContainerInspection(container: DockerContainerInspection, spec: JobSpec, expectedCapability: string): void;
|
|
217
|
+
export declare function assertWorkerContainerInspection(container: DockerContainerInspection, spec: JobSpec, expectedCapability: string, networkKeeperId?: string, expectedMcpToken?: string): void;
|
|
218
|
+
export declare function assertClaudeAgentContainerInspection(container: DockerContainerInspection, spec: JobSpec, expectedCapability: string, expectedMcpToken?: string): void;
|
|
211
219
|
export declare function assertClaudeToolRunnerContainerInspection(container: DockerContainerInspection, spec: JobSpec, expectedSetup: string, networkKeeperId?: string): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { MCP_TOKEN_ENV } from "../../coding/mcp-token.js";
|
|
2
3
|
export const CODING_WORKER_UID = 10001;
|
|
3
4
|
export const CODING_WORKER_GID = 10001;
|
|
4
5
|
// The keeper needs headroom for runc's short-lived exec process plus Node's threads.
|
|
@@ -28,6 +29,14 @@ export const CLAUDE_TOOL_SETUP_ENV = "WARDBY_TOOL_SETUP";
|
|
|
28
29
|
export const CODING_PROXY_DENY_PORT = 8788;
|
|
29
30
|
export const DOCKER_ISOLATION_ERROR = "docker_isolation_unsupported";
|
|
30
31
|
export const WORKER_STOP_GRACE_SECONDS = 10;
|
|
32
|
+
/** The Claude worker's SDK config dir (claude-coding-worker/driver.ts CLAUDE_CONFIG_DIR). */
|
|
33
|
+
export const CLAUDE_CONFIG_PATH = "/tmp/claude-config";
|
|
34
|
+
/**
|
|
35
|
+
* Its own memory-backed scratch on a session-resume run: room for a session file up to the largest the
|
|
36
|
+
* control plane reads (coding/protocol.ts MAX_RAW_TRANSCRIPT_BYTES, 64 MiB) plus the SDK's small config
|
|
37
|
+
* files. Past it the SDK's writes there fail with ENOSPC, as /tmp's would; /tmp itself keeps its room.
|
|
38
|
+
*/
|
|
39
|
+
export const CLAUDE_CONFIG_SCRATCH_MIB = 80;
|
|
31
40
|
export const WORKER_PATHS = {
|
|
32
41
|
workspace: "/workspace",
|
|
33
42
|
git: "/workspace/.git",
|
|
@@ -90,6 +99,11 @@ function validateSpec(spec) {
|
|
|
90
99
|
else if (spec.toolImage !== undefined) {
|
|
91
100
|
throw isolationError();
|
|
92
101
|
}
|
|
102
|
+
if (spec.sessionResume !== undefined && (spec.sessionResume !== true || spec.provider !== "claude-code")) {
|
|
103
|
+
throw isolationError();
|
|
104
|
+
}
|
|
105
|
+
if (spec.mcpTools !== undefined && spec.mcpTools !== true)
|
|
106
|
+
throw isolationError();
|
|
93
107
|
if (spec.services !== undefined) {
|
|
94
108
|
// docker-services.ts re-validates every entry against the catalog schema. Both providers' shells
|
|
95
109
|
// share the network keeper's namespace: Codex's worker, and Claude Code's tool runner.
|
|
@@ -295,6 +309,27 @@ function workerNetworkMode(spec) {
|
|
|
295
309
|
const names = isolationNames(spec.runId);
|
|
296
310
|
return spec.services === undefined ? names.network : `container:${names.networkKeeperContainer}`;
|
|
297
311
|
}
|
|
312
|
+
/**
|
|
313
|
+
* A run with MCP tools only: the agent's MCP token, by name. Like the capability, its value comes
|
|
314
|
+
* from the docker process's own environment (DockerCommandOptions.env), never the command line.
|
|
315
|
+
*/
|
|
316
|
+
function mcpTokenEnvArgs(spec) {
|
|
317
|
+
return spec.mcpTools ? ["--env", MCP_TOKEN_ENV] : [];
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* The agent container's exact WARDBY_ environment: the proxy URL, the capability, and for a run with
|
|
321
|
+
* MCP tools its MCP token. Anything missing, changed or extra fails the attestation.
|
|
322
|
+
*/
|
|
323
|
+
function agentEnvironmentMatches(environment, spec, expectedCapability, expectedMcpToken) {
|
|
324
|
+
if (spec.mcpTools && expectedMcpToken === undefined)
|
|
325
|
+
return false;
|
|
326
|
+
const expected = [
|
|
327
|
+
`WARDBY_PROXY_URL=http://${CODING_PROXY_ALIAS}:${CODING_PROXY_PORT}`,
|
|
328
|
+
`WARDBY_RUN_CAPABILITY=${expectedCapability}`,
|
|
329
|
+
...(spec.mcpTools ? [`${MCP_TOKEN_ENV}=${expectedMcpToken}`] : []),
|
|
330
|
+
];
|
|
331
|
+
return environment.length === expected.length && expected.every((value) => environment.includes(value));
|
|
332
|
+
}
|
|
298
333
|
export function buildWorkerCreateArgs(spec, proxyPort = CODING_PROXY_PORT) {
|
|
299
334
|
validateSpec(spec);
|
|
300
335
|
assertIntegerRange(proxyPort, 1, 65_535);
|
|
@@ -349,6 +384,7 @@ export function buildWorkerCreateArgs(spec, proxyPort = CODING_PROXY_PORT) {
|
|
|
349
384
|
`WARDBY_PROXY_URL=http://${CODING_PROXY_ALIAS}:${proxyPort}`,
|
|
350
385
|
"--env",
|
|
351
386
|
"WARDBY_RUN_CAPABILITY",
|
|
387
|
+
...mcpTokenEnvArgs(spec),
|
|
352
388
|
"--restart",
|
|
353
389
|
"no",
|
|
354
390
|
"--stop-signal",
|
|
@@ -432,6 +468,12 @@ export function buildClaudeAgentCreateArgs(spec, proxyPort = CODING_PROXY_PORT)
|
|
|
432
468
|
`/tmp:rw,noexec,nosuid,nodev,size=${scratchMb}m,mode=1777`,
|
|
433
469
|
"--tmpfs",
|
|
434
470
|
`/home/wardby:rw,noexec,nosuid,nodev,size=${scratchMb}m,uid=${CODING_WORKER_UID},gid=${CODING_WORKER_GID},mode=0700`,
|
|
471
|
+
...(spec.sessionResume
|
|
472
|
+
? [
|
|
473
|
+
"--tmpfs",
|
|
474
|
+
`${CLAUDE_CONFIG_PATH}:rw,noexec,nosuid,nodev,size=${CLAUDE_CONFIG_SCRATCH_MIB}m,uid=${CODING_WORKER_UID},gid=${CODING_WORKER_GID},mode=0700`,
|
|
475
|
+
]
|
|
476
|
+
: []),
|
|
435
477
|
"--mount",
|
|
436
478
|
`type=volume,src=${names.storageVolume},dst=${WORKER_PATHS.input},volume-subpath=input,volume-nocopy,readonly`,
|
|
437
479
|
"--mount",
|
|
@@ -442,6 +484,7 @@ export function buildClaudeAgentCreateArgs(spec, proxyPort = CODING_PROXY_PORT)
|
|
|
442
484
|
`WARDBY_PROXY_URL=http://${CODING_PROXY_ALIAS}:${proxyPort}`,
|
|
443
485
|
"--env",
|
|
444
486
|
"WARDBY_RUN_CAPABILITY",
|
|
487
|
+
...mcpTokenEnvArgs(spec),
|
|
445
488
|
"--restart",
|
|
446
489
|
"no",
|
|
447
490
|
"--stop-signal",
|
|
@@ -763,7 +806,7 @@ function assertExactWorkerMounts(container, names) {
|
|
|
763
806
|
}
|
|
764
807
|
}
|
|
765
808
|
}
|
|
766
|
-
export function assertWorkerContainerInspection(container, spec, expectedCapability, networkKeeperId) {
|
|
809
|
+
export function assertWorkerContainerInspection(container, spec, expectedCapability, networkKeeperId, expectedMcpToken) {
|
|
767
810
|
validateSpec(spec);
|
|
768
811
|
const names = isolationNames(spec.runId);
|
|
769
812
|
const host = container.HostConfig;
|
|
@@ -805,9 +848,7 @@ export function assertWorkerContainerInspection(container, spec, expectedCapabil
|
|
|
805
848
|
Object.keys(container.NetworkSettings?.Ports ?? {}).length !== 0) {
|
|
806
849
|
throw isolationError();
|
|
807
850
|
}
|
|
808
|
-
if (wardbyEnvironment
|
|
809
|
-
!wardbyEnvironment.includes(`WARDBY_PROXY_URL=http://${CODING_PROXY_ALIAS}:${CODING_PROXY_PORT}`) ||
|
|
810
|
-
!wardbyEnvironment.includes(`WARDBY_RUN_CAPABILITY=${expectedCapability}`)) {
|
|
851
|
+
if (!agentEnvironmentMatches(wardbyEnvironment, spec, expectedCapability, expectedMcpToken)) {
|
|
811
852
|
throw isolationError();
|
|
812
853
|
}
|
|
813
854
|
const tmpfs = host.Tmpfs ?? {};
|
|
@@ -876,16 +917,14 @@ function assertClaudeContainerBaseline(container, image, spec, limits) {
|
|
|
876
917
|
!host.Tmpfs?.["/home/wardby"]?.includes("noexec"))
|
|
877
918
|
throw isolationError();
|
|
878
919
|
}
|
|
879
|
-
export function assertClaudeAgentContainerInspection(container, spec, expectedCapability) {
|
|
920
|
+
export function assertClaudeAgentContainerInspection(container, spec, expectedCapability, expectedMcpToken) {
|
|
880
921
|
validateSpec(spec);
|
|
881
922
|
if (spec.provider !== "claude-code")
|
|
882
923
|
throw isolationError();
|
|
883
924
|
const names = isolationNames(spec.runId);
|
|
884
925
|
assertClaudeContainerBaseline(container, spec.image, spec, claudeAgentLimits(spec));
|
|
885
926
|
const environment = (container.Config?.Env ?? []).filter((value) => value.startsWith("WARDBY_"));
|
|
886
|
-
if (environment
|
|
887
|
-
!environment.includes(`WARDBY_PROXY_URL=http://${CODING_PROXY_ALIAS}:${CODING_PROXY_PORT}`) ||
|
|
888
|
-
!environment.includes(`WARDBY_RUN_CAPABILITY=${expectedCapability}`))
|
|
927
|
+
if (!agentEnvironmentMatches(environment, spec, expectedCapability, expectedMcpToken))
|
|
889
928
|
throw isolationError();
|
|
890
929
|
assertExactMountSet(container, names, [
|
|
891
930
|
{ path: WORKER_PATHS.input, writable: false, subpath: "input" },
|
|
@@ -88,6 +88,12 @@ export interface DockerJobLauncherOptions {
|
|
|
88
88
|
workspaceRoot: string;
|
|
89
89
|
proxyContainer: string;
|
|
90
90
|
resolveCapability: (runId: string) => Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* The run's MCP token (the capability vault), asked for only when the spec has mcpTools; the agent
|
|
93
|
+
* container gets it as WARDBY_MCP_TOKEN, through the docker process's environment like the
|
|
94
|
+
* capability. Absent = a run with MCP tools can't be launched.
|
|
95
|
+
*/
|
|
96
|
+
resolveMcpToken?: (runId: string) => Promise<string | undefined>;
|
|
91
97
|
/** Consult the durable application state before a startup sweep deletes resources. */
|
|
92
98
|
isRunActive: (runId: string, handle: JobHandle) => Promise<boolean>;
|
|
93
99
|
docker?: DockerCommandRunner;
|
|
@@ -131,6 +137,8 @@ export declare class DockerJobLauncher implements WorkspaceJobLauncher {
|
|
|
131
137
|
remove(handle: JobHandle): Promise<void>;
|
|
132
138
|
private initialize;
|
|
133
139
|
private launchLocked;
|
|
140
|
+
/** The run's MCP token for a spec with mcpTools (refused unless well formed); undefined otherwise, unasked. */
|
|
141
|
+
private mcpTokenFor;
|
|
134
142
|
private provision;
|
|
135
143
|
/**
|
|
136
144
|
* A run with services (docs/coding-services.md). The network keeper joins the run's internal
|
|
@@ -164,6 +172,7 @@ export declare class DockerJobLauncher implements WorkspaceJobLauncher {
|
|
|
164
172
|
private removeNetworkIfAttested;
|
|
165
173
|
private removeVolumeIfAttested;
|
|
166
174
|
private seedRun;
|
|
175
|
+
readTranscript(handle: JobHandle, maxBytes: number): Promise<string | undefined>;
|
|
167
176
|
private readResultArtifact;
|
|
168
177
|
private readWorkerFailureDiagnostic;
|
|
169
178
|
private keeperName;
|
|
@@ -7,11 +7,12 @@ import { dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
|
7
7
|
import { logger } from "../../core/logger.js";
|
|
8
8
|
import { ensurePrivateDirectory } from "../../core/private-directory.js";
|
|
9
9
|
import { readBoundedRegularFile } from "../../coding-worker/artifact.js";
|
|
10
|
-
import {
|
|
10
|
+
import { parseCodingWorkerOutputJson, redactAndTruncate, MAX_CODING_ARTIFACT_BYTES, MAX_CODING_INPUT_BYTES, MAX_CODING_OUTPUT_ISSUES, SAFE_CODING_OUTPUT_ISSUE, } from "../../coding/protocol.js";
|
|
11
11
|
import { assertDockerHostSupportsIsolation, assertClaudeAgentContainerInspection, assertClaudeToolRunnerContainerInspection, assertIsolationNetworkInspection, assertKeeperContainerInspection, assertNetworkKeeperContainerInspection, assertProxyContainerInspection, assertStorageVolumeInspection, assertWorkerContainerInspection, buildDockerIsolationPlan, CLAUDE_TOOL_SETUP_ENV, dockerSupportsServicesFor, } from "./docker-isolation.js";
|
|
12
12
|
import { serviceUnreadyError } from "../../coding/services/wording.js";
|
|
13
13
|
import { assertServiceContainerInspection, buildDockerServicePlan, dockerServiceContainerNames, } from "./docker-services.js";
|
|
14
14
|
import { claudeToolSetup } from "./claude-tool-setup.js";
|
|
15
|
+
import { isMcpToken, MCP_TOKEN_ENV } from "../../coding/mcp-token.js";
|
|
15
16
|
import { reportServiceState, } from "./service-state.js";
|
|
16
17
|
import { replaceDirectoryFromStaging } from "./workspace-swap.js";
|
|
17
18
|
const BACKEND = "docker";
|
|
@@ -95,7 +96,7 @@ export class NodeDockerCommandRunner {
|
|
|
95
96
|
if (args.some((argument) => argument.includes("\0")))
|
|
96
97
|
throw new Error("docker_argument_invalid");
|
|
97
98
|
const extraEnv = options.env ?? {};
|
|
98
|
-
if (Object.keys(extraEnv).some((key) => key !== "WARDBY_RUN_CAPABILITY" && key !== CLAUDE_TOOL_SETUP_ENV))
|
|
99
|
+
if (Object.keys(extraEnv).some((key) => key !== "WARDBY_RUN_CAPABILITY" && key !== MCP_TOKEN_ENV && key !== CLAUDE_TOOL_SETUP_ENV))
|
|
99
100
|
throw new Error("docker_environment_invalid");
|
|
100
101
|
const env = {
|
|
101
102
|
PATH: this.path,
|
|
@@ -447,6 +448,10 @@ function serviceUnready(name, cause) {
|
|
|
447
448
|
function capabilityFromInspection(container) {
|
|
448
449
|
return container.Config?.Env?.find((value) => value.startsWith("WARDBY_RUN_CAPABILITY="))?.slice("WARDBY_RUN_CAPABILITY=".length);
|
|
449
450
|
}
|
|
451
|
+
function mcpTokenFromInspection(container) {
|
|
452
|
+
const prefix = `${MCP_TOKEN_ENV}=`;
|
|
453
|
+
return container.Config?.Env?.find((value) => value.startsWith(prefix))?.slice(prefix.length);
|
|
454
|
+
}
|
|
450
455
|
function dockerState(inspection) {
|
|
451
456
|
const state = inspection.State;
|
|
452
457
|
if (!state)
|
|
@@ -655,14 +660,19 @@ export class DockerJobLauncher {
|
|
|
655
660
|
const capability = ensureCapability(await this.options.resolveCapability(spec.runId));
|
|
656
661
|
if (hash(capability) !== existing.capabilityHash)
|
|
657
662
|
throw new Error("docker_capability_changed");
|
|
663
|
+
const mcpToken = await this.mcpTokenFor(spec);
|
|
664
|
+
if ((mcpToken === undefined ? undefined : hash(mcpToken)) !== existing.mcpTokenHash) {
|
|
665
|
+
throw new Error("docker_mcp_token_changed");
|
|
666
|
+
}
|
|
658
667
|
if (existing.phase === "active") {
|
|
659
668
|
await this.refresh(existing);
|
|
660
669
|
return clone(existing.handle);
|
|
661
670
|
}
|
|
662
|
-
return this.provision(existing, plan, services, capability);
|
|
671
|
+
return this.provision(existing, plan, services, capability, mcpToken);
|
|
663
672
|
}
|
|
664
673
|
await this.validateInputArtifact(spec.inputArtifact);
|
|
665
674
|
const capability = ensureCapability(await this.options.resolveCapability(spec.runId));
|
|
675
|
+
const mcpToken = await this.mcpTokenFor(spec);
|
|
666
676
|
const record = {
|
|
667
677
|
schemaVersion: STATE_SCHEMA_VERSION,
|
|
668
678
|
runId: spec.runId,
|
|
@@ -673,12 +683,13 @@ export class DockerJobLauncher {
|
|
|
673
683
|
createdAt: this.now(),
|
|
674
684
|
deadlineAt: this.now() + plan.deadlineMs,
|
|
675
685
|
capabilityHash: hash(capability),
|
|
686
|
+
...(mcpToken !== undefined ? { mcpTokenHash: hash(mcpToken) } : {}),
|
|
676
687
|
phase: "provisioning",
|
|
677
688
|
};
|
|
678
689
|
// This durable record is the idempotency fence before any Docker side effect.
|
|
679
690
|
await this.writeRecord(record);
|
|
680
691
|
try {
|
|
681
|
-
return await this.provision(record, plan, services, capability);
|
|
692
|
+
return await this.provision(record, plan, services, capability, mcpToken);
|
|
682
693
|
}
|
|
683
694
|
catch (error) {
|
|
684
695
|
await this.options
|
|
@@ -691,7 +702,16 @@ export class DockerJobLauncher {
|
|
|
691
702
|
throw error;
|
|
692
703
|
}
|
|
693
704
|
}
|
|
694
|
-
|
|
705
|
+
/** The run's MCP token for a spec with mcpTools (refused unless well formed); undefined otherwise, unasked. */
|
|
706
|
+
async mcpTokenFor(spec) {
|
|
707
|
+
if (!spec.mcpTools)
|
|
708
|
+
return undefined;
|
|
709
|
+
const token = await this.options.resolveMcpToken?.(spec.runId);
|
|
710
|
+
if (!isMcpToken(token))
|
|
711
|
+
throw new Error("docker_mcp_token_invalid");
|
|
712
|
+
return token;
|
|
713
|
+
}
|
|
714
|
+
async provision(record, plan, services, capability, mcpToken) {
|
|
695
715
|
await this.assertHost();
|
|
696
716
|
const labels = resourceLabels(record);
|
|
697
717
|
await this.createAndAssert(appendLabels(plan.networkCreateArgs, labels), ["network", "inspect", plan.names.network], (value) => {
|
|
@@ -740,14 +760,14 @@ export class DockerJobLauncher {
|
|
|
740
760
|
await this.createAndAssert(workerArgs, ["container", "inspect", plan.names.workerContainer], (value) => {
|
|
741
761
|
const inspected = value;
|
|
742
762
|
if (record.spec.provider === "claude-code") {
|
|
743
|
-
assertClaudeAgentContainerInspection(inspected, record.spec, capability);
|
|
763
|
+
assertClaudeAgentContainerInspection(inspected, record.spec, capability, mcpToken);
|
|
744
764
|
}
|
|
745
765
|
else {
|
|
746
|
-
assertWorkerContainerInspection(inspected, record.spec, capability, networkKeeperId);
|
|
766
|
+
assertWorkerContainerInspection(inspected, record.spec, capability, networkKeeperId, mcpToken);
|
|
747
767
|
}
|
|
748
768
|
if (!labelsMatch(inspected.Config?.Labels, labels))
|
|
749
769
|
throw new Error("docker_resource_attestation_failed");
|
|
750
|
-
}, { env: { WARDBY_RUN_CAPABILITY: capability } });
|
|
770
|
+
}, { env: { WARDBY_RUN_CAPABILITY: capability, ...(mcpToken !== undefined ? { [MCP_TOKEN_ENV]: mcpToken } : {}) } });
|
|
751
771
|
await this.startContainer(plan.names.workerContainer);
|
|
752
772
|
record.phase = "active";
|
|
753
773
|
await this.writeRecord(record);
|
|
@@ -939,8 +959,12 @@ export class DockerJobLauncher {
|
|
|
939
959
|
const capability = capabilityFromInspection(inspection);
|
|
940
960
|
if (!capability || hash(capability) !== record.capabilityHash)
|
|
941
961
|
throw new Error("docker_resource_attestation_failed");
|
|
962
|
+
// Only a run with MCP tools carries a token, and only the one its record hashed.
|
|
963
|
+
const mcpToken = record.spec.mcpTools ? mcpTokenFromInspection(inspection) : undefined;
|
|
964
|
+
if (record.spec.mcpTools && (!mcpToken || hash(mcpToken) !== record.mcpTokenHash))
|
|
965
|
+
throw new Error("docker_resource_attestation_failed");
|
|
942
966
|
if (record.spec.provider === "claude-code") {
|
|
943
|
-
assertClaudeAgentContainerInspection(inspection, record.spec, capability);
|
|
967
|
+
assertClaudeAgentContainerInspection(inspection, record.spec, capability, mcpToken);
|
|
944
968
|
const tool = await this.inspect([
|
|
945
969
|
"container",
|
|
946
970
|
"inspect",
|
|
@@ -956,7 +980,7 @@ export class DockerJobLauncher {
|
|
|
956
980
|
}
|
|
957
981
|
}
|
|
958
982
|
else {
|
|
959
|
-
assertWorkerContainerInspection(inspection, record.spec, capability, await this.attestedNetworkKeeperId(record));
|
|
983
|
+
assertWorkerContainerInspection(inspection, record.spec, capability, await this.attestedNetworkKeeperId(record), mcpToken);
|
|
960
984
|
}
|
|
961
985
|
const phase = dockerState(inspection);
|
|
962
986
|
if (!phase || phase === "provisioning" || phase === "active")
|
|
@@ -1067,13 +1091,38 @@ export class DockerJobLauncher {
|
|
|
1067
1091
|
await this.transfer.seedDirectory(resolve(runRoot, "git"), keeper, "/run/wardby/storage/git");
|
|
1068
1092
|
await this.transfer.seedInput(record.spec.inputArtifact, keeper);
|
|
1069
1093
|
}
|
|
1094
|
+
async readTranscript(handle, maxBytes) {
|
|
1095
|
+
await this.ready;
|
|
1096
|
+
const record = await this.findRecord(handle);
|
|
1097
|
+
if (!record)
|
|
1098
|
+
return undefined;
|
|
1099
|
+
const staging = await mkdtemp(join(this.stateRoot, ".wardby-transcript-"));
|
|
1100
|
+
const target = join(staging, "session.jsonl");
|
|
1101
|
+
try {
|
|
1102
|
+
try {
|
|
1103
|
+
await this.run([
|
|
1104
|
+
"container",
|
|
1105
|
+
"cp",
|
|
1106
|
+
`${this.keeperName(record)}:/run/wardby/storage/output/session.jsonl`,
|
|
1107
|
+
target,
|
|
1108
|
+
]);
|
|
1109
|
+
}
|
|
1110
|
+
catch {
|
|
1111
|
+
return undefined;
|
|
1112
|
+
}
|
|
1113
|
+
return await readBoundedRegularFile(target, maxBytes, "transcript_too_large");
|
|
1114
|
+
}
|
|
1115
|
+
finally {
|
|
1116
|
+
await rm(staging, { recursive: true, force: true });
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1070
1119
|
async readResultArtifact(record) {
|
|
1071
1120
|
const staging = await mkdtemp(join(this.stateRoot, ".wardby-result-"));
|
|
1072
1121
|
const target = join(staging, "result.json");
|
|
1073
1122
|
try {
|
|
1074
1123
|
await this.run(["container", "cp", `${this.keeperName(record)}:/run/wardby/storage/output/result.json`, target]);
|
|
1075
1124
|
const raw = await readBoundedRegularFile(target, MAX_CODING_ARTIFACT_BYTES, "docker_result_artifact_invalid");
|
|
1076
|
-
const output =
|
|
1125
|
+
const output = parseCodingWorkerOutputJson(raw);
|
|
1077
1126
|
if (output.runId !== record.runId)
|
|
1078
1127
|
throw new Error("docker_result_run_mismatch");
|
|
1079
1128
|
return JSON.stringify(output);
|
|
@@ -31,6 +31,8 @@ export declare class FakeKubernetesApi implements KubernetesApi {
|
|
|
31
31
|
onExec: (call: FakeExecCall) => Promise<number>;
|
|
32
32
|
/** The admission chain a dry-run create runs through. Default: echo the pod back unchanged. */
|
|
33
33
|
onDryRunCreatePod: (namespace: string, body: V1Pod) => Promise<V1Pod>;
|
|
34
|
+
/** Runs at the start of every pod create; tests throw KubernetesQuotaExceededError (or anything) from it. */
|
|
35
|
+
onCreatePod: (namespace: string, body: V1Pod) => Promise<void>;
|
|
34
36
|
readonly deploymentPatches: Array<{
|
|
35
37
|
name: string;
|
|
36
38
|
replicas?: number;
|
|
@@ -13,6 +13,8 @@ export class FakeKubernetesApi {
|
|
|
13
13
|
};
|
|
14
14
|
/** The admission chain a dry-run create runs through. Default: echo the pod back unchanged. */
|
|
15
15
|
onDryRunCreatePod = async (_namespace, body) => body;
|
|
16
|
+
/** Runs at the start of every pod create; tests throw KubernetesQuotaExceededError (or anything) from it. */
|
|
17
|
+
onCreatePod = async () => { };
|
|
16
18
|
deploymentPatches = [];
|
|
17
19
|
/** Deployment names whose patch throws KubernetesForbiddenError. */
|
|
18
20
|
forbidden = new Set();
|
|
@@ -83,6 +85,7 @@ export class FakeKubernetesApi {
|
|
|
83
85
|
this.delete("secret", namespace, name);
|
|
84
86
|
}
|
|
85
87
|
async createPod(namespace, body) {
|
|
88
|
+
await this.onCreatePod(namespace, body);
|
|
86
89
|
return this.create("pod", namespace, body);
|
|
87
90
|
}
|
|
88
91
|
/**
|
|
@@ -12,6 +12,14 @@ export declare class KubernetesNotFoundError extends Error {
|
|
|
12
12
|
export declare class KubernetesForbiddenError extends Error {
|
|
13
13
|
constructor(message?: string, options?: ErrorOptions);
|
|
14
14
|
}
|
|
15
|
+
/** A create the namespace ResourceQuota refused (HTTP 403 "exceeded quota"). */
|
|
16
|
+
export declare class KubernetesQuotaExceededError extends Error {
|
|
17
|
+
/** The refusing quota's name as the API server worded it; unvalidated, and nothing else of the refusal is kept. */
|
|
18
|
+
readonly quotaName?: string;
|
|
19
|
+
constructor(message?: string, options?: ErrorOptions & {
|
|
20
|
+
quotaName?: string;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
15
23
|
/** Stale resourceVersion on replace. */
|
|
16
24
|
export declare class KubernetesConflictError extends Error {
|
|
17
25
|
constructor(message?: string);
|