dorfl 0.0.0 → 0.1.1
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/dist/advance-ci-template.d.ts +73 -0
- package/dist/advance-ci-template.d.ts.map +1 -0
- package/dist/advance-ci-template.js +104 -0
- package/dist/advance-ci-template.js.map +1 -0
- package/dist/advance-classify.d.ts +132 -0
- package/dist/advance-classify.d.ts.map +1 -0
- package/dist/advance-classify.js +120 -0
- package/dist/advance-classify.js.map +1 -0
- package/dist/advance-drivers.d.ts +182 -0
- package/dist/advance-drivers.d.ts.map +1 -0
- package/dist/advance-drivers.js +231 -0
- package/dist/advance-drivers.js.map +1 -0
- package/dist/advance-isolated.d.ts +156 -0
- package/dist/advance-isolated.d.ts.map +1 -0
- package/dist/advance-isolated.js +256 -0
- package/dist/advance-isolated.js.map +1 -0
- package/dist/advance-lifecycle-template.d.ts +107 -0
- package/dist/advance-lifecycle-template.d.ts.map +1 -0
- package/dist/advance-lifecycle-template.js +668 -0
- package/dist/advance-lifecycle-template.js.map +1 -0
- package/dist/advance-loop-driver.d.ts +325 -0
- package/dist/advance-loop-driver.d.ts.map +1 -0
- package/dist/advance-loop-driver.js +437 -0
- package/dist/advance-loop-driver.js.map +1 -0
- package/dist/advance-treeless-publish.d.ts +108 -0
- package/dist/advance-treeless-publish.d.ts.map +1 -0
- package/dist/advance-treeless-publish.js +71 -0
- package/dist/advance-treeless-publish.js.map +1 -0
- package/dist/advance.d.ts +340 -0
- package/dist/advance.d.ts.map +1 -0
- package/dist/advance.js +1122 -0
- package/dist/advance.js.map +1 -0
- package/dist/advancing-lock.d.ts +294 -0
- package/dist/advancing-lock.d.ts.map +1 -0
- package/dist/advancing-lock.js +594 -0
- package/dist/advancing-lock.js.map +1 -0
- package/dist/agent-launch.d.ts +79 -0
- package/dist/agent-launch.d.ts.map +1 -0
- package/dist/agent-launch.js +61 -0
- package/dist/agent-launch.js.map +1 -0
- package/dist/agent-stop.d.ts +149 -0
- package/dist/agent-stop.d.ts.map +1 -0
- package/dist/agent-stop.js +307 -0
- package/dist/agent-stop.js.map +1 -0
- package/dist/apply-decide.d.ts +127 -0
- package/dist/apply-decide.d.ts.map +1 -0
- package/dist/apply-decide.js +176 -0
- package/dist/apply-decide.js.map +1 -0
- package/dist/apply-merge-action.d.ts +206 -0
- package/dist/apply-merge-action.d.ts.map +1 -0
- package/dist/apply-merge-action.js +307 -0
- package/dist/apply-merge-action.js.map +1 -0
- package/dist/apply-persist.d.ts +174 -0
- package/dist/apply-persist.d.ts.map +1 -0
- package/dist/apply-persist.js +359 -0
- package/dist/apply-persist.js.map +1 -0
- package/dist/arbiter.d.ts +120 -0
- package/dist/arbiter.d.ts.map +1 -0
- package/dist/arbiter.js +255 -0
- package/dist/arbiter.js.map +1 -0
- package/dist/brand.d.ts +70 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +84 -0
- package/dist/brand.js.map +1 -0
- package/dist/buildable-body.d.ts +132 -0
- package/dist/buildable-body.d.ts.map +1 -0
- package/dist/buildable-body.js +131 -0
- package/dist/buildable-body.js.map +1 -0
- package/dist/categorise.d.ts +66 -0
- package/dist/categorise.d.ts.map +1 -0
- package/dist/categorise.js +106 -0
- package/dist/categorise.js.map +1 -0
- package/dist/claim-cas.d.ts +117 -0
- package/dist/claim-cas.d.ts.map +1 -0
- package/dist/claim-cas.js +312 -0
- package/dist/claim-cas.js.map +1 -0
- package/dist/cli-spinner.d.ts +112 -0
- package/dist/cli-spinner.d.ts.map +1 -0
- package/dist/cli-spinner.js +157 -0
- package/dist/cli-spinner.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +3100 -0
- package/dist/cli.js.map +1 -0
- package/dist/close-job-template.d.ts +70 -0
- package/dist/close-job-template.d.ts.map +1 -0
- package/dist/close-job-template.js +180 -0
- package/dist/close-job-template.js.map +1 -0
- package/dist/close-job.d.ts +95 -0
- package/dist/close-job.d.ts.map +1 -0
- package/dist/close-job.js +226 -0
- package/dist/close-job.js.map +1 -0
- package/dist/complete.d.ts +361 -0
- package/dist/complete.d.ts.map +1 -0
- package/dist/complete.js +885 -0
- package/dist/complete.js.map +1 -0
- package/dist/concurrency.d.ts +68 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +112 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/config-override.d.ts +76 -0
- package/dist/config-override.d.ts.map +1 -0
- package/dist/config-override.js +50 -0
- package/dist/config-override.js.map +1 -0
- package/dist/config.d.ts +668 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +241 -0
- package/dist/config.js.map +1 -0
- package/dist/continue-branch.d.ts +249 -0
- package/dist/continue-branch.d.ts.map +1 -0
- package/dist/continue-branch.js +389 -0
- package/dist/continue-branch.js.map +1 -0
- package/dist/cwd-section.d.ts +186 -0
- package/dist/cwd-section.d.ts.map +1 -0
- package/dist/cwd-section.js +209 -0
- package/dist/cwd-section.js.map +1 -0
- package/dist/decision-engine.d.ts +170 -0
- package/dist/decision-engine.d.ts.map +1 -0
- package/dist/decision-engine.js +136 -0
- package/dist/decision-engine.js.map +1 -0
- package/dist/detect.d.ts +17 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +118 -0
- package/dist/detect.js.map +1 -0
- package/dist/do-autopick.d.ts +85 -0
- package/dist/do-autopick.d.ts.map +1 -0
- package/dist/do-autopick.js +112 -0
- package/dist/do-autopick.js.map +1 -0
- package/dist/do-config.d.ts +312 -0
- package/dist/do-config.d.ts.map +1 -0
- package/dist/do-config.js +358 -0
- package/dist/do-config.js.map +1 -0
- package/dist/do-remote-auto.d.ts +75 -0
- package/dist/do-remote-auto.d.ts.map +1 -0
- package/dist/do-remote-auto.js +111 -0
- package/dist/do-remote-auto.js.map +1 -0
- package/dist/do.d.ts +621 -0
- package/dist/do.d.ts.map +1 -0
- package/dist/do.js +1882 -0
- package/dist/do.js.map +1 -0
- package/dist/drop-source.d.ts +96 -0
- package/dist/drop-source.d.ts.map +1 -0
- package/dist/drop-source.js +91 -0
- package/dist/drop-source.js.map +1 -0
- package/dist/eligibility.d.ts +46 -0
- package/dist/eligibility.d.ts.map +1 -0
- package/dist/eligibility.js +34 -0
- package/dist/eligibility.js.map +1 -0
- package/dist/env-config.d.ts +51 -0
- package/dist/env-config.d.ts.map +1 -0
- package/dist/env-config.js +272 -0
- package/dist/env-config.js.map +1 -0
- package/dist/failure-cause.d.ts +70 -0
- package/dist/failure-cause.d.ts.map +1 -0
- package/dist/failure-cause.js +126 -0
- package/dist/failure-cause.js.map +1 -0
- package/dist/format.d.ts +43 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +256 -0
- package/dist/format.js.map +1 -0
- package/dist/frontmatter.d.ts +208 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +344 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/gate-readiness.d.ts +84 -0
- package/dist/gate-readiness.d.ts.map +1 -0
- package/dist/gate-readiness.js +103 -0
- package/dist/gate-readiness.js.map +1 -0
- package/dist/gc.d.ts +165 -0
- package/dist/gc.d.ts.map +1 -0
- package/dist/gc.js +313 -0
- package/dist/gc.js.map +1 -0
- package/dist/gh-failure.d.ts +42 -0
- package/dist/gh-failure.d.ts.map +1 -0
- package/dist/gh-failure.js +49 -0
- package/dist/gh-failure.js.map +1 -0
- package/dist/git.d.ts +75 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +130 -0
- package/dist/git.js.map +1 -0
- package/dist/github.d.ts +187 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +343 -0
- package/dist/github.js.map +1 -0
- package/dist/harness.d.ts +242 -0
- package/dist/harness.d.ts.map +1 -0
- package/dist/harness.js +157 -0
- package/dist/harness.js.map +1 -0
- package/dist/identity.d.ts +167 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +231 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +147 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/install-ci-branch-protection.d.ts +147 -0
- package/dist/install-ci-branch-protection.d.ts.map +1 -0
- package/dist/install-ci-branch-protection.js +166 -0
- package/dist/install-ci-branch-protection.js.map +1 -0
- package/dist/install-ci-capabilities/advance-lifecycle.d.ts +15 -0
- package/dist/install-ci-capabilities/advance-lifecycle.d.ts.map +1 -0
- package/dist/install-ci-capabilities/advance-lifecycle.js +28 -0
- package/dist/install-ci-capabilities/advance-lifecycle.js.map +1 -0
- package/dist/install-ci-capabilities/close-job.d.ts +13 -0
- package/dist/install-ci-capabilities/close-job.d.ts.map +1 -0
- package/dist/install-ci-capabilities/close-job.js +26 -0
- package/dist/install-ci-capabilities/close-job.js.map +1 -0
- package/dist/install-ci-capabilities/example-noop.d.ts +16 -0
- package/dist/install-ci-capabilities/example-noop.d.ts.map +1 -0
- package/dist/install-ci-capabilities/example-noop.js +23 -0
- package/dist/install-ci-capabilities/example-noop.js.map +1 -0
- package/dist/install-ci-capabilities/intake.d.ts +15 -0
- package/dist/install-ci-capabilities/intake.d.ts.map +1 -0
- package/dist/install-ci-capabilities/intake.js +28 -0
- package/dist/install-ci-capabilities/intake.js.map +1 -0
- package/dist/install-ci-capabilities/verify.d.ts +14 -0
- package/dist/install-ci-capabilities/verify.d.ts.map +1 -0
- package/dist/install-ci-capabilities/verify.js +27 -0
- package/dist/install-ci-capabilities/verify.js.map +1 -0
- package/dist/install-ci-core.d.ts +446 -0
- package/dist/install-ci-core.d.ts.map +1 -0
- package/dist/install-ci-core.js +760 -0
- package/dist/install-ci-core.js.map +1 -0
- package/dist/install-ci-github.d.ts +167 -0
- package/dist/install-ci-github.d.ts.map +1 -0
- package/dist/install-ci-github.js +315 -0
- package/dist/install-ci-github.js.map +1 -0
- package/dist/install-ci.d.ts +105 -0
- package/dist/install-ci.d.ts.map +1 -0
- package/dist/install-ci.js +363 -0
- package/dist/install-ci.js.map +1 -0
- package/dist/intake-event.d.ts +88 -0
- package/dist/intake-event.d.ts.map +1 -0
- package/dist/intake-event.js +66 -0
- package/dist/intake-event.js.map +1 -0
- package/dist/intake-marker.d.ts +95 -0
- package/dist/intake-marker.d.ts.map +1 -0
- package/dist/intake-marker.js +127 -0
- package/dist/intake-marker.js.map +1 -0
- package/dist/intake-triage.d.ts +48 -0
- package/dist/intake-triage.d.ts.map +1 -0
- package/dist/intake-triage.js +95 -0
- package/dist/intake-triage.js.map +1 -0
- package/dist/intake-trigger-template.d.ts +185 -0
- package/dist/intake-trigger-template.d.ts.map +1 -0
- package/dist/intake-trigger-template.js +449 -0
- package/dist/intake-trigger-template.js.map +1 -0
- package/dist/intake.d.ts +569 -0
- package/dist/intake.d.ts.map +1 -0
- package/dist/intake.js +1628 -0
- package/dist/intake.js.map +1 -0
- package/dist/integration-core.d.ts +539 -0
- package/dist/integration-core.d.ts.map +1 -0
- package/dist/integration-core.js +2195 -0
- package/dist/integration-core.js.map +1 -0
- package/dist/integrator.d.ts +343 -0
- package/dist/integrator.d.ts.map +1 -0
- package/dist/integrator.js +400 -0
- package/dist/integrator.js.map +1 -0
- package/dist/isolation.d.ts +219 -0
- package/dist/isolation.d.ts.map +1 -0
- package/dist/isolation.js +261 -0
- package/dist/isolation.js.map +1 -0
- package/dist/issue-provider.d.ts +349 -0
- package/dist/issue-provider.d.ts.map +1 -0
- package/dist/issue-provider.js +360 -0
- package/dist/issue-provider.js.map +1 -0
- package/dist/item-lock.d.ts +626 -0
- package/dist/item-lock.d.ts.map +1 -0
- package/dist/item-lock.js +1381 -0
- package/dist/item-lock.js.map +1 -0
- package/dist/item-path.d.ts +49 -0
- package/dist/item-path.d.ts.map +1 -0
- package/dist/item-path.js +66 -0
- package/dist/item-path.js.map +1 -0
- package/dist/ledger-lint.d.ts +129 -0
- package/dist/ledger-lint.d.ts.map +1 -0
- package/dist/ledger-lint.js +249 -0
- package/dist/ledger-lint.js.map +1 -0
- package/dist/ledger-read.d.ts +357 -0
- package/dist/ledger-read.d.ts.map +1 -0
- package/dist/ledger-read.js +442 -0
- package/dist/ledger-read.js.map +1 -0
- package/dist/ledger-write.d.ts +330 -0
- package/dist/ledger-write.d.ts.map +1 -0
- package/dist/ledger-write.js +411 -0
- package/dist/ledger-write.js.map +1 -0
- package/dist/lifecycle-gather.d.ts +30 -0
- package/dist/lifecycle-gather.d.ts.map +1 -0
- package/dist/lifecycle-gather.js +205 -0
- package/dist/lifecycle-gather.js.map +1 -0
- package/dist/lifecycle-pools.d.ts +180 -0
- package/dist/lifecycle-pools.d.ts.map +1 -0
- package/dist/lifecycle-pools.js +78 -0
- package/dist/lifecycle-pools.js.map +1 -0
- package/dist/merge-question-surfacer.d.ts +166 -0
- package/dist/merge-question-surfacer.d.ts.map +1 -0
- package/dist/merge-question-surfacer.js +297 -0
- package/dist/merge-question-surfacer.js.map +1 -0
- package/dist/mint-adr.d.ts +126 -0
- package/dist/mint-adr.d.ts.map +1 -0
- package/dist/mint-adr.js +257 -0
- package/dist/mint-adr.js.map +1 -0
- package/dist/mirror-pool-scan.d.ts +125 -0
- package/dist/mirror-pool-scan.d.ts.map +1 -0
- package/dist/mirror-pool-scan.js +104 -0
- package/dist/mirror-pool-scan.js.map +1 -0
- package/dist/needs-attention.d.ts +341 -0
- package/dist/needs-attention.d.ts.map +1 -0
- package/dist/needs-attention.js +900 -0
- package/dist/needs-attention.js.map +1 -0
- package/dist/orphan-sidecar.d.ts +79 -0
- package/dist/orphan-sidecar.d.ts.map +1 -0
- package/dist/orphan-sidecar.js +71 -0
- package/dist/orphan-sidecar.js.map +1 -0
- package/dist/output.d.ts +48 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +66 -0
- package/dist/output.js.map +1 -0
- package/dist/pi-harness.d.ts +179 -0
- package/dist/pi-harness.d.ts.map +1 -0
- package/dist/pi-harness.js +342 -0
- package/dist/pi-harness.js.map +1 -0
- package/dist/placement.d.ts +99 -0
- package/dist/placement.d.ts.map +1 -0
- package/dist/placement.js +67 -0
- package/dist/placement.js.map +1 -0
- package/dist/prd-to-spec.d.ts +329 -0
- package/dist/prd-to-spec.d.ts.map +1 -0
- package/dist/prd-to-spec.js +706 -0
- package/dist/prd-to-spec.js.map +1 -0
- package/dist/prepare.d.ts +121 -0
- package/dist/prepare.d.ts.map +1 -0
- package/dist/prepare.js +140 -0
- package/dist/prepare.js.map +1 -0
- package/dist/prompt.d.ts +363 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +499 -0
- package/dist/prompt.js.map +1 -0
- package/dist/protocol/ADR-FORMAT.md +47 -0
- package/dist/protocol/CLAIM-PROTOCOL.md +217 -0
- package/dist/protocol/REVIEW-PROTOCOL.md +119 -0
- package/dist/protocol/SURFACE-PROTOCOL.md +121 -0
- package/dist/protocol/TASKING-PROTOCOL.md +122 -0
- package/dist/protocol/WORK-CONTRACT.md +276 -0
- package/dist/protocol/spec-template.md +71 -0
- package/dist/protocol/task-template.md +65 -0
- package/dist/readiness.d.ts +66 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +36 -0
- package/dist/readiness.js.map +1 -0
- package/dist/reap-branches.d.ts +102 -0
- package/dist/reap-branches.d.ts.map +1 -0
- package/dist/reap-branches.js +149 -0
- package/dist/reap-branches.js.map +1 -0
- package/dist/recover-isolated.d.ts +72 -0
- package/dist/recover-isolated.d.ts.map +1 -0
- package/dist/recover-isolated.js +188 -0
- package/dist/recover-isolated.js.map +1 -0
- package/dist/registry.d.ts +172 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +296 -0
- package/dist/registry.js.map +1 -0
- package/dist/repo-config.d.ts +201 -0
- package/dist/repo-config.d.ts.map +1 -0
- package/dist/repo-config.js +414 -0
- package/dist/repo-config.js.map +1 -0
- package/dist/repo-key.d.ts +20 -0
- package/dist/repo-key.d.ts.map +1 -0
- package/dist/repo-key.js +68 -0
- package/dist/repo-key.js.map +1 -0
- package/dist/repo-mirror.d.ts +177 -0
- package/dist/repo-mirror.d.ts.map +1 -0
- package/dist/repo-mirror.js +271 -0
- package/dist/repo-mirror.js.map +1 -0
- package/dist/retry-backoff.d.ts +90 -0
- package/dist/retry-backoff.d.ts.map +1 -0
- package/dist/retry-backoff.js +98 -0
- package/dist/retry-backoff.js.map +1 -0
- package/dist/review-gate.d.ts +173 -0
- package/dist/review-gate.d.ts.map +1 -0
- package/dist/review-gate.js +261 -0
- package/dist/review-gate.js.map +1 -0
- package/dist/review-verdict.d.ts +149 -0
- package/dist/review-verdict.d.ts.map +1 -0
- package/dist/review-verdict.js +332 -0
- package/dist/review-verdict.js.map +1 -0
- package/dist/run.d.ts +221 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +963 -0
- package/dist/run.js.map +1 -0
- package/dist/scan.d.ts +308 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +374 -0
- package/dist/scan.js.map +1 -0
- package/dist/select-order.d.ts +75 -0
- package/dist/select-order.d.ts.map +1 -0
- package/dist/select-order.js +108 -0
- package/dist/select-order.js.map +1 -0
- package/dist/select-priority.d.ts +188 -0
- package/dist/select-priority.d.ts.map +1 -0
- package/dist/select-priority.js +80 -0
- package/dist/select-priority.js.map +1 -0
- package/dist/select.d.ts +25 -0
- package/dist/select.d.ts.map +1 -0
- package/dist/select.js +43 -0
- package/dist/select.js.map +1 -0
- package/dist/session-path.d.ts +36 -0
- package/dist/session-path.d.ts.map +1 -0
- package/dist/session-path.js +129 -0
- package/dist/session-path.js.map +1 -0
- package/dist/sidecar-apply.d.ts +83 -0
- package/dist/sidecar-apply.d.ts.map +1 -0
- package/dist/sidecar-apply.js +111 -0
- package/dist/sidecar-apply.js.map +1 -0
- package/dist/sidecar.d.ts +245 -0
- package/dist/sidecar.d.ts.map +1 -0
- package/dist/sidecar.js +481 -0
- package/dist/sidecar.js.map +1 -0
- package/dist/slug-namespace.d.ts +204 -0
- package/dist/slug-namespace.d.ts.map +1 -0
- package/dist/slug-namespace.js +229 -0
- package/dist/slug-namespace.js.map +1 -0
- package/dist/spec-complete.d.ts +44 -0
- package/dist/spec-complete.d.ts.map +1 -0
- package/dist/spec-complete.js +69 -0
- package/dist/spec-complete.js.map +1 -0
- package/dist/start.d.ts +97 -0
- package/dist/start.d.ts.map +1 -0
- package/dist/start.js +633 -0
- package/dist/start.js.map +1 -0
- package/dist/status.d.ts +199 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +228 -0
- package/dist/status.js.map +1 -0
- package/dist/surface-gate.d.ts +162 -0
- package/dist/surface-gate.d.ts.map +1 -0
- package/dist/surface-gate.js +206 -0
- package/dist/surface-gate.js.map +1 -0
- package/dist/surface-persist.d.ts +86 -0
- package/dist/surface-persist.d.ts.map +1 -0
- package/dist/surface-persist.js +129 -0
- package/dist/surface-persist.js.map +1 -0
- package/dist/tasker-review-loop.d.ts +249 -0
- package/dist/tasker-review-loop.d.ts.map +1 -0
- package/dist/tasker-review-loop.js +369 -0
- package/dist/tasker-review-loop.js.map +1 -0
- package/dist/tasking-eligibility.d.ts +74 -0
- package/dist/tasking-eligibility.d.ts.map +1 -0
- package/dist/tasking-eligibility.js +52 -0
- package/dist/tasking-eligibility.js.map +1 -0
- package/dist/tasking-lock.d.ts +111 -0
- package/dist/tasking-lock.d.ts.map +1 -0
- package/dist/tasking-lock.js +256 -0
- package/dist/tasking-lock.js.map +1 -0
- package/dist/tasking.d.ts +275 -0
- package/dist/tasking.d.ts.map +1 -0
- package/dist/tasking.js +951 -0
- package/dist/tasking.js.map +1 -0
- package/dist/triage-gate.d.ts +127 -0
- package/dist/triage-gate.d.ts.map +1 -0
- package/dist/triage-gate.js +139 -0
- package/dist/triage-gate.js.map +1 -0
- package/dist/triage-persist.d.ts +163 -0
- package/dist/triage-persist.d.ts.map +1 -0
- package/dist/triage-persist.js +387 -0
- package/dist/triage-persist.js.map +1 -0
- package/dist/verdict-json.d.ts +32 -0
- package/dist/verdict-json.d.ts.map +1 -0
- package/dist/verdict-json.js +74 -0
- package/dist/verdict-json.js.map +1 -0
- package/dist/verify-workflow-template.d.ts +60 -0
- package/dist/verify-workflow-template.d.ts.map +1 -0
- package/dist/verify-workflow-template.js +126 -0
- package/dist/verify-workflow-template.js.map +1 -0
- package/dist/verify.d.ts +60 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +62 -0
- package/dist/verify.js.map +1 -0
- package/dist/watch-session.d.ts +112 -0
- package/dist/watch-session.d.ts.map +1 -0
- package/dist/watch-session.js +347 -0
- package/dist/watch-session.js.map +1 -0
- package/dist/work-layout.d.ts +198 -0
- package/dist/work-layout.d.ts.map +1 -0
- package/dist/work-layout.js +217 -0
- package/dist/work-layout.js.map +1 -0
- package/dist/work-on.d.ts +154 -0
- package/dist/work-on.d.ts.map +1 -0
- package/dist/work-on.js +387 -0
- package/dist/work-on.js.map +1 -0
- package/dist/workspace.d.ts +224 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +325 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +46 -2
- package/src/advance-ci-template.ts +203 -0
- package/src/advance-classify.ts +197 -0
- package/src/advance-drivers.ts +414 -0
- package/src/advance-isolated.ts +432 -0
- package/src/advance-lifecycle-template.ts +791 -0
- package/src/advance-loop-driver.ts +745 -0
- package/src/advance-treeless-publish.ts +177 -0
- package/src/advance.ts +1564 -0
- package/src/advancing-lock.ts +988 -0
- package/src/agent-launch.ts +137 -0
- package/src/agent-stop.ts +361 -0
- package/src/apply-decide.ts +242 -0
- package/src/apply-merge-action.ts +502 -0
- package/src/apply-persist.ts +518 -0
- package/src/arbiter.ts +372 -0
- package/src/brand.ts +111 -0
- package/src/buildable-body.ts +196 -0
- package/src/categorise.ts +158 -0
- package/src/claim-cas.ts +513 -0
- package/src/cli-spinner.ts +225 -0
- package/src/cli.ts +4379 -0
- package/src/close-job-template.ts +236 -0
- package/src/close-job.ts +319 -0
- package/src/complete.ts +1379 -0
- package/src/concurrency.ts +151 -0
- package/src/config-override.ts +116 -0
- package/src/config.ts +883 -0
- package/src/continue-branch.ts +542 -0
- package/src/cwd-section.ts +392 -0
- package/src/decision-engine.ts +272 -0
- package/src/detect.ts +124 -0
- package/src/do-autopick.ts +223 -0
- package/src/do-config.ts +589 -0
- package/src/do-remote-auto.ts +197 -0
- package/src/do.ts +2623 -0
- package/src/drop-source.ts +194 -0
- package/src/eligibility.ts +79 -0
- package/src/env-config.ts +305 -0
- package/src/failure-cause.ts +142 -0
- package/src/format.ts +313 -0
- package/src/frontmatter.ts +477 -0
- package/src/gate-readiness.ts +147 -0
- package/src/gc.ts +510 -0
- package/src/gh-failure.ts +53 -0
- package/src/git.ts +186 -0
- package/src/github.ts +468 -0
- package/src/harness.ts +355 -0
- package/src/identity.ts +322 -0
- package/src/index.ts +785 -0
- package/src/install-ci-branch-protection.ts +255 -0
- package/src/install-ci-capabilities/advance-lifecycle.ts +34 -0
- package/src/install-ci-capabilities/close-job.ts +32 -0
- package/src/install-ci-capabilities/example-noop.ts +24 -0
- package/src/install-ci-capabilities/intake.ts +34 -0
- package/src/install-ci-capabilities/verify.ts +33 -0
- package/src/install-ci-core.ts +1088 -0
- package/src/install-ci-github.ts +376 -0
- package/src/install-ci.ts +552 -0
- package/src/intake-event.ts +102 -0
- package/src/intake-marker.ts +195 -0
- package/src/intake-triage.ts +138 -0
- package/src/intake-trigger-template.ts +591 -0
- package/src/intake.ts +2445 -0
- package/src/integration-core.ts +3065 -0
- package/src/integrator.ts +771 -0
- package/src/isolation.ts +484 -0
- package/src/issue-provider.ts +733 -0
- package/src/item-lock.ts +1858 -0
- package/src/item-path.ts +75 -0
- package/src/ledger-lint.ts +332 -0
- package/src/ledger-read.ts +924 -0
- package/src/ledger-write.ts +865 -0
- package/src/lifecycle-gather.ts +298 -0
- package/src/lifecycle-pools.ts +250 -0
- package/src/merge-question-surfacer.ts +496 -0
- package/src/mint-adr.ts +362 -0
- package/src/mirror-pool-scan.ts +240 -0
- package/src/needs-attention.ts +1506 -0
- package/src/orphan-sidecar.ts +150 -0
- package/src/output.ts +89 -0
- package/src/pi-harness.ts +403 -0
- package/src/placement.ts +131 -0
- package/src/prd-to-spec.ts +1059 -0
- package/src/prepare.ts +230 -0
- package/src/prompt.ts +763 -0
- package/src/readiness.ts +98 -0
- package/src/reap-branches.ts +278 -0
- package/src/recover-isolated.ts +276 -0
- package/src/registry.ts +475 -0
- package/src/repo-config.ts +550 -0
- package/src/repo-key.ts +74 -0
- package/src/repo-mirror.ts +367 -0
- package/src/retry-backoff.ts +130 -0
- package/src/review-gate.ts +389 -0
- package/src/review-verdict.ts +422 -0
- package/src/run.ts +1430 -0
- package/src/scan.ts +611 -0
- package/src/select-order.ts +143 -0
- package/src/select-priority.ts +266 -0
- package/src/select.ts +62 -0
- package/src/session-path.ts +153 -0
- package/src/sidecar-apply.ts +216 -0
- package/src/sidecar.ts +700 -0
- package/src/slug-namespace.ts +367 -0
- package/src/spec-complete.ts +118 -0
- package/src/start.ts +974 -0
- package/src/status.ts +441 -0
- package/src/surface-gate.ts +337 -0
- package/src/surface-persist.ts +241 -0
- package/src/tasker-review-loop.ts +671 -0
- package/src/tasking-eligibility.ts +114 -0
- package/src/tasking-lock.ts +416 -0
- package/src/tasking.ts +1437 -0
- package/src/triage-gate.ts +248 -0
- package/src/triage-persist.ts +570 -0
- package/src/verdict-json.ts +73 -0
- package/src/verify-workflow-template.ts +159 -0
- package/src/verify.ts +123 -0
- package/src/watch-session.ts +397 -0
- package/src/work-layout.ts +262 -0
- package/src/work-on.ts +660 -0
- package/src/workspace.ts +502 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure categorisation of backlog items into the "who can take it" groups used by
|
|
3
|
+
* the human decision dashboard. Grouping is deliberately INDEPENDENT of the
|
|
4
|
+
* repo's `autoBuild` policy: a human always sees the full picture, and the
|
|
5
|
+
* policy only changes the eligibility *verdict* / summary counts elsewhere —
|
|
6
|
+
* never which group an item lands in.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {ScannedItem} from './scan.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Which group an item belongs to, derived from its two autonomy axes
|
|
13
|
+
* (`humanOnly`, `needsAnswers`) and its dependency readiness (NOT the runner's
|
|
14
|
+
* `autoBuild` policy):
|
|
15
|
+
* - `agent-claimable` — neither axis gated AND deps satisfied: an agent can
|
|
16
|
+
* claim it now (provided this repo's `autoBuild` policy is on).
|
|
17
|
+
* - `human-only` — `humanOnly: true`: a human decides/builds it; an agent never
|
|
18
|
+
* claims it, regardless of policy or deps.
|
|
19
|
+
* - `needs-answers` — not `humanOnly` but `needsAnswers: true`: open questions
|
|
20
|
+
* block autonomous work until they are answered (the questions live in the
|
|
21
|
+
* body); an agent never claims it.
|
|
22
|
+
* - `blocked` — neither axis gated but deps unsatisfied: would be
|
|
23
|
+
* agent-claimable once its blockers reach `work/done/`.
|
|
24
|
+
*
|
|
25
|
+
* `humanOnly` takes precedence over `needsAnswers` for display grouping (a single
|
|
26
|
+
* group per item), but BOTH gate the agent identically in `eligibility`.
|
|
27
|
+
*/
|
|
28
|
+
export type Category =
|
|
29
|
+
| 'agent-claimable'
|
|
30
|
+
| 'human-only'
|
|
31
|
+
| 'needs-answers'
|
|
32
|
+
| 'blocked';
|
|
33
|
+
|
|
34
|
+
/** Stable display order for the four groups. */
|
|
35
|
+
export const CATEGORY_ORDER: Category[] = [
|
|
36
|
+
'agent-claimable',
|
|
37
|
+
'human-only',
|
|
38
|
+
'needs-answers',
|
|
39
|
+
'blocked',
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
/** Human-facing section headings for each group. */
|
|
43
|
+
export const CATEGORY_LABELS: Record<Category, string> = {
|
|
44
|
+
'agent-claimable':
|
|
45
|
+
'Agent-claimable now (not human-only, no open questions, deps satisfied; needs --auto-build)',
|
|
46
|
+
'human-only': 'Human-only (humanOnly: true — a human decides/builds)',
|
|
47
|
+
'needs-answers':
|
|
48
|
+
'Needs answers (needsAnswers: true — open questions block autonomous work)',
|
|
49
|
+
blocked: 'Blocked (not gated, waiting on deps)',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** A scanned item, classified for the dashboard. */
|
|
53
|
+
export interface CategorisedItem {
|
|
54
|
+
item: ScannedItem;
|
|
55
|
+
category: Category;
|
|
56
|
+
/** Whether its `blockedBy` deps are all satisfied (ready to be picked up). */
|
|
57
|
+
ready: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Map an item's autonomy axes (`humanOnly`, `needsAnswers`) + dependency
|
|
62
|
+
* readiness to its dashboard category. Policy-independent by design: the
|
|
63
|
+
* category reflects what the author declared and whether its deps are met, not
|
|
64
|
+
* the runner's `autoBuild` policy. `humanOnly` is shown before `needsAnswers`
|
|
65
|
+
* when both are set, so the REASON is always visible.
|
|
66
|
+
*/
|
|
67
|
+
export function categoriseItem(item: ScannedItem): CategorisedItem {
|
|
68
|
+
const ready = item.eligibility.blockedBy.satisfied;
|
|
69
|
+
let category: Category;
|
|
70
|
+
if (item.humanOnly === true) {
|
|
71
|
+
category = 'human-only';
|
|
72
|
+
} else if (item.needsAnswers === true) {
|
|
73
|
+
category = 'needs-answers';
|
|
74
|
+
} else if (ready) {
|
|
75
|
+
category = 'agent-claimable';
|
|
76
|
+
} else {
|
|
77
|
+
category = 'blocked';
|
|
78
|
+
}
|
|
79
|
+
return {item, category, ready};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The items of one repo, bucketed by category and sorted ready-first. */
|
|
83
|
+
export type CategorisedGroups = Record<Category, CategorisedItem[]>;
|
|
84
|
+
|
|
85
|
+
function emptyGroups(): CategorisedGroups {
|
|
86
|
+
return {
|
|
87
|
+
'agent-claimable': [],
|
|
88
|
+
'human-only': [],
|
|
89
|
+
'needs-answers': [],
|
|
90
|
+
blocked: [],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Bucket a repo's scanned items into the three groups. Within each group, ready
|
|
96
|
+
* (deps-satisfied) items sort above blocked ones; ties keep the incoming order
|
|
97
|
+
* (the scan core already sorts items by slug), so the result is deterministic.
|
|
98
|
+
*/
|
|
99
|
+
export function categoriseItems(items: ScannedItem[]): CategorisedGroups {
|
|
100
|
+
const groups = emptyGroups();
|
|
101
|
+
for (const item of items) {
|
|
102
|
+
const categorised = categoriseItem(item);
|
|
103
|
+
groups[categorised.category].push(categorised);
|
|
104
|
+
}
|
|
105
|
+
for (const category of CATEGORY_ORDER) {
|
|
106
|
+
groups[category] = sortReadyFirst(groups[category]);
|
|
107
|
+
}
|
|
108
|
+
return groups;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Stable sort placing ready items before blocked ones, preserving order otherwise. */
|
|
112
|
+
export function sortReadyFirst(items: CategorisedItem[]): CategorisedItem[] {
|
|
113
|
+
return items
|
|
114
|
+
.map((value, index) => ({value, index}))
|
|
115
|
+
.sort((a, b) => {
|
|
116
|
+
if (a.value.ready !== b.value.ready) {
|
|
117
|
+
return a.value.ready ? -1 : 1;
|
|
118
|
+
}
|
|
119
|
+
return a.index - b.index;
|
|
120
|
+
})
|
|
121
|
+
.map((entry) => entry.value);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Per-category and readiness tallies for the dashboard summary. */
|
|
125
|
+
export interface CategorySummary {
|
|
126
|
+
agentClaimable: number;
|
|
127
|
+
humanOnly: number;
|
|
128
|
+
needsAnswers: number;
|
|
129
|
+
blocked: number;
|
|
130
|
+
ready: number;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Aggregate counts across every repo's groups for the summary line. */
|
|
134
|
+
export function summariseGroups(
|
|
135
|
+
allGroups: CategorisedGroups[],
|
|
136
|
+
): CategorySummary {
|
|
137
|
+
const summary: CategorySummary = {
|
|
138
|
+
agentClaimable: 0,
|
|
139
|
+
humanOnly: 0,
|
|
140
|
+
needsAnswers: 0,
|
|
141
|
+
blocked: 0,
|
|
142
|
+
ready: 0,
|
|
143
|
+
};
|
|
144
|
+
for (const groups of allGroups) {
|
|
145
|
+
summary.agentClaimable += groups['agent-claimable'].length;
|
|
146
|
+
summary.humanOnly += groups['human-only'].length;
|
|
147
|
+
summary.needsAnswers += groups['needs-answers'].length;
|
|
148
|
+
summary.blocked += groups['blocked'].length;
|
|
149
|
+
for (const category of CATEGORY_ORDER) {
|
|
150
|
+
for (const entry of groups[category]) {
|
|
151
|
+
if (entry.ready) {
|
|
152
|
+
summary.ready++;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return summary;
|
|
158
|
+
}
|
package/src/claim-cas.ts
ADDED
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
import {runAsync, type RunResult} from './git.js';
|
|
2
|
+
import {acquireItemLock, releaseItemLock, heldTaskSlugs} from './item-lock.js';
|
|
3
|
+
import {extractPromptSection} from './prompt.js';
|
|
4
|
+
import {resolveReadiness} from './readiness.js';
|
|
5
|
+
import {workBranchRef} from './slug-namespace.js';
|
|
6
|
+
import {workItemRel} from './work-layout.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* In-process TypeScript implementation of the atomic compare-and-swap claim from
|
|
10
|
+
* `scripts/CLAIM-PROTOCOL.md`. This is the first-class `dorfl claim`
|
|
11
|
+
* command (ADR §9: dorfl is the PRIMARY implementation of the claim
|
|
12
|
+
* protocol; `scripts/claim.sh` is retained as the portable, zero-dependency
|
|
13
|
+
* bootstrap / reference). The lock-substrate cut-over (prd
|
|
14
|
+
* `ledger-status-per-item-lock-refs`) has since diverged it from `claim.sh`'s
|
|
15
|
+
* body-move semantics — see the lock note below — but the exit codes are the same.
|
|
16
|
+
*
|
|
17
|
+
* It is async (each git call is a non-blocking `runAsync`) so two awaited claims
|
|
18
|
+
* over the same slug genuinely race — the arbiter's per-item-ref CAS (not test
|
|
19
|
+
* ordering) picks the single winner.
|
|
20
|
+
*
|
|
21
|
+
* Exit codes:
|
|
22
|
+
* 0 claim landed (the per-item lock is held; the body stays where it rested:
|
|
23
|
+
* `tasks/ready/` normally, or `tasks/backlog/` under --allow-backlog)
|
|
24
|
+
* 1 usage / environment error, or a readiness REFUSAL (unmet blockedBy)
|
|
25
|
+
* 2 item not claimable (not in backlog, or lost the lock race to someone else)
|
|
26
|
+
* 3 (legacy) push contention — no longer reachable: the per-item lock never
|
|
27
|
+
* falsely contends, so there is no retry budget to exhaust
|
|
28
|
+
*
|
|
29
|
+
* UNIFIED PER-ITEM LOCK (prd `ledger-status-per-item-lock-refs` US #1/#15/#16,
|
|
30
|
+
* ADR `ledger-status-on-per-item-lock-refs`): a claim ACQUIRES the item's
|
|
31
|
+
* per-item lock (`action: implement`) via the lock module and writes NOTHING to
|
|
32
|
+
* `main` — the body STAYS at `work/backlog/<slug>.md`. The claimable predicate is
|
|
33
|
+
* "in `backlog/` on `main` AND no lock held"; the held lock IS the claim. The lock
|
|
34
|
+
* is acquired FIRST, so a lock `lost` (the SAME item is already locked) makes the
|
|
35
|
+
* claim lose definitively (exit 2, NO retry budget). A subsequent claimability
|
|
36
|
+
* re-check (the body left `backlog/`) RELEASES the lock (never orphaned). Because
|
|
37
|
+
* claim touches no `main` (and no protected ref), a protected-`main` repo CAN be
|
|
38
|
+
* claimed. The interim dual-write (`git mv backlog→in-progress` + a `main` claim
|
|
39
|
+
* commit) is GONE.
|
|
40
|
+
*
|
|
41
|
+
* Before the claim runs, the HUMAN path's readiness guard (resolveReadiness) is
|
|
42
|
+
* applied: a task with an unmet `blockedBy` is REFUSED (exit 1, outcome
|
|
43
|
+
* 'not-ready') unless overridden; a `needsAnswers: true` task is WARNED about
|
|
44
|
+
* but still claimed. The autonomous runner does NOT pass `humanPath`, so its
|
|
45
|
+
* behaviour is unchanged (eligibility already filters those items upstream).
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/** Maps onto the four claim.sh exit codes. */
|
|
49
|
+
export type ClaimExitCode = 0 | 1 | 2 | 3;
|
|
50
|
+
|
|
51
|
+
/** A semantic label for each exit code (for callers/tests, never the verdict). */
|
|
52
|
+
export type ClaimCasOutcome =
|
|
53
|
+
| 'claimed'
|
|
54
|
+
| 'usage-error'
|
|
55
|
+
| 'lost'
|
|
56
|
+
| 'contended'
|
|
57
|
+
| 'not-ready';
|
|
58
|
+
|
|
59
|
+
export interface ClaimCasOptions {
|
|
60
|
+
/** The slug to claim (`work/backlog/<slug>.md`). */
|
|
61
|
+
slug: string;
|
|
62
|
+
/** Working clone/worktree the claim runs in. */
|
|
63
|
+
cwd: string;
|
|
64
|
+
/** Name of the arbiter remote (`--arbiter`). Defaults to `origin`. */
|
|
65
|
+
arbiter?: string;
|
|
66
|
+
/**
|
|
67
|
+
* (LEGACY, accepted-but-ignored) Cap on push retries when main merely advanced.
|
|
68
|
+
* The per-item lock never falsely contends (a per-item ref CAS is self-arbitrating),
|
|
69
|
+
* so there is no retry loop and nothing to bound. Kept on the option shape so
|
|
70
|
+
* existing callers/tests that pass `--retries` keep type-checking; it has NO effect.
|
|
71
|
+
*/
|
|
72
|
+
retries?: number;
|
|
73
|
+
/** Show the intended push without mutating the arbiter (`--dry-run`). */
|
|
74
|
+
dryRun?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Apply the human-path readiness guard before the CAS: refuse an unmet
|
|
77
|
+
* `blockedBy`, warn on `needsAnswers`. The HUMAN `claim`/`start` path sets
|
|
78
|
+
* this; the autonomous runner leaves it off (it filters upstream via
|
|
79
|
+
* eligibility and must NOT change behaviour here).
|
|
80
|
+
*/
|
|
81
|
+
humanPath?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Override flag (`--force` / `--ignore-not-ready`): bypass the readiness
|
|
84
|
+
* refusal and silence the `needsAnswers` warning, printing a loud notice that
|
|
85
|
+
* the guard was overridden. Only meaningful with `humanPath`.
|
|
86
|
+
*/
|
|
87
|
+
override?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* `--allow-backlog` (prd
|
|
90
|
+
* `do-allow-backlog-drive-staged-tasks-without-promotion`): WIDEN the claimable
|
|
91
|
+
* predicate to ALSO accept a `tasks/backlog/`-resident body (staging), so a
|
|
92
|
+
* human can drive a staged task in place WITHOUT promoting it to the pool. The
|
|
93
|
+
* claim STAYS a pure per-item-lock acquire \u2014 it writes NOTHING to `main` and
|
|
94
|
+
* does NOT `git mv` the body (the body stays in `tasks/backlog/`). Competitor
|
|
95
|
+
* exclusion is the HELD LOCK (the pool scan subtracts held slugs folder-
|
|
96
|
+
* agnostically), not the folder, so no move is needed. Default off \u21d2 the
|
|
97
|
+
* predicate is "in `tasks/ready/` on `main` AND no lock held" exactly as today;
|
|
98
|
+
* reachable ONLY via the explicit flag, never `run`/auto-pick/advance.
|
|
99
|
+
*/
|
|
100
|
+
allowBacklog?: boolean;
|
|
101
|
+
/** Environment for child git processes (identity etc.). */
|
|
102
|
+
env?: NodeJS.ProcessEnv;
|
|
103
|
+
/** Sink for human-readable progress notes (claim.sh writes these to stderr). */
|
|
104
|
+
note?: (message: string) => void;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface ClaimCasResult {
|
|
108
|
+
exitCode: ClaimExitCode;
|
|
109
|
+
outcome: ClaimCasOutcome;
|
|
110
|
+
/** Human-readable summary of the terminal condition. */
|
|
111
|
+
message: string;
|
|
112
|
+
/**
|
|
113
|
+
* (RETAINED for the option shape; now ALWAYS absent.) Historically the sha of
|
|
114
|
+
* the CLAIM COMMIT that landed on `main`, used by in-place onboarding to branch
|
|
115
|
+
* the work branch off the exact claim commit. The lock-substrate claim writes
|
|
116
|
+
* NOTHING to `main` (the body stays where it rested — `tasks/ready/` normally,
|
|
117
|
+
* or `tasks/backlog/` under --allow-backlog), so there is no claim
|
|
118
|
+
* commit — onboarding cuts the work branch straight off `<arbiter>/main` (which
|
|
119
|
+
* carries the backlog body). Kept on the result shape so existing readers
|
|
120
|
+
* (`do.ts` threads `claim.claimCommit` into onboarding) keep type-checking; an
|
|
121
|
+
* `undefined` value drives onboarding's fresh-off-`<arbiter>/main` branch path.
|
|
122
|
+
*/
|
|
123
|
+
claimCommit?: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The "lost" diagnostic for a held-lock loss, reused so its message carries the
|
|
128
|
+
* recovery hints a human re-running their OWN item needs. The body now STAYS in
|
|
129
|
+
* `work/backlog/` (claim never moves it), so a held item is identified by its LOCK
|
|
130
|
+
* (`action: implement` held on the per-item ref), not an `in-progress/` folder: a
|
|
131
|
+
* held lock + the body still in `backlog/` is the normal claimed state. We fetch
|
|
132
|
+
* the lock refs and, when the slug's lock is held, surface the resume/requeue
|
|
133
|
+
* recovery hints; otherwise (the body left `backlog/` entirely — done/removed) we
|
|
134
|
+
* fall back to the generic message.
|
|
135
|
+
*/
|
|
136
|
+
async function lostMessage(
|
|
137
|
+
slug: string,
|
|
138
|
+
arbiter: string,
|
|
139
|
+
cwd: string,
|
|
140
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
141
|
+
fallback: string,
|
|
142
|
+
): Promise<string> {
|
|
143
|
+
const held = await heldTaskSlugs(cwd, arbiter, env);
|
|
144
|
+
if (held.has(slug)) {
|
|
145
|
+
return `'${slug}' is already claimed on ${arbiter}/main (its per-item lock is held). If someone else claimed it, pick another item; if it's your own (e.g. an interrupted run), continue it with \`dorfl resume ${slug}\` (or \`work-on\`), or recover via \`requeue\`.`;
|
|
146
|
+
}
|
|
147
|
+
return fallback;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Raised for usage/environment errors (exit 1). */
|
|
151
|
+
class ClaimUsageError extends Error {}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Raised for a deliberate readiness REFUSAL (exit 1, outcome 'not-ready') —
|
|
155
|
+
* distinct from a usage/environment error. The task has an unmet `blockedBy`
|
|
156
|
+
* and the override was not supplied, so nothing is claimed.
|
|
157
|
+
*/
|
|
158
|
+
class ClaimNotReady extends Error {}
|
|
159
|
+
|
|
160
|
+
const DEFAULT_ARBITER = 'origin';
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Perform the claim CAS. Never throws for the expected "lost the race" or
|
|
164
|
+
* "contended" cases — those are returned as exit 2 / 3. Usage/environment
|
|
165
|
+
* problems surface as exit 1. A successful claim is exit 0. This mirrors
|
|
166
|
+
* claim.sh's control flow exactly (refuse dirty tree → loop attempts → on
|
|
167
|
+
* rejection refetch & decide lost-vs-advanced → cap retries → back off).
|
|
168
|
+
*/
|
|
169
|
+
export async function performClaim(
|
|
170
|
+
options: ClaimCasOptions,
|
|
171
|
+
): Promise<ClaimCasResult> {
|
|
172
|
+
const note = options.note ?? (() => {});
|
|
173
|
+
try {
|
|
174
|
+
return await runClaim(options, note);
|
|
175
|
+
} catch (err) {
|
|
176
|
+
if (err instanceof ClaimNotReady) {
|
|
177
|
+
return {exitCode: 1, outcome: 'not-ready', message: err.message};
|
|
178
|
+
}
|
|
179
|
+
if (err instanceof ClaimUsageError) {
|
|
180
|
+
return {exitCode: 1, outcome: 'usage-error', message: err.message};
|
|
181
|
+
}
|
|
182
|
+
// Any other unexpected failure is an environment error (exit 1), never a
|
|
183
|
+
// false "claimed". claim.sh treats unexpected rc the same way (die → 1).
|
|
184
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
185
|
+
return {exitCode: 1, outcome: 'usage-error', message};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function runClaim(
|
|
190
|
+
options: ClaimCasOptions,
|
|
191
|
+
note: (m: string) => void,
|
|
192
|
+
): Promise<ClaimCasResult> {
|
|
193
|
+
const slug = options.slug;
|
|
194
|
+
const arbiter = options.arbiter ?? DEFAULT_ARBITER;
|
|
195
|
+
const dryRun = options.dryRun ?? false;
|
|
196
|
+
const cwd = options.cwd;
|
|
197
|
+
const env = options.env;
|
|
198
|
+
|
|
199
|
+
if (!slug) {
|
|
200
|
+
throw new ClaimUsageError(
|
|
201
|
+
'missing <slug>. usage: dorfl claim <slug> [--arbiter remote]',
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
if ((await gitSoft(['rev-parse', '--git-dir'], cwd, env)).status !== 0) {
|
|
205
|
+
throw new ClaimUsageError('not inside a git repository');
|
|
206
|
+
}
|
|
207
|
+
if ((await gitSoft(['remote', 'get-url', arbiter], cwd, env)).status !== 0) {
|
|
208
|
+
throw new ClaimUsageError(
|
|
209
|
+
`no git remote named '${arbiter}' (set one, or pass --arbiter)`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Refuse to run with a dirty tree — the claim must be a clean, isolated commit.
|
|
214
|
+
const dirtyWorktree =
|
|
215
|
+
(await gitSoft(['diff', '--quiet'], cwd, env)).status !== 0;
|
|
216
|
+
const dirtyIndex =
|
|
217
|
+
(await gitSoft(['diff', '--cached', '--quiet'], cwd, env)).status !== 0;
|
|
218
|
+
if (dirtyWorktree || dirtyIndex) {
|
|
219
|
+
throw new ClaimUsageError(
|
|
220
|
+
'working tree has uncommitted changes; commit/stash them before claiming',
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// HUMAN-path readiness guard (run BEFORE the CAS so a not-ready task is never
|
|
225
|
+
// claimed). Reads the task frontmatter + `work/done/` from `<arbiter>/main`
|
|
226
|
+
// (the same source of truth the folder check uses) and resolves `blockedBy`
|
|
227
|
+
// via the shared resolveBlockedBy. Skipped entirely for the autonomous runner
|
|
228
|
+
// (no `humanPath`), whose eligibility filter already handles these upstream.
|
|
229
|
+
if (options.humanPath) {
|
|
230
|
+
await gitHard(['fetch', '--quiet', arbiter], cwd, env);
|
|
231
|
+
const readiness = await resolveReadiness({
|
|
232
|
+
slug,
|
|
233
|
+
cwd,
|
|
234
|
+
arbiter,
|
|
235
|
+
override: options.override === true,
|
|
236
|
+
env,
|
|
237
|
+
});
|
|
238
|
+
if (readiness.refuse) {
|
|
239
|
+
const missing = readiness.missing.join(', ');
|
|
240
|
+
const message =
|
|
241
|
+
`'${slug}' is not ready: blocked by unmet dependencies not yet in ` +
|
|
242
|
+
`work/done/ on ${arbiter}/main: ${missing}. ` +
|
|
243
|
+
'Re-run with --force (or --ignore-not-ready) to claim it anyway.';
|
|
244
|
+
note(message);
|
|
245
|
+
throw new ClaimNotReady(message);
|
|
246
|
+
}
|
|
247
|
+
if (readiness.overridden && readiness.missing.length > 0) {
|
|
248
|
+
note(
|
|
249
|
+
`!! readiness guard OVERRIDDEN: claiming '${slug}' despite unmet ` +
|
|
250
|
+
`blockedBy: ${readiness.missing.join(', ')} (not yet in work/done/).`,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
if (readiness.needsAnswers && !readiness.overridden) {
|
|
254
|
+
note(
|
|
255
|
+
`!! WARNING: '${slug}' is flagged needsAnswers: true — it has open ` +
|
|
256
|
+
'questions (see the task body). Claiming it anyway (human path); ' +
|
|
257
|
+
'resolve the questions before/while building.',
|
|
258
|
+
);
|
|
259
|
+
} else if (readiness.needsAnswers && readiness.overridden) {
|
|
260
|
+
note(
|
|
261
|
+
`!! readiness guard OVERRIDDEN: silencing the needsAnswers warning for '${slug}'.`,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const backlog = workItemRel('tasks-ready', `${slug}.md`);
|
|
267
|
+
const staged = workItemRel('tasks-backlog', `${slug}.md`);
|
|
268
|
+
const branch = workBranchRef('task', slug);
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* The CLAIMABLE-RESIDENCE half of the predicate: the body rests in the pool
|
|
272
|
+
* (`tasks/ready/`) on `<arbiter>/main`, OR \u2014 under `--allow-backlog` \u2014 in
|
|
273
|
+
* `tasks/backlog/` (staging). The held-lock half is the create-only acquire.
|
|
274
|
+
* Folder-agnostic exclusion is the lock, never the folder, so a staged body is
|
|
275
|
+
* a legitimate claimable residence under the flag; otherwise staging is invisible.
|
|
276
|
+
*/
|
|
277
|
+
async function claimableBodyRel(): Promise<string | undefined> {
|
|
278
|
+
if (await catFileExists(`${arbiter}/main:${backlog}`, cwd, env)) {
|
|
279
|
+
return backlog;
|
|
280
|
+
}
|
|
281
|
+
if (
|
|
282
|
+
options.allowBacklog === true &&
|
|
283
|
+
(await catFileExists(`${arbiter}/main:${staged}`, cwd, env))
|
|
284
|
+
) {
|
|
285
|
+
return staged;
|
|
286
|
+
}
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
async function bodyRestsClaimable(): Promise<boolean> {
|
|
290
|
+
return (await claimableBodyRel()) !== undefined;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* The human-facing folder label for a resolved claimable body path (`work/<dir>`,
|
|
295
|
+
* e.g. `work/tasks/ready` or `work/tasks/backlog`). Derived from the ACTUAL
|
|
296
|
+
* resolved residence so the claim message never hard-codes the wrong folder.
|
|
297
|
+
*/
|
|
298
|
+
function residenceFolder(bodyRel: string): string {
|
|
299
|
+
const dir = bodyRel.slice(0, bodyRel.lastIndexOf('/'));
|
|
300
|
+
return dir === '' ? bodyRel : dir;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* PRE-CLAIM WELL-FORMEDNESS GUARD (this task's interim guard against the
|
|
305
|
+
* promptless-promoted-task strand). The validator `resolveTask` /
|
|
306
|
+
* `extractPromptSection` (`prompt.ts`) requires a task body to carry a
|
|
307
|
+
* `## Prompt` section; it runs at DISPATCH (`do.ts` step 5), AFTER the claim,
|
|
308
|
+
* so a body missing `## Prompt` was caught only post-claim — the failure routed
|
|
309
|
+
* to `saveAgentFailure`, which left the lock `state: stuck`. We run the SAME
|
|
310
|
+
* validator (`extractPromptSection`, the single source of truth for "what makes
|
|
311
|
+
* a task dispatchable") HERE, BEFORE the lock is acquired, so a malformed body
|
|
312
|
+
* from ANY source (promotion, hand-authored, externally edited) is refused with a
|
|
313
|
+
* clean usage error and NO lock is taken. `bodyRel` is the resolved claimable
|
|
314
|
+
* residence (`tasks/ready/` or, under the flag, `tasks/backlog/`). A genuinely
|
|
315
|
+
* absent body is NOT this guard's concern (the claimability check returns `lost`
|
|
316
|
+
* separately) — this only fires when a body that DOES rest claimable lacks a
|
|
317
|
+
* `## Prompt`.
|
|
318
|
+
*/
|
|
319
|
+
async function assertBodyWellFormed(bodyRel: string): Promise<void> {
|
|
320
|
+
const show = await gitSoft(
|
|
321
|
+
['show', `${arbiter}/main:${bodyRel}`],
|
|
322
|
+
cwd,
|
|
323
|
+
env,
|
|
324
|
+
);
|
|
325
|
+
if (show.status !== 0) {
|
|
326
|
+
// The body vanished between the residence check and this read — leave it to
|
|
327
|
+
// the claimability path to report `lost`; do not synthesise a guard error.
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (extractPromptSection(show.stdout) === undefined) {
|
|
331
|
+
throw new ClaimUsageError(
|
|
332
|
+
`'${slug}' (${bodyRel}) has no '## Prompt' section, so it is not ` +
|
|
333
|
+
'dispatchable — add a `## Prompt` section to the task body before ' +
|
|
334
|
+
'claiming it. NO lock was acquired.',
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// UNIFIED PER-ITEM LOCK — the WHOLE of the claim now (prd
|
|
340
|
+
// `ledger-status-per-item-lock-refs` US #1/#15/#16; ADR
|
|
341
|
+
// `ledger-status-on-per-item-lock-refs`). The interim dual-write is GONE: claim
|
|
342
|
+
// acquires the item's per-item lock (`action: implement`) and writes NOTHING to
|
|
343
|
+
// `main` — the body STAYS at `work/backlog/<slug>.md`, the claimable predicate is
|
|
344
|
+
// "in `backlog/` on `main` AND no lock held", and the held lock IS the claim. So
|
|
345
|
+
// a protected-`main` repo can be claimed (claim touches no protected ref).
|
|
346
|
+
//
|
|
347
|
+
// A dry-run takes no lock (it mutates nothing) and just reports it WOULD claim.
|
|
348
|
+
/** The not-found diagnostic, naming the pool (and staging under the flag). */
|
|
349
|
+
const notFoundFallback =
|
|
350
|
+
options.allowBacklog === true
|
|
351
|
+
? `neither '${backlog}' nor '${staged}' found on ${arbiter}/main (already done/removed, or wrong slug).`
|
|
352
|
+
: `'${backlog}' not found on ${arbiter}/main (already done/removed, or wrong slug).`;
|
|
353
|
+
|
|
354
|
+
if (dryRun) {
|
|
355
|
+
await gitHard(['fetch', '--quiet', arbiter], cwd, env);
|
|
356
|
+
const bodyRel = await claimableBodyRel();
|
|
357
|
+
if (bodyRel === undefined) {
|
|
358
|
+
const message = await lostMessage(
|
|
359
|
+
slug,
|
|
360
|
+
arbiter,
|
|
361
|
+
cwd,
|
|
362
|
+
env,
|
|
363
|
+
notFoundFallback,
|
|
364
|
+
);
|
|
365
|
+
note(message);
|
|
366
|
+
return {exitCode: 2, outcome: 'lost', message};
|
|
367
|
+
}
|
|
368
|
+
// A dry-run still runs the pre-claim well-formedness guard so it reports a
|
|
369
|
+
// promptless body as a usage error rather than "would claim" it.
|
|
370
|
+
await assertBodyWellFormed(bodyRel);
|
|
371
|
+
const message = `DRY-RUN: would acquire the per-item lock for '${slug}' (body stays in ${residenceFolder(bodyRel)}/).`;
|
|
372
|
+
note(message);
|
|
373
|
+
return {exitCode: 0, outcome: 'claimed', message};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// PRE-CLAIM WELL-FORMEDNESS GUARD: fetch + read the claimable body and refuse a
|
|
377
|
+
// task missing its `## Prompt` BEFORE the lock is acquired (so a malformed body
|
|
378
|
+
// never strands a `state: stuck` lock at dispatch). A genuinely absent body is
|
|
379
|
+
// left to the post-lock claimability re-check to report as `lost`; this guard
|
|
380
|
+
// only fires for a body that DOES rest claimable but is not dispatchable.
|
|
381
|
+
await gitHard(['fetch', '--quiet', arbiter], cwd, env);
|
|
382
|
+
{
|
|
383
|
+
const bodyRel = await claimableBodyRel();
|
|
384
|
+
if (bodyRel !== undefined) {
|
|
385
|
+
await assertBodyWellFormed(bodyRel);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Acquire the lock FIRST. A lock `lost` (someone already holds this SAME item's
|
|
390
|
+
// lock) makes claim lose DEFINITIVELY — exit 2, NO retry budget (a per-item ref
|
|
391
|
+
// never falsely contends, so a rejection is a GENUINE same-item conflict the
|
|
392
|
+
// loser should lose). We do NOT try to tell "our own orphaned lock" apart by
|
|
393
|
+
// holder identity and auto-reclaim it: holder ids are NOT unique (a CI bot claims
|
|
394
|
+
// many items under one `user.name`), so a release+re-acquire "reclaim" could let a
|
|
395
|
+
// concurrent LOSER release the WINNER's still-valid lock — and an automatic sweep
|
|
396
|
+
// contradicts the ADR's recovery model (`ledger-status-on-per-item-lock-refs`:
|
|
397
|
+
// "no liveness heartbeat, no auto-sweep; a human asserts a lock is dead"). A
|
|
398
|
+
// genuinely orphaned lock is cleared by the human-mediated `release-lock` verb +
|
|
399
|
+
// `gc --ledger` report, never an auto-steal at claim time.
|
|
400
|
+
const lock = await acquireItemLock({
|
|
401
|
+
item: `task:${slug}`,
|
|
402
|
+
action: 'implement',
|
|
403
|
+
cwd,
|
|
404
|
+
arbiter,
|
|
405
|
+
env,
|
|
406
|
+
});
|
|
407
|
+
if (lock.outcome === 'error') {
|
|
408
|
+
// Environment/usage problem acquiring the lock — surface as exit 1, never a
|
|
409
|
+
// false claim. Nothing was acquired.
|
|
410
|
+
throw new ClaimUsageError(
|
|
411
|
+
`failed to acquire the item lock for '${slug}': ${lock.message}`,
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
if (lock.outcome === 'lost') {
|
|
415
|
+
const message = await lostMessage(slug, arbiter, cwd, env, lock.message);
|
|
416
|
+
note(message);
|
|
417
|
+
return {exitCode: 2, outcome: 'lost', message};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/** Release the lock we just acquired (best-effort) — used when the claimability
|
|
421
|
+
* re-check finds the item is no longer in the pool, so the lock is never
|
|
422
|
+
* orphaned (the body never moved, so the item is cleanly returned to the pool). */
|
|
423
|
+
async function releaseHeldLock(): Promise<void> {
|
|
424
|
+
await releaseItemLock({item: `task:${slug}`, cwd, arbiter, env});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// The RESOLVED claimable residence (`tasks/ready/` or, under `--allow-backlog`,
|
|
428
|
+
// `tasks/backlog/`), captured by the post-lock claimability re-check below so the
|
|
429
|
+
// success message reports the real folder rather than a hard-coded guess.
|
|
430
|
+
let claimedBodyRel: string | undefined;
|
|
431
|
+
|
|
432
|
+
try {
|
|
433
|
+
// CLAIMABLE PREDICATE (US #15): "in `tasks/ready/` (the pool) on `main` AND no
|
|
434
|
+
// lock held" \u2014 widened under `--allow-backlog` to ALSO accept a
|
|
435
|
+
// `tasks/backlog/`-resident body (staging), so a human can drive a staged task
|
|
436
|
+
// in place. The HELD-LOCK half is the create-only acquire above (a held slug
|
|
437
|
+
// already lost the race). Confirm the residence here \u2014 the body STAYS where it
|
|
438
|
+
// rested (claim moves nothing, even under the flag), so a `done`/absent item is
|
|
439
|
+
// not claimable: release the lock we just took (it never protected any in-flight
|
|
440
|
+
// work) and lose (exit 2).
|
|
441
|
+
await gitHard(['fetch', '--quiet', arbiter], cwd, env);
|
|
442
|
+
claimedBodyRel = await claimableBodyRel();
|
|
443
|
+
if (claimedBodyRel === undefined) {
|
|
444
|
+
await releaseHeldLock();
|
|
445
|
+
const message = await lostMessage(
|
|
446
|
+
slug,
|
|
447
|
+
arbiter,
|
|
448
|
+
cwd,
|
|
449
|
+
env,
|
|
450
|
+
notFoundFallback,
|
|
451
|
+
);
|
|
452
|
+
note(message);
|
|
453
|
+
return {exitCode: 2, outcome: 'lost', message};
|
|
454
|
+
}
|
|
455
|
+
} catch (err) {
|
|
456
|
+
// A plumbing failure after we took the lock: release it so the held lock does
|
|
457
|
+
// not orphan an item that never started, then re-throw for the top-level
|
|
458
|
+
// handler to classify (exit 1).
|
|
459
|
+
await releaseHeldLock();
|
|
460
|
+
throw err;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// CLAIMED. The body rests where it was claimed from (`tasks/ready/` normally, or
|
|
464
|
+
// `tasks/backlog/` under `--allow-backlog`) on `<arbiter>/main` and the lock is
|
|
465
|
+
// held. There is NO claim commit and nothing on `main` to branch from —
|
|
466
|
+
// onboarding cuts the work branch straight off `<arbiter>/main` (which carries the
|
|
467
|
+
// body). The folder is the RESOLVED residence, not a hard-coded guess: a `ready/`
|
|
468
|
+
// claim must not falsely report `backlog/` (it misled a whole CI-incident triage).
|
|
469
|
+
// `claimedBodyRel` is always set here (the claimability re-check above returns
|
|
470
|
+
// `lost` otherwise); fall back to the pool residence (`backlog` IS the
|
|
471
|
+
// `tasks-ready` path constant) for type-safety — derived via the layout helper,
|
|
472
|
+
// never a raw `work/<folder>` literal (the work-layout guard).
|
|
473
|
+
const residence = residenceFolder(claimedBodyRel ?? backlog);
|
|
474
|
+
const message = `CLAIMED '${slug}' (lock held; body stays in ${residence}/ on ${arbiter}/main).`;
|
|
475
|
+
note(message);
|
|
476
|
+
note(
|
|
477
|
+
`Start work: git fetch ${arbiter} && git switch -C ${branch} ${arbiter}/main`,
|
|
478
|
+
);
|
|
479
|
+
return {exitCode: 0, outcome: 'claimed', message};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/** `git cat-file -e <object>` — true iff the object exists. */
|
|
483
|
+
async function catFileExists(
|
|
484
|
+
object: string,
|
|
485
|
+
cwd: string,
|
|
486
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
487
|
+
): Promise<boolean> {
|
|
488
|
+
return (await gitSoft(['cat-file', '-e', object], cwd, env)).status === 0;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/** Run git, returning the raw result (no throw) — for soft checks. */
|
|
492
|
+
function gitSoft(
|
|
493
|
+
args: string[],
|
|
494
|
+
cwd: string,
|
|
495
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
496
|
+
): Promise<RunResult> {
|
|
497
|
+
return runAsync('git', args, cwd, {env});
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/** Run git; throw on non-zero (genuinely unexpected plumbing failures). */
|
|
501
|
+
async function gitHard(
|
|
502
|
+
args: string[],
|
|
503
|
+
cwd: string,
|
|
504
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
505
|
+
): Promise<RunResult> {
|
|
506
|
+
const result = await runAsync('git', args, cwd, {env});
|
|
507
|
+
if (result.status !== 0) {
|
|
508
|
+
throw new Error(
|
|
509
|
+
`git ${args.join(' ')} failed (exit ${result.status}): ${result.stderr.trim()}`,
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
return result;
|
|
513
|
+
}
|