dorfl 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advance-ci-template.d.ts +73 -0
- package/dist/advance-ci-template.d.ts.map +1 -0
- package/dist/advance-ci-template.js +104 -0
- package/dist/advance-ci-template.js.map +1 -0
- package/dist/advance-classify.d.ts +132 -0
- package/dist/advance-classify.d.ts.map +1 -0
- package/dist/advance-classify.js +120 -0
- package/dist/advance-classify.js.map +1 -0
- package/dist/advance-drivers.d.ts +182 -0
- package/dist/advance-drivers.d.ts.map +1 -0
- package/dist/advance-drivers.js +231 -0
- package/dist/advance-drivers.js.map +1 -0
- package/dist/advance-isolated.d.ts +156 -0
- package/dist/advance-isolated.d.ts.map +1 -0
- package/dist/advance-isolated.js +256 -0
- package/dist/advance-isolated.js.map +1 -0
- package/dist/advance-lifecycle-template.d.ts +107 -0
- package/dist/advance-lifecycle-template.d.ts.map +1 -0
- package/dist/advance-lifecycle-template.js +668 -0
- package/dist/advance-lifecycle-template.js.map +1 -0
- package/dist/advance-loop-driver.d.ts +325 -0
- package/dist/advance-loop-driver.d.ts.map +1 -0
- package/dist/advance-loop-driver.js +437 -0
- package/dist/advance-loop-driver.js.map +1 -0
- package/dist/advance-treeless-publish.d.ts +108 -0
- package/dist/advance-treeless-publish.d.ts.map +1 -0
- package/dist/advance-treeless-publish.js +71 -0
- package/dist/advance-treeless-publish.js.map +1 -0
- package/dist/advance.d.ts +340 -0
- package/dist/advance.d.ts.map +1 -0
- package/dist/advance.js +1122 -0
- package/dist/advance.js.map +1 -0
- package/dist/advancing-lock.d.ts +294 -0
- package/dist/advancing-lock.d.ts.map +1 -0
- package/dist/advancing-lock.js +594 -0
- package/dist/advancing-lock.js.map +1 -0
- package/dist/agent-launch.d.ts +79 -0
- package/dist/agent-launch.d.ts.map +1 -0
- package/dist/agent-launch.js +61 -0
- package/dist/agent-launch.js.map +1 -0
- package/dist/agent-stop.d.ts +149 -0
- package/dist/agent-stop.d.ts.map +1 -0
- package/dist/agent-stop.js +307 -0
- package/dist/agent-stop.js.map +1 -0
- package/dist/apply-decide.d.ts +127 -0
- package/dist/apply-decide.d.ts.map +1 -0
- package/dist/apply-decide.js +176 -0
- package/dist/apply-decide.js.map +1 -0
- package/dist/apply-merge-action.d.ts +206 -0
- package/dist/apply-merge-action.d.ts.map +1 -0
- package/dist/apply-merge-action.js +307 -0
- package/dist/apply-merge-action.js.map +1 -0
- package/dist/apply-persist.d.ts +174 -0
- package/dist/apply-persist.d.ts.map +1 -0
- package/dist/apply-persist.js +359 -0
- package/dist/apply-persist.js.map +1 -0
- package/dist/arbiter.d.ts +120 -0
- package/dist/arbiter.d.ts.map +1 -0
- package/dist/arbiter.js +255 -0
- package/dist/arbiter.js.map +1 -0
- package/dist/brand.d.ts +70 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +84 -0
- package/dist/brand.js.map +1 -0
- package/dist/buildable-body.d.ts +132 -0
- package/dist/buildable-body.d.ts.map +1 -0
- package/dist/buildable-body.js +131 -0
- package/dist/buildable-body.js.map +1 -0
- package/dist/categorise.d.ts +66 -0
- package/dist/categorise.d.ts.map +1 -0
- package/dist/categorise.js +106 -0
- package/dist/categorise.js.map +1 -0
- package/dist/claim-cas.d.ts +117 -0
- package/dist/claim-cas.d.ts.map +1 -0
- package/dist/claim-cas.js +312 -0
- package/dist/claim-cas.js.map +1 -0
- package/dist/cli-spinner.d.ts +112 -0
- package/dist/cli-spinner.d.ts.map +1 -0
- package/dist/cli-spinner.js +157 -0
- package/dist/cli-spinner.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +3094 -0
- package/dist/cli.js.map +1 -0
- package/dist/close-job-template.d.ts +70 -0
- package/dist/close-job-template.d.ts.map +1 -0
- package/dist/close-job-template.js +180 -0
- package/dist/close-job-template.js.map +1 -0
- package/dist/close-job.d.ts +95 -0
- package/dist/close-job.d.ts.map +1 -0
- package/dist/close-job.js +226 -0
- package/dist/close-job.js.map +1 -0
- package/dist/complete.d.ts +361 -0
- package/dist/complete.d.ts.map +1 -0
- package/dist/complete.js +885 -0
- package/dist/complete.js.map +1 -0
- package/dist/concurrency.d.ts +68 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +112 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/config-override.d.ts +76 -0
- package/dist/config-override.d.ts.map +1 -0
- package/dist/config-override.js +50 -0
- package/dist/config-override.js.map +1 -0
- package/dist/config.d.ts +668 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +241 -0
- package/dist/config.js.map +1 -0
- package/dist/continue-branch.d.ts +249 -0
- package/dist/continue-branch.d.ts.map +1 -0
- package/dist/continue-branch.js +389 -0
- package/dist/continue-branch.js.map +1 -0
- package/dist/cwd-section.d.ts +186 -0
- package/dist/cwd-section.d.ts.map +1 -0
- package/dist/cwd-section.js +209 -0
- package/dist/cwd-section.js.map +1 -0
- package/dist/decision-engine.d.ts +170 -0
- package/dist/decision-engine.d.ts.map +1 -0
- package/dist/decision-engine.js +136 -0
- package/dist/decision-engine.js.map +1 -0
- package/dist/detect.d.ts +17 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +118 -0
- package/dist/detect.js.map +1 -0
- package/dist/do-autopick.d.ts +85 -0
- package/dist/do-autopick.d.ts.map +1 -0
- package/dist/do-autopick.js +112 -0
- package/dist/do-autopick.js.map +1 -0
- package/dist/do-config.d.ts +312 -0
- package/dist/do-config.d.ts.map +1 -0
- package/dist/do-config.js +358 -0
- package/dist/do-config.js.map +1 -0
- package/dist/do-remote-auto.d.ts +75 -0
- package/dist/do-remote-auto.d.ts.map +1 -0
- package/dist/do-remote-auto.js +111 -0
- package/dist/do-remote-auto.js.map +1 -0
- package/dist/do.d.ts +621 -0
- package/dist/do.d.ts.map +1 -0
- package/dist/do.js +1882 -0
- package/dist/do.js.map +1 -0
- package/dist/drop-source.d.ts +96 -0
- package/dist/drop-source.d.ts.map +1 -0
- package/dist/drop-source.js +91 -0
- package/dist/drop-source.js.map +1 -0
- package/dist/eligibility.d.ts +46 -0
- package/dist/eligibility.d.ts.map +1 -0
- package/dist/eligibility.js +34 -0
- package/dist/eligibility.js.map +1 -0
- package/dist/env-config.d.ts +51 -0
- package/dist/env-config.d.ts.map +1 -0
- package/dist/env-config.js +272 -0
- package/dist/env-config.js.map +1 -0
- package/dist/failure-cause.d.ts +70 -0
- package/dist/failure-cause.d.ts.map +1 -0
- package/dist/failure-cause.js +126 -0
- package/dist/failure-cause.js.map +1 -0
- package/dist/format.d.ts +43 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +256 -0
- package/dist/format.js.map +1 -0
- package/dist/frontmatter.d.ts +215 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +345 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/gate-readiness.d.ts +84 -0
- package/dist/gate-readiness.d.ts.map +1 -0
- package/dist/gate-readiness.js +103 -0
- package/dist/gate-readiness.js.map +1 -0
- package/dist/gc.d.ts +165 -0
- package/dist/gc.d.ts.map +1 -0
- package/dist/gc.js +313 -0
- package/dist/gc.js.map +1 -0
- package/dist/gh-failure.d.ts +42 -0
- package/dist/gh-failure.d.ts.map +1 -0
- package/dist/gh-failure.js +49 -0
- package/dist/gh-failure.js.map +1 -0
- package/dist/git.d.ts +75 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +130 -0
- package/dist/git.js.map +1 -0
- package/dist/github.d.ts +187 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +343 -0
- package/dist/github.js.map +1 -0
- package/dist/harness.d.ts +242 -0
- package/dist/harness.d.ts.map +1 -0
- package/dist/harness.js +157 -0
- package/dist/harness.js.map +1 -0
- package/dist/identity.d.ts +167 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +231 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +147 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/install-ci-branch-protection.d.ts +147 -0
- package/dist/install-ci-branch-protection.d.ts.map +1 -0
- package/dist/install-ci-branch-protection.js +166 -0
- package/dist/install-ci-branch-protection.js.map +1 -0
- package/dist/install-ci-capabilities/advance-lifecycle.d.ts +15 -0
- package/dist/install-ci-capabilities/advance-lifecycle.d.ts.map +1 -0
- package/dist/install-ci-capabilities/advance-lifecycle.js +28 -0
- package/dist/install-ci-capabilities/advance-lifecycle.js.map +1 -0
- package/dist/install-ci-capabilities/close-job.d.ts +13 -0
- package/dist/install-ci-capabilities/close-job.d.ts.map +1 -0
- package/dist/install-ci-capabilities/close-job.js +26 -0
- package/dist/install-ci-capabilities/close-job.js.map +1 -0
- package/dist/install-ci-capabilities/example-noop.d.ts +16 -0
- package/dist/install-ci-capabilities/example-noop.d.ts.map +1 -0
- package/dist/install-ci-capabilities/example-noop.js +23 -0
- package/dist/install-ci-capabilities/example-noop.js.map +1 -0
- package/dist/install-ci-capabilities/intake.d.ts +15 -0
- package/dist/install-ci-capabilities/intake.d.ts.map +1 -0
- package/dist/install-ci-capabilities/intake.js +28 -0
- package/dist/install-ci-capabilities/intake.js.map +1 -0
- package/dist/install-ci-capabilities/verify.d.ts +14 -0
- package/dist/install-ci-capabilities/verify.d.ts.map +1 -0
- package/dist/install-ci-capabilities/verify.js +27 -0
- package/dist/install-ci-capabilities/verify.js.map +1 -0
- package/dist/install-ci-core.d.ts +446 -0
- package/dist/install-ci-core.d.ts.map +1 -0
- package/dist/install-ci-core.js +760 -0
- package/dist/install-ci-core.js.map +1 -0
- package/dist/install-ci-github.d.ts +167 -0
- package/dist/install-ci-github.d.ts.map +1 -0
- package/dist/install-ci-github.js +315 -0
- package/dist/install-ci-github.js.map +1 -0
- package/dist/install-ci.d.ts +105 -0
- package/dist/install-ci.d.ts.map +1 -0
- package/dist/install-ci.js +363 -0
- package/dist/install-ci.js.map +1 -0
- package/dist/intake-event.d.ts +88 -0
- package/dist/intake-event.d.ts.map +1 -0
- package/dist/intake-event.js +66 -0
- package/dist/intake-event.js.map +1 -0
- package/dist/intake-marker.d.ts +95 -0
- package/dist/intake-marker.d.ts.map +1 -0
- package/dist/intake-marker.js +127 -0
- package/dist/intake-marker.js.map +1 -0
- package/dist/intake-triage.d.ts +48 -0
- package/dist/intake-triage.d.ts.map +1 -0
- package/dist/intake-triage.js +95 -0
- package/dist/intake-triage.js.map +1 -0
- package/dist/intake-trigger-template.d.ts +185 -0
- package/dist/intake-trigger-template.d.ts.map +1 -0
- package/dist/intake-trigger-template.js +449 -0
- package/dist/intake-trigger-template.js.map +1 -0
- package/dist/intake.d.ts +569 -0
- package/dist/intake.d.ts.map +1 -0
- package/dist/intake.js +1628 -0
- package/dist/intake.js.map +1 -0
- package/dist/integration-core.d.ts +539 -0
- package/dist/integration-core.d.ts.map +1 -0
- package/dist/integration-core.js +2195 -0
- package/dist/integration-core.js.map +1 -0
- package/dist/integrator.d.ts +343 -0
- package/dist/integrator.d.ts.map +1 -0
- package/dist/integrator.js +400 -0
- package/dist/integrator.js.map +1 -0
- package/dist/isolation.d.ts +219 -0
- package/dist/isolation.d.ts.map +1 -0
- package/dist/isolation.js +261 -0
- package/dist/isolation.js.map +1 -0
- package/dist/issue-provider.d.ts +349 -0
- package/dist/issue-provider.d.ts.map +1 -0
- package/dist/issue-provider.js +360 -0
- package/dist/issue-provider.js.map +1 -0
- package/dist/item-lock.d.ts +626 -0
- package/dist/item-lock.d.ts.map +1 -0
- package/dist/item-lock.js +1381 -0
- package/dist/item-lock.js.map +1 -0
- package/dist/item-path.d.ts +49 -0
- package/dist/item-path.d.ts.map +1 -0
- package/dist/item-path.js +66 -0
- package/dist/item-path.js.map +1 -0
- package/dist/ledger-lint.d.ts +129 -0
- package/dist/ledger-lint.d.ts.map +1 -0
- package/dist/ledger-lint.js +249 -0
- package/dist/ledger-lint.js.map +1 -0
- package/dist/ledger-read.d.ts +357 -0
- package/dist/ledger-read.d.ts.map +1 -0
- package/dist/ledger-read.js +442 -0
- package/dist/ledger-read.js.map +1 -0
- package/dist/ledger-write.d.ts +330 -0
- package/dist/ledger-write.d.ts.map +1 -0
- package/dist/ledger-write.js +411 -0
- package/dist/ledger-write.js.map +1 -0
- package/dist/lifecycle-gather.d.ts +30 -0
- package/dist/lifecycle-gather.d.ts.map +1 -0
- package/dist/lifecycle-gather.js +205 -0
- package/dist/lifecycle-gather.js.map +1 -0
- package/dist/lifecycle-pools.d.ts +180 -0
- package/dist/lifecycle-pools.d.ts.map +1 -0
- package/dist/lifecycle-pools.js +78 -0
- package/dist/lifecycle-pools.js.map +1 -0
- package/dist/merge-question-surfacer.d.ts +166 -0
- package/dist/merge-question-surfacer.d.ts.map +1 -0
- package/dist/merge-question-surfacer.js +297 -0
- package/dist/merge-question-surfacer.js.map +1 -0
- package/dist/mint-adr.d.ts +126 -0
- package/dist/mint-adr.d.ts.map +1 -0
- package/dist/mint-adr.js +257 -0
- package/dist/mint-adr.js.map +1 -0
- package/dist/mirror-pool-scan.d.ts +125 -0
- package/dist/mirror-pool-scan.d.ts.map +1 -0
- package/dist/mirror-pool-scan.js +104 -0
- package/dist/mirror-pool-scan.js.map +1 -0
- package/dist/needs-attention.d.ts +341 -0
- package/dist/needs-attention.d.ts.map +1 -0
- package/dist/needs-attention.js +900 -0
- package/dist/needs-attention.js.map +1 -0
- package/dist/orphan-sidecar.d.ts +79 -0
- package/dist/orphan-sidecar.d.ts.map +1 -0
- package/dist/orphan-sidecar.js +71 -0
- package/dist/orphan-sidecar.js.map +1 -0
- package/dist/output.d.ts +48 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +66 -0
- package/dist/output.js.map +1 -0
- package/dist/pi-harness.d.ts +179 -0
- package/dist/pi-harness.d.ts.map +1 -0
- package/dist/pi-harness.js +342 -0
- package/dist/pi-harness.js.map +1 -0
- package/dist/placement.d.ts +99 -0
- package/dist/placement.d.ts.map +1 -0
- package/dist/placement.js +67 -0
- package/dist/placement.js.map +1 -0
- package/dist/prd-to-spec.d.ts +315 -0
- package/dist/prd-to-spec.d.ts.map +1 -0
- package/dist/prd-to-spec.js +684 -0
- package/dist/prd-to-spec.js.map +1 -0
- package/dist/prepare.d.ts +121 -0
- package/dist/prepare.d.ts.map +1 -0
- package/dist/prepare.js +140 -0
- package/dist/prepare.js.map +1 -0
- package/dist/prompt.d.ts +360 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +499 -0
- package/dist/prompt.js.map +1 -0
- package/dist/protocol/ADR-FORMAT.md +47 -0
- package/dist/protocol/CLAIM-PROTOCOL.md +217 -0
- package/dist/protocol/REVIEW-PROTOCOL.md +119 -0
- package/dist/protocol/SURFACE-PROTOCOL.md +121 -0
- package/dist/protocol/TASKING-PROTOCOL.md +122 -0
- package/dist/protocol/WORK-CONTRACT.md +276 -0
- package/dist/protocol/spec-template.md +71 -0
- package/dist/protocol/task-template.md +65 -0
- package/dist/readiness.d.ts +66 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +36 -0
- package/dist/readiness.js.map +1 -0
- package/dist/reap-branches.d.ts +102 -0
- package/dist/reap-branches.d.ts.map +1 -0
- package/dist/reap-branches.js +149 -0
- package/dist/reap-branches.js.map +1 -0
- package/dist/recover-isolated.d.ts +72 -0
- package/dist/recover-isolated.d.ts.map +1 -0
- package/dist/recover-isolated.js +188 -0
- package/dist/recover-isolated.js.map +1 -0
- package/dist/registry.d.ts +172 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +296 -0
- package/dist/registry.js.map +1 -0
- package/dist/repo-config.d.ts +201 -0
- package/dist/repo-config.d.ts.map +1 -0
- package/dist/repo-config.js +414 -0
- package/dist/repo-config.js.map +1 -0
- package/dist/repo-key.d.ts +20 -0
- package/dist/repo-key.d.ts.map +1 -0
- package/dist/repo-key.js +68 -0
- package/dist/repo-key.js.map +1 -0
- package/dist/repo-mirror.d.ts +177 -0
- package/dist/repo-mirror.d.ts.map +1 -0
- package/dist/repo-mirror.js +271 -0
- package/dist/repo-mirror.js.map +1 -0
- package/dist/retry-backoff.d.ts +90 -0
- package/dist/retry-backoff.d.ts.map +1 -0
- package/dist/retry-backoff.js +98 -0
- package/dist/retry-backoff.js.map +1 -0
- package/dist/review-gate.d.ts +173 -0
- package/dist/review-gate.d.ts.map +1 -0
- package/dist/review-gate.js +261 -0
- package/dist/review-gate.js.map +1 -0
- package/dist/review-verdict.d.ts +149 -0
- package/dist/review-verdict.d.ts.map +1 -0
- package/dist/review-verdict.js +332 -0
- package/dist/review-verdict.js.map +1 -0
- package/dist/run.d.ts +221 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +963 -0
- package/dist/run.js.map +1 -0
- package/dist/scan.d.ts +308 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +374 -0
- package/dist/scan.js.map +1 -0
- package/dist/select-order.d.ts +75 -0
- package/dist/select-order.d.ts.map +1 -0
- package/dist/select-order.js +108 -0
- package/dist/select-order.js.map +1 -0
- package/dist/select-priority.d.ts +188 -0
- package/dist/select-priority.d.ts.map +1 -0
- package/dist/select-priority.js +80 -0
- package/dist/select-priority.js.map +1 -0
- package/dist/select.d.ts +25 -0
- package/dist/select.d.ts.map +1 -0
- package/dist/select.js +43 -0
- package/dist/select.js.map +1 -0
- package/dist/session-path.d.ts +36 -0
- package/dist/session-path.d.ts.map +1 -0
- package/dist/session-path.js +129 -0
- package/dist/session-path.js.map +1 -0
- package/dist/sidecar-apply.d.ts +83 -0
- package/dist/sidecar-apply.d.ts.map +1 -0
- package/dist/sidecar-apply.js +111 -0
- package/dist/sidecar-apply.js.map +1 -0
- package/dist/sidecar.d.ts +245 -0
- package/dist/sidecar.d.ts.map +1 -0
- package/dist/sidecar.js +481 -0
- package/dist/sidecar.js.map +1 -0
- package/dist/slug-namespace.d.ts +204 -0
- package/dist/slug-namespace.d.ts.map +1 -0
- package/dist/slug-namespace.js +229 -0
- package/dist/slug-namespace.js.map +1 -0
- package/dist/spec-complete.d.ts +44 -0
- package/dist/spec-complete.d.ts.map +1 -0
- package/dist/spec-complete.js +69 -0
- package/dist/spec-complete.js.map +1 -0
- package/dist/start.d.ts +97 -0
- package/dist/start.d.ts.map +1 -0
- package/dist/start.js +633 -0
- package/dist/start.js.map +1 -0
- package/dist/status.d.ts +199 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +228 -0
- package/dist/status.js.map +1 -0
- package/dist/surface-gate.d.ts +162 -0
- package/dist/surface-gate.d.ts.map +1 -0
- package/dist/surface-gate.js +206 -0
- package/dist/surface-gate.js.map +1 -0
- package/dist/surface-persist.d.ts +86 -0
- package/dist/surface-persist.d.ts.map +1 -0
- package/dist/surface-persist.js +129 -0
- package/dist/surface-persist.js.map +1 -0
- package/dist/tasker-review-loop.d.ts +249 -0
- package/dist/tasker-review-loop.d.ts.map +1 -0
- package/dist/tasker-review-loop.js +369 -0
- package/dist/tasker-review-loop.js.map +1 -0
- package/dist/tasking-eligibility.d.ts +74 -0
- package/dist/tasking-eligibility.d.ts.map +1 -0
- package/dist/tasking-eligibility.js +52 -0
- package/dist/tasking-eligibility.js.map +1 -0
- package/dist/tasking-lock.d.ts +111 -0
- package/dist/tasking-lock.d.ts.map +1 -0
- package/dist/tasking-lock.js +256 -0
- package/dist/tasking-lock.js.map +1 -0
- package/dist/tasking.d.ts +275 -0
- package/dist/tasking.d.ts.map +1 -0
- package/dist/tasking.js +952 -0
- package/dist/tasking.js.map +1 -0
- package/dist/triage-gate.d.ts +127 -0
- package/dist/triage-gate.d.ts.map +1 -0
- package/dist/triage-gate.js +139 -0
- package/dist/triage-gate.js.map +1 -0
- package/dist/triage-persist.d.ts +163 -0
- package/dist/triage-persist.d.ts.map +1 -0
- package/dist/triage-persist.js +387 -0
- package/dist/triage-persist.js.map +1 -0
- package/dist/verdict-json.d.ts +32 -0
- package/dist/verdict-json.d.ts.map +1 -0
- package/dist/verdict-json.js +74 -0
- package/dist/verdict-json.js.map +1 -0
- package/dist/verify-workflow-template.d.ts +60 -0
- package/dist/verify-workflow-template.d.ts.map +1 -0
- package/dist/verify-workflow-template.js +126 -0
- package/dist/verify-workflow-template.js.map +1 -0
- package/dist/verify.d.ts +60 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +62 -0
- package/dist/verify.js.map +1 -0
- package/dist/watch-session.d.ts +112 -0
- package/dist/watch-session.d.ts.map +1 -0
- package/dist/watch-session.js +347 -0
- package/dist/watch-session.js.map +1 -0
- package/dist/work-layout.d.ts +198 -0
- package/dist/work-layout.d.ts.map +1 -0
- package/dist/work-layout.js +217 -0
- package/dist/work-layout.js.map +1 -0
- package/dist/work-on.d.ts +154 -0
- package/dist/work-on.d.ts.map +1 -0
- package/dist/work-on.js +387 -0
- package/dist/work-on.js.map +1 -0
- package/dist/workspace.d.ts +224 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +325 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +46 -2
- package/src/advance-ci-template.ts +203 -0
- package/src/advance-classify.ts +197 -0
- package/src/advance-drivers.ts +414 -0
- package/src/advance-isolated.ts +432 -0
- package/src/advance-lifecycle-template.ts +791 -0
- package/src/advance-loop-driver.ts +745 -0
- package/src/advance-treeless-publish.ts +177 -0
- package/src/advance.ts +1564 -0
- package/src/advancing-lock.ts +988 -0
- package/src/agent-launch.ts +137 -0
- package/src/agent-stop.ts +361 -0
- package/src/apply-decide.ts +242 -0
- package/src/apply-merge-action.ts +502 -0
- package/src/apply-persist.ts +518 -0
- package/src/arbiter.ts +372 -0
- package/src/brand.ts +111 -0
- package/src/buildable-body.ts +196 -0
- package/src/categorise.ts +158 -0
- package/src/claim-cas.ts +513 -0
- package/src/cli-spinner.ts +225 -0
- package/src/cli.ts +4369 -0
- package/src/close-job-template.ts +236 -0
- package/src/close-job.ts +319 -0
- package/src/complete.ts +1379 -0
- package/src/concurrency.ts +151 -0
- package/src/config-override.ts +116 -0
- package/src/config.ts +883 -0
- package/src/continue-branch.ts +542 -0
- package/src/cwd-section.ts +392 -0
- package/src/decision-engine.ts +272 -0
- package/src/detect.ts +124 -0
- package/src/do-autopick.ts +223 -0
- package/src/do-config.ts +589 -0
- package/src/do-remote-auto.ts +197 -0
- package/src/do.ts +2623 -0
- package/src/drop-source.ts +194 -0
- package/src/eligibility.ts +79 -0
- package/src/env-config.ts +305 -0
- package/src/failure-cause.ts +142 -0
- package/src/format.ts +313 -0
- package/src/frontmatter.ts +485 -0
- package/src/gate-readiness.ts +147 -0
- package/src/gc.ts +510 -0
- package/src/gh-failure.ts +53 -0
- package/src/git.ts +186 -0
- package/src/github.ts +468 -0
- package/src/harness.ts +355 -0
- package/src/identity.ts +322 -0
- package/src/index.ts +785 -0
- package/src/install-ci-branch-protection.ts +255 -0
- package/src/install-ci-capabilities/advance-lifecycle.ts +34 -0
- package/src/install-ci-capabilities/close-job.ts +32 -0
- package/src/install-ci-capabilities/example-noop.ts +24 -0
- package/src/install-ci-capabilities/intake.ts +34 -0
- package/src/install-ci-capabilities/verify.ts +33 -0
- package/src/install-ci-core.ts +1088 -0
- package/src/install-ci-github.ts +376 -0
- package/src/install-ci.ts +552 -0
- package/src/intake-event.ts +102 -0
- package/src/intake-marker.ts +195 -0
- package/src/intake-triage.ts +138 -0
- package/src/intake-trigger-template.ts +591 -0
- package/src/intake.ts +2445 -0
- package/src/integration-core.ts +3065 -0
- package/src/integrator.ts +771 -0
- package/src/isolation.ts +484 -0
- package/src/issue-provider.ts +733 -0
- package/src/item-lock.ts +1858 -0
- package/src/item-path.ts +75 -0
- package/src/ledger-lint.ts +332 -0
- package/src/ledger-read.ts +924 -0
- package/src/ledger-write.ts +865 -0
- package/src/lifecycle-gather.ts +298 -0
- package/src/lifecycle-pools.ts +250 -0
- package/src/merge-question-surfacer.ts +496 -0
- package/src/mint-adr.ts +362 -0
- package/src/mirror-pool-scan.ts +240 -0
- package/src/needs-attention.ts +1506 -0
- package/src/orphan-sidecar.ts +150 -0
- package/src/output.ts +89 -0
- package/src/pi-harness.ts +403 -0
- package/src/placement.ts +131 -0
- package/src/prd-to-spec.ts +1023 -0
- package/src/prepare.ts +230 -0
- package/src/prompt.ts +760 -0
- package/src/readiness.ts +98 -0
- package/src/reap-branches.ts +278 -0
- package/src/recover-isolated.ts +276 -0
- package/src/registry.ts +475 -0
- package/src/repo-config.ts +550 -0
- package/src/repo-key.ts +74 -0
- package/src/repo-mirror.ts +367 -0
- package/src/retry-backoff.ts +130 -0
- package/src/review-gate.ts +389 -0
- package/src/review-verdict.ts +422 -0
- package/src/run.ts +1430 -0
- package/src/scan.ts +611 -0
- package/src/select-order.ts +143 -0
- package/src/select-priority.ts +266 -0
- package/src/select.ts +62 -0
- package/src/session-path.ts +153 -0
- package/src/sidecar-apply.ts +216 -0
- package/src/sidecar.ts +700 -0
- package/src/slug-namespace.ts +367 -0
- package/src/spec-complete.ts +118 -0
- package/src/start.ts +974 -0
- package/src/status.ts +441 -0
- package/src/surface-gate.ts +337 -0
- package/src/surface-persist.ts +241 -0
- package/src/tasker-review-loop.ts +671 -0
- package/src/tasking-eligibility.ts +114 -0
- package/src/tasking-lock.ts +416 -0
- package/src/tasking.ts +1438 -0
- package/src/triage-gate.ts +248 -0
- package/src/triage-persist.ts +570 -0
- package/src/verdict-json.ts +73 -0
- package/src/verify-workflow-template.ts +159 -0
- package/src/verify.ts +123 -0
- package/src/watch-session.ts +397 -0
- package/src/work-layout.ts +262 -0
- package/src/work-on.ts +660 -0
- package/src/workspace.ts +502 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `install-ci` CLOSE-JOB capability (prd `runner-in-ci`, task
|
|
3
|
+
* `install-ci-close-job-workflow`; capability E: close issues when their work
|
|
4
|
+
* lands). This module GENERATES the one fixed workflow file for the close-job and
|
|
5
|
+
* STRUCTURALLY VALIDATES it, mirroring the snapshot-assertion style of
|
|
6
|
+
* `advance-lifecycle-template.ts` / `advance-ci-template.ts` (the package depends on
|
|
7
|
+
* NO YAML lib, so the checks are presence/shape assertions over the raw text).
|
|
8
|
+
*
|
|
9
|
+
* The discipline (from the prd capability-E row + the Out-of-Scope fence):
|
|
10
|
+
*
|
|
11
|
+
* - TRIGGER: a MERGE to `main`. There is no native "PR merged" event, so the
|
|
12
|
+
* workflow uses `push: {branches: [main]}` (NOT `pull_request: closed`): it
|
|
13
|
+
* fires for BOTH PR-merges AND direct pushes to `main`, and it ALWAYS runs with
|
|
14
|
+
* a normal (non-fork-restricted) `GITHUB_TOKEN` that can actually close issues
|
|
15
|
+
* — whereas a `pull_request` event from a FORK gets a read-only token and
|
|
16
|
+
* cannot close. (See the `## Decisions` block in the task.)
|
|
17
|
+
* - The job INVOKES the close machinery via `dorfl close-merged-issues`,
|
|
18
|
+
* which CONSUMES the UNCHANGED engine pieces: the resolution
|
|
19
|
+
* (`resolveClosingIssue`), the "prd complete?" query (`prd-complete-query`,
|
|
20
|
+
* done), and `IssueProvider.closeIssue`. CI owns ONLY the job + trigger; it
|
|
21
|
+
* re-implements NONE of those (the Out-of-Scope fence).
|
|
22
|
+
* - CI runs IN-PLACE (the CI container IS the isolation): no
|
|
23
|
+
* `--isolated`/`--remote`/registry. A CI concurrency group serialises
|
|
24
|
+
* overlapping close ticks on `main`; the claim CAS is the real cross-run
|
|
25
|
+
* serialiser elsewhere, but the close-job mutates only the ISSUE, so the group
|
|
26
|
+
* just avoids redundant concurrent close passes.
|
|
27
|
+
* - The running CI job NEVER edits `.github/workflows/**` (US #9): it requests NO
|
|
28
|
+
* `workflows` permission and cannot rewrite its own triggers. It needs only
|
|
29
|
+
* `contents: read` (to read the `work/` tree) + `issues: write` (to close).
|
|
30
|
+
*
|
|
31
|
+
* The structural validator is the dependency-free counterpart of "the workflow
|
|
32
|
+
* parses + carries the right discipline" the task's acceptance criteria require;
|
|
33
|
+
* the test generates this artifact under `--fake` and asserts every invariant.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import type {ResolvedCIConfig} from './install-ci-core.js';
|
|
37
|
+
|
|
38
|
+
/** The capability id (the registry key + the emitted workflow file stem). */
|
|
39
|
+
export const CLOSE_JOB_CAPABILITY_ID = 'close-job';
|
|
40
|
+
|
|
41
|
+
/** The wizard-facing label for the close-job capability. */
|
|
42
|
+
export const CLOSE_JOB_CAPABILITY_LABEL =
|
|
43
|
+
'Close issues when their work lands (the close-job: on a merge to main)';
|
|
44
|
+
|
|
45
|
+
/** The repo-relative path (under the output base) of the emitted workflow. */
|
|
46
|
+
export const CLOSE_JOB_WORKFLOW_PATH = 'workflows/close-job.yml';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Generate the close-job workflow YAML. Deterministic: the same config produces
|
|
50
|
+
* byte-identical output. The workflow is a FIXED shell (ADR §6: all policy is
|
|
51
|
+
* env/config) — `config` is accepted for parity with the `CapabilityEmitter` seam
|
|
52
|
+
* and future per-config wiring, but the close-job shape itself is
|
|
53
|
+
* config-independent.
|
|
54
|
+
*/
|
|
55
|
+
export function generateCloseJobWorkflow(_config: ResolvedCIConfig): string {
|
|
56
|
+
return `\
|
|
57
|
+
# dorfl — the ISSUE CLOSE-JOB in CI (capability E, prd runner-in-ci).
|
|
58
|
+
# EMITTED by \`dorfl install-ci\`; the human commits it. DO NOT hand-edit a
|
|
59
|
+
# copy — re-run install-ci to upgrade the shell.
|
|
60
|
+
#
|
|
61
|
+
# TRIGGER — a MERGE to main. There is NO native "PR merged" event, so this uses
|
|
62
|
+
# \`push: {branches: [main]}\` (NOT \`pull_request: closed\` + a merged guard):
|
|
63
|
+
# * it fires for BOTH a PR-merge AND a direct push to main; and
|
|
64
|
+
# * it ALWAYS runs with a normal (non-fork-restricted) GITHUB_TOKEN that can
|
|
65
|
+
# actually CLOSE issues — a \`pull_request\` event from a FORK gets a read-only
|
|
66
|
+
# token and could not close (a real limitation we deliberately avoid).
|
|
67
|
+
#
|
|
68
|
+
# WHAT IT DOES — \`dorfl close-merged-issues\` resolves which source issue(s)
|
|
69
|
+
# the landed work closes and closes them. CI owns ONLY this job + the trigger; the
|
|
70
|
+
# command CONSUMES the engine's UNCHANGED pieces and re-implements none of them:
|
|
71
|
+
# * the RESOLUTION (resolveClosingIssue): a lone task closes its own \`issue:\`;
|
|
72
|
+
# a fanned task reaches the number via \`task.prd: → prd issue:\`.
|
|
73
|
+
# * the "prd complete?" QUERY (prd-complete-query, done): a prd's issue closes
|
|
74
|
+
# ONLY when ALL its \`prd:<slug>\` tasks are in work/done/.
|
|
75
|
+
# * the CLOSE (IssueProvider.closeIssue): the atomic comment+close seam — NO
|
|
76
|
+
# direct \`gh\` in the engine core; any comment rides this close, never the PR
|
|
77
|
+
# comment seam.
|
|
78
|
+
#
|
|
79
|
+
# CI runs IN-PLACE (the CI container IS the isolation): NO --isolated/--remote/
|
|
80
|
+
# registry (laptop-only affordances). The concurrency group below serialises
|
|
81
|
+
# overlapping close ticks on main.
|
|
82
|
+
#
|
|
83
|
+
# SAFETY (US #9): the running job is FORBIDDEN from editing the workflows tree
|
|
84
|
+
# under .github. It requests NO \`workflows\` permission, so it can never rewrite
|
|
85
|
+
# its own triggers. It needs only \`contents: read\` (read the work/ tree) +
|
|
86
|
+
# \`issues: write\` (close the issue).
|
|
87
|
+
|
|
88
|
+
name: close-job
|
|
89
|
+
|
|
90
|
+
on:
|
|
91
|
+
# A merge to main: fires for a PR-merge AND a direct push, ALWAYS with a token
|
|
92
|
+
# that can close issues (unlike a fork \`pull_request\` event's read-only token).
|
|
93
|
+
push:
|
|
94
|
+
branches:
|
|
95
|
+
- main
|
|
96
|
+
|
|
97
|
+
# Serialise overlapping close ticks on main; the close-job mutates only the ISSUE
|
|
98
|
+
# (not the main-CAS), so this just avoids redundant concurrent passes.
|
|
99
|
+
concurrency:
|
|
100
|
+
group: close-job-\${{ github.ref }}
|
|
101
|
+
cancel-in-progress: false
|
|
102
|
+
|
|
103
|
+
# NO \`workflows\` permission: the running job can NEVER edit the workflows tree
|
|
104
|
+
# under .github (US #9). It needs only to READ the work/ tree and CLOSE issues.
|
|
105
|
+
permissions:
|
|
106
|
+
contents: read
|
|
107
|
+
issues: write
|
|
108
|
+
|
|
109
|
+
jobs:
|
|
110
|
+
close-merged-issues:
|
|
111
|
+
runs-on: ubuntu-latest
|
|
112
|
+
steps:
|
|
113
|
+
- uses: actions/checkout@v4
|
|
114
|
+
with:
|
|
115
|
+
fetch-depth: 0
|
|
116
|
+
- uses: ./.github/actions/dorfl-setup
|
|
117
|
+
- name: close issues whose work has landed on main
|
|
118
|
+
# In-place in this checkout (no --isolated/--remote): the CI container IS
|
|
119
|
+
# the isolation. Resolves the closing issue(s) from the work/ tree, runs
|
|
120
|
+
# the "prd complete?" query for the prd case, and closes via the provider
|
|
121
|
+
# seam — all UNCHANGED engine pieces, consumed not re-built.
|
|
122
|
+
env:
|
|
123
|
+
GH_TOKEN: \${{ secrets.GITHUB_TOKEN }}
|
|
124
|
+
run: dorfl close-merged-issues
|
|
125
|
+
`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** A single structural problem found in the generated workflow. */
|
|
129
|
+
export interface CloseJobProblem {
|
|
130
|
+
/** A short, stable id for the violated invariant (for tests/assertions). */
|
|
131
|
+
id: string;
|
|
132
|
+
/** Human-readable description of what is missing or wrong. */
|
|
133
|
+
message: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The result of {@link validateCloseJobWorkflow}. */
|
|
137
|
+
export interface CloseJobValidation {
|
|
138
|
+
/** True iff the workflow satisfies EVERY structural invariant. */
|
|
139
|
+
ok: boolean;
|
|
140
|
+
/** Each violated invariant (empty when `ok`). */
|
|
141
|
+
problems: CloseJobProblem[];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Structurally validate the close-job workflow against the task's acceptance
|
|
146
|
+
* criteria. Dependency-free (no YAML lib): presence/shape assertions over the raw
|
|
147
|
+
* text, mirroring {@link validateAdvanceLifecycleWorkflow}.
|
|
148
|
+
*/
|
|
149
|
+
export function validateCloseJobWorkflow(text: string): CloseJobValidation {
|
|
150
|
+
const problems: CloseJobProblem[] = [];
|
|
151
|
+
const require = (id: string, present: boolean, message: string): void => {
|
|
152
|
+
if (!present) {
|
|
153
|
+
problems.push({id, message});
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// The OPERATIVE (non-comment) lines: the prohibitions below (no `--isolated`/
|
|
158
|
+
// `--remote`/`pull_request` trigger/`.github/workflows` self-edit/direct `gh
|
|
159
|
+
// issue close`) are about what the job DOES, not what the explanatory comments
|
|
160
|
+
// MENTION. Strip full-line `#` comments before the negative checks; the positive
|
|
161
|
+
// presence checks run over the full text (comments are harmless there).
|
|
162
|
+
const operative = text
|
|
163
|
+
.split('\n')
|
|
164
|
+
.filter((line) => !/^\s*#/.test(line))
|
|
165
|
+
.join('\n');
|
|
166
|
+
|
|
167
|
+
// --- TRIGGER: a merge to main via `push: {branches: [main]}` ----------------
|
|
168
|
+
require('trigger-push-main', /\bon:\s*[\s\S]*?push:\s*[\s\S]*?branches:\s*[\s\S]*?-\s*main\b/.test(
|
|
169
|
+
text,
|
|
170
|
+
), 'must trigger on a merge to main via `on.push.branches: [main]` (fires for ' +
|
|
171
|
+
'PR-merges AND direct pushes, always with a token that can close issues).');
|
|
172
|
+
// NOT the `pull_request` trigger: a fork PR gets a read-only token that cannot
|
|
173
|
+
// close, and there is no native "PR merged" event — `push: [main]` is chosen.
|
|
174
|
+
require('not-pull-request-trigger', !/\bpull_request:/.test(
|
|
175
|
+
operative,
|
|
176
|
+
), 'must NOT use the `pull_request` trigger (a fork PR gets a read-only token ' +
|
|
177
|
+
'that cannot close; `push: [main]` is the chosen trigger).');
|
|
178
|
+
// And it must NOT be the build/task tick's cron/dispatch shape — the close-job
|
|
179
|
+
// is event-driven on a merge, not a scheduled drain.
|
|
180
|
+
require('no-cron-trigger', !/\bschedule:\s*[\s\S]*?-\s*cron:/.test(
|
|
181
|
+
operative,
|
|
182
|
+
), 'the close-job is merge-triggered, NOT a cron drain (no `on.schedule.cron`).');
|
|
183
|
+
require('no-answer-loop-push-trigger', !/work\/questions\//.test(
|
|
184
|
+
text,
|
|
185
|
+
), 'the close-job must NOT carry the `push work/questions/**` (answer-loop) ' +
|
|
186
|
+
'trigger — that is the advance-lifecycle task.');
|
|
187
|
+
|
|
188
|
+
// --- INVOKES the close machinery via the existing command -------------------
|
|
189
|
+
// Scoped to operative (non-comment) lines: the explanatory comment NAMES the
|
|
190
|
+
// command, so a real `run:` step (not the doc) must carry it.
|
|
191
|
+
require('invokes-close-merged-issues', /dorfl close-merged-issues\b/.test(
|
|
192
|
+
operative,
|
|
193
|
+
), 'must invoke `dorfl close-merged-issues` (the close-job driver that ' +
|
|
194
|
+
'CONSUMES the unchanged resolution + query + close).');
|
|
195
|
+
// It must NOT re-implement the close with a direct `gh issue close` (the close
|
|
196
|
+
// goes through the IssueProvider seam, not direct `gh` in CI).
|
|
197
|
+
require('no-direct-gh-issue-close', !/gh issue close\b/.test(
|
|
198
|
+
operative,
|
|
199
|
+
), 'the close must go through `dorfl close-merged-issues` (the provider ' +
|
|
200
|
+
'seam), NOT a direct `gh issue close` in the workflow.');
|
|
201
|
+
// It must NOT invoke a build/task/intake verb — the close-job only closes.
|
|
202
|
+
require('no-build-verbs', !/dorfl (?:do|advance|intake)\b/.test(
|
|
203
|
+
operative,
|
|
204
|
+
), 'the close-job must invoke ONLY `close-merged-issues`, not a build/task/' +
|
|
205
|
+
'intake verb (CI owns only the close job + trigger).');
|
|
206
|
+
|
|
207
|
+
// --- CI runs IN-PLACE: no isolation machinery ------------------------------
|
|
208
|
+
require('no-isolated-flag', !/--isolated\b/.test(
|
|
209
|
+
operative,
|
|
210
|
+
), 'CI runs IN-PLACE (the container IS the isolation): no `--isolated` flag.');
|
|
211
|
+
require('no-remote-flag', !/--remote\b/.test(
|
|
212
|
+
operative,
|
|
213
|
+
), 'CI runs IN-PLACE: no `--remote` flag (laptop-only affordance).');
|
|
214
|
+
|
|
215
|
+
// --- A CI concurrency group ------------------------------------------------
|
|
216
|
+
require('concurrency-group', /\bconcurrency:\s*[\s\S]*?group:/.test(
|
|
217
|
+
text,
|
|
218
|
+
), 'must carry a CI `concurrency.group` so overlapping close ticks never collide.');
|
|
219
|
+
|
|
220
|
+
// --- US #9: NO `workflows` permission; cannot self-edit triggers ------------
|
|
221
|
+
require('no-workflows-permission', !/\bworkflows:\s*write\b/.test(
|
|
222
|
+
text,
|
|
223
|
+
), 'the running job must request NO `workflows` permission (US #9: it can ' +
|
|
224
|
+
'never edit `.github/workflows/**` / rewrite its own triggers).');
|
|
225
|
+
require('never-edits-dot-github-workflows', !/\.github\/workflows\//.test(
|
|
226
|
+
operative,
|
|
227
|
+
), 'no emitted job step may touch `.github/workflows/**` (US #9).');
|
|
228
|
+
// It DOES need `issues: write` (to close) — assert the permission is present so
|
|
229
|
+
// the close can actually happen with the merge-to-main token. Scoped to operative
|
|
230
|
+
// lines: the safety comment names the permission, so the real block must carry it.
|
|
231
|
+
require('issues-write-permission', /\bissues:\s*write\b/.test(
|
|
232
|
+
operative,
|
|
233
|
+
), 'must request `issues: write` so the merge-to-main token can close the issue.');
|
|
234
|
+
|
|
235
|
+
return {ok: problems.length === 0, problems};
|
|
236
|
+
}
|
package/src/close-job.ts
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CI CLOSE-JOB driver (prd `runner-in-ci`, capability E; task
|
|
3
|
+
* `install-ci-close-job-workflow`). When work lands on `main`, this resolves which
|
|
4
|
+
* source issue(s) the landed work closes and closes them — but it OWNS none of the
|
|
5
|
+
* machinery it relies on. It is the thin JOB that WIRES three UNCHANGED engine
|
|
6
|
+
* pieces together (the Out-of-Scope fence: do NOT re-build them):
|
|
7
|
+
*
|
|
8
|
+
* - the RESOLUTION — {@link resolveClosingIssue} (`frontmatter.ts`): an artifact
|
|
9
|
+
* uses `issue:` XOR `prd:`; a lone task closes its own `issue:` directly, a
|
|
10
|
+
* fanned task reaches the number via `task.prd: → work/prds/<prd>.md prd
|
|
11
|
+
* issue:`, and `prd:` WINS on a (hand-edited) conflict;
|
|
12
|
+
* - the QUERY — {@link isSpecComplete} (`spec-complete.ts`, task
|
|
13
|
+
* `prd-complete-query`, done): a spec is COMPLETE iff ≥1 `spec:<slug>` task AND
|
|
14
|
+
* all such tasks are in `work/done/`;
|
|
15
|
+
* - the CLOSE — {@link IssueProvider.closeIssue} (`issue-provider.ts`, the atomic
|
|
16
|
+
* comment+close seam intake already uses): NO direct `gh` in this core; any
|
|
17
|
+
* informational comment rides the SAME close call (never the PR seam
|
|
18
|
+
* `postPRComment`).
|
|
19
|
+
*
|
|
20
|
+
* The closure conditions, per artifact kind:
|
|
21
|
+
*
|
|
22
|
+
* - a **lone task** (`issue:`, no `prd:`) that resides in `work/done/` — its PR
|
|
23
|
+
* merged, so its own issue closes (reason `completed`);
|
|
24
|
+
* - a **prd** (`issue:`) — closes ONLY when {@link isSpecComplete} says ALL its
|
|
25
|
+
* `spec:<slug>` tasks are in `work/done/` (reason `completed`).
|
|
26
|
+
*
|
|
27
|
+
* A prd whose query is NOT yet complete is left OPEN (the final fanned task's
|
|
28
|
+
* merge tick closes it). A lone task still outside `work/done/` is skipped. The
|
|
29
|
+
* close DEGRADES (never throws) on a missing/unauthenticated provider, exactly
|
|
30
|
+
* like intake's bounce close — the run reports the real cause and stays exit-0.
|
|
31
|
+
*
|
|
32
|
+
* This is the JOB the close-job WORKFLOW (capability E) invokes via
|
|
33
|
+
* `dorfl close-merged-issues`; the workflow is triggered on a merge to
|
|
34
|
+
* `main` (`push: {branches: [main]}`). The driver itself is provider-pluggable
|
|
35
|
+
* (it takes an {@link IssueProvider}) and reads only the `work/` tree.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import {readdirSync, readFileSync} from 'node:fs';
|
|
39
|
+
import {basename, join} from 'node:path';
|
|
40
|
+
import {
|
|
41
|
+
TASK_LIFECYCLE_FOLDERS,
|
|
42
|
+
SPEC_FOLDERS,
|
|
43
|
+
type WorkFolderKey,
|
|
44
|
+
workFolderPath,
|
|
45
|
+
workItemRel,
|
|
46
|
+
isWorkItemFile,
|
|
47
|
+
} from './work-layout.js';
|
|
48
|
+
import {parseFrontmatter, resolveClosingIssue} from './frontmatter.js';
|
|
49
|
+
import {isSpecComplete} from './spec-complete.js';
|
|
50
|
+
import {
|
|
51
|
+
type IssueProvider,
|
|
52
|
+
type IssueCloseReason,
|
|
53
|
+
GitHubIssueProvider,
|
|
54
|
+
} from './issue-provider.js';
|
|
55
|
+
|
|
56
|
+
/** The task lifecycle folders a lone-task `issue:` can reside in. */
|
|
57
|
+
const TASK_FOLDERS = TASK_LIFECYCLE_FOLDERS;
|
|
58
|
+
|
|
59
|
+
/** The spec folders an `issue:`-bearing spec can reside in. */
|
|
60
|
+
const SPEC_LIFECYCLE_FOLDERS = SPEC_FOLDERS;
|
|
61
|
+
|
|
62
|
+
/** Why the close-job acted (or did not act) on a candidate issue. */
|
|
63
|
+
export type CloseDecision =
|
|
64
|
+
| 'closed' // the issue was closed via the provider seam
|
|
65
|
+
| 'not-complete' // a prd whose query says it is not yet complete → left open
|
|
66
|
+
| 'not-landed' // a lone task not yet in work/done/ → left open
|
|
67
|
+
| 'close-failed'; // closure condition held but the provider close degraded
|
|
68
|
+
|
|
69
|
+
/** One candidate the close-job considered, with the decision it reached. */
|
|
70
|
+
export interface CloseCandidate {
|
|
71
|
+
/** The resolved issue number. */
|
|
72
|
+
issueNumber: number;
|
|
73
|
+
/** Whether the closing link was a lone task's `issue:` or a spec's `issue:`. */
|
|
74
|
+
via: 'issue' | 'spec';
|
|
75
|
+
/** The slug of the artifact carrying the closing link (spec slug / task slug). */
|
|
76
|
+
slug: string;
|
|
77
|
+
/** What the close-job decided for this candidate. */
|
|
78
|
+
decision: CloseDecision;
|
|
79
|
+
/** The provider's failure detail when `decision === 'close-failed'`. */
|
|
80
|
+
reason?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The result of one {@link runCloseJob} pass over a repo's `work/` tree. */
|
|
84
|
+
export interface CloseJobResult {
|
|
85
|
+
/** Every candidate considered, with its decision (for the human-facing log). */
|
|
86
|
+
candidates: CloseCandidate[];
|
|
87
|
+
/** Issue numbers actually closed this pass. */
|
|
88
|
+
closed: number[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Options for {@link runCloseJob}. */
|
|
92
|
+
export interface CloseJobOptions {
|
|
93
|
+
/** The repo working-tree root whose `work/` tree to scan. */
|
|
94
|
+
repoPath: string;
|
|
95
|
+
/** The issue seam to close through (GitHub adapter in production; a stub in tests). */
|
|
96
|
+
issueProvider: IssueProvider;
|
|
97
|
+
/** Environment passed through to the provider (for the `gh` adapter). */
|
|
98
|
+
env?: NodeJS.ProcessEnv;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** List the `.md` filenames in `<repoPath>/work/<folder>/`, sorted; `[]` if absent. */
|
|
102
|
+
function listMarkdown(repoPath: string, folder: WorkFolderKey): string[] {
|
|
103
|
+
const dir = workFolderPath(repoPath, folder);
|
|
104
|
+
let entries: string[];
|
|
105
|
+
try {
|
|
106
|
+
entries = readdirSync(dir);
|
|
107
|
+
} catch {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
return entries.filter((name) => isWorkItemFile(name)).sort();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Read a prd's `issue:` number by slug, scanning the prd folders. Returns
|
|
115
|
+
* `undefined` when no prd with that slug carries an `issue:` (a prd with no source
|
|
116
|
+
* issue, or a typo'd `prd:` hop — degrades to "no issue to close", never crashes).
|
|
117
|
+
*/
|
|
118
|
+
function specIssueNumber(
|
|
119
|
+
repoPath: string,
|
|
120
|
+
specSlug: string,
|
|
121
|
+
): number | undefined {
|
|
122
|
+
for (const folder of SPEC_LIFECYCLE_FOLDERS) {
|
|
123
|
+
for (const file of listMarkdown(repoPath, folder)) {
|
|
124
|
+
const fm = parseFrontmatter(
|
|
125
|
+
readFileSync(join(repoPath, workItemRel(folder, file)), 'utf8'),
|
|
126
|
+
);
|
|
127
|
+
const slug = fm.slug ?? basename(file, '.md');
|
|
128
|
+
if (slug === specSlug && fm.issue !== undefined) {
|
|
129
|
+
return fm.issue;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Resolve the DEDUPLICATED set of closure candidates from the `work/` tree, each
|
|
138
|
+
* via the UNCHANGED {@link resolveClosingIssue}:
|
|
139
|
+
*
|
|
140
|
+
* - every prd carrying `issue:` (in `work/prds/ready/` or `work/prds/tasked/`) is a
|
|
141
|
+
* prd-kind candidate keyed on its own `prd:` query;
|
|
142
|
+
* - every LONE task (`issue:` and NO `prd:`) is an `issue`-kind candidate.
|
|
143
|
+
*
|
|
144
|
+
* A fanned task carries `prd:` (NOT its own `issue:`), so it reaches the number
|
|
145
|
+
* through its prd's candidate, never as its own — the issue number lives ONLY on
|
|
146
|
+
* the prd. Deduplicated by issue number: a prd enumerated once even though many
|
|
147
|
+
* tasks point at it. Prd candidates are listed before lone-task candidates, each
|
|
148
|
+
* group slug-sorted, for a deterministic log.
|
|
149
|
+
*/
|
|
150
|
+
function resolveCandidates(repoPath: string): {
|
|
151
|
+
issueNumber: number;
|
|
152
|
+
via: 'issue' | 'spec';
|
|
153
|
+
slug: string;
|
|
154
|
+
}[] {
|
|
155
|
+
const seen = new Set<number>();
|
|
156
|
+
const specCandidates: {issueNumber: number; via: 'spec'; slug: string}[] = [];
|
|
157
|
+
const taskCandidates: {issueNumber: number; via: 'issue'; slug: string}[] =
|
|
158
|
+
[];
|
|
159
|
+
|
|
160
|
+
// Spec candidates: a spec's `issue:` closes when ITS query is complete.
|
|
161
|
+
for (const folder of SPEC_LIFECYCLE_FOLDERS) {
|
|
162
|
+
for (const file of listMarkdown(repoPath, folder)) {
|
|
163
|
+
const fm = parseFrontmatter(
|
|
164
|
+
readFileSync(join(repoPath, workItemRel(folder, file)), 'utf8'),
|
|
165
|
+
);
|
|
166
|
+
const slug = fm.slug ?? basename(file, '.md');
|
|
167
|
+
const closing = resolveClosingIssue(fm);
|
|
168
|
+
// A prd's own closing link is its `issue:` (a prd has no `prd:`); on the
|
|
169
|
+
// hand-edit conflict `prd:` wins via resolveClosingIssue, so only a true
|
|
170
|
+
// `issue:`-bearing prd becomes a candidate here.
|
|
171
|
+
if (closing?.via === 'issue' && !seen.has(closing.issue)) {
|
|
172
|
+
seen.add(closing.issue);
|
|
173
|
+
specCandidates.push({issueNumber: closing.issue, via: 'spec', slug});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Lone-task candidates: a task with `issue:` and NO `prd:` closes its OWN
|
|
179
|
+
// issue directly when it lands in work/done/.
|
|
180
|
+
for (const folder of TASK_FOLDERS) {
|
|
181
|
+
for (const file of listMarkdown(repoPath, folder)) {
|
|
182
|
+
const fm = parseFrontmatter(
|
|
183
|
+
readFileSync(join(repoPath, workItemRel(folder, file)), 'utf8'),
|
|
184
|
+
);
|
|
185
|
+
const slug = fm.slug ?? basename(file, '.md');
|
|
186
|
+
const closing = resolveClosingIssue(fm);
|
|
187
|
+
// `resolveClosingIssue` returns `via: 'issue'` ONLY when there is no `prd:`
|
|
188
|
+
// (prd wins on conflict), so a fanned task never lands here — it reaches
|
|
189
|
+
// its issue through the prd candidate above.
|
|
190
|
+
if (closing?.via === 'issue' && !seen.has(closing.issue)) {
|
|
191
|
+
seen.add(closing.issue);
|
|
192
|
+
taskCandidates.push({issueNumber: closing.issue, via: 'issue', slug});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
specCandidates.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
198
|
+
taskCandidates.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
199
|
+
return [...specCandidates, ...taskCandidates];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** True iff the lone task with this slug resides in `work/done/`. */
|
|
203
|
+
function loneTaskLanded(repoPath: string, taskSlug: string): boolean {
|
|
204
|
+
for (const file of listMarkdown(repoPath, 'done')) {
|
|
205
|
+
const fm = parseFrontmatter(
|
|
206
|
+
readFileSync(join(repoPath, workItemRel('done', file)), 'utf8'),
|
|
207
|
+
);
|
|
208
|
+
const slug = fm.slug ?? basename(file, '.md');
|
|
209
|
+
if (slug === taskSlug) {
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** The closing comment posted (atomically, on the close call) for each kind. */
|
|
217
|
+
function closeComment(via: 'issue' | 'spec', slug: string): string {
|
|
218
|
+
return via === 'spec'
|
|
219
|
+
? `Closed by dorfl: every task of spec \`${slug}\` has landed in \`work/done/\`.`
|
|
220
|
+
: `Closed by dorfl: the task \`${slug}\` has landed in \`work/done/\`.`;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Run the close-job over a repo's `work/` tree: resolve the closure candidates,
|
|
225
|
+
* apply the per-kind closure condition (a landed lone task; a prd whose
|
|
226
|
+
* {@link isSpecComplete} query holds), and close the qualifying issues through the
|
|
227
|
+
* {@link IssueProvider.closeIssue} seam (reason `completed`, an informational
|
|
228
|
+
* comment riding the SAME atomic close). REUSES the unchanged resolution + query +
|
|
229
|
+
* close — it re-implements NONE of them. NEVER throws: a degraded provider close
|
|
230
|
+
* is reported as `close-failed`, not a crash (the terminal CI tick stays exit-0).
|
|
231
|
+
*/
|
|
232
|
+
export async function runCloseJob(
|
|
233
|
+
options: CloseJobOptions,
|
|
234
|
+
): Promise<CloseJobResult> {
|
|
235
|
+
const {repoPath, issueProvider, env} = options;
|
|
236
|
+
const candidates: CloseCandidate[] = [];
|
|
237
|
+
const closed: number[] = [];
|
|
238
|
+
const completedReason: IssueCloseReason = 'completed';
|
|
239
|
+
|
|
240
|
+
for (const cand of resolveCandidates(repoPath)) {
|
|
241
|
+
// The closure CONDITION per kind — the only place this job decides; the
|
|
242
|
+
// computation of "complete" / "landed" is the UNCHANGED engine query.
|
|
243
|
+
let shouldClose: boolean;
|
|
244
|
+
let notReady: CloseDecision;
|
|
245
|
+
if (cand.via === 'spec') {
|
|
246
|
+
shouldClose = isSpecComplete({repoPath, slug: cand.slug}).complete;
|
|
247
|
+
notReady = 'not-complete';
|
|
248
|
+
} else {
|
|
249
|
+
shouldClose = loneTaskLanded(repoPath, cand.slug);
|
|
250
|
+
notReady = 'not-landed';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (!shouldClose) {
|
|
254
|
+
candidates.push({
|
|
255
|
+
issueNumber: cand.issueNumber,
|
|
256
|
+
via: cand.via,
|
|
257
|
+
slug: cand.slug,
|
|
258
|
+
decision: notReady,
|
|
259
|
+
});
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// CLOSE via the provider seam (NO direct `gh`): comment + reason + close in
|
|
264
|
+
// ONE atomic call, exactly the seam intake's bounce uses.
|
|
265
|
+
const result = await issueProvider.closeIssue({
|
|
266
|
+
cwd: repoPath,
|
|
267
|
+
issueNumber: cand.issueNumber,
|
|
268
|
+
comment: closeComment(cand.via, cand.slug),
|
|
269
|
+
reason: completedReason,
|
|
270
|
+
env,
|
|
271
|
+
});
|
|
272
|
+
if (result.closed) {
|
|
273
|
+
closed.push(cand.issueNumber);
|
|
274
|
+
candidates.push({
|
|
275
|
+
issueNumber: cand.issueNumber,
|
|
276
|
+
via: cand.via,
|
|
277
|
+
slug: cand.slug,
|
|
278
|
+
decision: 'closed',
|
|
279
|
+
});
|
|
280
|
+
} else {
|
|
281
|
+
candidates.push({
|
|
282
|
+
issueNumber: cand.issueNumber,
|
|
283
|
+
via: cand.via,
|
|
284
|
+
slug: cand.slug,
|
|
285
|
+
decision: 'close-failed',
|
|
286
|
+
reason: result.reason ?? result.instruction,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return {candidates, closed};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** Options for {@link performCloseMergedIssues} (the CLI entry). */
|
|
295
|
+
export interface PerformCloseMergedIssuesOptions {
|
|
296
|
+
/** The repo working-tree root (default: the CLI's cwd). */
|
|
297
|
+
repoPath: string;
|
|
298
|
+
/** Override the `gh` binary (tests inject a stub); production uses `gh` on PATH. */
|
|
299
|
+
ghBin?: string;
|
|
300
|
+
/** Environment passed through to the provider. */
|
|
301
|
+
env?: NodeJS.ProcessEnv;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* The CLI entry the close-job WORKFLOW invokes (`dorfl
|
|
306
|
+
* close-merged-issues`): construct the GitHub issue provider and run the
|
|
307
|
+
* close-job over the checkout's `work/` tree. Provider-pluggable via
|
|
308
|
+
* {@link runCloseJob}; this wrapper only picks the default (GitHub) adapter.
|
|
309
|
+
*/
|
|
310
|
+
export async function performCloseMergedIssues(
|
|
311
|
+
options: PerformCloseMergedIssuesOptions,
|
|
312
|
+
): Promise<CloseJobResult> {
|
|
313
|
+
const issueProvider = new GitHubIssueProvider({ghBin: options.ghBin});
|
|
314
|
+
return runCloseJob({
|
|
315
|
+
repoPath: options.repoPath,
|
|
316
|
+
issueProvider,
|
|
317
|
+
env: options.env,
|
|
318
|
+
});
|
|
319
|
+
}
|