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
package/src/git.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import {spawnSync, spawn} from 'node:child_process';
|
|
2
|
+
import {mkdirSync} from 'node:fs';
|
|
3
|
+
import {dirname} from 'node:path';
|
|
4
|
+
|
|
5
|
+
/** Result of running a git (or any) command. */
|
|
6
|
+
export interface RunResult {
|
|
7
|
+
status: number;
|
|
8
|
+
stdout: string;
|
|
9
|
+
stderr: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Run a command synchronously in `cwd`, capturing output. A non-zero exit is NOT
|
|
14
|
+
* thrown here — callers inspect `status` (claim.sh's exit codes are meaningful).
|
|
15
|
+
*/
|
|
16
|
+
export function run(
|
|
17
|
+
command: string,
|
|
18
|
+
args: string[],
|
|
19
|
+
cwd: string,
|
|
20
|
+
options: {input?: string; env?: NodeJS.ProcessEnv} = {},
|
|
21
|
+
): RunResult {
|
|
22
|
+
const result = spawnSync(command, args, {
|
|
23
|
+
cwd,
|
|
24
|
+
encoding: 'utf8',
|
|
25
|
+
input: options.input,
|
|
26
|
+
env: options.env ?? process.env,
|
|
27
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
28
|
+
});
|
|
29
|
+
if (result.error) {
|
|
30
|
+
throw new Error(`failed to spawn '${command}': ${result.error.message}`);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
status: result.status ?? -1,
|
|
34
|
+
stdout: result.stdout ?? '',
|
|
35
|
+
stderr: result.stderr ?? '',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Async variant of {@link run}: spawns the command WITHOUT blocking the event
|
|
41
|
+
* loop, so two awaited calls genuinely run concurrently. Used to verify the
|
|
42
|
+
* claim race the way claim.sh's own verification does (truly simultaneous).
|
|
43
|
+
*/
|
|
44
|
+
export function runAsync(
|
|
45
|
+
command: string,
|
|
46
|
+
args: string[],
|
|
47
|
+
cwd: string,
|
|
48
|
+
options: {input?: string; env?: NodeJS.ProcessEnv} = {},
|
|
49
|
+
): Promise<RunResult> {
|
|
50
|
+
return new Promise((resolvePromise, reject) => {
|
|
51
|
+
const child = spawn(command, args, {
|
|
52
|
+
cwd,
|
|
53
|
+
env: options.env ?? process.env,
|
|
54
|
+
});
|
|
55
|
+
let stdout = '';
|
|
56
|
+
let stderr = '';
|
|
57
|
+
child.stdout.on('data', (chunk: Buffer) => {
|
|
58
|
+
stdout += chunk.toString('utf8');
|
|
59
|
+
});
|
|
60
|
+
child.stderr.on('data', (chunk: Buffer) => {
|
|
61
|
+
stderr += chunk.toString('utf8');
|
|
62
|
+
});
|
|
63
|
+
child.on('error', (err) =>
|
|
64
|
+
reject(new Error(`failed to spawn '${command}': ${err.message}`)),
|
|
65
|
+
);
|
|
66
|
+
child.on('close', (code) => {
|
|
67
|
+
resolvePromise({status: code ?? -1, stdout, stderr});
|
|
68
|
+
});
|
|
69
|
+
if (options.input !== undefined) {
|
|
70
|
+
child.stdin.end(options.input);
|
|
71
|
+
} else {
|
|
72
|
+
child.stdin.end();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Run `git <args>` in `cwd`; throws on non-zero exit (use `run` for soft checks). */
|
|
78
|
+
export function git(
|
|
79
|
+
args: string[],
|
|
80
|
+
cwd: string,
|
|
81
|
+
options: {input?: string; env?: NodeJS.ProcessEnv} = {},
|
|
82
|
+
): string {
|
|
83
|
+
const result = run('git', args, cwd, options);
|
|
84
|
+
if (result.status !== 0) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`git ${args.join(' ')} failed (exit ${result.status}): ${result.stderr.trim()}`,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return result.stdout;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Move a tracked file with `git mv`, creating the destination directory first
|
|
94
|
+
* (`mkdir -p`). The `work/` contract requires this: git does not track empty
|
|
95
|
+
* dirs, so `work/done/` (or `work/in-progress/`) may not exist yet. No
|
|
96
|
+
* `.gitkeep` placeholders — the mover owns dir creation.
|
|
97
|
+
*/
|
|
98
|
+
export function gitMv(from: string, to: string, cwd: string): void {
|
|
99
|
+
mkdirSync(dirname(toAbsolute(cwd, to)), {recursive: true});
|
|
100
|
+
git(['mv', from, to], cwd);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function toAbsolute(cwd: string, p: string): string {
|
|
104
|
+
return p.startsWith('/') ? p : `${cwd}/${p}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The pre-flight DIVERGENCE check for the in-place ff paths (`do` /
|
|
109
|
+
* `complete --merge`): how many commits local `main` is AHEAD of
|
|
110
|
+
* `<arbiter>/main` (`git rev-list --count <arbiter>/main..main`). A non-zero
|
|
111
|
+
* count means local `main` carries UNPUSHED commits the arbiter lacks — the task
|
|
112
|
+
* builds off `<arbiter>/main`, so its merge-back ff cannot apply, exactly the
|
|
113
|
+
* "checkout state that breaks the in-place flow" class the dirty-tree refusal
|
|
114
|
+
* guards. Returns 0 when local `main` is at/behind the arbiter (safe).
|
|
115
|
+
*
|
|
116
|
+
* Best-effort / SAFE-direction: if either ref cannot be resolved (no local
|
|
117
|
+
* `main`, an unreachable arbiter that left `<arbiter>/main` absent) the count
|
|
118
|
+
* cannot be computed, so we read it as 0 (do NOT block on an unknown) — the
|
|
119
|
+
* caller is expected to have fetched first, and a genuinely diverged main is the
|
|
120
|
+
* case we DO catch. Read-only.
|
|
121
|
+
*/
|
|
122
|
+
export async function localMainAheadCount(
|
|
123
|
+
cwd: string,
|
|
124
|
+
arbiter: string,
|
|
125
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
126
|
+
): Promise<number> {
|
|
127
|
+
const res = await runAsync(
|
|
128
|
+
'git',
|
|
129
|
+
['rev-list', '--count', `${arbiter}/main..main`],
|
|
130
|
+
cwd,
|
|
131
|
+
{env},
|
|
132
|
+
);
|
|
133
|
+
if (res.status !== 0) {
|
|
134
|
+
return 0; // a ref did not resolve — cannot compute; do not block (safe).
|
|
135
|
+
}
|
|
136
|
+
const n = Number.parseInt(res.stdout.trim(), 10);
|
|
137
|
+
return Number.isFinite(n) ? n : 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** How far local `main` has diverged from `<arbiter>/main`, both directions. */
|
|
141
|
+
export interface LocalMainDivergence {
|
|
142
|
+
/** Commits on local `main` the arbiter lacks (UNPUSHED — `main-divergence-guard`). */
|
|
143
|
+
ahead: number;
|
|
144
|
+
/** Commits on `<arbiter>/main` the local `main` lacks (behind — needs a pull/rebase). */
|
|
145
|
+
behind: number;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Read the DIVERGENCE of local `main` vs `<arbiter>/main` in BOTH directions
|
|
150
|
+
* (`git rev-list --left-right --count <arbiter>/main...main`): `ahead` =
|
|
151
|
+
* unpushed local commits the arbiter lacks (the `main-divergence-guard`
|
|
152
|
+
* framing), `behind` = arbiter commits the local tree lacks. This is the honest
|
|
153
|
+
* expression of the LOCAL working tree's staleness relative to the arbiter — the
|
|
154
|
+
* source of truth — for the cwd-local section of `scan`/`status` (it labels the
|
|
155
|
+
* section as possibly ahead of / behind the fetched arbiter `main`).
|
|
156
|
+
*
|
|
157
|
+
* Best-effort / SAFE: if either ref cannot be resolved (no local `main`, an
|
|
158
|
+
* unreachable arbiter so `<arbiter>/main` is absent) the divergence cannot be
|
|
159
|
+
* computed, so it reads as `{ahead: 0, behind: 0}` (in sync) — never throws. The
|
|
160
|
+
* caller is expected to have fetched the arbiter first; a genuinely diverged
|
|
161
|
+
* `main` is the case we DO catch. Read-only.
|
|
162
|
+
*/
|
|
163
|
+
export async function localMainDivergence(
|
|
164
|
+
cwd: string,
|
|
165
|
+
arbiter: string,
|
|
166
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
167
|
+
): Promise<LocalMainDivergence> {
|
|
168
|
+
const res = await runAsync(
|
|
169
|
+
'git',
|
|
170
|
+
['rev-list', '--left-right', '--count', `${arbiter}/main...main`],
|
|
171
|
+
cwd,
|
|
172
|
+
{env},
|
|
173
|
+
);
|
|
174
|
+
if (res.status !== 0) {
|
|
175
|
+
return {ahead: 0, behind: 0}; // a ref did not resolve — read as in sync (safe).
|
|
176
|
+
}
|
|
177
|
+
// `--left-right --count A...B` prints `<behind>\t<ahead>` (left = A=arbiter
|
|
178
|
+
// commits B lacks = behind; right = B=local commits A lacks = ahead).
|
|
179
|
+
const parts = res.stdout.trim().split(/\s+/);
|
|
180
|
+
const behind = Number.parseInt(parts[0] ?? '', 10);
|
|
181
|
+
const ahead = Number.parseInt(parts[1] ?? '', 10);
|
|
182
|
+
return {
|
|
183
|
+
ahead: Number.isFinite(ahead) ? ahead : 0,
|
|
184
|
+
behind: Number.isFinite(behind) ? behind : 0,
|
|
185
|
+
};
|
|
186
|
+
}
|
package/src/github.ts
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import {run, type RunResult} from './git.js';
|
|
2
|
+
import {ghFailureDetail} from './gh-failure.js';
|
|
3
|
+
import {realSleep, retryWithBackoff} from './retry-backoff.js';
|
|
4
|
+
import {
|
|
5
|
+
NoneProvider,
|
|
6
|
+
manualRequestText,
|
|
7
|
+
type ReviewProvider,
|
|
8
|
+
type OpenRequestInput,
|
|
9
|
+
type OpenRequestResult,
|
|
10
|
+
type PostPRCommentInput,
|
|
11
|
+
type PostPRCommentOnBranchInput,
|
|
12
|
+
type PostPRCommentResult,
|
|
13
|
+
} from './integrator.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The **GitHub** integration provider (ADR §6 in
|
|
17
|
+
* `docs/adr/execution-substrate-decisions.md`): the concrete `propose`-mode
|
|
18
|
+
* review-request step, implemented by shelling out to the `gh` CLI.
|
|
19
|
+
*
|
|
20
|
+
* It fulfils the provider seam introduced by `agent-workspaces`
|
|
21
|
+
* (`./integrator.ts`, with its `none` provider). The contract that seam encodes
|
|
22
|
+
* is load-bearing here:
|
|
23
|
+
*
|
|
24
|
+
* - The **universal, safety-bearing action is `git push`** — done by the seam
|
|
25
|
+
* BEFORE the provider is asked to open a request (`Integrator.integrate`).
|
|
26
|
+
* So by the time `openRequest` runs the branch is already on the arbiter and
|
|
27
|
+
* the work is SAFE regardless of what `gh` does (ADR §4/§6).
|
|
28
|
+
* - Therefore this provider **NEVER hard-fails**: if `gh` is missing or
|
|
29
|
+
* unauthenticated it degrades to the `none` behaviour (branch pushed + print
|
|
30
|
+
* manual-PR instructions) rather than throwing — a provider failure must
|
|
31
|
+
* leave a safe, pushed branch, not lost work.
|
|
32
|
+
* - It **NEVER `--force`s** anything (the only force in the system is the claim
|
|
33
|
+
* micro-commit's `--force-with-lease` inside claim.sh).
|
|
34
|
+
*
|
|
35
|
+
* Selection is driven PURELY by the ARBITER URL: a GitHub remote auto-selects
|
|
36
|
+
* this provider; any other arbiter (local `--bare`, a non-GitHub host) defaults
|
|
37
|
+
* to `none` (see {@link selectProvider}). There is NO `provider` override axis —
|
|
38
|
+
* the provider is fully determined by the arbiter; whether `gh` can actually open
|
|
39
|
+
* a PR is the IDENTITY's `providers.github` auth (or ambient `gh` auth), checked
|
|
40
|
+
* by {@link GitHubProvider.available}. The separate "suppress the PR" intent is
|
|
41
|
+
* the `noPR` config axis, layered ON TOP of this arbiter-derived provider (it
|
|
42
|
+
* does NOT pick a provider).
|
|
43
|
+
*
|
|
44
|
+
* The core never imports `gh`; ONLY this adapter shells out to it (the `gh`
|
|
45
|
+
* invocation lives entirely behind the `ReviewProvider` seam). Tests stub `gh`
|
|
46
|
+
* via the injectable `ghBin` (no network, no real GitHub).
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The review-request providers dorfl knows about. This is the RETURN type
|
|
51
|
+
* of {@link selectProvider} (which provider the arbiter resolves to) — NOT a
|
|
52
|
+
* config OVERRIDE axis (there is none; the provider is purely arbiter-derived).
|
|
53
|
+
*/
|
|
54
|
+
export type ProviderName = 'none' | 'github';
|
|
55
|
+
|
|
56
|
+
/** The default `gh` CLI binary name (resolved on `PATH`). */
|
|
57
|
+
export const DEFAULT_GH_BIN = 'gh';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* True iff `url` is a GitHub arbiter remote, recognised across the URL shapes
|
|
61
|
+
* the arbiter can take (scp-like ssh `git@github.com:o/r.git`, `ssh://`,
|
|
62
|
+
* `https://`/`http://`). We match on the HOST being exactly `github.com` (or a
|
|
63
|
+
* `github.com` subdomain — GitHub Enterprise installs are out of scope and read
|
|
64
|
+
* as not-GitHub, the safe `none` default). A mere substring match is rejected so
|
|
65
|
+
* a lookalike host (`notgithub.com.evil`) never selects the GitHub provider.
|
|
66
|
+
*/
|
|
67
|
+
export function isGitHubArbiterUrl(url: string): boolean {
|
|
68
|
+
const host = arbiterHost(url);
|
|
69
|
+
if (host === undefined) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return host === 'github.com' || host.endsWith('.github.com');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Extract the bare host from an arbiter remote URL, or `undefined` for a local
|
|
77
|
+
* filesystem path (`file://...` / `/abs/path`) which has no host. Mirrors the
|
|
78
|
+
* `repo-mirror` URL handling (the four shapes the arbiter can take) but only
|
|
79
|
+
* needs the host for provider detection.
|
|
80
|
+
*/
|
|
81
|
+
function arbiterHost(url: string): string | undefined {
|
|
82
|
+
const trimmed = url.trim();
|
|
83
|
+
|
|
84
|
+
if (!trimmed.includes('://')) {
|
|
85
|
+
// scp-like ssh: [user@]host:path (no `://`, a `:` before the path, NOT a
|
|
86
|
+
// plain absolute local path).
|
|
87
|
+
const scp = /^(?:[^@/]+@)?([^/:]+):(.+)$/;
|
|
88
|
+
const m = scp.exec(trimmed);
|
|
89
|
+
if (m && !trimmed.startsWith('/')) {
|
|
90
|
+
return m[1].toLowerCase();
|
|
91
|
+
}
|
|
92
|
+
return undefined; // a plain local path has no host
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const rest = trimmed.slice(trimmed.indexOf('://') + 3);
|
|
96
|
+
const slash = rest.indexOf('/');
|
|
97
|
+
const authority = slash === -1 ? rest : rest.slice(0, slash);
|
|
98
|
+
const host = stripUserAndPort(authority).toLowerCase();
|
|
99
|
+
// `file://` yields an empty authority (file:///abs/path) → no host.
|
|
100
|
+
return host === '' ? undefined : host;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Drop `user@` and `:port` from an authority, leaving the bare host. */
|
|
104
|
+
function stripUserAndPort(authority: string): string {
|
|
105
|
+
const afterUser = authority.includes('@')
|
|
106
|
+
? authority.slice(authority.lastIndexOf('@') + 1)
|
|
107
|
+
: authority;
|
|
108
|
+
const colon = afterUser.indexOf(':');
|
|
109
|
+
return colon === -1 ? afterUser : afterUser.slice(0, colon);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface SelectProviderOptions {
|
|
113
|
+
/**
|
|
114
|
+
* The arbiter remote URL (the SOLE determinant of the provider). `undefined`
|
|
115
|
+
* when it cannot be resolved — detection then yields `none` (the safe default).
|
|
116
|
+
*/
|
|
117
|
+
arbiterUrl?: string;
|
|
118
|
+
/** The `gh` CLI binary the GitHub provider invokes (tests inject a stub). */
|
|
119
|
+
ghBin?: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Resolve the review-request provider for an integration (ADR §6), PURELY from
|
|
124
|
+
* the arbiter URL — there is NO override axis:
|
|
125
|
+
*
|
|
126
|
+
* - a `github.com` arbiter URL ⇒ the GitHub provider, else
|
|
127
|
+
* - the `none` provider (the safe default for unknown / local `--bare`
|
|
128
|
+
* arbiters, which have no review concept).
|
|
129
|
+
*
|
|
130
|
+
* The GitHub provider degrades to `none` behaviour at RUNTIME when `gh` is
|
|
131
|
+
* absent/unauthenticated (so it is safe to select it on URL alone — the work is
|
|
132
|
+
* already pushed by the seam, ADR §6); this keeps SELECTION a pure, testable
|
|
133
|
+
* function of the arbiter URL. The orthogonal "do not open a PR" INTENT is the
|
|
134
|
+
* `noPR` config axis (handled by the caller, layered on top — it does NOT pick a
|
|
135
|
+
* provider here), and whether `gh` is authed to actually open the PR is the
|
|
136
|
+
* identity's `providers.github` / ambient `gh` auth.
|
|
137
|
+
*/
|
|
138
|
+
export function selectProvider(options: SelectProviderOptions): ReviewProvider {
|
|
139
|
+
if (options.arbiterUrl && isGitHubArbiterUrl(options.arbiterUrl)) {
|
|
140
|
+
return new GitHubProvider({ghBin: options.ghBin});
|
|
141
|
+
}
|
|
142
|
+
return new NoneProvider();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface GitHubProviderOptions {
|
|
146
|
+
/**
|
|
147
|
+
* The `gh` CLI binary (default `gh` on `PATH`). Tests inject a stub script so
|
|
148
|
+
* the seam is exercised without a real model / network / GitHub.
|
|
149
|
+
*/
|
|
150
|
+
ghBin?: string;
|
|
151
|
+
/** The base branch PRs target. Default `main`. */
|
|
152
|
+
base?: string;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The GitHub provider: opens a PR for an already-pushed `work/<slug>` branch via
|
|
157
|
+
* `gh pr create`. It NEVER hard-fails — a missing/unauthenticated `gh` degrades
|
|
158
|
+
* to the `none` behaviour (the branch is already pushed; print manual-PR
|
|
159
|
+
* instructions) — and NEVER `--force`s anything. The created PR URL is parsed
|
|
160
|
+
* from `gh`'s stdout and returned so the caller can record it.
|
|
161
|
+
*/
|
|
162
|
+
export class GitHubProvider implements ReviewProvider {
|
|
163
|
+
readonly name = 'github';
|
|
164
|
+
private readonly ghBin: string;
|
|
165
|
+
private readonly base: string;
|
|
166
|
+
|
|
167
|
+
constructor(options: GitHubProviderOptions = {}) {
|
|
168
|
+
this.ghBin = options.ghBin ?? DEFAULT_GH_BIN;
|
|
169
|
+
this.base = options.base ?? 'main';
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Open a PR for `input.branch` via `gh pr create --base main --head <branch>`,
|
|
174
|
+
* passing an explicit `--title`/`--body` when the caller supplied them (the
|
|
175
|
+
* synthesised single-line title + the agent's summary body) and falling back to
|
|
176
|
+
* `--fill` ONLY when BOTH are absent (today's behaviour — no regression). A
|
|
177
|
+
* partial set (one present) still drops `--fill`: `--fill` and an explicit
|
|
178
|
+
* `--title`/`--body` are mutually exclusive to `gh`, so once we override either
|
|
179
|
+
* field we must supply both explicitly (the other defaults to the slug-derived
|
|
180
|
+
* title / an empty body rather than re-deriving a run-on subject). The branch
|
|
181
|
+
* is GUARANTEED to be on the arbiter already (the push is the seam's safety-
|
|
182
|
+
* bearing step), so any `gh` failure is non-fatal: we fall back to the same
|
|
183
|
+
* manual-instructions result the `none` provider returns. On success we parse
|
|
184
|
+
* the PR URL `gh` prints and surface it (recorded by the caller into the job
|
|
185
|
+
* record / `status`).
|
|
186
|
+
*/
|
|
187
|
+
async openRequest(input: OpenRequestInput): Promise<OpenRequestResult> {
|
|
188
|
+
const args = [
|
|
189
|
+
'pr',
|
|
190
|
+
'create',
|
|
191
|
+
'--base',
|
|
192
|
+
this.base,
|
|
193
|
+
'--head',
|
|
194
|
+
input.branch,
|
|
195
|
+
...prCreateContentArgs(input),
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
// First attempt. A non-zero / missing `gh` can mean two VERY different things:
|
|
199
|
+
// - DETERMINISTIC: `gh` is missing or unauthenticated — retrying is pointless
|
|
200
|
+
// (every attempt fails identically); degrade IMMEDIATELY (today's
|
|
201
|
+
// behaviour, no wasted backoff).
|
|
202
|
+
// - TRANSIENT (OUTAGE): `gh` is present + authed but the network/API is down
|
|
203
|
+
// — RETRY with bounded backoff (the same shared helper the push uses)
|
|
204
|
+
// before degrading. This is a LOW-severity mode: the branch is already
|
|
205
|
+
// pushed (the seam's safety step), so the work is safe — only the review
|
|
206
|
+
// surface is missing. We do NOT gate requeue on it.
|
|
207
|
+
const first = this.runGh(args, input.cwd, input.env);
|
|
208
|
+
if (first !== undefined && first.status === 0) {
|
|
209
|
+
return this.parseOpened(input, first);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Failed once — distinguish DETERMINISTIC (missing/unauth) from a TRANSIENT
|
|
213
|
+
// outage by an availability probe. Missing/unauth ⇒ degrade now (no retry).
|
|
214
|
+
// Thread the FAILED first attempt so the degrade surfaces the REAL `gh` cause
|
|
215
|
+
// (its stderr / the missing-binary detail), not a hard-coded auth guess.
|
|
216
|
+
//
|
|
217
|
+
// NOTE (degrade NARROWED): for a propose-with-PR-intent run (`noPR` unset) the
|
|
218
|
+
// start-of-run "`gh` unavailable/unauthed" case is now caught UP FRONT by the
|
|
219
|
+
// pre-flight `gh` auth probe (see `do.ts`'s pre-flight guard / `selectProvider`
|
|
220
|
+
// docs), so it never reaches this point as a silent degrade. The legitimate
|
|
221
|
+
// callers that still land here are: `noPR: true` (intended push-only — the
|
|
222
|
+
// caller does not even pass a GitHub provider, so this is moot), and a `gh`
|
|
223
|
+
// that went away AFTER a passing up-front probe (a transient mid-run loss).
|
|
224
|
+
if (!this.available(input.cwd, input.env)) {
|
|
225
|
+
return this.degrade(input, 'unavailable', first);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// `gh` IS available but the create failed — a transient outage. Retry the
|
|
229
|
+
// create with bounded backoff before a clean give-up into the OUTAGE degrade.
|
|
230
|
+
const attempt = await retryWithBackoff(
|
|
231
|
+
async () => {
|
|
232
|
+
const r = this.runGh(args, input.cwd, input.env);
|
|
233
|
+
if (r !== undefined && r.status === 0) {
|
|
234
|
+
return {ok: true as const, value: r};
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
ok: false as const,
|
|
238
|
+
error: r?.stderr.trim() || 'gh pr create failed',
|
|
239
|
+
};
|
|
240
|
+
},
|
|
241
|
+
{sleep: input.sleep ?? realSleep, ...input.backoff},
|
|
242
|
+
);
|
|
243
|
+
if (!attempt.ok) {
|
|
244
|
+
return this.degrade(input, 'outage');
|
|
245
|
+
}
|
|
246
|
+
return this.parseOpened(input, attempt.value);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** Map a successful `gh pr create` RunResult to an OpenRequestResult. */
|
|
250
|
+
private parseOpened(
|
|
251
|
+
input: OpenRequestInput,
|
|
252
|
+
result: RunResult,
|
|
253
|
+
): OpenRequestResult {
|
|
254
|
+
const url = parsePrUrl(result.stdout);
|
|
255
|
+
if (url === undefined) {
|
|
256
|
+
// gh succeeded but we could not parse a URL — still treat the PR as
|
|
257
|
+
// opened (gh exited 0) but fall back to a generic confirmation.
|
|
258
|
+
return {
|
|
259
|
+
opened: true,
|
|
260
|
+
instruction: `Opened a GitHub PR for ${input.branch}.`,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
opened: true,
|
|
265
|
+
url,
|
|
266
|
+
instruction: `Opened a GitHub PR for ${input.branch}: ${url}`,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Post a follow-up COMMENT on an already-opened PR via
|
|
272
|
+
* `gh pr comment <url> --body <text>` (task `review-gate-pr-comment`),
|
|
273
|
+
* threading the PR by the `url` {@link openRequest} returned. The PR already
|
|
274
|
+
* exists (this runs AFTER the propose integrate), so any `gh` failure is
|
|
275
|
+
* non-fatal: a missing/unauthenticated `gh` DEGRADES to the same surface-the-
|
|
276
|
+
* text result the `none` provider returns — NEVER throws (ADR §6). The comment
|
|
277
|
+
* is ADVISORY: it changes no gate/verdict/merge logic. NEVER `--force`s.
|
|
278
|
+
*/
|
|
279
|
+
postPRComment(input: PostPRCommentInput): PostPRCommentResult {
|
|
280
|
+
const result = this.runGh(
|
|
281
|
+
['pr', 'comment', input.url, '--body', input.body],
|
|
282
|
+
input.cwd,
|
|
283
|
+
input.env,
|
|
284
|
+
);
|
|
285
|
+
// gh missing (spawn failed) OR non-zero exit (e.g. unauthenticated): the PR
|
|
286
|
+
// already exists and the review is in the run output, so degrade gracefully
|
|
287
|
+
// — NEVER throw (the comment is advisory; a failure must not lose work).
|
|
288
|
+
if (result === undefined || result.status !== 0) {
|
|
289
|
+
// Surface the REAL `gh` cause (its stderr, with the missing-binary special
|
|
290
|
+
// case) — NOT a hard-coded "unavailable or unauthenticated" guess that sends
|
|
291
|
+
// the operator chasing a phantom auth problem (mirrors `issue-provider.ts`).
|
|
292
|
+
const reason = ghFailureDetail(result);
|
|
293
|
+
return {
|
|
294
|
+
posted: false,
|
|
295
|
+
instruction:
|
|
296
|
+
`${reason} The review was not posted as a comment on ` +
|
|
297
|
+
`${input.url}. The review:\n${input.body}`,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
posted: true,
|
|
302
|
+
instruction: `Posted the review as a comment on ${input.url}.`,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Post the review comment by RESOLVING the PR from the pushed `work/<slug>`
|
|
308
|
+
* BRANCH (task `review-comment-fallback-on-unparsed-pr-url`), the FALLBACK for
|
|
309
|
+
* when `gh pr create` opened a PR (exit 0) but its stdout url was unparseable so
|
|
310
|
+
* {@link openRequest} returned `{opened: true}` with NO `url`. We first RESOLVE
|
|
311
|
+
* the open PR's url from the branch (`gh pr view <branch> --json url --jq .url`):
|
|
312
|
+
*
|
|
313
|
+
* - a url comes back ⇒ a PR genuinely exists — post the comment on it via the
|
|
314
|
+
* url-keyed {@link postPRComment} (the audit trail is preserved);
|
|
315
|
+
* - nothing resolvable (no PR for the branch, or `gh` missing/unauthenticated)
|
|
316
|
+
* ⇒ an HONEST clean no-op (`posted: false`) — but only AFTER trying. The
|
|
317
|
+
* "no PR ⇒ no comment" rule holds; what changes is we no longer drop the
|
|
318
|
+
* comment when a PR DID open.
|
|
319
|
+
*
|
|
320
|
+
* Resolving the url first (rather than commenting on the branch directly) keeps
|
|
321
|
+
* the no-PR case a deterministic no-op and reuses the exact same comment
|
|
322
|
+
* mechanics as the url path. NEVER throws, NEVER `--force`s (ADR §6).
|
|
323
|
+
*/
|
|
324
|
+
postPRCommentOnBranch(
|
|
325
|
+
input: PostPRCommentOnBranchInput,
|
|
326
|
+
): PostPRCommentResult {
|
|
327
|
+
const url = this.resolvePrUrlForBranch(input.branch, input.cwd, input.env);
|
|
328
|
+
if (url === undefined) {
|
|
329
|
+
// No PR resolvable from the branch (truly none, or `gh` unavailable): an
|
|
330
|
+
// honest no-op — but only after trying. Surface the review text so it is
|
|
331
|
+
// never lost; nothing was posted.
|
|
332
|
+
return {
|
|
333
|
+
posted: false,
|
|
334
|
+
instruction:
|
|
335
|
+
`No open PR could be resolved for ${input.branch}, so the review ` +
|
|
336
|
+
`was not posted as a comment. The review:\n${input.body}`,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
// A PR genuinely exists for the branch — comment on it via the url path.
|
|
340
|
+
return this.postPRComment({
|
|
341
|
+
cwd: input.cwd,
|
|
342
|
+
url,
|
|
343
|
+
body: input.body,
|
|
344
|
+
env: input.env,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Resolve the open PR's url for `branch` via `gh pr view <branch> --json url
|
|
350
|
+
* --jq .url`, or `undefined` when no PR is found / `gh` is missing or
|
|
351
|
+
* unauthenticated (a non-zero exit or a spawn failure). Read-only; mutates
|
|
352
|
+
* nothing. The result is parsed for a PR url (any surrounding chatter ignored)
|
|
353
|
+
* so a stray warning line never defeats the resolution.
|
|
354
|
+
*/
|
|
355
|
+
private resolvePrUrlForBranch(
|
|
356
|
+
branch: string,
|
|
357
|
+
cwd: string,
|
|
358
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
359
|
+
): string | undefined {
|
|
360
|
+
const result = this.runGh(
|
|
361
|
+
['pr', 'view', branch, '--json', 'url', '--jq', '.url'],
|
|
362
|
+
cwd,
|
|
363
|
+
env,
|
|
364
|
+
);
|
|
365
|
+
if (result === undefined || result.status !== 0) {
|
|
366
|
+
return undefined; // no PR for the branch, or gh missing/unauthenticated
|
|
367
|
+
}
|
|
368
|
+
return parsePrUrl(result.stdout);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Is `gh` available AND authenticated (so a PR can actually be opened)?
|
|
373
|
+
* `gh auth status` exits 0 when authenticated. A missing `gh` (spawn failure)
|
|
374
|
+
* or a non-zero exit both read as unavailable. Read-only; mutates nothing.
|
|
375
|
+
*/
|
|
376
|
+
available(cwd: string, env?: NodeJS.ProcessEnv): boolean {
|
|
377
|
+
const result = this.runGh(['auth', 'status'], cwd, env);
|
|
378
|
+
return result !== undefined && result.status === 0;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Run `gh <args>` in `cwd`, returning the result, or `undefined` when `gh`
|
|
383
|
+
* cannot even be spawned (binary missing). `run` throws on a spawn error; we
|
|
384
|
+
* catch it here so a missing `gh` degrades rather than crashing the runner.
|
|
385
|
+
*/
|
|
386
|
+
private runGh(
|
|
387
|
+
args: string[],
|
|
388
|
+
cwd: string,
|
|
389
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
390
|
+
): RunResult | undefined {
|
|
391
|
+
try {
|
|
392
|
+
return run(this.ghBin, args, cwd, {env});
|
|
393
|
+
} catch {
|
|
394
|
+
return undefined; // gh binary not found / not executable
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* The graceful-degradation result (identical SHAPE to the `none` provider's):
|
|
400
|
+
* the branch is already pushed (safe), only the PR is missing. The `reason`
|
|
401
|
+
* distinguishes the two LOW-severity degrade causes so the operator knows what
|
|
402
|
+
* to do: `unavailable` (`gh` missing/unauth — fix `gh`/auth) vs `outage`
|
|
403
|
+
* (transient network/API failure that survived the bounded retry — just re-run
|
|
404
|
+
* / open it manually). Both print the SAME manual `gh pr create` suggestion.
|
|
405
|
+
*/
|
|
406
|
+
private degrade(
|
|
407
|
+
input: OpenRequestInput,
|
|
408
|
+
reason: 'unavailable' | 'outage',
|
|
409
|
+
/**
|
|
410
|
+
* The FAILED `gh pr create` result that triggered the `unavailable` degrade
|
|
411
|
+
* (`undefined` = `gh` binary missing). Threaded in so the `unavailable` arm
|
|
412
|
+
* surfaces the REAL cause rather than a hard-coded auth guess. The `outage`
|
|
413
|
+
* arm does not need it (its wording is already honest about the retried
|
|
414
|
+
* transient failure).
|
|
415
|
+
*/
|
|
416
|
+
result?: RunResult,
|
|
417
|
+
): OpenRequestResult {
|
|
418
|
+
// Echo the explicit title/body in the suggested manual command when present,
|
|
419
|
+
// so a human opening the PR by hand reuses the same content the autonomous
|
|
420
|
+
// path would have set (else fall back to the bare `--fill` suggestion).
|
|
421
|
+
const contentArgs = prCreateContentArgs(input);
|
|
422
|
+
const suggestion =
|
|
423
|
+
`gh pr create --base ${this.base} --head ${input.branch} ${contentArgs.join(' ')}`.trim();
|
|
424
|
+
const cause =
|
|
425
|
+
reason === 'outage'
|
|
426
|
+
? '`gh pr create` failed after retries (a transient outage), so no PR ' +
|
|
427
|
+
'was opened — the branch is pushed and the work is SAFE; re-run or ' +
|
|
428
|
+
'open one manually, e.g. '
|
|
429
|
+
: // Surface the REAL `gh` cause (its stderr, with the missing-binary
|
|
430
|
+
// special case) — NOT a hard-coded "unavailable or unauthenticated"
|
|
431
|
+
// guess (mirrors `issue-provider.ts`).
|
|
432
|
+
`${ghFailureDetail(result)} No PR was opened — open one manually, e.g. `;
|
|
433
|
+
return {
|
|
434
|
+
opened: false,
|
|
435
|
+
instruction:
|
|
436
|
+
`Pushed ${input.branch} to ${input.arbiter}. ${cause}` +
|
|
437
|
+
`\`${suggestion}\`.` +
|
|
438
|
+
manualRequestText(input),
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* The CONTENT args for `gh pr create`: an explicit `--title`/`--body` when the
|
|
445
|
+
* caller supplied either (a partial set is completed so `--fill` is never mixed
|
|
446
|
+
* with an explicit field — `gh` forbids that), else the lone `--fill` (today's
|
|
447
|
+
* behaviour, no regression). Returned as a flat arg array so both the live
|
|
448
|
+
* invocation and the degraded suggestion build from one source of truth.
|
|
449
|
+
*/
|
|
450
|
+
export function prCreateContentArgs(input: {
|
|
451
|
+
title?: string;
|
|
452
|
+
body?: string;
|
|
453
|
+
}): string[] {
|
|
454
|
+
if (input.title === undefined && input.body === undefined) {
|
|
455
|
+
return ['--fill'];
|
|
456
|
+
}
|
|
457
|
+
return ['--title', input.title ?? '', '--body', input.body ?? ''];
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Parse the PR URL `gh pr create` prints to stdout. `gh` prints the PR URL as a
|
|
462
|
+
* line (often the only/last line); we pick the first GitHub PR URL we find. Any
|
|
463
|
+
* surrounding chatter is ignored. Returns `undefined` when no URL is present.
|
|
464
|
+
*/
|
|
465
|
+
function parsePrUrl(stdout: string): string | undefined {
|
|
466
|
+
const match = stdout.match(/https?:\/\/\S+\/pull\/\d+/);
|
|
467
|
+
return match ? match[0] : undefined;
|
|
468
|
+
}
|