@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
|
@@ -1,19 +1,41 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import {
|
|
2
|
+
import { constants as fsConstants } from "node:fs";
|
|
3
|
+
import { lstat, mkdir, open, opendir, readFile, readlink, realpath, rm, writeFile, } from "node:fs/promises";
|
|
3
4
|
import { isAbsolute, resolve, sep } from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { gitExcludePathspecs, normalizeCollectExclusions } from "../../coding/collect-exclude.js";
|
|
6
7
|
import { WARDBY_PROTECTED_PATHS, isProtectedPathException, isWellFormedProtectedPath, protectedPathBody, protectsSomePath, } from "../../coding/protected-paths.js";
|
|
7
8
|
import { ensurePrivateDirectory } from "../../core/private-directory.js";
|
|
9
|
+
import { simulatorGitEnvironment } from "../../config/test-simulators.js";
|
|
8
10
|
import { globRegex } from "../../core/glob.js";
|
|
11
|
+
import { redactExactSecretValues } from "../../core/secret-spans.js";
|
|
9
12
|
import { MAX_REDACTED_SPAN, redactTokenShapedValues, normalizeGitRef } from "../../coding/protocol.js";
|
|
10
|
-
import {
|
|
13
|
+
import { isSafeGitAuthToken } from "./remote.js";
|
|
11
14
|
export const DEFAULT_MAX_CHANGED_FILES = 1_000;
|
|
12
15
|
export const DEFAULT_MAX_DIFF_BYTES = 1024 * 1024;
|
|
13
16
|
const MAX_GIT_OUTPUT_BYTES = 2 * 1024 * 1024;
|
|
14
17
|
const MAX_WORKSPACE_ENTRIES = 100_000;
|
|
15
18
|
const SAFE_COMMIT_SHA = /^[0-9a-f]{40}$/;
|
|
19
|
+
const SAFE_GIT_USERNAME = /^[A-Za-z0-9._-]{1,64}$/;
|
|
16
20
|
const SAFE_RUN_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
|
|
21
|
+
/** Where a continuation's target branch is fetched to (never under refs/remotes, so baseCommit's ref is untouched). */
|
|
22
|
+
const MERGE_TARGET_REF = "refs/wardby/merge-target";
|
|
23
|
+
/** Where the head branch is re-fetched while deepening history (see fetchMergeTarget). */
|
|
24
|
+
const MERGE_HEAD_REF = "refs/wardby/merge-head";
|
|
25
|
+
/**
|
|
26
|
+
* The trusted automatic merge of the target branch, recorded at prepare time:
|
|
27
|
+
* a commit whose tree is the merge result (markers in conflicted files), whose
|
|
28
|
+
* parents are baseCommit and the target commit, and whose message carries the
|
|
29
|
+
* target ref and the conflicted paths as JSON. Recovery and finalize read it
|
|
30
|
+
* back; the agent's changes are measured against its tree.
|
|
31
|
+
*/
|
|
32
|
+
const MERGE_STATE_REF = "refs/wardby/merge-state";
|
|
33
|
+
const MERGE_STATE_SUBJECT = "wardby merge state";
|
|
34
|
+
/** How far `fetch --deepen` goes, step by step, looking for a merge base in a depth-1 clone. */
|
|
35
|
+
const MERGE_BASE_DEEPEN_STEPS = [64, 256, 1024, 4096];
|
|
36
|
+
/** A conflict marker pair at the start of a line: git writes 7 characters (any longer run counts too), then a space or the line end. */
|
|
37
|
+
const CONFLICT_MARKER_START = /^<{7,}(?: |\r?$)/m;
|
|
38
|
+
const CONFLICT_MARKER_END = /^>{7,}(?: |\r?$)/m;
|
|
17
39
|
const HARDENED_GIT_CONFIG = [
|
|
18
40
|
"-c",
|
|
19
41
|
"core.hooksPath=/dev/null",
|
|
@@ -41,11 +63,10 @@ export function redactGitOutput(value, secrets = []) {
|
|
|
41
63
|
// MAX_REDACTED_SPAN of margin rather than on all 2 MiB git may have produced
|
|
42
64
|
// (see redactAndTruncate: the margin is what keeps truncation safe). The rest
|
|
43
65
|
// is discarded here and never reaches a log or the database.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
66
|
+
// The shared span-union redactor; any non-empty value counts here, as it always has.
|
|
67
|
+
const output = redactExactSecretValues(value.slice(0, GIT_OUTPUT_DISPLAY_BYTES + MAX_REDACTED_SPAN), secrets, {
|
|
68
|
+
minLength: 1,
|
|
69
|
+
});
|
|
49
70
|
return redactTokenShapedValues(output).slice(0, GIT_OUTPUT_DISPLAY_BYTES);
|
|
50
71
|
}
|
|
51
72
|
/** Runs Git without a shell or inherited application secrets. */
|
|
@@ -62,9 +83,12 @@ export class NodeGitCommandRunner {
|
|
|
62
83
|
options.askPassPath ?? fileURLToPath(new URL("../../../scripts/git-askpass.sh", import.meta.url));
|
|
63
84
|
}
|
|
64
85
|
async run(args, options = {}) {
|
|
65
|
-
if (options.authToken !== undefined && !
|
|
86
|
+
if (options.authToken !== undefined && !isSafeGitAuthToken(options.authToken)) {
|
|
66
87
|
throw new Error("git_auth_token_invalid");
|
|
67
88
|
}
|
|
89
|
+
if (options.authUsername !== undefined && !SAFE_GIT_USERNAME.test(options.authUsername)) {
|
|
90
|
+
throw new Error("git_auth_username_invalid");
|
|
91
|
+
}
|
|
68
92
|
const env = {
|
|
69
93
|
PATH: this.path,
|
|
70
94
|
HOME: this.options.homeDir,
|
|
@@ -77,8 +101,11 @@ export class NodeGitCommandRunner {
|
|
|
77
101
|
GIT_TERMINAL_PROMPT: "0",
|
|
78
102
|
GCM_INTERACTIVE: "never",
|
|
79
103
|
GIT_ASKPASS: options.authToken ? this.askPassPath : "/bin/false",
|
|
104
|
+
...(options.authToken && options.authUsername ? { WARDBY_GIT_USERNAME: options.authUsername } : {}),
|
|
80
105
|
SSH_ASKPASS: "/bin/false",
|
|
81
106
|
GIT_LFS_SKIP_SMUDGE: "1",
|
|
107
|
+
// WARDBY_TEST_SIMULATORS (test only): the simulator's throwaway CA; empty otherwise.
|
|
108
|
+
...simulatorGitEnvironment(),
|
|
82
109
|
};
|
|
83
110
|
const maxBytes = options.maxOutputBytes ?? MAX_GIT_OUTPUT_BYTES;
|
|
84
111
|
const secrets = options.authToken ? [options.authToken] : [];
|
|
@@ -133,7 +160,7 @@ export class NodeGitCommandRunner {
|
|
|
133
160
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
134
161
|
stderr: redactGitOutput(Buffer.concat(stderr).toString("utf8"), secrets),
|
|
135
162
|
};
|
|
136
|
-
if (code !== 0) {
|
|
163
|
+
if (code !== 0 && (code === null || !options.acceptExitCodes?.includes(code))) {
|
|
137
164
|
rejectPromise(new GitCommandError(code, result.stderr.trim()));
|
|
138
165
|
return;
|
|
139
166
|
}
|
|
@@ -192,6 +219,26 @@ function nullSeparated(value) {
|
|
|
192
219
|
values.pop();
|
|
193
220
|
return values.map(validateChangedPath);
|
|
194
221
|
}
|
|
222
|
+
function safeGitRef(value) {
|
|
223
|
+
try {
|
|
224
|
+
return normalizeGitRef(value);
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/** The merge state's message: a fixed subject, then the target ref and conflicted paths as JSON. */
|
|
231
|
+
function mergeStateMessage(targetMerge) {
|
|
232
|
+
return `${MERGE_STATE_SUBJECT}\n\n${JSON.stringify({ ref: targetMerge.ref, conflicted: targetMerge.conflictedPaths })}\n`;
|
|
233
|
+
}
|
|
234
|
+
function sameTargetMerge(left, right) {
|
|
235
|
+
if (!left || !right)
|
|
236
|
+
return left === right;
|
|
237
|
+
return (left.ref === right.ref &&
|
|
238
|
+
left.targetCommit === right.targetCommit &&
|
|
239
|
+
left.conflictedPaths.length === right.conflictedPaths.length &&
|
|
240
|
+
left.conflictedPaths.every((path, index) => path === right.conflictedPaths[index]));
|
|
241
|
+
}
|
|
195
242
|
function directChild(root, child) {
|
|
196
243
|
return child.startsWith(`${root}${sep}`) && !child.slice(root.length + 1).includes(sep);
|
|
197
244
|
}
|
|
@@ -244,9 +291,14 @@ export class GitVcsProvider {
|
|
|
244
291
|
// baseCommit already means exactly what it needs to: "where this
|
|
245
292
|
// round started."
|
|
246
293
|
const cloneBranch = normalized.continuation ? normalized.headRef : normalized.baseRef;
|
|
294
|
+
// A continuation is first brought up to date with the branch its pull
|
|
295
|
+
// request targets now (a person may have retargeted it since the root run).
|
|
296
|
+
const target = normalized.continuation ? await this.remote.pullRequestBase?.(normalized) : null;
|
|
297
|
+
const mergeRef = target ? safeGitRef(target.ref) : null;
|
|
298
|
+
let mergeFetched = false;
|
|
247
299
|
try {
|
|
248
300
|
await this.remote.withAccess(normalized.repository, async (token) => {
|
|
249
|
-
const auth = token
|
|
301
|
+
const auth = this.gitAuth(token);
|
|
250
302
|
if (this.remote.refNotFoundError) {
|
|
251
303
|
const listed = await this.git.run([
|
|
252
304
|
...HARDENED_GIT_CONFIG,
|
|
@@ -280,6 +332,9 @@ export class GitVcsProvider {
|
|
|
280
332
|
cloneUrl,
|
|
281
333
|
workspacePath,
|
|
282
334
|
], { cwd: runRoot, ...auth });
|
|
335
|
+
if (mergeRef && mergeRef !== normalized.headRef) {
|
|
336
|
+
mergeFetched = await this.fetchMergeTarget(gitMetadataPath, workspacePath, cloneBranch, mergeRef, auth);
|
|
337
|
+
}
|
|
283
338
|
});
|
|
284
339
|
await rm(resolve(workspacePath, ".git"), { force: true });
|
|
285
340
|
const baseCommit = await this.revParseRaw(gitMetadataPath, workspacePath, `refs/remotes/origin/${cloneBranch}^{commit}`);
|
|
@@ -307,7 +362,15 @@ export class GitVcsProvider {
|
|
|
307
362
|
"HEAD",
|
|
308
363
|
`refs/heads/${normalized.headRef}`,
|
|
309
364
|
]);
|
|
310
|
-
|
|
365
|
+
const merged = mergeFetched && mergeRef
|
|
366
|
+
? await this.mergeTargetBranch(gitMetadataPath, workspacePath, baseCommit, mergeRef)
|
|
367
|
+
: null;
|
|
368
|
+
await this.gitForPaths(gitMetadataPath, workspacePath, [
|
|
369
|
+
"read-tree",
|
|
370
|
+
"--reset",
|
|
371
|
+
"-u",
|
|
372
|
+
merged?.tree ?? baseCommit,
|
|
373
|
+
]);
|
|
311
374
|
await this.inspectWorkspace(workspacePath);
|
|
312
375
|
return {
|
|
313
376
|
id: `vcs-${normalized.runId}`,
|
|
@@ -315,6 +378,7 @@ export class GitVcsProvider {
|
|
|
315
378
|
baseCommit,
|
|
316
379
|
workspacePath,
|
|
317
380
|
gitMetadataPath,
|
|
381
|
+
...(merged ? { targetMerge: merged.targetMerge } : {}),
|
|
318
382
|
};
|
|
319
383
|
}
|
|
320
384
|
catch (error) {
|
|
@@ -351,19 +415,30 @@ export class GitVcsProvider {
|
|
|
351
415
|
const symbolicHead = (await this.gitFor(prepared, ["symbolic-ref", "--short", "HEAD"])).stdout.trim();
|
|
352
416
|
if (symbolicHead !== prepared.headRef)
|
|
353
417
|
throw new Error("vcs_head_ref_mismatch");
|
|
418
|
+
const merge = await this.readMergeState(prepared);
|
|
354
419
|
const currentHead = await this.revParse(prepared, "HEAD");
|
|
355
420
|
if (currentHead !== prepared.baseCommit) {
|
|
356
421
|
const parent = await this.revParse(prepared, "HEAD^");
|
|
357
422
|
if (parent !== prepared.baseCommit)
|
|
358
423
|
throw new Error("vcs_commit_history_invalid");
|
|
424
|
+
if (merge && (await this.revParse(prepared, "HEAD^2")) !== merge.targetCommit) {
|
|
425
|
+
throw new Error("vcs_commit_history_invalid");
|
|
426
|
+
}
|
|
359
427
|
}
|
|
360
|
-
|
|
428
|
+
if (!merge)
|
|
429
|
+
return prepared;
|
|
430
|
+
const { stateCommit: _stateCommit, ...targetMerge } = merge;
|
|
431
|
+
return { ...prepared, targetMerge };
|
|
361
432
|
}
|
|
362
433
|
async finalizeChanges(workspace, details) {
|
|
363
434
|
const prepared = await this.validatePrepared(workspace);
|
|
364
435
|
await this.inspectWorkspace(prepared.workspacePath);
|
|
365
436
|
await this.assertRemote(prepared);
|
|
366
437
|
await this.assertSafeLocalConfig(prepared.gitMetadataPath);
|
|
438
|
+
// The merge state on disk is the trusted record; the handle must agree with it.
|
|
439
|
+
const merge = await this.readMergeState(prepared);
|
|
440
|
+
if (!sameTargetMerge(merge, prepared.targetMerge))
|
|
441
|
+
throw new Error("vcs_workspace_handle_invalid");
|
|
367
442
|
// Excluded paths (src/coding/collect-exclude.ts) are never collected from the worker, so
|
|
368
443
|
// they are also neither added nor deleted here: tracked files under them stay untouched.
|
|
369
444
|
await this.gitFor(prepared, [
|
|
@@ -373,15 +448,12 @@ export class GitVcsProvider {
|
|
|
373
448
|
":/",
|
|
374
449
|
...gitExcludePathspecs(normalizeCollectExclusions(prepared.collectExclude)),
|
|
375
450
|
]);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
prepared.baseCommit,
|
|
383
|
-
"--",
|
|
384
|
-
])).stdout);
|
|
451
|
+
// Every check below applies to the agent's own changes: against baseCommit, or, after a
|
|
452
|
+
// merge, against the trusted automatic merge result (so the target branch's own changes,
|
|
453
|
+
// protected paths included, pass, while any agent edit -- a conflict it resolved, a
|
|
454
|
+
// target change it reverted -- is checked).
|
|
455
|
+
const comparedTo = merge?.stateCommit ?? prepared.baseCommit;
|
|
456
|
+
const changed = nullSeparated((await this.gitFor(prepared, ["diff", "--cached", "--name-only", "-z", "--no-renames", comparedTo, "--"])).stdout);
|
|
385
457
|
if (changed.length > this.maxChangedFiles)
|
|
386
458
|
throw new Error("vcs_changed_file_limit");
|
|
387
459
|
const protectedChange = changed.find(protectedPathMatcher(prepared.protectedPaths));
|
|
@@ -389,7 +461,7 @@ export class GitVcsProvider {
|
|
|
389
461
|
throw new Error(`vcs_protected_path:${protectedChange}`);
|
|
390
462
|
let diff;
|
|
391
463
|
try {
|
|
392
|
-
diff = (await this.gitFor(prepared, ["diff", "--cached", "--binary", "--no-ext-diff", "--no-textconv",
|
|
464
|
+
diff = (await this.gitFor(prepared, ["diff", "--cached", "--binary", "--no-ext-diff", "--no-textconv", comparedTo, "--"], { maxOutputBytes: this.maxDiffBytes })).stdout;
|
|
393
465
|
}
|
|
394
466
|
catch (error) {
|
|
395
467
|
if (error instanceof GitCommandError && error.message.includes("git_output_limit")) {
|
|
@@ -399,8 +471,12 @@ export class GitVcsProvider {
|
|
|
399
471
|
}
|
|
400
472
|
if (Buffer.byteLength(diff, "utf8") > this.maxDiffBytes)
|
|
401
473
|
throw new Error("vcs_diff_size_limit");
|
|
474
|
+
// After the size limits, so a conflicted file is never read past what the diff limit allows.
|
|
475
|
+
if (merge)
|
|
476
|
+
await this.assertConflictsResolved(prepared.workspacePath, merge.conflictedPaths);
|
|
402
477
|
const currentHead = await this.revParse(prepared, "HEAD");
|
|
403
|
-
|
|
478
|
+
// A merge with no agent edits still has the merge itself to push.
|
|
479
|
+
if (!merge && changed.length === 0 && currentHead === prepared.baseCommit) {
|
|
404
480
|
return {
|
|
405
481
|
outcome: "no_changes",
|
|
406
482
|
repository: prepared.repository,
|
|
@@ -412,7 +488,10 @@ export class GitVcsProvider {
|
|
|
412
488
|
if (symbolicHead !== prepared.headRef)
|
|
413
489
|
throw new Error("vcs_head_ref_mismatch");
|
|
414
490
|
let commitSha;
|
|
415
|
-
if (currentHead === prepared.baseCommit) {
|
|
491
|
+
if (currentHead === prepared.baseCommit && merge) {
|
|
492
|
+
commitSha = await this.commitMerge(prepared, merge);
|
|
493
|
+
}
|
|
494
|
+
else if (currentHead === prepared.baseCommit) {
|
|
416
495
|
await this.gitFor(prepared, ["commit", "--no-verify", "--no-gpg-sign", "-m", `Wardby run ${prepared.runId}`]);
|
|
417
496
|
commitSha = await this.revParse(prepared, "HEAD");
|
|
418
497
|
}
|
|
@@ -420,14 +499,21 @@ export class GitVcsProvider {
|
|
|
420
499
|
const parent = await this.revParse(prepared, "HEAD^");
|
|
421
500
|
if (parent !== prepared.baseCommit)
|
|
422
501
|
throw new Error("vcs_commit_history_invalid");
|
|
502
|
+
if (merge && (await this.revParse(prepared, "HEAD^2")) !== merge.targetCommit) {
|
|
503
|
+
throw new Error("vcs_commit_history_invalid");
|
|
504
|
+
}
|
|
423
505
|
const afterCommitChanges = nullSeparated((await this.gitFor(prepared, ["diff", "--cached", "--name-only", "-z", "HEAD", "--"])).stdout);
|
|
424
506
|
if (afterCommitChanges.length > 0)
|
|
425
507
|
throw new Error("vcs_finalized_workspace_changed");
|
|
426
508
|
commitSha = currentHead;
|
|
427
509
|
}
|
|
428
510
|
await this.remote.assertContinuationOpen(prepared);
|
|
511
|
+
// Before the push: a description comment must already exist when the push starts a review.
|
|
512
|
+
await this.remote
|
|
513
|
+
.proposeDescriptionBeforePush?.({ workspace: prepared, details, changedPaths: changed, commitSha })
|
|
514
|
+
.catch(() => undefined);
|
|
429
515
|
await this.pushOnce(prepared, commitSha);
|
|
430
|
-
const published = await this.remote.publish({ workspace: prepared, details, changedPaths: changed });
|
|
516
|
+
const published = await this.remote.publish({ workspace: prepared, details, changedPaths: changed, commitSha });
|
|
431
517
|
if (published.kind === "branch") {
|
|
432
518
|
if (published.branch !== prepared.headRef)
|
|
433
519
|
throw new Error("vcs_head_ref_mismatch");
|
|
@@ -449,8 +535,47 @@ export class GitVcsProvider {
|
|
|
449
535
|
commitSha,
|
|
450
536
|
pullRequestNumber: published.number,
|
|
451
537
|
pullRequestUrl: published.url,
|
|
538
|
+
...(published.description ? { description: published.description } : {}),
|
|
539
|
+
...(merge && prepared.continuation
|
|
540
|
+
? {
|
|
541
|
+
targetMerge: {
|
|
542
|
+
ref: merge.ref,
|
|
543
|
+
targetCommit: merge.targetCommit,
|
|
544
|
+
conflicts: merge.conflictedPaths.length,
|
|
545
|
+
},
|
|
546
|
+
}
|
|
547
|
+
: {}),
|
|
452
548
|
};
|
|
453
549
|
}
|
|
550
|
+
/** The two-parent merge commit (baseCommit, the target) of the staged tree, as the Wardby identity. */
|
|
551
|
+
async commitMerge(prepared, merge) {
|
|
552
|
+
const tree = (await this.gitFor(prepared, ["write-tree"])).stdout.trim();
|
|
553
|
+
if (!SAFE_COMMIT_SHA.test(tree))
|
|
554
|
+
throw new Error("vcs_commit_sha_invalid");
|
|
555
|
+
const commitSha = (await this.gitFor(prepared, [
|
|
556
|
+
"commit-tree",
|
|
557
|
+
tree,
|
|
558
|
+
"-p",
|
|
559
|
+
prepared.baseCommit,
|
|
560
|
+
"-p",
|
|
561
|
+
merge.targetCommit,
|
|
562
|
+
"-m",
|
|
563
|
+
`Merge ${merge.ref} into ${prepared.headRef} (Wardby run ${prepared.runId})`,
|
|
564
|
+
])).stdout.trim();
|
|
565
|
+
if (!SAFE_COMMIT_SHA.test(commitSha))
|
|
566
|
+
throw new Error("vcs_commit_sha_invalid");
|
|
567
|
+
await this.gitFor(prepared, ["update-ref", `refs/heads/${prepared.headRef}`, commitSha, prepared.baseCommit]);
|
|
568
|
+
return commitSha;
|
|
569
|
+
}
|
|
570
|
+
/** Re-derive a continuation's PR description without a push, delegated to the remote; never throws. */
|
|
571
|
+
async refreshPullRequestDescription(workspace, details) {
|
|
572
|
+
try {
|
|
573
|
+
return await this.remote.refreshDescription?.(workspace, details);
|
|
574
|
+
}
|
|
575
|
+
catch {
|
|
576
|
+
return { kind: "skipped", reason: "error" };
|
|
577
|
+
}
|
|
578
|
+
}
|
|
454
579
|
async cleanup(workspace) {
|
|
455
580
|
const expected = this.expectedPaths(workspace.runId);
|
|
456
581
|
if (workspace.id !== `vcs-${workspace.runId}` ||
|
|
@@ -465,6 +590,15 @@ export class GitVcsProvider {
|
|
|
465
590
|
* delegated to the remote; a remote without one is a no-op. Wrapped so
|
|
466
591
|
* this can NEVER throw or otherwise affect the real coding run.
|
|
467
592
|
*/
|
|
593
|
+
/** Delegated to the remote; never throws (undefined on any failure). */
|
|
594
|
+
async continuationPullRequestDraft(workspace) {
|
|
595
|
+
try {
|
|
596
|
+
return await this.remote.continuationPullRequestDraft?.(workspace);
|
|
597
|
+
}
|
|
598
|
+
catch {
|
|
599
|
+
return undefined;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
468
602
|
async notifyContinuationStarted(workspace, details) {
|
|
469
603
|
try {
|
|
470
604
|
await this.remote.notifyContinuationStarted?.(workspace, details);
|
|
@@ -561,6 +695,179 @@ export class GitVcsProvider {
|
|
|
561
695
|
}
|
|
562
696
|
return { ...workspace, ...normalized };
|
|
563
697
|
}
|
|
698
|
+
/**
|
|
699
|
+
* Fetches a continuation's target branch from the same `origin` the clone
|
|
700
|
+
* came from (never another URL, so never a fork) and deepens the depth-1
|
|
701
|
+
* clone step by step until the head and the target share a merge base.
|
|
702
|
+
* Returns true once they do; throws vcs_target_merge_failed when the fetch
|
|
703
|
+
* fails or no merge base turns up within MERGE_BASE_DEEPEN_STEPS.
|
|
704
|
+
*/
|
|
705
|
+
async fetchMergeTarget(gitMetadataPath, workspacePath, cloneBranch, ref, auth) {
|
|
706
|
+
const fetch = (depth, refspec) => this.gitForPaths(gitMetadataPath, workspacePath, [...this.remote.gitConfig, "fetch", "--no-tags", "--no-write-fetch-head", ...depth, "origin", refspec], auth);
|
|
707
|
+
const target = `+refs/heads/${ref}:${MERGE_TARGET_REF}`;
|
|
708
|
+
// The head is deepened through its own ref under refs/wardby, so the clone's
|
|
709
|
+
// refs/remotes/origin/<head> (baseCommit) never moves.
|
|
710
|
+
const head = `+refs/heads/${cloneBranch}:${MERGE_HEAD_REF}`;
|
|
711
|
+
try {
|
|
712
|
+
await fetch(["--depth", "1"], target);
|
|
713
|
+
for (const step of [0, ...MERGE_BASE_DEEPEN_STEPS]) {
|
|
714
|
+
if (step > 0) {
|
|
715
|
+
// One fetch per side: newer git deepens only the refs a fetch names
|
|
716
|
+
// (older git deepened every shallow boundary), and a fetch naming
|
|
717
|
+
// both deepens only one of them.
|
|
718
|
+
await fetch([`--deepen=${step}`], head);
|
|
719
|
+
await fetch([`--deepen=${step}`], target);
|
|
720
|
+
}
|
|
721
|
+
const base = await this.gitForPaths(gitMetadataPath, workspacePath, ["merge-base", `refs/remotes/origin/${cloneBranch}`, MERGE_TARGET_REF], { acceptExitCodes: [1] });
|
|
722
|
+
if (base.stdout.trim())
|
|
723
|
+
return true;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
catch (error) {
|
|
727
|
+
throw new Error("vcs_target_merge_failed", { cause: error });
|
|
728
|
+
}
|
|
729
|
+
throw new Error("vcs_target_merge_failed");
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Merges the fetched target into baseCommit without touching the index or
|
|
733
|
+
* the working tree (`merge-tree --write-tree`: no MERGE_HEAD, no hooks, no
|
|
734
|
+
* merge drivers -- none are configured), and records the result as the merge
|
|
735
|
+
* state. Null when the target is already part of the branch (nothing to merge).
|
|
736
|
+
*/
|
|
737
|
+
async mergeTargetBranch(gitMetadataPath, workspacePath, baseCommit, ref) {
|
|
738
|
+
const targetCommit = await this.revParseRaw(gitMetadataPath, workspacePath, `${MERGE_TARGET_REF}^{commit}`);
|
|
739
|
+
const mergeBase = (await this.gitForPaths(gitMetadataPath, workspacePath, ["merge-base", baseCommit, targetCommit])).stdout.trim();
|
|
740
|
+
if (mergeBase === targetCommit)
|
|
741
|
+
return null;
|
|
742
|
+
// The clone is --no-checkout and nothing is read into the index or the
|
|
743
|
+
// working tree until after this merge, so no repository .gitattributes
|
|
744
|
+
// (a marker size, `-merge`, `merge=union`) can steer it.
|
|
745
|
+
let output;
|
|
746
|
+
try {
|
|
747
|
+
output = (await this.gitForPaths(gitMetadataPath, workspacePath, ["merge-tree", "--write-tree", "-z", "--name-only", "--no-messages", baseCommit, targetCommit], { acceptExitCodes: [1] })).stdout;
|
|
748
|
+
}
|
|
749
|
+
catch (error) {
|
|
750
|
+
throw new Error("vcs_target_merge_failed", { cause: error });
|
|
751
|
+
}
|
|
752
|
+
const [tree, ...paths] = output.split("\0");
|
|
753
|
+
if (!SAFE_COMMIT_SHA.test(tree))
|
|
754
|
+
throw new Error("vcs_target_merge_failed");
|
|
755
|
+
const conflictedPaths = [...new Set(paths.filter(Boolean))].map(validateChangedPath);
|
|
756
|
+
if (conflictedPaths.length > this.maxChangedFiles)
|
|
757
|
+
throw new Error("vcs_target_merge_failed");
|
|
758
|
+
const targetMerge = { ref, targetCommit, conflictedPaths };
|
|
759
|
+
// The message goes through a file: a long conflicted-path list could pass an argument's size limit.
|
|
760
|
+
const messagePath = resolve(gitMetadataPath, "WARDBY_MERGE_STATE_MSG");
|
|
761
|
+
await writeFile(messagePath, mergeStateMessage(targetMerge), { mode: 0o600 });
|
|
762
|
+
try {
|
|
763
|
+
const stateCommit = (await this.gitForPaths(gitMetadataPath, workspacePath, [
|
|
764
|
+
"commit-tree",
|
|
765
|
+
tree,
|
|
766
|
+
"-p",
|
|
767
|
+
baseCommit,
|
|
768
|
+
"-p",
|
|
769
|
+
targetCommit,
|
|
770
|
+
"-F",
|
|
771
|
+
messagePath,
|
|
772
|
+
])).stdout.trim();
|
|
773
|
+
if (!SAFE_COMMIT_SHA.test(stateCommit))
|
|
774
|
+
throw new Error("vcs_commit_sha_invalid");
|
|
775
|
+
await this.gitForPaths(gitMetadataPath, workspacePath, ["update-ref", MERGE_STATE_REF, stateCommit]);
|
|
776
|
+
}
|
|
777
|
+
finally {
|
|
778
|
+
await rm(messagePath, { force: true });
|
|
779
|
+
}
|
|
780
|
+
return { tree, targetMerge };
|
|
781
|
+
}
|
|
782
|
+
/** The recorded merge state (see MERGE_STATE_REF), validated, or undefined when the workspace merged nothing. */
|
|
783
|
+
async readMergeState(workspace) {
|
|
784
|
+
const { gitMetadataPath, workspacePath } = workspace;
|
|
785
|
+
const stateCommit = (await this.gitForPaths(gitMetadataPath, workspacePath, [
|
|
786
|
+
"for-each-ref",
|
|
787
|
+
"--format=%(objectname)",
|
|
788
|
+
MERGE_STATE_REF,
|
|
789
|
+
])).stdout.trim();
|
|
790
|
+
if (!stateCommit)
|
|
791
|
+
return undefined;
|
|
792
|
+
if (!SAFE_COMMIT_SHA.test(stateCommit))
|
|
793
|
+
throw new Error("vcs_merge_state_invalid");
|
|
794
|
+
const raw = (await this.gitForPaths(gitMetadataPath, workspacePath, ["cat-file", "commit", stateCommit])).stdout;
|
|
795
|
+
const split = raw.indexOf("\n\n");
|
|
796
|
+
if (split < 0)
|
|
797
|
+
throw new Error("vcs_merge_state_invalid");
|
|
798
|
+
const parents = raw
|
|
799
|
+
.slice(0, split)
|
|
800
|
+
.split("\n")
|
|
801
|
+
.filter((line) => line.startsWith("parent "))
|
|
802
|
+
.map((line) => line.slice("parent ".length));
|
|
803
|
+
const message = raw.slice(split + 2);
|
|
804
|
+
if (parents.length !== 2 ||
|
|
805
|
+
parents[0] !== workspace.baseCommit ||
|
|
806
|
+
!SAFE_COMMIT_SHA.test(parents[1]) ||
|
|
807
|
+
!message.startsWith(`${MERGE_STATE_SUBJECT}\n\n`)) {
|
|
808
|
+
throw new Error("vcs_merge_state_invalid");
|
|
809
|
+
}
|
|
810
|
+
let parsed;
|
|
811
|
+
try {
|
|
812
|
+
parsed = JSON.parse(message.slice(MERGE_STATE_SUBJECT.length + 2));
|
|
813
|
+
}
|
|
814
|
+
catch (error) {
|
|
815
|
+
throw new Error("vcs_merge_state_invalid", { cause: error });
|
|
816
|
+
}
|
|
817
|
+
const state = parsed;
|
|
818
|
+
if (typeof state.ref !== "string" ||
|
|
819
|
+
!Array.isArray(state.conflicted) ||
|
|
820
|
+
state.conflicted.length > this.maxChangedFiles ||
|
|
821
|
+
state.conflicted.some((path) => typeof path !== "string")) {
|
|
822
|
+
throw new Error("vcs_merge_state_invalid");
|
|
823
|
+
}
|
|
824
|
+
const ref = safeGitRef(state.ref);
|
|
825
|
+
if (!ref)
|
|
826
|
+
throw new Error("vcs_merge_state_invalid");
|
|
827
|
+
return {
|
|
828
|
+
ref,
|
|
829
|
+
targetCommit: parents[1],
|
|
830
|
+
conflictedPaths: state.conflicted.map(validateChangedPath),
|
|
831
|
+
stateCommit,
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Refuses to finalize while a file the merge left conflicted still holds a
|
|
836
|
+
* conflict marker pair. Only those files are read: elsewhere a line of
|
|
837
|
+
* `<<<<<<<` may be legitimate content (a fixture, a doc about merging).
|
|
838
|
+
*/
|
|
839
|
+
async assertConflictsResolved(workspacePath, conflictedPaths) {
|
|
840
|
+
for (const path of conflictedPaths) {
|
|
841
|
+
const fullPath = resolve(workspacePath, path);
|
|
842
|
+
if (!fullPath.startsWith(`${workspacePath}${sep}`))
|
|
843
|
+
throw new Error("vcs_changed_path_invalid");
|
|
844
|
+
// One no-follow open, then stat and read through that handle: nothing can swap the file in between.
|
|
845
|
+
let handle;
|
|
846
|
+
try {
|
|
847
|
+
handle = await open(fullPath, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
|
|
848
|
+
}
|
|
849
|
+
catch (error) {
|
|
850
|
+
const code = error.code;
|
|
851
|
+
// Deleted while resolving, or a symlink (ELOOP): nothing left to hold a marker.
|
|
852
|
+
if (code === "ENOENT" || code === "ENOTDIR" || code === "ELOOP")
|
|
853
|
+
continue;
|
|
854
|
+
throw error;
|
|
855
|
+
}
|
|
856
|
+
let content;
|
|
857
|
+
try {
|
|
858
|
+
// Not a regular file (a directory now stands there): nothing to scan.
|
|
859
|
+
if (!(await handle.stat()).isFile())
|
|
860
|
+
continue;
|
|
861
|
+
content = await handle.readFile("utf8");
|
|
862
|
+
}
|
|
863
|
+
finally {
|
|
864
|
+
await handle.close();
|
|
865
|
+
}
|
|
866
|
+
if (CONFLICT_MARKER_START.test(content) && CONFLICT_MARKER_END.test(content)) {
|
|
867
|
+
throw new Error(`vcs_conflict_markers_remain:${path}`);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
564
871
|
async inspectWorkspace(workspacePath) {
|
|
565
872
|
const rootStat = await lstat(workspacePath);
|
|
566
873
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink())
|
|
@@ -635,10 +942,16 @@ export class GitVcsProvider {
|
|
|
635
942
|
throw new Error("vcs_git_config_unsafe");
|
|
636
943
|
}
|
|
637
944
|
}
|
|
945
|
+
/** The git credentials for a remote's access token; none when the remote needs no token. */
|
|
946
|
+
gitAuth(token) {
|
|
947
|
+
if (token === undefined)
|
|
948
|
+
return {};
|
|
949
|
+
return { authToken: token, ...(this.remote.gitUsername ? { authUsername: this.remote.gitUsername } : {}) };
|
|
950
|
+
}
|
|
638
951
|
async pushOnce(workspace, commitSha) {
|
|
639
952
|
this.remote.assertPushRef?.(workspace.headRef);
|
|
640
953
|
await this.remote.withAccess(workspace.repository, async (token) => {
|
|
641
|
-
const auth = token
|
|
954
|
+
const auth = this.gitAuth(token);
|
|
642
955
|
const remote = await this.remoteHead(workspace, auth);
|
|
643
956
|
if (remote === commitSha)
|
|
644
957
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type GitHubRepositoryAccess, type RepositoryFileInput } from "./github.js";
|
|
2
2
|
import type { GitRemote, PublishInput, PublishResult } from "./remote.js";
|
|
3
|
-
import type { ContinuationFinishedDetails, ContinuationOutcome, PreparedWorkspace } from "./types.js";
|
|
3
|
+
import type { ContinuationFinishedDetails, ContinuationOutcome, ContinuationTarget, DescriptionWriteOutcome, FinalizeChangesDetails, PreparedWorkspace } from "./types.js";
|
|
4
4
|
export interface GitHubRemoteOptions {
|
|
5
5
|
github: GitHubRepositoryAccess;
|
|
6
6
|
/** Test-only transport override; production composition always uses github.com. */
|
|
@@ -42,7 +42,30 @@ export declare class GitHubRemote implements GitRemote {
|
|
|
42
42
|
rootRunId: string;
|
|
43
43
|
};
|
|
44
44
|
}): Promise<void>;
|
|
45
|
-
|
|
45
|
+
/** See GitRemote.pullRequestBase: the root run's open PR's current base branch. Never throws. */
|
|
46
|
+
pullRequestBase(input: {
|
|
47
|
+
runId: string;
|
|
48
|
+
repository: string;
|
|
49
|
+
baseRef: string;
|
|
50
|
+
headRef: string;
|
|
51
|
+
continuation?: {
|
|
52
|
+
rootRunId: string;
|
|
53
|
+
};
|
|
54
|
+
}): Promise<{
|
|
55
|
+
ref: string;
|
|
56
|
+
} | null>;
|
|
57
|
+
/** See VcsProvider.continuationPullRequestDraft: GitHub's draft flag on the root run's open PR. Never throws. */
|
|
58
|
+
continuationPullRequestDraft(workspace: PreparedWorkspace): Promise<boolean | undefined>;
|
|
59
|
+
/** A continuation's description comment, written before the push (see GitRemote.proposeDescriptionBeforePush). Never throws. */
|
|
60
|
+
proposeDescriptionBeforePush({ workspace: prepared, details, changedPaths, commitSha, }: PublishInput & {
|
|
61
|
+
commitSha: string;
|
|
62
|
+
}): Promise<void>;
|
|
63
|
+
publish({ workspace: prepared, details, changedPaths, commitSha }: PublishInput): Promise<PublishResult>;
|
|
64
|
+
/** The no-push path: a fix round that changed nothing still re-derives its PR description. */
|
|
65
|
+
refreshDescription(workspace: ContinuationTarget, details: FinalizeChangesDetails): Promise<DescriptionWriteOutcome | undefined>;
|
|
66
|
+
/** Never throws: a description problem must not fail an already-pushed run. */
|
|
67
|
+
private updateDescription;
|
|
68
|
+
private descriptionInput;
|
|
46
69
|
/**
|
|
47
70
|
* Best-effort "wardby is working on this PR" signal (see VcsProvider) --
|
|
48
71
|
* whole body wrapped so this can NEVER throw or otherwise affect the
|
|
@@ -62,6 +85,6 @@ export declare class GitHubRemote implements GitRemote {
|
|
|
62
85
|
* github.ts). Safe to call more than once for the same run. Same
|
|
63
86
|
* never-throw contract as notifyContinuationStarted.
|
|
64
87
|
*/
|
|
65
|
-
notifyContinuationFinished(workspace:
|
|
88
|
+
notifyContinuationFinished(workspace: ContinuationTarget, outcome: ContinuationOutcome, details?: ContinuationFinishedDetails): Promise<void>;
|
|
66
89
|
readRepositoryFile(input: RepositoryFileInput): Promise<string | null>;
|
|
67
90
|
}
|