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,924 @@
|
|
|
1
|
+
import {readdirSync, readFileSync} from 'node:fs';
|
|
2
|
+
import {basename, join} from 'node:path';
|
|
3
|
+
import {parseFrontmatter} from './frontmatter.js';
|
|
4
|
+
import {runAsync, type RunResult} from './git.js';
|
|
5
|
+
import {
|
|
6
|
+
type WorkFolderKey,
|
|
7
|
+
type SpecFolder,
|
|
8
|
+
workFolderPath,
|
|
9
|
+
workFolderRel,
|
|
10
|
+
isWorkItemFile,
|
|
11
|
+
} from './work-layout.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The **read half** of the ledger-transition seam (ADR
|
|
15
|
+
* `docs/adr/claim-ledger-vs-protected-main.md`, status: accepted — the "Read
|
|
16
|
+
* seam"). ONE entry point — "resolve the live `work/` state for a repo" — that
|
|
17
|
+
* every reader goes through, so a FUTURE strategy could resolve some states from
|
|
18
|
+
* elsewhere (e.g. work-branch tips, a dedicated ledger ref) without each reader
|
|
19
|
+
* (`scan`, eligibility's data, readiness, the claim CAS) learning a new
|
|
20
|
+
* mechanism.
|
|
21
|
+
*
|
|
22
|
+
* It is a PURE REFACTOR: there is exactly ONE strategy ({@link currentLedgerRead})
|
|
23
|
+
* and it does EXACTLY what the code did before — the local method reads the
|
|
24
|
+
* working tree (offline, cross-repo); the arbiter method reads `<arbiter>/main`
|
|
25
|
+
* via `git show`/`ls-tree`. No mode, no config, no `ledgerMode`, no new ref, no
|
|
26
|
+
* new network read.
|
|
27
|
+
*
|
|
28
|
+
* The seam is honest about the real read sources rather than pretending they are
|
|
29
|
+
* one (per the ADR — do not collapse them):
|
|
30
|
+
*
|
|
31
|
+
* - **local working tree** — a working clone reads `work/tasks/ready|tasks/done`
|
|
32
|
+
* from its checkout (pool = `tasks/ready`; staging = `tasks/backlog`, surfaced
|
|
33
|
+
* elsewhere). OFFLINE. (Pre-registry `scan`/`status` used this; `run`'s in-place
|
|
34
|
+
* checkouts still do.)
|
|
35
|
+
* - **arbiter `main`** — the human claim guard (`readiness`) and the claim CAS
|
|
36
|
+
* read the task + `work/done/` from `<arbiter>/main`.
|
|
37
|
+
* - **hub mirror `main`** — `scan`/`status` (registry model, ADR §1) read the
|
|
38
|
+
* full `work/` lifecycle from each BARE hub mirror's `main` ref. A mirror has
|
|
39
|
+
* no working tree, so this reads the committed tree via `git ls-tree`/`git
|
|
40
|
+
* show` (the SAME mechanism the arbiter `done/` read uses, widened to the
|
|
41
|
+
* full backlog set). This read itself is offline; the
|
|
42
|
+
* fetch-first contract (ADR §5/§6 — the old "scan is always offline" invariant
|
|
43
|
+
* is retired) lives ONE layer up in `scan`/`status`, which refresh the
|
|
44
|
+
* mirror's `main` before calling this method. The read STRATEGY here is
|
|
45
|
+
* unchanged either way.
|
|
46
|
+
*
|
|
47
|
+
* The signatures stay at the SEMANTIC level ("resolve live state") and storage-
|
|
48
|
+
* agnostic: the ONLY public distinction is local-vs-arbiter (no `main`/path is
|
|
49
|
+
* baked into the public shape beyond that). `gc` is NOT a consumer — its `work/`
|
|
50
|
+
* reads are job-WORKTREE discovery under `<workspacesDir>/work/*` (the execution
|
|
51
|
+
* substrate), not the `work/` lifecycle ledger this seam resolves, so it has no
|
|
52
|
+
* applicable read to route here.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* One agent-POOL task's parsed gate/deps, as resolved from the live `work/`
|
|
57
|
+
* state. The pool lives in `work/tasks/ready/` in the new layout (staging is
|
|
58
|
+
* `work/tasks/backlog/`); the type name follows the pool noun (`ready`) so a
|
|
59
|
+
* later reader cannot misread `backlog` as the pool.
|
|
60
|
+
*/
|
|
61
|
+
export interface LedgerReadyItem {
|
|
62
|
+
/** Filename within `work/tasks/ready/` (e.g. `scan.md`). */
|
|
63
|
+
file: string;
|
|
64
|
+
/** Resolved slug (frontmatter `slug:`, falling back to the filename). */
|
|
65
|
+
slug: string;
|
|
66
|
+
/** Autonomy axis 1 (DECIDED): `true` (human-only) | `undefined` (undeclared). */
|
|
67
|
+
humanOnly: boolean | undefined;
|
|
68
|
+
/** Autonomy axis 2 (DISCOVERED): `true` (open questions) | `undefined`. */
|
|
69
|
+
needsAnswers: boolean | undefined;
|
|
70
|
+
/** Slugs this item is blocked by. */
|
|
71
|
+
blockedBy: string[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The result of a prd-existence read (ADR §3a): does a prd named `<slug>` exist,
|
|
76
|
+
* and where. A prd lives at `work/prds/ready/<slug>.md`; once TASKED it rests at
|
|
77
|
+
* `work/prds/tasked/<slug>.md` (the tasked resting state, the source of truth for
|
|
78
|
+
* tasked-ness — task `prd-sliced-folder-step-a`). BOTH folders are consulted (any
|
|
79
|
+
* is enough): a prd that is up-for-tasking OR already tasked still occupies its
|
|
80
|
+
* slug, so collision detection must see it. While a prd IS being tasked its body
|
|
81
|
+
* STAYS in `work/prds/ready/` (the tasking lock no longer moves it — task
|
|
82
|
+
* `cutover-retire-slicing-advancing-markers-and-trim-folder-sets`; the transient
|
|
83
|
+
* `tasking/` folder is retired, the in-flight state is the per-item lock ref), so a
|
|
84
|
+
* mid-tasking prd is detected via its `work/prds/ready/` residence. The slug is resolved
|
|
85
|
+
* from frontmatter `slug:`, falling back to the filename — the SAME shape the task
|
|
86
|
+
* readers use.
|
|
87
|
+
*/
|
|
88
|
+
export interface SpecExistence {
|
|
89
|
+
/**
|
|
90
|
+
* Whether a prd named `<slug>` exists in `work/prds/ready/` and/or `work/prds/tasked/`
|
|
91
|
+
* (up-for-tasking OR already tasked — either still claims the slug).
|
|
92
|
+
*/
|
|
93
|
+
exists: boolean;
|
|
94
|
+
/** The spec source file, when present (`work/prds/ready/<slug>.md`). */
|
|
95
|
+
specFile: string | undefined;
|
|
96
|
+
/**
|
|
97
|
+
* The tasked resting file, when present (`work/prds/tasked/<slug>.md`) — i.e. the
|
|
98
|
+
* spec HAS BEEN tasked (the source of truth for tasked-ness, task
|
|
99
|
+
* `prd-sliced-folder-step-a`). A re-task moves it back `prds/tasked/ -> prds/ready/`.
|
|
100
|
+
*/
|
|
101
|
+
specTaskedFile: string | undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* One prd enumerated for the AUTO-TASK selection pool (ADR §3 — the
|
|
106
|
+
* "tasks-first then specs to task" priority). A prd is NOT in the task
|
|
107
|
+
* scan/candidate model, so the auto-pick pool is built HERE from `work/prds/ready/`
|
|
108
|
+
* through this single shared prd read path (the same path
|
|
109
|
+
* {@link SpecExistence} uses, widened from existence to the gate axes the tasking
|
|
110
|
+
* predicate needs). The tasking-eligibility predicate (`autoslice-gate`'s
|
|
111
|
+
* `resolveTaskingEligibility`) is applied to these by the selection layer; this
|
|
112
|
+
* reader does NOT itself decide eligibility (it just surfaces the inputs).
|
|
113
|
+
*/
|
|
114
|
+
export interface LedgerSpecItem {
|
|
115
|
+
/** Filename within `work/prds/ready/` (e.g. `auto-slice.md`). */
|
|
116
|
+
file: string;
|
|
117
|
+
/** Resolved slug (frontmatter `slug:`, falling back to the filename). */
|
|
118
|
+
slug: string;
|
|
119
|
+
/** Autonomy axis 1 (DECIDED): `true` (human-only) | `undefined`. */
|
|
120
|
+
humanOnly: boolean | undefined;
|
|
121
|
+
/** Autonomy axis 2 (DISCOVERED): `true` (open questions) | `undefined`. */
|
|
122
|
+
needsAnswers: boolean | undefined;
|
|
123
|
+
/** Spec-only cross-prd order: prd slugs that must already be TASKED first. */
|
|
124
|
+
taskedAfter: string[];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The prd pool of ONE repo, resolved from `work/prds/ready/` (the auto-task candidate
|
|
129
|
+
* source). Carries every prd's gate axes PLUS the set of already-TASKED slugs so
|
|
130
|
+
* the selection layer can resolve each prd's `taskedAfter` against `work/prds/tasked/`
|
|
131
|
+
* RESIDENCE (task `prd-sliced-folder-step-a` / prd `slicing-coherence` US #9): the
|
|
132
|
+
* FOLDER is the source of truth, like `done/` for tasks (the auto-tasker reads
|
|
133
|
+
* folder-residence; the `tasked:` marker was removed in
|
|
134
|
+
* `remove-sliced-marker-step-b`). Built
|
|
135
|
+
* through the SAME prd read path as {@link SpecExistence}; there is no second prd
|
|
136
|
+
* reader.
|
|
137
|
+
*/
|
|
138
|
+
export interface LedgerSpecPool {
|
|
139
|
+
/** Every prd in `work/prds/ready/`, sorted by slug. */
|
|
140
|
+
specs: LedgerSpecItem[];
|
|
141
|
+
/** Slugs whose spec resides in `work/prds/tasked/` (resolves `taskedAfter`). */
|
|
142
|
+
taskedSlugs: Set<string>;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* One OBSERVATION's lifecycle-pool fields, as resolved from `work/notes/observations/`
|
|
147
|
+
* (the triage candidate source for the advance auto-pick lifecycle pools, task
|
|
148
|
+
* `advance-autopick-lifecycle-pools`). An observation with NO `triaged:` marker is
|
|
149
|
+
* UNTRIAGED (still in the triage pool); a non-empty `triaged:` value (`keep` /
|
|
150
|
+
* `duplicate`) means it is SETTLED and DROPS OUT of the pool (US #30). This is the
|
|
151
|
+
* FIRST read of `work/notes/observations/` in the seam — `scan`/eligibility read only
|
|
152
|
+
* `backlog`/`done`/`specs*`.
|
|
153
|
+
*/
|
|
154
|
+
export interface LedgerObservationItem {
|
|
155
|
+
/** Filename within `work/notes/observations/` (e.g. `stray-note.md`). */
|
|
156
|
+
file: string;
|
|
157
|
+
/** Resolved slug (frontmatter `slug:`, falling back to the filename). */
|
|
158
|
+
slug: string;
|
|
159
|
+
/**
|
|
160
|
+
* The SETTLED marker (`triaged:` frontmatter): a non-empty value (`keep` /
|
|
161
|
+
* `duplicate`) drops the observation out of the triage pool; `undefined` ⇒
|
|
162
|
+
* UNTRIAGED (still a triage candidate).
|
|
163
|
+
*/
|
|
164
|
+
triaged: string | undefined;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The live `work/` lifecycle state of ONE repo as resolved from the LOCAL
|
|
169
|
+
* working tree. Storage-agnostic in shape: it is "the resolved state", not "the
|
|
170
|
+
* files on disk".
|
|
171
|
+
*/
|
|
172
|
+
export interface LocalLedgerState {
|
|
173
|
+
/** Parsed `work/tasks/ready/*.md` (the agent POOL), sorted by slug. */
|
|
174
|
+
ready: LedgerReadyItem[];
|
|
175
|
+
/** Slugs present in `work/done/` (per-repo; resolves `blockedBy`). */
|
|
176
|
+
doneSlugs: Set<string>;
|
|
177
|
+
/**
|
|
178
|
+
* `work/notes/observations/*.md` items (sorted by slug) — the triage candidate source
|
|
179
|
+
* for the advance auto-pick lifecycle pools (task
|
|
180
|
+
* `advance-autopick-lifecycle-pools`). UNTRIAGED observations (no `triaged:`
|
|
181
|
+
* marker) are the triage pool; SETTLED ones (`triaged:` non-empty) drop out.
|
|
182
|
+
*/
|
|
183
|
+
observations: LedgerObservationItem[];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** The live `work/` state of ONE repo as resolved from the arbiter. */
|
|
187
|
+
export interface ArbiterLedgerState {
|
|
188
|
+
/**
|
|
189
|
+
* The requested task's raw file contents from the arbiter (it may live in
|
|
190
|
+
* the POOL `tasks/ready/` or in `in-progress/`), or `undefined` when not found
|
|
191
|
+
* there.
|
|
192
|
+
*/
|
|
193
|
+
task: string | undefined;
|
|
194
|
+
/** Slugs present in `work/done/` on the arbiter (per-repo; resolves `blockedBy`). */
|
|
195
|
+
doneSlugs: Set<string>;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** What the LOCAL-tree resolve method needs: which repo checkout to read. */
|
|
199
|
+
export interface ResolveLocalStateInput {
|
|
200
|
+
/** The repo working-tree root whose `work/` state to resolve. */
|
|
201
|
+
repoPath: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** What the prd-existence resolve method needs: which repo + which slug. */
|
|
205
|
+
export interface ResolveSpecExistenceInput {
|
|
206
|
+
/** The repo root whose `work/prds/ready/`+`work/prds/tasked/` to read. */
|
|
207
|
+
repoPath: string;
|
|
208
|
+
/** The slug to look up (matched against frontmatter `slug:`, then filename). */
|
|
209
|
+
slug: string;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** What the prd-pool resolve method needs: which repo's `work/prds/ready/` to enumerate. */
|
|
213
|
+
export interface ResolveSpecPoolInput {
|
|
214
|
+
/** The repo working-tree root whose `work/prds/ready/` to read. */
|
|
215
|
+
repoPath: string;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* What the MIRROR-ref resolve method needs to read the full `work/` lifecycle
|
|
220
|
+
* from a BARE hub mirror's committed tree.
|
|
221
|
+
*/
|
|
222
|
+
export interface ResolveMirrorStateInput {
|
|
223
|
+
/** The bare hub mirror directory (`<workspacesDir>/repos/<key>.git`). */
|
|
224
|
+
mirrorPath: string;
|
|
225
|
+
/**
|
|
226
|
+
* The mirror-LOCAL ref whose `work/` tree to read (default `main`). A hub
|
|
227
|
+
* mirror is bare, so `main` is a LOCAL branch — read `main:work/...`, NOT
|
|
228
|
+
* `origin/main:work/...`.
|
|
229
|
+
*/
|
|
230
|
+
ref?: string;
|
|
231
|
+
/** Environment for child git processes. */
|
|
232
|
+
env?: NodeJS.ProcessEnv;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* What the MIRROR-ref prd-pool method needs: which bare hub mirror's committed
|
|
237
|
+
* `work/prds/ready/`+`work/prds/tasked/` tree to enumerate.
|
|
238
|
+
*/
|
|
239
|
+
export interface ResolveMirrorSpecPoolInput {
|
|
240
|
+
/** The bare hub mirror directory (`<workspacesDir>/repos/<key>.git`). */
|
|
241
|
+
mirrorPath: string;
|
|
242
|
+
/** The mirror-LOCAL ref whose `work/prds*` tree to read (default `main`). */
|
|
243
|
+
ref?: string;
|
|
244
|
+
/** Environment for child git processes. */
|
|
245
|
+
env?: NodeJS.ProcessEnv;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** What the ARBITER resolve method needs to read committed `work/` state. */
|
|
249
|
+
export interface ResolveArbiterStateInput {
|
|
250
|
+
/** The slug whose task file to resolve (`work/{backlog,in-progress}/<slug>.md`). */
|
|
251
|
+
slug: string;
|
|
252
|
+
/** A working clone whose remotes include the arbiter (the reads run here). */
|
|
253
|
+
cwd: string;
|
|
254
|
+
/** Name of the arbiter git remote (its `main` is the source of truth). */
|
|
255
|
+
arbiter: string;
|
|
256
|
+
/** Environment for child git processes. */
|
|
257
|
+
env?: NodeJS.ProcessEnv;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* The read-seam interface: ONE entry with THREE resolve-methods. The local
|
|
262
|
+
* method is synchronous and OFFLINE; the arbiter and mirror methods are async
|
|
263
|
+
* (they shell out to git). A future strategy implements this same interface to
|
|
264
|
+
* resolve some states elsewhere — without any reader changing.
|
|
265
|
+
*/
|
|
266
|
+
export interface LedgerReadStrategy {
|
|
267
|
+
/** Resolve a repo's live `work/` state from its LOCAL working tree (offline). */
|
|
268
|
+
resolveLocalState(input: ResolveLocalStateInput): LocalLedgerState;
|
|
269
|
+
/** Resolve a repo's live `work/` state from the ARBITER (`<arbiter>/main`). */
|
|
270
|
+
resolveArbiterState(
|
|
271
|
+
input: ResolveArbiterStateInput,
|
|
272
|
+
): Promise<ArbiterLedgerState>;
|
|
273
|
+
/**
|
|
274
|
+
* Resolve the FULL live `work/` lifecycle (backlog + done + observations) of
|
|
275
|
+
* a repo from its BARE hub mirror's `main` ref. Mirrors have no working
|
|
276
|
+
* tree, so `resolveLocalState`'s `readdirSync`/`readFileSync` cannot read them
|
|
277
|
+
* — this reads the committed tree via `git ls-tree`/`git show` (the same
|
|
278
|
+
* mechanism the arbiter method uses for `done/`, widened to the full set).
|
|
279
|
+
*/
|
|
280
|
+
resolveMirrorState(input: ResolveMirrorStateInput): Promise<LocalLedgerState>;
|
|
281
|
+
/**
|
|
282
|
+
* Enumerate the repo's prd pool from a BARE hub mirror's committed `work/prds/ready/`
|
|
283
|
+
* tree (+ already-TASKED slugs from `work/prds/tasked/` residence) — the
|
|
284
|
+
* mirror-ref counterpart of {@link LedgerReadStrategy.resolveSpecPool}, for the
|
|
285
|
+
* NO-CHECKOUT mirror-side auto-pick (`run`'s isolated loop + the one-shot/CI
|
|
286
|
+
* `advance --remote -n`). A mirror is bare, so this reads the committed tree via
|
|
287
|
+
* `git ls-tree`/`git show` (the SAME mechanism {@link resolveMirrorState} uses),
|
|
288
|
+
* not a working-tree `readdirSync`. Returns the SAME {@link LedgerSpecPool} shape
|
|
289
|
+
* the working-tree reader returns, so the tasking-eligibility predicate
|
|
290
|
+
* (`taskableSpecs`) applies byte-identically to either source.
|
|
291
|
+
*/
|
|
292
|
+
resolveMirrorSpecPool(
|
|
293
|
+
input: ResolveMirrorSpecPoolInput,
|
|
294
|
+
): Promise<LedgerSpecPool>;
|
|
295
|
+
/**
|
|
296
|
+
* Resolve whether a prd named `<slug>` exists in the LOCAL working tree's
|
|
297
|
+
* `work/prds/ready/` (the prd source — where a mid-tasking prd ALSO rests now that the
|
|
298
|
+
* `tasking/` folder is retired) and/or `work/prds/tasked/` (the tasked resting
|
|
299
|
+
* state). The slug is resolved from each candidate file's frontmatter `slug:`,
|
|
300
|
+
* falling back to the filename — the SAME shape the task readers use.
|
|
301
|
+
*
|
|
302
|
+
* This is the FIRST prd read path in the seam: `ledger-read.ts`/`scan.ts` read
|
|
303
|
+
* only `backlog`/`done`, NEVER `work/prds/ready/`. It is added here
|
|
304
|
+
* so the §3a slug-namespace resolver, and later the auto-tasking / `do prd:` work,
|
|
305
|
+
* share ONE prd read path rather than each growing a bespoke scan. Synchronous
|
|
306
|
+
* and OFFLINE (a working-tree read), like {@link resolveLocalState}.
|
|
307
|
+
*/
|
|
308
|
+
resolveSpecExistence(input: ResolveSpecExistenceInput): SpecExistence;
|
|
309
|
+
/**
|
|
310
|
+
* Enumerate the repo's prd pool from `work/prds/ready/` (the auto-task candidate
|
|
311
|
+
* source for the `do`/`run` "tasks-first then specs to task" priority, ADR
|
|
312
|
+
* §3). Returns every prd's gate axes (`humanOnly`/`needsAnswers`/`taskedAfter`)
|
|
313
|
+
* PLUS the set of already-TASKED slugs so the selection layer can resolve
|
|
314
|
+
* `taskedAfter` against `work/prds/tasked/` residence (the FOLDER is the source of
|
|
315
|
+
* truth) and apply `autoslice-gate`'s
|
|
316
|
+
* predicate. This is the SAME prd read path {@link resolveSpecExistence} uses,
|
|
317
|
+
* widened from a single-slug existence check to a full enumeration — NOT a
|
|
318
|
+
* second prd reader. Synchronous and OFFLINE (a working-tree read), like
|
|
319
|
+
* {@link resolveLocalState}.
|
|
320
|
+
*/
|
|
321
|
+
resolveSpecPool(input: ResolveSpecPoolInput): LedgerSpecPool;
|
|
322
|
+
/**
|
|
323
|
+
* Enumerate `work/tasks/backlog/*.md` (the TASK STAGING folder) into the SAME
|
|
324
|
+
* {@link LedgerReadyItem} shape `resolveLocalState().ready` returns for the pool
|
|
325
|
+
* — the SURFACE-on-staging widening (prd
|
|
326
|
+
* `staging-surface-and-apply-promote-safety` F2). Synchronous + OFFLINE
|
|
327
|
+
* (working-tree read), like {@link resolveLocalState}. The pool / staging
|
|
328
|
+
* folders are distinct durable status folders (one-slug-one-folder — a slug
|
|
329
|
+
* is in at most one), so the two reads compose without de-duplication
|
|
330
|
+
* gymnastics. Missing folder reads as empty. CONSUMED ONLY by the lifecycle
|
|
331
|
+
* GATHER under the `surfaceStaging` gate — the BUILD/claim pool stays
|
|
332
|
+
* pool-only (`resolveLocalState().ready`), untouched by this read.
|
|
333
|
+
*/
|
|
334
|
+
resolveLocalTaskStaging(input: ResolveLocalStateInput): LedgerReadyItem[];
|
|
335
|
+
/**
|
|
336
|
+
* Enumerate `work/prds/proposed/*.md` (the PRD STAGING folder) into the
|
|
337
|
+
* SAME {@link LedgerSpecItem} shape `resolveSpecPool().specs` returns for the
|
|
338
|
+
* pool — the PRD-symmetric `surfaceStaging` widening (prd
|
|
339
|
+
* `staging-surface-and-apply-promote-safety` F2, prd q4 answer). Sync + OFFLINE.
|
|
340
|
+
*/
|
|
341
|
+
resolveLocalSpecStaging(input: ResolveSpecPoolInput): LedgerSpecItem[];
|
|
342
|
+
/**
|
|
343
|
+
* Enumerate `work/prds/tasked/*.md` (the TASKED resting folder) into the SAME
|
|
344
|
+
* {@link LedgerSpecItem} shape `resolveSpecPool().specs` returns. UNLIKE the pool
|
|
345
|
+
* (`prds/ready/`) and staging (`prds/proposed/`) readers, this exists so the
|
|
346
|
+
* lifecycle GATHER can surface/apply a `needsAnswers:true` prd that drifted
|
|
347
|
+
* AFTER it was tasked and rests IN PLACE in `prds/tasked/` (WORK-CONTRACT
|
|
348
|
+
* "A PRD that has drifted AFTER it was TASKED"). Without it, such a prd's
|
|
349
|
+
* ANSWERED sidecar is enumerated by no pool and the human's answer is STRANDED
|
|
350
|
+
* (observation `tasked-prd-needsanswers-sidecar-stranded-no-apply-pool`).
|
|
351
|
+
* `resolveSpecPool` deliberately returns tasked specs only as `taskedSlugs`
|
|
352
|
+
* (residence, for `taskedAfter`), NOT as enumerable gate-bearing items, so this
|
|
353
|
+
* is a SEPARATE read. Sync + OFFLINE.
|
|
354
|
+
*/
|
|
355
|
+
resolveLocalSpecTasked(input: ResolveSpecPoolInput): LedgerSpecItem[];
|
|
356
|
+
/**
|
|
357
|
+
* Mirror-ref counterpart of {@link resolveLocalTaskStaging}: read
|
|
358
|
+
* `<ref>:work/tasks/backlog/*.md` from a BARE hub mirror via `git ls-tree` +
|
|
359
|
+
* `git show` (the SAME mechanism `resolveMirrorState` uses for the pool).
|
|
360
|
+
*/
|
|
361
|
+
resolveMirrorTaskStaging(
|
|
362
|
+
input: ResolveMirrorStateInput,
|
|
363
|
+
): Promise<LedgerReadyItem[]>;
|
|
364
|
+
/**
|
|
365
|
+
* Mirror-ref counterpart of {@link resolveLocalSpecStaging}: read
|
|
366
|
+
* `<ref>:work/prds/proposed/*.md` from a bare mirror.
|
|
367
|
+
*/
|
|
368
|
+
resolveMirrorSpecStaging(
|
|
369
|
+
input: ResolveMirrorSpecPoolInput,
|
|
370
|
+
): Promise<LedgerSpecItem[]>;
|
|
371
|
+
/**
|
|
372
|
+
* Mirror-ref counterpart of {@link resolveLocalSpecTasked}: read
|
|
373
|
+
* `<ref>:work/prds/tasked/*.md` from a bare mirror, so a `needsAnswers` tasked
|
|
374
|
+
* prd's answered sidecar is never stranded on the mirror-side advance path
|
|
375
|
+
* either.
|
|
376
|
+
*/
|
|
377
|
+
resolveMirrorSpecTasked(
|
|
378
|
+
input: ResolveMirrorSpecPoolInput,
|
|
379
|
+
): Promise<LedgerSpecItem[]>;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// --- The sole strategy: exactly today's behaviour -------------------------
|
|
383
|
+
|
|
384
|
+
function listMarkdown(dir: string): string[] {
|
|
385
|
+
let entries: string[];
|
|
386
|
+
try {
|
|
387
|
+
entries = readdirSync(dir);
|
|
388
|
+
} catch {
|
|
389
|
+
return [];
|
|
390
|
+
}
|
|
391
|
+
return entries.filter((name) => isWorkItemFile(name)).sort();
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function slugForFile(dir: string, file: string): string {
|
|
395
|
+
const content = readFileSync(join(dir, file), 'utf8');
|
|
396
|
+
const fm = parseFrontmatter(content);
|
|
397
|
+
return fm.slug ?? basename(file, '.md');
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Read a folder of TASK items (`tasks-ready` or `tasks-backlog`) from the local
|
|
402
|
+
* tree into the {@link LedgerReadyItem[]} shape. Factored so the POOL reader
|
|
403
|
+
* (`tasks/ready`) and the STAGING reader (`tasks/backlog`, the `surfaceStaging`
|
|
404
|
+
* widening) share one parse path — the two folders carry the SAME item shape
|
|
405
|
+
* (frontmatter + body), only the trust polarity differs.
|
|
406
|
+
*/
|
|
407
|
+
function readLocalTaskFolder(
|
|
408
|
+
repoPath: string,
|
|
409
|
+
folder: 'tasks-ready' | 'tasks-backlog',
|
|
410
|
+
): LedgerReadyItem[] {
|
|
411
|
+
const dir = workFolderPath(repoPath, folder);
|
|
412
|
+
const items: LedgerReadyItem[] = [];
|
|
413
|
+
for (const file of listMarkdown(dir)) {
|
|
414
|
+
const content = readFileSync(join(dir, file), 'utf8');
|
|
415
|
+
const fm = parseFrontmatter(content);
|
|
416
|
+
items.push({
|
|
417
|
+
file,
|
|
418
|
+
slug: fm.slug ?? basename(file, '.md'),
|
|
419
|
+
humanOnly: fm.humanOnly,
|
|
420
|
+
needsAnswers: fm.needsAnswers,
|
|
421
|
+
blockedBy: fm.blockedBy,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
return items.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/** Read `work/tasks/ready/*.md` (the agent POOL) from the local tree, parsed and sorted by slug. */
|
|
428
|
+
function readLocalReady(repoPath: string): LedgerReadyItem[] {
|
|
429
|
+
return readLocalTaskFolder(repoPath, 'tasks-ready');
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Read `work/tasks/backlog/*.md` (the TASK STAGING folder, prd
|
|
434
|
+
* `staging-surface-and-apply-promote-safety` F2) from the local tree. Same
|
|
435
|
+
* {@link LedgerReadyItem} shape as the pool reader — the SURFACE-on-staging
|
|
436
|
+
* widening only enumerates items; it does NOT promote them.
|
|
437
|
+
*/
|
|
438
|
+
function readLocalTaskStaging(repoPath: string): LedgerReadyItem[] {
|
|
439
|
+
return readLocalTaskFolder(repoPath, 'tasks-backlog');
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Read `work/prds/proposed/*.md` (the PRD STAGING folder, the prd twin
|
|
444
|
+
* of {@link readLocalTaskStaging}, prd q4 answer) from the local tree. Returns
|
|
445
|
+
* the SAME {@link LedgerSpecItem} shape `resolveSpecPool().specs` returns.
|
|
446
|
+
*/
|
|
447
|
+
function readLocalSpecStaging(repoPath: string): LedgerSpecItem[] {
|
|
448
|
+
return readLocalSpecFolder(repoPath, 'specs-proposed');
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Read `work/prds/tasked/*.md` (the TASKED resting folder) into the SAME
|
|
453
|
+
* {@link LedgerSpecItem} shape. Used by the lifecycle gather to surface/apply a
|
|
454
|
+
* `needsAnswers` prd that drifted after tasking and rests in place in
|
|
455
|
+
* `prds/tasked/` — so its answered sidecar is never stranded.
|
|
456
|
+
*/
|
|
457
|
+
function readLocalSpecTasked(repoPath: string): LedgerSpecItem[] {
|
|
458
|
+
return readLocalSpecFolder(repoPath, 'specs-tasked');
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/** Shared body for the local prd-FOLDER readers (proposed/tasked) — same item shape. */
|
|
462
|
+
function readLocalSpecFolder(
|
|
463
|
+
repoPath: string,
|
|
464
|
+
folder: 'specs-proposed' | 'specs-tasked',
|
|
465
|
+
): LedgerSpecItem[] {
|
|
466
|
+
const dir = workFolderPath(repoPath, folder);
|
|
467
|
+
const specs: LedgerSpecItem[] = [];
|
|
468
|
+
for (const file of listMarkdown(dir)) {
|
|
469
|
+
const content = readFileSync(join(dir, file), 'utf8');
|
|
470
|
+
const fm = parseFrontmatter(content);
|
|
471
|
+
specs.push({
|
|
472
|
+
file,
|
|
473
|
+
slug: fm.slug ?? basename(file, '.md'),
|
|
474
|
+
humanOnly: fm.humanOnly,
|
|
475
|
+
needsAnswers: fm.needsAnswers,
|
|
476
|
+
taskedAfter: fm.taskedAfter,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
return specs.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/** Collect the slugs present in `work/done/` on the local tree. */
|
|
483
|
+
function readLocalDoneSlugs(repoPath: string): Set<string> {
|
|
484
|
+
const dir = workFolderPath(repoPath, 'done');
|
|
485
|
+
const slugs = new Set<string>();
|
|
486
|
+
for (const file of listMarkdown(dir)) {
|
|
487
|
+
slugs.add(slugForFile(dir, file));
|
|
488
|
+
}
|
|
489
|
+
return slugs;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Read `work/notes/observations/*.md` (slug-sorted) from the local tree.
|
|
494
|
+
*
|
|
495
|
+
* Identity rule (task `observation-identity-is-its-filename-not-a-foreign-slug`):
|
|
496
|
+
* an observation's IDENTITY is its FILENAME, NEVER a foreign frontmatter `slug:`.
|
|
497
|
+
* Earlier this read `fm.slug ?? basename(file)`, which let the review-nits minting
|
|
498
|
+
* (which wrote the REVIEWED TASK's slug into `slug:` as a back-pointer) drive the
|
|
499
|
+
* lifecycle pool to emit `obs:<reviewed-slug>` — a key that did not round-trip
|
|
500
|
+
* through `findItemPath` (filename-only) and collided with the reviewed task in
|
|
501
|
+
* `work/done/`. Identity is now ALWAYS the basename, so the enumerate→resolve
|
|
502
|
+
* round-trip is total by construction and a stray frontmatter `slug:` cannot
|
|
503
|
+
* re-break it. The back-pointer lives in `reviewOf:` instead.
|
|
504
|
+
*/
|
|
505
|
+
function readLocalObservations(repoPath: string): LedgerObservationItem[] {
|
|
506
|
+
const dir = workFolderPath(repoPath, 'observations');
|
|
507
|
+
const items: LedgerObservationItem[] = [];
|
|
508
|
+
for (const file of listMarkdown(dir)) {
|
|
509
|
+
const content = readFileSync(join(dir, file), 'utf8');
|
|
510
|
+
const fm = parseFrontmatter(content);
|
|
511
|
+
items.push({
|
|
512
|
+
file,
|
|
513
|
+
slug: basename(file, '.md'),
|
|
514
|
+
triaged: fm.triaged,
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
return items.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Does a prd named `slug` exist in `<repoPath>/work/<folder>/`? A prd source file
|
|
522
|
+
* is `work/prds/ready/*.md` (where a mid-tasking prd also rests — the `tasking/` folder is
|
|
523
|
+
* retired); a tasked prd rests at `work/prds/tasked/*.md` (the source of truth for
|
|
524
|
+
* tasked-ness). We match the slug against each file's
|
|
525
|
+
* frontmatter `slug:` (falling back to the filename) — the SAME shape the task
|
|
526
|
+
* readers use — so a renamed file whose frontmatter slug matches still resolves.
|
|
527
|
+
* Returns the matching filename, or `undefined`.
|
|
528
|
+
*/
|
|
529
|
+
function findSpecFileBySlug(
|
|
530
|
+
repoPath: string,
|
|
531
|
+
folder: SpecFolder,
|
|
532
|
+
slug: string,
|
|
533
|
+
): string | undefined {
|
|
534
|
+
const dir = workFolderPath(repoPath, folder);
|
|
535
|
+
for (const file of listMarkdown(dir)) {
|
|
536
|
+
if (slugForFile(dir, file) === slug) {
|
|
537
|
+
return file;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return undefined;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Enumerate `work/prds/ready/*.md` into the auto-task prd pool (the tasks-first/prd
|
|
545
|
+
* priority's prd source) — the SAME prd read path {@link findSpecFileBySlug} uses,
|
|
546
|
+
* widened from a single-slug existence check to a full enumeration. Each prd's
|
|
547
|
+
* slug is resolved from frontmatter `slug:` (falling back to the filename) and
|
|
548
|
+
* its gate axes (`humanOnly`/`needsAnswers`/`taskedAfter`) parsed. The
|
|
549
|
+
* already-TASKED set is RESIDENCE in `work/prds/tasked/` (task
|
|
550
|
+
* `prd-sliced-folder-step-a` / prd `slicing-coherence` US #9): the FOLDER is the
|
|
551
|
+
* source of truth (the build-machine `done/` analogue), so `taskedAfter` resolves
|
|
552
|
+
* against `prds/tasked/` residence (mirroring `blockedBy` -> `done/`). The `tasked:`
|
|
553
|
+
* frontmatter marker was removed entirely in `remove-sliced-marker-step-b`. This
|
|
554
|
+
* matches `tasking.ts`'s `readTaskedSlugs`. Missing folders read as empty.
|
|
555
|
+
*/
|
|
556
|
+
function readLocalSpecPool(repoPath: string): LocalSpecPool {
|
|
557
|
+
const dir = workFolderPath(repoPath, 'specs-ready');
|
|
558
|
+
const specs: LedgerSpecItem[] = [];
|
|
559
|
+
for (const file of listMarkdown(dir)) {
|
|
560
|
+
const content = readFileSync(join(dir, file), 'utf8');
|
|
561
|
+
const fm = parseFrontmatter(content);
|
|
562
|
+
specs.push({
|
|
563
|
+
file,
|
|
564
|
+
slug: fm.slug ?? basename(file, '.md'),
|
|
565
|
+
humanOnly: fm.humanOnly,
|
|
566
|
+
needsAnswers: fm.needsAnswers,
|
|
567
|
+
taskedAfter: fm.taskedAfter,
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
specs.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
571
|
+
|
|
572
|
+
// Tasked-ness is RESIDENCE in `work/prds/tasked/` — the FOLDER is the source of
|
|
573
|
+
// truth, like `done/` for tasks (the `tasked:` marker was removed in
|
|
574
|
+
// `remove-sliced-marker-step-b`), mirroring tasking.ts's readTaskedSlugs. Missing
|
|
575
|
+
// folder reads as empty.
|
|
576
|
+
const taskedSlugs = new Set<string>();
|
|
577
|
+
const taskedDir = workFolderPath(repoPath, 'specs-tasked');
|
|
578
|
+
for (const file of listMarkdown(taskedDir)) {
|
|
579
|
+
const content = readFileSync(join(taskedDir, file), 'utf8');
|
|
580
|
+
const fm = parseFrontmatter(content);
|
|
581
|
+
taskedSlugs.add(fm.slug ?? basename(file, '.md'));
|
|
582
|
+
}
|
|
583
|
+
return {specs, taskedSlugs};
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/** Internal alias for {@link LedgerSpecPool} (kept local to the reader). */
|
|
587
|
+
type LocalSpecPool = LedgerSpecPool;
|
|
588
|
+
|
|
589
|
+
/** Run git, returning the raw result (no throw) — for soft checks. */
|
|
590
|
+
function gitSoft(
|
|
591
|
+
args: string[],
|
|
592
|
+
cwd: string,
|
|
593
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
594
|
+
): Promise<RunResult> {
|
|
595
|
+
return runAsync('git', args, cwd, {env});
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Read the task file's contents from `<arbiter>/main`. It may live in `backlog/`
|
|
600
|
+
* (the normal claim case) or `in-progress/` (start --resume); read whichever
|
|
601
|
+
* exists. Returns `undefined` when the task is not found there.
|
|
602
|
+
*/
|
|
603
|
+
async function readTaskOnArbiter(
|
|
604
|
+
slug: string,
|
|
605
|
+
arbiter: string,
|
|
606
|
+
cwd: string,
|
|
607
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
608
|
+
): Promise<string | undefined> {
|
|
609
|
+
for (const folder of ['tasks-ready', 'in-progress'] as const) {
|
|
610
|
+
const object = `${arbiter}/main:${workFolderRel(folder)}/${slug}.md`;
|
|
611
|
+
const show = await gitSoft(['show', object], cwd, env);
|
|
612
|
+
if (show.status === 0) {
|
|
613
|
+
return show.stdout;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
return undefined;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Collect the slugs present in `work/done/` on `<arbiter>/main`, read from the
|
|
621
|
+
* committed arbiter tree (`ls-tree`). The slug is the filename minus `.md`
|
|
622
|
+
* (matching how claim/done moves name the file after its slug).
|
|
623
|
+
*/
|
|
624
|
+
async function readDoneSlugsOnArbiter(
|
|
625
|
+
arbiter: string,
|
|
626
|
+
cwd: string,
|
|
627
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
628
|
+
): Promise<Set<string>> {
|
|
629
|
+
return readDoneSlugsFromTree(`${arbiter}/main`, cwd, env);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// --- Reading a committed `work/` tree (ref-based; bare-mirror or arbiter) ----
|
|
633
|
+
//
|
|
634
|
+
// These helpers read `work/{backlog,done}` from a git REF via
|
|
635
|
+
// `git ls-tree`/`git show` — the ONLY mechanism that works against a BARE repo
|
|
636
|
+
// (no working tree). `treeBase` is the `<ref>:work/<folder>` prefix; `cwd` is
|
|
637
|
+
// the repo the `git -C <cwd>` commands run in (the mirror itself for the mirror
|
|
638
|
+
// method, a working clone for the arbiter method).
|
|
639
|
+
|
|
640
|
+
/** `git ls-tree --name-only <base>` → the `.md` filenames (sorted), or `[]`. */
|
|
641
|
+
async function listMarkdownInTree(
|
|
642
|
+
base: string,
|
|
643
|
+
cwd: string,
|
|
644
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
645
|
+
): Promise<string[]> {
|
|
646
|
+
const tree = await gitSoft(['ls-tree', '--name-only', base], cwd, env);
|
|
647
|
+
if (tree.status !== 0) {
|
|
648
|
+
// The folder does not exist on this ref — nothing there.
|
|
649
|
+
return [];
|
|
650
|
+
}
|
|
651
|
+
return tree.stdout
|
|
652
|
+
.split('\n')
|
|
653
|
+
.map((s) => s.trim())
|
|
654
|
+
.filter((name) => isWorkItemFile(name))
|
|
655
|
+
.sort();
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/** `git show <base>/<file>` → the file's raw contents, or `undefined`. */
|
|
659
|
+
async function showInTree(
|
|
660
|
+
base: string,
|
|
661
|
+
file: string,
|
|
662
|
+
cwd: string,
|
|
663
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
664
|
+
): Promise<string | undefined> {
|
|
665
|
+
const show = await gitSoft(['show', `${base}/${file}`], cwd, env);
|
|
666
|
+
return show.status === 0 ? show.stdout : undefined;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/** Collect the slugs in `<ref>:work/done` (filename minus `.md`). */
|
|
670
|
+
async function readDoneSlugsFromTree(
|
|
671
|
+
ref: string,
|
|
672
|
+
cwd: string,
|
|
673
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
674
|
+
): Promise<Set<string>> {
|
|
675
|
+
const slugs = new Set<string>();
|
|
676
|
+
for (const file of await listMarkdownInTree(
|
|
677
|
+
`${ref}:${workFolderRel('done')}`,
|
|
678
|
+
cwd,
|
|
679
|
+
env,
|
|
680
|
+
)) {
|
|
681
|
+
slugs.add(file.slice(0, -'.md'.length));
|
|
682
|
+
}
|
|
683
|
+
return slugs;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Parse `<ref>:work/tasks/<folder>/*.md` from a committed tree into
|
|
688
|
+
* {@link LedgerReadyItem[]}, sorted by slug. Factored so the POOL + STAGING
|
|
689
|
+
* mirror reads share ONE parse path (mirrors `readLocalTaskFolder`).
|
|
690
|
+
*/
|
|
691
|
+
async function readTaskFolderFromTree(
|
|
692
|
+
folder: 'tasks-ready' | 'tasks-backlog',
|
|
693
|
+
ref: string,
|
|
694
|
+
cwd: string,
|
|
695
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
696
|
+
): Promise<LedgerReadyItem[]> {
|
|
697
|
+
const base = `${ref}:${workFolderRel(folder)}`;
|
|
698
|
+
const items: LedgerReadyItem[] = [];
|
|
699
|
+
for (const file of await listMarkdownInTree(base, cwd, env)) {
|
|
700
|
+
const content = await showInTree(base, file, cwd, env);
|
|
701
|
+
if (content === undefined) {
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
const fm = parseFrontmatter(content);
|
|
705
|
+
items.push({
|
|
706
|
+
file,
|
|
707
|
+
slug: fm.slug ?? basename(file, '.md'),
|
|
708
|
+
humanOnly: fm.humanOnly,
|
|
709
|
+
needsAnswers: fm.needsAnswers,
|
|
710
|
+
blockedBy: fm.blockedBy,
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
return items.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/** Parse `<ref>:work/tasks/ready/*.md` into pool items, sorted by slug. */
|
|
717
|
+
async function readReadyFromTree(
|
|
718
|
+
ref: string,
|
|
719
|
+
cwd: string,
|
|
720
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
721
|
+
): Promise<LedgerReadyItem[]> {
|
|
722
|
+
return readTaskFolderFromTree('tasks-ready', ref, cwd, env);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/** Parse `<ref>:work/tasks/backlog/*.md` (TASK STAGING) into items, sorted by slug. */
|
|
726
|
+
async function readTaskStagingFromTree(
|
|
727
|
+
ref: string,
|
|
728
|
+
cwd: string,
|
|
729
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
730
|
+
): Promise<LedgerReadyItem[]> {
|
|
731
|
+
return readTaskFolderFromTree('tasks-backlog', ref, cwd, env);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/** Parse `<ref>:work/prds/proposed/*.md` (PRD STAGING) into prd items, sorted by slug. */
|
|
735
|
+
async function readSpecStagingFromTree(
|
|
736
|
+
ref: string,
|
|
737
|
+
cwd: string,
|
|
738
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
739
|
+
): Promise<LedgerSpecItem[]> {
|
|
740
|
+
return readSpecFolderFromTree('specs-proposed', ref, cwd, env);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/** Parse `<ref>:work/prds/tasked/*.md` (TASKED resting) into prd items, sorted by slug. */
|
|
744
|
+
async function readSpecTaskedFromTree(
|
|
745
|
+
ref: string,
|
|
746
|
+
cwd: string,
|
|
747
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
748
|
+
): Promise<LedgerSpecItem[]> {
|
|
749
|
+
return readSpecFolderFromTree('specs-tasked', ref, cwd, env);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/** Shared body for the mirror-ref prd-FOLDER readers (proposed/tasked) — same item shape. */
|
|
753
|
+
async function readSpecFolderFromTree(
|
|
754
|
+
folder: 'specs-proposed' | 'specs-tasked',
|
|
755
|
+
ref: string,
|
|
756
|
+
cwd: string,
|
|
757
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
758
|
+
): Promise<LedgerSpecItem[]> {
|
|
759
|
+
const base = `${ref}:${workFolderRel(folder)}`;
|
|
760
|
+
const specs: LedgerSpecItem[] = [];
|
|
761
|
+
for (const file of await listMarkdownInTree(base, cwd, env)) {
|
|
762
|
+
const content = await showInTree(base, file, cwd, env);
|
|
763
|
+
if (content === undefined) {
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
const fm = parseFrontmatter(content);
|
|
767
|
+
specs.push({
|
|
768
|
+
file,
|
|
769
|
+
slug: fm.slug ?? basename(file, '.md'),
|
|
770
|
+
humanOnly: fm.humanOnly,
|
|
771
|
+
needsAnswers: fm.needsAnswers,
|
|
772
|
+
taskedAfter: fm.taskedAfter,
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
return specs.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Parse `<ref>:work/prds/ready/*.md` into the auto-task prd pool, sorted by slug, plus
|
|
780
|
+
* the already-TASKED slugs from `<ref>:work/prds/tasked/` RESIDENCE (the folder is
|
|
781
|
+
* the source of truth, mirroring the working-tree {@link readLocalSpecPool}). Reads
|
|
782
|
+
* a committed tree (bare-mirror or any ref) via `ls-tree`/`show`. Missing folders
|
|
783
|
+
* read as empty.
|
|
784
|
+
*/
|
|
785
|
+
async function readSpecPoolFromTree(
|
|
786
|
+
ref: string,
|
|
787
|
+
cwd: string,
|
|
788
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
789
|
+
): Promise<LedgerSpecPool> {
|
|
790
|
+
const specBase = `${ref}:${workFolderRel('specs-ready')}`;
|
|
791
|
+
const specs: LedgerSpecItem[] = [];
|
|
792
|
+
for (const file of await listMarkdownInTree(specBase, cwd, env)) {
|
|
793
|
+
const content = await showInTree(specBase, file, cwd, env);
|
|
794
|
+
if (content === undefined) {
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
const fm = parseFrontmatter(content);
|
|
798
|
+
specs.push({
|
|
799
|
+
file,
|
|
800
|
+
slug: fm.slug ?? basename(file, '.md'),
|
|
801
|
+
humanOnly: fm.humanOnly,
|
|
802
|
+
needsAnswers: fm.needsAnswers,
|
|
803
|
+
taskedAfter: fm.taskedAfter,
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
specs.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
807
|
+
|
|
808
|
+
// Tasked-ness is RESIDENCE in `work/prds/tasked/` — the FOLDER is the source of
|
|
809
|
+
// truth (the `tasked:` marker was removed in `remove-sliced-marker-step-b`),
|
|
810
|
+
// exactly as the working-tree reader resolves it.
|
|
811
|
+
const taskedBase = `${ref}:${workFolderRel('specs-tasked')}`;
|
|
812
|
+
const taskedSlugs = new Set<string>();
|
|
813
|
+
for (const file of await listMarkdownInTree(taskedBase, cwd, env)) {
|
|
814
|
+
const content = await showInTree(taskedBase, file, cwd, env);
|
|
815
|
+
if (content === undefined) {
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
const fm = parseFrontmatter(content);
|
|
819
|
+
taskedSlugs.add(fm.slug ?? basename(file, '.md'));
|
|
820
|
+
}
|
|
821
|
+
return {specs, taskedSlugs};
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Parse `<ref>:work/notes/observations/*.md` into items, sorted by slug. Identity is the
|
|
826
|
+
* FILENAME (mirrors {@link readLocalObservations}) so the in-place + mirror
|
|
827
|
+
* enumerations agree, and a foreign frontmatter `slug:` cannot break the
|
|
828
|
+
* enumerate→resolve round-trip.
|
|
829
|
+
*/
|
|
830
|
+
async function readObservationsFromTree(
|
|
831
|
+
ref: string,
|
|
832
|
+
cwd: string,
|
|
833
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
834
|
+
): Promise<LedgerObservationItem[]> {
|
|
835
|
+
const base = `${ref}:${workFolderRel('observations')}`;
|
|
836
|
+
const items: LedgerObservationItem[] = [];
|
|
837
|
+
for (const file of await listMarkdownInTree(base, cwd, env)) {
|
|
838
|
+
const content = await showInTree(base, file, cwd, env);
|
|
839
|
+
if (content === undefined) {
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
const fm = parseFrontmatter(content);
|
|
843
|
+
items.push({
|
|
844
|
+
file,
|
|
845
|
+
slug: basename(file, '.md'),
|
|
846
|
+
triaged: fm.triaged,
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
return items.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* The ONLY ledger-read strategy: current behaviour. The local method reads the
|
|
854
|
+
* working tree (offline); the arbiter method reads `<arbiter>/main`. A future
|
|
855
|
+
* strategy would be a different object implementing the same interface — chosen
|
|
856
|
+
* NOWHERE today (no mode/config selects it).
|
|
857
|
+
*/
|
|
858
|
+
export const currentLedgerRead: LedgerReadStrategy = {
|
|
859
|
+
resolveLocalState({repoPath}) {
|
|
860
|
+
return {
|
|
861
|
+
ready: readLocalReady(repoPath),
|
|
862
|
+
doneSlugs: readLocalDoneSlugs(repoPath),
|
|
863
|
+
observations: readLocalObservations(repoPath),
|
|
864
|
+
};
|
|
865
|
+
},
|
|
866
|
+
async resolveArbiterState({slug, cwd, arbiter, env}) {
|
|
867
|
+
const task = await readTaskOnArbiter(slug, arbiter, cwd, env);
|
|
868
|
+
const doneSlugs = await readDoneSlugsOnArbiter(arbiter, cwd, env);
|
|
869
|
+
return {task, doneSlugs};
|
|
870
|
+
},
|
|
871
|
+
resolveSpecExistence({repoPath, slug}) {
|
|
872
|
+
const specFile = findSpecFileBySlug(repoPath, 'specs-ready', slug);
|
|
873
|
+
const specTaskedFile = findSpecFileBySlug(repoPath, 'specs-tasked', slug);
|
|
874
|
+
return {
|
|
875
|
+
exists: specFile !== undefined || specTaskedFile !== undefined,
|
|
876
|
+
specFile,
|
|
877
|
+
specTaskedFile,
|
|
878
|
+
};
|
|
879
|
+
},
|
|
880
|
+
resolveSpecPool({repoPath}) {
|
|
881
|
+
return readLocalSpecPool(repoPath);
|
|
882
|
+
},
|
|
883
|
+
resolveLocalTaskStaging({repoPath}) {
|
|
884
|
+
return readLocalTaskStaging(repoPath);
|
|
885
|
+
},
|
|
886
|
+
resolveLocalSpecStaging({repoPath}) {
|
|
887
|
+
return readLocalSpecStaging(repoPath);
|
|
888
|
+
},
|
|
889
|
+
resolveLocalSpecTasked({repoPath}) {
|
|
890
|
+
return readLocalSpecTasked(repoPath);
|
|
891
|
+
},
|
|
892
|
+
async resolveMirrorTaskStaging({mirrorPath, ref = 'main', env}) {
|
|
893
|
+
return readTaskStagingFromTree(ref, mirrorPath, env);
|
|
894
|
+
},
|
|
895
|
+
async resolveMirrorSpecStaging({mirrorPath, ref = 'main', env}) {
|
|
896
|
+
return readSpecStagingFromTree(ref, mirrorPath, env);
|
|
897
|
+
},
|
|
898
|
+
async resolveMirrorSpecTasked({mirrorPath, ref = 'main', env}) {
|
|
899
|
+
return readSpecTaskedFromTree(ref, mirrorPath, env);
|
|
900
|
+
},
|
|
901
|
+
async resolveMirrorState({mirrorPath, ref = 'main', env}) {
|
|
902
|
+
// A hub mirror is BARE — read the full `work/` lifecycle from its committed
|
|
903
|
+
// `<ref>:work/...` tree, running git INSIDE the mirror (`git -C <mirror>`).
|
|
904
|
+
// The ref is mirror-LOCAL (`main`), never `origin/main`.
|
|
905
|
+
const [ready, doneSlugs, observations] = await Promise.all([
|
|
906
|
+
readReadyFromTree(ref, mirrorPath, env),
|
|
907
|
+
readDoneSlugsFromTree(ref, mirrorPath, env),
|
|
908
|
+
readObservationsFromTree(ref, mirrorPath, env),
|
|
909
|
+
]);
|
|
910
|
+
return {ready, doneSlugs, observations};
|
|
911
|
+
},
|
|
912
|
+
async resolveMirrorSpecPool({mirrorPath, ref = 'main', env}) {
|
|
913
|
+
// The prd pool from the bare mirror's committed `<ref>:work/prds*` tree — the
|
|
914
|
+
// mirror-ref counterpart of `resolveSpecPool` (a working-tree read). Same shape,
|
|
915
|
+
// so `taskableSpecs` applies identically to either source.
|
|
916
|
+
return readSpecPoolFromTree(ref, mirrorPath, env);
|
|
917
|
+
},
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
/**
|
|
921
|
+
* The active ledger-read strategy. There is exactly one (current behaviour);
|
|
922
|
+
* this indirection is the seam's single insertion point — NOT a selectable mode.
|
|
923
|
+
*/
|
|
924
|
+
export const ledgerRead: LedgerReadStrategy = currentLedgerRead;
|