dorfl 0.1.1 → 0.2.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 +3 -3
- package/dist/advance-ci-template.js +1 -1
- package/dist/advance-ci-template.js.map +1 -1
- package/dist/advance-classify.d.ts +5 -5
- package/dist/advance-classify.d.ts.map +1 -1
- package/dist/advance-classify.js +4 -4
- package/dist/advance-drivers.d.ts +8 -8
- package/dist/advance-drivers.d.ts.map +1 -1
- package/dist/advance-drivers.js +20 -8
- package/dist/advance-drivers.js.map +1 -1
- package/dist/advance-isolated.d.ts +3 -3
- package/dist/advance-isolated.d.ts.map +1 -1
- package/dist/advance-isolated.js +1 -1
- package/dist/advance-lifecycle-template.d.ts +2 -2
- package/dist/advance-lifecycle-template.d.ts.map +1 -1
- package/dist/advance-lifecycle-template.js +85 -13
- package/dist/advance-lifecycle-template.js.map +1 -1
- package/dist/advance-loop-driver.d.ts +3 -3
- package/dist/advance-loop-driver.d.ts.map +1 -1
- package/dist/advance-loop-driver.js +1 -1
- package/dist/advance-treeless-publish.d.ts +24 -1
- package/dist/advance-treeless-publish.d.ts.map +1 -1
- package/dist/advance-treeless-publish.js +41 -0
- package/dist/advance-treeless-publish.js.map +1 -1
- package/dist/advance.d.ts +69 -17
- package/dist/advance.d.ts.map +1 -1
- package/dist/advance.js +409 -102
- package/dist/advance.js.map +1 -1
- package/dist/advancing-lock.d.ts +31 -3
- package/dist/advancing-lock.d.ts.map +1 -1
- package/dist/advancing-lock.js +55 -5
- package/dist/advancing-lock.js.map +1 -1
- package/dist/agent-launch.d.ts +12 -0
- package/dist/agent-launch.d.ts.map +1 -1
- package/dist/agent-launch.js +22 -12
- package/dist/agent-launch.js.map +1 -1
- package/dist/agent-stop.d.ts +40 -2
- package/dist/agent-stop.d.ts.map +1 -1
- package/dist/agent-stop.js +30 -2
- package/dist/agent-stop.js.map +1 -1
- package/dist/apply-decide.d.ts +19 -5
- package/dist/apply-decide.d.ts.map +1 -1
- package/dist/apply-decide.js +38 -9
- package/dist/apply-decide.js.map +1 -1
- package/dist/apply-merge-action.d.ts +20 -8
- package/dist/apply-merge-action.d.ts.map +1 -1
- package/dist/apply-merge-action.js +44 -9
- package/dist/apply-merge-action.js.map +1 -1
- package/dist/apply-persist.d.ts +62 -31
- package/dist/apply-persist.d.ts.map +1 -1
- package/dist/apply-persist.js +173 -44
- package/dist/apply-persist.js.map +1 -1
- package/dist/apply-stuck-action.d.ts +151 -0
- package/dist/apply-stuck-action.d.ts.map +1 -0
- package/dist/apply-stuck-action.js +125 -0
- package/dist/apply-stuck-action.js.map +1 -0
- package/dist/brand.d.ts +12 -1
- package/dist/brand.d.ts.map +1 -1
- package/dist/brand.js +2 -1
- package/dist/brand.js.map +1 -1
- package/dist/buildable-body.d.ts +14 -14
- package/dist/buildable-body.js +9 -9
- package/dist/claim-cas.d.ts +3 -3
- package/dist/claim-cas.js +1 -1
- package/dist/claim-cas.js.map +1 -1
- package/dist/cli-spinner.d.ts +1 -1
- package/dist/cli-spinner.js +1 -1
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +385 -128
- package/dist/cli.js.map +1 -1
- package/dist/close-job-template.d.ts +3 -3
- package/dist/close-job-template.js +9 -9
- package/dist/close-job.d.ts +8 -8
- package/dist/close-job.js +25 -25
- package/dist/close-job.js.map +1 -1
- package/dist/complete.d.ts +9 -6
- package/dist/complete.d.ts.map +1 -1
- package/dist/complete.js +99 -45
- package/dist/complete.js.map +1 -1
- package/dist/concurrency.d.ts +1 -1
- package/dist/concurrency.js +1 -1
- package/dist/config.d.ts +86 -40
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +61 -9
- package/dist/config.js.map +1 -1
- package/dist/continue-branch.d.ts +1 -1
- package/dist/continue-branch.d.ts.map +1 -1
- package/dist/continue-branch.js +23 -1
- package/dist/continue-branch.js.map +1 -1
- package/dist/cwd-section.js +1 -1
- package/dist/cwd-section.js.map +1 -1
- package/dist/decision-engine.d.ts +39 -11
- package/dist/decision-engine.d.ts.map +1 -1
- package/dist/decision-engine.js +10 -6
- package/dist/decision-engine.js.map +1 -1
- package/dist/do-autopick.d.ts +6 -6
- package/dist/do-autopick.d.ts.map +1 -1
- package/dist/do-autopick.js +16 -6
- package/dist/do-autopick.js.map +1 -1
- package/dist/do-config.d.ts +4 -4
- package/dist/do-config.js +3 -3
- package/dist/do-config.js.map +1 -1
- package/dist/do-remote-auto.d.ts +2 -2
- package/dist/do-remote-auto.js +1 -1
- package/dist/do.d.ts +74 -81
- package/dist/do.d.ts.map +1 -1
- package/dist/do.js +439 -50
- package/dist/do.js.map +1 -1
- package/dist/drop-source.d.ts +2 -2
- package/dist/env-config.d.ts.map +1 -1
- package/dist/env-config.js +19 -11
- package/dist/env-config.js.map +1 -1
- package/dist/failure-cause.d.ts +3 -2
- package/dist/failure-cause.d.ts.map +1 -1
- package/dist/failure-cause.js +28 -1
- package/dist/failure-cause.js.map +1 -1
- package/dist/format.d.ts +6 -6
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +13 -30
- package/dist/format.js.map +1 -1
- package/dist/frontmatter.d.ts +28 -15
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +38 -24
- package/dist/frontmatter.js.map +1 -1
- package/dist/gc.d.ts +65 -6
- package/dist/gc.d.ts.map +1 -1
- package/dist/gc.js +126 -9
- package/dist/gc.js.map +1 -1
- package/dist/github.d.ts +14 -0
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +73 -0
- package/dist/github.js.map +1 -1
- package/dist/harness.d.ts +25 -0
- package/dist/harness.d.ts.map +1 -1
- package/dist/harness.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/install-ci-branch-protection.d.ts +133 -39
- package/dist/install-ci-branch-protection.d.ts.map +1 -1
- package/dist/install-ci-branch-protection.js +191 -49
- package/dist/install-ci-branch-protection.js.map +1 -1
- package/dist/install-ci-capabilities/advance-lifecycle.d.ts +1 -1
- package/dist/install-ci-capabilities/advance-lifecycle.js +1 -1
- package/dist/install-ci-capabilities/close-job.d.ts +1 -1
- package/dist/install-ci-capabilities/close-job.js +1 -1
- package/dist/install-ci-capabilities/example-noop.d.ts +1 -1
- package/dist/install-ci-capabilities/example-noop.js +1 -1
- package/dist/install-ci-capabilities/intake.d.ts +2 -2
- package/dist/install-ci-capabilities/intake.js +2 -2
- package/dist/install-ci-capabilities/verify.d.ts +1 -1
- package/dist/install-ci-capabilities/verify.js +1 -1
- package/dist/install-ci-core.d.ts +24 -4
- package/dist/install-ci-core.d.ts.map +1 -1
- package/dist/install-ci-core.js +12 -5
- package/dist/install-ci-core.js.map +1 -1
- package/dist/install-ci-github.d.ts +33 -1
- package/dist/install-ci-github.d.ts.map +1 -1
- package/dist/install-ci-github.js +74 -1
- package/dist/install-ci-github.js.map +1 -1
- package/dist/install-ci.d.ts +1 -1
- package/dist/install-ci.js +4 -4
- package/dist/install-ci.js.map +1 -1
- package/dist/install-skills.d.ts +123 -0
- package/dist/install-skills.d.ts.map +1 -0
- package/dist/install-skills.js +100 -0
- package/dist/install-skills.js.map +1 -0
- package/dist/intake-event.d.ts +6 -6
- package/dist/intake-event.js +6 -6
- package/dist/intake-marker.d.ts +3 -3
- package/dist/intake-marker.d.ts.map +1 -1
- package/dist/intake-triage.d.ts +1 -1
- package/dist/intake-triage.js +2 -2
- package/dist/intake-trigger-template.d.ts +8 -8
- package/dist/intake-trigger-template.d.ts.map +1 -1
- package/dist/intake-trigger-template.js +17 -17
- package/dist/intake-trigger-template.js.map +1 -1
- package/dist/intake.d.ts +65 -52
- package/dist/intake.d.ts.map +1 -1
- package/dist/intake.js +92 -76
- package/dist/intake.js.map +1 -1
- package/dist/integration-core.d.ts +27 -24
- package/dist/integration-core.d.ts.map +1 -1
- package/dist/integration-core.js +191 -77
- package/dist/integration-core.js.map +1 -1
- package/dist/integrator.d.ts +1 -1
- package/dist/integrator.d.ts.map +1 -1
- package/dist/integrator.js +19 -3
- package/dist/integrator.js.map +1 -1
- package/dist/isolation.d.ts +4 -4
- package/dist/isolation.d.ts.map +1 -1
- package/dist/isolation.js +9 -0
- package/dist/isolation.js.map +1 -1
- package/dist/issue-provider.d.ts +4 -4
- package/dist/issue-provider.js +1 -1
- package/dist/item-lock.d.ts +216 -149
- package/dist/item-lock.d.ts.map +1 -1
- package/dist/item-lock.js +345 -270
- package/dist/item-lock.js.map +1 -1
- package/dist/item-path.d.ts +2 -2
- package/dist/item-path.js +2 -2
- package/dist/ledger-lint.d.ts +9 -9
- package/dist/ledger-lint.js +9 -9
- package/dist/ledger-read.d.ts +57 -57
- package/dist/ledger-read.d.ts.map +1 -1
- package/dist/ledger-read.js +24 -24
- package/dist/ledger-read.js.map +1 -1
- package/dist/ledger-write.d.ts +33 -28
- package/dist/ledger-write.d.ts.map +1 -1
- package/dist/ledger-write.js +100 -122
- package/dist/ledger-write.js.map +1 -1
- package/dist/lifecycle-gather.d.ts +18 -1
- package/dist/lifecycle-gather.d.ts.map +1 -1
- package/dist/lifecycle-gather.js +23 -17
- package/dist/lifecycle-gather.js.map +1 -1
- package/dist/lifecycle-pools.d.ts +44 -7
- package/dist/lifecycle-pools.d.ts.map +1 -1
- package/dist/lifecycle-pools.js +27 -7
- package/dist/lifecycle-pools.js.map +1 -1
- package/dist/merge-question-surfacer.d.ts +18 -4
- package/dist/merge-question-surfacer.d.ts.map +1 -1
- package/dist/merge-question-surfacer.js +20 -5
- package/dist/merge-question-surfacer.js.map +1 -1
- package/dist/migrate-stuck-locks.d.ts +129 -0
- package/dist/migrate-stuck-locks.d.ts.map +1 -0
- package/dist/migrate-stuck-locks.js +355 -0
- package/dist/migrate-stuck-locks.js.map +1 -0
- package/dist/mint-adr.js +4 -4
- package/dist/mirror-pool-scan.d.ts +2 -2
- package/dist/mirror-pool-scan.js +3 -3
- package/dist/mirror-pool-scan.js.map +1 -1
- package/dist/needs-attention.d.ts +304 -27
- package/dist/needs-attention.d.ts.map +1 -1
- package/dist/needs-attention.js +542 -67
- package/dist/needs-attention.js.map +1 -1
- package/dist/orphan-sidecar.d.ts +10 -6
- package/dist/orphan-sidecar.d.ts.map +1 -1
- package/dist/orphan-sidecar.js +35 -2
- package/dist/orphan-sidecar.js.map +1 -1
- package/dist/pi-harness.d.ts +16 -0
- package/dist/pi-harness.d.ts.map +1 -1
- package/dist/pi-harness.js +82 -2
- package/dist/pi-harness.js.map +1 -1
- package/dist/placement.d.ts +8 -8
- package/dist/placement.js +3 -3
- package/dist/prd-to-spec.d.ts.map +1 -1
- package/dist/prd-to-spec.js +9 -5
- package/dist/prd-to-spec.js.map +1 -1
- package/dist/prompt.d.ts +16 -19
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +17 -19
- package/dist/prompt.js.map +1 -1
- package/dist/protocol/CLAIM-PROTOCOL.md +17 -10
- package/dist/protocol/REVIEW-PROTOCOL.md +4 -1
- package/dist/protocol/SURFACE-PROTOCOL.md +16 -2
- package/dist/protocol/TASKING-PROTOCOL.md +3 -1
- package/dist/protocol/WORK-CONTRACT.md +22 -18
- package/dist/protocol/task-template.md +1 -1
- package/dist/readiness.d.ts +1 -1
- package/dist/reap-branches.d.ts +12 -9
- package/dist/reap-branches.d.ts.map +1 -1
- package/dist/reap-branches.js +25 -7
- package/dist/reap-branches.js.map +1 -1
- package/dist/recover-isolated.d.ts +12 -0
- package/dist/recover-isolated.d.ts.map +1 -1
- package/dist/recover-isolated.js +6 -1
- package/dist/recover-isolated.js.map +1 -1
- package/dist/repo-config.d.ts +23 -2
- package/dist/repo-config.d.ts.map +1 -1
- package/dist/repo-config.js +64 -18
- package/dist/repo-config.js.map +1 -1
- package/dist/repo-mirror.d.ts.map +1 -1
- package/dist/repo-mirror.js +18 -2
- package/dist/repo-mirror.js.map +1 -1
- package/dist/review-gate.d.ts +3 -3
- package/dist/review-gate.d.ts.map +1 -1
- package/dist/review-gate.js +11 -10
- package/dist/review-gate.js.map +1 -1
- package/dist/review-verdict.d.ts +2 -2
- package/dist/review-verdict.d.ts.map +1 -1
- package/dist/review-verdict.js +2 -2
- package/dist/review-verdict.js.map +1 -1
- package/dist/run.d.ts +2 -2
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +58 -23
- package/dist/run.js.map +1 -1
- package/dist/scan.d.ts +26 -17
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +29 -15
- package/dist/scan.js.map +1 -1
- package/dist/select-order.d.ts +1 -1
- package/dist/select-priority.d.ts +14 -14
- package/dist/select-priority.d.ts.map +1 -1
- package/dist/select-priority.js +5 -5
- package/dist/select-priority.js.map +1 -1
- package/dist/sidecar-apply.js +1 -1
- package/dist/sidecar-apply.js.map +1 -1
- package/dist/sidecar.d.ts +47 -12
- package/dist/sidecar.d.ts.map +1 -1
- package/dist/sidecar.js +84 -4
- package/dist/sidecar.js.map +1 -1
- package/dist/skills/answer-questions/SKILL.md +89 -0
- package/dist/skills/capture-signal/SKILL.md +52 -0
- package/dist/skills/convert-from-prd-to-spec/SKILL.md +90 -0
- package/dist/skills/drive-tasks/SKILL.md +218 -0
- package/dist/skills/from-idea/SKILL.md +83 -0
- package/dist/skills/merge-prs/SKILL.md +70 -0
- package/dist/skills/orchestrate/SKILL.md +101 -0
- package/dist/skills/promote/SKILL.md +35 -0
- package/dist/skills/review/SKILL.md +16 -0
- package/dist/skills/setup/SKILL.md +258 -0
- package/dist/skills/setup/protocol/ADR-FORMAT.md +47 -0
- package/dist/skills/setup/protocol/CLAIM-PROTOCOL.md +224 -0
- package/dist/skills/setup/protocol/REVIEW-PROTOCOL.md +122 -0
- package/dist/skills/setup/protocol/SURFACE-PROTOCOL.md +135 -0
- package/dist/skills/setup/protocol/TASKING-PROTOCOL.md +124 -0
- package/dist/skills/setup/protocol/WORK-CONTRACT.md +280 -0
- package/dist/skills/setup/protocol/spec-template.md +71 -0
- package/dist/skills/setup/protocol/task-template.md +65 -0
- package/dist/skills/surface-questions/SKILL.md +16 -0
- package/dist/skills/to-spec/SKILL.md +34 -0
- package/dist/skills/to-task/SKILL.md +19 -0
- package/dist/skills/triage-observations/SKILL.md +78 -0
- package/dist/skills/work/SKILL.md +51 -0
- package/dist/slug-namespace.d.ts +6 -6
- package/dist/slug-namespace.js +8 -8
- package/dist/slug-namespace.js.map +1 -1
- package/dist/spec-complete.d.ts.map +1 -1
- package/dist/spec-complete.js +4 -5
- package/dist/spec-complete.js.map +1 -1
- package/dist/start.d.ts +1 -1
- package/dist/start.d.ts.map +1 -1
- package/dist/start.js +54 -60
- package/dist/start.js.map +1 -1
- package/dist/status.d.ts +3 -3
- package/dist/status.js +4 -4
- package/dist/status.js.map +1 -1
- package/dist/surface-gate.d.ts +2 -2
- package/dist/surface-gate.d.ts.map +1 -1
- package/dist/surface-gate.js +10 -3
- package/dist/surface-gate.js.map +1 -1
- package/dist/surface-persist.d.ts +2 -2
- package/dist/surface-persist.d.ts.map +1 -1
- package/dist/surface-persist.js +1 -1
- package/dist/surface-persist.js.map +1 -1
- package/dist/tasker-review-loop.d.ts +11 -10
- package/dist/tasker-review-loop.d.ts.map +1 -1
- package/dist/tasker-review-loop.js +8 -8
- package/dist/tasker-review-loop.js.map +1 -1
- package/dist/tasking-eligibility.d.ts +21 -21
- package/dist/tasking-eligibility.d.ts.map +1 -1
- package/dist/tasking-eligibility.js +10 -10
- package/dist/tasking-lock.d.ts +10 -10
- package/dist/tasking-lock.d.ts.map +1 -1
- package/dist/tasking-lock.js +69 -49
- package/dist/tasking-lock.js.map +1 -1
- package/dist/tasking.d.ts +73 -39
- package/dist/tasking.d.ts.map +1 -1
- package/dist/tasking.js +309 -95
- package/dist/tasking.js.map +1 -1
- package/dist/triage-gate.d.ts +1 -1
- package/dist/triage-persist.d.ts +15 -11
- package/dist/triage-persist.d.ts.map +1 -1
- package/dist/triage-persist.js +48 -18
- package/dist/triage-persist.js.map +1 -1
- package/dist/vendor/incur/agents.d.ts +58 -0
- package/dist/vendor/incur/agents.d.ts.map +1 -0
- package/dist/vendor/incur/agents.js +343 -0
- package/dist/vendor/incur/agents.js.map +1 -0
- package/dist/verify-workflow-template.d.ts +1 -1
- package/dist/verify-workflow-template.js +3 -3
- package/dist/watch-session.d.ts +11 -3
- package/dist/watch-session.d.ts.map +1 -1
- package/dist/watch-session.js +94 -7
- package/dist/watch-session.js.map +1 -1
- package/dist/work-layout.d.ts +15 -9
- package/dist/work-layout.d.ts.map +1 -1
- package/dist/work-layout.js +14 -9
- package/dist/work-layout.js.map +1 -1
- package/dist/workspace.d.ts +2 -2
- package/package.json +2 -2
- package/src/advance-ci-template.ts +4 -4
- package/src/advance-classify.ts +5 -5
- package/src/advance-drivers.ts +26 -13
- package/src/advance-isolated.ts +3 -3
- package/src/advance-lifecycle-template.ts +98 -13
- package/src/advance-loop-driver.ts +3 -3
- package/src/advance-treeless-publish.ts +46 -1
- package/src/advance.ts +495 -115
- package/src/advancing-lock.ts +102 -7
- package/src/agent-launch.ts +37 -12
- package/src/agent-stop.ts +60 -2
- package/src/apply-decide.ts +38 -9
- package/src/apply-merge-action.ts +49 -11
- package/src/apply-persist.ts +236 -62
- package/src/apply-stuck-action.ts +260 -0
- package/src/brand.ts +14 -2
- package/src/buildable-body.ts +14 -14
- package/src/claim-cas.ts +4 -4
- package/src/cli-spinner.ts +1 -1
- package/src/cli.ts +472 -141
- package/src/close-job-template.ts +9 -9
- package/src/close-job.ts +26 -26
- package/src/complete.ts +121 -63
- package/src/concurrency.ts +1 -1
- package/src/config.ts +143 -49
- package/src/continue-branch.ts +23 -1
- package/src/cwd-section.ts +1 -1
- package/src/decision-engine.ts +57 -19
- package/src/do-autopick.ts +21 -10
- package/src/do-config.ts +7 -7
- package/src/do-remote-auto.ts +2 -2
- package/src/do.ts +558 -85
- package/src/drop-source.ts +2 -2
- package/src/env-config.ts +19 -11
- package/src/failure-cause.ts +30 -1
- package/src/format.ts +13 -33
- package/src/frontmatter.ts +55 -35
- package/src/gc.ts +172 -9
- package/src/github.ts +78 -0
- package/src/harness.ts +25 -0
- package/src/index.ts +10 -0
- package/src/install-ci-branch-protection.ts +283 -58
- package/src/install-ci-capabilities/advance-lifecycle.ts +1 -1
- package/src/install-ci-capabilities/close-job.ts +1 -1
- package/src/install-ci-capabilities/example-noop.ts +1 -1
- package/src/install-ci-capabilities/intake.ts +2 -2
- package/src/install-ci-capabilities/verify.ts +1 -1
- package/src/install-ci-core.ts +34 -7
- package/src/install-ci-github.ts +87 -1
- package/src/install-ci.ts +4 -4
- package/src/install-skills.ts +166 -0
- package/src/intake-event.ts +6 -6
- package/src/intake-marker.ts +3 -3
- package/src/intake-triage.ts +2 -2
- package/src/intake-trigger-template.ts +18 -18
- package/src/intake.ts +138 -103
- package/src/integration-core.ts +234 -100
- package/src/integrator.ts +22 -9
- package/src/isolation.ts +13 -4
- package/src/issue-provider.ts +4 -4
- package/src/item-lock.ts +505 -361
- package/src/item-path.ts +2 -2
- package/src/ledger-lint.ts +9 -9
- package/src/ledger-read.ts +81 -81
- package/src/ledger-write.ts +137 -152
- package/src/lifecycle-gather.ts +45 -22
- package/src/lifecycle-pools.ts +71 -13
- package/src/merge-question-surfacer.ts +32 -8
- package/src/migrate-stuck-locks.ts +451 -0
- package/src/mint-adr.ts +4 -4
- package/src/mirror-pool-scan.ts +5 -5
- package/src/needs-attention.ts +877 -104
- package/src/orphan-sidecar.ts +49 -8
- package/src/pi-harness.ts +82 -2
- package/src/placement.ts +8 -8
- package/src/prd-to-spec.ts +13 -5
- package/src/prompt.ts +20 -25
- package/src/readiness.ts +1 -1
- package/src/reap-branches.ts +38 -14
- package/src/recover-isolated.ts +18 -1
- package/src/repo-config.ts +66 -17
- package/src/repo-mirror.ts +23 -1
- package/src/review-gate.ts +12 -11
- package/src/review-verdict.ts +3 -3
- package/src/run.ts +69 -23
- package/src/scan.ts +36 -22
- package/src/select-order.ts +1 -1
- package/src/select-priority.ts +15 -15
- package/src/sidecar-apply.ts +1 -1
- package/src/sidecar.ts +141 -14
- package/src/slug-namespace.ts +10 -10
- package/src/spec-complete.ts +4 -5
- package/src/start.ts +57 -63
- package/src/status.ts +7 -7
- package/src/surface-gate.ts +12 -5
- package/src/surface-persist.ts +3 -3
- package/src/tasker-review-loop.ts +18 -17
- package/src/tasking-eligibility.ts +21 -21
- package/src/tasking-lock.ts +75 -60
- package/src/tasking.ts +381 -135
- package/src/triage-gate.ts +1 -1
- package/src/triage-persist.ts +71 -27
- package/src/vendor/incur/LICENSE +21 -0
- package/src/vendor/incur/README.md +19 -0
- package/src/vendor/incur/agents.ts +392 -0
- package/src/verify-workflow-template.ts +3 -3
- package/src/watch-session.ts +102 -7
- package/src/work-layout.ts +14 -9
- package/src/workspace.ts +2 -2
package/src/github.ts
CHANGED
|
@@ -209,6 +209,26 @@ export class GitHubProvider implements ReviewProvider {
|
|
|
209
209
|
return this.parseOpened(input, first);
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
// PR ALREADY EXISTS (task `committed-recovery-completes-existing-pr`): a
|
|
213
|
+
// re-pushed branch whose PR is still open makes `gh pr create` fail with
|
|
214
|
+
// "a pull request for branch ... already exists". This is NOT an outage and
|
|
215
|
+
// NOT a missing/unauth `gh` — retrying is pointless (it fails identically)
|
|
216
|
+
// and degrading to push-only would DROP the refreshed body + the Gate-2
|
|
217
|
+
// review comment on a PR that genuinely exists (the committed-recovery re-run
|
|
218
|
+
// case). Instead RESOLVE the existing PR, UPDATE its title/body to match what
|
|
219
|
+
// this run would have created, and return it as `opened` so the caller's
|
|
220
|
+
// review-comment path fires normally. NEVER throws; a failed edit still
|
|
221
|
+
// returns the resolved PR (the comment is the more important audit trail).
|
|
222
|
+
if (prAlreadyExists(first)) {
|
|
223
|
+
const existing = this.updateExistingRequest(input);
|
|
224
|
+
if (existing !== undefined) {
|
|
225
|
+
return existing;
|
|
226
|
+
}
|
|
227
|
+
// Could not resolve the existing PR's url (e.g. a transient `gh pr view`
|
|
228
|
+
// failure) — fall through to the degrade path rather than crashing; the
|
|
229
|
+
// branch is already pushed, so the work is safe.
|
|
230
|
+
}
|
|
231
|
+
|
|
212
232
|
// Failed once — distinguish DETERMINISTIC (missing/unauth) from a TRANSIENT
|
|
213
233
|
// outage by an availability probe. Missing/unauth ⇒ degrade now (no retry).
|
|
214
234
|
// Thread the FAILED first attempt so the degrade surfaces the REAL `gh` cause
|
|
@@ -246,6 +266,47 @@ export class GitHubProvider implements ReviewProvider {
|
|
|
246
266
|
return this.parseOpened(input, attempt.value);
|
|
247
267
|
}
|
|
248
268
|
|
|
269
|
+
/**
|
|
270
|
+
* The PR for this branch ALREADY EXISTS (task
|
|
271
|
+
* `committed-recovery-completes-existing-pr`): resolve its url, REFRESH its
|
|
272
|
+
* title/body via `gh pr edit` (so a committed-recovery re-run's synthesised
|
|
273
|
+
* title + task-pointer body replace the earlier run's blank `--fill` ones),
|
|
274
|
+
* and return it as `{opened: true, url}` so the caller's review-comment path
|
|
275
|
+
* fires on the existing PR. Returns `undefined` when the url cannot be
|
|
276
|
+
* resolved (the caller then falls through to the degrade path). The `gh pr
|
|
277
|
+
* edit` is best-effort: a failed edit still returns the resolved PR (posting
|
|
278
|
+
* the review comment matters more than refreshing the body), and it is only
|
|
279
|
+
* attempted when this run actually has explicit title/body to set (else the
|
|
280
|
+
* existing PR's content is left untouched).
|
|
281
|
+
*/
|
|
282
|
+
private updateExistingRequest(
|
|
283
|
+
input: OpenRequestInput,
|
|
284
|
+
): OpenRequestResult | undefined {
|
|
285
|
+
const url = this.resolvePrUrlForBranch(input.branch, input.cwd, input.env);
|
|
286
|
+
if (url === undefined) {
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
// Refresh the PR body/title only when this run supplies them (a committed-
|
|
290
|
+
// recovery re-run does; an unset run leaves the existing content alone).
|
|
291
|
+
if (input.title !== undefined || input.body !== undefined) {
|
|
292
|
+
const editArgs = ['pr', 'edit', url];
|
|
293
|
+
if (input.title !== undefined) {
|
|
294
|
+
editArgs.push('--title', input.title);
|
|
295
|
+
}
|
|
296
|
+
if (input.body !== undefined) {
|
|
297
|
+
editArgs.push('--body', input.body);
|
|
298
|
+
}
|
|
299
|
+
// Best-effort: ignore the result. A failed edit must not lose the PR (or
|
|
300
|
+
// the upcoming review comment) — NEVER throws (runGh swallows spawn errors).
|
|
301
|
+
this.runGh(editArgs, input.cwd, input.env);
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
opened: true,
|
|
305
|
+
url,
|
|
306
|
+
instruction: `Updated the existing GitHub PR for ${input.branch}: ${url}`,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
249
310
|
/** Map a successful `gh pr create` RunResult to an OpenRequestResult. */
|
|
250
311
|
private parseOpened(
|
|
251
312
|
input: OpenRequestInput,
|
|
@@ -457,6 +518,23 @@ export function prCreateContentArgs(input: {
|
|
|
457
518
|
return ['--title', input.title ?? '', '--body', input.body ?? ''];
|
|
458
519
|
}
|
|
459
520
|
|
|
521
|
+
/**
|
|
522
|
+
* Does a FAILED `gh pr create` result mean "a PR for this branch already
|
|
523
|
+
* exists" (task `committed-recovery-completes-existing-pr`)? `gh` exits non-zero
|
|
524
|
+
* with a message like `a pull request for branch "work/task-x" into branch
|
|
525
|
+
* "main" already exists: https://github.com/.../pull/357`. We match on the
|
|
526
|
+
* stable "already exists" phrase in `gh`'s stderr/stdout so a re-pushed branch
|
|
527
|
+
* whose PR is still open is treated as an UPDATE, not a transient outage. A
|
|
528
|
+
* missing `gh` (`undefined`) or a success is not this case.
|
|
529
|
+
*/
|
|
530
|
+
function prAlreadyExists(result: RunResult | undefined): boolean {
|
|
531
|
+
if (result === undefined || result.status === 0) {
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
const text = `${result.stderr ?? ''}\n${result.stdout ?? ''}`.toLowerCase();
|
|
535
|
+
return text.includes('already exists');
|
|
536
|
+
}
|
|
537
|
+
|
|
460
538
|
/**
|
|
461
539
|
* Parse the PR URL `gh pr create` prints to stdout. `gh` prints the PR URL as a
|
|
462
540
|
* line (often the only/last line); we pick the first GitHub PR URL we find. Any
|
package/src/harness.ts
CHANGED
|
@@ -61,6 +61,21 @@ export interface LaunchInput {
|
|
|
61
61
|
* `undefined` ⇒ the pi adapter falls back to a generated default for its cwd.
|
|
62
62
|
*/
|
|
63
63
|
session?: string;
|
|
64
|
+
/**
|
|
65
|
+
* **Optional agent-session DEADLINE** (absolute epoch-ms wall-clock timestamp)
|
|
66
|
+
* for the ASYNC {@link Harness} launch (spec
|
|
67
|
+
* `graceful-pre-timeout-wip-checkpoint`). When set AND the future arrives
|
|
68
|
+
* before the child exits, the harness sends SIGTERM (a ~10s grace, then
|
|
69
|
+
* SIGKILL) and resolves the {@link LaunchResult} with `timedOut: true` — so
|
|
70
|
+
* the caller can route the run as a CHECKPOINT (save WIP + auto-continue /
|
|
71
|
+
* surface) rather than a generic agent-failure. Ignored on the synchronous
|
|
72
|
+
* {@link Harness.launch} path (`spawnSync` cannot be interrupted from the
|
|
73
|
+
* same event loop; the async path is where CI's `--watch` legs run and where
|
|
74
|
+
* the checkpoint discipline lives). Absent ⇒ no deadline (byte-for-byte the
|
|
75
|
+
* pre-task behaviour: a run finishing before its deadline is unchanged; on
|
|
76
|
+
* `exit` the timer is cleared).
|
|
77
|
+
*/
|
|
78
|
+
deadlineMs?: number;
|
|
64
79
|
env?: NodeJS.ProcessEnv;
|
|
65
80
|
}
|
|
66
81
|
|
|
@@ -170,6 +185,16 @@ export interface LaunchResult {
|
|
|
170
185
|
record: HarnessRecord;
|
|
171
186
|
/** Failure detail when `ok` is false (the stderr/failure channel). */
|
|
172
187
|
detail?: string;
|
|
188
|
+
/**
|
|
189
|
+
* **True iff the launch was stopped by the dorfl-internal DEADLINE**
|
|
190
|
+
* ({@link LaunchInput.deadlineMs}) rather than exiting on its own (spec
|
|
191
|
+
* `graceful-pre-timeout-wip-checkpoint`). Distinct from `ok` (a deadline
|
|
192
|
+
* stop is neither a success nor a generic failure — it is a CHECKPOINT the
|
|
193
|
+
* caller routes through the save+auto-continue/surface path). Absent/false
|
|
194
|
+
* when the child exited before the deadline, so a run that finishes
|
|
195
|
+
* normally is byte-for-byte unchanged.
|
|
196
|
+
*/
|
|
197
|
+
timedOut?: boolean;
|
|
173
198
|
/**
|
|
174
199
|
* The agent's final ANSWER (task `harness-agent-output`): the concatenated
|
|
175
200
|
* `text` of the LAST assistant turn the invocation produced. This is the
|
package/src/index.ts
CHANGED
|
@@ -26,6 +26,8 @@ export type {
|
|
|
26
26
|
} from './repo-config.js';
|
|
27
27
|
export {
|
|
28
28
|
REPO_CONFIG_FILENAME,
|
|
29
|
+
REPO_CONFIG_FILENAME_LEGACY,
|
|
30
|
+
resolveRepoConfigPath,
|
|
29
31
|
REPO_ALLOWED_KEYS,
|
|
30
32
|
REPO_REJECTED_KEYS,
|
|
31
33
|
repoConfigPath,
|
|
@@ -783,3 +785,11 @@ export type {
|
|
|
783
785
|
InstallCIResult,
|
|
784
786
|
} from './install-ci.js';
|
|
785
787
|
export {installCI, runWizard} from './install-ci.js';
|
|
788
|
+
|
|
789
|
+
export type {
|
|
790
|
+
InstallSkillsOptions,
|
|
791
|
+
InstallSkillsResult,
|
|
792
|
+
InstalledAgent,
|
|
793
|
+
} from './install-skills.js';
|
|
794
|
+
export {installSkills, resolveSkillsSourceDir} from './install-skills.js';
|
|
795
|
+
export type {Agent} from './vendor/incur/agents.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tier-1 GitHub branch-protection STEP for `install-ci` (
|
|
2
|
+
* Tier-1 GitHub branch-protection STEP for `install-ci` (spec
|
|
3
3
|
* `land-time-reverify-and-parallel-merge-ceiling`, task
|
|
4
4
|
* `install-ci-tier1-branch-protection`; Story 11). Closes the propose-mode
|
|
5
5
|
* PR-merge-time drift window on a GitHub arbiter: a required `verify` check + a
|
|
@@ -34,28 +34,44 @@
|
|
|
34
34
|
* change can flip it knowingly; the spec calls this "pick the cheaper of the
|
|
35
35
|
* two and record the choice."
|
|
36
36
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
37
|
+
* DEFAULT BRANCH — NOT hardcoded to `main`. The GitHub adapter resolves the
|
|
38
|
+
* repo's real default branch ({@link CIProviderContext.getDefaultBranch}, via
|
|
39
|
+
* `gh repo view --json defaultBranchRef`); the orchestrator threads it into
|
|
40
|
+
* BOTH the classic PUT and the printed `gh api` fallback so a `master`-defaulted
|
|
41
|
+
* (or otherwise-renamed) repo is protected on the correct branch instead of
|
|
42
|
+
* 404-ing a hardcoded `main`. The lookup falls back to {@link
|
|
43
|
+
* DEFAULT_PROTECTED_BRANCH} (`main`) only when it fails/empties, and that
|
|
44
|
+
* fallback is LOGGED so it is visible. An explicit `branch` option still wins
|
|
45
|
+
* over auto-detection (a repo whose protected branch is not its default).
|
|
40
46
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
47
|
+
* DEADLOCK GUARD — a required check that has NEVER reported blocks every merge
|
|
48
|
+
* (GitHub treats an unreported required check as pending), so a PR opened before
|
|
49
|
+
* `verify.yml` first ran would deadlock. The guard is a RUNTIME MECHANISM, not a
|
|
50
|
+
* log line: the required-`verify` check is enforced through a branch RULESET
|
|
51
|
+
* ({@link buildBranchProtectionRuleset}, `POST /repos/{owner}/{repo}/rulesets`)
|
|
52
|
+
* whose `required_status_checks` rule carries `do_not_enforce_on_create: true` —
|
|
53
|
+
* GitHub's native "require this check, but do not fail refs created before the
|
|
54
|
+
* rule / before the check first ran" toggle. The ruleset targets the resolved
|
|
55
|
+
* default branch via `conditions.ref_name`.
|
|
45
56
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
57
|
+
* WHY RULESET FOR THE GUARD BUT CLASSIC PUT FOR THE BASE (nit-a preserved).
|
|
58
|
+
* The base protection stays a single classic PUT
|
|
59
|
+
* ({@link buildBranchProtectionSpec}: `strict: true` = "require branches up to
|
|
60
|
+
* date before merging") because that endpoint is the simplest way to express
|
|
61
|
+
* up-to-date-ness and nit-a ratified the classic-PUT choice. ONLY the deadlock-
|
|
62
|
+
* prone piece — the required-status-check gate — moves to a ruleset, because the
|
|
63
|
+
* `do_not_enforce_on_create` create-exemption exists ONLY on rulesets, not on
|
|
64
|
+
* the classic `required_status_checks` object. Keeping the required check in the
|
|
65
|
+
* classic PUT AND adding the ruleset would double-enforce it and NULLIFY the
|
|
66
|
+
* exemption (the classic copy has no exemption), so the required check lives in
|
|
67
|
+
* the ruleset ALONE; the classic PUT keeps `strict` with an EMPTY `checks`
|
|
68
|
+
* array (valid: "require up to date", no named required check at the classic
|
|
69
|
+
* layer). This is exactly "only the deadlock-guard aspect needs the ruleset" —
|
|
70
|
+
* not a full base-protection migration. Chosen over the pre-run mechanism
|
|
71
|
+
* (`gh workflow run` + wait) because `writeArtifacts` writes `verify.yml`
|
|
72
|
+
* LOCALLY and does NOT push, so at install time the workflow is not yet on the
|
|
73
|
+
* default branch and a pre-run has nothing to dispatch. The ruleset toggle needs
|
|
74
|
+
* no pushed workflow and no wait, so it is the only viable runtime guard here.
|
|
59
75
|
*/
|
|
60
76
|
|
|
61
77
|
import {VERIFY_CHECK_CONTEXT} from './verify-workflow-template.js';
|
|
@@ -64,15 +80,17 @@ import type {CIProviderContext} from './install-ci-core.js';
|
|
|
64
80
|
export {VERIFY_CHECK_CONTEXT};
|
|
65
81
|
|
|
66
82
|
/**
|
|
67
|
-
* The branch-protection request body the GitHub adapter PUTs at
|
|
83
|
+
* The BASE branch-protection request body the GitHub adapter PUTs at
|
|
68
84
|
* `/repos/{owner}/{repo}/branches/{branch}/protection`. Shape mirrors the REST
|
|
69
85
|
* docs (the GitHub PUT REQUIRES `enforce_admins`, `required_pull_request_reviews`,
|
|
70
86
|
* and `restrictions` to be present; `null` for "not configured"). We set only
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
87
|
+
* `strict: true` (= "require branches up to date before merging") with an EMPTY
|
|
88
|
+
* `checks` array — the required `${VERIFY_CHECK_CONTEXT}` check is NOT here; it
|
|
89
|
+
* lives in the deadlock-guard RULESET ({@link buildBranchProtectionRuleset}) so
|
|
90
|
+
* its `do_not_enforce_on_create` create-exemption is meaningful (see module
|
|
91
|
+
* header). The other required fields stay `null` so install-ci does not silently
|
|
92
|
+
* impose unrelated gates (reviews, admin enforcement, push restrictions) the
|
|
93
|
+
* user did not opt into.
|
|
76
94
|
*/
|
|
77
95
|
export interface BranchProtectionSpec {
|
|
78
96
|
required_status_checks: {
|
|
@@ -85,16 +103,15 @@ export interface BranchProtectionSpec {
|
|
|
85
103
|
}
|
|
86
104
|
|
|
87
105
|
/**
|
|
88
|
-
* Build the Tier-1 branch-protection spec the GitHub adapter PUTs
|
|
89
|
-
* `
|
|
90
|
-
*
|
|
91
|
-
* agreement, so the two cannot drift.
|
|
106
|
+
* Build the Tier-1 BASE branch-protection spec the GitHub adapter PUTs
|
|
107
|
+
* (`strict: true`, no named required check — the required check is the ruleset's
|
|
108
|
+
* job, see {@link buildBranchProtectionRuleset} and the module header).
|
|
92
109
|
*/
|
|
93
110
|
export function buildBranchProtectionSpec(): BranchProtectionSpec {
|
|
94
111
|
return {
|
|
95
112
|
required_status_checks: {
|
|
96
113
|
strict: true,
|
|
97
|
-
checks: [
|
|
114
|
+
checks: [],
|
|
98
115
|
},
|
|
99
116
|
enforce_admins: null,
|
|
100
117
|
required_pull_request_reviews: null,
|
|
@@ -102,6 +119,70 @@ export function buildBranchProtectionSpec(): BranchProtectionSpec {
|
|
|
102
119
|
};
|
|
103
120
|
}
|
|
104
121
|
|
|
122
|
+
/** The name the deadlock-guard ruleset is created under (stable/idempotent-ish). */
|
|
123
|
+
export const BRANCH_PROTECTION_RULESET_NAME = 'dorfl-verify-required';
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The deadlock-guard RULESET body the GitHub adapter POSTs at
|
|
127
|
+
* `/repos/{owner}/{repo}/rulesets`. It carries the required-`${VERIFY_CHECK_CONTEXT}`
|
|
128
|
+
* status-check rule with `do_not_enforce_on_create: true` — GitHub's native
|
|
129
|
+
* "require this check, but do not fail refs that predate the rule / the check's
|
|
130
|
+
* first run" toggle (the runtime deadlock guard). `enforcement: 'active'` +
|
|
131
|
+
* `conditions.ref_name` scope it to the resolved default branch. The required
|
|
132
|
+
* `context` is the SAME {@link VERIFY_CHECK_CONTEXT} constant the emitted verify
|
|
133
|
+
* workflow names its job after — by construction, so the two cannot drift.
|
|
134
|
+
*/
|
|
135
|
+
export interface BranchProtectionRuleset {
|
|
136
|
+
name: string;
|
|
137
|
+
target: 'branch';
|
|
138
|
+
enforcement: 'active';
|
|
139
|
+
conditions: {
|
|
140
|
+
ref_name: {
|
|
141
|
+
include: string[];
|
|
142
|
+
exclude: string[];
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
rules: {
|
|
146
|
+
type: 'required_status_checks';
|
|
147
|
+
parameters: {
|
|
148
|
+
strict_required_status_checks_policy: boolean;
|
|
149
|
+
do_not_enforce_on_create: true;
|
|
150
|
+
required_status_checks: {context: string}[];
|
|
151
|
+
};
|
|
152
|
+
}[];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Build the deadlock-guard ruleset for `branch` (the resolved default branch).
|
|
157
|
+
* The `ref_name` include uses the exact-ref form (`refs/heads/<branch>`) so the
|
|
158
|
+
* rule targets only that branch. `do_not_enforce_on_create: true` is the guard.
|
|
159
|
+
*/
|
|
160
|
+
export function buildBranchProtectionRuleset(
|
|
161
|
+
branch: string = DEFAULT_PROTECTED_BRANCH,
|
|
162
|
+
): BranchProtectionRuleset {
|
|
163
|
+
return {
|
|
164
|
+
name: BRANCH_PROTECTION_RULESET_NAME,
|
|
165
|
+
target: 'branch',
|
|
166
|
+
enforcement: 'active',
|
|
167
|
+
conditions: {
|
|
168
|
+
ref_name: {
|
|
169
|
+
include: [`refs/heads/${branch}`],
|
|
170
|
+
exclude: [],
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
rules: [
|
|
174
|
+
{
|
|
175
|
+
type: 'required_status_checks',
|
|
176
|
+
parameters: {
|
|
177
|
+
strict_required_status_checks_policy: true,
|
|
178
|
+
do_not_enforce_on_create: true,
|
|
179
|
+
required_status_checks: [{context: VERIFY_CHECK_CONTEXT}],
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
105
186
|
/**
|
|
106
187
|
* The repo's default branch the protection rule targets (the rule the spec
|
|
107
188
|
* names: protect `main` so a propose-mode PR cannot be merged stale). Exposed
|
|
@@ -132,6 +213,26 @@ export function formatManualBranchProtectionCommand(
|
|
|
132
213
|
);
|
|
133
214
|
}
|
|
134
215
|
|
|
216
|
+
/**
|
|
217
|
+
* The exact `gh api` command the user runs themselves to create the deadlock-
|
|
218
|
+
* guard RULESET when install-ci cannot auto-configure (no admin scope). Quoted
|
|
219
|
+
* body is the same {@link BranchProtectionRuleset} the auto path POSTs, so
|
|
220
|
+
* reproducing the call by copy-paste is byte-equivalent to a successful auto
|
|
221
|
+
* run. Pure string, no I/O.
|
|
222
|
+
*/
|
|
223
|
+
export function formatManualBranchRulesetCommand(
|
|
224
|
+
repo: string,
|
|
225
|
+
branch: string = DEFAULT_PROTECTED_BRANCH,
|
|
226
|
+
): string {
|
|
227
|
+
const body = JSON.stringify(buildBranchProtectionRuleset(branch));
|
|
228
|
+
return (
|
|
229
|
+
`echo '${body}' | gh api -X POST ` +
|
|
230
|
+
`-H "Accept: application/vnd.github+json" ` +
|
|
231
|
+
`repos/${repo}/rulesets ` +
|
|
232
|
+
`--input -`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
135
236
|
/** Options for {@link installCIBranchProtectionStep}. */
|
|
136
237
|
export interface BranchProtectionStepOptions {
|
|
137
238
|
/** The CI-provider seam (GitHub adapter in production; stub in tests). */
|
|
@@ -140,7 +241,13 @@ export interface BranchProtectionStepOptions {
|
|
|
140
241
|
fake?: boolean;
|
|
141
242
|
/** Sink for human-facing progress lines. */
|
|
142
243
|
log: (line: string) => void;
|
|
143
|
-
/**
|
|
244
|
+
/**
|
|
245
|
+
* Explicitly override the branch the rule targets. When OMITTED, the step
|
|
246
|
+
* auto-detects the repo's default branch via
|
|
247
|
+
* {@link CIProviderContext.getDefaultBranch}, falling back to
|
|
248
|
+
* {@link DEFAULT_PROTECTED_BRANCH} (`main`) and logging the fallback. An
|
|
249
|
+
* explicit value always wins over auto-detection.
|
|
250
|
+
*/
|
|
144
251
|
branch?: string;
|
|
145
252
|
}
|
|
146
253
|
|
|
@@ -168,41 +275,105 @@ export interface BranchProtectionStepResult {
|
|
|
168
275
|
error?: string;
|
|
169
276
|
/** The branch the step targeted (echoed for tests / logs). */
|
|
170
277
|
branch: string;
|
|
278
|
+
/**
|
|
279
|
+
* Whether the branch was AUTO-DETECTED (`true`) or came from an explicit
|
|
280
|
+
* `branch` option / the `main` fallback (`false`). Echoed for tests / logs.
|
|
281
|
+
*/
|
|
282
|
+
branchAutoDetected?: boolean;
|
|
283
|
+
/**
|
|
284
|
+
* The deadlock-guard RULESET outcome (only on the admin auto path):
|
|
285
|
+
* - `set` — the ruleset POST succeeded;
|
|
286
|
+
* - `failed` — the ruleset POST was rejected (detail in `rulesetError`);
|
|
287
|
+
* - `skipped-no-seam` — the provider does not implement the ruleset seam.
|
|
288
|
+
* Absent on the non-admin / skipped paths.
|
|
289
|
+
*/
|
|
290
|
+
rulesetStatus?: 'set' | 'failed' | 'skipped-no-seam';
|
|
291
|
+
/** The ruleset failure detail when `rulesetStatus === 'failed'`. */
|
|
292
|
+
rulesetError?: string;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Resolve the branch the protection targets. An EXPLICIT `branch` option always
|
|
297
|
+
* wins; otherwise auto-detect the repo's default branch via
|
|
298
|
+
* {@link CIProviderContext.getDefaultBranch}, falling back to `main` (LOGGED)
|
|
299
|
+
* when the lookup fails/empties. Returns the branch + whether it was
|
|
300
|
+
* auto-detected (for the result / log lines).
|
|
301
|
+
*/
|
|
302
|
+
async function resolveTargetBranch(
|
|
303
|
+
ctx: CIProviderContext,
|
|
304
|
+
explicit: string | undefined,
|
|
305
|
+
log: (line: string) => void,
|
|
306
|
+
): Promise<{branch: string; autoDetected: boolean}> {
|
|
307
|
+
if (explicit !== undefined) {
|
|
308
|
+
return {branch: explicit, autoDetected: false};
|
|
309
|
+
}
|
|
310
|
+
const detected = ctx.getDefaultBranch
|
|
311
|
+
? await ctx.getDefaultBranch().catch(() => undefined)
|
|
312
|
+
: undefined;
|
|
313
|
+
if (detected) {
|
|
314
|
+
return {branch: detected, autoDetected: true};
|
|
315
|
+
}
|
|
316
|
+
log(
|
|
317
|
+
`branch protection: could not detect the default branch; ` +
|
|
318
|
+
`falling back to \`${DEFAULT_PROTECTED_BRANCH}\`.`,
|
|
319
|
+
);
|
|
320
|
+
return {branch: DEFAULT_PROTECTED_BRANCH, autoDetected: false};
|
|
171
321
|
}
|
|
172
322
|
|
|
173
323
|
/**
|
|
174
324
|
* The orchestrator install-ci calls AFTER artifacts are written + secrets are
|
|
175
|
-
* orchestrated:
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
325
|
+
* orchestrated:
|
|
326
|
+
*
|
|
327
|
+
* 1. RESOLVE the target branch (explicit option > auto-detected default
|
|
328
|
+
* branch > `main` fallback), so the PUT + printed fallback target the real
|
|
329
|
+
* default branch (see module header, "DEFAULT BRANCH");
|
|
330
|
+
* 2. detect admin scope (cheapest path: {@link
|
|
331
|
+
* CIProviderContext.getRepoAdminScope});
|
|
332
|
+
* 3. ADMIN: PUT the base protection ({@link
|
|
333
|
+
* CIProviderContext.setBranchProtection}) AND create the deadlock-guard
|
|
334
|
+
* ruleset ({@link CIProviderContext.setBranchRuleset}); NON-ADMIN: print
|
|
335
|
+
* the exact ready-to-run `gh api` commands (PUT + ruleset POST) + the
|
|
336
|
+
* manual UI fallback.
|
|
179
337
|
*
|
|
180
|
-
* Never throws — a `setBranchProtection` rejection is reported as `failed
|
|
181
|
-
*
|
|
182
|
-
*
|
|
338
|
+
* Never throws — a `setBranchProtection` rejection is reported as `failed`, a
|
|
339
|
+
* `setBranchRuleset` rejection as `rulesetStatus: 'failed'`, so install-ci's
|
|
340
|
+
* later steps still run and the user sees the failure detail AND the manual
|
|
341
|
+
* command to retry by hand.
|
|
183
342
|
*/
|
|
184
343
|
export async function installCIBranchProtectionStep(
|
|
185
344
|
options: BranchProtectionStepOptions,
|
|
186
345
|
): Promise<BranchProtectionStepResult> {
|
|
187
|
-
const branch = options.branch ?? DEFAULT_PROTECTED_BRANCH;
|
|
188
346
|
const {ctx, log, fake} = options;
|
|
189
347
|
|
|
190
348
|
if (fake) {
|
|
191
|
-
|
|
192
|
-
|
|
349
|
+
const target = options.branch ?? DEFAULT_PROTECTED_BRANCH;
|
|
350
|
+
log(`branch protection: skipped (--fake; would have targeted ${target})`);
|
|
351
|
+
return {status: 'skipped-fake', branch: target};
|
|
193
352
|
}
|
|
194
353
|
if (!ctx.setBranchProtection) {
|
|
195
354
|
log(
|
|
196
355
|
'branch protection: skipped (provider does not implement the seam — non-GitHub host).',
|
|
197
356
|
);
|
|
198
|
-
return {
|
|
357
|
+
return {
|
|
358
|
+
status: 'skipped-no-seam',
|
|
359
|
+
branch: options.branch ?? DEFAULT_PROTECTED_BRANCH,
|
|
360
|
+
};
|
|
199
361
|
}
|
|
200
362
|
if (!ctx.repo) {
|
|
201
363
|
log('branch protection: skipped (repo unknown — pass --repo to enable).');
|
|
202
|
-
return {
|
|
364
|
+
return {
|
|
365
|
+
status: 'skipped-no-repo',
|
|
366
|
+
branch: options.branch ?? DEFAULT_PROTECTED_BRANCH,
|
|
367
|
+
};
|
|
203
368
|
}
|
|
204
369
|
|
|
205
370
|
const repo = ctx.repo;
|
|
371
|
+
const {branch, autoDetected} = await resolveTargetBranch(
|
|
372
|
+
ctx,
|
|
373
|
+
options.branch,
|
|
374
|
+
log,
|
|
375
|
+
);
|
|
376
|
+
|
|
206
377
|
// Cheapest scope-detection: one repo-permissions read (see module header).
|
|
207
378
|
// `undefined` ⇒ unknown ⇒ treat as non-admin (instruct, never silently
|
|
208
379
|
// attempt a call that would fail with 403 anyway).
|
|
@@ -213,20 +384,30 @@ export async function installCIBranchProtectionStep(
|
|
|
213
384
|
if (adminScope !== true) {
|
|
214
385
|
log('branch protection: no admin-scoped credential detected.');
|
|
215
386
|
log(
|
|
216
|
-
` install-ci will NOT call the GitHub API. Run
|
|
387
|
+
` install-ci will NOT call the GitHub API. Run these yourself (admin token required):`,
|
|
217
388
|
);
|
|
218
389
|
log(` ${formatManualBranchProtectionCommand(repo, branch)}`);
|
|
390
|
+
log(
|
|
391
|
+
` Then create the deadlock-guard ruleset (required check \`${VERIFY_CHECK_CONTEXT}\`, ` +
|
|
392
|
+
`do_not_enforce_on_create):`,
|
|
393
|
+
);
|
|
394
|
+
log(` ${formatManualBranchRulesetCommand(repo, branch)}`);
|
|
219
395
|
log(
|
|
220
396
|
` Manual UI fallback: https://github.com/${repo}/settings/branches ` +
|
|
221
397
|
`→ "Add branch protection rule" → branch name pattern \`${branch}\` ` +
|
|
222
|
-
`→ enable "Require
|
|
223
|
-
|
|
398
|
+
`→ enable "Require branches to be up to date", then add a RULESET ` +
|
|
399
|
+
`requiring \`${VERIFY_CHECK_CONTEXT}\` with "Do not require ... on creation".`,
|
|
224
400
|
);
|
|
225
401
|
log(
|
|
226
402
|
` (The ambient CI \`GITHUB_TOKEN\` is NEVER admin; a human admin's \`gh\` ` +
|
|
227
403
|
`or a configured PAT/App token with "Administration: write" is required.)`,
|
|
228
404
|
);
|
|
229
|
-
return {
|
|
405
|
+
return {
|
|
406
|
+
status: 'instructed',
|
|
407
|
+
adminScope,
|
|
408
|
+
branch,
|
|
409
|
+
branchAutoDetected: autoDetected,
|
|
410
|
+
};
|
|
230
411
|
}
|
|
231
412
|
|
|
232
413
|
const spec = buildBranchProtectionSpec();
|
|
@@ -234,15 +415,8 @@ export async function installCIBranchProtectionStep(
|
|
|
234
415
|
await ctx.setBranchProtection(branch, spec);
|
|
235
416
|
log(
|
|
236
417
|
`branch protection: set on ${repo}@${branch} ` +
|
|
237
|
-
`(
|
|
418
|
+
`(strict: true = require branches up to date).`,
|
|
238
419
|
);
|
|
239
|
-
log(
|
|
240
|
-
` NOTE: PRs opened BEFORE \`verify.yml\` lands on \`${branch}\` have ` +
|
|
241
|
-
`no \`${VERIFY_CHECK_CONTEXT}\` check waiting. Push/merge \`verify.yml\` ` +
|
|
242
|
-
`to \`${branch}\` first; existing in-flight PRs may need a no-op push ` +
|
|
243
|
-
`(or close/reopen) to re-trigger the check.`,
|
|
244
|
-
);
|
|
245
|
-
return {status: 'set', adminScope, branch};
|
|
246
420
|
} catch (err) {
|
|
247
421
|
const error = err instanceof Error ? err.message : String(err);
|
|
248
422
|
log(`branch protection: FAILED (${error})`);
|
|
@@ -250,6 +424,57 @@ export async function installCIBranchProtectionStep(
|
|
|
250
424
|
` Retry by hand (admin token required):\n` +
|
|
251
425
|
` ${formatManualBranchProtectionCommand(repo, branch)}`,
|
|
252
426
|
);
|
|
253
|
-
return {
|
|
427
|
+
return {
|
|
428
|
+
status: 'failed',
|
|
429
|
+
adminScope,
|
|
430
|
+
error,
|
|
431
|
+
branch,
|
|
432
|
+
branchAutoDetected: autoDetected,
|
|
433
|
+
};
|
|
254
434
|
}
|
|
435
|
+
|
|
436
|
+
// The deadlock guard: the required `verify` check lives in a RULESET with
|
|
437
|
+
// `do_not_enforce_on_create: true` (see module header), NOT in the classic
|
|
438
|
+
// PUT above — so a ref that predates the rule / the check's first run is not
|
|
439
|
+
// deadlocked by a never-reported required check.
|
|
440
|
+
let rulesetStatus: 'set' | 'failed' | 'skipped-no-seam';
|
|
441
|
+
let rulesetError: string | undefined;
|
|
442
|
+
if (!ctx.setBranchRuleset) {
|
|
443
|
+
rulesetStatus = 'skipped-no-seam';
|
|
444
|
+
log(
|
|
445
|
+
` deadlock guard: provider does not implement the ruleset seam; ` +
|
|
446
|
+
`required check \`${VERIFY_CHECK_CONTEXT}\` NOT enforced.`,
|
|
447
|
+
);
|
|
448
|
+
} else {
|
|
449
|
+
try {
|
|
450
|
+
await ctx.setBranchRuleset(buildBranchProtectionRuleset(branch));
|
|
451
|
+
rulesetStatus = 'set';
|
|
452
|
+
log(
|
|
453
|
+
`deadlock-guard ruleset: created on ${repo}@${branch} ` +
|
|
454
|
+
`(required check \`${VERIFY_CHECK_CONTEXT}\`, do_not_enforce_on_create: true).`,
|
|
455
|
+
);
|
|
456
|
+
log(
|
|
457
|
+
` NOTE: still push/merge \`verify.yml\` to \`${branch}\` so the check ` +
|
|
458
|
+
`can report on new PRs; the ruleset's create-exemption keeps existing ` +
|
|
459
|
+
`in-flight refs from deadlocking on the not-yet-run check.`,
|
|
460
|
+
);
|
|
461
|
+
} catch (err) {
|
|
462
|
+
rulesetError = err instanceof Error ? err.message : String(err);
|
|
463
|
+
rulesetStatus = 'failed';
|
|
464
|
+
log(`deadlock-guard ruleset: FAILED (${rulesetError})`);
|
|
465
|
+
log(
|
|
466
|
+
` Retry by hand (admin token required):\n` +
|
|
467
|
+
` ${formatManualBranchRulesetCommand(repo, branch)}`,
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return {
|
|
473
|
+
status: 'set',
|
|
474
|
+
adminScope,
|
|
475
|
+
branch,
|
|
476
|
+
branchAutoDetected: autoDetected,
|
|
477
|
+
rulesetStatus,
|
|
478
|
+
rulesetError,
|
|
479
|
+
};
|
|
255
480
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The ADVANCE-LIFECYCLE capability emitter (
|
|
2
|
+
* The ADVANCE-LIFECYCLE capability emitter (SPEC `runner-in-ci`, task
|
|
3
3
|
* `install-ci-advance-lifecycle-workflow`; capability C: auto-triage observations
|
|
4
4
|
* + surface declared blockers + apply committed answers). A SELF-REGISTERING
|
|
5
5
|
* module: it calls {@link registerCapability} at import time, so
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The CLOSE-JOB capability emitter (
|
|
2
|
+
* The CLOSE-JOB capability emitter (SPEC `runner-in-ci`, task
|
|
3
3
|
* `install-ci-close-job-workflow`; capability E: close issues when their work
|
|
4
4
|
* lands). A SELF-REGISTERING module: it calls {@link registerCapability} at import
|
|
5
5
|
* time, so {@link loadCapabilityRegistry} picks it up WITHOUT any edit to a shared
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* REFERENCE capability registration (
|
|
2
|
+
* REFERENCE capability registration (SPEC `runner-in-ci`, task
|
|
3
3
|
* `install-ci-core-and-github-adapter`). This file proves the capability-emitter
|
|
4
4
|
* REGISTRY seam works as a DIRECTORY of self-registering modules: a new capability
|
|
5
5
|
* is a NEW file in `install-ci-capabilities/` that calls {@link registerCapability}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The ISSUE-INTAKE capability emitter (
|
|
2
|
+
* The ISSUE-INTAKE capability emitter (SPEC `runner-in-ci`, task
|
|
3
3
|
* `install-ci-intake-trigger-and-review-surface`; capability D: consider incoming
|
|
4
|
-
* issues → task/
|
|
4
|
+
* issues → task/SPEC, PLUS insertion point E: surface the review verdict into the
|
|
5
5
|
* issue thread). A SELF-REGISTERING module: it calls {@link registerCapability} at
|
|
6
6
|
* import time, so {@link loadCapabilityRegistry} picks it up WITHOUT any edit to a
|
|
7
7
|
* shared central list/switch (the file-orthogonality contract — this task and the
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The VERIFY capability emitter (
|
|
2
|
+
* The VERIFY capability emitter (spec
|
|
3
3
|
* `land-time-reverify-and-parallel-merge-ceiling`, task
|
|
4
4
|
* `install-ci-tier1-branch-protection`; Story 11 — Tier-1 GitHub ceiling).
|
|
5
5
|
* A SELF-REGISTERING module: it calls {@link registerCapability} at import
|