@wardby/cli 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deploy/local/docker-compose.quickstart-coding.yml +13 -0
- package/dist/claude-coding-worker/driver.d.ts +21 -3
- package/dist/claude-coding-worker/driver.js +125 -17
- package/dist/claude-coding-worker/main.js +34 -6
- package/dist/claude-coding-worker/sdk.js +12 -1
- package/dist/claude-coding-worker/tool-socket.d.ts +27 -0
- package/dist/claude-coding-worker/tool-socket.js +111 -0
- package/dist/claude-coding-worker/transcript.d.ts +18 -0
- package/dist/claude-coding-worker/transcript.js +77 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +1 -0
- package/dist/cli.js +24 -10
- package/dist/coding/continuation-wording.d.ts +35 -0
- package/dist/coding/continuation-wording.js +73 -0
- package/dist/coding/linked-issue-note.d.ts +23 -0
- package/dist/coding/linked-issue-note.js +47 -0
- package/dist/coding/merge-wording.d.ts +28 -0
- package/dist/coding/merge-wording.js +78 -0
- package/dist/coding/pr-description-note.d.ts +9 -0
- package/dist/coding/pr-description-note.js +32 -0
- package/dist/coding/profile.d.ts +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 +235 -12
- package/dist/coding/redact.d.ts +3 -0
- package/dist/coding/redact.js +12 -0
- package/dist/coding/registry/allowlist.d.ts +12 -0
- package/dist/coding/registry/allowlist.js +14 -1
- package/dist/coding/registry/audit-mode.d.ts +153 -0
- package/dist/coding/registry/audit-mode.js +304 -0
- package/dist/coding/registry/lockfile-shared.d.ts +36 -0
- package/dist/coding/registry/lockfile-shared.js +128 -0
- package/dist/coding/registry/lockfiles.js +1 -1
- package/dist/coding/registry/npm-lockfile-formats.d.ts +11 -0
- package/dist/coding/registry/npm-lockfile-formats.js +41 -0
- package/dist/coding/registry/npm-lockfile.d.ts +8 -4
- package/dist/coding/registry/npm-lockfile.js +4 -6
- package/dist/coding/registry/npm.js +78 -8
- package/dist/coding/registry/pnpm-lockfile.d.ts +17 -0
- package/dist/coding/registry/pnpm-lockfile.js +189 -0
- package/dist/coding/registry/pypi-plan.d.ts +50 -0
- package/dist/coding/registry/pypi-plan.js +406 -0
- package/dist/coding/registry/pypi-requirements.d.ts +58 -0
- package/dist/coding/registry/pypi-requirements.js +155 -0
- package/dist/coding/registry/pypi.d.ts +3 -27
- package/dist/coding/registry/pypi.js +40 -154
- package/dist/coding/registry/refusal-hints.d.ts +20 -0
- package/dist/coding/registry/refusal-hints.js +61 -0
- package/dist/coding/registry/refusal-wording.d.ts +11 -0
- package/dist/coding/registry/refusal-wording.js +56 -0
- package/dist/coding/registry/report.d.ts +70 -8
- package/dist/coding/registry/report.js +112 -5
- package/dist/coding/registry/types.d.ts +58 -8
- package/dist/coding/registry/yarn-lockfile.d.ts +30 -0
- package/dist/coding/registry/yarn-lockfile.js +367 -0
- package/dist/coding/services/catalog.d.ts +37 -351
- package/dist/coding/transcript/claude-code.d.ts +13 -0
- package/dist/coding/transcript/claude-code.js +273 -0
- package/dist/coding/transcript/download-protocol.d.ts +30 -0
- package/dist/coding/transcript/download-protocol.js +18 -0
- package/dist/coding/transcript/format.d.ts +20 -0
- package/dist/coding/transcript/format.js +32 -0
- package/dist/coding/transcript/recorder.d.ts +51 -0
- package/dist/coding/transcript/recorder.js +225 -0
- package/dist/coding/transcript/resume/checkout.d.ts +31 -0
- package/dist/coding/transcript/resume/checkout.js +203 -0
- package/dist/coding/transcript/resume/command.d.ts +17 -0
- package/dist/coding/transcript/resume/command.js +176 -0
- package/dist/coding/transcript/resume/download.d.ts +20 -0
- package/dist/coding/transcript/resume/download.js +153 -0
- package/dist/coding/transcript/resume/launch.d.ts +38 -0
- package/dist/coding/transcript/resume/launch.js +128 -0
- package/dist/coding/transcript/resume/session-file.d.ts +13 -0
- package/dist/coding/transcript/resume/session-file.js +79 -0
- package/dist/coding/transcript/resume/stand-in.d.ts +11 -0
- package/dist/coding/transcript/resume/stand-in.js +49 -0
- package/dist/coding-worker/artifact.d.ts +8 -3
- package/dist/coding-worker/artifact.js +3 -1
- package/dist/coding-worker/debug-trace.d.ts +6 -5
- package/dist/coding-worker/debug-trace.js +13 -18
- package/dist/coding-worker/dependency-cache.d.mts +229 -0
- package/dist/coding-worker/dependency-cache.mjs +2123 -0
- package/dist/coding-worker/driver.d.ts +4 -3
- package/dist/coding-worker/driver.js +116 -38
- package/dist/coding-worker/errors.d.ts +1 -0
- package/dist/coding-worker/errors.js +32 -0
- package/dist/coding-worker/task-note.d.ts +11 -0
- package/dist/coding-worker/task-note.js +13 -0
- package/dist/coding-worker/types.d.ts +11 -0
- package/dist/config/dependency-cache.d.ts +23 -0
- package/dist/config/dependency-cache.js +32 -0
- package/dist/config/providers.d.ts +12 -3
- package/dist/config/providers.js +55 -5
- package/dist/config/test-simulators.d.ts +82 -0
- package/dist/config/test-simulators.js +305 -0
- package/dist/core/async-context.d.ts +2 -0
- package/dist/core/async-context.js +12 -0
- package/dist/core/budget-events.d.ts +108 -0
- package/dist/core/budget-events.js +346 -0
- package/dist/core/budget-groups.d.ts +50 -1
- package/dist/core/budget-groups.js +236 -27
- package/dist/core/budget-stopped-head.d.ts +46 -0
- package/dist/core/budget-stopped-head.js +81 -0
- package/dist/core/budget-topup.d.ts +51 -0
- package/dist/core/budget-topup.js +156 -0
- package/dist/core/budget-wording.d.ts +16 -2
- package/dist/core/budget-wording.js +40 -2
- package/dist/core/coding-queue.d.ts +2 -1
- package/dist/core/coding-queue.js +7 -0
- package/dist/core/cron.d.ts +19 -1
- package/dist/core/cron.js +17 -0
- package/dist/core/datastores.js +1 -1
- package/dist/core/deferred-coding.d.ts +14 -0
- package/dist/core/deferred-coding.js +62 -0
- package/dist/core/delegation-child.d.ts +25 -0
- package/dist/core/delegation-child.js +37 -0
- package/dist/core/dispatch.d.ts +42 -0
- package/dist/core/dispatch.js +131 -56
- package/dist/core/engine-native.js +1 -1
- package/dist/core/error-code.d.ts +38 -0
- package/dist/core/error-code.js +168 -0
- package/dist/core/grants.d.ts +19 -6
- package/dist/core/grants.js +55 -6
- package/dist/core/host-events.d.ts +18 -2
- package/dist/core/host-events.js +284 -24
- package/dist/core/host-status.d.ts +85 -3
- package/dist/core/host-status.js +298 -20
- package/dist/core/issue-bridge.d.ts +50 -6
- package/dist/core/issue-bridge.js +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 +54 -26
- package/dist/core/logger.d.ts +5 -0
- package/dist/core/logger.js +14 -1
- package/dist/core/lost-run-children.d.ts +6 -0
- package/dist/core/lost-run-children.js +32 -0
- package/dist/core/mark-ready.d.ts +34 -0
- package/dist/core/mark-ready.js +152 -0
- package/dist/core/markdown-code.d.ts +8 -0
- package/dist/core/markdown-code.js +107 -0
- package/dist/core/memory-tools.js +7 -0
- package/dist/core/merge-order-check.d.ts +2 -1
- package/dist/core/merge-order-check.js +8 -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 +27 -14
- 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 +2 -1
- 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 +99 -13
- 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 +80 -34
- package/dist/core/runner.js +439 -144
- 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 +10 -74
- package/dist/core/secret-guard.d.ts +46 -0
- package/dist/core/secret-guard.js +104 -0
- package/dist/core/secret-guarded-stores.d.ts +12 -0
- package/dist/core/secret-guarded-stores.js +41 -0
- package/dist/core/secret-spans.d.ts +50 -0
- package/dist/core/secret-spans.js +94 -0
- package/dist/core/stop-run.d.ts +46 -0
- package/dist/core/stop-run.js +61 -0
- 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 +43 -8
- 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 +34 -3
- package/dist/generated/prisma/client.d.ts +34 -3
- package/dist/generated/prisma/commonInputTypes.d.ts +220 -60
- 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 +44 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +428 -9
- package/dist/generated/prisma/internal/prismaNamespace.js +92 -1
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +95 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +92 -1
- package/dist/generated/prisma/models/Agent.d.ts +106 -8
- package/dist/generated/prisma/models/AgentRepository.d.ts +42 -1
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +229 -1
- package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
- package/dist/generated/prisma/models/CodingProxySession.d.ts +114 -1
- package/dist/generated/prisma/models/CodingRun.d.ts +1637 -1
- package/dist/generated/prisma/models/DependencySnapshot.d.ts +1668 -0
- package/dist/generated/prisma/models/DependencySnapshot.js +1 -0
- package/dist/generated/prisma/models/IssuePullRequest.d.ts +6 -2
- package/dist/generated/prisma/models/LocalReview.d.ts +40 -1
- package/dist/generated/prisma/models/NativeGatewayCall.d.ts +39 -1
- package/dist/generated/prisma/models/NativeGatewaySession.d.ts +35 -1
- package/dist/generated/prisma/models/RegistryAllowance.d.ts +41 -1
- package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +75 -1
- package/dist/generated/prisma/models/RegistryAuditRecord.d.ts +1364 -0
- package/dist/generated/prisma/models/RegistryAuditRecord.js +1 -0
- package/dist/generated/prisma/models/Run.d.ts +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.d.ts +4 -0
- package/dist/help-index.json +1320 -69
- package/dist/import/create.js +32 -3
- package/dist/import/neutral-schema.d.ts +50 -281
- package/dist/import/neutral-schema.js +5 -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/ownership.d.ts +7 -7
- 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/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 +58 -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 +198 -16
- package/dist/mcp/tools/datastore.js +17 -8
- package/dist/mcp/tools/grants.js +9 -3
- package/dist/mcp/tools/memory.js +11 -1
- package/dist/mcp/tools/notification-channels.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 +18 -5
- package/dist/mcp/tools/run-access.d.ts +16 -0
- package/dist/mcp/tools/run-access.js +25 -0
- package/dist/mcp/tools/run-transcript-download.d.ts +30 -0
- package/dist/mcp/tools/run-transcript-download.js +129 -0
- package/dist/mcp/tools/run-transcript.d.ts +19 -0
- package/dist/mcp/tools/run-transcript.js +70 -0
- package/dist/mcp/tools/runs.js +34 -12
- 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/secrets.js +2 -2
- 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 +1 -1
- package/dist/mcp/tools/tools.js +25 -9
- package/dist/mcp/transport/stdio-link-host.d.ts +20 -0
- package/dist/mcp/transport/stdio-link-host.js +67 -0
- package/dist/mcp/transport/streamable-http.d.ts +13 -0
- package/dist/mcp/transport/streamable-http.js +41 -1
- package/dist/native-worker/docker-launcher.d.ts +38 -2
- package/dist/native-worker/docker-launcher.js +65 -5
- package/dist/native-worker/gateway-server.d.ts +41 -3
- package/dist/native-worker/gateway-server.js +124 -27
- package/dist/native-worker/gateway.d.ts +27 -1
- package/dist/native-worker/gateway.js +70 -4
- package/dist/native-worker/http-server.d.ts +3 -1
- package/dist/native-worker/http-server.js +11 -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 +18 -2
- package/dist/native-worker/ledger.js +57 -4
- 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 +129 -577
- package/dist/native-worker/protocol.js +47 -1
- 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/dependency-cache/eviction.d.ts +29 -0
- package/dist/providers/coding-proxy/dependency-cache/eviction.js +87 -0
- package/dist/providers/coding-proxy/dependency-cache/key.d.ts +33 -0
- package/dist/providers/coding-proxy/dependency-cache/key.js +86 -0
- package/dist/providers/coding-proxy/dependency-cache/model-request-seal.d.ts +18 -0
- package/dist/providers/coding-proxy/dependency-cache/model-request-seal.js +40 -0
- package/dist/providers/coding-proxy/dependency-cache/prisma-store.d.ts +25 -0
- package/dist/providers/coding-proxy/dependency-cache/prisma-store.js +131 -0
- package/dist/providers/coding-proxy/dependency-cache/service.d.ts +70 -0
- package/dist/providers/coding-proxy/dependency-cache/service.js +409 -0
- package/dist/providers/coding-proxy/dependency-cache/store.d.ts +85 -0
- package/dist/providers/coding-proxy/dependency-cache/store.js +95 -0
- package/dist/providers/coding-proxy/hold.d.ts +32 -0
- package/dist/providers/coding-proxy/hold.js +86 -0
- package/dist/providers/coding-proxy/interrupted.d.ts +70 -0
- package/dist/providers/coding-proxy/interrupted.js +104 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +15 -2
- package/dist/providers/coding-proxy/memory-ledger.js +84 -8
- package/dist/providers/coding-proxy/metering.d.ts +16 -0
- package/dist/providers/coding-proxy/metering.js +27 -4
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -2
- package/dist/providers/coding-proxy/prisma-ledger.js +179 -67
- package/dist/providers/coding-proxy/proxy.d.ts +14 -1
- package/dist/providers/coding-proxy/proxy.js +166 -14
- package/dist/providers/coding-proxy/registry/audit.d.ts +53 -10
- package/dist/providers/coding-proxy/registry/audit.js +94 -17
- package/dist/providers/coding-proxy/registry/lockfile-parse-worker.d.ts +36 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse-worker.js +67 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse.d.ts +16 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse.js +110 -0
- package/dist/providers/coding-proxy/registry/plan.d.ts +9 -0
- package/dist/providers/coding-proxy/registry/plan.js +201 -48
- package/dist/providers/coding-proxy/registry/prisma-store.d.ts +11 -5
- package/dist/providers/coding-proxy/registry/prisma-store.js +120 -17
- package/dist/providers/coding-proxy/registry/service.d.ts +97 -16
- package/dist/providers/coding-proxy/registry/service.js +579 -112
- package/dist/providers/coding-proxy/registry/store.d.ts +84 -9
- package/dist/providers/coding-proxy/registry/store.js +54 -1
- package/dist/providers/coding-proxy/runtime.d.ts +4 -0
- package/dist/providers/coding-proxy/runtime.js +78 -16
- package/dist/providers/coding-proxy/server.d.ts +6 -1
- package/dist/providers/coding-proxy/server.js +45 -1
- package/dist/providers/coding-proxy/types.d.ts +65 -1
- package/dist/providers/datastore/types.d.ts +5 -0
- package/dist/providers/engine/types.d.ts +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 +47 -7
- package/dist/providers/executor/container.d.ts +361 -8
- package/dist/providers/executor/container.js +1136 -91
- 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/index.d.ts +2 -1
- package/dist/providers/issue-tracker/types.d.ts +17 -0
- package/dist/providers/issue-tracker/types.js +39 -1
- package/dist/providers/jobs/claude-tool-setup.d.ts +4 -0
- package/dist/providers/jobs/claude-tool-setup.js +5 -2
- package/dist/providers/jobs/docker-isolation.d.ts +8 -0
- package/dist/providers/jobs/docker-isolation.js +17 -0
- package/dist/providers/jobs/docker.d.ts +1 -0
- package/dist/providers/jobs/docker.js +27 -2
- 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 +2 -0
- package/dist/providers/jobs/kubernetes-isolation.js +17 -1
- package/dist/providers/jobs/kubernetes.d.ts +6 -1
- package/dist/providers/jobs/kubernetes.js +105 -16
- package/dist/providers/jobs/types.d.ts +33 -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 +134 -2
- package/dist/providers/review-host/types.js +8 -0
- package/dist/providers/storage/gcs.d.ts +63 -0
- package/dist/providers/storage/gcs.js +69 -0
- package/dist/providers/storage/index.d.ts +15 -0
- package/dist/providers/storage/index.js +14 -0
- package/dist/providers/storage/local.d.ts +24 -0
- package/dist/providers/storage/local.js +92 -0
- package/dist/providers/storage/meter.d.ts +14 -0
- package/dist/providers/storage/meter.js +34 -0
- package/dist/providers/storage/s3.d.ts +41 -0
- package/dist/providers/storage/s3.js +107 -0
- package/dist/providers/storage/types.d.ts +37 -3
- package/dist/providers/storage/types.js +21 -4
- package/dist/providers/vcs/git.d.ts +33 -2
- package/dist/providers/vcs/git.js +324 -22
- package/dist/providers/vcs/github-remote.d.ts +26 -3
- package/dist/providers/vcs/github-remote.js +124 -14
- package/dist/providers/vcs/github.d.ts +214 -6
- package/dist/providers/vcs/github.js +447 -45
- package/dist/providers/vcs/index.js +8 -1
- package/dist/providers/vcs/pr-description.d.ts +127 -0
- package/dist/providers/vcs/pr-description.js +270 -0
- package/dist/providers/vcs/remote.d.ts +33 -1
- package/dist/providers/vcs/routing.d.ts +4 -2
- package/dist/providers/vcs/routing.js +6 -0
- package/dist/providers/vcs/types.d.ts +80 -3
- package/dist/quickstart/coding-seed.d.ts +14 -3
- package/dist/quickstart/coding-seed.js +213 -4
- 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/generated/zod.bundle.js +62 -1
- package/dist/sandbox/generated/zod3.bundle.js +5 -0
- package/dist/sandbox/host-functions.d.ts +1 -0
- package/dist/sandbox/host-functions.js +6 -11
- package/dist/sandbox/secret-broker.js +3 -4
- package/dist/sandbox/tool-capabilities.d.ts +10 -30
- 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/openapi.js +2 -4
- package/dist/wardby-bin.js +10 -0
- package/docs/agent-recipes.md +58 -20
- package/docs/code-review-agents.md +551 -41
- package/docs/coding-agent-setup.md +489 -7
- package/docs/coding-packages.md +1033 -90
- package/docs/coding-services.md +27 -12
- package/docs/coding-worker-byo-images.md +20 -0
- package/docs/coding-worker-isolation.md +105 -30
- package/docs/getting-started-gke.md +124 -137
- package/docs/getting-started-identity-provider.md +10 -1
- package/docs/getting-started.md +9 -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/native-sandbox.md +119 -23
- package/docs/observability.md +4 -0
- package/docs/security-deployment.md +33 -2
- package/docs/slack-notifications.md +35 -19
- package/docs/tool-secrets.md +42 -10
- package/docs/viewer-api.openapi.yml +1 -1
- package/help/admin-viewer.md +24 -2
- package/help/architecture-agent.md +11 -6
- package/help/build-worker-image.md +3 -1
- package/help/builder-agent.md +19 -6
- 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-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/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/merge-conflict.md +49 -0
- package/help/errors/native-sandbox-gateway-error.md +20 -0
- package/help/errors/native-sandbox-launch-abandoned.md +21 -0
- package/help/errors/native-sandbox-worker-exited.md +3 -2
- package/help/errors/package-not-allowed-pending.md +52 -0
- package/help/errors/package-not-allowed.md +51 -0
- package/help/errors/package-refusals.md +43 -0
- package/help/errors/patch-cursor-malformed.md +31 -0
- package/help/errors/run-lost.md +39 -0
- package/help/errors/run-transcript-download.md +44 -0
- package/help/errors/secret-in-value.md +69 -0
- package/help/errors/target-merge.md +40 -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/identity-and-access.md +2 -0
- 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/merge-order-check.md +5 -0
- package/help/native-capabilities.md +29 -1
- package/help/native-sandbox.md +15 -1
- package/help/operating-agents.md +5 -0
- package/help/package-audit-mode.md +91 -0
- package/help/related-pull-requests.md +10 -7
- package/help/resume-runs-locally.md +131 -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 +78 -7
- package/package.json +17 -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/schema.prisma +311 -97
- package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
|
@@ -1,11 +1,14 @@
|
|
|
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
13
|
import { isSafeGitHubInstallationToken } from "./github.js";
|
|
11
14
|
export const DEFAULT_MAX_CHANGED_FILES = 1_000;
|
|
@@ -14,6 +17,24 @@ 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}$/;
|
|
16
19
|
const SAFE_RUN_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
|
|
20
|
+
/** Where a continuation's target branch is fetched to (never under refs/remotes, so baseCommit's ref is untouched). */
|
|
21
|
+
const MERGE_TARGET_REF = "refs/wardby/merge-target";
|
|
22
|
+
/** Where the head branch is re-fetched while deepening history (see fetchMergeTarget). */
|
|
23
|
+
const MERGE_HEAD_REF = "refs/wardby/merge-head";
|
|
24
|
+
/**
|
|
25
|
+
* The trusted automatic merge of the target branch, recorded at prepare time:
|
|
26
|
+
* a commit whose tree is the merge result (markers in conflicted files), whose
|
|
27
|
+
* parents are baseCommit and the target commit, and whose message carries the
|
|
28
|
+
* target ref and the conflicted paths as JSON. Recovery and finalize read it
|
|
29
|
+
* back; the agent's changes are measured against its tree.
|
|
30
|
+
*/
|
|
31
|
+
const MERGE_STATE_REF = "refs/wardby/merge-state";
|
|
32
|
+
const MERGE_STATE_SUBJECT = "wardby merge state";
|
|
33
|
+
/** How far `fetch --deepen` goes, step by step, looking for a merge base in a depth-1 clone. */
|
|
34
|
+
const MERGE_BASE_DEEPEN_STEPS = [64, 256, 1024, 4096];
|
|
35
|
+
/** 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. */
|
|
36
|
+
const CONFLICT_MARKER_START = /^<{7,}(?: |\r?$)/m;
|
|
37
|
+
const CONFLICT_MARKER_END = /^>{7,}(?: |\r?$)/m;
|
|
17
38
|
const HARDENED_GIT_CONFIG = [
|
|
18
39
|
"-c",
|
|
19
40
|
"core.hooksPath=/dev/null",
|
|
@@ -41,11 +62,10 @@ export function redactGitOutput(value, secrets = []) {
|
|
|
41
62
|
// MAX_REDACTED_SPAN of margin rather than on all 2 MiB git may have produced
|
|
42
63
|
// (see redactAndTruncate: the margin is what keeps truncation safe). The rest
|
|
43
64
|
// is discarded here and never reaches a log or the database.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
65
|
+
// The shared span-union redactor; any non-empty value counts here, as it always has.
|
|
66
|
+
const output = redactExactSecretValues(value.slice(0, GIT_OUTPUT_DISPLAY_BYTES + MAX_REDACTED_SPAN), secrets, {
|
|
67
|
+
minLength: 1,
|
|
68
|
+
});
|
|
49
69
|
return redactTokenShapedValues(output).slice(0, GIT_OUTPUT_DISPLAY_BYTES);
|
|
50
70
|
}
|
|
51
71
|
/** Runs Git without a shell or inherited application secrets. */
|
|
@@ -79,6 +99,8 @@ export class NodeGitCommandRunner {
|
|
|
79
99
|
GIT_ASKPASS: options.authToken ? this.askPassPath : "/bin/false",
|
|
80
100
|
SSH_ASKPASS: "/bin/false",
|
|
81
101
|
GIT_LFS_SKIP_SMUDGE: "1",
|
|
102
|
+
// WARDBY_TEST_SIMULATORS (test only): the simulator's throwaway CA; empty otherwise.
|
|
103
|
+
...simulatorGitEnvironment(),
|
|
82
104
|
};
|
|
83
105
|
const maxBytes = options.maxOutputBytes ?? MAX_GIT_OUTPUT_BYTES;
|
|
84
106
|
const secrets = options.authToken ? [options.authToken] : [];
|
|
@@ -133,7 +155,7 @@ export class NodeGitCommandRunner {
|
|
|
133
155
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
134
156
|
stderr: redactGitOutput(Buffer.concat(stderr).toString("utf8"), secrets),
|
|
135
157
|
};
|
|
136
|
-
if (code !== 0) {
|
|
158
|
+
if (code !== 0 && (code === null || !options.acceptExitCodes?.includes(code))) {
|
|
137
159
|
rejectPromise(new GitCommandError(code, result.stderr.trim()));
|
|
138
160
|
return;
|
|
139
161
|
}
|
|
@@ -192,6 +214,26 @@ function nullSeparated(value) {
|
|
|
192
214
|
values.pop();
|
|
193
215
|
return values.map(validateChangedPath);
|
|
194
216
|
}
|
|
217
|
+
function safeGitRef(value) {
|
|
218
|
+
try {
|
|
219
|
+
return normalizeGitRef(value);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/** The merge state's message: a fixed subject, then the target ref and conflicted paths as JSON. */
|
|
226
|
+
function mergeStateMessage(targetMerge) {
|
|
227
|
+
return `${MERGE_STATE_SUBJECT}\n\n${JSON.stringify({ ref: targetMerge.ref, conflicted: targetMerge.conflictedPaths })}\n`;
|
|
228
|
+
}
|
|
229
|
+
function sameTargetMerge(left, right) {
|
|
230
|
+
if (!left || !right)
|
|
231
|
+
return left === right;
|
|
232
|
+
return (left.ref === right.ref &&
|
|
233
|
+
left.targetCommit === right.targetCommit &&
|
|
234
|
+
left.conflictedPaths.length === right.conflictedPaths.length &&
|
|
235
|
+
left.conflictedPaths.every((path, index) => path === right.conflictedPaths[index]));
|
|
236
|
+
}
|
|
195
237
|
function directChild(root, child) {
|
|
196
238
|
return child.startsWith(`${root}${sep}`) && !child.slice(root.length + 1).includes(sep);
|
|
197
239
|
}
|
|
@@ -244,6 +286,11 @@ export class GitVcsProvider {
|
|
|
244
286
|
// baseCommit already means exactly what it needs to: "where this
|
|
245
287
|
// round started."
|
|
246
288
|
const cloneBranch = normalized.continuation ? normalized.headRef : normalized.baseRef;
|
|
289
|
+
// A continuation is first brought up to date with the branch its pull
|
|
290
|
+
// request targets now (a person may have retargeted it since the root run).
|
|
291
|
+
const target = normalized.continuation ? await this.remote.pullRequestBase?.(normalized) : null;
|
|
292
|
+
const mergeRef = target ? safeGitRef(target.ref) : null;
|
|
293
|
+
let mergeFetched = false;
|
|
247
294
|
try {
|
|
248
295
|
await this.remote.withAccess(normalized.repository, async (token) => {
|
|
249
296
|
const auth = token !== undefined ? { authToken: token } : {};
|
|
@@ -280,6 +327,9 @@ export class GitVcsProvider {
|
|
|
280
327
|
cloneUrl,
|
|
281
328
|
workspacePath,
|
|
282
329
|
], { cwd: runRoot, ...auth });
|
|
330
|
+
if (mergeRef && mergeRef !== normalized.headRef) {
|
|
331
|
+
mergeFetched = await this.fetchMergeTarget(gitMetadataPath, workspacePath, cloneBranch, mergeRef, auth);
|
|
332
|
+
}
|
|
283
333
|
});
|
|
284
334
|
await rm(resolve(workspacePath, ".git"), { force: true });
|
|
285
335
|
const baseCommit = await this.revParseRaw(gitMetadataPath, workspacePath, `refs/remotes/origin/${cloneBranch}^{commit}`);
|
|
@@ -307,7 +357,15 @@ export class GitVcsProvider {
|
|
|
307
357
|
"HEAD",
|
|
308
358
|
`refs/heads/${normalized.headRef}`,
|
|
309
359
|
]);
|
|
310
|
-
|
|
360
|
+
const merged = mergeFetched && mergeRef
|
|
361
|
+
? await this.mergeTargetBranch(gitMetadataPath, workspacePath, baseCommit, mergeRef)
|
|
362
|
+
: null;
|
|
363
|
+
await this.gitForPaths(gitMetadataPath, workspacePath, [
|
|
364
|
+
"read-tree",
|
|
365
|
+
"--reset",
|
|
366
|
+
"-u",
|
|
367
|
+
merged?.tree ?? baseCommit,
|
|
368
|
+
]);
|
|
311
369
|
await this.inspectWorkspace(workspacePath);
|
|
312
370
|
return {
|
|
313
371
|
id: `vcs-${normalized.runId}`,
|
|
@@ -315,6 +373,7 @@ export class GitVcsProvider {
|
|
|
315
373
|
baseCommit,
|
|
316
374
|
workspacePath,
|
|
317
375
|
gitMetadataPath,
|
|
376
|
+
...(merged ? { targetMerge: merged.targetMerge } : {}),
|
|
318
377
|
};
|
|
319
378
|
}
|
|
320
379
|
catch (error) {
|
|
@@ -351,19 +410,30 @@ export class GitVcsProvider {
|
|
|
351
410
|
const symbolicHead = (await this.gitFor(prepared, ["symbolic-ref", "--short", "HEAD"])).stdout.trim();
|
|
352
411
|
if (symbolicHead !== prepared.headRef)
|
|
353
412
|
throw new Error("vcs_head_ref_mismatch");
|
|
413
|
+
const merge = await this.readMergeState(prepared);
|
|
354
414
|
const currentHead = await this.revParse(prepared, "HEAD");
|
|
355
415
|
if (currentHead !== prepared.baseCommit) {
|
|
356
416
|
const parent = await this.revParse(prepared, "HEAD^");
|
|
357
417
|
if (parent !== prepared.baseCommit)
|
|
358
418
|
throw new Error("vcs_commit_history_invalid");
|
|
419
|
+
if (merge && (await this.revParse(prepared, "HEAD^2")) !== merge.targetCommit) {
|
|
420
|
+
throw new Error("vcs_commit_history_invalid");
|
|
421
|
+
}
|
|
359
422
|
}
|
|
360
|
-
|
|
423
|
+
if (!merge)
|
|
424
|
+
return prepared;
|
|
425
|
+
const { stateCommit: _stateCommit, ...targetMerge } = merge;
|
|
426
|
+
return { ...prepared, targetMerge };
|
|
361
427
|
}
|
|
362
428
|
async finalizeChanges(workspace, details) {
|
|
363
429
|
const prepared = await this.validatePrepared(workspace);
|
|
364
430
|
await this.inspectWorkspace(prepared.workspacePath);
|
|
365
431
|
await this.assertRemote(prepared);
|
|
366
432
|
await this.assertSafeLocalConfig(prepared.gitMetadataPath);
|
|
433
|
+
// The merge state on disk is the trusted record; the handle must agree with it.
|
|
434
|
+
const merge = await this.readMergeState(prepared);
|
|
435
|
+
if (!sameTargetMerge(merge, prepared.targetMerge))
|
|
436
|
+
throw new Error("vcs_workspace_handle_invalid");
|
|
367
437
|
// Excluded paths (src/coding/collect-exclude.ts) are never collected from the worker, so
|
|
368
438
|
// they are also neither added nor deleted here: tracked files under them stay untouched.
|
|
369
439
|
await this.gitFor(prepared, [
|
|
@@ -373,15 +443,12 @@ export class GitVcsProvider {
|
|
|
373
443
|
":/",
|
|
374
444
|
...gitExcludePathspecs(normalizeCollectExclusions(prepared.collectExclude)),
|
|
375
445
|
]);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
prepared.baseCommit,
|
|
383
|
-
"--",
|
|
384
|
-
])).stdout);
|
|
446
|
+
// Every check below applies to the agent's own changes: against baseCommit, or, after a
|
|
447
|
+
// merge, against the trusted automatic merge result (so the target branch's own changes,
|
|
448
|
+
// protected paths included, pass, while any agent edit -- a conflict it resolved, a
|
|
449
|
+
// target change it reverted -- is checked).
|
|
450
|
+
const comparedTo = merge?.stateCommit ?? prepared.baseCommit;
|
|
451
|
+
const changed = nullSeparated((await this.gitFor(prepared, ["diff", "--cached", "--name-only", "-z", "--no-renames", comparedTo, "--"])).stdout);
|
|
385
452
|
if (changed.length > this.maxChangedFiles)
|
|
386
453
|
throw new Error("vcs_changed_file_limit");
|
|
387
454
|
const protectedChange = changed.find(protectedPathMatcher(prepared.protectedPaths));
|
|
@@ -389,7 +456,7 @@ export class GitVcsProvider {
|
|
|
389
456
|
throw new Error(`vcs_protected_path:${protectedChange}`);
|
|
390
457
|
let diff;
|
|
391
458
|
try {
|
|
392
|
-
diff = (await this.gitFor(prepared, ["diff", "--cached", "--binary", "--no-ext-diff", "--no-textconv",
|
|
459
|
+
diff = (await this.gitFor(prepared, ["diff", "--cached", "--binary", "--no-ext-diff", "--no-textconv", comparedTo, "--"], { maxOutputBytes: this.maxDiffBytes })).stdout;
|
|
393
460
|
}
|
|
394
461
|
catch (error) {
|
|
395
462
|
if (error instanceof GitCommandError && error.message.includes("git_output_limit")) {
|
|
@@ -399,8 +466,12 @@ export class GitVcsProvider {
|
|
|
399
466
|
}
|
|
400
467
|
if (Buffer.byteLength(diff, "utf8") > this.maxDiffBytes)
|
|
401
468
|
throw new Error("vcs_diff_size_limit");
|
|
469
|
+
// After the size limits, so a conflicted file is never read past what the diff limit allows.
|
|
470
|
+
if (merge)
|
|
471
|
+
await this.assertConflictsResolved(prepared.workspacePath, merge.conflictedPaths);
|
|
402
472
|
const currentHead = await this.revParse(prepared, "HEAD");
|
|
403
|
-
|
|
473
|
+
// A merge with no agent edits still has the merge itself to push.
|
|
474
|
+
if (!merge && changed.length === 0 && currentHead === prepared.baseCommit) {
|
|
404
475
|
return {
|
|
405
476
|
outcome: "no_changes",
|
|
406
477
|
repository: prepared.repository,
|
|
@@ -412,7 +483,10 @@ export class GitVcsProvider {
|
|
|
412
483
|
if (symbolicHead !== prepared.headRef)
|
|
413
484
|
throw new Error("vcs_head_ref_mismatch");
|
|
414
485
|
let commitSha;
|
|
415
|
-
if (currentHead === prepared.baseCommit) {
|
|
486
|
+
if (currentHead === prepared.baseCommit && merge) {
|
|
487
|
+
commitSha = await this.commitMerge(prepared, merge);
|
|
488
|
+
}
|
|
489
|
+
else if (currentHead === prepared.baseCommit) {
|
|
416
490
|
await this.gitFor(prepared, ["commit", "--no-verify", "--no-gpg-sign", "-m", `Wardby run ${prepared.runId}`]);
|
|
417
491
|
commitSha = await this.revParse(prepared, "HEAD");
|
|
418
492
|
}
|
|
@@ -420,14 +494,21 @@ export class GitVcsProvider {
|
|
|
420
494
|
const parent = await this.revParse(prepared, "HEAD^");
|
|
421
495
|
if (parent !== prepared.baseCommit)
|
|
422
496
|
throw new Error("vcs_commit_history_invalid");
|
|
497
|
+
if (merge && (await this.revParse(prepared, "HEAD^2")) !== merge.targetCommit) {
|
|
498
|
+
throw new Error("vcs_commit_history_invalid");
|
|
499
|
+
}
|
|
423
500
|
const afterCommitChanges = nullSeparated((await this.gitFor(prepared, ["diff", "--cached", "--name-only", "-z", "HEAD", "--"])).stdout);
|
|
424
501
|
if (afterCommitChanges.length > 0)
|
|
425
502
|
throw new Error("vcs_finalized_workspace_changed");
|
|
426
503
|
commitSha = currentHead;
|
|
427
504
|
}
|
|
428
505
|
await this.remote.assertContinuationOpen(prepared);
|
|
506
|
+
// Before the push: a description comment must already exist when the push starts a review.
|
|
507
|
+
await this.remote
|
|
508
|
+
.proposeDescriptionBeforePush?.({ workspace: prepared, details, changedPaths: changed, commitSha })
|
|
509
|
+
.catch(() => undefined);
|
|
429
510
|
await this.pushOnce(prepared, commitSha);
|
|
430
|
-
const published = await this.remote.publish({ workspace: prepared, details, changedPaths: changed });
|
|
511
|
+
const published = await this.remote.publish({ workspace: prepared, details, changedPaths: changed, commitSha });
|
|
431
512
|
if (published.kind === "branch") {
|
|
432
513
|
if (published.branch !== prepared.headRef)
|
|
433
514
|
throw new Error("vcs_head_ref_mismatch");
|
|
@@ -449,8 +530,47 @@ export class GitVcsProvider {
|
|
|
449
530
|
commitSha,
|
|
450
531
|
pullRequestNumber: published.number,
|
|
451
532
|
pullRequestUrl: published.url,
|
|
533
|
+
...(published.description ? { description: published.description } : {}),
|
|
534
|
+
...(merge && prepared.continuation
|
|
535
|
+
? {
|
|
536
|
+
targetMerge: {
|
|
537
|
+
ref: merge.ref,
|
|
538
|
+
targetCommit: merge.targetCommit,
|
|
539
|
+
conflicts: merge.conflictedPaths.length,
|
|
540
|
+
},
|
|
541
|
+
}
|
|
542
|
+
: {}),
|
|
452
543
|
};
|
|
453
544
|
}
|
|
545
|
+
/** The two-parent merge commit (baseCommit, the target) of the staged tree, as the Wardby identity. */
|
|
546
|
+
async commitMerge(prepared, merge) {
|
|
547
|
+
const tree = (await this.gitFor(prepared, ["write-tree"])).stdout.trim();
|
|
548
|
+
if (!SAFE_COMMIT_SHA.test(tree))
|
|
549
|
+
throw new Error("vcs_commit_sha_invalid");
|
|
550
|
+
const commitSha = (await this.gitFor(prepared, [
|
|
551
|
+
"commit-tree",
|
|
552
|
+
tree,
|
|
553
|
+
"-p",
|
|
554
|
+
prepared.baseCommit,
|
|
555
|
+
"-p",
|
|
556
|
+
merge.targetCommit,
|
|
557
|
+
"-m",
|
|
558
|
+
`Merge ${merge.ref} into ${prepared.headRef} (Wardby run ${prepared.runId})`,
|
|
559
|
+
])).stdout.trim();
|
|
560
|
+
if (!SAFE_COMMIT_SHA.test(commitSha))
|
|
561
|
+
throw new Error("vcs_commit_sha_invalid");
|
|
562
|
+
await this.gitFor(prepared, ["update-ref", `refs/heads/${prepared.headRef}`, commitSha, prepared.baseCommit]);
|
|
563
|
+
return commitSha;
|
|
564
|
+
}
|
|
565
|
+
/** Re-derive a continuation's PR description without a push, delegated to the remote; never throws. */
|
|
566
|
+
async refreshPullRequestDescription(workspace, details) {
|
|
567
|
+
try {
|
|
568
|
+
return await this.remote.refreshDescription?.(workspace, details);
|
|
569
|
+
}
|
|
570
|
+
catch {
|
|
571
|
+
return { kind: "skipped", reason: "error" };
|
|
572
|
+
}
|
|
573
|
+
}
|
|
454
574
|
async cleanup(workspace) {
|
|
455
575
|
const expected = this.expectedPaths(workspace.runId);
|
|
456
576
|
if (workspace.id !== `vcs-${workspace.runId}` ||
|
|
@@ -465,6 +585,15 @@ export class GitVcsProvider {
|
|
|
465
585
|
* delegated to the remote; a remote without one is a no-op. Wrapped so
|
|
466
586
|
* this can NEVER throw or otherwise affect the real coding run.
|
|
467
587
|
*/
|
|
588
|
+
/** Delegated to the remote; never throws (undefined on any failure). */
|
|
589
|
+
async continuationPullRequestDraft(workspace) {
|
|
590
|
+
try {
|
|
591
|
+
return await this.remote.continuationPullRequestDraft?.(workspace);
|
|
592
|
+
}
|
|
593
|
+
catch {
|
|
594
|
+
return undefined;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
468
597
|
async notifyContinuationStarted(workspace, details) {
|
|
469
598
|
try {
|
|
470
599
|
await this.remote.notifyContinuationStarted?.(workspace, details);
|
|
@@ -561,6 +690,179 @@ export class GitVcsProvider {
|
|
|
561
690
|
}
|
|
562
691
|
return { ...workspace, ...normalized };
|
|
563
692
|
}
|
|
693
|
+
/**
|
|
694
|
+
* Fetches a continuation's target branch from the same `origin` the clone
|
|
695
|
+
* came from (never another URL, so never a fork) and deepens the depth-1
|
|
696
|
+
* clone step by step until the head and the target share a merge base.
|
|
697
|
+
* Returns true once they do; throws vcs_target_merge_failed when the fetch
|
|
698
|
+
* fails or no merge base turns up within MERGE_BASE_DEEPEN_STEPS.
|
|
699
|
+
*/
|
|
700
|
+
async fetchMergeTarget(gitMetadataPath, workspacePath, cloneBranch, ref, auth) {
|
|
701
|
+
const fetch = (depth, refspec) => this.gitForPaths(gitMetadataPath, workspacePath, [...this.remote.gitConfig, "fetch", "--no-tags", "--no-write-fetch-head", ...depth, "origin", refspec], auth);
|
|
702
|
+
const target = `+refs/heads/${ref}:${MERGE_TARGET_REF}`;
|
|
703
|
+
// The head is deepened through its own ref under refs/wardby, so the clone's
|
|
704
|
+
// refs/remotes/origin/<head> (baseCommit) never moves.
|
|
705
|
+
const head = `+refs/heads/${cloneBranch}:${MERGE_HEAD_REF}`;
|
|
706
|
+
try {
|
|
707
|
+
await fetch(["--depth", "1"], target);
|
|
708
|
+
for (const step of [0, ...MERGE_BASE_DEEPEN_STEPS]) {
|
|
709
|
+
if (step > 0) {
|
|
710
|
+
// One fetch per side: newer git deepens only the refs a fetch names
|
|
711
|
+
// (older git deepened every shallow boundary), and a fetch naming
|
|
712
|
+
// both deepens only one of them.
|
|
713
|
+
await fetch([`--deepen=${step}`], head);
|
|
714
|
+
await fetch([`--deepen=${step}`], target);
|
|
715
|
+
}
|
|
716
|
+
const base = await this.gitForPaths(gitMetadataPath, workspacePath, ["merge-base", `refs/remotes/origin/${cloneBranch}`, MERGE_TARGET_REF], { acceptExitCodes: [1] });
|
|
717
|
+
if (base.stdout.trim())
|
|
718
|
+
return true;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
catch (error) {
|
|
722
|
+
throw new Error("vcs_target_merge_failed", { cause: error });
|
|
723
|
+
}
|
|
724
|
+
throw new Error("vcs_target_merge_failed");
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Merges the fetched target into baseCommit without touching the index or
|
|
728
|
+
* the working tree (`merge-tree --write-tree`: no MERGE_HEAD, no hooks, no
|
|
729
|
+
* merge drivers -- none are configured), and records the result as the merge
|
|
730
|
+
* state. Null when the target is already part of the branch (nothing to merge).
|
|
731
|
+
*/
|
|
732
|
+
async mergeTargetBranch(gitMetadataPath, workspacePath, baseCommit, ref) {
|
|
733
|
+
const targetCommit = await this.revParseRaw(gitMetadataPath, workspacePath, `${MERGE_TARGET_REF}^{commit}`);
|
|
734
|
+
const mergeBase = (await this.gitForPaths(gitMetadataPath, workspacePath, ["merge-base", baseCommit, targetCommit])).stdout.trim();
|
|
735
|
+
if (mergeBase === targetCommit)
|
|
736
|
+
return null;
|
|
737
|
+
// The clone is --no-checkout and nothing is read into the index or the
|
|
738
|
+
// working tree until after this merge, so no repository .gitattributes
|
|
739
|
+
// (a marker size, `-merge`, `merge=union`) can steer it.
|
|
740
|
+
let output;
|
|
741
|
+
try {
|
|
742
|
+
output = (await this.gitForPaths(gitMetadataPath, workspacePath, ["merge-tree", "--write-tree", "-z", "--name-only", "--no-messages", baseCommit, targetCommit], { acceptExitCodes: [1] })).stdout;
|
|
743
|
+
}
|
|
744
|
+
catch (error) {
|
|
745
|
+
throw new Error("vcs_target_merge_failed", { cause: error });
|
|
746
|
+
}
|
|
747
|
+
const [tree, ...paths] = output.split("\0");
|
|
748
|
+
if (!SAFE_COMMIT_SHA.test(tree))
|
|
749
|
+
throw new Error("vcs_target_merge_failed");
|
|
750
|
+
const conflictedPaths = [...new Set(paths.filter(Boolean))].map(validateChangedPath);
|
|
751
|
+
if (conflictedPaths.length > this.maxChangedFiles)
|
|
752
|
+
throw new Error("vcs_target_merge_failed");
|
|
753
|
+
const targetMerge = { ref, targetCommit, conflictedPaths };
|
|
754
|
+
// The message goes through a file: a long conflicted-path list could pass an argument's size limit.
|
|
755
|
+
const messagePath = resolve(gitMetadataPath, "WARDBY_MERGE_STATE_MSG");
|
|
756
|
+
await writeFile(messagePath, mergeStateMessage(targetMerge), { mode: 0o600 });
|
|
757
|
+
try {
|
|
758
|
+
const stateCommit = (await this.gitForPaths(gitMetadataPath, workspacePath, [
|
|
759
|
+
"commit-tree",
|
|
760
|
+
tree,
|
|
761
|
+
"-p",
|
|
762
|
+
baseCommit,
|
|
763
|
+
"-p",
|
|
764
|
+
targetCommit,
|
|
765
|
+
"-F",
|
|
766
|
+
messagePath,
|
|
767
|
+
])).stdout.trim();
|
|
768
|
+
if (!SAFE_COMMIT_SHA.test(stateCommit))
|
|
769
|
+
throw new Error("vcs_commit_sha_invalid");
|
|
770
|
+
await this.gitForPaths(gitMetadataPath, workspacePath, ["update-ref", MERGE_STATE_REF, stateCommit]);
|
|
771
|
+
}
|
|
772
|
+
finally {
|
|
773
|
+
await rm(messagePath, { force: true });
|
|
774
|
+
}
|
|
775
|
+
return { tree, targetMerge };
|
|
776
|
+
}
|
|
777
|
+
/** The recorded merge state (see MERGE_STATE_REF), validated, or undefined when the workspace merged nothing. */
|
|
778
|
+
async readMergeState(workspace) {
|
|
779
|
+
const { gitMetadataPath, workspacePath } = workspace;
|
|
780
|
+
const stateCommit = (await this.gitForPaths(gitMetadataPath, workspacePath, [
|
|
781
|
+
"for-each-ref",
|
|
782
|
+
"--format=%(objectname)",
|
|
783
|
+
MERGE_STATE_REF,
|
|
784
|
+
])).stdout.trim();
|
|
785
|
+
if (!stateCommit)
|
|
786
|
+
return undefined;
|
|
787
|
+
if (!SAFE_COMMIT_SHA.test(stateCommit))
|
|
788
|
+
throw new Error("vcs_merge_state_invalid");
|
|
789
|
+
const raw = (await this.gitForPaths(gitMetadataPath, workspacePath, ["cat-file", "commit", stateCommit])).stdout;
|
|
790
|
+
const split = raw.indexOf("\n\n");
|
|
791
|
+
if (split < 0)
|
|
792
|
+
throw new Error("vcs_merge_state_invalid");
|
|
793
|
+
const parents = raw
|
|
794
|
+
.slice(0, split)
|
|
795
|
+
.split("\n")
|
|
796
|
+
.filter((line) => line.startsWith("parent "))
|
|
797
|
+
.map((line) => line.slice("parent ".length));
|
|
798
|
+
const message = raw.slice(split + 2);
|
|
799
|
+
if (parents.length !== 2 ||
|
|
800
|
+
parents[0] !== workspace.baseCommit ||
|
|
801
|
+
!SAFE_COMMIT_SHA.test(parents[1]) ||
|
|
802
|
+
!message.startsWith(`${MERGE_STATE_SUBJECT}\n\n`)) {
|
|
803
|
+
throw new Error("vcs_merge_state_invalid");
|
|
804
|
+
}
|
|
805
|
+
let parsed;
|
|
806
|
+
try {
|
|
807
|
+
parsed = JSON.parse(message.slice(MERGE_STATE_SUBJECT.length + 2));
|
|
808
|
+
}
|
|
809
|
+
catch (error) {
|
|
810
|
+
throw new Error("vcs_merge_state_invalid", { cause: error });
|
|
811
|
+
}
|
|
812
|
+
const state = parsed;
|
|
813
|
+
if (typeof state.ref !== "string" ||
|
|
814
|
+
!Array.isArray(state.conflicted) ||
|
|
815
|
+
state.conflicted.length > this.maxChangedFiles ||
|
|
816
|
+
state.conflicted.some((path) => typeof path !== "string")) {
|
|
817
|
+
throw new Error("vcs_merge_state_invalid");
|
|
818
|
+
}
|
|
819
|
+
const ref = safeGitRef(state.ref);
|
|
820
|
+
if (!ref)
|
|
821
|
+
throw new Error("vcs_merge_state_invalid");
|
|
822
|
+
return {
|
|
823
|
+
ref,
|
|
824
|
+
targetCommit: parents[1],
|
|
825
|
+
conflictedPaths: state.conflicted.map(validateChangedPath),
|
|
826
|
+
stateCommit,
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Refuses to finalize while a file the merge left conflicted still holds a
|
|
831
|
+
* conflict marker pair. Only those files are read: elsewhere a line of
|
|
832
|
+
* `<<<<<<<` may be legitimate content (a fixture, a doc about merging).
|
|
833
|
+
*/
|
|
834
|
+
async assertConflictsResolved(workspacePath, conflictedPaths) {
|
|
835
|
+
for (const path of conflictedPaths) {
|
|
836
|
+
const fullPath = resolve(workspacePath, path);
|
|
837
|
+
if (!fullPath.startsWith(`${workspacePath}${sep}`))
|
|
838
|
+
throw new Error("vcs_changed_path_invalid");
|
|
839
|
+
// One no-follow open, then stat and read through that handle: nothing can swap the file in between.
|
|
840
|
+
let handle;
|
|
841
|
+
try {
|
|
842
|
+
handle = await open(fullPath, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
|
|
843
|
+
}
|
|
844
|
+
catch (error) {
|
|
845
|
+
const code = error.code;
|
|
846
|
+
// Deleted while resolving, or a symlink (ELOOP): nothing left to hold a marker.
|
|
847
|
+
if (code === "ENOENT" || code === "ENOTDIR" || code === "ELOOP")
|
|
848
|
+
continue;
|
|
849
|
+
throw error;
|
|
850
|
+
}
|
|
851
|
+
let content;
|
|
852
|
+
try {
|
|
853
|
+
// Not a regular file (a directory now stands there): nothing to scan.
|
|
854
|
+
if (!(await handle.stat()).isFile())
|
|
855
|
+
continue;
|
|
856
|
+
content = await handle.readFile("utf8");
|
|
857
|
+
}
|
|
858
|
+
finally {
|
|
859
|
+
await handle.close();
|
|
860
|
+
}
|
|
861
|
+
if (CONFLICT_MARKER_START.test(content) && CONFLICT_MARKER_END.test(content)) {
|
|
862
|
+
throw new Error(`vcs_conflict_markers_remain:${path}`);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
564
866
|
async inspectWorkspace(workspacePath) {
|
|
565
867
|
const rootStat = await lstat(workspacePath);
|
|
566
868
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink())
|
|
@@ -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
|
}
|