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/do.ts
CHANGED
|
@@ -59,7 +59,14 @@ import {
|
|
|
59
59
|
parseStopSentinel,
|
|
60
60
|
isWorkBranchDiffEmpty,
|
|
61
61
|
emptyDiffStopReason,
|
|
62
|
+
emptyDiffDisposeEnvelope,
|
|
63
|
+
type AgentStopClass,
|
|
62
64
|
} from './agent-stop.js';
|
|
65
|
+
import {
|
|
66
|
+
surfaceStuckToNeedsAttention,
|
|
67
|
+
routeToNeedsAttention,
|
|
68
|
+
} from './needs-attention.js';
|
|
69
|
+
import {resolveItemPathByIdentity} from './item-path.js';
|
|
63
70
|
import {
|
|
64
71
|
classifyFailureCause,
|
|
65
72
|
failureCauseLabel,
|
|
@@ -117,6 +124,149 @@ import {
|
|
|
117
124
|
* `complete` (the caller threads the resolved mode in as `integration`).
|
|
118
125
|
*/
|
|
119
126
|
|
|
127
|
+
/**
|
|
128
|
+
* The commit-message subject the deadline-checkpoint save writes, and the
|
|
129
|
+
* pattern used to COUNT consecutive checkpoints on the branch (spec
|
|
130
|
+
* `graceful-pre-timeout-wip-checkpoint` — the anti-loop ceiling). Living
|
|
131
|
+
* on-branch means the counter naturally RESETS when the item completes (the
|
|
132
|
+
* branch is discarded on integration) and when a `--reset` requeue discards
|
|
133
|
+
* the branch: a genuinely-progressing task cannot silently accumulate a
|
|
134
|
+
* ceiling breach across generations.
|
|
135
|
+
*/
|
|
136
|
+
const DEADLINE_CHECKPOINT_COMMIT_SUBJECT_PREFIX = 'chore(deadline-checkpoint)';
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Distinct reason strings for the two deadline-checkpoint branches (spec
|
|
140
|
+
* `graceful-pre-timeout-wip-checkpoint` — the CI/human report must NEVER
|
|
141
|
+
* collapse to a generic "agent-failed"). Auto-continue and surface carry
|
|
142
|
+
* different phrasing so the counter + ceiling are legible.
|
|
143
|
+
*/
|
|
144
|
+
function deadlineAutoContinueReason(params: {
|
|
145
|
+
slug: string;
|
|
146
|
+
count: number;
|
|
147
|
+
max: number;
|
|
148
|
+
}): string {
|
|
149
|
+
return (
|
|
150
|
+
`deadline checkpoint (auto-continued ${params.count}/${params.max}): ` +
|
|
151
|
+
`'${params.slug}' hit the dorfl-internal deadline with new work-branch ` +
|
|
152
|
+
`progress this session; saved the WIP and released the lock so the next ` +
|
|
153
|
+
`tick continues from the branch tip.`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
function deadlineSurfaceReason(params: {
|
|
157
|
+
slug: string;
|
|
158
|
+
kind: 'no-progress' | 'ceiling';
|
|
159
|
+
count?: number;
|
|
160
|
+
max?: number;
|
|
161
|
+
}): string {
|
|
162
|
+
if (params.kind === 'no-progress') {
|
|
163
|
+
return (
|
|
164
|
+
`deadline checkpoint (no progress / ceiling): '${params.slug}' hit ` +
|
|
165
|
+
`the dorfl-internal deadline WITHOUT any work-branch progress this ` +
|
|
166
|
+
`session — indistinguishable from a wedge; surfaced for a human to ` +
|
|
167
|
+
`decide (continue / split / cancel).`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
return (
|
|
171
|
+
`deadline checkpoint (no progress / ceiling): '${params.slug}' has hit ` +
|
|
172
|
+
`the dorfl-internal deadline ${params.count}/${params.max} times ` +
|
|
173
|
+
`consecutively — it may be too big for one CI leg. Split it or run ` +
|
|
174
|
+
`it locally; surfaced for a human to decide.`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Count how many DEADLINE-CHECKPOINT commits (subject prefix
|
|
180
|
+
* `chore(deadline-checkpoint)`) currently sit on the work branch ahead of
|
|
181
|
+
* `<arbiter>/main` — the branch-based anti-loop counter (spec
|
|
182
|
+
* `graceful-pre-timeout-wip-checkpoint`). A best-effort count: an unreachable
|
|
183
|
+
* arbiter / a bare mirror reads as 0 (the SAFE direction — never falsely block
|
|
184
|
+
* an auto-continue) so a genuine plumbing fault degrades to "under the ceiling"
|
|
185
|
+
* rather than surfacing a spurious ceiling breach. Resets naturally when the
|
|
186
|
+
* item completes (the branch is discarded on integration).
|
|
187
|
+
*/
|
|
188
|
+
async function countDeadlineCheckpointsOnBranch(params: {
|
|
189
|
+
cwd: string;
|
|
190
|
+
arbiter: string;
|
|
191
|
+
branch: string;
|
|
192
|
+
env: NodeJS.ProcessEnv | undefined;
|
|
193
|
+
}): Promise<number> {
|
|
194
|
+
const {cwd, arbiter, branch, env} = params;
|
|
195
|
+
const range = `${arbiter}/main..HEAD`;
|
|
196
|
+
void branch;
|
|
197
|
+
const r = await runAsync('git', ['log', '--format=%s', range], cwd, {env});
|
|
198
|
+
if (r.status !== 0) {
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
const lines = r.stdout.split('\n').filter((s) => s.length > 0);
|
|
202
|
+
return lines.filter((s) =>
|
|
203
|
+
s.startsWith(DEADLINE_CHECKPOINT_COMMIT_SUBJECT_PREFIX),
|
|
204
|
+
).length;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* SAVE the WIP on a deadline stop (spec `graceful-pre-timeout-wip-checkpoint`,
|
|
209
|
+
* build step 3): commit the tree as-is + push `work/<slug>`. Reuses the SAVE
|
|
210
|
+
* HALF of the needs-attention mechanism ({@link routeToNeedsAttention}) but
|
|
211
|
+
* ADDS a distinguishing checkpoint-marker commit on top so
|
|
212
|
+
* {@link countDeadlineCheckpointsOnBranch} can count auto-continues. Distinct
|
|
213
|
+
* from `applyNeedsAttentionTransition` (the whole thing) which ALSO marks the
|
|
214
|
+
* lock stuck — auto-continue must NOT mark stuck; only the surface branch does.
|
|
215
|
+
*/
|
|
216
|
+
async function saveDeadlineCheckpoint(params: {
|
|
217
|
+
slug: string;
|
|
218
|
+
branch: string;
|
|
219
|
+
cwd: string;
|
|
220
|
+
arbiter: string;
|
|
221
|
+
reason: string;
|
|
222
|
+
env: NodeJS.ProcessEnv | undefined;
|
|
223
|
+
note: (message: string) => void;
|
|
224
|
+
}): Promise<import('./needs-attention.js').RouteToNeedsAttentionResult> {
|
|
225
|
+
const {slug, branch, cwd, arbiter, reason, env, note} = params;
|
|
226
|
+
void reason;
|
|
227
|
+
// Save any uncommitted work first (the routeToNeedsAttention save half also
|
|
228
|
+
// commits + pushes; but we ALSO want a distinct checkpoint-marker commit so
|
|
229
|
+
// countDeadlineCheckpointsOnBranch can enumerate them). Stage everything and
|
|
230
|
+
// commit a MARKER commit if there's anything to record OR if there is not
|
|
231
|
+
// already a marker on the tip — the marker's job is to make the checkpoint
|
|
232
|
+
// COUNTABLE, not to represent new work.
|
|
233
|
+
const addResult = await runAsync('git', ['add', '-A'], cwd, {env});
|
|
234
|
+
void addResult;
|
|
235
|
+
const diffCached = await runAsync(
|
|
236
|
+
'git',
|
|
237
|
+
['diff', '--cached', '--quiet'],
|
|
238
|
+
cwd,
|
|
239
|
+
{env},
|
|
240
|
+
);
|
|
241
|
+
const hasStaged = diffCached.status !== 0;
|
|
242
|
+
if (hasStaged) {
|
|
243
|
+
await runAsync(
|
|
244
|
+
'git',
|
|
245
|
+
[
|
|
246
|
+
'commit',
|
|
247
|
+
'-q',
|
|
248
|
+
'-m',
|
|
249
|
+
`${DEADLINE_CHECKPOINT_COMMIT_SUBJECT_PREFIX}: save wip for '${slug}'`,
|
|
250
|
+
],
|
|
251
|
+
cwd,
|
|
252
|
+
{env},
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
// Push the branch to the arbiter (best-effort). Reuse routeToNeedsAttention's
|
|
256
|
+
// save-half exact contract: it commits any residue + pushes the branch with
|
|
257
|
+
// bounded backoff. We already committed above; the wip commit inside
|
|
258
|
+
// routeToNeedsAttention will be a no-op (clean tree) and the push runs.
|
|
259
|
+
return routeToNeedsAttention({
|
|
260
|
+
cwd,
|
|
261
|
+
slug,
|
|
262
|
+
reason: `deadline-checkpoint save for '${slug}' (see branch)`,
|
|
263
|
+
arbiter,
|
|
264
|
+
branch,
|
|
265
|
+
note,
|
|
266
|
+
env,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
120
270
|
/** The terminal status of one in-place `do` run. */
|
|
121
271
|
export type DoOutcome =
|
|
122
272
|
| 'completed' // claimed/onboarded → agent → gate green → integrated → exited
|
|
@@ -126,18 +276,21 @@ export type DoOutcome =
|
|
|
126
276
|
| 'surface-unmoved' // the tree-less surface to needs-attention did NOT land on the arbiter (lost the CAS race / no arbiter) — the item is STILL in-progress on the arbiter; retry/resolve
|
|
127
277
|
| 'agent-failed' // the agent ran but produced bad/empty output (the conservative generic), OR the cause is unknown — work SAVED + surfaced
|
|
128
278
|
| 'transient-infra' // a harness-surfaced model/connection outage (post-retry) or a git/provider outage — RETRY the same work (FAILURE-CAUSE axis)
|
|
279
|
+
| 'needs-reauth' // a credential expired / was revoked (OAuth refresh) — retry cannot help; a human must RE-AUTH (FAILURE-CAUSE axis)
|
|
129
280
|
| 'config-error' // a thrown CORE wiring/config error (e.g. review on, no reviewGate) — fix the WIRING, not the task (FAILURE-CAUSE axis)
|
|
130
281
|
| 'agent-stopped' // the agent DELIBERATELY stopped (task drifted/ambiguous) OR produced no change → surfaced; gate + Gate-2 SKIPPED
|
|
282
|
+
| 'deadline-auto-continued' // the dorfl-internal deadline fired; WIP saved + branch pushed + lock RELEASED (no sidecar) so the next tick continues (spec `graceful-pre-timeout-wip-checkpoint`)
|
|
283
|
+
| 'deadline-surfaced' // the dorfl-internal deadline fired but auto-continue was refused (no progress this session, or the maxAutoCheckpoints ceiling was hit); WIP saved + question SURFACED for a human
|
|
131
284
|
| 'refused' // refused (dirty tree, wrong folder, nothing to complete, …)
|
|
132
285
|
| 'usage-error' // usage / environment problem, or a slug-resolution error
|
|
133
|
-
| 'tasked' // `do
|
|
134
|
-
| 'gate-refused' // `do
|
|
135
|
-
| 'stale'; // `do
|
|
286
|
+
| 'tasked' // `do spec:<slug>` — the spec was tasked into work/backlog/ (runner-owned)
|
|
287
|
+
| 'gate-refused' // `do spec:<slug>` — the tasking gate refused (honest skip)
|
|
288
|
+
| 'stale'; // `do spec:<slug>` — the held spec was edited under the lock (stale tasking)
|
|
136
289
|
|
|
137
290
|
export interface DoResult {
|
|
138
291
|
exitCode: 0 | 1 | 2 | 3;
|
|
139
292
|
outcome: DoOutcome;
|
|
140
|
-
/** The resolved bare slug acted on (task or
|
|
293
|
+
/** The resolved bare slug acted on (task or spec), when one was resolved. */
|
|
141
294
|
slug?: string;
|
|
142
295
|
/** The work branch the run operated on, when one was created/switched-to. */
|
|
143
296
|
branch?: string;
|
|
@@ -168,10 +321,18 @@ export type DoDorfl = (input: {
|
|
|
168
321
|
* Absent ⇒ no body ⇒ the provider degrades to `--fill` (no regression).
|
|
169
322
|
*/
|
|
170
323
|
output?: string;
|
|
324
|
+
/**
|
|
325
|
+
* **True iff the injected agent simulates a dorfl-internal DEADLINE stop**
|
|
326
|
+
* (spec `graceful-pre-timeout-wip-checkpoint`). Test-only signal so an
|
|
327
|
+
* injected `DoDorfl` can drive the checkpoint routing (save WIP +
|
|
328
|
+
* auto-continue / surface). Production `runDoAgent` never sets this on the
|
|
329
|
+
* injected path — the real deadline race lives in `PiHarness.launchAsync`.
|
|
330
|
+
*/
|
|
331
|
+
timedOut?: boolean;
|
|
171
332
|
};
|
|
172
333
|
|
|
173
334
|
export interface DoOptions {
|
|
174
|
-
/** The raw CLI slug argument: bare (= task), `task:<slug>`, or `
|
|
335
|
+
/** The raw CLI slug argument: bare (= task), `task:<slug>`, or `spec:<slug>`. */
|
|
175
336
|
arg: string;
|
|
176
337
|
/** The working clone/checkout to run in-place in. */
|
|
177
338
|
cwd: string;
|
|
@@ -187,10 +348,10 @@ export interface DoOptions {
|
|
|
187
348
|
/**
|
|
188
349
|
* Per-repo `autoTask` policy (resolved by `autoslice-gate`: flag > env >
|
|
189
350
|
* per-repo > global > default false). It gates the AUTO-PICK / pool path only
|
|
190
|
-
* (`do-autopick.ts`'s taskable-
|
|
191
|
-
* UNDECLARED
|
|
351
|
+
* (`do-autopick.ts`'s taskable-spec pool): "may an agent auto-task an
|
|
352
|
+
* UNDECLARED spec in this repo?". An EXPLICITLY-named `do spec:<slug>` tasks
|
|
192
353
|
* REGARDLESS of this policy (the dispatch passes `explicit: true` to
|
|
193
|
-
* `performTask` — naming the
|
|
354
|
+
* `performTask` — naming the spec IS the authorization, exactly as `do <task>`
|
|
194
355
|
* builds regardless of `autoBuild`). Ignored by the task-build path.
|
|
195
356
|
*/
|
|
196
357
|
autoTask?: boolean;
|
|
@@ -205,7 +366,7 @@ export interface DoOptions {
|
|
|
205
366
|
promptGuidance?: PromptGuidance;
|
|
206
367
|
/**
|
|
207
368
|
* **The tasker review→edit→converge LOOP seam** (`slicer-review-edit-loop`):
|
|
208
|
-
* consumed ONLY by the `do
|
|
369
|
+
* consumed ONLY by the `do spec:<slug>` tasking path — after the agent produces
|
|
209
370
|
* candidate tasks, run the `review` SKILL as a review→edit→re-review loop that
|
|
210
371
|
* improves them, routing the verdict through the needsAnswers / needs-attention
|
|
211
372
|
* sink. Ignored by the task-build path. Omitted ⇒ no loop (candidate tasks land
|
|
@@ -234,27 +395,27 @@ export interface DoOptions {
|
|
|
234
395
|
explicitMerge?: boolean;
|
|
235
396
|
/**
|
|
236
397
|
* **Per-TRANSITION override for the TASKING transition only** (config
|
|
237
|
-
* `taskingIntegration`). Consumed ONLY by the `do
|
|
398
|
+
* `taskingIntegration`). Consumed ONLY by the `do spec:<slug>` tasking path: the
|
|
238
399
|
* value threaded into {@link performTask} is `taskingIntegration ?? integration`,
|
|
239
400
|
* so an unset override is byte-for-byte today's behaviour (tasking uses
|
|
240
401
|
* `integration`). The task-BUILD path ALWAYS threads `integration` (never this
|
|
241
402
|
* key). An explicit `--merge`/`--propose` flag wins over BOTH (the flag-override
|
|
242
403
|
* layer sets `integration` AND `taskingIntegration` to the typed mode — see
|
|
243
|
-
* `do-config.ts`). DISTINCT from intake's per-EMITTED-TYPE `{task,
|
|
404
|
+
* `do-config.ts`). DISTINCT from intake's per-EMITTED-TYPE `{task, spec}` resolver.
|
|
244
405
|
*/
|
|
245
406
|
taskingIntegration?: IntegrationMode;
|
|
246
407
|
/**
|
|
247
|
-
* **The per-repo TASK-PLACEMENT default** (
|
|
408
|
+
* **The per-repo TASK-PLACEMENT default** (spec
|
|
248
409
|
* `staging-pool-position-gate-and-trust-model` US #5, task
|
|
249
410
|
* `runner-deterministic-slice-placement-policy-and-precedence`). Consumed by
|
|
250
|
-
* the `do
|
|
411
|
+
* the `do spec:<slug>` tasking path: the value is fed as the
|
|
251
412
|
* CONFIGURED-DEFAULT rung into the runner-deterministic placement resolver
|
|
252
413
|
* (`src/placement.ts`). Resolved per-repo through the SAME chain as
|
|
253
414
|
* `taskingIntegration` (flag > env > per-repo > global > built-in
|
|
254
|
-
* `
|
|
415
|
+
* `backlog`). The task-BUILD path ignores it (placement is a TASKING
|
|
255
416
|
* lifecycle concern).
|
|
256
417
|
*/
|
|
257
|
-
tasksLandIn?: '
|
|
418
|
+
tasksLandIn?: 'backlog' | 'ready';
|
|
258
419
|
/**
|
|
259
420
|
* **The OPERATOR's EXPLICIT task-placement override** (the TOP precedence
|
|
260
421
|
* rung in the placement resolver). Set ONLY when the operator typed
|
|
@@ -263,7 +424,7 @@ export interface DoOptions {
|
|
|
263
424
|
* CLI always wins, no special force-key) — the positional analogue of
|
|
264
425
|
* `explicitMerge` overriding the untrusted-origin build-propose rule.
|
|
265
426
|
*/
|
|
266
|
-
explicitTasksLandIn?: '
|
|
427
|
+
explicitTasksLandIn?: 'backlog' | 'ready';
|
|
267
428
|
/**
|
|
268
429
|
* Override the pre-flight DIVERGENCE guard (`--ignore-diverged-main`, mirroring
|
|
269
430
|
* `--ignore-not-ready`): proceed even when local `main` is ahead of
|
|
@@ -274,7 +435,7 @@ export interface DoOptions {
|
|
|
274
435
|
*/
|
|
275
436
|
ignoreDivergedMain?: boolean;
|
|
276
437
|
/**
|
|
277
|
-
* **`--allow-backlog`** (
|
|
438
|
+
* **`--allow-backlog`** (spec
|
|
278
439
|
* `do-allow-backlog-drive-staged-tasks-without-promotion`): let this `do task:`
|
|
279
440
|
* invocation FIND, CLAIM, and COMPLETE a task that lives in `tasks/backlog/`
|
|
280
441
|
* (staging) IN PLACE, WITHOUT first promoting it to the pool — so no `advance`
|
|
@@ -284,7 +445,7 @@ export interface DoOptions {
|
|
|
284
445
|
* build/gate are identical, and the done-move goes `tasks/backlog/ → tasks/done/`
|
|
285
446
|
* directly (the explicit drive IS the promotion). EXPLICIT-INVOCATION-ONLY:
|
|
286
447
|
* default off, never set by `run`/auto-pick/`advance` (the leak-fence). The
|
|
287
|
-
* task-build path only; the `do
|
|
448
|
+
* task-build path only; the `do spec:` path is unaffected.
|
|
288
449
|
*/
|
|
289
450
|
allowBacklog?: boolean;
|
|
290
451
|
/** The declared per-repo ENV-PREP step (string | list), run ONCE before the
|
|
@@ -300,7 +461,7 @@ export interface DoOptions {
|
|
|
300
461
|
*/
|
|
301
462
|
freshWorktreeGate?: boolean;
|
|
302
463
|
/**
|
|
303
|
-
* **The cross-job merge-serialiser CAS-retry cap** (config `mergeRetries`,
|
|
464
|
+
* **The cross-job merge-serialiser CAS-retry cap** (config `mergeRetries`, spec
|
|
304
465
|
* `land-time-reverify-and-parallel-merge-ceiling` Story 5 / Applied Answer q1
|
|
305
466
|
* (a)). Threaded VERBATIM into `performComplete` → `performIntegration` so a
|
|
306
467
|
* wide-matrix CI's raised cap actually reaches the cross-job land queue (the
|
|
@@ -335,7 +496,7 @@ export interface DoOptions {
|
|
|
335
496
|
*/
|
|
336
497
|
providerInstance?: ReviewProvider;
|
|
337
498
|
/**
|
|
338
|
-
* **Gate 2 — the PR/code review gate** (GATES
|
|
499
|
+
* **Gate 2 — the PR/code review gate** (GATES spec `work/specs/tasked/review.md`):
|
|
339
500
|
* threaded VERBATIM into `performComplete` (the gate rides inside the shared
|
|
340
501
|
* `do`/`complete` pipeline, so CI inherits it for free). When `review` is on,
|
|
341
502
|
* the `review` SKILL runs as a fresh-context agent AFTER the green `verify` and
|
|
@@ -349,7 +510,7 @@ export interface DoOptions {
|
|
|
349
510
|
reviewGate?: ReviewGate;
|
|
350
511
|
/**
|
|
351
512
|
* **The task-SET ACCEPTANCE GATE seam** (task `slice-acceptance-gate`):
|
|
352
|
-
* consumed ONLY by the `do
|
|
513
|
+
* consumed ONLY by the `do spec:<slug>` tasking path. When `review` resolves on,
|
|
353
514
|
* a fresh-context review of the produced task SET runs BEFORE the tasks
|
|
354
515
|
* integrate (riding `performIntegration`'s review block); `block` routes the set
|
|
355
516
|
* to needs-attention, `approve` lets it integrate. It rides the SAME BUILD
|
|
@@ -408,6 +569,22 @@ export interface DoOptions {
|
|
|
408
569
|
* a sink to assert the surfaced lines without a real terminal.
|
|
409
570
|
*/
|
|
410
571
|
watchSink?: (line: string) => void;
|
|
572
|
+
/**
|
|
573
|
+
* The dorfl-internal agent-session deadline in minutes (spec
|
|
574
|
+
* `graceful-pre-timeout-wip-checkpoint`). Threaded through {@link runDoAgent}
|
|
575
|
+
* to `launchWithOptionalWatch` — the harness races the child against it and
|
|
576
|
+
* flags a graceful stop on fire, which `performDo` routes as a CHECKPOINT
|
|
577
|
+
* (save WIP + auto-continue on progress under the ceiling, else surface).
|
|
578
|
+
* Absent ⇒ no deadline (a run that finishes on its own is byte-for-byte
|
|
579
|
+
* unchanged).
|
|
580
|
+
*/
|
|
581
|
+
agentDeadlineMinutes?: number;
|
|
582
|
+
/**
|
|
583
|
+
* Anti-loop ceiling on CONSECUTIVE deadline auto-continues (spec
|
|
584
|
+
* `graceful-pre-timeout-wip-checkpoint`). On hitting this the next
|
|
585
|
+
* deadline checkpoint surfaces to a human instead of auto-continuing.
|
|
586
|
+
*/
|
|
587
|
+
maxAutoCheckpoints?: number;
|
|
411
588
|
}
|
|
412
589
|
|
|
413
590
|
/**
|
|
@@ -433,6 +610,25 @@ interface DoAgentLaunchOptions {
|
|
|
433
610
|
watch?: boolean;
|
|
434
611
|
watchSink?: (line: string) => void;
|
|
435
612
|
color?: boolean;
|
|
613
|
+
/**
|
|
614
|
+
* **The dorfl-internal agent deadline in minutes** (spec
|
|
615
|
+
* `graceful-pre-timeout-wip-checkpoint`). Threaded to {@link runDoAgent},
|
|
616
|
+
* which converts it to a wall-clock `deadlineMs` and passes it to
|
|
617
|
+
* {@link launchWithOptionalWatch} — the pi harness races the child against
|
|
618
|
+
* that deadline. When the deadline fires, the agent is gracefully stopped
|
|
619
|
+
* (SIGTERM + 10s grace + SIGKILL) and the caller routes the run as a
|
|
620
|
+
* CHECKPOINT (save WIP + auto-continue / surface). Absent ⇒ no deadline
|
|
621
|
+
* (byte-for-byte the pre-task behaviour).
|
|
622
|
+
*/
|
|
623
|
+
agentDeadlineMinutes?: number;
|
|
624
|
+
/**
|
|
625
|
+
* **The anti-loop ceiling** for consecutive deadline auto-continues (spec
|
|
626
|
+
* `graceful-pre-timeout-wip-checkpoint`). On hitting this the next deadline
|
|
627
|
+
* checkpoint SURFACES to a human instead of auto-continuing. Absent ⇒
|
|
628
|
+
* unlimited (⇒ defensive callers should always thread the resolved config
|
|
629
|
+
* value; the default is 5).
|
|
630
|
+
*/
|
|
631
|
+
maxAutoCheckpoints?: number;
|
|
436
632
|
env?: NodeJS.ProcessEnv;
|
|
437
633
|
/**
|
|
438
634
|
* The optional runner IDENTITY (a bot). Threaded from the host-only
|
|
@@ -453,7 +649,7 @@ interface DoAgentLaunchOptions {
|
|
|
453
649
|
* there is no checkout, so the worktree is materialised under `workspacesDir`.
|
|
454
650
|
*/
|
|
455
651
|
export interface DoRemoteOptions extends DoAgentLaunchOptions {
|
|
456
|
-
/** The raw CLI slug argument: bare (= task), `task:<slug>`, or `
|
|
652
|
+
/** The raw CLI slug argument: bare (= task), `task:<slug>`, or `spec:<slug>`. */
|
|
457
653
|
arg: string;
|
|
458
654
|
/**
|
|
459
655
|
* The registered remote spec/URL to run against (`do --remote <r>`). Resolved
|
|
@@ -473,12 +669,12 @@ export interface DoRemoteOptions extends DoAgentLaunchOptions {
|
|
|
473
669
|
arbiter?: string;
|
|
474
670
|
/**
|
|
475
671
|
* Per-repo `autoTask` policy — gates the AUTO-PICK / pool path only. An
|
|
476
|
-
* EXPLICITLY-named `do --remote
|
|
672
|
+
* EXPLICITLY-named `do --remote spec:<slug>` tasks regardless of it (the
|
|
477
673
|
* dispatch passes `explicit: true`), mirroring `do <task>` vs `autoBuild`.
|
|
478
674
|
* Ignored by the task-build path.
|
|
479
675
|
*/
|
|
480
676
|
autoTask?: boolean;
|
|
481
|
-
/** The tasker review→edit→converge loop seam — `do --remote
|
|
677
|
+
/** The tasker review→edit→converge loop seam — `do --remote spec:<slug>` path only (see {@link DoOptions.reviewLoop}). */
|
|
482
678
|
reviewLoop?: TaskReviewGate;
|
|
483
679
|
/** The tasker improver loop's `taskerLoopMax` cap. Loop only. */
|
|
484
680
|
taskerLoopMax?: number;
|
|
@@ -495,24 +691,24 @@ export interface DoRemoteOptions extends DoAgentLaunchOptions {
|
|
|
495
691
|
explicitMerge?: boolean;
|
|
496
692
|
/**
|
|
497
693
|
* **Per-TRANSITION override for the TASKING transition only** (config
|
|
498
|
-
* `taskingIntegration`) on the `do --remote
|
|
694
|
+
* `taskingIntegration`) on the `do --remote spec:<slug>` path: threaded into
|
|
499
695
|
* {@link performTask} as `taskingIntegration ?? integration`. Unset ⇒ tasking
|
|
500
696
|
* uses `integration` (today's behaviour); the task-BUILD path always threads
|
|
501
697
|
* `integration`. See {@link DoOptions.taskingIntegration}.
|
|
502
698
|
*/
|
|
503
699
|
taskingIntegration?: IntegrationMode;
|
|
504
700
|
/**
|
|
505
|
-
* **The per-repo TASK-PLACEMENT default** (
|
|
701
|
+
* **The per-repo TASK-PLACEMENT default** (spec
|
|
506
702
|
* `staging-pool-position-gate-and-trust-model` US #5) on the `do --remote
|
|
507
|
-
*
|
|
703
|
+
* spec:<slug>` path: threaded into {@link performTask} as the
|
|
508
704
|
* configured-default rung. See {@link DoOptions.tasksLandIn}.
|
|
509
705
|
*/
|
|
510
|
-
tasksLandIn?: '
|
|
706
|
+
tasksLandIn?: 'backlog' | 'ready';
|
|
511
707
|
/**
|
|
512
708
|
* **The OPERATOR's EXPLICIT task-placement override** on the `do --remote
|
|
513
|
-
*
|
|
709
|
+
* spec:` path. See {@link DoOptions.explicitTasksLandIn}.
|
|
514
710
|
*/
|
|
515
|
-
explicitTasksLandIn?: '
|
|
711
|
+
explicitTasksLandIn?: 'backlog' | 'ready';
|
|
516
712
|
/** The declared per-repo ENV-PREP step (string | list), run ONCE before the
|
|
517
713
|
* first `verify` on a fresh worktree. Unset ⇒ a no-op (NO default install). */
|
|
518
714
|
prepare?: VerifyConfig;
|
|
@@ -526,7 +722,7 @@ export interface DoRemoteOptions extends DoAgentLaunchOptions {
|
|
|
526
722
|
*/
|
|
527
723
|
freshWorktreeGate?: boolean;
|
|
528
724
|
/**
|
|
529
|
-
* **The cross-job merge-serialiser CAS-retry cap** (config `mergeRetries`,
|
|
725
|
+
* **The cross-job merge-serialiser CAS-retry cap** (config `mergeRetries`, spec
|
|
530
726
|
* `land-time-reverify-and-parallel-merge-ceiling` Story 5 / Applied Answer q1
|
|
531
727
|
* (a)). Threaded VERBATIM into `performComplete` → `performIntegration` so the
|
|
532
728
|
* resolved cap reaches the cross-job land queue (the CAS loop IS the queue
|
|
@@ -564,7 +760,7 @@ export interface DoRemoteOptions extends DoAgentLaunchOptions {
|
|
|
564
760
|
reviewModel?: string;
|
|
565
761
|
reviewMaxRounds?: number;
|
|
566
762
|
reviewGate?: ReviewGate;
|
|
567
|
-
/** The task-SET ACCEPTANCE GATE seam — `do --remote
|
|
763
|
+
/** The task-SET ACCEPTANCE GATE seam — `do --remote spec:<slug>` path only (see {@link DoOptions.taskReviewGate}). */
|
|
568
764
|
taskReviewGate?: ReviewGate;
|
|
569
765
|
/**
|
|
570
766
|
* **`--allow-backlog`** on the no-checkout `do --remote`/`--isolated` path (see
|
|
@@ -586,7 +782,7 @@ export interface DoRemoteOptions extends DoAgentLaunchOptions {
|
|
|
586
782
|
const DEFAULT_ARBITER = 'origin';
|
|
587
783
|
|
|
588
784
|
/**
|
|
589
|
-
* Map a `do
|
|
785
|
+
* Map a `do spec:<slug>` {@link TaskResult} onto the `do` {@link DoResult}
|
|
590
786
|
* contract: outcomes pass through (tasked / gate-refused / stale / agent-failed /
|
|
591
787
|
* usage-error), the lock-lost outcome splits into `lost` (exit 2) vs `contended`
|
|
592
788
|
* (exit 3) by its exit code, and the tasking-only exit 4 (stale) is reported on
|
|
@@ -620,7 +816,7 @@ function taskResultToDoResult(tasked: TaskResult): DoResult {
|
|
|
620
816
|
break;
|
|
621
817
|
case 'needs-attention':
|
|
622
818
|
// The tasker review→edit loop found the decomposition unclear and routed the
|
|
623
|
-
//
|
|
819
|
+
// spec to needs-attention (no guessed tasks). Same exit class as a stuck
|
|
624
820
|
// build (1).
|
|
625
821
|
outcome = 'needs-attention';
|
|
626
822
|
exitCode = 1;
|
|
@@ -684,8 +880,8 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
684
880
|
}
|
|
685
881
|
|
|
686
882
|
// 1. Resolve the slug across BOTH namespaces — `do` is the ONE command that
|
|
687
|
-
// spans them (ADR §3a): bare → task (after a no-
|
|
688
|
-
// ERROR on collision), `task:`/`
|
|
883
|
+
// spans them (ADR §3a): bare → task (after a no-spec-collision check;
|
|
884
|
+
// ERROR on collision), `task:`/`spec:` explicit. A collision / resolution
|
|
689
885
|
// failure is a loud usage error (exit 1).
|
|
690
886
|
let resolved;
|
|
691
887
|
try {
|
|
@@ -717,10 +913,10 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
717
913
|
arbiter,
|
|
718
914
|
doer: 'agent',
|
|
719
915
|
autoTask: options.autoTask,
|
|
720
|
-
// EXPLICIT dispatch: a `do
|
|
916
|
+
// EXPLICIT dispatch: a `do spec:<slug>` target was NAMED (the operator typed
|
|
721
917
|
// it, or the auto-pick POOL already filtered it on `autoTask` before
|
|
722
918
|
// dispatching here — the single policy-enforcement point). So the tasking gate
|
|
723
|
-
// drops the `autoTask` policy term and binds only the
|
|
919
|
+
// drops the `autoTask` policy term and binds only the spec's own readiness
|
|
724
920
|
// (`humanOnly`/`needsAnswers`) + `taskedAfter`, EXACTLY as `do <task>` builds a
|
|
725
921
|
// named task regardless of `autoBuild` (the pool gates the policy, not the
|
|
726
922
|
// explicit claim).
|
|
@@ -741,19 +937,24 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
741
937
|
// `integration:'propose'` + `taskingIntegration:'merge'` lands the task FILES
|
|
742
938
|
// on main here while the BUILD path below still threads plain `integration`.
|
|
743
939
|
integration: options.taskingIntegration ?? options.integration,
|
|
940
|
+
// The cross-job merge-serialiser CAS-retry cap (config `mergeRetries`) —
|
|
941
|
+
// threaded so the `do spec:` tasking-transition's land tail respects the
|
|
942
|
+
// same per-repo cap the build path uses (task
|
|
943
|
+
// `thread-merge-retries-cross-task-and-ratify-default`).
|
|
944
|
+
mergeRetries: options.mergeRetries,
|
|
744
945
|
// The per-repo TASK-PLACEMENT default + the operator's explicit
|
|
745
946
|
// override (task `runner-deterministic-slice-placement-policy-and-
|
|
746
947
|
// precedence`). The tasker reads them as the configured-default + the
|
|
747
948
|
// top rung of the runner-deterministic placement resolver; the
|
|
748
949
|
// `originTrust: untrusted` force is read inside the tasker from the
|
|
749
|
-
//
|
|
950
|
+
// spec's stamped frontmatter.
|
|
750
951
|
tasksLandIn: options.tasksLandIn,
|
|
751
952
|
explicitTasksLandIn: options.explicitTasksLandIn,
|
|
752
953
|
noPR: options.noPR,
|
|
753
954
|
providerInstance: options.providerInstance,
|
|
754
955
|
// The tasker review→edit→converge loop (slicer-review-edit-loop): improves the
|
|
755
956
|
// candidate tasks in place + routes the verdict through the needsAnswers /
|
|
756
|
-
// needs-attention sink. Threaded only on the `do
|
|
957
|
+
// needs-attention sink. Threaded only on the `do spec:` path; omitted ⇒ no loop.
|
|
757
958
|
reviewLoop: options.reviewLoop,
|
|
758
959
|
taskerLoopMax: options.taskerLoopMax,
|
|
759
960
|
reviewExecutions: options.reviewExecutions,
|
|
@@ -942,15 +1143,18 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
942
1143
|
// auto-resolved). Surface to needs-attention TREE-LESSLY via the SAME `#89`
|
|
943
1144
|
// mechanism `requeue` uses for the reverse direction — the rebase was
|
|
944
1145
|
// ABORTED, so the kept `work/<slug>` tip == the arbiter tip (already on the
|
|
945
|
-
// arbiter, after-commit, recoverable). The surface is purely the
|
|
946
|
-
// `
|
|
947
|
-
// worktree mutation) instead of running the agent — the §10
|
|
1146
|
+
// arbiter, after-commit, recoverable). The surface is purely the lock amend
|
|
1147
|
+
// to `state: stuck` with the reason (post lock-cutover — no folder move, no
|
|
1148
|
+
// branch push, no worktree mutation) instead of running the agent — the §10
|
|
1149
|
+
// path. The work
|
|
948
1150
|
// did NOT onboard; the runner owns the bounce.
|
|
949
1151
|
if (tree.continueRebaseConflict) {
|
|
950
1152
|
const reason =
|
|
951
1153
|
`continuing the kept ${tree.branch}: rebase onto the latest main ` +
|
|
952
|
-
'conflicted (aborted, never auto-resolved) —
|
|
953
|
-
'
|
|
1154
|
+
'conflicted (aborted, never auto-resolved) — run `requeue --reconcile` ' +
|
|
1155
|
+
'to non-destructively re-sync the mirror and retry the rebase (keeps ' +
|
|
1156
|
+
'the work). Last resort: `requeue --reset` DESTRUCTIVELY discards the ' +
|
|
1157
|
+
'branch and starts fresh.';
|
|
954
1158
|
const surfaced = await ledgerWrite.applyTreelessNeedsAttentionTransition({
|
|
955
1159
|
cwd: tree.dir,
|
|
956
1160
|
slug,
|
|
@@ -984,8 +1188,10 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
984
1188
|
const reason =
|
|
985
1189
|
`continuing the kept ${tree.branch}: publishing the rebased work branch ` +
|
|
986
1190
|
`to the arbiter failed terminally (${tree.continuePushFailure}) — the kept ` +
|
|
987
|
-
'branch is left intact on the arbiter (recoverable); `requeue`
|
|
988
|
-
'
|
|
1191
|
+
'branch is left intact on the arbiter (recoverable); `requeue --reconcile` ' +
|
|
1192
|
+
'to non-destructively re-sync the mirror and retry once the churn ' +
|
|
1193
|
+
'settles (keeps the work). Last resort: `requeue --reset` DESTRUCTIVELY ' +
|
|
1194
|
+
'discards the branch and starts fresh.';
|
|
989
1195
|
const surfaced = await ledgerWrite.applyTreelessNeedsAttentionTransition({
|
|
990
1196
|
cwd: tree.dir,
|
|
991
1197
|
slug,
|
|
@@ -1008,7 +1214,7 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
1008
1214
|
|
|
1009
1215
|
// 5. Run the agent autonomously in the checkout, ON the work branch — the
|
|
1010
1216
|
// SAME prompt assembly `dorfl prompt` emits (canonical wrapper +
|
|
1011
|
-
// source
|
|
1217
|
+
// source spec + the task's ## Prompt). The agent only edits code (it does
|
|
1012
1218
|
// no git). This is the one NEW middle step `ar-run.sh` shelled out for
|
|
1013
1219
|
// (`prompt | pi`).
|
|
1014
1220
|
// The post-claim pipeline reads the uniform `IsolatedTree` handle (`tree.dir`)
|
|
@@ -1047,7 +1253,7 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
1047
1253
|
content: readFileSync(task.path, 'utf8'),
|
|
1048
1254
|
env,
|
|
1049
1255
|
});
|
|
1050
|
-
// Per-item override layer: a task or
|
|
1256
|
+
// Per-item override layer: a task or spec may pin `promptGuidance.testFirst`
|
|
1051
1257
|
// in its frontmatter, superseding the resolved repo policy for THIS item.
|
|
1052
1258
|
const itemGuidance = resolvePromptGuidanceForItem({
|
|
1053
1259
|
cwd: tree.dir,
|
|
@@ -1074,7 +1280,12 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
1074
1280
|
throw err;
|
|
1075
1281
|
}
|
|
1076
1282
|
|
|
1077
|
-
let agent: {
|
|
1283
|
+
let agent: {
|
|
1284
|
+
ok: boolean;
|
|
1285
|
+
detail?: string;
|
|
1286
|
+
output?: string;
|
|
1287
|
+
timedOut?: boolean;
|
|
1288
|
+
};
|
|
1078
1289
|
try {
|
|
1079
1290
|
agent = await runDoAgent(options, tree.dir, prompt, slug);
|
|
1080
1291
|
} catch (err) {
|
|
@@ -1089,6 +1300,23 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
1089
1300
|
note,
|
|
1090
1301
|
});
|
|
1091
1302
|
}
|
|
1303
|
+
// DEADLINE CHECKPOINT (spec `graceful-pre-timeout-wip-checkpoint`): the
|
|
1304
|
+
// dorfl-internal deadline fired — stop is graceful, NOT a failure. Route
|
|
1305
|
+
// through the shared checkpoint path (save WIP + auto-continue on progress
|
|
1306
|
+
// under the ceiling, else surface). Distinct from `saveAgentFailure` on
|
|
1307
|
+
// purpose — the deadline path must NOT mark the item stuck when it
|
|
1308
|
+
// auto-continues.
|
|
1309
|
+
if (agent.timedOut) {
|
|
1310
|
+
return await routeDeadlineCheckpoint({
|
|
1311
|
+
slug,
|
|
1312
|
+
branch,
|
|
1313
|
+
cwd: tree.dir,
|
|
1314
|
+
arbiter: tree.arbiterRemote,
|
|
1315
|
+
maxAutoCheckpoints: options.maxAutoCheckpoints ?? 5,
|
|
1316
|
+
env,
|
|
1317
|
+
note,
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1092
1320
|
if (!agent.ok) {
|
|
1093
1321
|
const detail = agent.detail ?? `the agent failed to build '${slug}'.`;
|
|
1094
1322
|
return await saveAgentFailure({
|
|
@@ -1123,7 +1351,8 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
1123
1351
|
branch,
|
|
1124
1352
|
cwd: tree.dir,
|
|
1125
1353
|
arbiter: tree.arbiterRemote,
|
|
1126
|
-
reason: stopReason,
|
|
1354
|
+
reason: stopReason.reason,
|
|
1355
|
+
kind: stopReason.kind,
|
|
1127
1356
|
env,
|
|
1128
1357
|
note,
|
|
1129
1358
|
});
|
|
@@ -1175,7 +1404,7 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
1175
1404
|
verify: options.verify,
|
|
1176
1405
|
freshWorktreeGate: options.freshWorktreeGate,
|
|
1177
1406
|
// The cross-job merge-serialiser CAS-retry cap (config `mergeRetries`) — the
|
|
1178
|
-
// git-alone FLOOR of the cross-job land queue (
|
|
1407
|
+
// git-alone FLOOR of the cross-job land queue (spec `land-time-reverify-and-
|
|
1179
1408
|
// parallel-merge-ceiling` Story 5 / Applied Answer q1 (a)). Threaded so a
|
|
1180
1409
|
// wide-matrix CI's raised cap actually reaches the merge loop.
|
|
1181
1410
|
mergeRetries: options.mergeRetries,
|
|
@@ -1275,8 +1504,10 @@ export async function performDo(options: DoOptions): Promise<DoResult> {
|
|
|
1275
1504
|
// (`runRemotePipeline`) uses, so `advance task:<slug>` (via the default
|
|
1276
1505
|
// `doDriver = performDo`) agrees with the remote path on the caller-visible
|
|
1277
1506
|
// label.
|
|
1507
|
+
//
|
|
1508
|
+
// PR-2b D3: a clean surface (routedToNeedsAttention:true) is GREEN.
|
|
1278
1509
|
return {
|
|
1279
|
-
exitCode: 1,
|
|
1510
|
+
exitCode: completed.routedToNeedsAttention ? 0 : 1,
|
|
1280
1511
|
outcome: 'needs-attention',
|
|
1281
1512
|
slug,
|
|
1282
1513
|
branch,
|
|
@@ -1373,7 +1604,9 @@ function routeReport(
|
|
|
1373
1604
|
return {
|
|
1374
1605
|
fragment:
|
|
1375
1606
|
`push of ${branch} FAILED — the work is saved LOCALLY only; push it ` +
|
|
1376
|
-
'when online, then `requeue` (continue)
|
|
1607
|
+
'when online, then `requeue` (continue) or `requeue --reconcile` ' +
|
|
1608
|
+
'(non-destructive retry). Last resort: `requeue --reset` ' +
|
|
1609
|
+
'DESTRUCTIVELY discards.',
|
|
1377
1610
|
pushFailed: true,
|
|
1378
1611
|
};
|
|
1379
1612
|
}
|
|
@@ -1389,7 +1622,10 @@ function routeReport(
|
|
|
1389
1622
|
landed = 'saved locally';
|
|
1390
1623
|
}
|
|
1391
1624
|
return {
|
|
1392
|
-
fragment:
|
|
1625
|
+
fragment:
|
|
1626
|
+
`${landed}. Recover via \`requeue\` (continue) or \`requeue --reconcile\` ` +
|
|
1627
|
+
'(non-destructive retry). Last resort: `requeue --reset` ' +
|
|
1628
|
+
'DESTRUCTIVELY discards.',
|
|
1393
1629
|
pushFailed: false,
|
|
1394
1630
|
};
|
|
1395
1631
|
}
|
|
@@ -1403,10 +1639,12 @@ function routeReport(
|
|
|
1403
1639
|
*
|
|
1404
1640
|
* This routes it through the SAME work-preserving machinery a RED GATE uses: the
|
|
1405
1641
|
* ledger write seam's needs-attention transition (`git add -A` + a wip commit
|
|
1406
|
-
* capturing the agent's work
|
|
1407
|
-
* with the failure detail
|
|
1408
|
-
*
|
|
1409
|
-
*
|
|
1642
|
+
* capturing the agent's work, then — post lock-cutover — a LOCK AMEND to
|
|
1643
|
+
* `state: stuck` with the failure detail as the reason on the lock entry, in
|
|
1644
|
+
* place of the retired `git mv → needs-attention/` move-only commit), surfaced on
|
|
1645
|
+
* the arbiter's `main` (the autonomous, cross-machine-visible mode-M surfacing
|
|
1646
|
+
* `do` already uses for the gate-fail path) so `scan`/`status`/another machine
|
|
1647
|
+
* see it.
|
|
1410
1648
|
*
|
|
1411
1649
|
* It ALSO pushes the `work/<slug>` branch to the arbiter so the saved partial
|
|
1412
1650
|
* commits travel cross-machine and the item is RECOVERABLE via `requeue`
|
|
@@ -1429,7 +1667,8 @@ function routeReport(
|
|
|
1429
1667
|
* contract stays coherent). Only the WORK-PRESERVING side-effect (unchanged here)
|
|
1430
1668
|
* matches the gate-failure path. We do NOT validate or "fix" the partial work — a broken
|
|
1431
1669
|
* tree committed + surfaced (with the reason) is recoverable; the human chooses
|
|
1432
|
-
* `requeue` (continue)
|
|
1670
|
+
* `requeue` (continue) / `requeue --reconcile` (non-destructive retry) vs
|
|
1671
|
+
* `requeue --reset` (destructive last resort).
|
|
1433
1672
|
*/
|
|
1434
1673
|
async function saveAgentFailure(params: {
|
|
1435
1674
|
slug: string;
|
|
@@ -1477,8 +1716,10 @@ async function saveAgentFailure(params: {
|
|
|
1477
1716
|
: `Agent run failed building '${slug}' [${cause}] (${detail}); could not ` +
|
|
1478
1717
|
`mark '${slug}' stuck (${routed.reasonNotMoved ?? 'unknown'}).`;
|
|
1479
1718
|
note(message);
|
|
1719
|
+
// PR-2b D3: a cleanly-surfaced bounce is GREEN (exitCode 0); a FAILED surface
|
|
1720
|
+
// stays non-zero.
|
|
1480
1721
|
return {
|
|
1481
|
-
exitCode: 1,
|
|
1722
|
+
exitCode: routed.moved ? 0 : 1,
|
|
1482
1723
|
outcome: failureCauseToDoOutcome(cause),
|
|
1483
1724
|
slug,
|
|
1484
1725
|
branch,
|
|
@@ -1499,7 +1740,9 @@ function failureCauseToDoOutcome(cause: FailureCause): DoOutcome {
|
|
|
1499
1740
|
|
|
1500
1741
|
/**
|
|
1501
1742
|
* Build the HONEST result for a CONTINUE-site surface that did NOT land on the
|
|
1502
|
-
* arbiter (`{moved: false}`). The tree-less
|
|
1743
|
+
* arbiter (`{moved: false}`). The tree-less stuck-lock amend (post lock-cutover —
|
|
1744
|
+
* `state: stuck` with the reason, in place of the retired `in-progress/ →
|
|
1745
|
+
* needs-attention/` move)
|
|
1503
1746
|
* lost the CAS race against a busy arbiter (its contention-retry cap exhausted) or
|
|
1504
1747
|
* had no arbiter to publish to, so the item is STILL in-progress on the arbiter —
|
|
1505
1748
|
* a clean `needs-attention` would mislead (it claims the surface landed). Distinct
|
|
@@ -1544,14 +1787,14 @@ async function resolveStopReason(params: {
|
|
|
1544
1787
|
cwd: string;
|
|
1545
1788
|
arbiter: string;
|
|
1546
1789
|
env: NodeJS.ProcessEnv | undefined;
|
|
1547
|
-
}): Promise<
|
|
1790
|
+
}): Promise<AgentStopClass | undefined> {
|
|
1548
1791
|
const {output, slug, cwd, arbiter, env} = params;
|
|
1549
1792
|
const sentinel = parseStopSentinel(output);
|
|
1550
1793
|
if (sentinel !== undefined) {
|
|
1551
|
-
return sentinel.reason;
|
|
1794
|
+
return {kind: 'sentinel', reason: sentinel.reason};
|
|
1552
1795
|
}
|
|
1553
1796
|
if (await isWorkBranchDiffEmpty({cwd, arbiter, env})) {
|
|
1554
|
-
return emptyDiffStopReason(slug);
|
|
1797
|
+
return {kind: 'empty-diff', reason: emptyDiffStopReason(slug)};
|
|
1555
1798
|
}
|
|
1556
1799
|
return undefined;
|
|
1557
1800
|
}
|
|
@@ -1570,12 +1813,66 @@ async function saveAgentStop(params: {
|
|
|
1570
1813
|
cwd: string;
|
|
1571
1814
|
arbiter: string;
|
|
1572
1815
|
reason: string;
|
|
1816
|
+
kind: 'sentinel' | 'empty-diff';
|
|
1573
1817
|
env: NodeJS.ProcessEnv | undefined;
|
|
1574
1818
|
note: (message: string) => void;
|
|
1575
1819
|
}): Promise<DoResult> {
|
|
1576
|
-
const {slug, cwd, arbiter, reason, env, note} = params;
|
|
1820
|
+
const {slug, cwd, arbiter, reason, kind, env, note} = params;
|
|
1577
1821
|
const branch = params.branch ?? workBranchRef('task', slug);
|
|
1578
1822
|
|
|
1823
|
+
// EMPTY-DIFF branch (spec resolved decision #2, task
|
|
1824
|
+
// `empty-diff-bounce-surfaces-dispose-defaulted-question`): surface a sidecar
|
|
1825
|
+
// on `<arbiter>/main` carrying an engine-authored DISPOSE-DEFAULTED envelope
|
|
1826
|
+
// question, THEN release the lock. "Nothing to do" is a non-deterministic LLM
|
|
1827
|
+
// judgement, so this seam MUST NOT blindly requeue (that would infinite-loop);
|
|
1828
|
+
// the surfaced sidecar + `needsAnswers:true` on `main` parks the item as a
|
|
1829
|
+
// human-visible question a `dispose` answer settles to `tasks/cancelled/`.
|
|
1830
|
+
if (kind === 'empty-diff') {
|
|
1831
|
+
const item = `task:${slug}`;
|
|
1832
|
+
const itemPath = resolveItemPathByIdentity(cwd, item);
|
|
1833
|
+
if (itemPath === undefined) {
|
|
1834
|
+
const message =
|
|
1835
|
+
`The agent STOPPED building '${slug}' (empty diff) but its body could ` +
|
|
1836
|
+
`not be located on the arbiter to surface a sidecar. Reason: ${reason}`;
|
|
1837
|
+
note(message);
|
|
1838
|
+
return {
|
|
1839
|
+
exitCode: 1,
|
|
1840
|
+
outcome: 'agent-stopped',
|
|
1841
|
+
slug,
|
|
1842
|
+
branch,
|
|
1843
|
+
routedToNeedsAttention: false,
|
|
1844
|
+
message,
|
|
1845
|
+
};
|
|
1846
|
+
}
|
|
1847
|
+
const surfaced = await surfaceStuckToNeedsAttention({
|
|
1848
|
+
cwd,
|
|
1849
|
+
slug,
|
|
1850
|
+
item,
|
|
1851
|
+
itemPath,
|
|
1852
|
+
reason,
|
|
1853
|
+
envelope: emptyDiffDisposeEnvelope({item, reason}),
|
|
1854
|
+
arbiter,
|
|
1855
|
+
env,
|
|
1856
|
+
note,
|
|
1857
|
+
});
|
|
1858
|
+
const message = surfaced.surfaced
|
|
1859
|
+
? `The agent STOPPED building '${slug}' (empty diff); surfaced a ` +
|
|
1860
|
+
`dispose-defaulted question on ${arbiter}/main and released the lock. ` +
|
|
1861
|
+
`Reason: ${reason}`
|
|
1862
|
+
: `The agent STOPPED building '${slug}' (empty diff) but the surface ` +
|
|
1863
|
+
`did not land (${surfaced.reasonNotSurfaced ?? 'unknown'}). ` +
|
|
1864
|
+
`Reason: ${reason}`;
|
|
1865
|
+
note(message);
|
|
1866
|
+
return {
|
|
1867
|
+
exitCode: 1,
|
|
1868
|
+
outcome: 'agent-stopped',
|
|
1869
|
+
slug,
|
|
1870
|
+
branch,
|
|
1871
|
+
routedToNeedsAttention: surfaced.surfaced,
|
|
1872
|
+
message,
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1579
1876
|
const routed = await ledgerWrite.applyNeedsAttentionTransition({
|
|
1580
1877
|
cwd,
|
|
1581
1878
|
slug,
|
|
@@ -1593,8 +1890,11 @@ async function saveAgentStop(params: {
|
|
|
1593
1890
|
: `The agent STOPPED building '${slug}' but it could not be marked stuck ` +
|
|
1594
1891
|
`(${routed.reasonNotMoved ?? 'unknown'}). Reason: ${reason}`;
|
|
1595
1892
|
note(message);
|
|
1893
|
+
// PR-2b D3: agent-stopped (sentinel) on a clean surface is GREEN (exitCode 0);
|
|
1894
|
+
// a FAILED surface stays non-zero. The empty-diff branch above is UNCHANGED
|
|
1895
|
+
// (owned by `empty-diff-bounce-surfaces-dispose-defaulted-question`).
|
|
1596
1896
|
return {
|
|
1597
|
-
exitCode: 1,
|
|
1897
|
+
exitCode: routed.moved ? 0 : 1,
|
|
1598
1898
|
outcome: 'agent-stopped',
|
|
1599
1899
|
slug,
|
|
1600
1900
|
branch,
|
|
@@ -1626,11 +1926,26 @@ async function runDoAgent(
|
|
|
1626
1926
|
cwd: string,
|
|
1627
1927
|
prompt: string,
|
|
1628
1928
|
slug: string,
|
|
1629
|
-
): Promise<{
|
|
1929
|
+
): Promise<{
|
|
1930
|
+
ok: boolean;
|
|
1931
|
+
detail?: string;
|
|
1932
|
+
output?: string;
|
|
1933
|
+
timedOut?: boolean;
|
|
1934
|
+
}> {
|
|
1630
1935
|
if (options.dorfl) {
|
|
1631
1936
|
return options.dorfl({cwd, prompt, slug, env: options.env});
|
|
1632
1937
|
}
|
|
1633
1938
|
const harness = options.harness ?? new NullHarness();
|
|
1939
|
+
// Convert the dorfl-internal deadline (minutes) into a wall-clock epoch-ms so
|
|
1940
|
+
// the harness (`launchAsync`) can race the child against it (spec
|
|
1941
|
+
// `graceful-pre-timeout-wip-checkpoint`). Absent ⇒ no deadline; a run that
|
|
1942
|
+
// finishes before it is byte-for-byte unchanged (the harness clears the
|
|
1943
|
+
// timer on normal exit). Forcing the async path when a deadline is set is
|
|
1944
|
+
// {@link launchWithOptionalWatch}'s job.
|
|
1945
|
+
const deadlineMs =
|
|
1946
|
+
options.agentDeadlineMinutes !== undefined
|
|
1947
|
+
? Date.now() + options.agentDeadlineMinutes * 60_000
|
|
1948
|
+
: undefined;
|
|
1634
1949
|
const launched = await launchWithOptionalWatch({
|
|
1635
1950
|
harness,
|
|
1636
1951
|
dir: cwd,
|
|
@@ -1642,6 +1957,7 @@ async function runDoAgent(
|
|
|
1642
1957
|
sessionId: slug,
|
|
1643
1958
|
sessionsDir: options.sessionsDir,
|
|
1644
1959
|
watch: options.watch,
|
|
1960
|
+
deadlineMs,
|
|
1645
1961
|
watchSink: options.watchSink,
|
|
1646
1962
|
color: options.color,
|
|
1647
1963
|
env: options.env,
|
|
@@ -1649,7 +1965,134 @@ async function runDoAgent(
|
|
|
1649
1965
|
// Surface the agent's FINAL SUMMARY (`LaunchResult.output`) — the source channel
|
|
1650
1966
|
// for the propose-mode PR body — instead of dropping it. Absent (no parseable
|
|
1651
1967
|
// assistant text) ⇒ undefined ⇒ the body degrades to `--fill` (no regression).
|
|
1652
|
-
return {
|
|
1968
|
+
return {
|
|
1969
|
+
ok: launched.ok,
|
|
1970
|
+
detail: launched.detail,
|
|
1971
|
+
output: launched.output,
|
|
1972
|
+
timedOut: launched.timedOut,
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
/**
|
|
1977
|
+
* Route a DEADLINE STOP (spec `graceful-pre-timeout-wip-checkpoint`) through
|
|
1978
|
+
* the checkpoint machinery: ALWAYS save the WIP (commit + push), then
|
|
1979
|
+
* decide — progress AND under ceiling ⇒ AUTO-CONTINUE (release lock, keep
|
|
1980
|
+
* branch, NO sidecar, exit 0); else ⇒ SURFACE a `needsAnswers:true` question.
|
|
1981
|
+
* Shared by {@link performDo} and {@link runRemotePipeline} so the in-place
|
|
1982
|
+
* and remote forms route a deadline stop identically.
|
|
1983
|
+
*/
|
|
1984
|
+
async function routeDeadlineCheckpoint(params: {
|
|
1985
|
+
slug: string;
|
|
1986
|
+
branch: string;
|
|
1987
|
+
cwd: string;
|
|
1988
|
+
arbiter: string;
|
|
1989
|
+
maxAutoCheckpoints: number;
|
|
1990
|
+
env: NodeJS.ProcessEnv | undefined;
|
|
1991
|
+
note: (message: string) => void;
|
|
1992
|
+
}): Promise<DoResult> {
|
|
1993
|
+
const {slug, branch, cwd, arbiter, maxAutoCheckpoints, env, note} = params;
|
|
1994
|
+
|
|
1995
|
+
// 1. ALWAYS save the WIP first: commit any residue + push the work branch.
|
|
1996
|
+
const savedReason = `deadline checkpoint save for '${slug}'`;
|
|
1997
|
+
const saved = await saveDeadlineCheckpoint({
|
|
1998
|
+
slug,
|
|
1999
|
+
branch,
|
|
2000
|
+
cwd,
|
|
2001
|
+
arbiter,
|
|
2002
|
+
reason: savedReason,
|
|
2003
|
+
env,
|
|
2004
|
+
note,
|
|
2005
|
+
});
|
|
2006
|
+
void saved;
|
|
2007
|
+
|
|
2008
|
+
// 2. Progress this session? Reuse the SAME primitive the STOP backstop uses.
|
|
2009
|
+
const emptyDiff = await isWorkBranchDiffEmpty({cwd, arbiter, env});
|
|
2010
|
+
const madeProgressThisSession = !emptyDiff;
|
|
2011
|
+
|
|
2012
|
+
// 3. Count consecutive deadline checkpoints on the branch (ceiling gate). The
|
|
2013
|
+
// marker commit we just saved is included — so the count is the number
|
|
2014
|
+
// of checkpoints INCLUDING this one.
|
|
2015
|
+
const checkpointCount = await countDeadlineCheckpointsOnBranch({
|
|
2016
|
+
cwd,
|
|
2017
|
+
arbiter,
|
|
2018
|
+
branch,
|
|
2019
|
+
env,
|
|
2020
|
+
});
|
|
2021
|
+
|
|
2022
|
+
if (madeProgressThisSession && checkpointCount <= maxAutoCheckpoints) {
|
|
2023
|
+
// AUTO-CONTINUE: release the lock via the SAME default keep+continue path
|
|
2024
|
+
// `requeue` uses (no --reset, no --reconcile, no sidecar). The branch is
|
|
2025
|
+
// KEPT on the arbiter so the next claim continues from its tip.
|
|
2026
|
+
const reason = deadlineAutoContinueReason({
|
|
2027
|
+
slug,
|
|
2028
|
+
count: checkpointCount,
|
|
2029
|
+
max: maxAutoCheckpoints,
|
|
2030
|
+
});
|
|
2031
|
+
const returned = await ledgerWrite.applyReturnToBacklogTransition({
|
|
2032
|
+
cwd,
|
|
2033
|
+
slug,
|
|
2034
|
+
arbiter,
|
|
2035
|
+
env,
|
|
2036
|
+
note,
|
|
2037
|
+
});
|
|
2038
|
+
if (returned.moved) {
|
|
2039
|
+
const message =
|
|
2040
|
+
`Auto-continued '${slug}' at the dorfl-internal deadline (checkpoint ` +
|
|
2041
|
+
`${checkpointCount}/${maxAutoCheckpoints}): WIP saved + branch pushed, ` +
|
|
2042
|
+
`lock released so the next tick continues from ${branch}. ${reason}`;
|
|
2043
|
+
note(message);
|
|
2044
|
+
return {
|
|
2045
|
+
exitCode: 0,
|
|
2046
|
+
outcome: 'deadline-auto-continued',
|
|
2047
|
+
slug,
|
|
2048
|
+
branch,
|
|
2049
|
+
message,
|
|
2050
|
+
};
|
|
2051
|
+
}
|
|
2052
|
+
// The auto-continue lock release did not land — fall through to SURFACE.
|
|
2053
|
+
note(
|
|
2054
|
+
`Auto-continue lock release for '${slug}' did not land ` +
|
|
2055
|
+
`(${returned.reasonNotMoved ?? 'unknown'}); surfacing instead.`,
|
|
2056
|
+
);
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
// SURFACE: mark the lock stuck via the whole applyNeedsAttentionTransition
|
|
2060
|
+
// (save + push + stuck). The WIP was already saved above; a second save is
|
|
2061
|
+
// idempotent (empty commit is skipped inside routeToNeedsAttention).
|
|
2062
|
+
const surfaceReason = madeProgressThisSession
|
|
2063
|
+
? deadlineSurfaceReason({
|
|
2064
|
+
slug,
|
|
2065
|
+
kind: 'ceiling',
|
|
2066
|
+
count: checkpointCount,
|
|
2067
|
+
max: maxAutoCheckpoints,
|
|
2068
|
+
})
|
|
2069
|
+
: deadlineSurfaceReason({slug, kind: 'no-progress'});
|
|
2070
|
+
const routed = await ledgerWrite.applyNeedsAttentionTransition({
|
|
2071
|
+
cwd,
|
|
2072
|
+
slug,
|
|
2073
|
+
reason: surfaceReason,
|
|
2074
|
+
arbiter,
|
|
2075
|
+
env,
|
|
2076
|
+
note,
|
|
2077
|
+
});
|
|
2078
|
+
const report = routed.moved ? routeReport(routed, branch) : undefined;
|
|
2079
|
+
const message = routed.moved
|
|
2080
|
+
? `Surfaced '${slug}' at the deadline checkpoint (${
|
|
2081
|
+
madeProgressThisSession
|
|
2082
|
+
? `ceiling ${checkpointCount}/${maxAutoCheckpoints}`
|
|
2083
|
+
: 'no progress this session'
|
|
2084
|
+
}); ${report!.fragment}. ${surfaceReason}`
|
|
2085
|
+
: `Could not surface '${slug}' at the deadline checkpoint ` +
|
|
2086
|
+
`(${routed.reasonNotMoved ?? 'unknown'}). ${surfaceReason}`;
|
|
2087
|
+
note(message);
|
|
2088
|
+
return {
|
|
2089
|
+
exitCode: 1,
|
|
2090
|
+
outcome: 'deadline-surfaced',
|
|
2091
|
+
slug,
|
|
2092
|
+
branch,
|
|
2093
|
+
routedToNeedsAttention: routed.moved,
|
|
2094
|
+
message,
|
|
2095
|
+
};
|
|
1653
2096
|
}
|
|
1654
2097
|
|
|
1655
2098
|
/**
|
|
@@ -1875,7 +2318,7 @@ export async function performDoRemote(
|
|
|
1875
2318
|
try {
|
|
1876
2319
|
// 2a. Resolve the slug across BOTH namespaces against the claim clone (it
|
|
1877
2320
|
// carries `work/` from the mirror's main). A collision / resolution
|
|
1878
|
-
// failure is a loud usage error; a `
|
|
2321
|
+
// failure is a loud usage error; a `spec:` arg reaches the not-yet-wired
|
|
1879
2322
|
// stub — identical behaviour to in-place `do`.
|
|
1880
2323
|
let resolved;
|
|
1881
2324
|
try {
|
|
@@ -1905,9 +2348,9 @@ export async function performDoRemote(
|
|
|
1905
2348
|
arbiter: 'origin',
|
|
1906
2349
|
doer: 'agent',
|
|
1907
2350
|
autoTask: options.autoTask,
|
|
1908
|
-
// EXPLICIT dispatch (same as the in-place path above): the `
|
|
2351
|
+
// EXPLICIT dispatch (same as the in-place path above): the `spec:<slug>` was
|
|
1909
2352
|
// NAMED (typed, or pool-filtered on `autoTask` before reaching here), so the
|
|
1910
|
-
// tasking gate drops the policy term — only the
|
|
2353
|
+
// tasking gate drops the policy term — only the spec's own readiness +
|
|
1911
2354
|
// `taskedAfter` bind, mirroring the build path vs `autoBuild`.
|
|
1912
2355
|
explicit: true,
|
|
1913
2356
|
dorfl: options.dorfl,
|
|
@@ -1919,22 +2362,26 @@ export async function performDoRemote(
|
|
|
1919
2362
|
// `provider` is the SAME the task-build path threads (arg parity), but the
|
|
1920
2363
|
// MODE is the per-TRANSITION TASKING resolution
|
|
1921
2364
|
// (`per-transition-integration-mode-slicing-vs-build`):
|
|
1922
|
-
// `taskingIntegration ?? integration`, so the `--remote
|
|
2365
|
+
// `taskingIntegration ?? integration`, so the `--remote spec:` output ALSO
|
|
1923
2366
|
// routes through the shared core with the tasking-resolved mode.
|
|
1924
2367
|
integration: options.taskingIntegration ?? options.integration,
|
|
2368
|
+
// The cross-job merge-serialiser CAS-retry cap (config `mergeRetries`) —
|
|
2369
|
+
// threaded on the no-checkout `do --remote spec:` tasking path too,
|
|
2370
|
+
// mirroring the in-place site above.
|
|
2371
|
+
mergeRetries: options.mergeRetries,
|
|
1925
2372
|
// The per-repo TASK-PLACEMENT default + the operator's explicit
|
|
1926
2373
|
// override (task `runner-deterministic-slice-placement-policy-and-
|
|
1927
|
-
// precedence`). Same threading as the in-place `do
|
|
2374
|
+
// precedence`). Same threading as the in-place `do spec:` path.
|
|
1928
2375
|
tasksLandIn: options.tasksLandIn,
|
|
1929
2376
|
explicitTasksLandIn: options.explicitTasksLandIn,
|
|
1930
2377
|
noPR: options.noPR,
|
|
1931
2378
|
providerInstance: options.providerInstance,
|
|
1932
|
-
// The tasker review→edit→converge loop on the `do --remote
|
|
2379
|
+
// The tasker review→edit→converge loop on the `do --remote spec:` path too.
|
|
1933
2380
|
reviewLoop: options.reviewLoop,
|
|
1934
2381
|
taskerLoopMax: options.taskerLoopMax,
|
|
1935
2382
|
reviewExecutions: options.reviewExecutions,
|
|
1936
2383
|
taskerLoopModel: options.taskerLoopModel,
|
|
1937
|
-
// The task-SET ACCEPTANCE GATE on the `do --remote
|
|
2384
|
+
// The task-SET ACCEPTANCE GATE on the `do --remote spec:` path too.
|
|
1938
2385
|
review: options.review,
|
|
1939
2386
|
reviewGate: options.taskReviewGate,
|
|
1940
2387
|
acceptanceReviewModel: options.reviewModel,
|
|
@@ -2094,8 +2541,10 @@ async function runRemotePipeline(
|
|
|
2094
2541
|
if (tree.continueRebaseConflict) {
|
|
2095
2542
|
const reason =
|
|
2096
2543
|
`continuing the kept ${tree.branch}: rebase onto the latest main ` +
|
|
2097
|
-
'conflicted (aborted, never auto-resolved) —
|
|
2098
|
-
'
|
|
2544
|
+
'conflicted (aborted, never auto-resolved) — run `requeue --reconcile` ' +
|
|
2545
|
+
'to non-destructively re-sync the mirror and retry the rebase (keeps ' +
|
|
2546
|
+
'the work). Last resort: `requeue --reset` DESTRUCTIVELY discards the ' +
|
|
2547
|
+
'branch and starts fresh.';
|
|
2099
2548
|
await ledgerWrite.applyNeedsAttentionTransition({
|
|
2100
2549
|
cwd,
|
|
2101
2550
|
slug,
|
|
@@ -2127,8 +2576,10 @@ async function runRemotePipeline(
|
|
|
2127
2576
|
const reason =
|
|
2128
2577
|
`continuing the kept ${tree.branch}: publishing the rebased work branch ` +
|
|
2129
2578
|
`to the arbiter failed terminally (${tree.continuePushFailure}) — the kept ` +
|
|
2130
|
-
'branch is left intact on the arbiter (recoverable); `requeue`
|
|
2131
|
-
'
|
|
2579
|
+
'branch is left intact on the arbiter (recoverable); `requeue --reconcile` ' +
|
|
2580
|
+
'to non-destructively re-sync the mirror and retry once the churn ' +
|
|
2581
|
+
'settles (keeps the work). Last resort: `requeue --reset` DESTRUCTIVELY ' +
|
|
2582
|
+
'discards the branch and starts fresh.';
|
|
2132
2583
|
await ledgerWrite.applyNeedsAttentionTransition({
|
|
2133
2584
|
cwd,
|
|
2134
2585
|
slug,
|
|
@@ -2238,7 +2689,7 @@ async function runRemotePipeline(
|
|
|
2238
2689
|
content: readFileSync(task.path, 'utf8'),
|
|
2239
2690
|
env,
|
|
2240
2691
|
});
|
|
2241
|
-
// Per-item override layer (mirrors in-place `do`): the task/
|
|
2692
|
+
// Per-item override layer (mirrors in-place `do`): the task/spec frontmatter
|
|
2242
2693
|
// may override the resolved repo `promptGuidance.testFirst` for THIS item.
|
|
2243
2694
|
const itemGuidance = resolvePromptGuidanceForItem({
|
|
2244
2695
|
cwd,
|
|
@@ -2265,7 +2716,12 @@ async function runRemotePipeline(
|
|
|
2265
2716
|
throw err;
|
|
2266
2717
|
}
|
|
2267
2718
|
|
|
2268
|
-
let agent: {
|
|
2719
|
+
let agent: {
|
|
2720
|
+
ok: boolean;
|
|
2721
|
+
detail?: string;
|
|
2722
|
+
output?: string;
|
|
2723
|
+
timedOut?: boolean;
|
|
2724
|
+
};
|
|
2269
2725
|
try {
|
|
2270
2726
|
agent = await runDoAgent(options, cwd, prompt, slug);
|
|
2271
2727
|
} catch (err) {
|
|
@@ -2280,6 +2736,19 @@ async function runRemotePipeline(
|
|
|
2280
2736
|
note,
|
|
2281
2737
|
});
|
|
2282
2738
|
}
|
|
2739
|
+
// Deadline checkpoint on the no-checkout `do --remote` path — same routing
|
|
2740
|
+
// as the in-place path (see performDo).
|
|
2741
|
+
if (agent.timedOut) {
|
|
2742
|
+
return await routeDeadlineCheckpoint({
|
|
2743
|
+
slug,
|
|
2744
|
+
branch: branch ?? workBranchRef('task', slug),
|
|
2745
|
+
cwd,
|
|
2746
|
+
arbiter: arbiterRemote,
|
|
2747
|
+
maxAutoCheckpoints: options.maxAutoCheckpoints ?? 5,
|
|
2748
|
+
env,
|
|
2749
|
+
note,
|
|
2750
|
+
});
|
|
2751
|
+
}
|
|
2283
2752
|
if (!agent.ok) {
|
|
2284
2753
|
const detail = agent.detail ?? `the agent failed to build '${slug}'.`;
|
|
2285
2754
|
return await saveRemoteAgentFailure({
|
|
@@ -2311,7 +2780,8 @@ async function runRemotePipeline(
|
|
|
2311
2780
|
branch,
|
|
2312
2781
|
cwd,
|
|
2313
2782
|
arbiter: arbiterRemote,
|
|
2314
|
-
reason: stopReason,
|
|
2783
|
+
reason: stopReason.reason,
|
|
2784
|
+
kind: stopReason.kind,
|
|
2315
2785
|
env,
|
|
2316
2786
|
note,
|
|
2317
2787
|
});
|
|
@@ -2500,8 +2970,9 @@ async function saveRemoteAgentFailure(params: {
|
|
|
2500
2970
|
: `Agent run failed building '${slug}' [${cause}] (${detail}); could not ` +
|
|
2501
2971
|
`mark '${slug}' stuck (${routed.reasonNotMoved ?? 'unknown'}).`;
|
|
2502
2972
|
note(message);
|
|
2973
|
+
// PR-2b D3: cleanly-surfaced remote agent failure is GREEN.
|
|
2503
2974
|
return {
|
|
2504
|
-
exitCode: 1,
|
|
2975
|
+
exitCode: routed.moved ? 0 : 1,
|
|
2505
2976
|
outcome: failureCauseToDoOutcome(cause),
|
|
2506
2977
|
slug,
|
|
2507
2978
|
branch,
|
|
@@ -2568,7 +3039,7 @@ async function primeWorktreeTrackingRef(
|
|
|
2568
3039
|
* identity) ride VERBATIM from the threaded `DoOptions` onto the structurally-
|
|
2569
3040
|
* matching {@link DoRemoteOptions} fields; `cwd` is DROPPED (the worktree replaces
|
|
2570
3041
|
* it) and `remote` + `workspacesDir` are supplied from this driver's closure (the
|
|
2571
|
-
* mirror's arbiter URL + the agents' execution area). A `
|
|
3042
|
+
* mirror's arbiter URL + the agents' execution area). A `spec:` arg flows through
|
|
2572
3043
|
* unchanged — `performDoRemote` tasks it against the claim clone with NO build
|
|
2573
3044
|
* worktree (the tasking/surface/triage/apply rungs are tree-less ledger moves, the
|
|
2574
3045
|
* substrate the task's criterion 4 preserves).
|
|
@@ -2613,6 +3084,8 @@ export function jobWorktreeDoDriver(closure: {
|
|
|
2613
3084
|
watch: options.watch,
|
|
2614
3085
|
watchSink: options.watchSink,
|
|
2615
3086
|
color: options.color,
|
|
3087
|
+
agentDeadlineMinutes: options.agentDeadlineMinutes,
|
|
3088
|
+
maxAutoCheckpoints: options.maxAutoCheckpoints,
|
|
2616
3089
|
read: options.read,
|
|
2617
3090
|
env: options.env,
|
|
2618
3091
|
note: options.note,
|