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/start.ts
CHANGED
|
@@ -78,7 +78,7 @@ export interface StartOptions {
|
|
|
78
78
|
*/
|
|
79
79
|
override?: boolean;
|
|
80
80
|
/**
|
|
81
|
-
* `--allow-backlog` (
|
|
81
|
+
* `--allow-backlog` (spec
|
|
82
82
|
* `do-allow-backlog-drive-staged-tasks-without-promotion`): recognise a
|
|
83
83
|
* `tasks/backlog/`-resident body (staging) as a valid start/onboard residence,
|
|
84
84
|
* so the no-checkout `do --remote/--isolated … --allow-backlog` flow (which
|
|
@@ -122,7 +122,8 @@ class StartUsageError extends Error {}
|
|
|
122
122
|
/**
|
|
123
123
|
* Raised for a deliberate REFUSAL (exit 1, outcome 'refused') — distinct from a
|
|
124
124
|
* usage/environment error. Used when the item exists but start declines to act
|
|
125
|
-
* (an in-progress item without --resume). The decision is
|
|
125
|
+
* (an in-progress item without --resume). The decision is LOCK-based (a held
|
|
126
|
+
* `active` per-item lock), not a `work/in-progress/` folder read.
|
|
126
127
|
*/
|
|
127
128
|
class StartRefusal extends Error {}
|
|
128
129
|
|
|
@@ -236,7 +237,7 @@ async function runStart(
|
|
|
236
237
|
* resume the lock `stuck → active`, onboard).
|
|
237
238
|
* Everything else dispatches by folder unchanged.
|
|
238
239
|
*
|
|
239
|
-
* Under `--allow-backlog` (
|
|
240
|
+
* Under `--allow-backlog` (spec
|
|
240
241
|
* `do-allow-backlog-drive-staged-tasks-without-promotion`) a body resting in
|
|
241
242
|
* `tasks/backlog/` (staging) is treated EXACTLY like the pool for this re-key
|
|
242
243
|
* (held active ⇒ in-progress; held stuck ⇒ needs-attention; else the backlog
|
|
@@ -262,11 +263,11 @@ async function dispatchFolder(
|
|
|
262
263
|
if (!inPool) {
|
|
263
264
|
return folder;
|
|
264
265
|
}
|
|
265
|
-
// In the pool/staging: claimed-ness
|
|
266
|
+
// In the pool/staging: claimed-ness is the per-item lock (not the folder).
|
|
267
|
+
// Post-`retire-stuck-lock-state` there is no `stuck` state — a parked item is
|
|
268
|
+
// a `needsAnswers:true` pool item on `main` (rendered by status/scan and
|
|
269
|
+
// drained by the apply rung), NEVER a lock re-key.
|
|
266
270
|
const lock = await readItemLock({item: `task:${slug}`, cwd, arbiter, env});
|
|
267
|
-
if (lock && lock.state === 'stuck') {
|
|
268
|
-
return 'needs-attention';
|
|
269
|
-
}
|
|
270
271
|
if (lock && lock.state === 'active') {
|
|
271
272
|
return 'in-progress';
|
|
272
273
|
}
|
|
@@ -404,7 +405,7 @@ async function continueConflictResult(params: {
|
|
|
404
405
|
}
|
|
405
406
|
const message =
|
|
406
407
|
`Could not continue '${params.slug}': the kept work branch did not rebase ` +
|
|
407
|
-
`cleanly onto ${params.arbiter}/main;
|
|
408
|
+
`cleanly onto ${params.arbiter}/main; marked stuck on its per-item lock ` +
|
|
408
409
|
'(surfaced by status). Resolve against the latest main, or `requeue --reset` ' +
|
|
409
410
|
'to discard and start fresh.';
|
|
410
411
|
return {
|
|
@@ -438,8 +439,8 @@ async function continuePushFailureResult(params: {
|
|
|
438
439
|
}
|
|
439
440
|
const message =
|
|
440
441
|
`Could not continue '${params.slug}': publishing the rebased work branch to ` +
|
|
441
|
-
`${params.arbiter} failed terminally (${params.pushFailure});
|
|
442
|
-
'
|
|
442
|
+
`${params.arbiter} failed terminally (${params.pushFailure}); marked stuck ` +
|
|
443
|
+
'on its per-item lock (surfaced by status), the kept branch left intact on ' +
|
|
443
444
|
'the arbiter (recoverable). `requeue` to retry once the churn settles.';
|
|
444
445
|
return {
|
|
445
446
|
exitCode: 1,
|
|
@@ -465,42 +466,17 @@ async function startFromNeedsAttention(params: {
|
|
|
465
466
|
}): Promise<StartResult> {
|
|
466
467
|
const {slug, arbiter, cwd, env, note} = params;
|
|
467
468
|
|
|
468
|
-
//
|
|
469
|
-
//
|
|
470
|
-
//
|
|
471
|
-
//
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (stuck?.questions && stuck.questions.length > 0) {
|
|
479
|
-
note('Surfaced questions:');
|
|
480
|
-
for (const q of stuck.questions) {
|
|
481
|
-
note(` - ${q}`);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
// Resume the lock `stuck → active` THROUGH the write seam (a pure lock amend, NO
|
|
486
|
-
// `main` write, NO temp checkout — the body already rests in `backlog/` and the
|
|
487
|
-
// work stays on the kept `work/<slug>` branch), then onboard onto work/<slug>.
|
|
488
|
-
const resolved = await ledgerWrite.applyResolveNeedsAttentionTransition({
|
|
489
|
-
cwd,
|
|
490
|
-
slug,
|
|
491
|
-
arbiter,
|
|
492
|
-
env,
|
|
493
|
-
note,
|
|
494
|
-
});
|
|
495
|
-
if (!resolved.moved) {
|
|
496
|
-
throw new StartUsageError(
|
|
497
|
-
resolved.reasonNotMoved ??
|
|
498
|
-
`could not resolve '${slug}' from needs-attention.`,
|
|
499
|
-
);
|
|
500
|
-
}
|
|
469
|
+
// Post-`retire-stuck-lock-state`: the `stuck` lock state is gone; a parked
|
|
470
|
+
// item is a `needsAnswers:true` pool item on `main` drained by the apply
|
|
471
|
+
// rung (answer the sidecar). This branch fires only when a LEGACY
|
|
472
|
+
// `needs-attention/` folder body still exists on `<arbiter>/main` (no
|
|
473
|
+
// live path lands one). Onboard the human onto the kept work branch — no
|
|
474
|
+
// lock amend, no reason/questions read from the lock (those live on the
|
|
475
|
+
// surfaced sidecar now).
|
|
476
|
+
note(
|
|
477
|
+
`'${slug}' is in the legacy needs-attention/ folder — onboarding onto its work branch; answer any question sidecar on main to drain it.`,
|
|
478
|
+
);
|
|
501
479
|
|
|
502
|
-
// The lock is back to active (the human owns it). Onboard onto the work branch:
|
|
503
|
-
// CONTINUE from a kept arbiter work/<slug> when present, else fresh off main.
|
|
504
480
|
const switched = await switchToWorkBranch({slug, arbiter, cwd, env, note});
|
|
505
481
|
if (switched.rebaseConflict) {
|
|
506
482
|
return continueConflictResult({slug, arbiter, cwd, env, note});
|
|
@@ -522,10 +498,14 @@ async function startFromNeedsAttention(params: {
|
|
|
522
498
|
}
|
|
523
499
|
|
|
524
500
|
/**
|
|
525
|
-
* In-progress → already claimed (
|
|
526
|
-
* apply). Refuse by default. With --resume the human explicitly asserts
|
|
501
|
+
* In-progress → already claimed (the per-item LOCK is held `active`, so the CAS
|
|
502
|
+
* cannot apply). Refuse by default. With --resume the human explicitly asserts
|
|
527
503
|
* ownership, so we switch to the work branch WITHOUT claiming. The decision is
|
|
528
|
-
*
|
|
504
|
+
* LOCK-based: `dispatchFolder` reaches here only when the lock is held `active`
|
|
505
|
+
* (the body rests in the pool/staging, NOT a `work/in-progress/` folder file —
|
|
506
|
+
* the folder cutover retired that path,
|
|
507
|
+
* `finish-in-progress-folder-cutover-remove-legacy-recovery-readers`). We never
|
|
508
|
+
* read the advisory `claimed_by` to guess ownership.
|
|
529
509
|
*/
|
|
530
510
|
async function startFromInProgress(params: {
|
|
531
511
|
slug: string;
|
|
@@ -538,10 +518,11 @@ async function startFromInProgress(params: {
|
|
|
538
518
|
const {slug, arbiter, cwd, env, resume, note} = params;
|
|
539
519
|
|
|
540
520
|
if (!resume) {
|
|
541
|
-
// The
|
|
542
|
-
//
|
|
543
|
-
// message; whoever holds it is read from git
|
|
544
|
-
// (`git log work/
|
|
521
|
+
// The held LOCK drove the decision (the per-item lock is the source of truth
|
|
522
|
+
// for liveness now — the body stays in the pool, no `work/in-progress/` file).
|
|
523
|
+
// We do NOT name the claimer in the message; whoever holds it is read from git
|
|
524
|
+
// history (`git log` over the item's `work/tasks/ready/<slug>.md` + the lock
|
|
525
|
+
// ref history).
|
|
545
526
|
throw new StartRefusal(
|
|
546
527
|
`'${slug}' is already in-progress; see \`git log\` for who claimed it; ` +
|
|
547
528
|
'if this is your own work, re-run with --resume.',
|
|
@@ -620,7 +601,7 @@ async function switchToWorkBranch(params: {
|
|
|
620
601
|
}): Promise<SwitchResult> {
|
|
621
602
|
const {slug, arbiter, cwd, env, note} = params;
|
|
622
603
|
// `start` is a TASK-only command: the branch is the task-namespaced
|
|
623
|
-
// `work/task-<slug>` (distinct from a same-slug
|
|
604
|
+
// `work/task-<slug>` (distinct from a same-slug spec-tasking branch).
|
|
624
605
|
const branch = workBranchRef('task', slug);
|
|
625
606
|
|
|
626
607
|
await gitHard(['fetch', '--quiet', arbiter], cwd, env);
|
|
@@ -816,8 +797,9 @@ function surfaceUnmovedStartResult(params: {
|
|
|
816
797
|
* TREE-LESS (`#89` mechanism), the SAME-PROFILE sibling of
|
|
817
798
|
* {@link routeContinuePushFailure}: the rebase was ABORTED, so the REAL continued
|
|
818
799
|
* `work/<slug>` is already on the arbiter from the prior requeue, untouched
|
|
819
|
-
* (after-commit, durable, recoverable). The surface is PURELY the
|
|
820
|
-
* `
|
|
800
|
+
* (after-commit, durable, recoverable). The surface is PURELY the lock amend to
|
|
801
|
+
* `state: stuck` with the reason (post lock-cutover — no `in-progress/ →
|
|
802
|
+
* needs-attention/` folder move) — we publish it via
|
|
821
803
|
* the tree-less surface CAS (the SAME no-checkout primitive `requeue` uses for the
|
|
822
804
|
* reverse direction), NO temp-branch switch/restore, NO `pushBranch`, NO worktree.
|
|
823
805
|
*/
|
|
@@ -831,8 +813,10 @@ async function routeContinueConflict(params: {
|
|
|
831
813
|
const {slug, arbiter, cwd, env, note} = params;
|
|
832
814
|
const reason =
|
|
833
815
|
`continuing the kept ${arbiter}/${workBranchRef('task', slug)}: rebase onto ` +
|
|
834
|
-
`${arbiter}/main conflicted (aborted, never auto-resolved) —
|
|
835
|
-
'
|
|
816
|
+
`${arbiter}/main conflicted (aborted, never auto-resolved) — run ` +
|
|
817
|
+
'`requeue --reconcile` to non-destructively re-sync the mirror and retry ' +
|
|
818
|
+
'the rebase (keeps the work). Last resort: `requeue --reset` ' +
|
|
819
|
+
'DESTRUCTIVELY discards the branch and starts fresh.';
|
|
836
820
|
note(reason);
|
|
837
821
|
// PROPAGATE the {moved, reasonNotMoved} result to the caller so a `moved:false`
|
|
838
822
|
// (the surface did NOT reach main — lost the CAS race) is surfaced honestly
|
|
@@ -857,8 +841,9 @@ async function routeContinueConflict(params: {
|
|
|
857
841
|
* TREE-LESS (`#89` mechanism): the recoverable artifact — the kept `work/<slug>`
|
|
858
842
|
* — is ALREADY on the arbiter from the prior requeue (our local rebased tip is
|
|
859
843
|
* what FAILED to push, so it is not the cross-machine truth), and the work is
|
|
860
|
-
* already committed. So the surface is PURELY the
|
|
861
|
-
*
|
|
844
|
+
* already committed. So the surface is PURELY the lock amend to `state: stuck`
|
|
845
|
+
* with the reason (post lock-cutover — no `in-progress/ → needs-attention/`
|
|
846
|
+
* folder move): we publish it via the tree-less
|
|
862
847
|
* surface CAS (the SAME no-checkout primitive `requeue` uses for the reverse
|
|
863
848
|
* direction) — NO temp-branch switch/restore, NO `pushBranch`, NO worktree. A
|
|
864
849
|
* `requeue` then continues from the kept arbiter tip.
|
|
@@ -875,8 +860,10 @@ async function routeContinuePushFailure(params: {
|
|
|
875
860
|
const reason =
|
|
876
861
|
`continuing the kept ${arbiter}/${workBranchRef('task', slug)}: publishing ` +
|
|
877
862
|
`the rebased work branch to ${arbiter} failed terminally (${pushFailure}) — ` +
|
|
878
|
-
'the kept branch is left intact on the arbiter (recoverable); `requeue
|
|
879
|
-
'
|
|
863
|
+
'the kept branch is left intact on the arbiter (recoverable); `requeue ' +
|
|
864
|
+
'--reconcile` to non-destructively re-sync the mirror and retry once the ' +
|
|
865
|
+
'churn settles (keeps the work). Last resort: `requeue --reset` ' +
|
|
866
|
+
'DESTRUCTIVELY discards the branch and starts fresh.';
|
|
880
867
|
note(reason);
|
|
881
868
|
// PROPAGATE the {moved, reasonNotMoved} result to the caller so a `moved:false`
|
|
882
869
|
// (the surface did NOT reach main — lost the CAS race) is surfaced honestly
|
|
@@ -909,7 +896,7 @@ async function inferSlugFromBranch(
|
|
|
909
896
|
|
|
910
897
|
/**
|
|
911
898
|
* Which work/ folder the slug currently lives in on `<arbiter>/main`. Under
|
|
912
|
-
* `--allow-backlog` (
|
|
899
|
+
* `--allow-backlog` (spec `do-allow-backlog-drive-staged-tasks-without-promotion`)
|
|
913
900
|
* it ALSO recognises `tasks/backlog/` (staging) at LOWEST priority — after the
|
|
914
901
|
* pool — so a same-slug pool copy still wins; otherwise staging is invisible.
|
|
915
902
|
*/
|
|
@@ -936,7 +923,14 @@ async function folderOnArbiterMain(
|
|
|
936
923
|
)[] = [
|
|
937
924
|
'tasks-ready',
|
|
938
925
|
...(allowBacklog ? (['tasks-backlog'] as const) : []),
|
|
939
|
-
|
|
926
|
+
// NOTE: `work/in-progress/` is NOT probed (task
|
|
927
|
+
// `finish-in-progress-folder-cutover-remove-legacy-recovery-readers`): the
|
|
928
|
+
// per-item-lock cutover moved claim OFF writing that folder, so nothing lands a
|
|
929
|
+
// body there. A claimed-and-in-flight item RESTS in the pool/staging on `main`
|
|
930
|
+
// with the held lock as its liveness — `dispatchFolder` re-keys THAT to the
|
|
931
|
+
// `in-progress` dispatch off the LOCK (`state: active`), never a folder read.
|
|
932
|
+
// (`needs-attention/` is likewise the lock `state: stuck`; its retained probe is
|
|
933
|
+
// a separate cutover's concern, left untouched here.)
|
|
940
934
|
'needs-attention',
|
|
941
935
|
'done',
|
|
942
936
|
];
|
package/src/status.ts
CHANGED
|
@@ -81,7 +81,7 @@ export interface JobStatus {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
* One repo's PER-ITEM LOCK refs, surfaced for the dashboard (
|
|
84
|
+
* One repo's PER-ITEM LOCK refs, surfaced for the dashboard (spec
|
|
85
85
|
* `ledger-status-per-item-lock-refs` US #8; task
|
|
86
86
|
* `needs-attention-as-stuck-lock-state`). The in-flight view read from the lock
|
|
87
87
|
* refs — held (`active` = in-progress) and stuck (`needs-attention`) entries +
|
|
@@ -111,7 +111,7 @@ export interface StatusReport {
|
|
|
111
111
|
/** Stuck (needs-attention), crashed (running-but-dead), or un-reaped (done) jobs. */
|
|
112
112
|
attention: JobStatus[];
|
|
113
113
|
/**
|
|
114
|
-
* The PER-ITEM LOCK in-flight view (
|
|
114
|
+
* The PER-ITEM LOCK in-flight view (spec `ledger-status-per-item-lock-refs` US
|
|
115
115
|
* #8; task `needs-attention-as-stuck-lock-state`): per registered hub mirror,
|
|
116
116
|
* the held lock entries read from the mirror's `refs/dorfl/lock/*` refs —
|
|
117
117
|
* `active` holds (in-progress) and `stuck` holds (needs-attention) + reasons.
|
|
@@ -124,7 +124,7 @@ export interface StatusReport {
|
|
|
124
124
|
*/
|
|
125
125
|
lockHeld?: RepoLockEntries[];
|
|
126
126
|
/**
|
|
127
|
-
* The one-slug-one-folder LINT (
|
|
127
|
+
* The one-slug-one-folder LINT (spec `ledger-integrity` story 3): per registered
|
|
128
128
|
* hub mirror, any slug present in MORE THAN ONE `work/` status folder (a corrupt
|
|
129
129
|
* ledger). Read from the mirror's bare `main` ref (the SAME `ls-tree` source the
|
|
130
130
|
* needs-attention surface uses). Only repos WITH a duplicate appear. `status`
|
|
@@ -235,7 +235,7 @@ export async function status(options: StatusOptions): Promise<StatusReport> {
|
|
|
235
235
|
// reflects the remote truth. Never fatal — a failed fetch WARNS and falls back
|
|
236
236
|
// to the mirror's last-known `main`.
|
|
237
237
|
fetchMirrorMainOrWarn({mirrorPath, warn: options.warn, env: options.env});
|
|
238
|
-
// The PER-ITEM LOCK in-flight view (
|
|
238
|
+
// The PER-ITEM LOCK in-flight view (spec US #8): read the mirror's lock refs to
|
|
239
239
|
// surface held (`active` = in-progress) and stuck (`needs-attention`) entries +
|
|
240
240
|
// reasons/questions. A bare hub mirror's arbiter is its `origin` (the SAME
|
|
241
241
|
// handle the `scan` held-slug subtraction reads). Best-effort: a fetch/read
|
|
@@ -249,7 +249,7 @@ export async function status(options: StatusOptions): Promise<StatusReport> {
|
|
|
249
249
|
if (entries.length > 0) {
|
|
250
250
|
lockHeld.push({repoPath: mirrorPath, entries});
|
|
251
251
|
}
|
|
252
|
-
// The one-slug-one-folder LINT (
|
|
252
|
+
// The one-slug-one-folder LINT (spec story 3): derive any slug residing in >1
|
|
253
253
|
// status folder from the SAME freshly-fetched `main` ref, surfaced LOUDLY.
|
|
254
254
|
const dups = lintRefLedger('main', mirrorPath, options.env);
|
|
255
255
|
if (dups.length > 0) {
|
|
@@ -359,7 +359,7 @@ export function formatStatus(report: StatusReport): string {
|
|
|
359
359
|
}
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
// The PER-ITEM LOCK in-flight view (
|
|
362
|
+
// The PER-ITEM LOCK in-flight view (spec US #8; task
|
|
363
363
|
// `cutover-needs-attention-becomes-lock-stuck-recovery-surface`): the held lock
|
|
364
364
|
// refs read from each mirror — `active` holds (in-progress) and `stuck` holds
|
|
365
365
|
// (needs-attention) + their reasons/questions. This is the SOLE stuck-state
|
|
@@ -377,7 +377,7 @@ export function formatStatus(report: StatusReport): string {
|
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
-
// The one-slug-one-folder LINT (
|
|
380
|
+
// The one-slug-one-folder LINT (spec `ledger-integrity` story 3): WARN LOUDLY
|
|
381
381
|
// about every slug residing in >1 status folder of a registered mirror's ledger
|
|
382
382
|
// (a corrupt ledger — never a silent pass). A human must resolve each.
|
|
383
383
|
if (dupCount > 0) {
|
package/src/surface-gate.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {parseableJsonContractPrompt} from './review-verdict.js';
|
|
|
6
6
|
import type {NewQuestion} from './sidecar.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* The **SURFACE gate** (
|
|
9
|
+
* The **SURFACE gate** (spec `advance-loop`, task `advance-rung-surface`,
|
|
10
10
|
* US #32/33) — the surface-question rung's fresh-context spawn, the DIRECT mirror
|
|
11
11
|
* of the PR/code review gate ({@link import('./review-gate.js')}). On
|
|
12
12
|
* `classify=surface`, the advance engine spawns a FRESH-CONTEXT agent with the
|
|
@@ -70,7 +70,7 @@ export interface SurfaceEmit {
|
|
|
70
70
|
|
|
71
71
|
/** What the surface gate needs to launch a fresh-context surface of one item. */
|
|
72
72
|
export interface SurfaceGateInput {
|
|
73
|
-
/** The namespaced identity the surface is for (`task:foo` / `
|
|
73
|
+
/** The namespaced identity the surface is for (`task:foo` / `spec:bar` / `observation:baz`). */
|
|
74
74
|
item: string;
|
|
75
75
|
/** The working clone/checkout the gate runs in. */
|
|
76
76
|
cwd: string;
|
|
@@ -252,9 +252,16 @@ export function buildSurfacePrompt(item: string): string {
|
|
|
252
252
|
` "note": "… (optional; your reasoning / findings prose lives HERE, not outside the object)"}`,
|
|
253
253
|
'```',
|
|
254
254
|
``,
|
|
255
|
-
`
|
|
256
|
-
`
|
|
257
|
-
|
|
255
|
+
`RULE — empty is VALID, absence is NOT. When there is nothing to ask (no open`,
|
|
256
|
+
`judgement to surface), you MUST STILL emit the JSON object, with`,
|
|
257
|
+
`\`"questions": []\` (an empty array); put any explanation of WHY in the`,
|
|
258
|
+
`\`note\` field INSIDE the object. Do NOT replace the object with a prose`,
|
|
259
|
+
`sentence like "no open questions", do NOT skip the emit, and do NOT drop the`,
|
|
260
|
+
`\`questions\` field. The parser (\`parseSurfaceEmit\`) enforces this: an empty`,
|
|
261
|
+
`\`questions\` array is a valid, honest "no open judgement" result; ABSENCE of`,
|
|
262
|
+
`the \`questions\` field is rejected as an unparseable emit — that failure is`,
|
|
263
|
+
`what strands the surface rung. Emitting \`{"questions": [], "note": "…"}\` is`,
|
|
264
|
+
`ALWAYS the safe, honest close for a nothing-to-ask item.`,
|
|
258
265
|
``,
|
|
259
266
|
// The SHARED defensive-JSON contract (the same hardening Gate-2's verdict
|
|
260
267
|
// prompt carries) — the surface rung hit the IDENTICAL unparseable-emit
|
package/src/surface-persist.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from './sidecar.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* The engine-owned SURFACE PERSIST (
|
|
16
|
+
* The engine-owned SURFACE PERSIST (spec `advance-loop`, task
|
|
17
17
|
* `advance-rung-surface`, US #15/33) — the half of the surface rung the ENGINE
|
|
18
18
|
* owns (the skill JUDGES, the engine PERSISTS). Given the questions the
|
|
19
19
|
* `surface-questions` skill EMITTED (gathered by `surface-gate.ts`'s spawn), the
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
export interface SurfacePersistOptions {
|
|
54
54
|
/** Working clone/worktree the persist commits in. */
|
|
55
55
|
cwd: string;
|
|
56
|
-
/** The namespaced item identity (`task:foo` / `
|
|
56
|
+
/** The namespaced item identity (`task:foo` / `spec:bar` / `observation:baz`). */
|
|
57
57
|
item: string;
|
|
58
58
|
/**
|
|
59
59
|
* The item file path RELATIVE to `cwd` (e.g. `work/backlog/foo.md`). The
|
|
@@ -192,7 +192,7 @@ export function persistSurfacedQuestions(
|
|
|
192
192
|
|
|
193
193
|
// Write the appended/created sidecar.
|
|
194
194
|
mkdirSync(dirname(sidecarAbs), {recursive: true});
|
|
195
|
-
writeFileSync(sidecarAbs, serialiseSidecar(model));
|
|
195
|
+
writeFileSync(sidecarAbs, serialiseSidecar(model, {repoRoot: cwd}));
|
|
196
196
|
|
|
197
197
|
// Stage exactly the two paths and commit them TOGETHER (one atomic commit) —
|
|
198
198
|
// the sidecar write + the `needsAnswers:true` flip land in the SAME commit, so
|
|
@@ -29,9 +29,9 @@ export {parseReviewVerdict as parseTaskReviewVerdict} from './review-verdict.js'
|
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* **The tasker review→edit→re-review→converge LOOP** (`slicer-review-edit-loop`,
|
|
32
|
-
* GATES
|
|
32
|
+
* GATES spec `work/specs/ready/review.md` RESOLVED DESIGN — Shape 2 / insertion point A).
|
|
33
33
|
*
|
|
34
|
-
* On the `do
|
|
34
|
+
* On the `do spec:<slug>` tasking path (`tasking.ts`/`performTask`), AFTER the
|
|
35
35
|
* agent produces a candidate set of `work/tasks/backlog/<slug>.md` tasks and BEFORE the
|
|
36
36
|
* runner finalises/lands them, this loop RUNS the `review` SKILL
|
|
37
37
|
* (`skills/review/SKILL.md`), APPLIES its findings as EDITS to the candidate task
|
|
@@ -47,12 +47,12 @@ export {parseReviewVerdict as parseTaskReviewVerdict} from './review-verdict.js'
|
|
|
47
47
|
* N so the loop can never run forever.
|
|
48
48
|
*
|
|
49
49
|
* ⚠️ ASPIRATION-VS-BUILT (2026-06-10): the "single context" wording above is the
|
|
50
|
-
*
|
|
50
|
+
* spec's ASPIRATION, NOT what this module does at runtime. The ACTUAL N loop is
|
|
51
51
|
* RUNNER-DRIVEN and PER-PASS: `runOneExecution` does `for (pass …) { gate(…);
|
|
52
52
|
* applyEdits(…to disk…) }` — ONE agent LAUNCH per pass, the runner writing the
|
|
53
53
|
* agent's edits to the candidate task FILES (`work/tasks/backlog/`) between passes, the
|
|
54
54
|
* next pass's agent re-reading the edited files. Accumulation is via DISK +
|
|
55
|
-
* re-launch, NOT one agent retaining context. `
|
|
55
|
+
* re-launch, NOT one agent retaining context. `spec/review.md` §Shape 2 is internally
|
|
56
56
|
* contradictory on this (single-context headline vs "edit the files" operative spec);
|
|
57
57
|
* this code implements the operative reading. See
|
|
58
58
|
* `work/findings/review-edit-loop-single-context-is-unbuilt-aspiration-vs-per-pass-disk-impl.md`.
|
|
@@ -75,8 +75,9 @@ export {parseReviewVerdict as parseTaskReviewVerdict} from './review-verdict.js'
|
|
|
75
75
|
* - **a specific uncertain task** → emit it `needsAnswers: true` with the
|
|
76
76
|
* questions in its body (created, not agent-buildable until a human answers).
|
|
77
77
|
* - **the whole decomposition unclear / `taskerLoopMax` exhausted with blockers** →
|
|
78
|
-
*
|
|
79
|
-
* reason,
|
|
78
|
+
* mark the spec stuck on its per-item lock (post lock-cutover — `state: stuck`
|
|
79
|
+
* with the questions as the reason, no `work/needs-attention/` folder write),
|
|
80
|
+
* emitting NO guessed tasks.
|
|
80
81
|
*
|
|
81
82
|
* The verdict sink itself (the git transitions for those three outcomes) is the
|
|
82
83
|
* caller's (`tasking.ts`): this module decides WHICH outcome and prepares the
|
|
@@ -101,7 +102,7 @@ export type TaskReviewVerdict = ReviewVerdict;
|
|
|
101
102
|
|
|
102
103
|
/** What the review gate needs to launch a fresh-context review+edit pass. */
|
|
103
104
|
export interface TaskReviewGateInput {
|
|
104
|
-
/** The
|
|
105
|
+
/** The spec slug whose candidate tasks are under review. */
|
|
105
106
|
slug: string;
|
|
106
107
|
/** The working clone/checkout the loop runs in (candidate tasks live here). */
|
|
107
108
|
cwd: string;
|
|
@@ -141,7 +142,7 @@ export type LoopOutcome =
|
|
|
141
142
|
| 'converged'
|
|
142
143
|
/** `taskerLoopMax` hit with blockers → specific uncertain task(s) → needsAnswers. */
|
|
143
144
|
| 'uncertain-tasks'
|
|
144
|
-
/** `taskerLoopMax` hit / decomposition unclear → route the
|
|
145
|
+
/** `taskerLoopMax` hit / decomposition unclear → route the spec to needs-attention. */
|
|
145
146
|
| 'decomposition-unclear';
|
|
146
147
|
|
|
147
148
|
/** The result of running the loop — the disposition the caller's sink routes. */
|
|
@@ -174,7 +175,7 @@ export interface RunTaskReviewLoopResult {
|
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
export interface RunTaskReviewLoopOptions {
|
|
177
|
-
/** The
|
|
178
|
+
/** The spec slug whose candidate tasks are being improved. */
|
|
178
179
|
slug: string;
|
|
179
180
|
/** The working clone/checkout the loop runs in. */
|
|
180
181
|
cwd: string;
|
|
@@ -226,7 +227,7 @@ export interface RunTaskReviewLoopOptions {
|
|
|
226
227
|
* to the candidate task files, then re-review — until `verdict === 'approve'` (no
|
|
227
228
|
* NEW blocking issue → converged) or the pass count reaches `taskerLoopMax`. On the cap
|
|
228
229
|
* with a still-`block` verdict, ROUTE per the verdict's channels:
|
|
229
|
-
* - `decompositionUnclear` set ⇒ `decomposition-unclear` (
|
|
230
|
+
* - `decompositionUnclear` set ⇒ `decomposition-unclear` (spec → needs-attention,
|
|
230
231
|
* no guessed tasks);
|
|
231
232
|
* - else `uncertainTasks` (or, as a floor, every candidate task) ⇒
|
|
232
233
|
* `uncertain-tasks` (those tasks emitted `needsAnswers: true` + questions).
|
|
@@ -296,7 +297,7 @@ export async function runTaskReviewLoop(
|
|
|
296
297
|
note(
|
|
297
298
|
`Tasker review loop did not converge within taskerLoopMax=${taskerLoopMax} ` +
|
|
298
299
|
`across ${executions} fresh context(s); the whole decomposition is ` +
|
|
299
|
-
'unclear — routing the
|
|
300
|
+
'unclear — routing the spec to needs-attention (no guessed tasks).',
|
|
300
301
|
);
|
|
301
302
|
return {
|
|
302
303
|
outcome: 'decomposition-unclear',
|
|
@@ -308,7 +309,7 @@ export async function runTaskReviewLoop(
|
|
|
308
309
|
message:
|
|
309
310
|
`The decomposition of '${options.slug}' is still unclear after ` +
|
|
310
311
|
`taskerLoopMax=${taskerLoopMax} review pass(es) across ${executions} fresh ` +
|
|
311
|
-
'context(s); routing the
|
|
312
|
+
'context(s); routing the spec to needs-attention with the open ' +
|
|
312
313
|
'questions, emitting no guessed tasks.',
|
|
313
314
|
};
|
|
314
315
|
}
|
|
@@ -617,18 +618,18 @@ export function buildTaskReviewPrompt(input: TaskReviewGateInput): string {
|
|
|
617
618
|
const list = input.candidateTasks.map((p) => ` - ${p}`).join('\n');
|
|
618
619
|
return [
|
|
619
620
|
`You are a FRESH-CONTEXT reviewer in the TASKER review→edit→converge LOOP`,
|
|
620
|
-
`(insertion point A). Review the CANDIDATE TASKS just produced for the
|
|
621
|
+
`(insertion point A). Review the CANDIDATE TASKS just produced for the spec`,
|
|
621
622
|
`"${input.slug}":`,
|
|
622
623
|
list || ' (no candidate tasks found)',
|
|
623
624
|
``,
|
|
624
625
|
reviewDisciplinePrompt(),
|
|
625
626
|
``,
|
|
626
|
-
`Read the source
|
|
627
|
+
`Read the source spec (${workItemRel('specs-ready', `${input.slug}.md`)}) and review the candidate`,
|
|
627
628
|
`decomposition ADVERSARIALLY. Review the WHOLE SET — graph coherence / gaps /`,
|
|
628
629
|
`overlap / goal-composition (dependency-graph coherence, set-level gaps,`,
|
|
629
|
-
`overlapping/duplicated tasks, and "does the set compose into the
|
|
630
|
+
`overlapping/duplicated tasks, and "does the set compose into the spec goal")`,
|
|
630
631
|
`— not just per-task well-formedness. The DESTINATION CHECK ("if every task`,
|
|
631
|
-
`is built exactly as written, do we end up with the system the
|
|
632
|
+
`is built exactly as written, do we end up with the system the spec describes?")`,
|
|
632
633
|
`is PART OF this pass and may ITSELF trigger edits — that is why this is a`,
|
|
633
634
|
`loop, not a one-shot gate.`,
|
|
634
635
|
``,
|
|
@@ -645,7 +646,7 @@ export function buildTaskReviewPrompt(input: TaskReviewGateInput): string {
|
|
|
645
646
|
` can FIX a finding by editing (the natural improver step).`,
|
|
646
647
|
` - "uncertainTasks" — specific tasks you cannot make buildable (each gets`,
|
|
647
648
|
` \`needsAnswers: true\` with the questions in its body).`,
|
|
648
|
-
` - "decompositionUnclear" — the WHOLE decomposition is unsound (the
|
|
649
|
+
` - "decompositionUnclear" — the WHOLE decomposition is unsound (the spec is`,
|
|
649
650
|
` routed to needs-attention; emit no guessed tasks).`,
|
|
650
651
|
`Do NOT fill "review" / "edit" / "questions" — those are other callers'`,
|
|
651
652
|
`channels. Flag, do not guess: a flagged question costs one human glance; a`,
|
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pure tasking-eligibility resolution — the auto-task decision layer, one level
|
|
3
|
-
* UP from the build gate (`eligibility.ts`). No I/O: callers pass in the
|
|
3
|
+
* UP from the build gate (`eligibility.ts`). No I/O: callers pass in the spec's
|
|
4
4
|
* two autonomy axes (`humanOnly`, `needsAnswers`), the repo's `autoTask` policy,
|
|
5
|
-
* the
|
|
6
|
-
* TASKED (resolved against `work/
|
|
5
|
+
* the spec's `taskedAfter` slugs, and the set of slugs whose prds are already
|
|
6
|
+
* TASKED (resolved against `work/specs/tasked/` residence, NOT `work/done/`).
|
|
7
7
|
*
|
|
8
8
|
* This mirrors the build-gate shape deliberately (CONTEXT.md / the `auto-slice`
|
|
9
|
-
*
|
|
10
|
-
* predicate, applied to a
|
|
11
|
-
* cross-
|
|
9
|
+
* spec): the same `needsAnswers !== true && humanOnly !== true && <repo policy>`
|
|
10
|
+
* predicate, applied to a spec's two axes + the repo's `autoTask` toggle — and a
|
|
11
|
+
* cross-spec ordering check that resolves against tasked-ness rather than done-ness.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import type {HumanOnlyGate} from './eligibility.js';
|
|
15
15
|
|
|
16
16
|
export type {HumanOnlyGate};
|
|
17
17
|
|
|
18
|
-
/** Resolution of a
|
|
18
|
+
/** Resolution of a spec's `taskedAfter` against the set of already-tasked prds. */
|
|
19
19
|
export interface TaskedAfterResult {
|
|
20
|
-
/** True when every listed
|
|
20
|
+
/** True when every listed spec is already tasked. */
|
|
21
21
|
satisfied: boolean;
|
|
22
|
-
/** Listed
|
|
22
|
+
/** Listed spec slugs not yet tasked, in declaration order. */
|
|
23
23
|
missing: string[];
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export interface TaskingEligibilityInput {
|
|
27
|
-
/** Autonomy axis 1 (DECIDED): a human must drive THIS
|
|
27
|
+
/** Autonomy axis 1 (DECIDED): a human must drive THIS spec's tasking. */
|
|
28
28
|
humanOnly: HumanOnlyGate;
|
|
29
|
-
/** Autonomy axis 2 (DISCOVERED): the
|
|
29
|
+
/** Autonomy axis 2 (DISCOVERED): the spec has unresolved questions. */
|
|
30
30
|
needsAnswers: HumanOnlyGate;
|
|
31
|
-
/** Cross-
|
|
31
|
+
/** Cross-spec order: spec slugs that must already be tasked before this one. */
|
|
32
32
|
taskedAfter: string[];
|
|
33
|
-
/** Slugs of prds that are already TASKED (residence in `work/
|
|
33
|
+
/** Slugs of prds that are already TASKED (residence in `work/specs/tasked/`). */
|
|
34
34
|
taskedSlugs: Set<string>;
|
|
35
35
|
/** Per-repo policy: may an agent auto-task *undeclared* prds in this repo? */
|
|
36
36
|
autoTask: boolean;
|
|
37
37
|
/**
|
|
38
|
-
* The target was named EXPLICITLY by the operator (`do
|
|
39
|
-
* `autoTask` POLICY is already satisfied — naming the
|
|
38
|
+
* The target was named EXPLICITLY by the operator (`do spec:<slug>`), so the
|
|
39
|
+
* `autoTask` POLICY is already satisfied — naming the spec IS the authorization,
|
|
40
40
|
* exactly as `do <task>` builds a named task regardless of `autoBuild` (the
|
|
41
41
|
* `autoBuild` precedent: the pool/scan gates the policy, the explicit claim path
|
|
42
42
|
* never re-checks it). When `true`, the policy term drops from the gate and ONLY
|
|
43
|
-
* the
|
|
43
|
+
* the spec's own readiness axes (`humanOnly`/`needsAnswers`) + `taskedAfter` bind.
|
|
44
44
|
* Defaults `false` (the AUTO-PICK pool path, where the `autoTask` policy DOES
|
|
45
45
|
* gate). The pool is the single policy-enforcement point; the per-invocation gate
|
|
46
46
|
* applies the policy only when NOT explicit.
|
|
@@ -49,7 +49,7 @@ export interface TaskingEligibilityInput {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export interface TaskingEligibilityResult {
|
|
52
|
-
/** Taskable now = gate passes AND every `taskedAfter`
|
|
52
|
+
/** Taskable now = gate passes AND every `taskedAfter` spec is already tasked. */
|
|
53
53
|
taskable: boolean;
|
|
54
54
|
/** Whether the autonomy gate alone passes (agent-taskable on its own axes). */
|
|
55
55
|
gatePass: boolean;
|
|
@@ -61,7 +61,7 @@ export interface TaskingEligibilityResult {
|
|
|
61
61
|
* `true` AND `humanOnly` is not `true` AND the repo's `autoTask` POLICY is
|
|
62
62
|
* satisfied — where the policy is satisfied either by the repo's `autoTask`
|
|
63
63
|
* toggle being on (the AUTO-PICK pool path) OR by the target being named
|
|
64
|
-
* EXPLICITLY (`explicit: true` — `do
|
|
64
|
+
* EXPLICITLY (`explicit: true` — `do spec:<slug>`, where naming IS the
|
|
65
65
|
* authorization, mirroring `do <task>` vs `autoBuild`). Both readiness axes
|
|
66
66
|
* block orthogonally and are never agent-taskable regardless of policy; a human
|
|
67
67
|
* is never bound by either. The exact mirror of `resolveGate` (the build gate),
|
|
@@ -82,9 +82,9 @@ export function resolveTaskGate(
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* Resolve a
|
|
86
|
-
* `done/`): satisfied iff every listed
|
|
87
|
-
* untasked blocker ⇒ not yet taskable (so this
|
|
85
|
+
* Resolve a spec's `taskedAfter` against the slugs of prds already TASKED (NOT
|
|
86
|
+
* `done/`): satisfied iff every listed spec is present in `taskedSlugs`. An
|
|
87
|
+
* untasked blocker ⇒ not yet taskable (so this spec's emitted tasks can
|
|
88
88
|
* reference the real slugs of those prds' tasks).
|
|
89
89
|
*/
|
|
90
90
|
export function resolveTaskedAfter(
|