dorfl 0.0.0 → 0.1.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/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 +3094 -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 +215 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +345 -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 +315 -0
- package/dist/prd-to-spec.d.ts.map +1 -0
- package/dist/prd-to-spec.js +684 -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 +360 -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 +952 -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 +4369 -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 +485 -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 +1023 -0
- package/src/prepare.ts +230 -0
- package/src/prompt.ts +760 -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 +1438 -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,771 @@
|
|
|
1
|
+
import type {IntegrationMode} from './config.js';
|
|
2
|
+
import {git, run} from './git.js';
|
|
3
|
+
import {isAncestor} from './gc.js';
|
|
4
|
+
import type {BackoffOptions, Sleep} from './retry-backoff.js';
|
|
5
|
+
import {pushProposeBranchWithStaleLeaseRetry} from './continue-branch.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The **integration seam** (ADR §6): integrating a completed work branch back to
|
|
9
|
+
* the arbiter has two orthogonal axes —
|
|
10
|
+
*
|
|
11
|
+
* - **mode**: `merge` (ff/rebase onto `<arbiter>/main`, push to main —
|
|
12
|
+
* provider-agnostic git) or `propose` (push the branch + request review).
|
|
13
|
+
* - **provider** (a seam): the review-request tool — `github` (its own task)
|
|
14
|
+
* or **`none`** (push + tell the human to open a request manually, the only
|
|
15
|
+
* option for a local `--bare` arbiter, which has no review concept).
|
|
16
|
+
*
|
|
17
|
+
* The **universal, safety-bearing action is `git push`** to the arbiter; the
|
|
18
|
+
* review request is layered on top and provider-specific. Deletion safety
|
|
19
|
+
* (ADR §4) rides on the push, never the provider step — a provider failure
|
|
20
|
+
* leaves a safe, pushed branch, not lost work. We NEVER `--force` to main.
|
|
21
|
+
*
|
|
22
|
+
* Before integrating, `integrateWithRebase` rebases the branch onto the latest
|
|
23
|
+
* `<arbiter>/main` (ADR §10): clean → proceed; conflict → `git rebase --abort` +
|
|
24
|
+
* route to `needs-attention` (NEVER auto-resolve).
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** The review-request provider seam. `none` and (later) `github` implement it. */
|
|
28
|
+
export interface ReviewProvider {
|
|
29
|
+
/** Stable provider name stamped into results (`none`, `github`, …). */
|
|
30
|
+
readonly name: string;
|
|
31
|
+
/**
|
|
32
|
+
* Request review of an already-pushed branch. The branch is guaranteed to be
|
|
33
|
+
* on the arbiter before this is called (the push is the safety guarantee), so
|
|
34
|
+
* a provider failure never loses work. ASYNC: a real provider RETRIES the
|
|
35
|
+
* request with bounded backoff on a transient OUTAGE before degrading (a
|
|
36
|
+
* LOW-severity mode — the branch is already safe, only the review surface is
|
|
37
|
+
* missing), driven by an injectable sleep so tests need no real waits.
|
|
38
|
+
*/
|
|
39
|
+
openRequest(input: OpenRequestInput): Promise<OpenRequestResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Post a follow-up COMMENT on an already-opened review request (the PR the
|
|
42
|
+
* sibling {@link openRequest} created), threaded by its `url`. Used by the
|
|
43
|
+
* Gate-2 review-comment poster (task `review-gate-pr-comment`) to make the
|
|
44
|
+
* review's verdict VISIBLE on the PR. It is the SIBLING of `openRequest` on the
|
|
45
|
+
* "write text to the PR" surface: `openRequest` writes the creation BODY,
|
|
46
|
+
* `postPRComment` writes a follow-up comment AFTER the PR exists.
|
|
47
|
+
*
|
|
48
|
+
* Keyed by the PR `url` (the review-request surface). The issue seam's sibling
|
|
49
|
+
* `postIssueComment` (`issue-provider.ts`) is keyed by the ISSUE NUMBER instead —
|
|
50
|
+
* GitHub shares the comment id space, but other providers may not, so the two
|
|
51
|
+
* comment surfaces are nominally DISTINCT seams (distinct input types).
|
|
52
|
+
*
|
|
53
|
+
* ADVISORY — it gates nothing; like `openRequest` it must NEVER throw (a
|
|
54
|
+
* missing/unauthenticated `gh`, or the `none` provider, DEGRADES: it surfaces
|
|
55
|
+
* the text in the result `instruction`, never losing the review — ADR §6).
|
|
56
|
+
*/
|
|
57
|
+
postPRComment(input: PostPRCommentInput): PostPRCommentResult;
|
|
58
|
+
/**
|
|
59
|
+
* Post a follow-up COMMENT on the PR opened for an already-pushed `work/<slug>`
|
|
60
|
+
* BRANCH, RESOLVING the PR from that branch instead of being handed its `url`.
|
|
61
|
+
* This is the FALLBACK for the audit-trail gap where `gh pr create` opened a PR
|
|
62
|
+
* (exit 0) but dorfl could not PARSE the PR url out of its stdout: the
|
|
63
|
+
* sibling {@link openRequest} then returns `{opened: true}` with NO `url`, so the
|
|
64
|
+
* url-keyed {@link postPRComment} has nothing to thread on. Given the branch, a
|
|
65
|
+
* real provider resolves its open PR (`gh pr comment <branch>` / `gh pr view
|
|
66
|
+
* <branch>`) and comments — closing the gap where a genuinely-opened PR's review
|
|
67
|
+
* was silently dropped.
|
|
68
|
+
*
|
|
69
|
+
* It is the BRANCH-keyed twin of {@link postPRComment} (which is URL-keyed); the
|
|
70
|
+
* core prefers the url path when it HAS a url and only falls back here when a PR
|
|
71
|
+
* was opened without a parseable url. The `posted` flag reports whether a comment
|
|
72
|
+
* was actually posted; when NO PR can be resolved from the branch at all it is a
|
|
73
|
+
* clean no-op (`posted: false`) — the honest "no PR ⇒ no comment" outcome, but
|
|
74
|
+
* only AFTER trying to resolve one.
|
|
75
|
+
*
|
|
76
|
+
* ADVISORY — it gates nothing; like the others it must NEVER throw (a
|
|
77
|
+
* missing/unauthenticated `gh`, the `none` provider, or no resolvable PR all
|
|
78
|
+
* DEGRADE: surface the text in the result `instruction`, never losing the
|
|
79
|
+
* review — ADR §6).
|
|
80
|
+
*/
|
|
81
|
+
postPRCommentOnBranch(input: PostPRCommentOnBranchInput): PostPRCommentResult;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface PostPRCommentInput {
|
|
85
|
+
cwd: string;
|
|
86
|
+
/**
|
|
87
|
+
* The URL of the opened review request (the PR) to comment on — the `url`
|
|
88
|
+
* {@link OpenRequestResult} returned. The GitHub provider passes it to
|
|
89
|
+
* `gh pr comment <url>`; absent ⇒ the caller should not call postPRComment (no
|
|
90
|
+
* PR to comment on).
|
|
91
|
+
*/
|
|
92
|
+
url: string;
|
|
93
|
+
/** The comment body (the verbatim review prose, JSON block stripped). */
|
|
94
|
+
body: string;
|
|
95
|
+
env?: NodeJS.ProcessEnv;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface PostPRCommentOnBranchInput {
|
|
99
|
+
cwd: string;
|
|
100
|
+
/**
|
|
101
|
+
* The pushed `work/<slug>` branch whose open PR to RESOLVE and comment on — the
|
|
102
|
+
* branch {@link OpenRequestInput.branch} opened a PR for. The GitHub provider
|
|
103
|
+
* passes it to `gh pr view <branch>` / `gh pr comment <branch>`; a provider that
|
|
104
|
+
* cannot resolve a PR from it cleanly no-ops (nothing to comment on).
|
|
105
|
+
*/
|
|
106
|
+
branch: string;
|
|
107
|
+
/** The comment body (the verbatim review prose, JSON block stripped). */
|
|
108
|
+
body: string;
|
|
109
|
+
env?: NodeJS.ProcessEnv;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface PostPRCommentResult {
|
|
113
|
+
/** True iff a comment was actually posted (a real, authenticated provider). */
|
|
114
|
+
posted: boolean;
|
|
115
|
+
/** Human-readable confirmation / fallback (the verdict text on degrade). */
|
|
116
|
+
instruction: string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface OpenRequestInput {
|
|
120
|
+
cwd: string;
|
|
121
|
+
/** The pushed work branch to request review of. */
|
|
122
|
+
branch: string;
|
|
123
|
+
/** The arbiter remote the branch was pushed to. */
|
|
124
|
+
arbiter: string;
|
|
125
|
+
/**
|
|
126
|
+
* Optional explicit, single-line review-request TITLE. When present a provider
|
|
127
|
+
* passes it verbatim (e.g. `gh pr create --title`) instead of deriving the
|
|
128
|
+
* title from the commit subject (`--fill`), which can be a multi-line run-on.
|
|
129
|
+
* Synthesised runner-side from the task frontmatter (`<type>(<slug>): <title>`,
|
|
130
|
+
* capped to one line). Absent ⇒ today's `--fill`-derived title (no regression).
|
|
131
|
+
*/
|
|
132
|
+
title?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Optional review-request BODY/description (advisory prose — it gates nothing).
|
|
135
|
+
* When present a provider passes it verbatim (e.g. `gh pr create --body`)
|
|
136
|
+
* instead of `--fill`'s empty/commit-derived description. Typically the build
|
|
137
|
+
* agent's final summary, optionally under a runner-scaffolded header (a pointer
|
|
138
|
+
* to `work/done/<slug>.md` + the prd/ADR it serves). Absent ⇒ today's `--fill`
|
|
139
|
+
* (no regression). This is the BODY-AT-OPEN surface; a follow-up PR COMMENT is
|
|
140
|
+
* a separate provider method.
|
|
141
|
+
*/
|
|
142
|
+
body?: string;
|
|
143
|
+
env?: NodeJS.ProcessEnv;
|
|
144
|
+
/**
|
|
145
|
+
* Bounded-backoff bounds for the provider's review-request retry (the OUTAGE-
|
|
146
|
+
* retry of e.g. `gh pr create`). Defaults to the shared `DEFAULT_BACKOFF`.
|
|
147
|
+
*/
|
|
148
|
+
backoff?: BackoffOptions;
|
|
149
|
+
/**
|
|
150
|
+
* Injectable sleep for that backoff (tests drive the retry timeline with NO
|
|
151
|
+
* real waits — the `run.ts` `sleep`/`realSleep` seam). Defaults to a real
|
|
152
|
+
* `setTimeout`.
|
|
153
|
+
*/
|
|
154
|
+
sleep?: Sleep;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface OpenRequestResult {
|
|
158
|
+
/** True iff a review request was actually opened (a real provider). */
|
|
159
|
+
opened: boolean;
|
|
160
|
+
/** Human-readable next step / confirmation. */
|
|
161
|
+
instruction: string;
|
|
162
|
+
/**
|
|
163
|
+
* The URL of the opened review request (e.g. a GitHub PR), when a provider
|
|
164
|
+
* created one and could report it. Absent for push-only / degraded paths.
|
|
165
|
+
*/
|
|
166
|
+
url?: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* The graceful-degradation provider (ADR §6): it opens NO review request (there
|
|
171
|
+
* is no API — e.g. a local `--bare` arbiter) and instead tells the human to open
|
|
172
|
+
* one manually. The branch is already pushed, so the work is safe regardless.
|
|
173
|
+
*/
|
|
174
|
+
export class NoneProvider implements ReviewProvider {
|
|
175
|
+
readonly name = 'none';
|
|
176
|
+
|
|
177
|
+
async openRequest(input: OpenRequestInput): Promise<OpenRequestResult> {
|
|
178
|
+
return {
|
|
179
|
+
opened: false,
|
|
180
|
+
instruction:
|
|
181
|
+
`Pushed ${input.branch} to ${input.arbiter}. Open a review request ` +
|
|
182
|
+
'manually to land it on main (no review provider configured).' +
|
|
183
|
+
manualRequestText(input),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* No API to post a comment (a local `--bare` arbiter has no review concept), so
|
|
189
|
+
* DEGRADE: surface the review text in the result instead of throwing — the
|
|
190
|
+
* verdict stays in the run output, never lost (ADR §6). The caller treats this
|
|
191
|
+
* as a clean no-op for the PR (nothing was posted).
|
|
192
|
+
*/
|
|
193
|
+
postPRComment(input: PostPRCommentInput): PostPRCommentResult {
|
|
194
|
+
return {
|
|
195
|
+
posted: false,
|
|
196
|
+
instruction:
|
|
197
|
+
'No review provider configured — the review was not posted as a PR ' +
|
|
198
|
+
`comment. The review:\n${input.body}`,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* No API to resolve a PR from a branch (a local `--bare` arbiter has no review
|
|
204
|
+
* concept), so DEGRADE exactly like {@link postPRComment}: surface the review
|
|
205
|
+
* text, post nothing, never throw. A clean no-op for the PR.
|
|
206
|
+
*/
|
|
207
|
+
postPRCommentOnBranch(
|
|
208
|
+
input: PostPRCommentOnBranchInput,
|
|
209
|
+
): PostPRCommentResult {
|
|
210
|
+
return {
|
|
211
|
+
posted: false,
|
|
212
|
+
instruction:
|
|
213
|
+
'No review provider configured — the review was not posted as a PR ' +
|
|
214
|
+
`comment. The review:\n${input.body}`,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface IntegrateInput {
|
|
220
|
+
cwd: string;
|
|
221
|
+
/** The arbiter remote name. */
|
|
222
|
+
arbiter: string;
|
|
223
|
+
/** The work branch to integrate (`work/<slug>`). */
|
|
224
|
+
branch: string;
|
|
225
|
+
/** Integration mode (`propose` default, or `merge`). */
|
|
226
|
+
mode: IntegrationMode;
|
|
227
|
+
/**
|
|
228
|
+
* Optional single-line review-request TITLE threaded to the provider (propose
|
|
229
|
+
* mode). Absent ⇒ the provider's `--fill` default. Ignored in `merge` mode
|
|
230
|
+
* (no review request is opened).
|
|
231
|
+
*/
|
|
232
|
+
title?: string;
|
|
233
|
+
/**
|
|
234
|
+
* Optional review-request BODY threaded to the provider (propose mode). Absent
|
|
235
|
+
* ⇒ the provider's `--fill` default. Ignored in `merge` mode.
|
|
236
|
+
*/
|
|
237
|
+
body?: string;
|
|
238
|
+
/**
|
|
239
|
+
* **The PR-INTENT axis** (config `noPR`, ADR §6). When `true` on the `propose`
|
|
240
|
+
* path, push the branch (the safety-bearing step) but SKIP `openRequest` — the
|
|
241
|
+
* explicit suppress-PR intent (re-homing the old `provider: none` use). No
|
|
242
|
+
* warning: the no-PR outcome is intended. It does NOT pick a provider; the
|
|
243
|
+
* arbiter-derived provider is simply not asked to open a request. Ignored in
|
|
244
|
+
* `merge` mode (it never opens a request).
|
|
245
|
+
*/
|
|
246
|
+
noPR?: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* **Reap the remote head branch INLINE after a merge lands** (this task's part
|
|
249
|
+
* (b)). When `true` on the `merge` path, AFTER the work landed on `main` (the
|
|
250
|
+
* commits are now provably on main, so the ancestor predicate trivially holds),
|
|
251
|
+
* delete the remote `work/<slug>` head branch via `git push <arbiter> --delete`
|
|
252
|
+
* — the cross-machine counterpart of the worktree reap, done at the exact merge
|
|
253
|
+
* moment so no sweep is needed for the we-merged case. IDEMPOTENT: when no
|
|
254
|
+
* remote head exists (the plain `${branch}:main` push opened none), the delete is
|
|
255
|
+
* a clean best-effort no-op. NEVER `--force` (a just-merged ref needs none). The
|
|
256
|
+
* autonomous complete path sets this on; the direct `integrate` callers / tests
|
|
257
|
+
* leave it off, so the bare `${branch}:main` push is byte-for-byte unchanged.
|
|
258
|
+
* Ignored in `propose` mode (the branch is the review surface — it is reaped
|
|
259
|
+
* later by the `gc --remote-branches` sweep once its PR merges).
|
|
260
|
+
*/
|
|
261
|
+
deleteMergedHead?: boolean;
|
|
262
|
+
env?: NodeJS.ProcessEnv;
|
|
263
|
+
/** Bounded-backoff bounds for the provider's review-request retry. */
|
|
264
|
+
backoff?: BackoffOptions;
|
|
265
|
+
/** Injectable sleep for that backoff (tests; defaults to real `setTimeout`). */
|
|
266
|
+
sleep?: Sleep;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export interface IntegrateResult {
|
|
270
|
+
mode: IntegrationMode;
|
|
271
|
+
/** True when the work landed on the arbiter's `main` (merge mode). */
|
|
272
|
+
mergedToMain: boolean;
|
|
273
|
+
/**
|
|
274
|
+
* **Race-1 non-fast-forward signal** (merge mode): set `true` when the
|
|
275
|
+
* `${branch}:main` push was REJECTED non-fast-forward because a SIBLING advanced
|
|
276
|
+
* `<arbiter>/main` during the push window (and our commit is NOT already on main
|
|
277
|
+
* — the idempotency probe ruled that out). The work did NOT land; the caller
|
|
278
|
+
* (integration-core's step-4 tail) must re-fetch + re-rebase (reconciling
|
|
279
|
+
* sibling-ledger divergence) + retry the push, up to its bounded cap. Absent on a
|
|
280
|
+
* clean (or idempotent-landed) merge.
|
|
281
|
+
*/
|
|
282
|
+
mergeNonFastForward?: boolean;
|
|
283
|
+
/** The ref the work was pushed to (`main` for merge, the branch for propose). */
|
|
284
|
+
pushedRef: string;
|
|
285
|
+
/** The provider name used (propose mode); `none` in merge mode. */
|
|
286
|
+
provider: string;
|
|
287
|
+
/** True iff a review request was opened (propose + a real provider). */
|
|
288
|
+
requestOpened: boolean;
|
|
289
|
+
/**
|
|
290
|
+
* **BENIGN already-landed race tail** (propose mode — task
|
|
291
|
+
* `propose-push-survives-stale-lease-on-reaped-work-ref`): set `true` when
|
|
292
|
+
* the propose push observed a GONE `work/<slug>` ref on the arbiter AND the
|
|
293
|
+
* work was provably reachable from `<arbiter>/main` (an earlier merge had
|
|
294
|
+
* already landed it + reaped the head). The result is a CLEAN no-op: no push
|
|
295
|
+
* (or no completed push), no review request attempted against a vanished
|
|
296
|
+
* ref, distinct from a real push failure. Absent on the normal pushed-and-
|
|
297
|
+
* proposed path and in merge mode (merge has its own `mergedToMain`).
|
|
298
|
+
*/
|
|
299
|
+
alreadyLanded?: boolean;
|
|
300
|
+
/** Human-readable next step (propose mode). */
|
|
301
|
+
instruction?: string;
|
|
302
|
+
/**
|
|
303
|
+
* The URL of the opened review request (e.g. a GitHub PR), when a provider
|
|
304
|
+
* created one and reported it. Recorded in the job record / surfaced by
|
|
305
|
+
* `status`. Absent in merge mode and on the push-only / degraded path.
|
|
306
|
+
*/
|
|
307
|
+
url?: string;
|
|
308
|
+
/**
|
|
309
|
+
* The SHA that LANDED on the arbiter's `main` (the MERGE-mode twin of {@link
|
|
310
|
+
* url}). Populated only on the merge path — the work branch's tip is exactly
|
|
311
|
+
* what `${branch}:main` pushed. ADDITIVE + optional, so existing `do`/`run`/
|
|
312
|
+
* `complete` callers are unaffected; intake reads it to link the landed commit
|
|
313
|
+
* in its completion comment. Absent in propose mode (the PR `url` is the link
|
|
314
|
+
* there) and best-effort on merge (a failed tip read simply omits it).
|
|
315
|
+
*/
|
|
316
|
+
commit?: string;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** Outcome of the full rebase-then-integrate flow. */
|
|
320
|
+
export interface IntegrateWithRebaseResult {
|
|
321
|
+
outcome: 'integrated' | 'needs-attention';
|
|
322
|
+
/** Set when `integrated`. */
|
|
323
|
+
integration?: IntegrateResult;
|
|
324
|
+
/** Set when `needs-attention` (e.g. a rebase conflict). */
|
|
325
|
+
reason?: string;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export interface IntegratorOptions {
|
|
329
|
+
/** The review-request provider (default: the `none` provider). */
|
|
330
|
+
provider?: ReviewProvider;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export class Integrator {
|
|
334
|
+
private readonly provider: ReviewProvider;
|
|
335
|
+
|
|
336
|
+
constructor(options: IntegratorOptions = {}) {
|
|
337
|
+
this.provider = options.provider ?? new NoneProvider();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Integrate WITHOUT rebasing (assumes the caller already rebased, or the
|
|
342
|
+
* branch is known up-to-date). `merge` pushes the branch to `main` (plain,
|
|
343
|
+
* non-force push); `propose` pushes the branch under its own ref + asks the
|
|
344
|
+
* provider to request review. NEVER `--force` (and NEVER force-touches main).
|
|
345
|
+
*/
|
|
346
|
+
async integrate(input: IntegrateInput): Promise<IntegrateResult> {
|
|
347
|
+
if (input.mode === 'merge') {
|
|
348
|
+
// Race-1 (claim-vs-integrate): push `${branch}:main` ONCE. On a
|
|
349
|
+
// non-fast-forward rejection (a sibling same-repo claim/integrate advanced
|
|
350
|
+
// `<arbiter>/main` during our push window) report it so the integration-core
|
|
351
|
+
// step-4 tail re-rebases (with its sibling-ledger reconcile) + retries the
|
|
352
|
+
// push. We never rebase here (that would miss the ledger reconcile arms) and
|
|
353
|
+
// never `--force` main.
|
|
354
|
+
const pushed = mergePushOnce(input);
|
|
355
|
+
if (pushed.kind === 'non-fast-forward') {
|
|
356
|
+
// Signal the caller to re-rebase via step-4 and call integrate again.
|
|
357
|
+
return {
|
|
358
|
+
mode: 'merge',
|
|
359
|
+
mergedToMain: false,
|
|
360
|
+
pushedRef: 'main',
|
|
361
|
+
provider: 'none',
|
|
362
|
+
requestOpened: false,
|
|
363
|
+
mergeNonFastForward: true,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
// Capture the SHA that LANDED on `main` — the work branch's tip is exactly
|
|
367
|
+
// what `${branch}:main` pushed (additive `commit?`, the merge-mode twin of
|
|
368
|
+
// propose's `url`). Best-effort: a failed read leaves `commit` absent, so a
|
|
369
|
+
// caller that links it (intake) simply omits the link rather than throwing.
|
|
370
|
+
const commit = resolveBranchTip(input);
|
|
371
|
+
// Part (b): reap the remote head INLINE now the merge has landed. The work
|
|
372
|
+
// is on `main` (we just pushed it there), so the head is provably merged and
|
|
373
|
+
// safe to delete — the exact merge moment, no sweep needed. Idempotent +
|
|
374
|
+
// best-effort: a no-remote-head merge (the common `${branch}:main` push) is a
|
|
375
|
+
// clean no-op. NEVER `--force`. Gated by `deleteMergedHead` so the bare
|
|
376
|
+
// `integrate` callers / tests are unchanged.
|
|
377
|
+
if (input.deleteMergedHead === true) {
|
|
378
|
+
deleteMergedHeadBranch(input);
|
|
379
|
+
}
|
|
380
|
+
return {
|
|
381
|
+
mode: 'merge',
|
|
382
|
+
mergedToMain: true,
|
|
383
|
+
pushedRef: 'main',
|
|
384
|
+
provider: 'none',
|
|
385
|
+
requestOpened: false,
|
|
386
|
+
...(commit !== undefined ? {commit} : {}),
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// propose: push the branch under its own name (the safety-bearing step),
|
|
391
|
+
// THEN ask the provider to request review. Reconcile with --force-with-lease
|
|
392
|
+
// on the WORK BRANCH ONLY (§11: a work branch is unshared) so a RECOVERY
|
|
393
|
+
// complete — which rebases the kept branch onto fresh `main` (a PLAIN rebase
|
|
394
|
+
// after the per-item-lock cut-over: no transient status lands on a branch, so
|
|
395
|
+
// there is nothing to drop) and so REWRITES the tip vs an already-pushed
|
|
396
|
+
// `work/<slug>` (the bounce now pushes it via the seam) — lands cleanly
|
|
397
|
+
// instead of failing non-fast-forward. The lease guards the CAS; this
|
|
398
|
+
// is NEVER a plain `--force`, and NEVER touches main.
|
|
399
|
+
//
|
|
400
|
+
// STALE-LEASE SURVIVAL + BENIGN ALREADY-LANDED (task `propose-push-
|
|
401
|
+
// survives-stale-lease-on-reaped-work-ref`): route through the propose
|
|
402
|
+
// stale-lease retry helper (the sibling of
|
|
403
|
+
// `pushContinuedBranchWithStaleLeaseRetry`, sharing its `stale info`
|
|
404
|
+
// detection + bounded retry, with the propose-specific addition of the
|
|
405
|
+
// gone-ref + ancestor-of-`<arbiter>/main` = BENIGN already-landed predicate
|
|
406
|
+
// — mirroring `deleteMergedHeadBranch`'s ancestor guard + the leased-delete
|
|
407
|
+
// `already-reaped` precedent). Survives a `stale info` rejection when the
|
|
408
|
+
// arbiter's view of the unshared work ref moved under us (re-leases against
|
|
409
|
+
// the freshly-observed tip); reports `alreadyLanded` (no PR re-open against
|
|
410
|
+
// a vanished ref) when the work already landed via a sibling's merge +
|
|
411
|
+
// reap; SURFACES every non-stale failure (connectivity, protected ref,
|
|
412
|
+
// auth) and a non-provably-landed stale-info-after-cap as a terminal throw.
|
|
413
|
+
// For a first-time propose (no remote ref yet) the helper's create-only
|
|
414
|
+
// empty-expected lease shape (`<branch>:`) accepts the new ref unchanged.
|
|
415
|
+
const proposePush = pushProposeBranchWithStaleLeaseRetry({
|
|
416
|
+
cwd: input.cwd,
|
|
417
|
+
branch: input.branch,
|
|
418
|
+
arbiter: input.arbiter,
|
|
419
|
+
env: input.env,
|
|
420
|
+
});
|
|
421
|
+
if (proposePush.kind === 'already-landed') {
|
|
422
|
+
// BENIGN already-landed: the work is provably on `<arbiter>/main` and the
|
|
423
|
+
// head was reaped. Do NOT call the provider — there is no ref to open a
|
|
424
|
+
// review request against, and asking the provider to open a PR for
|
|
425
|
+
// landed work would be a confusing no-op. Distinct from a real failure:
|
|
426
|
+
// `alreadyLanded: true`, no throw, no PR.
|
|
427
|
+
return {
|
|
428
|
+
mode: 'propose',
|
|
429
|
+
mergedToMain: false,
|
|
430
|
+
pushedRef: input.branch,
|
|
431
|
+
provider: 'none',
|
|
432
|
+
requestOpened: false,
|
|
433
|
+
alreadyLanded: true,
|
|
434
|
+
instruction:
|
|
435
|
+
`${input.branch}: the work is already on ${input.arbiter}/main ` +
|
|
436
|
+
'and its remote head was reaped — nothing to propose (clean no-op).',
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
// PR-INTENT (`noPR: true`): the branch is now pushed (safe) — deliberately do
|
|
440
|
+
// NOT open a review request (the explicit suppress-PR intent). No warning: the
|
|
441
|
+
// no-PR outcome is intended, not a degrade. The provider is reported as `none`
|
|
442
|
+
// (no request opened), exactly as a push-only propose surfaces.
|
|
443
|
+
if (input.noPR === true) {
|
|
444
|
+
return {
|
|
445
|
+
mode: 'propose',
|
|
446
|
+
mergedToMain: false,
|
|
447
|
+
pushedRef: input.branch,
|
|
448
|
+
provider: 'none',
|
|
449
|
+
requestOpened: false,
|
|
450
|
+
instruction:
|
|
451
|
+
`Pushed ${input.branch} to ${input.arbiter}. No PR was opened ` +
|
|
452
|
+
'(noPR is set — the suppress-PR intent).',
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
const review = await this.provider.openRequest({
|
|
456
|
+
cwd: input.cwd,
|
|
457
|
+
branch: input.branch,
|
|
458
|
+
arbiter: input.arbiter,
|
|
459
|
+
title: input.title,
|
|
460
|
+
body: input.body,
|
|
461
|
+
env: input.env,
|
|
462
|
+
backoff: input.backoff,
|
|
463
|
+
sleep: input.sleep,
|
|
464
|
+
});
|
|
465
|
+
return {
|
|
466
|
+
mode: 'propose',
|
|
467
|
+
mergedToMain: false,
|
|
468
|
+
pushedRef: input.branch,
|
|
469
|
+
provider: this.provider.name,
|
|
470
|
+
requestOpened: review.opened,
|
|
471
|
+
instruction: review.instruction,
|
|
472
|
+
url: review.url,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Rebase-before-integrate (ADR §10): fetch + rebase the branch onto the latest
|
|
478
|
+
* `<arbiter>/main`. Clean → integrate. Conflict → the rebase is already
|
|
479
|
+
* aborted by `rebaseOntoArbiterMain`; we return `needs-attention` (NEVER
|
|
480
|
+
* auto-resolve, NEVER push a half-merged tree).
|
|
481
|
+
*/
|
|
482
|
+
async integrateWithRebase(
|
|
483
|
+
input: IntegrateInput,
|
|
484
|
+
): Promise<IntegrateWithRebaseResult> {
|
|
485
|
+
const rebase = rebaseOntoArbiterMain({
|
|
486
|
+
cwd: input.cwd,
|
|
487
|
+
arbiter: input.arbiter,
|
|
488
|
+
branch: input.branch,
|
|
489
|
+
env: input.env,
|
|
490
|
+
});
|
|
491
|
+
if (!rebase.clean) {
|
|
492
|
+
return {
|
|
493
|
+
outcome: 'needs-attention',
|
|
494
|
+
reason:
|
|
495
|
+
`Rebasing ${input.branch} onto ${input.arbiter}/main conflicted; ` +
|
|
496
|
+
'the rebase was aborted (never auto-resolved). A human must resolve ' +
|
|
497
|
+
'against the latest main, then re-integrate.',
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
return {outcome: 'integrated', integration: await this.integrate(input)};
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
export interface RebaseInput {
|
|
505
|
+
cwd: string;
|
|
506
|
+
arbiter: string;
|
|
507
|
+
branch: string;
|
|
508
|
+
env?: NodeJS.ProcessEnv;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
export interface RebaseResult {
|
|
512
|
+
/** True iff the branch was cleanly rebased onto the latest arbiter main. */
|
|
513
|
+
clean: boolean;
|
|
514
|
+
/** True iff the rebase conflicted (and was aborted). */
|
|
515
|
+
conflicted: boolean;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Deterministically rebase `branch` onto the freshly-fetched `<arbiter>/main`
|
|
520
|
+
* (ADR §10). A clean rebase leaves the branch on top of main. A conflicting
|
|
521
|
+
* rebase is `git rebase --abort`ed (restoring the pre-rebase state) and reported
|
|
522
|
+
* as `conflicted` — we NEVER pick `--ours`/`--theirs` or any heuristic
|
|
523
|
+
* (resolution requires semantic judgement; a wrong-but-compiling merge is the
|
|
524
|
+
* worst outcome). Must be called with `branch` checked out.
|
|
525
|
+
*/
|
|
526
|
+
export function rebaseOntoArbiterMain(input: RebaseInput): RebaseResult {
|
|
527
|
+
const env = input.env;
|
|
528
|
+
// Fetch the arbiter's `main` into the `<arbiter>/main` remote-tracking ref
|
|
529
|
+
// EXPLICITLY. A job worktree is cut from a bare hub mirror whose `origin`
|
|
530
|
+
// remote has no fetch refspec (so `origin/main` would not otherwise resolve);
|
|
531
|
+
// a normal clone already has it but the explicit refspec is harmless there.
|
|
532
|
+
git(
|
|
533
|
+
[
|
|
534
|
+
'fetch',
|
|
535
|
+
'--quiet',
|
|
536
|
+
input.arbiter,
|
|
537
|
+
`+refs/heads/main:refs/remotes/${input.arbiter}/main`,
|
|
538
|
+
],
|
|
539
|
+
input.cwd,
|
|
540
|
+
{env},
|
|
541
|
+
);
|
|
542
|
+
// Ensure we are on the branch we intend to rebase.
|
|
543
|
+
git(['checkout', '--quiet', input.branch], input.cwd, {env});
|
|
544
|
+
|
|
545
|
+
const rebase = run('git', ['rebase', `${input.arbiter}/main`], input.cwd, {
|
|
546
|
+
env,
|
|
547
|
+
});
|
|
548
|
+
if (rebase.status === 0) {
|
|
549
|
+
return {clean: true, conflicted: false};
|
|
550
|
+
}
|
|
551
|
+
// Conflict (or any non-zero): abort to restore the pre-rebase state. NEVER
|
|
552
|
+
// auto-resolve. `--abort` is best-effort; if there is nothing to abort it is
|
|
553
|
+
// a no-op error we can ignore.
|
|
554
|
+
run('git', ['rebase', '--abort'], input.cwd, {env});
|
|
555
|
+
return {clean: false, conflicted: true};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/** Outcome of {@link mergePushOnce}. */
|
|
559
|
+
type MergePushResult = {kind: 'landed'} | {kind: 'non-fast-forward'};
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Push `${branch}:main` (merge mode) ONCE, classifying the outcome for the
|
|
563
|
+
* caller's bounded re-rebase-and-retry loop (Race 1: claim-vs-integrate, task
|
|
564
|
+
* `run-fleet-claim-integrate-and-sibling-rebase-concurrency-safe`). It does NOT
|
|
565
|
+
* rebase itself: the rebase belongs to the integration-core step-4 tail, which
|
|
566
|
+
* ALSO carries the sibling-ledger + divergent-done-move reconciliation arms a bare
|
|
567
|
+
* rebase here would miss. This function's only job is to push and tell the caller
|
|
568
|
+
* whether to LOOP (re-rebase via step-4) or STOP.
|
|
569
|
+
*
|
|
570
|
+
* - `landed` — the push succeeded, OR (under the non-atomic `file://` transport)
|
|
571
|
+
* it reported failure but our tip is ALREADY reachable on `<arbiter>/main`
|
|
572
|
+
* (the push genuinely landed — an IDEMPOTENT no-op; never re-rebase our own
|
|
573
|
+
* already-landed commit, which would self-conflict). The `isAncestor` probe is
|
|
574
|
+
* the SAME merged-vs-unmerged predicate `gc.ts`/`finishStrandedBranch` use.
|
|
575
|
+
* - `non-fast-forward` — a SIBLING advanced `<arbiter>/main` during our push
|
|
576
|
+
* window (a claim CAS commit, or a sibling integrate); the caller must
|
|
577
|
+
* re-fetch + re-run the step-4 rebase (reconciling sibling-ledger divergence)
|
|
578
|
+
* and retry the push. We NEVER `--force` main.
|
|
579
|
+
*
|
|
580
|
+
* Any OTHER push failure (unreachable arbiter, refused ref) THROWS, exactly as a
|
|
581
|
+
* plain `git push` would.
|
|
582
|
+
*/
|
|
583
|
+
function mergePushOnce(input: IntegrateInput): MergePushResult {
|
|
584
|
+
const env = input.env;
|
|
585
|
+
const refspec = `${input.branch}:main`;
|
|
586
|
+
const arbiterRef = `refs/remotes/${input.arbiter}/main`;
|
|
587
|
+
|
|
588
|
+
const push = run('git', ['push', input.arbiter, refspec], input.cwd, {env});
|
|
589
|
+
if (push.status === 0) {
|
|
590
|
+
return {kind: 'landed'};
|
|
591
|
+
}
|
|
592
|
+
// Distinguish a CONTENTION rejection (main advanced — recoverable by a step-4
|
|
593
|
+
// re-rebase) from any other push failure (which surfaces as today's throw).
|
|
594
|
+
const combined = `${push.stderr}\n${push.stdout}`;
|
|
595
|
+
const nonFastForward =
|
|
596
|
+
/non-fast-forward|fetch first|\[rejected\]|failed to push/i.test(combined);
|
|
597
|
+
if (!nonFastForward) {
|
|
598
|
+
throw new Error(
|
|
599
|
+
`git push ${input.arbiter} ${refspec} failed (exit ${push.status}): ` +
|
|
600
|
+
`${push.stderr.trim() || push.stdout.trim()}`,
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
// Re-fetch the arbiter's main and check IDEMPOTENCY first: under `file://` a
|
|
604
|
+
// reported failure can have actually landed. If our tip is already on main, it
|
|
605
|
+
// landed — never re-rebase our own commit onto a main that has it.
|
|
606
|
+
git(
|
|
607
|
+
['fetch', '--quiet', input.arbiter, `+refs/heads/main:${arbiterRef}`],
|
|
608
|
+
input.cwd,
|
|
609
|
+
{env},
|
|
610
|
+
);
|
|
611
|
+
const tip = run(
|
|
612
|
+
'git',
|
|
613
|
+
['rev-parse', '--verify', '--quiet', `refs/heads/${input.branch}`],
|
|
614
|
+
input.cwd,
|
|
615
|
+
{env},
|
|
616
|
+
).stdout.trim();
|
|
617
|
+
if (tip !== '' && isAncestor(input.cwd, tip, arbiterRef, env)) {
|
|
618
|
+
return {kind: 'landed'};
|
|
619
|
+
}
|
|
620
|
+
// A genuine sibling main-advance: the caller re-runs the step-4 rebase + retries.
|
|
621
|
+
return {kind: 'non-fast-forward'};
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Push a branch to the arbiter. Used by both modes; `merge` targets `main`
|
|
626
|
+
* (plain, never forced), `propose` targets the branch's own ref. The caller may
|
|
627
|
+
* pass extra git args (e.g. `--force-with-lease=<work-branch>` on the propose
|
|
628
|
+
* path, to reconcile a recovery-rewritten WORK branch — §11, unshared, lease-
|
|
629
|
+
* guarded). There is NEVER a plain `--force`, and `main` is NEVER forced; the
|
|
630
|
+
* only leases in the system are this work-branch one + the claim micro-commit's.
|
|
631
|
+
*/
|
|
632
|
+
function pushBranch(
|
|
633
|
+
input: IntegrateInput,
|
|
634
|
+
refspec: string,
|
|
635
|
+
...extraArgs: string[]
|
|
636
|
+
): void {
|
|
637
|
+
git(['push', input.arbiter, refspec, ...extraArgs], input.cwd, {
|
|
638
|
+
env: input.env,
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Reap the remote `work/<slug>` HEAD branch on the arbiter AFTER its work landed
|
|
644
|
+
* on `main` (merge mode, part (b)). The merge push above already put the commits
|
|
645
|
+
* on `main`, so the head is PROVABLY merged — it is the recovery point no longer
|
|
646
|
+
* (its work is on main), exactly the never-delete invariant's release condition.
|
|
647
|
+
* We additionally CONFIRM the head, when it exists, is an ancestor of
|
|
648
|
+
* `<arbiter>/main` before deleting, so a racing un-merged amend is never reaped.
|
|
649
|
+
*
|
|
650
|
+
* BEST-EFFORT + idempotent (soft `run`, never throws): the deletion of a
|
|
651
|
+
* fully-merged ref needs NO force (and we never pass one); a no-remote-head merge
|
|
652
|
+
* (the plain `${branch}:main` push opened none) is a clean no-op; an unreachable
|
|
653
|
+
* arbiter / already-gone ref is tolerated. The integrate's safety rides on the
|
|
654
|
+
* merge push, never on this hygiene step.
|
|
655
|
+
*/
|
|
656
|
+
function deleteMergedHeadBranch(input: IntegrateInput): void {
|
|
657
|
+
const env = input.env;
|
|
658
|
+
const arbiter = input.arbiter;
|
|
659
|
+
const branch = input.branch;
|
|
660
|
+
// Does a remote head exist at all? (`ls-remote` exits 0 with empty stdout when
|
|
661
|
+
// absent.) No head ⇒ nothing to reap (the common direct-merge case).
|
|
662
|
+
const ls = run('git', ['ls-remote', '--heads', arbiter, branch], input.cwd, {
|
|
663
|
+
env,
|
|
664
|
+
});
|
|
665
|
+
if (ls.status !== 0 || ls.stdout.trim() === '') {
|
|
666
|
+
return; // unreachable arbiter, or no remote head — nothing to delete.
|
|
667
|
+
}
|
|
668
|
+
// The head exists. Confirm it is an ancestor of <arbiter>/main before deleting
|
|
669
|
+
// (it just merged, so this holds; the guard refuses a racing un-merged amend).
|
|
670
|
+
run(
|
|
671
|
+
'git',
|
|
672
|
+
[
|
|
673
|
+
'fetch',
|
|
674
|
+
'--quiet',
|
|
675
|
+
arbiter,
|
|
676
|
+
`+refs/heads/main:refs/remotes/${arbiter}/main`,
|
|
677
|
+
`+refs/heads/${branch}:refs/remotes/${arbiter}/${branch}`,
|
|
678
|
+
],
|
|
679
|
+
input.cwd,
|
|
680
|
+
{env},
|
|
681
|
+
);
|
|
682
|
+
const headSha = parseLsRemoteSha(ls.stdout);
|
|
683
|
+
if (headSha !== undefined) {
|
|
684
|
+
const isMerged = run(
|
|
685
|
+
'git',
|
|
686
|
+
['merge-base', '--is-ancestor', headSha, `refs/remotes/${arbiter}/main`],
|
|
687
|
+
input.cwd,
|
|
688
|
+
{env},
|
|
689
|
+
);
|
|
690
|
+
if (isMerged.status !== 0) {
|
|
691
|
+
return; // NOT provably merged (a racing un-merged amend) — never reap.
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
// Provably merged: WRITE-THROUGH delete — drop the LOCAL tracking ref FIRST
|
|
695
|
+
// (the ref that drives continue-detection), THEN the arbiter head (NEVER
|
|
696
|
+
// `--force`). The asymmetry is the point: an arbiter-delete failure leaves
|
|
697
|
+
// the local store BEHIND (self-healing on next fetch), never AHEAD (a stale
|
|
698
|
+
// `refs/remotes/<arbiter>/work/<slug>` that drives a wrong "continue" — the
|
|
699
|
+
// permanent stale-continue bug today's arbiter-first ordering creates).
|
|
700
|
+
run(
|
|
701
|
+
'git',
|
|
702
|
+
['update-ref', '-d', `refs/remotes/${arbiter}/${branch}`],
|
|
703
|
+
input.cwd,
|
|
704
|
+
{env},
|
|
705
|
+
);
|
|
706
|
+
run('git', ['push', arbiter, '--delete', branch], input.cwd, {env});
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/** First sha from a `git ls-remote` output line (`<sha>\t<ref>`), or undefined. */
|
|
710
|
+
function parseLsRemoteSha(stdout: string): string | undefined {
|
|
711
|
+
const m = /^([0-9a-f]{40})\s/m.exec(stdout.trim());
|
|
712
|
+
return m ? m[1] : undefined;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Resolve the SHA the merge path just pushed to `main` — the work branch's tip
|
|
717
|
+
* (`${branch}:main` pushes exactly that). BEST-EFFORT (soft `run`, never throws):
|
|
718
|
+
* on any failure it returns `undefined`, so the additive {@link
|
|
719
|
+
* IntegrateResult.commit} stays absent rather than breaking the integrate. Used to
|
|
720
|
+
* link the landed commit (intake's completion comment); the integrate's safety
|
|
721
|
+
* rides on the push above, never on this read.
|
|
722
|
+
*/
|
|
723
|
+
function resolveBranchTip(input: IntegrateInput): string | undefined {
|
|
724
|
+
const res = run('git', ['rev-parse', input.branch], input.cwd, {
|
|
725
|
+
env: input.env,
|
|
726
|
+
});
|
|
727
|
+
if (res.status !== 0) {
|
|
728
|
+
return undefined;
|
|
729
|
+
}
|
|
730
|
+
const sha = res.stdout.trim();
|
|
731
|
+
return sha === '' ? undefined : sha;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* Render the runner-synthesised TITLE + BODY into a human's MANUAL review-request
|
|
736
|
+
* instructions (the `none` provider, and the GitHub provider's degraded path),
|
|
737
|
+
* so a human opening the request by hand reuses the SAME title/body the
|
|
738
|
+
* autonomous path would have set. Returns '' when neither is present (today's
|
|
739
|
+
* bare instruction — no regression). Surfaced as a trailing block so the
|
|
740
|
+
* leading instruction line stays clean.
|
|
741
|
+
*/
|
|
742
|
+
export function manualRequestText(input: {
|
|
743
|
+
title?: string;
|
|
744
|
+
body?: string;
|
|
745
|
+
}): string {
|
|
746
|
+
const parts: string[] = [];
|
|
747
|
+
if (input.title) {
|
|
748
|
+
parts.push(`\nSuggested title: ${input.title}`);
|
|
749
|
+
}
|
|
750
|
+
if (input.body) {
|
|
751
|
+
parts.push(`\nSuggested body:\n${input.body}`);
|
|
752
|
+
}
|
|
753
|
+
return parts.join('');
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/** True if the arbiter's `main` currently contains `commitish` (work landed). */
|
|
757
|
+
export function arbiterMainContains(
|
|
758
|
+
cwd: string,
|
|
759
|
+
arbiter: string,
|
|
760
|
+
commitish: string,
|
|
761
|
+
env?: NodeJS.ProcessEnv,
|
|
762
|
+
): boolean {
|
|
763
|
+
run('git', ['fetch', '-q', arbiter], cwd, {env});
|
|
764
|
+
const res = run(
|
|
765
|
+
'git',
|
|
766
|
+
['merge-base', '--is-ancestor', commitish, `${arbiter}/main`],
|
|
767
|
+
cwd,
|
|
768
|
+
{env},
|
|
769
|
+
);
|
|
770
|
+
return res.status === 0;
|
|
771
|
+
}
|