dorfl 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advance-ci-template.d.ts +3 -3
- package/dist/advance-ci-template.js +1 -1
- package/dist/advance-ci-template.js.map +1 -1
- package/dist/advance-classify.d.ts +5 -5
- package/dist/advance-classify.d.ts.map +1 -1
- package/dist/advance-classify.js +4 -4
- package/dist/advance-drivers.d.ts +8 -8
- package/dist/advance-drivers.d.ts.map +1 -1
- package/dist/advance-drivers.js +20 -8
- package/dist/advance-drivers.js.map +1 -1
- package/dist/advance-isolated.d.ts +3 -3
- package/dist/advance-isolated.d.ts.map +1 -1
- package/dist/advance-isolated.js +1 -1
- package/dist/advance-lifecycle-template.d.ts +2 -2
- package/dist/advance-lifecycle-template.d.ts.map +1 -1
- package/dist/advance-lifecycle-template.js +85 -13
- package/dist/advance-lifecycle-template.js.map +1 -1
- package/dist/advance-loop-driver.d.ts +3 -3
- package/dist/advance-loop-driver.d.ts.map +1 -1
- package/dist/advance-loop-driver.js +1 -1
- package/dist/advance-treeless-publish.d.ts +24 -1
- package/dist/advance-treeless-publish.d.ts.map +1 -1
- package/dist/advance-treeless-publish.js +41 -0
- package/dist/advance-treeless-publish.js.map +1 -1
- package/dist/advance.d.ts +69 -17
- package/dist/advance.d.ts.map +1 -1
- package/dist/advance.js +409 -102
- package/dist/advance.js.map +1 -1
- package/dist/advancing-lock.d.ts +31 -3
- package/dist/advancing-lock.d.ts.map +1 -1
- package/dist/advancing-lock.js +55 -5
- package/dist/advancing-lock.js.map +1 -1
- package/dist/agent-launch.d.ts +12 -0
- package/dist/agent-launch.d.ts.map +1 -1
- package/dist/agent-launch.js +22 -12
- package/dist/agent-launch.js.map +1 -1
- package/dist/agent-stop.d.ts +40 -2
- package/dist/agent-stop.d.ts.map +1 -1
- package/dist/agent-stop.js +30 -2
- package/dist/agent-stop.js.map +1 -1
- package/dist/apply-decide.d.ts +19 -5
- package/dist/apply-decide.d.ts.map +1 -1
- package/dist/apply-decide.js +38 -9
- package/dist/apply-decide.js.map +1 -1
- package/dist/apply-merge-action.d.ts +20 -8
- package/dist/apply-merge-action.d.ts.map +1 -1
- package/dist/apply-merge-action.js +44 -9
- package/dist/apply-merge-action.js.map +1 -1
- package/dist/apply-persist.d.ts +62 -31
- package/dist/apply-persist.d.ts.map +1 -1
- package/dist/apply-persist.js +173 -44
- package/dist/apply-persist.js.map +1 -1
- package/dist/apply-stuck-action.d.ts +151 -0
- package/dist/apply-stuck-action.d.ts.map +1 -0
- package/dist/apply-stuck-action.js +125 -0
- package/dist/apply-stuck-action.js.map +1 -0
- package/dist/brand.d.ts +12 -1
- package/dist/brand.d.ts.map +1 -1
- package/dist/brand.js +2 -1
- package/dist/brand.js.map +1 -1
- package/dist/buildable-body.d.ts +14 -14
- package/dist/buildable-body.js +9 -9
- package/dist/claim-cas.d.ts +3 -3
- package/dist/claim-cas.js +1 -1
- package/dist/claim-cas.js.map +1 -1
- package/dist/cli-spinner.d.ts +1 -1
- package/dist/cli-spinner.js +1 -1
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +385 -128
- package/dist/cli.js.map +1 -1
- package/dist/close-job-template.d.ts +3 -3
- package/dist/close-job-template.js +9 -9
- package/dist/close-job.d.ts +8 -8
- package/dist/close-job.js +25 -25
- package/dist/close-job.js.map +1 -1
- package/dist/complete.d.ts +9 -6
- package/dist/complete.d.ts.map +1 -1
- package/dist/complete.js +99 -45
- package/dist/complete.js.map +1 -1
- package/dist/concurrency.d.ts +1 -1
- package/dist/concurrency.js +1 -1
- package/dist/config.d.ts +86 -40
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +61 -9
- package/dist/config.js.map +1 -1
- package/dist/continue-branch.d.ts +1 -1
- package/dist/continue-branch.d.ts.map +1 -1
- package/dist/continue-branch.js +23 -1
- package/dist/continue-branch.js.map +1 -1
- package/dist/cwd-section.js +1 -1
- package/dist/cwd-section.js.map +1 -1
- package/dist/decision-engine.d.ts +39 -11
- package/dist/decision-engine.d.ts.map +1 -1
- package/dist/decision-engine.js +10 -6
- package/dist/decision-engine.js.map +1 -1
- package/dist/do-autopick.d.ts +6 -6
- package/dist/do-autopick.d.ts.map +1 -1
- package/dist/do-autopick.js +16 -6
- package/dist/do-autopick.js.map +1 -1
- package/dist/do-config.d.ts +4 -4
- package/dist/do-config.js +3 -3
- package/dist/do-config.js.map +1 -1
- package/dist/do-remote-auto.d.ts +2 -2
- package/dist/do-remote-auto.js +1 -1
- package/dist/do.d.ts +74 -81
- package/dist/do.d.ts.map +1 -1
- package/dist/do.js +439 -50
- package/dist/do.js.map +1 -1
- package/dist/drop-source.d.ts +2 -2
- package/dist/env-config.d.ts.map +1 -1
- package/dist/env-config.js +19 -11
- package/dist/env-config.js.map +1 -1
- package/dist/failure-cause.d.ts +3 -2
- package/dist/failure-cause.d.ts.map +1 -1
- package/dist/failure-cause.js +28 -1
- package/dist/failure-cause.js.map +1 -1
- package/dist/format.d.ts +6 -6
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +13 -30
- package/dist/format.js.map +1 -1
- package/dist/frontmatter.d.ts +28 -15
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +38 -24
- package/dist/frontmatter.js.map +1 -1
- package/dist/gc.d.ts +65 -6
- package/dist/gc.d.ts.map +1 -1
- package/dist/gc.js +126 -9
- package/dist/gc.js.map +1 -1
- package/dist/github.d.ts +14 -0
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +73 -0
- package/dist/github.js.map +1 -1
- package/dist/harness.d.ts +25 -0
- package/dist/harness.d.ts.map +1 -1
- package/dist/harness.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/install-ci-branch-protection.d.ts +133 -39
- package/dist/install-ci-branch-protection.d.ts.map +1 -1
- package/dist/install-ci-branch-protection.js +191 -49
- package/dist/install-ci-branch-protection.js.map +1 -1
- package/dist/install-ci-capabilities/advance-lifecycle.d.ts +1 -1
- package/dist/install-ci-capabilities/advance-lifecycle.js +1 -1
- package/dist/install-ci-capabilities/close-job.d.ts +1 -1
- package/dist/install-ci-capabilities/close-job.js +1 -1
- package/dist/install-ci-capabilities/example-noop.d.ts +1 -1
- package/dist/install-ci-capabilities/example-noop.js +1 -1
- package/dist/install-ci-capabilities/intake.d.ts +2 -2
- package/dist/install-ci-capabilities/intake.js +2 -2
- package/dist/install-ci-capabilities/verify.d.ts +1 -1
- package/dist/install-ci-capabilities/verify.js +1 -1
- package/dist/install-ci-core.d.ts +24 -4
- package/dist/install-ci-core.d.ts.map +1 -1
- package/dist/install-ci-core.js +12 -5
- package/dist/install-ci-core.js.map +1 -1
- package/dist/install-ci-github.d.ts +33 -1
- package/dist/install-ci-github.d.ts.map +1 -1
- package/dist/install-ci-github.js +74 -1
- package/dist/install-ci-github.js.map +1 -1
- package/dist/install-ci.d.ts +1 -1
- package/dist/install-ci.js +4 -4
- package/dist/install-ci.js.map +1 -1
- package/dist/install-skills.d.ts +123 -0
- package/dist/install-skills.d.ts.map +1 -0
- package/dist/install-skills.js +100 -0
- package/dist/install-skills.js.map +1 -0
- package/dist/intake-event.d.ts +6 -6
- package/dist/intake-event.js +6 -6
- package/dist/intake-marker.d.ts +3 -3
- package/dist/intake-marker.d.ts.map +1 -1
- package/dist/intake-triage.d.ts +1 -1
- package/dist/intake-triage.js +2 -2
- package/dist/intake-trigger-template.d.ts +8 -8
- package/dist/intake-trigger-template.d.ts.map +1 -1
- package/dist/intake-trigger-template.js +17 -17
- package/dist/intake-trigger-template.js.map +1 -1
- package/dist/intake.d.ts +65 -52
- package/dist/intake.d.ts.map +1 -1
- package/dist/intake.js +92 -76
- package/dist/intake.js.map +1 -1
- package/dist/integration-core.d.ts +27 -24
- package/dist/integration-core.d.ts.map +1 -1
- package/dist/integration-core.js +191 -77
- package/dist/integration-core.js.map +1 -1
- package/dist/integrator.d.ts +1 -1
- package/dist/integrator.d.ts.map +1 -1
- package/dist/integrator.js +19 -3
- package/dist/integrator.js.map +1 -1
- package/dist/isolation.d.ts +4 -4
- package/dist/isolation.d.ts.map +1 -1
- package/dist/isolation.js +9 -0
- package/dist/isolation.js.map +1 -1
- package/dist/issue-provider.d.ts +4 -4
- package/dist/issue-provider.js +1 -1
- package/dist/item-lock.d.ts +216 -149
- package/dist/item-lock.d.ts.map +1 -1
- package/dist/item-lock.js +345 -270
- package/dist/item-lock.js.map +1 -1
- package/dist/item-path.d.ts +2 -2
- package/dist/item-path.js +2 -2
- package/dist/ledger-lint.d.ts +9 -9
- package/dist/ledger-lint.js +9 -9
- package/dist/ledger-read.d.ts +57 -57
- package/dist/ledger-read.d.ts.map +1 -1
- package/dist/ledger-read.js +24 -24
- package/dist/ledger-read.js.map +1 -1
- package/dist/ledger-write.d.ts +33 -28
- package/dist/ledger-write.d.ts.map +1 -1
- package/dist/ledger-write.js +100 -122
- package/dist/ledger-write.js.map +1 -1
- package/dist/lifecycle-gather.d.ts +18 -1
- package/dist/lifecycle-gather.d.ts.map +1 -1
- package/dist/lifecycle-gather.js +23 -17
- package/dist/lifecycle-gather.js.map +1 -1
- package/dist/lifecycle-pools.d.ts +44 -7
- package/dist/lifecycle-pools.d.ts.map +1 -1
- package/dist/lifecycle-pools.js +27 -7
- package/dist/lifecycle-pools.js.map +1 -1
- package/dist/merge-question-surfacer.d.ts +18 -4
- package/dist/merge-question-surfacer.d.ts.map +1 -1
- package/dist/merge-question-surfacer.js +20 -5
- package/dist/merge-question-surfacer.js.map +1 -1
- package/dist/migrate-stuck-locks.d.ts +129 -0
- package/dist/migrate-stuck-locks.d.ts.map +1 -0
- package/dist/migrate-stuck-locks.js +355 -0
- package/dist/migrate-stuck-locks.js.map +1 -0
- package/dist/mint-adr.js +4 -4
- package/dist/mirror-pool-scan.d.ts +2 -2
- package/dist/mirror-pool-scan.js +3 -3
- package/dist/mirror-pool-scan.js.map +1 -1
- package/dist/needs-attention.d.ts +304 -27
- package/dist/needs-attention.d.ts.map +1 -1
- package/dist/needs-attention.js +542 -67
- package/dist/needs-attention.js.map +1 -1
- package/dist/orphan-sidecar.d.ts +10 -6
- package/dist/orphan-sidecar.d.ts.map +1 -1
- package/dist/orphan-sidecar.js +35 -2
- package/dist/orphan-sidecar.js.map +1 -1
- package/dist/pi-harness.d.ts +16 -0
- package/dist/pi-harness.d.ts.map +1 -1
- package/dist/pi-harness.js +82 -2
- package/dist/pi-harness.js.map +1 -1
- package/dist/placement.d.ts +8 -8
- package/dist/placement.js +3 -3
- package/dist/prd-to-spec.d.ts.map +1 -1
- package/dist/prd-to-spec.js +9 -5
- package/dist/prd-to-spec.js.map +1 -1
- package/dist/prompt.d.ts +16 -19
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +17 -19
- package/dist/prompt.js.map +1 -1
- package/dist/protocol/CLAIM-PROTOCOL.md +17 -10
- package/dist/protocol/REVIEW-PROTOCOL.md +4 -1
- package/dist/protocol/SURFACE-PROTOCOL.md +16 -2
- package/dist/protocol/TASKING-PROTOCOL.md +3 -1
- package/dist/protocol/WORK-CONTRACT.md +22 -18
- package/dist/protocol/task-template.md +1 -1
- package/dist/readiness.d.ts +1 -1
- package/dist/reap-branches.d.ts +12 -9
- package/dist/reap-branches.d.ts.map +1 -1
- package/dist/reap-branches.js +25 -7
- package/dist/reap-branches.js.map +1 -1
- package/dist/recover-isolated.d.ts +12 -0
- package/dist/recover-isolated.d.ts.map +1 -1
- package/dist/recover-isolated.js +6 -1
- package/dist/recover-isolated.js.map +1 -1
- package/dist/repo-config.d.ts +23 -2
- package/dist/repo-config.d.ts.map +1 -1
- package/dist/repo-config.js +64 -18
- package/dist/repo-config.js.map +1 -1
- package/dist/repo-mirror.d.ts.map +1 -1
- package/dist/repo-mirror.js +18 -2
- package/dist/repo-mirror.js.map +1 -1
- package/dist/review-gate.d.ts +3 -3
- package/dist/review-gate.d.ts.map +1 -1
- package/dist/review-gate.js +11 -10
- package/dist/review-gate.js.map +1 -1
- package/dist/review-verdict.d.ts +2 -2
- package/dist/review-verdict.d.ts.map +1 -1
- package/dist/review-verdict.js +2 -2
- package/dist/review-verdict.js.map +1 -1
- package/dist/run.d.ts +2 -2
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +58 -23
- package/dist/run.js.map +1 -1
- package/dist/scan.d.ts +26 -17
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +29 -15
- package/dist/scan.js.map +1 -1
- package/dist/select-order.d.ts +1 -1
- package/dist/select-priority.d.ts +14 -14
- package/dist/select-priority.d.ts.map +1 -1
- package/dist/select-priority.js +5 -5
- package/dist/select-priority.js.map +1 -1
- package/dist/sidecar-apply.js +1 -1
- package/dist/sidecar-apply.js.map +1 -1
- package/dist/sidecar.d.ts +47 -12
- package/dist/sidecar.d.ts.map +1 -1
- package/dist/sidecar.js +84 -4
- package/dist/sidecar.js.map +1 -1
- package/dist/skills/answer-questions/SKILL.md +89 -0
- package/dist/skills/capture-signal/SKILL.md +52 -0
- package/dist/skills/convert-from-prd-to-spec/SKILL.md +90 -0
- package/dist/skills/drive-tasks/SKILL.md +218 -0
- package/dist/skills/from-idea/SKILL.md +83 -0
- package/dist/skills/merge-prs/SKILL.md +70 -0
- package/dist/skills/orchestrate/SKILL.md +101 -0
- package/dist/skills/promote/SKILL.md +35 -0
- package/dist/skills/review/SKILL.md +16 -0
- package/dist/skills/setup/SKILL.md +258 -0
- package/dist/skills/setup/protocol/ADR-FORMAT.md +47 -0
- package/dist/skills/setup/protocol/CLAIM-PROTOCOL.md +224 -0
- package/dist/skills/setup/protocol/REVIEW-PROTOCOL.md +122 -0
- package/dist/skills/setup/protocol/SURFACE-PROTOCOL.md +135 -0
- package/dist/skills/setup/protocol/TASKING-PROTOCOL.md +124 -0
- package/dist/skills/setup/protocol/WORK-CONTRACT.md +280 -0
- package/dist/skills/setup/protocol/spec-template.md +71 -0
- package/dist/skills/setup/protocol/task-template.md +65 -0
- package/dist/skills/surface-questions/SKILL.md +16 -0
- package/dist/skills/to-spec/SKILL.md +34 -0
- package/dist/skills/to-task/SKILL.md +19 -0
- package/dist/skills/triage-observations/SKILL.md +78 -0
- package/dist/skills/work/SKILL.md +51 -0
- package/dist/slug-namespace.d.ts +6 -6
- package/dist/slug-namespace.js +8 -8
- package/dist/slug-namespace.js.map +1 -1
- package/dist/spec-complete.d.ts.map +1 -1
- package/dist/spec-complete.js +4 -5
- package/dist/spec-complete.js.map +1 -1
- package/dist/start.d.ts +1 -1
- package/dist/start.d.ts.map +1 -1
- package/dist/start.js +54 -60
- package/dist/start.js.map +1 -1
- package/dist/status.d.ts +3 -3
- package/dist/status.js +4 -4
- package/dist/status.js.map +1 -1
- package/dist/surface-gate.d.ts +2 -2
- package/dist/surface-gate.d.ts.map +1 -1
- package/dist/surface-gate.js +10 -3
- package/dist/surface-gate.js.map +1 -1
- package/dist/surface-persist.d.ts +2 -2
- package/dist/surface-persist.d.ts.map +1 -1
- package/dist/surface-persist.js +1 -1
- package/dist/surface-persist.js.map +1 -1
- package/dist/tasker-review-loop.d.ts +11 -10
- package/dist/tasker-review-loop.d.ts.map +1 -1
- package/dist/tasker-review-loop.js +8 -8
- package/dist/tasker-review-loop.js.map +1 -1
- package/dist/tasking-eligibility.d.ts +21 -21
- package/dist/tasking-eligibility.d.ts.map +1 -1
- package/dist/tasking-eligibility.js +10 -10
- package/dist/tasking-lock.d.ts +10 -10
- package/dist/tasking-lock.d.ts.map +1 -1
- package/dist/tasking-lock.js +69 -49
- package/dist/tasking-lock.js.map +1 -1
- package/dist/tasking.d.ts +73 -39
- package/dist/tasking.d.ts.map +1 -1
- package/dist/tasking.js +309 -95
- package/dist/tasking.js.map +1 -1
- package/dist/triage-gate.d.ts +1 -1
- package/dist/triage-persist.d.ts +15 -11
- package/dist/triage-persist.d.ts.map +1 -1
- package/dist/triage-persist.js +48 -18
- package/dist/triage-persist.js.map +1 -1
- package/dist/vendor/incur/agents.d.ts +58 -0
- package/dist/vendor/incur/agents.d.ts.map +1 -0
- package/dist/vendor/incur/agents.js +343 -0
- package/dist/vendor/incur/agents.js.map +1 -0
- package/dist/verify-workflow-template.d.ts +1 -1
- package/dist/verify-workflow-template.js +3 -3
- package/dist/watch-session.d.ts +11 -3
- package/dist/watch-session.d.ts.map +1 -1
- package/dist/watch-session.js +94 -7
- package/dist/watch-session.js.map +1 -1
- package/dist/work-layout.d.ts +15 -9
- package/dist/work-layout.d.ts.map +1 -1
- package/dist/work-layout.js +14 -9
- package/dist/work-layout.js.map +1 -1
- package/dist/workspace.d.ts +2 -2
- package/package.json +2 -2
- package/src/advance-ci-template.ts +4 -4
- package/src/advance-classify.ts +5 -5
- package/src/advance-drivers.ts +26 -13
- package/src/advance-isolated.ts +3 -3
- package/src/advance-lifecycle-template.ts +98 -13
- package/src/advance-loop-driver.ts +3 -3
- package/src/advance-treeless-publish.ts +46 -1
- package/src/advance.ts +495 -115
- package/src/advancing-lock.ts +102 -7
- package/src/agent-launch.ts +37 -12
- package/src/agent-stop.ts +60 -2
- package/src/apply-decide.ts +38 -9
- package/src/apply-merge-action.ts +49 -11
- package/src/apply-persist.ts +236 -62
- package/src/apply-stuck-action.ts +260 -0
- package/src/brand.ts +14 -2
- package/src/buildable-body.ts +14 -14
- package/src/claim-cas.ts +4 -4
- package/src/cli-spinner.ts +1 -1
- package/src/cli.ts +472 -141
- package/src/close-job-template.ts +9 -9
- package/src/close-job.ts +26 -26
- package/src/complete.ts +121 -63
- package/src/concurrency.ts +1 -1
- package/src/config.ts +143 -49
- package/src/continue-branch.ts +23 -1
- package/src/cwd-section.ts +1 -1
- package/src/decision-engine.ts +57 -19
- package/src/do-autopick.ts +21 -10
- package/src/do-config.ts +7 -7
- package/src/do-remote-auto.ts +2 -2
- package/src/do.ts +558 -85
- package/src/drop-source.ts +2 -2
- package/src/env-config.ts +19 -11
- package/src/failure-cause.ts +30 -1
- package/src/format.ts +13 -33
- package/src/frontmatter.ts +55 -35
- package/src/gc.ts +172 -9
- package/src/github.ts +78 -0
- package/src/harness.ts +25 -0
- package/src/index.ts +10 -0
- package/src/install-ci-branch-protection.ts +283 -58
- package/src/install-ci-capabilities/advance-lifecycle.ts +1 -1
- package/src/install-ci-capabilities/close-job.ts +1 -1
- package/src/install-ci-capabilities/example-noop.ts +1 -1
- package/src/install-ci-capabilities/intake.ts +2 -2
- package/src/install-ci-capabilities/verify.ts +1 -1
- package/src/install-ci-core.ts +34 -7
- package/src/install-ci-github.ts +87 -1
- package/src/install-ci.ts +4 -4
- package/src/install-skills.ts +166 -0
- package/src/intake-event.ts +6 -6
- package/src/intake-marker.ts +3 -3
- package/src/intake-triage.ts +2 -2
- package/src/intake-trigger-template.ts +18 -18
- package/src/intake.ts +138 -103
- package/src/integration-core.ts +234 -100
- package/src/integrator.ts +22 -9
- package/src/isolation.ts +13 -4
- package/src/issue-provider.ts +4 -4
- package/src/item-lock.ts +505 -361
- package/src/item-path.ts +2 -2
- package/src/ledger-lint.ts +9 -9
- package/src/ledger-read.ts +81 -81
- package/src/ledger-write.ts +137 -152
- package/src/lifecycle-gather.ts +45 -22
- package/src/lifecycle-pools.ts +71 -13
- package/src/merge-question-surfacer.ts +32 -8
- package/src/migrate-stuck-locks.ts +451 -0
- package/src/mint-adr.ts +4 -4
- package/src/mirror-pool-scan.ts +5 -5
- package/src/needs-attention.ts +877 -104
- package/src/orphan-sidecar.ts +49 -8
- package/src/pi-harness.ts +82 -2
- package/src/placement.ts +8 -8
- package/src/prd-to-spec.ts +13 -5
- package/src/prompt.ts +20 -25
- package/src/readiness.ts +1 -1
- package/src/reap-branches.ts +38 -14
- package/src/recover-isolated.ts +18 -1
- package/src/repo-config.ts +66 -17
- package/src/repo-mirror.ts +23 -1
- package/src/review-gate.ts +12 -11
- package/src/review-verdict.ts +3 -3
- package/src/run.ts +69 -23
- package/src/scan.ts +36 -22
- package/src/select-order.ts +1 -1
- package/src/select-priority.ts +15 -15
- package/src/sidecar-apply.ts +1 -1
- package/src/sidecar.ts +141 -14
- package/src/slug-namespace.ts +10 -10
- package/src/spec-complete.ts +4 -5
- package/src/start.ts +57 -63
- package/src/status.ts +7 -7
- package/src/surface-gate.ts +12 -5
- package/src/surface-persist.ts +3 -3
- package/src/tasker-review-loop.ts +18 -17
- package/src/tasking-eligibility.ts +21 -21
- package/src/tasking-lock.ts +75 -60
- package/src/tasking.ts +381 -135
- package/src/triage-gate.ts +1 -1
- package/src/triage-persist.ts +71 -27
- package/src/vendor/incur/LICENSE +21 -0
- package/src/vendor/incur/README.md +19 -0
- package/src/vendor/incur/agents.ts +392 -0
- package/src/verify-workflow-template.ts +3 -3
- package/src/watch-session.ts +102 -7
- package/src/work-layout.ts +14 -9
- package/src/workspace.ts +2 -2
package/src/scan.ts
CHANGED
|
@@ -53,7 +53,7 @@ export function lifecycleGatesFrom(config: {
|
|
|
53
53
|
surfaceBlockers: boolean;
|
|
54
54
|
/**
|
|
55
55
|
* Spec `staging-surface-and-apply-promote-safety` F2 — the gate that widens
|
|
56
|
-
* the SURFACE candidate set into STAGING (`tasks/backlog/` + `
|
|
56
|
+
* the SURFACE candidate set into STAGING (`tasks/backlog/` + `specs/proposed/`).
|
|
57
57
|
* Threaded here so the `scan --json` `lifecycle.surface[]` reflects the
|
|
58
58
|
* expanded pool and the CI matrix enumerates staging surface legs. BUILD/claim
|
|
59
59
|
* stays pool-only — only this lifecycle path widens.
|
|
@@ -78,7 +78,7 @@ export interface ScannedTriageItem {
|
|
|
78
78
|
}
|
|
79
79
|
/**
|
|
80
80
|
* A surface/apply lifecycle item, with its namespace. SURFACE only ever carries
|
|
81
|
-
* `needsAnswers` task/
|
|
81
|
+
* `needsAnswers` task/spec items (an observation with no sidecar goes to `triage`,
|
|
82
82
|
* not `surface`). APPLY, however, ALSO carries an ANSWERED OBSERVATION: since the
|
|
83
83
|
* classifier (`buildLifecyclePools`) routes an observation whose sidecar is
|
|
84
84
|
* all-answered to `apply` (CONSUME, always-on), the projection MUST keep it here
|
|
@@ -108,7 +108,7 @@ export interface ScannedBlockedItem {
|
|
|
108
108
|
export interface ScannedLifecycle {
|
|
109
109
|
/** Untriaged observations → `obs:<slug>` legs (gated by `observationTriage`). */
|
|
110
110
|
triage: ScannedTriageItem[];
|
|
111
|
-
/** `needsAnswers` task/
|
|
111
|
+
/** `needsAnswers` task/spec items with no answered sidecar → surface legs (gated by `surfaceBlockers`). */
|
|
112
112
|
surface: ScannedBlockedItem[];
|
|
113
113
|
/**
|
|
114
114
|
* Items WITH an all-answered sidecar → apply legs (CONSUME, always-on). Carries
|
|
@@ -132,7 +132,7 @@ export interface ScannedItem extends ReadyItem {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
|
-
* A
|
|
135
|
+
* A SPEC entry in `scan --json`'s taskable-spec pool — the SAME shape an eligible
|
|
136
136
|
* task carries in `items[]` (a `slug` + an `eligibility.eligible` boolean), so
|
|
137
137
|
* the propose-matrix `jq` filter mirrors the task one: `select(.eligibility.eligible)
|
|
138
138
|
* | "spec:" + .slug`. "Eligible" here means TASKABLE — the per-repo `autoTask`
|
|
@@ -159,7 +159,7 @@ export interface RepoReport {
|
|
|
159
159
|
items: ScannedItem[];
|
|
160
160
|
/**
|
|
161
161
|
* The TASKABLE-SPEC pool for this repo (the `specs[]` companion of `items[]`):
|
|
162
|
-
* every spec in `work/
|
|
162
|
+
* every spec in `work/specs/ready/` not already in `work/specs/tasked/`, each tagged with
|
|
163
163
|
* `eligibility.eligible` from {@link taskableSpecs} (the SAME `autoslice-gate`
|
|
164
164
|
* predicate the mirror-side pool scan uses — NOT a forked predicate). This is
|
|
165
165
|
* what makes the propose-mode CI matrix enumerate `spec:<slug>` legs for ready
|
|
@@ -183,7 +183,7 @@ export interface RepoReport {
|
|
|
183
183
|
*/
|
|
184
184
|
lifecycle: ScannedLifecycle;
|
|
185
185
|
/**
|
|
186
|
-
* The one-slug-one-folder LINT result (
|
|
186
|
+
* The one-slug-one-folder LINT result (spec `ledger-integrity` story 3): any
|
|
187
187
|
* slug present in MORE THAN ONE `work/` status folder in THIS repo's ledger.
|
|
188
188
|
* Empty ⇒ a clean ledger. Non-empty ⇒ a corrupt ledger the formatter WARNS
|
|
189
189
|
* about loudly and a human must resolve (never auto-fixed). Derived by listing
|
|
@@ -191,7 +191,7 @@ export interface RepoReport {
|
|
|
191
191
|
*/
|
|
192
192
|
ledgerDuplicates: DuplicateSlug[];
|
|
193
193
|
/**
|
|
194
|
-
* The PER-ITEM LOCK in-flight view for this repo (
|
|
194
|
+
* The PER-ITEM LOCK in-flight view for this repo (spec
|
|
195
195
|
* `ledger-status-per-item-lock-refs` US #8; task
|
|
196
196
|
* `needs-attention-as-stuck-lock-state`): the held lock entries read from the
|
|
197
197
|
* repo's `refs/dorfl/lock/*` refs — `active` holds (in-progress) and
|
|
@@ -240,7 +240,7 @@ export function readReadyItems(repoPath: string): ReadyItem[] {
|
|
|
240
240
|
* through the EXACT same eligibility path as in-place (`do-autopick`), not a fork.
|
|
241
241
|
*/
|
|
242
242
|
/**
|
|
243
|
-
* Score a
|
|
243
|
+
* Score a spec pool down to its TASKABLE subset, then label every spec with
|
|
244
244
|
* `eligibility.eligible` (true ⇔ taskable). REUSES {@link taskableSpecs} —
|
|
245
245
|
* the SAME `autoslice-gate` predicate the mirror-side `scanMirrorPool` + the
|
|
246
246
|
* in-place `do-autopick` pool already run — so what is taskable does not
|
|
@@ -280,8 +280,8 @@ export function scoreSpecs(
|
|
|
280
280
|
* re-enumeration — a pure shape map over the already-gated pools.
|
|
281
281
|
*
|
|
282
282
|
* The pool items' `namespace` is the wider {@link SelectedNamespace}. SURFACE by
|
|
283
|
-
* construction only carries `'task'`/`'
|
|
284
|
-
* `triage` candidate, never `surface`), so it narrows + drops any non-task/
|
|
283
|
+
* construction only carries `'task'`/`'spec'` (an observation with no sidecar is a
|
|
284
|
+
* `triage` candidate, never `surface`), so it narrows + drops any non-task/spec
|
|
285
285
|
* defensively. APPLY additionally admits `'observation'` (an answered observation
|
|
286
286
|
* sidecar → apply), and it MUST be kept so the matrix `jq` emits its
|
|
287
287
|
* `observation:<slug>` apply leg — narrowing it away here is exactly what stranded
|
|
@@ -324,7 +324,7 @@ export function scoreItems(
|
|
|
324
324
|
counts: {totalItems: number; totalEligible: number},
|
|
325
325
|
heldSlugs: Set<string> = new Set(),
|
|
326
326
|
): ScannedItem[] {
|
|
327
|
-
// HELD-SLUG SUBTRACTION (
|
|
327
|
+
// HELD-SLUG SUBTRACTION (spec `ledger-status-per-item-lock-refs` US #15; task
|
|
328
328
|
// `claim-acquires-unified-lock-no-body-move`): exclude any pool slug whose
|
|
329
329
|
// per-item lock is currently held — the eligible pool is "in `tasks/ready/` on
|
|
330
330
|
// `main` AND no lock held".
|
|
@@ -435,7 +435,7 @@ export async function scan(
|
|
|
435
435
|
// the lock refs from the mirror's origin; non-fatal (empty set on any fault),
|
|
436
436
|
// so the read-only scan degrades gracefully exactly as its config reads do.
|
|
437
437
|
const heldSlugs = await heldTaskSlugs(mirror.path, 'origin', options.env);
|
|
438
|
-
// The PER-ITEM LOCK in-flight view (
|
|
438
|
+
// The PER-ITEM LOCK in-flight view (spec US #8; task
|
|
439
439
|
// `needs-attention-as-stuck-lock-state`): ADDITIONALLY read the full held
|
|
440
440
|
// lock entries (action × state + reason) from the mirror's lock refs, so the
|
|
441
441
|
// scan surfaces held (in-progress) + stuck (needs-attention) items. Read from
|
|
@@ -448,7 +448,7 @@ export async function scan(
|
|
|
448
448
|
'origin',
|
|
449
449
|
options.env,
|
|
450
450
|
);
|
|
451
|
-
// Spec pool — the TASKABLE-
|
|
451
|
+
// Spec pool — the TASKABLE-SPEC companion of the task pool above
|
|
452
452
|
// (`ci-propose-matrix-must-enumerate-sliceable-prds-not-only-slices`). Resolve
|
|
453
453
|
// `autoTask` PER REPO from the mirror's COMMITTED `.dorfl.json`
|
|
454
454
|
// (exactly as the mirror-side pool scan does — NOT forked); a read fault is
|
|
@@ -508,7 +508,7 @@ export async function scan(
|
|
|
508
508
|
env: options.env,
|
|
509
509
|
}),
|
|
510
510
|
);
|
|
511
|
-
// The one-slug-one-folder LINT (
|
|
511
|
+
// The one-slug-one-folder LINT (spec story 3): derive any slug residing in >1
|
|
512
512
|
// status folder from the mirror's committed `main` tree (the SAME `ls-tree`
|
|
513
513
|
// read the seam uses), so a corrupt ledger is surfaced LOUDLY by the formatter.
|
|
514
514
|
const ledgerDuplicates = lintRefLedger('main', mirror.path, options.env);
|
|
@@ -543,13 +543,22 @@ export function scanRepoPaths(
|
|
|
543
543
|
repoPaths: string[],
|
|
544
544
|
config: Config,
|
|
545
545
|
/**
|
|
546
|
-
* The HELD-SLUG set to SUBTRACT from each repo's pool (`tasks/ready/`)
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
*
|
|
551
|
-
*
|
|
552
|
-
*
|
|
546
|
+
* The HELD-SLUG set to SUBTRACT from each repo's pool (`tasks/ready/`) AND from
|
|
547
|
+
* the in-place lifecycle triage/surface/apply pools (spec
|
|
548
|
+
* `ledger-status-per-item-lock-refs` US #15; task
|
|
549
|
+
* `in-place-scan-subtracts-held-locked-slugs-from-propose-matrix`). Passed
|
|
550
|
+
* BOTH to {@link scoreItems} AND to {@link gatherLifecycleInPlace}, so a slug
|
|
551
|
+
* whose per-item lock is currently held (state `active`/`stuck`) never leaks
|
|
552
|
+
* into the propose matrix via EITHER the eligible-task pool OR a lifecycle
|
|
553
|
+
* leg — CI would otherwise enumerate a `task:<slug>` surface/apply leg that
|
|
554
|
+
* always loses the claim CAS.
|
|
555
|
+
*
|
|
556
|
+
* This is a WORKING-TREE, OFFLINE scan (it has no arbiter handle to fetch the
|
|
557
|
+
* lock refs from — that is the registry `scan`'s job), so the held set is
|
|
558
|
+
* supplied by the in-place CALLER (which knows its arbiter, e.g.
|
|
559
|
+
* `resolveCwdSection` reads it fail-CLOSED via `heldTaskSlugsStrict`) and
|
|
560
|
+
* DEFAULTS to empty. An empty default preserves the offline read while keeping
|
|
561
|
+
* the seam in place.
|
|
553
562
|
*/
|
|
554
563
|
heldSlugs: Set<string> = new Set(),
|
|
555
564
|
/**
|
|
@@ -569,7 +578,7 @@ export function scanRepoPaths(
|
|
|
569
578
|
global: config,
|
|
570
579
|
override,
|
|
571
580
|
}).config;
|
|
572
|
-
// Spec pool — the TASKABLE-
|
|
581
|
+
// Spec pool — the TASKABLE-SPEC companion of the task pool. Resolve
|
|
573
582
|
// `autoTask` PER REPO from the working-tree `.dorfl.json` (the same
|
|
574
583
|
// way `autoBuild` is resolved); `taskableSpecs` (the SAME `autoslice-gate`
|
|
575
584
|
// predicate the autopick paths run) decides what is taskable — no forked
|
|
@@ -590,6 +599,11 @@ export function scanRepoPaths(
|
|
|
590
599
|
surfaceBlockers: resolved.surfaceBlockers,
|
|
591
600
|
surfaceStaging: resolved.surfaceStaging,
|
|
592
601
|
}),
|
|
602
|
+
// Held-slug subtraction on the LIFECYCLE side (task
|
|
603
|
+
// `in-place-scan-subtracts-held-locked-slugs-from-propose-matrix`):
|
|
604
|
+
// symmetric to the `scoreItems` subtraction above, so a held task never
|
|
605
|
+
// leaks into a surface/apply leg either.
|
|
606
|
+
heldSlugs,
|
|
593
607
|
}),
|
|
594
608
|
);
|
|
595
609
|
// The one-slug-one-folder LINT over THIS working tree's `work/` ledger.
|
package/src/select-order.ts
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* member of this union and naming it is a usage error.
|
|
29
29
|
*
|
|
30
30
|
* - `build` — build an eligible task;
|
|
31
|
-
* - `task` — task a taskable
|
|
31
|
+
* - `task` — task a taskable spec;
|
|
32
32
|
* - `surface` — render a `needsAnswers` blocker into an answerable sidecar;
|
|
33
33
|
* - `triage` — triage an untriaged observation.
|
|
34
34
|
*/
|
package/src/select-priority.ts
CHANGED
|
@@ -30,16 +30,16 @@ import {
|
|
|
30
30
|
* land). Build it standalone; do not assume `run` already calls it.
|
|
31
31
|
*
|
|
32
32
|
* **Up to FIVE pools.** The `scan`/`selectCandidates`/eligibility model is
|
|
33
|
-
* TASK-ONLY (there is no
|
|
33
|
+
* TASK-ONLY (there is no spec candidate). So this helper composes:
|
|
34
34
|
*
|
|
35
35
|
* - the **`build` pool** (eligible TASKS) — the EXISTING {@link selectCandidates}
|
|
36
36
|
* path (round-robin across repos, capped). This is the EXACT task-selection
|
|
37
37
|
* primitive `run` uses, so `run` and this helper SHARE it (they share
|
|
38
38
|
* `selectCandidates`, the task-pool core).
|
|
39
|
-
* - the **`task` pool** (
|
|
39
|
+
* - the **`task` pool** (spec-to-task) — a pool the caller builds from the spec reader
|
|
40
40
|
* (`ledgerRead.resolveSpecPool`) filtered by `autoslice-gate`'s pure predicate
|
|
41
41
|
* ({@link resolveTaskingEligibility}); see {@link taskableSpecs}. The helper
|
|
42
|
-
* does NOT reinvent
|
|
42
|
+
* does NOT reinvent spec eligibility.
|
|
43
43
|
*
|
|
44
44
|
* `do` is STRICTLY SEQUENTIAL (parallelism is `run`'s job, ADR §3) — this helper
|
|
45
45
|
* only ORDERS + COUNTS the items; the caller runs the existing `do` pipeline per
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Which namespace a selected item names (mirrors the slug-namespace split). The
|
|
52
|
-
* `do` selection only ever produces `task`/`
|
|
52
|
+
* `do` selection only ever produces `task`/`spec`; the `advance` selection ALSO
|
|
53
53
|
* produces `observation` (the lifecycle triage pool, task
|
|
54
54
|
* `advance-autopick-lifecycle-pools`), so a selected lifecycle item carries which
|
|
55
55
|
* rung the driver dispatches to. The widening is BACKWARD-COMPATIBLE: `do` never
|
|
@@ -76,13 +76,13 @@ export interface SelectedItem {
|
|
|
76
76
|
/**
|
|
77
77
|
* A lifecycle-pool selected item (task `advance-autopick-lifecycle-pools`). It is
|
|
78
78
|
* a {@link SelectedItem} — the same shape — carrying the lifecycle namespace
|
|
79
|
-
* (`observation` for triage; `task`/`
|
|
79
|
+
* (`observation` for triage; `task`/`spec` for a `needsAnswers`-blocked item the
|
|
80
80
|
* tick will surface/apply). A distinct alias names the lifecycle pools at the
|
|
81
81
|
* call sites WITHOUT a structural difference (the discriminator is `namespace`).
|
|
82
82
|
*/
|
|
83
83
|
export type LifecycleSelectedItem = SelectedItem;
|
|
84
84
|
|
|
85
|
-
/** A
|
|
85
|
+
/** A spec candidate for the tasking pool, before the eligibility gate runs. */
|
|
86
86
|
export interface SpecCandidate {
|
|
87
87
|
repoPath: string;
|
|
88
88
|
slug: string;
|
|
@@ -91,21 +91,21 @@ export interface SpecCandidate {
|
|
|
91
91
|
taskedAfter: string[];
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
/** Inputs to {@link taskableSpecs}: the raw
|
|
94
|
+
/** Inputs to {@link taskableSpecs}: the raw spec pool + the gate context. */
|
|
95
95
|
export interface TaskableSpecsInput {
|
|
96
|
-
/** Every
|
|
96
|
+
/** Every spec enumerated from `work/specs/ready/` (the auto-task candidate source). */
|
|
97
97
|
candidates: SpecCandidate[];
|
|
98
|
-
/** Slugs whose
|
|
98
|
+
/** Slugs whose spec resides in `work/specs/tasked/` (resolves `taskedAfter`). */
|
|
99
99
|
taskedSlugs: Set<string>;
|
|
100
100
|
/** The repo's resolved `autoTask` policy (`autoslice-gate`'s per-repo key). */
|
|
101
101
|
autoTask: boolean;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
|
-
* Filter a raw
|
|
105
|
+
* Filter a raw spec pool down to the TASKABLE prds, in declaration order, using
|
|
106
106
|
* `autoslice-gate`'s pure predicate ({@link resolveTaskingEligibility}) — NOT a
|
|
107
|
-
* reinvented eligibility model. A
|
|
108
|
-
* humanOnly !== true && autoTask` AND every `taskedAfter`
|
|
107
|
+
* reinvented eligibility model. A spec is taskable iff `needsAnswers !== true &&
|
|
108
|
+
* humanOnly !== true && autoTask` AND every `taskedAfter` spec is already tasked.
|
|
109
109
|
* Pure: no I/O (the caller reads the pool through `ledgerRead.resolveSpecPool`).
|
|
110
110
|
*/
|
|
111
111
|
export function taskableSpecs(input: TaskableSpecsInput): SpecCandidate[] {
|
|
@@ -171,7 +171,7 @@ export interface SelectPrioritisedInput {
|
|
|
171
171
|
*/
|
|
172
172
|
lifecycle?: SelectedLifecyclePools;
|
|
173
173
|
/**
|
|
174
|
-
* The HELD-SLUG set to SUBTRACT from the `build` pool (eligible TASKS) —
|
|
174
|
+
* The HELD-SLUG set to SUBTRACT from the `build` pool (eligible TASKS) — spec
|
|
175
175
|
* `ledger-status-per-item-lock-refs` US #15, task
|
|
176
176
|
* `claim-acquires-unified-lock-no-body-move`. A task whose per-item lock is
|
|
177
177
|
* currently held is dropped from selection, so the eligible pool is "in
|
|
@@ -198,7 +198,7 @@ export interface SelectedLifecyclePools {
|
|
|
198
198
|
* Build the ordered, counted list of items to do across the (up to) FIVE pools,
|
|
199
199
|
* applying the configurable {@link selectionOrder} with `apply` PINNED FIRST and
|
|
200
200
|
* the count bound. The task pool is selected via the EXISTING
|
|
201
|
-
* {@link selectCandidates} (the shared primitive `run` uses); the
|
|
201
|
+
* {@link selectCandidates} (the shared primitive `run` uses); the spec pool is the
|
|
202
202
|
* pre-filtered {@link taskableSpecs} output; the lifecycle pools (`apply` /
|
|
203
203
|
* `surface` / `triage`) are caller-built (none for `do`).
|
|
204
204
|
*
|
|
@@ -235,7 +235,7 @@ export function selectPrioritised(
|
|
|
235
235
|
|
|
236
236
|
// The per-pool item lists, keyed by the orderable pool name. NOTE the
|
|
237
237
|
// vocabulary bridge: `build` = the eligible-TASK pool (namespace `task`),
|
|
238
|
-
// `task` = the taskable-
|
|
238
|
+
// `task` = the taskable-spec pool (namespace `spec`) — the action names, not the
|
|
239
239
|
// item namespaces (task `advance-selection-order-config`).
|
|
240
240
|
const byPool: Record<SelectionPool, SelectedItem[]> = {
|
|
241
241
|
build: buildItems,
|
package/src/sidecar-apply.ts
CHANGED
|
@@ -174,7 +174,7 @@ export function applyAtomic(options: ApplyAtomicOptions): ApplyAtomicResult {
|
|
|
174
174
|
writeFileSync(itemAbs, setNeedsAnswersMarker(itemBody, true));
|
|
175
175
|
}
|
|
176
176
|
mkdirSync(dirname(sidecarAbs), {recursive: true});
|
|
177
|
-
writeFileSync(sidecarAbs, serialiseSidecar(sidecar));
|
|
177
|
+
writeFileSync(sidecarAbs, serialiseSidecar(sidecar, {repoRoot: cwd}));
|
|
178
178
|
touched.push(sidecarPath);
|
|
179
179
|
}
|
|
180
180
|
|
package/src/sidecar.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import {existsSync} from 'node:fs';
|
|
2
|
+
import {join} from 'node:path';
|
|
1
3
|
import {parseSlugArg, type SlugNamespace} from './slug-namespace.js';
|
|
2
|
-
import {workItemRel} from './work-layout.js';
|
|
4
|
+
import {workItemRel, type WorkFolderKey} from './work-layout.js';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
|
-
* The **question/answer SIDECAR contract** (
|
|
7
|
+
* The **question/answer SIDECAR contract** (spec `advance-loop`, task
|
|
6
8
|
* `advance-sidecar-contract`) — the one genuinely-new piece of the `advance`
|
|
7
9
|
* family. A strict, tooling-OWNED per-item file `work/questions/<type>-<slug>.md`
|
|
8
10
|
* carrying per-entry answered-state, so the tooling fully owns the Q&A artifact
|
|
@@ -72,7 +74,7 @@ import {workItemRel} from './work-layout.js';
|
|
|
72
74
|
* The item-types a sidecar can key onto (the slug-namespace + obs).
|
|
73
75
|
*
|
|
74
76
|
* HARD CUTOVER (spec `prd-to-spec-vocabulary-cutover-and-migration-command`,
|
|
75
|
-
* contract step): the legacy
|
|
77
|
+
* contract step): the legacy ''prd'' type member is GONE — the parent-spec type
|
|
76
78
|
* is `'spec'` only. A `spec:<slug>` identity keys onto the `spec-<slug>`
|
|
77
79
|
* lock/sidecar entry. The on-disk `prd-<slug>.md` sidecar FILE (dorfl's
|
|
78
80
|
* not-yet-converted data) is still probed by {@link sidecarPathCandidates} as a
|
|
@@ -88,13 +90,19 @@ export type SidecarType = 'spec' | 'task' | 'observation';
|
|
|
88
90
|
* sniffing the shape of another field. Absent ⇒ the existing binary content
|
|
89
91
|
* entry (every pre-`kind` sidecar parses + renders byte-identically).
|
|
90
92
|
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
93
|
+
* A TYPED FIELD is the PERMANENT home for the kind axis (not an interim step
|
|
94
|
+
* toward kind subfolders). Encoding kind in the PATH — either a filename prefix
|
|
95
|
+
* (`merge-<type>-<slug>.md`) or a subfolder (`work/questions/merge/…`) — was
|
|
96
|
+
* deliberately REJECTED: kind is a MUTABLE axis (one item can carry a `spec`
|
|
97
|
+
* question pre-build, then a `merge` question at land time), but `sidecarPathFor`
|
|
98
|
+
* is a pure function of item IDENTITY alone and does not know the kind, so a
|
|
99
|
+
* path that encodes kind would make identity-only lookups SILENTLY miss a
|
|
100
|
+
* sidecar filed under a different kind. So kind lives INSIDE the file (this
|
|
101
|
+
* field), the path stays identity-keyed, and per-kind queues are RENDERED by the
|
|
102
|
+
* tool (`status`/`scan`) rather than by the directory tree. See the observation
|
|
103
|
+
* `questions-folder-rename-and-kind-axis-prefix-vs-subfolder-2026-06-21` (its
|
|
104
|
+
* round-2 conclusion + the recorded answers) and `SURFACE-PROTOCOL.md`. The
|
|
105
|
+
* field is read in exactly ONE place (the apply dispatch).
|
|
98
106
|
*
|
|
99
107
|
* A mistyped/unknown `kind=` token parses to `undefined` (silent-on-malformed,
|
|
100
108
|
* mirroring the retired `disposition` precedent), never a throw, never a
|
|
@@ -208,7 +216,7 @@ function typeForNamespace(
|
|
|
208
216
|
if (explicit === 'task') {
|
|
209
217
|
return 'task';
|
|
210
218
|
}
|
|
211
|
-
// `parseSlugArg` only knows `task:`/`
|
|
219
|
+
// `parseSlugArg` only knows `task:`/`spec:`; the sidecar adds the
|
|
212
220
|
// `observation:` namespace (`obs:` is the CLI alias the verb resolves; the
|
|
213
221
|
// sidecar stores the canonical `observation`). A bare slug (no prefix)
|
|
214
222
|
// defaults to the task namespace, matching the resolver's "bare = task".
|
|
@@ -267,14 +275,14 @@ export function sidecarPathFor(identity: string): string {
|
|
|
267
275
|
* canonical {@link sidecarPathFor} path FIRST, then any legacy-data fallback that
|
|
268
276
|
* may still be on disk before the migration command converts it.
|
|
269
277
|
*
|
|
270
|
-
* MIGRATE step (
|
|
278
|
+
* MIGRATE step (spec `prd-to-spec-vocabulary-cutover-and-migration-command`): the
|
|
271
279
|
* producer side now emits `spec:<slug>`, so {@link sidecarPathFor} resolves
|
|
272
280
|
* `work/questions/spec-<slug>.md`. But the ON-DISK sidecar is still the legacy
|
|
273
281
|
* `work/questions/prd-<slug>.md` until `dorfl prd-to-spec` renames the DATA. So a
|
|
274
282
|
* `spec`-typed identity ALSO probes the legacy `prd-<slug>.md` as a fallback, and
|
|
275
283
|
* a reader takes the FIRST candidate that exists. This is a FILE-PATH DATA alias
|
|
276
284
|
* the migration command removes (it converts `prd-<slug>.md → spec-<slug>.md` on
|
|
277
|
-
* disk); it is NOT the `SlugNamespace`/`SidecarType`
|
|
285
|
+
* disk); it is NOT the `SlugNamespace`/`SidecarType` ''prd'' type member. Every
|
|
278
286
|
* non-`spec` type has a single candidate (its canonical path), unchanged.
|
|
279
287
|
*/
|
|
280
288
|
export function sidecarPathCandidates(identity: string): string[] {
|
|
@@ -291,6 +299,77 @@ export function sidecarPathCandidates(identity: string): string[] {
|
|
|
291
299
|
/** The fixed answer marker the human types prose under. */
|
|
292
300
|
const ANSWER_MARKER = '**Your answer** (write below this line):';
|
|
293
301
|
|
|
302
|
+
/**
|
|
303
|
+
* The lifecycle folders a given item type may currently reside in — the
|
|
304
|
+
* search set the {@link serialiseSidecar} human-visible link line scans to
|
|
305
|
+
* locate the item at write-time. Deliberately INCLUSIVE of the terminal
|
|
306
|
+
* folders (`done`, `cancelled`, `prds-dropped`) so a sidecar still-being-
|
|
307
|
+
* serialised for a finished item still emits a clickable link. Kept LOCAL to
|
|
308
|
+
* this module (rather than reused from `advance.ts`) because this set is the
|
|
309
|
+
* "where might the item CURRENTLY be on disk?" question, which is broader
|
|
310
|
+
* than advance's rung-classifier reach.
|
|
311
|
+
*
|
|
312
|
+
* DECISION (sidecar-visible-item-link): the task set is the four DURABLE
|
|
313
|
+
* folders `tasks-ready` / `done` / `cancelled` / `tasks-backlog` and
|
|
314
|
+
* deliberately EXCLUDES `in-progress` / `needs-attention`. Those two are NOT
|
|
315
|
+
* durable folders — they are retired transient lock-ref state (ADR
|
|
316
|
+
* `needs-attention-folder-cutover-followup-nits`, see the `TASK_LIFECYCLE_FOLDERS`
|
|
317
|
+
* JSDoc in `work-layout.ts`): a stuck task's BODY rests in `tasks/ready/`
|
|
318
|
+
* while the lock carries `state: stuck`, so no task body ever lives under
|
|
319
|
+
* `work/in-progress/` or `work/needs-attention/` for this scan to find. An
|
|
320
|
+
* earlier WIP of this task listed both; narrowing to the durable set matches
|
|
321
|
+
* the current on-disk reality and avoids scanning phantom folders.
|
|
322
|
+
* ALTERNATIVE considered: reuse `TASK_LIFECYCLE_FOLDERS` directly — rejected
|
|
323
|
+
* because it still carries the legacy `in-progress` entry and omits the
|
|
324
|
+
* `cancelled` / `tasks-backlog` folders a sidecar link may need to reach.
|
|
325
|
+
*/
|
|
326
|
+
const LINK_LIFECYCLE_FOLDERS: Record<SidecarType, readonly WorkFolderKey[]> = {
|
|
327
|
+
task: ['tasks-ready', 'done', 'cancelled', 'tasks-backlog'],
|
|
328
|
+
spec: ['specs-ready', 'specs-tasked', 'specs-proposed', 'specs-dropped'],
|
|
329
|
+
observation: ['observations'],
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Look up the item's CURRENT on-disk repo-relative path by scanning the
|
|
334
|
+
* lifecycle folders its type may reside in, in a documented precedence order.
|
|
335
|
+
* Returns `undefined` when the item is not found in ANY folder — the
|
|
336
|
+
* serialiser's "harmless fallback" (omit the link) branch.
|
|
337
|
+
*
|
|
338
|
+
* PURE lookup: no throws, no side effects. Every call is a fresh scan — the
|
|
339
|
+
* link SELF-HEALS on the next `serialise` after a `git mv` between folders
|
|
340
|
+
* (identity-keyed sidecar; NO lock-step move).
|
|
341
|
+
*/
|
|
342
|
+
function findItemRelPath(
|
|
343
|
+
repoRoot: string,
|
|
344
|
+
type: SidecarType,
|
|
345
|
+
slug: string,
|
|
346
|
+
): string | undefined {
|
|
347
|
+
for (const folder of LINK_LIFECYCLE_FOLDERS[type]) {
|
|
348
|
+
const rel = workItemRel(folder, `${slug}.md`);
|
|
349
|
+
if (existsSync(join(repoRoot, rel))) {
|
|
350
|
+
return rel;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return undefined;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Render the human-visible Markdown link line, from the sidecar's fixed path
|
|
358
|
+
* (`work/questions/<type>-<slug>.md`) to the item's current `work/<folder>/
|
|
359
|
+
* <slug>.md`. Since both live under `work/`, the sidecar-relative link is
|
|
360
|
+
* `../<folder-name>/<slug>.md` — the `..` climbs out of `questions/` and the
|
|
361
|
+
* `<folder-name>` (which may contain a `/`, e.g. `tasks/ready`) drops back in.
|
|
362
|
+
*/
|
|
363
|
+
function renderItemLinkLine(item: string, itemRel: string): string {
|
|
364
|
+
// itemRel is `work/<folder-name>/<slug>.md`; strip the leading `work/` and
|
|
365
|
+
// prefix with `../` so the link is relative to `work/questions/<file>.md`.
|
|
366
|
+
const prefix = 'work/';
|
|
367
|
+
const target = itemRel.startsWith(prefix)
|
|
368
|
+
? `../${itemRel.slice(prefix.length)}`
|
|
369
|
+
: itemRel;
|
|
370
|
+
return `Item: [\`${item}\`](${target})`;
|
|
371
|
+
}
|
|
372
|
+
|
|
294
373
|
// --- Parse ----------------------------------------------------------------
|
|
295
374
|
|
|
296
375
|
/** Pull the next monotonic id given the highest existing id number. */
|
|
@@ -582,7 +661,10 @@ function blockquote(value: string): string[] {
|
|
|
582
661
|
* `parseSidecar(serialiseSidecar(m))` recovers an equal MODEL; re-serialising
|
|
583
662
|
* canonicalises the text.
|
|
584
663
|
*/
|
|
585
|
-
export function serialiseSidecar(
|
|
664
|
+
export function serialiseSidecar(
|
|
665
|
+
model: SidecarModel,
|
|
666
|
+
options: SerialiseSidecarOptions = {},
|
|
667
|
+
): string {
|
|
586
668
|
const out: string[] = [];
|
|
587
669
|
const identityParts = [
|
|
588
670
|
`item=${model.item}`,
|
|
@@ -592,6 +674,21 @@ export function serialiseSidecar(model: SidecarModel): string {
|
|
|
592
674
|
];
|
|
593
675
|
out.push(`<!-- dorfl-sidecar: ${identityParts.join(' ')} -->`);
|
|
594
676
|
|
|
677
|
+
// Human-visible Markdown link line — placed AFTER the identity comment and
|
|
678
|
+
// BEFORE the first `## ` heading, i.e. in the parser's ignored preamble
|
|
679
|
+
// region. Regenerated on every serialise from the item's CURRENT on-disk
|
|
680
|
+
// location; NEVER round-tripped through the parsed model (the link line is
|
|
681
|
+
// write-only cosmetic output, per the source observation). If the item is
|
|
682
|
+
// not resolvable on disk, we simply OMIT the line (harmless fallback) — a
|
|
683
|
+
// broken link would be more confusing than no link.
|
|
684
|
+
if (options.repoRoot !== undefined) {
|
|
685
|
+
const itemRel = findItemRelPath(options.repoRoot, model.type, model.slug);
|
|
686
|
+
if (itemRel !== undefined) {
|
|
687
|
+
out.push('');
|
|
688
|
+
out.push(renderItemLinkLine(model.item, itemRel));
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
595
692
|
model.entries.forEach((entry) => {
|
|
596
693
|
out.push('');
|
|
597
694
|
const heading = entry.id.replace(/^q/, 'Q');
|
|
@@ -634,6 +731,36 @@ export function serialiseSidecar(model: SidecarModel): string {
|
|
|
634
731
|
return out.join('\n');
|
|
635
732
|
}
|
|
636
733
|
|
|
734
|
+
/**
|
|
735
|
+
* Options for {@link serialiseSidecar}. The optional `repoRoot` opts the
|
|
736
|
+
* caller into emitting the human-visible Markdown link line at the top of
|
|
737
|
+
* the sidecar (pointing at the item's current `work/<folder>/<slug>.md`).
|
|
738
|
+
* Callers that don't have a repo root (e.g. pure format tests) simply omit
|
|
739
|
+
* it and the serialiser emits no link — the parse is unaffected either way.
|
|
740
|
+
*
|
|
741
|
+
* DECISION (sidecar-visible-item-link): `repoRoot` is OPTIONAL and defaults
|
|
742
|
+
* to NO link, rather than being a required argument threaded through every
|
|
743
|
+
* caller. Only the two WRITING call sites (`applyAtomic` in
|
|
744
|
+
* `sidecar-apply.ts`, `persistSurfacedQuestions` in `surface-persist.ts`)
|
|
745
|
+
* pass `cwd`; any other current/future caller of `serialiseSidecar` silently
|
|
746
|
+
* emits no link line. This keeps the many pure-format / round-trip tests
|
|
747
|
+
* trivial (they need no on-disk repo) and keeps the link a write-only
|
|
748
|
+
* cosmetic concern of the persist paths. TRADE-OFF: a new writing caller must
|
|
749
|
+
* remember to pass `repoRoot` to get the link; ALTERNATIVE considered — make
|
|
750
|
+
* it required — rejected because it would force every format-only caller and
|
|
751
|
+
* test to fabricate a repo root purely to reach the same no-link output.
|
|
752
|
+
*/
|
|
753
|
+
export interface SerialiseSidecarOptions {
|
|
754
|
+
/**
|
|
755
|
+
* Absolute or relative path to the repository root, so the serialiser can
|
|
756
|
+
* scan `work/<lifecycle-folder>/<slug>.md` for the item and render a
|
|
757
|
+
* clickable relative link line. When omitted (or when the item cannot be
|
|
758
|
+
* located), the link line is omitted — a harmless fallback, never a
|
|
759
|
+
* broken link.
|
|
760
|
+
*/
|
|
761
|
+
repoRoot?: string;
|
|
762
|
+
}
|
|
763
|
+
|
|
637
764
|
// --- Append ---------------------------------------------------------------
|
|
638
765
|
|
|
639
766
|
/** A new question to append (no id — the appender mints the next monotonic id). */
|
package/src/slug-namespace.ts
CHANGED
|
@@ -43,8 +43,8 @@ import {ledgerRead, type LedgerReadStrategy} from './ledger-read.js';
|
|
|
43
43
|
* {@link resolveAdvanceArg}).
|
|
44
44
|
*
|
|
45
45
|
* HARD CUTOVER (spec `prd-to-spec-vocabulary-cutover-and-migration-command`,
|
|
46
|
-
* contract step): the legacy
|
|
47
|
-
* is `'spec'` only. A
|
|
46
|
+
* contract step): the legacy ''prd'' member is GONE — the parent-spec namespace
|
|
47
|
+
* is `'spec'` only. A ''prd:<slug>'' arg no longer parses to a namespace (it falls
|
|
48
48
|
* through to a bare literal slug), and a `work/prd-<slug>` branch ref no longer
|
|
49
49
|
* parses. No back-compat alias (the clean-break stance).
|
|
50
50
|
*/
|
|
@@ -102,7 +102,7 @@ export function workBranchRef(
|
|
|
102
102
|
* anchors the optional producer prefix BEFORE the type alternation, so
|
|
103
103
|
* `work/intake-task-foo` resolves to
|
|
104
104
|
* `{producer:'intake', namespace:'task', slug:'foo'}` (the `slug` never
|
|
105
|
-
* swallows the `intake-`/`task-` prefixes). The old
|
|
105
|
+
* swallows the `intake-`/`task-` prefixes). The old ''slice''/''brief''/''prd'' types
|
|
106
106
|
* are NOT in the alternation, so a pre-rename `work/prd-foo` ref returns
|
|
107
107
|
* `undefined` (the clean-break stance: no migration-window alias).
|
|
108
108
|
*/
|
|
@@ -112,7 +112,7 @@ export function parseWorkBranchRef(
|
|
|
112
112
|
| {producer?: BranchProducer; namespace: SlugNamespace; slug: string}
|
|
113
113
|
| undefined {
|
|
114
114
|
// HARD CUTOVER (spec `prd-to-spec-vocabulary-cutover-and-migration-command`,
|
|
115
|
-
// contract step): the type alternation is `task|spec` ONLY — the legacy
|
|
115
|
+
// contract step): the type alternation is `task|spec` ONLY — the legacy ''prd''
|
|
116
116
|
// token is GONE, so a pre-rename `work/prd-<slug>` ref returns `undefined` (no
|
|
117
117
|
// migration-window alias; the clean-break stance).
|
|
118
118
|
const match = /^work\/(?:(intake)-)?(task|spec)-(.+)$/.exec(branch);
|
|
@@ -155,7 +155,7 @@ const TASK_PREFIX = 'task:';
|
|
|
155
155
|
/**
|
|
156
156
|
* The parent-spec namespace prefix: `spec:<slug>` → `{explicit: 'spec'}`. HARD
|
|
157
157
|
* CUTOVER (spec `prd-to-spec-vocabulary-cutover-and-migration-command`): the
|
|
158
|
-
* legacy
|
|
158
|
+
* legacy ''prd:'' prefix is GONE — a ''prd:<slug>'' arg falls through to a bare
|
|
159
159
|
* literal slug (no namespace), the clean-break stance.
|
|
160
160
|
*/
|
|
161
161
|
const SPEC_PREFIX = 'spec:';
|
|
@@ -184,8 +184,8 @@ export class SlugResolutionError extends Error {
|
|
|
184
184
|
* slug. PURE string work, no existence check: `task:foo` → explicit task,
|
|
185
185
|
* `spec:foo` → explicit spec, `foo` → bare (`explicit: undefined`). The prefix
|
|
186
186
|
* match is case-sensitive and exact (`task:`/`spec:`); a slug like `tasked` is
|
|
187
|
-
* NOT a prefix and stays bare. HARD CUTOVER: the legacy
|
|
188
|
-
* namespace prefix anymore —
|
|
187
|
+
* NOT a prefix and stays bare. HARD CUTOVER: the legacy ''prd:'' prefix is not a
|
|
188
|
+
* namespace prefix anymore — ''prd:foo'' stays a bare literal slug.
|
|
189
189
|
*/
|
|
190
190
|
export function parseSlugArg(arg: string): ParsedSlugArg {
|
|
191
191
|
if (arg.startsWith(TASK_PREFIX)) {
|
|
@@ -263,7 +263,7 @@ export function resolveSlug(input: ResolveSlugInput): ResolvedSlug {
|
|
|
263
263
|
const parsed = parseSlugArg(input.arg);
|
|
264
264
|
|
|
265
265
|
if (parsed.explicit === 'observation') {
|
|
266
|
-
// `do` spans the task/
|
|
266
|
+
// `do` spans the task/spec namespaces ONLY (build a task OR task a spec).
|
|
267
267
|
// The `observation` namespace is `advance`'s alone (triage). Reject it here
|
|
268
268
|
// rather than let a `do obs:<slug>` resolve into a namespace `do` cannot act
|
|
269
269
|
// on — point the human at the verb that owns it.
|
|
@@ -289,7 +289,7 @@ export function resolveSlug(input: ResolveSlugInput): ResolvedSlug {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
/**
|
|
292
|
-
* Resolve a slug argument for the `advance` verb (
|
|
292
|
+
* Resolve a slug argument for the `advance` verb (spec `advance-loop`, task
|
|
293
293
|
* `advance-verb-resolver`). `advance` is the SIBLING top-level verb (NOT a `do`
|
|
294
294
|
* subcommand) that reuses this SAME shared `prefix:arg` resolver, EXTENDED with
|
|
295
295
|
* the `observation` namespace `do` does not span:
|
|
@@ -362,6 +362,6 @@ export function resolveTaskOnlyArg(arg: string): string {
|
|
|
362
362
|
);
|
|
363
363
|
}
|
|
364
364
|
// Bare or `task:` → the task slug. (A bare slug on a task-only command is
|
|
365
|
-
// unambiguously the task; the
|
|
365
|
+
// unambiguously the task; the spec namespace is unreachable here.)
|
|
366
366
|
return parsed.slug;
|
|
367
367
|
}
|
package/src/spec-complete.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from './work-layout.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* The read-only **"is this spec complete?"** core query (
|
|
13
|
+
* The read-only **"is this spec complete?"** core query (spec `issue-intake`, US #8 —
|
|
14
14
|
* the closure-linkage half). Given a spec slug + a `work/` tree, a spec is COMPLETE
|
|
15
15
|
* iff there is **≥1 task carrying `spec:<slug>`** AND **all such tasks reside in
|
|
16
16
|
* `work/done/`**. Pure `work/`-folder logic — no seam, no git, no `gh`, no mutation.
|
|
@@ -27,12 +27,11 @@ import {
|
|
|
27
27
|
* claim ledger (`ledger-read.ts` resolves claim-STATE, a different concern). It
|
|
28
28
|
* reuses {@link parseFrontmatter} (the `spec:` field) rather than hand-rolling a YAML
|
|
29
29
|
* parse, and scans the task lifecycle folders directly: `work/tasks/ready/`,
|
|
30
|
-
* `work/in-progress/`,
|
|
31
|
-
*
|
|
32
|
-
* means the spec is not yet complete.
|
|
30
|
+
* `work/in-progress/`, and `work/done/`. A task that has NOT yet landed in
|
|
31
|
+
* `work/done/` (still in backlog / in-progress) means the spec is not yet complete.
|
|
33
32
|
*/
|
|
34
33
|
|
|
35
|
-
/** The task lifecycle folders a `
|
|
34
|
+
/** The task lifecycle folders a `spec:<slug>` task can reside in. */
|
|
36
35
|
const TASK_FOLDERS = TASK_LIFECYCLE_FOLDERS;
|
|
37
36
|
|
|
38
37
|
/** Where a task resides — the folder name under `work/`. */
|