dorfl 0.14.2 → 0.15.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 +17 -16
- package/dist/advance-ci-template.d.ts.map +1 -1
- package/dist/advance-ci-template.js +42 -53
- package/dist/advance-ci-template.js.map +1 -1
- package/dist/advance-drivers.d.ts +8 -0
- package/dist/advance-drivers.d.ts.map +1 -1
- package/dist/advance-drivers.js +28 -4
- package/dist/advance-drivers.js.map +1 -1
- package/dist/advance-isolated.d.ts.map +1 -1
- package/dist/advance-isolated.js +3 -2
- package/dist/advance-isolated.js.map +1 -1
- package/dist/advance-lifecycle-template.d.ts +41 -40
- package/dist/advance-lifecycle-template.d.ts.map +1 -1
- package/dist/advance-lifecycle-template.js +309 -489
- package/dist/advance-lifecycle-template.js.map +1 -1
- package/dist/advance-loop-driver.d.ts.map +1 -1
- package/dist/advance-loop-driver.js +3 -2
- package/dist/advance-loop-driver.js.map +1 -1
- package/dist/advance-treeless-publish.d.ts +31 -0
- package/dist/advance-treeless-publish.d.ts.map +1 -1
- package/dist/advance-treeless-publish.js +40 -0
- package/dist/advance-treeless-publish.js.map +1 -1
- package/dist/advance.d.ts +63 -3
- package/dist/advance.d.ts.map +1 -1
- package/dist/advance.js +80 -12
- package/dist/advance.js.map +1 -1
- package/dist/advancing-lock.d.ts +9 -0
- package/dist/advancing-lock.d.ts.map +1 -1
- package/dist/advancing-lock.js +21 -1
- package/dist/advancing-lock.js.map +1 -1
- package/dist/agent-env.d.ts +61 -0
- package/dist/agent-env.d.ts.map +1 -0
- package/dist/agent-env.js +144 -0
- package/dist/agent-env.js.map +1 -0
- package/dist/agent-stop.d.ts +35 -0
- package/dist/agent-stop.d.ts.map +1 -1
- package/dist/agent-stop.js +62 -0
- package/dist/agent-stop.js.map +1 -1
- package/dist/apply-merge-action.d.ts +76 -34
- package/dist/apply-merge-action.d.ts.map +1 -1
- package/dist/apply-merge-action.js +339 -129
- package/dist/apply-merge-action.js.map +1 -1
- package/dist/apply-stuck-action.js +2 -2
- package/dist/apply-stuck-action.js.map +1 -1
- package/dist/ci-agent-result.d.ts +151 -0
- package/dist/ci-agent-result.d.ts.map +1 -0
- package/dist/ci-agent-result.js +314 -0
- package/dist/ci-agent-result.js.map +1 -0
- package/dist/ci-handoff-apply.d.ts +162 -0
- package/dist/ci-handoff-apply.d.ts.map +1 -0
- package/dist/ci-handoff-apply.js +497 -0
- package/dist/ci-handoff-apply.js.map +1 -0
- package/dist/ci-handoff-format.d.ts +369 -0
- package/dist/ci-handoff-format.d.ts.map +1 -0
- package/dist/ci-handoff-format.js +646 -0
- package/dist/ci-handoff-format.js.map +1 -0
- package/dist/ci-handoff-lfs.d.ts +146 -0
- package/dist/ci-handoff-lfs.d.ts.map +1 -0
- package/dist/ci-handoff-lfs.js +397 -0
- package/dist/ci-handoff-lfs.js.map +1 -0
- package/dist/ci-handoff.d.ts +99 -0
- package/dist/ci-handoff.d.ts.map +1 -0
- package/dist/ci-handoff.js +277 -0
- package/dist/ci-handoff.js.map +1 -0
- package/dist/ci-lock-outputs.d.ts +93 -0
- package/dist/ci-lock-outputs.d.ts.map +1 -0
- package/dist/ci-lock-outputs.js +223 -0
- package/dist/ci-lock-outputs.js.map +1 -0
- package/dist/ci-phase-build.d.ts +178 -0
- package/dist/ci-phase-build.d.ts.map +1 -0
- package/dist/ci-phase-build.js +989 -0
- package/dist/ci-phase-build.js.map +1 -0
- package/dist/ci-phase-driver.d.ts +247 -0
- package/dist/ci-phase-driver.d.ts.map +1 -0
- package/dist/ci-phase-driver.js +370 -0
- package/dist/ci-phase-driver.js.map +1 -0
- package/dist/ci-phase-intake.d.ts +172 -0
- package/dist/ci-phase-intake.d.ts.map +1 -0
- package/dist/ci-phase-intake.js +555 -0
- package/dist/ci-phase-intake.js.map +1 -0
- package/dist/ci-phase-tasking.d.ts +205 -0
- package/dist/ci-phase-tasking.d.ts.map +1 -0
- package/dist/ci-phase-tasking.js +906 -0
- package/dist/ci-phase-tasking.js.map +1 -0
- package/dist/ci-phase-treeless.d.ts +224 -0
- package/dist/ci-phase-treeless.d.ts.map +1 -0
- package/dist/ci-phase-treeless.js +1482 -0
- package/dist/ci-phase-treeless.js.map +1 -0
- package/dist/ci-read-token.d.ts +47 -0
- package/dist/ci-read-token.d.ts.map +1 -0
- package/dist/ci-read-token.js +80 -0
- package/dist/ci-read-token.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +447 -22
- package/dist/cli.js.map +1 -1
- package/dist/close-job-template.d.ts +10 -1
- package/dist/close-job-template.d.ts.map +1 -1
- package/dist/close-job-template.js +46 -14
- package/dist/close-job-template.js.map +1 -1
- package/dist/close-job.d.ts +20 -5
- package/dist/close-job.d.ts.map +1 -1
- package/dist/close-job.js +65 -12
- package/dist/close-job.js.map +1 -1
- package/dist/complete.d.ts.map +1 -1
- package/dist/complete.js +20 -1
- package/dist/complete.js.map +1 -1
- package/dist/config.d.ts +41 -44
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -4
- package/dist/config.js.map +1 -1
- package/dist/continue-branch.d.ts +63 -15
- package/dist/continue-branch.d.ts.map +1 -1
- package/dist/continue-branch.js +75 -8
- package/dist/continue-branch.js.map +1 -1
- package/dist/crashed-run-save.d.ts +73 -0
- package/dist/crashed-run-save.d.ts.map +1 -0
- package/dist/crashed-run-save.js +86 -0
- package/dist/crashed-run-save.js.map +1 -0
- package/dist/cwd-section.d.ts.map +1 -1
- package/dist/cwd-section.js +10 -2
- package/dist/cwd-section.js.map +1 -1
- package/dist/decision-engine.d.ts +10 -0
- package/dist/decision-engine.d.ts.map +1 -1
- package/dist/decision-engine.js.map +1 -1
- package/dist/do-config.d.ts +2 -24
- package/dist/do-config.d.ts.map +1 -1
- package/dist/do-config.js +1 -33
- package/dist/do-config.js.map +1 -1
- package/dist/do.d.ts +149 -1
- package/dist/do.d.ts.map +1 -1
- package/dist/do.js +115 -25
- package/dist/do.js.map +1 -1
- package/dist/dorfl-item-template.d.ts +98 -0
- package/dist/dorfl-item-template.d.ts.map +1 -0
- package/dist/dorfl-item-template.js +504 -0
- package/dist/dorfl-item-template.js.map +1 -0
- package/dist/env-config.d.ts.map +1 -1
- package/dist/env-config.js +7 -5
- package/dist/env-config.js.map +1 -1
- package/dist/frontmatter.d.ts +52 -0
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +136 -2
- package/dist/frontmatter.js.map +1 -1
- package/dist/gc.d.ts +13 -0
- package/dist/gc.d.ts.map +1 -1
- package/dist/gc.js +16 -2
- package/dist/gc.js.map +1 -1
- package/dist/git.d.ts +18 -1
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +70 -5
- package/dist/git.js.map +1 -1
- package/dist/harness.d.ts +44 -5
- package/dist/harness.d.ts.map +1 -1
- package/dist/harness.js +24 -1
- package/dist/harness.js.map +1 -1
- package/dist/index.d.ts +11 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/install-ci-action-pins.d.ts +123 -0
- package/dist/install-ci-action-pins.d.ts.map +1 -0
- package/dist/install-ci-action-pins.js +190 -0
- package/dist/install-ci-action-pins.js.map +1 -0
- package/dist/install-ci-actions-pr-creation.d.ts +70 -0
- package/dist/install-ci-actions-pr-creation.d.ts.map +1 -0
- package/dist/install-ci-actions-pr-creation.js +106 -0
- package/dist/install-ci-actions-pr-creation.js.map +1 -0
- package/dist/install-ci-capabilities/dorfl-item.d.ts +12 -0
- package/dist/install-ci-capabilities/dorfl-item.d.ts.map +1 -0
- package/dist/install-ci-capabilities/dorfl-item.js +26 -0
- package/dist/install-ci-capabilities/dorfl-item.js.map +1 -0
- package/dist/install-ci-core.d.ts +155 -37
- package/dist/install-ci-core.d.ts.map +1 -1
- package/dist/install-ci-core.js +304 -200
- package/dist/install-ci-core.js.map +1 -1
- package/dist/install-ci-github.d.ts +47 -2
- package/dist/install-ci-github.d.ts.map +1 -1
- package/dist/install-ci-github.js +113 -1
- package/dist/install-ci-github.js.map +1 -1
- package/dist/install-ci.d.ts +25 -6
- package/dist/install-ci.d.ts.map +1 -1
- package/dist/install-ci.js +72 -36
- package/dist/install-ci.js.map +1 -1
- package/dist/intake-marker.d.ts +6 -1
- package/dist/intake-marker.d.ts.map +1 -1
- package/dist/intake-marker.js.map +1 -1
- package/dist/intake-triage.d.ts.map +1 -1
- package/dist/intake-triage.js +6 -2
- package/dist/intake-triage.js.map +1 -1
- package/dist/intake-trigger-template.d.ts +31 -25
- package/dist/intake-trigger-template.d.ts.map +1 -1
- package/dist/intake-trigger-template.js +107 -292
- package/dist/intake-trigger-template.js.map +1 -1
- package/dist/intake.d.ts +186 -4
- package/dist/intake.d.ts.map +1 -1
- package/dist/intake.js +533 -416
- package/dist/intake.js.map +1 -1
- package/dist/integration-core.d.ts +154 -1
- package/dist/integration-core.d.ts.map +1 -1
- package/dist/integration-core.js +759 -486
- package/dist/integration-core.js.map +1 -1
- package/dist/integrator.d.ts +12 -0
- package/dist/integrator.d.ts.map +1 -1
- package/dist/integrator.js +21 -0
- package/dist/integrator.js.map +1 -1
- package/dist/isolation.d.ts +12 -2
- package/dist/isolation.d.ts.map +1 -1
- package/dist/isolation.js +19 -8
- package/dist/isolation.js.map +1 -1
- package/dist/item-lock.d.ts +93 -11
- package/dist/item-lock.d.ts.map +1 -1
- package/dist/item-lock.js +233 -65
- package/dist/item-lock.js.map +1 -1
- package/dist/land-question-residue.d.ts +58 -0
- package/dist/land-question-residue.d.ts.map +1 -0
- package/dist/land-question-residue.js +95 -0
- package/dist/land-question-residue.js.map +1 -0
- package/dist/lifecycle-gather.d.ts +16 -0
- package/dist/lifecycle-gather.d.ts.map +1 -1
- package/dist/lifecycle-gather.js +54 -6
- package/dist/lifecycle-gather.js.map +1 -1
- package/dist/merge-answer.d.ts +41 -0
- package/dist/merge-answer.d.ts.map +1 -0
- package/dist/merge-answer.js +60 -0
- package/dist/merge-answer.js.map +1 -0
- package/dist/merge-question-surfacer.d.ts +105 -30
- package/dist/merge-question-surfacer.d.ts.map +1 -1
- package/dist/merge-question-surfacer.js +202 -91
- package/dist/merge-question-surfacer.js.map +1 -1
- package/dist/merge-question-tick.d.ts +64 -0
- package/dist/merge-question-tick.d.ts.map +1 -0
- package/dist/merge-question-tick.js +96 -0
- package/dist/merge-question-tick.js.map +1 -0
- package/dist/mint-adr.d.ts.map +1 -1
- package/dist/mint-adr.js +20 -2
- package/dist/mint-adr.js.map +1 -1
- package/dist/needs-attention.d.ts +72 -2
- package/dist/needs-attention.d.ts.map +1 -1
- package/dist/needs-attention.js +275 -38
- package/dist/needs-attention.js.map +1 -1
- package/dist/phase-recorder.d.ts +168 -0
- package/dist/phase-recorder.d.ts.map +1 -0
- package/dist/phase-recorder.js +218 -0
- package/dist/phase-recorder.js.map +1 -0
- package/dist/phase.d.ts +94 -0
- package/dist/phase.d.ts.map +1 -0
- package/dist/phase.js +148 -0
- package/dist/phase.js.map +1 -0
- package/dist/pi-harness.d.ts.map +1 -1
- package/dist/pi-harness.js +19 -6
- package/dist/pi-harness.js.map +1 -1
- package/dist/prepare.d.ts.map +1 -1
- package/dist/prepare.js +4 -0
- package/dist/prepare.js.map +1 -1
- package/dist/prompt.d.ts +4 -0
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +48 -1
- package/dist/prompt.js.map +1 -1
- package/dist/protocol/CLAIM-PROTOCOL.md +3 -1
- package/dist/protocol/WORK-CONTRACT.md +1 -1
- package/dist/reap-branches.d.ts +48 -0
- package/dist/reap-branches.d.ts.map +1 -1
- package/dist/reap-branches.js +64 -0
- package/dist/reap-branches.js.map +1 -1
- package/dist/ref-write.d.ts +198 -0
- package/dist/ref-write.d.ts.map +1 -0
- package/dist/ref-write.js +79 -0
- package/dist/ref-write.js.map +1 -0
- package/dist/repo-config.js +8 -8
- package/dist/repo-config.js.map +1 -1
- package/dist/repo-mirror.d.ts +36 -0
- package/dist/repo-mirror.d.ts.map +1 -1
- package/dist/repo-mirror.js +91 -1
- package/dist/repo-mirror.js.map +1 -1
- package/dist/review-verdict.d.ts +1 -1
- package/dist/review-verdict.js +1 -1
- package/dist/run.d.ts +7 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +28 -4
- package/dist/run.js.map +1 -1
- package/dist/scan.d.ts +19 -1
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +21 -8
- package/dist/scan.js.map +1 -1
- package/dist/sidecar.d.ts +14 -0
- package/dist/sidecar.d.ts.map +1 -1
- package/dist/sidecar.js +21 -0
- package/dist/sidecar.js.map +1 -1
- package/dist/single-job-warning.d.ts +63 -0
- package/dist/single-job-warning.d.ts.map +1 -0
- package/dist/single-job-warning.js +110 -0
- package/dist/single-job-warning.js.map +1 -0
- package/dist/skills/setup/protocol/CLAIM-PROTOCOL.md +3 -1
- package/dist/skills/setup/protocol/WORK-CONTRACT.md +1 -1
- package/dist/spec-complete.d.ts +13 -6
- package/dist/spec-complete.d.ts.map +1 -1
- package/dist/spec-complete.js +23 -11
- package/dist/spec-complete.js.map +1 -1
- package/dist/start.d.ts.map +1 -1
- package/dist/start.js +47 -14
- package/dist/start.js.map +1 -1
- package/dist/status.d.ts +12 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +11 -3
- package/dist/status.js.map +1 -1
- package/dist/tasking.d.ts +246 -1
- package/dist/tasking.d.ts.map +1 -1
- package/dist/tasking.js +452 -358
- package/dist/tasking.js.map +1 -1
- package/dist/triage-persist.d.ts.map +1 -1
- package/dist/triage-persist.js +21 -2
- package/dist/triage-persist.js.map +1 -1
- package/dist/verify-workflow-template.d.ts.map +1 -1
- package/dist/verify-workflow-template.js +8 -4
- package/dist/verify-workflow-template.js.map +1 -1
- package/dist/verify.d.ts.map +1 -1
- package/dist/verify.js +4 -0
- package/dist/verify.js.map +1 -1
- package/dist/watch-session.d.ts +42 -13
- package/dist/watch-session.d.ts.map +1 -1
- package/dist/watch-session.js +52 -23
- package/dist/watch-session.js.map +1 -1
- package/dist/work-layout.d.ts +10 -4
- package/dist/work-layout.d.ts.map +1 -1
- package/dist/work-layout.js +11 -3
- package/dist/work-layout.js.map +1 -1
- package/dist/workspace.d.ts +65 -4
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +159 -11
- package/dist/workspace.js.map +1 -1
- package/package.json +1 -1
- package/src/advance-ci-template.ts +80 -81
- package/src/advance-drivers.ts +45 -6
- package/src/advance-isolated.ts +3 -5
- package/src/advance-lifecycle-template.ts +375 -538
- package/src/advance-loop-driver.ts +3 -5
- package/src/advance-treeless-publish.ts +61 -0
- package/src/advance.ts +145 -15
- package/src/advancing-lock.ts +36 -1
- package/src/agent-env.ts +174 -0
- package/src/agent-stop.ts +81 -0
- package/src/apply-merge-action.ts +401 -154
- package/src/apply-stuck-action.ts +2 -2
- package/src/ci-agent-result.ts +421 -0
- package/src/ci-handoff-apply.ts +737 -0
- package/src/ci-handoff-format.ts +926 -0
- package/src/ci-handoff-lfs.ts +519 -0
- package/src/ci-handoff.ts +392 -0
- package/src/ci-lock-outputs.ts +273 -0
- package/src/ci-phase-build.ts +1328 -0
- package/src/ci-phase-driver.ts +548 -0
- package/src/ci-phase-intake.ts +861 -0
- package/src/ci-phase-tasking.ts +1255 -0
- package/src/ci-phase-treeless.ts +2028 -0
- package/src/ci-read-token.ts +90 -0
- package/src/cli.ts +591 -29
- package/src/close-job-template.ts +52 -15
- package/src/close-job.ts +77 -12
- package/src/complete.ts +19 -1
- package/src/config.ts +43 -48
- package/src/continue-branch.ts +121 -16
- package/src/crashed-run-save.ts +162 -0
- package/src/cwd-section.ts +10 -0
- package/src/decision-engine.ts +10 -0
- package/src/do-config.ts +2 -57
- package/src/do.ts +170 -28
- package/src/dorfl-item-template.ts +556 -0
- package/src/env-config.ts +7 -5
- package/src/frontmatter.ts +155 -2
- package/src/gc.ts +27 -2
- package/src/git.ts +83 -5
- package/src/harness.ts +58 -6
- package/src/index.ts +50 -1
- package/src/install-ci-action-pins.ts +209 -0
- package/src/install-ci-actions-pr-creation.ts +186 -0
- package/src/install-ci-capabilities/dorfl-item.ts +33 -0
- package/src/install-ci-core.ts +388 -233
- package/src/install-ci-github.ts +149 -1
- package/src/install-ci.ts +83 -37
- package/src/intake-marker.ts +6 -1
- package/src/intake-triage.ts +7 -3
- package/src/intake-trigger-template.ts +126 -327
- package/src/intake.ts +725 -544
- package/src/integration-core.ts +975 -523
- package/src/integrator.ts +28 -0
- package/src/isolation.ts +29 -10
- package/src/item-lock.ts +308 -92
- package/src/land-question-residue.ts +122 -0
- package/src/lifecycle-gather.ts +82 -10
- package/src/merge-answer.ts +82 -0
- package/src/merge-question-surfacer.ts +320 -112
- package/src/merge-question-tick.ts +182 -0
- package/src/mint-adr.ts +28 -2
- package/src/needs-attention.ts +350 -42
- package/src/phase-recorder.ts +350 -0
- package/src/phase.ts +177 -0
- package/src/pi-harness.ts +25 -5
- package/src/prepare.ts +4 -0
- package/src/prompt.ts +68 -1
- package/src/reap-branches.ts +107 -0
- package/src/ref-write.ts +324 -0
- package/src/repo-config.ts +8 -8
- package/src/repo-mirror.ts +107 -1
- package/src/review-verdict.ts +1 -1
- package/src/run.ts +47 -6
- package/src/scan.ts +37 -7
- package/src/sidecar.ts +36 -0
- package/src/single-job-warning.ts +135 -0
- package/src/spec-complete.ts +36 -14
- package/src/start.ts +55 -16
- package/src/status.ts +29 -3
- package/src/tasking.ts +593 -378
- package/src/triage-persist.ts +24 -2
- package/src/verify-workflow-template.ts +8 -4
- package/src/verify.ts +4 -0
- package/src/watch-session.ts +86 -28
- package/src/work-layout.ts +11 -3
- package/src/workspace.ts +210 -14
package/dist/needs-attention.js
CHANGED
|
@@ -3,7 +3,7 @@ import { tmpdir } from 'node:os';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { workFolderPrefix, workFolderRel, workItemRel, isWorkItemFile, } from './work-layout.js';
|
|
5
5
|
import { run, runAsync } from './git.js';
|
|
6
|
-
import { branchAheadOf, rebaseContinuedBranchOntoMain, } from './continue-branch.js';
|
|
6
|
+
import { branchAheadOf, rebaseContinuedBranchOntoMain, describeContinueRebaseFailure, } from './continue-branch.js';
|
|
7
7
|
import { acquireItemLock, releaseItemLock, readItemLock, itemLockRef, lockEntryFor, refreshMainRef, parseLockEntry, } from './item-lock.js';
|
|
8
8
|
import { ledgerWrite } from './ledger-write.js';
|
|
9
9
|
import { workBranchRef } from './slug-namespace.js';
|
|
@@ -11,6 +11,7 @@ import { refreshArbiterRefs, resolveArbiterBranch } from './arbiter-refs.js';
|
|
|
11
11
|
import { appendQuestions, isEntryAnswered, newSidecar, parseSidecar, resolveSidecarIdentity, serialiseSidecar, sidecarPathFor, sidecarPathCandidates, } from './sidecar.js';
|
|
12
12
|
import { parseFrontmatter, setNeedsAnswersMarker } from './frontmatter.js';
|
|
13
13
|
import { retryWithBackoff, realSleep, } from './retry-backoff.js';
|
|
14
|
+
import { saveCrashedRunWork, } from './crashed-run-save.js';
|
|
14
15
|
/**
|
|
15
16
|
* The **needs-attention mechanism** (ADR `ledger-status-on-per-item-lock-refs`;
|
|
16
17
|
* spec `ledger-status-per-item-lock-refs`; ADR §12 for the original folder model).
|
|
@@ -91,18 +92,7 @@ export async function routeToNeedsAttention(options) {
|
|
|
91
92
|
// tip. Skip when the tree is clean (no aborted work to save). NOTE this no
|
|
92
93
|
// longer needs a folder source — the body rests in `backlog/` (task 9a) and
|
|
93
94
|
// never moves on a bounce.
|
|
94
|
-
|
|
95
|
-
const hadWip = !nothingStaged(cwd, env);
|
|
96
|
-
if (hadWip) {
|
|
97
|
-
// Save the agent's uncommitted work as a plain wip commit on the work-branch
|
|
98
|
-
// tip (the RECOVERABLE half — a `requeue` continues from it). No bookkeeping
|
|
99
|
-
// trailer: after the per-item-lock cut-over (tasks 9a–9d) NO transient status
|
|
100
|
-
// (no `needs-attention/` move-only commit) lands on a branch, so a branch cut
|
|
101
|
-
// from `main` rebases PLAINLY with nothing to drop — the `drop-bookkeeping-rebase`
|
|
102
|
-
// machinery and its `Dorfl-Bookkeeping` trailer are gone (9d).
|
|
103
|
-
const wipBody = `chore(${slug}): save aborted work (wip)`;
|
|
104
|
-
gitHard(['commit', '-q', '-m', wipBody], cwd, env);
|
|
105
|
-
}
|
|
95
|
+
const hadWip = commitAbortedWork({ cwd, slug, env });
|
|
106
96
|
const commitMessage = `chore(${slug}): bounce to stuck; ${options.reason}`;
|
|
107
97
|
const moveCommit = hadWip ? revParseHead(cwd, env) : undefined;
|
|
108
98
|
note(`Bounced '${slug}' to stuck (lock): ${options.reason}`);
|
|
@@ -123,6 +113,9 @@ export async function routeToNeedsAttention(options) {
|
|
|
123
113
|
if (branchAheadOf(cwd, branch, 'main', env)) {
|
|
124
114
|
const arbiter = options.arbiter;
|
|
125
115
|
const result = await retryWithBackoff(async () => {
|
|
116
|
+
// Write-seam implementation: `routeToNeedsAttention` is reached only
|
|
117
|
+
// through `ledgerWrite.applyNeedsAttentionTransition` or
|
|
118
|
+
// `refWrite.saveWorkBranch` (guard: `write-sites-through-seams.test.ts`).
|
|
126
119
|
const r = gitSoftRun(['push', arbiter, `${branch}:${branch}`], cwd, env);
|
|
127
120
|
return r.status === 0
|
|
128
121
|
? { ok: true, value: undefined }
|
|
@@ -147,6 +140,31 @@ export async function routeToNeedsAttention(options) {
|
|
|
147
140
|
}
|
|
148
141
|
return { moved: true, commitMessage, moveCommit, branchPush, pushError };
|
|
149
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* The LOCAL half of {@link routeToNeedsAttention}'s save: commit whatever the
|
|
145
|
+
* agent left uncommitted (`git add -A`) as a plain wip commit on the current
|
|
146
|
+
* branch tip. Returns whether a commit was made (a clean tree makes none).
|
|
147
|
+
*
|
|
148
|
+
* No bookkeeping trailer: after the per-item-lock cut-over (tasks 9a–9d) NO
|
|
149
|
+
* transient status (no `needs-attention/` move-only commit) lands on a branch,
|
|
150
|
+
* so a branch cut from `main` rebases PLAINLY with nothing to drop: the
|
|
151
|
+
* `drop-bookkeeping-rebase` machinery and its `Dorfl-Bookkeeping` trailer are
|
|
152
|
+
* gone (9d).
|
|
153
|
+
*
|
|
154
|
+
* The CI agent phase (task `ci-split-build-path-non-integrate-intents`) runs
|
|
155
|
+
* this on its own when its pipeline halts at a needs-attention bounce, so the
|
|
156
|
+
* wip travels in the handoff bundle; the apply phase then re-runs the whole
|
|
157
|
+
* route on the bundle's tip, where this finds a clean tree and commits nothing.
|
|
158
|
+
*/
|
|
159
|
+
export function commitAbortedWork(params) {
|
|
160
|
+
const { cwd, slug, env } = params;
|
|
161
|
+
gitHard(['add', '-A'], cwd, env);
|
|
162
|
+
if (nothingStaged(cwd, env)) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
gitHard(['commit', '-q', '-m', `chore(${slug}): save aborted work (wip)`], cwd, env);
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
150
168
|
/**
|
|
151
169
|
* The clean re-queue (ADR §12 / WORK-CONTRACT return path): once the human has
|
|
152
170
|
* resolved the cause, move the stuck item back to `work/tasks/ready/<slug>.md` and
|
|
@@ -185,9 +203,10 @@ export async function routeToNeedsAttention(options) {
|
|
|
185
203
|
* closes the claim-race window; a FAILED delete ABORTS (no backlog move)
|
|
186
204
|
* so the item stays in needs-attention. The next claim then finds NO
|
|
187
205
|
* arbiter branch and cuts fresh — no special claim-time logic.
|
|
188
|
-
* - **`-m "<note>"` = HANDOFF NOTE.** When `message` is set,
|
|
189
|
-
* `## Requeue YYYY-MM-DD` section to the item BODY
|
|
190
|
-
*
|
|
206
|
+
* - **`-m "<note>"` = HANDOFF NOTE.** When `message` is set, ADD a dated
|
|
207
|
+
* `## Requeue YYYY-MM-DD` section to the item BODY, just before
|
|
208
|
+
* `## Acceptance criteria` (additive; accumulates over repeated requeues,
|
|
209
|
+
* oldest first) for the next agent. Applies to BOTH modes.
|
|
191
210
|
*
|
|
192
211
|
* Like the move, NEVER throws for the expected "not in needs-attention" case.
|
|
193
212
|
*/
|
|
@@ -233,6 +252,10 @@ export async function deleteRemoteWorkBranchIfPresent(options) {
|
|
|
233
252
|
const branch = workBranchRef('task', slug);
|
|
234
253
|
await gitSoftAsync(['update-ref', '-d', `refs/remotes/${arbiter}/${branch}`], cwd, env);
|
|
235
254
|
await gitSoftAsync(['branch', '-D', branch], cwd, env);
|
|
255
|
+
// Write-seam implementation: callers reach this through
|
|
256
|
+
// `refWrite.deleteRemoteWorkBranch`, or through `returnToBacklog` behind
|
|
257
|
+
// `ledgerWrite.applyReturnToBacklogTransition` (guard:
|
|
258
|
+
// `write-sites-through-seams.test.ts`).
|
|
236
259
|
const del = await gitSoftAsync(['push', arbiter, '--delete', branch], cwd, env);
|
|
237
260
|
if (del.status === 0) {
|
|
238
261
|
return { branch, status: 'deleted', stderr: '' };
|
|
@@ -270,6 +293,17 @@ export async function returnToBacklog(options) {
|
|
|
270
293
|
reasonNotMoved: `no git remote named '${arbiter}' (set one, or pass --arbiter).`,
|
|
271
294
|
};
|
|
272
295
|
}
|
|
296
|
+
// Destructive vs non-destructive are exclusive verbs on the same escalation.
|
|
297
|
+
// Checked up front (before any lock is read or taken) so the refusal is the
|
|
298
|
+
// same whether the item's lock is held or already released by a surface.
|
|
299
|
+
if (options.reconcile && options.reset) {
|
|
300
|
+
return {
|
|
301
|
+
moved: false,
|
|
302
|
+
reasonNotMoved: `requeue for '${slug}': --reconcile and --reset are mutually ` +
|
|
303
|
+
'exclusive (non-destructive recovery vs destructive last resort). ' +
|
|
304
|
+
'Pick one.',
|
|
305
|
+
};
|
|
306
|
+
}
|
|
273
307
|
// Refresh the remote-tracking refs so every check below (the item's residence,
|
|
274
308
|
// the continue-branch guard, the CAS base) sees the arbiter's TRUTH, not a stale
|
|
275
309
|
// local copy. This is a fetch, not a checkout — the working tree is untouched.
|
|
@@ -310,7 +344,53 @@ export async function returnToBacklog(options) {
|
|
|
310
344
|
catch {
|
|
311
345
|
held = await readLocalItemLock(slug, cwd, env);
|
|
312
346
|
}
|
|
347
|
+
// RELEASED-LOCK RECOVERY (task
|
|
348
|
+
// `requeue-reset-and-reconcile-work-after-the-lock-was-released`). A surface
|
|
349
|
+
// (`surfaceStuckToNeedsAttention`) RELEASES the per-item lock after landing the
|
|
350
|
+
// question sidecar, so a surfaced item with a KEPT work branch has no held lock,
|
|
351
|
+
// yet it is exactly what `--reconcile` (re-sync + retry) and `--reset` (discard,
|
|
352
|
+
// start fresh) exist for. When the item's body rests in the pool/staging on
|
|
353
|
+
// `<arbiter>/main` AND its `work/task-<slug>` branch is on the arbiter, take a
|
|
354
|
+
// SHORT per-item lock (create-only, like claim) so no claim can continue from
|
|
355
|
+
// the branch while it is being rebased or deleted, run the ordinary held-lock
|
|
356
|
+
// path, and give the short lock back on every outcome. Plain `requeue` stays a
|
|
357
|
+
// no-op (the next claim already continues from the kept branch).
|
|
358
|
+
let shortLock = false;
|
|
359
|
+
let releasedRecoverable;
|
|
313
360
|
if (!held) {
|
|
361
|
+
releasedRecoverable = await probeReleasedRecoverableItem({
|
|
362
|
+
cwd,
|
|
363
|
+
slug,
|
|
364
|
+
arbiter,
|
|
365
|
+
branch: continueBranchName,
|
|
366
|
+
env,
|
|
367
|
+
});
|
|
368
|
+
if (releasedRecoverable !== undefined &&
|
|
369
|
+
(options.reset || options.reconcile)) {
|
|
370
|
+
const verb = options.reset ? '--reset' : '--reconcile';
|
|
371
|
+
const acquired = await acquireItemLock({
|
|
372
|
+
item: `task:${slug}`,
|
|
373
|
+
action: 'implement',
|
|
374
|
+
cwd,
|
|
375
|
+
arbiter,
|
|
376
|
+
env,
|
|
377
|
+
});
|
|
378
|
+
if (acquired.outcome !== 'acquired') {
|
|
379
|
+
const message = `requeue ${verb} for '${slug}': its lock was already released, ` +
|
|
380
|
+
'but the short lock this recovery needs could not be taken ' +
|
|
381
|
+
(acquired.outcome === 'lost'
|
|
382
|
+
? '(another run claimed the item meanwhile); nothing was changed.'
|
|
383
|
+
: `(${acquired.message}); nothing was changed. Try again shortly.`);
|
|
384
|
+
note(message);
|
|
385
|
+
return { moved: false, reasonNotMoved: message };
|
|
386
|
+
}
|
|
387
|
+
shortLock = true;
|
|
388
|
+
note(`'${slug}' has no held lock (a surface or earlier requeue already ` +
|
|
389
|
+
`released it); took a short lock to ${options.reset ? 'discard' : 'reconcile'} ` +
|
|
390
|
+
`the kept ${continueBranchName} (${verb}).`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (!held && !shortLock) {
|
|
314
394
|
// CROSS-NAMESPACE HINT (observation
|
|
315
395
|
// `crashed-do-spec-strands-a-tasking-lock-no-verb-releases`). `requeue` is a
|
|
316
396
|
// TASK-only verb, so a bare `<slug>` resolves to `task:<slug>` and finds no
|
|
@@ -351,15 +431,139 @@ export async function returnToBacklog(options) {
|
|
|
351
431
|
catch {
|
|
352
432
|
// Best-effort hint only: fall through to the plain refusal.
|
|
353
433
|
}
|
|
434
|
+
// A released item that DOES rest in the pool with a kept branch (plain
|
|
435
|
+
// requeue only; `--reset`/`--reconcile` took the short-lock path above):
|
|
436
|
+
// nothing to release, and the next claim already continues from the branch.
|
|
437
|
+
// Say so, and name the two verbs that DO act on a released item.
|
|
438
|
+
const keptHint = releasedRecoverable !== undefined
|
|
439
|
+
? ` NOTE: '${slug}' rests in the pool (${releasedRecoverable.bodyRel}) ` +
|
|
440
|
+
`with a kept work branch ${continueBranchName} on ${arbiter}; the ` +
|
|
441
|
+
'next claim continues from it, so plain requeue has nothing to do. ' +
|
|
442
|
+
'To act on the kept branch: `requeue --reconcile` (non-destructive ' +
|
|
443
|
+
're-sync + rebase retry) or `requeue --reset` (DESTRUCTIVELY discard ' +
|
|
444
|
+
'it and start fresh).'
|
|
445
|
+
: '';
|
|
354
446
|
return {
|
|
355
447
|
moved: false,
|
|
356
448
|
reasonNotMoved: `'${slug}' has no held per-item lock on ${arbiter} — nothing to requeue ` +
|
|
357
449
|
'(wrong slug, or already at rest in backlog/done?). requeue recovers a ' +
|
|
358
450
|
'task whose lock is held stuck (needs-attention) or active (a killed ' +
|
|
359
451
|
'in-progress run).' +
|
|
360
|
-
specHint
|
|
452
|
+
specHint +
|
|
453
|
+
keptHint,
|
|
361
454
|
};
|
|
362
455
|
}
|
|
456
|
+
// CRASHED-RUN SAVE (task
|
|
457
|
+
// `a-crashed-runs-local-work-is-saved-before-its-lock-is-released`). A run
|
|
458
|
+
// killed mid-agent leaves its lock held and its job worktree retained, possibly
|
|
459
|
+
// with commits (or a wip residue) the arbiter's work branch lacks. Releasing
|
|
460
|
+
// the lock over them hands the item to a next claim (or a `gc --force`) that
|
|
461
|
+
// cuts that worktree away, so SAVE them first: wip-commit + push the work
|
|
462
|
+
// branch. A failed save KEEPS the lock (and the worktree) and says so. Only on
|
|
463
|
+
// a HELD lock (a short recovery lock means the run already surfaced, its lock
|
|
464
|
+
// released) and never on `--reset` (which discards the branch by design).
|
|
465
|
+
let crashedRunSave;
|
|
466
|
+
if (held && !options.reset && options.workspacesDir !== undefined) {
|
|
467
|
+
crashedRunSave = await saveCrashedRunWork({
|
|
468
|
+
cwd,
|
|
469
|
+
arbiter,
|
|
470
|
+
slug,
|
|
471
|
+
workspacesDir: options.workspacesDir,
|
|
472
|
+
env,
|
|
473
|
+
note,
|
|
474
|
+
...(options.sleep !== undefined ? { sleep: options.sleep } : {}),
|
|
475
|
+
});
|
|
476
|
+
if (crashedRunSave.kind === 'not-saved') {
|
|
477
|
+
const message = `requeue for '${slug}': its crashed run left work in ` +
|
|
478
|
+
`${crashedRunSave.dir} that the arbiter's ${crashedRunSave.branch} ` +
|
|
479
|
+
`lacks, and it could not be saved: ${crashedRunSave.detail}. The lock ` +
|
|
480
|
+
'is KEPT (not released) and the worktree left in place, so nothing is ' +
|
|
481
|
+
`lost. Push ${crashedRunSave.branch} from that worktree by hand, then ` +
|
|
482
|
+
'`requeue` again.';
|
|
483
|
+
note(message);
|
|
484
|
+
return { moved: false, reasonNotMoved: message, crashedRunSave };
|
|
485
|
+
}
|
|
486
|
+
if (crashedRunSave.kind === 'saved') {
|
|
487
|
+
// The guard below reads the arbiter's branch from THIS clone: bring the
|
|
488
|
+
// just-pushed tip (and its objects) in.
|
|
489
|
+
await refreshArbiterRefs({
|
|
490
|
+
cwd,
|
|
491
|
+
arbiter,
|
|
492
|
+
branches: ['main', continueBranchName],
|
|
493
|
+
env,
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
const heldResult = await requeueHeldItem({
|
|
498
|
+
options,
|
|
499
|
+
arbiter,
|
|
500
|
+
continueBranchName,
|
|
501
|
+
note,
|
|
502
|
+
});
|
|
503
|
+
const result = crashedRunSave !== undefined ? { ...heldResult, crashedRunSave } : heldResult;
|
|
504
|
+
if (shortLock && !result.moved) {
|
|
505
|
+
// Give the SHORT lock back: the item returns to exactly the released,
|
|
506
|
+
// surfaced state it was in (its question sidecar untouched). A failed
|
|
507
|
+
// release here is reported, never thrown.
|
|
508
|
+
const back = await releaseItemLock({
|
|
509
|
+
item: `task:${slug}`,
|
|
510
|
+
cwd,
|
|
511
|
+
arbiter,
|
|
512
|
+
env,
|
|
513
|
+
});
|
|
514
|
+
const tail = back.outcome === 'error'
|
|
515
|
+
? ` WARNING: could not release the short recovery lock this requeue ` +
|
|
516
|
+
`took (${back.message}); clear it with \`dorfl release-lock ` +
|
|
517
|
+
`task:${slug}\`.`
|
|
518
|
+
: ' (The short recovery lock this requeue took was released again; ' +
|
|
519
|
+
'the item stays as it was before this requeue.)';
|
|
520
|
+
note(tail.trim());
|
|
521
|
+
return { ...result, reasonNotMoved: (result.reasonNotMoved ?? '') + tail };
|
|
522
|
+
}
|
|
523
|
+
return result;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Is `<slug>` a RELEASED-lock task that `requeue --reset`/`--reconcile` can act
|
|
527
|
+
* on? True iff its body rests in `tasks/ready/` or `tasks/backlog/` on
|
|
528
|
+
* `<arbiter>/main` (the D1 probe a surface uses) AND the arbiter HAS its
|
|
529
|
+
* `work/task-<slug>` branch (arbiter-authoritative `ls-remote`). A surfaced item
|
|
530
|
+
* (question sidecar + `needsAnswers:true`, lock released) is the motivating
|
|
531
|
+
* case, but the sidecar is NOT required: a plain requeue that already released
|
|
532
|
+
* the lock leaves the same recoverable shape. An unknown slug (no body) or a
|
|
533
|
+
* pooled item with no kept branch answers `undefined`, so the refusal for those
|
|
534
|
+
* is unchanged. Best-effort: an unreachable arbiter answers `undefined`.
|
|
535
|
+
*/
|
|
536
|
+
async function probeReleasedRecoverableItem(params) {
|
|
537
|
+
const { cwd, slug, arbiter, branch, env } = params;
|
|
538
|
+
try {
|
|
539
|
+
const bodyRel = await resolveBounceItemBodyPathOnMain({
|
|
540
|
+
cwd,
|
|
541
|
+
item: `task:${slug}`,
|
|
542
|
+
arbiter,
|
|
543
|
+
env,
|
|
544
|
+
});
|
|
545
|
+
if (bodyRel === undefined) {
|
|
546
|
+
return undefined;
|
|
547
|
+
}
|
|
548
|
+
const resolved = await resolveArbiterBranch({ cwd, arbiter, branch, env });
|
|
549
|
+
if (!resolved.trustworthy || resolved.sha === undefined) {
|
|
550
|
+
return undefined;
|
|
551
|
+
}
|
|
552
|
+
return { bodyRel, branchSha: resolved.sha };
|
|
553
|
+
}
|
|
554
|
+
catch {
|
|
555
|
+
return undefined;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* The body of {@link returnToBacklog} once the item's per-item lock is HELD
|
|
560
|
+
* (either a pre-existing stuck/active hold, or the short lock a released-lock
|
|
561
|
+
* `--reset`/`--reconcile` just took): the reconcile / reset / keep+continue
|
|
562
|
+
* guard, the optional handoff note, and the lock release.
|
|
563
|
+
*/
|
|
564
|
+
async function requeueHeldItem(params) {
|
|
565
|
+
const { options, arbiter, continueBranchName, note } = params;
|
|
566
|
+
const { cwd, slug, env } = options;
|
|
363
567
|
// `--reconcile`: the NON-DESTRUCTIVE recovery rung (task
|
|
364
568
|
// `requeue-reconcile-nondestructive-recovery-verb`, parent observation
|
|
365
569
|
// `rebase-conflict-on-continue-needs-nondestructive-recovery-not-reset`).
|
|
@@ -377,14 +581,6 @@ export async function returnToBacklog(options) {
|
|
|
377
581
|
// deletes the remote branch — this verb's contract is "keep the work".
|
|
378
582
|
let reconciled;
|
|
379
583
|
if (options.reconcile) {
|
|
380
|
-
if (options.reset) {
|
|
381
|
-
return {
|
|
382
|
-
moved: false,
|
|
383
|
-
reasonNotMoved: `requeue for '${slug}': --reconcile and --reset are mutually ` +
|
|
384
|
-
'exclusive (non-destructive recovery vs destructive last resort). ' +
|
|
385
|
-
'Pick one.',
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
584
|
const attempt = await attemptReconcile({
|
|
389
585
|
cwd,
|
|
390
586
|
slug,
|
|
@@ -396,7 +592,9 @@ export async function returnToBacklog(options) {
|
|
|
396
592
|
const branch = workBranchRef('task', slug);
|
|
397
593
|
const message = `requeue --reconcile for '${slug}': re-synced the ${arbiter} mirror ` +
|
|
398
594
|
`and RETRIED the rebase of ${branch} onto latest ${arbiter}/main, but ` +
|
|
399
|
-
|
|
595
|
+
(attempt.genuineConflict === false
|
|
596
|
+
? `the rebase still fails (${attempt.detail}). The `
|
|
597
|
+
: `the rebase still conflicts on genuine content (${attempt.detail}). The `) +
|
|
400
598
|
'kept branch is left UNTOUCHED on the arbiter (nothing deleted) and the ' +
|
|
401
599
|
'item is left stuck. A supported mirror-side "resolve against latest ' +
|
|
402
600
|
'main" command that fetches the kept branch into a scratch worktree, ' +
|
|
@@ -532,8 +730,9 @@ export async function returnToBacklog(options) {
|
|
|
532
730
|
'tasks-ready',
|
|
533
731
|
'tasks-backlog',
|
|
534
732
|
];
|
|
535
|
-
// `-m "<note>"` (the handoff steer):
|
|
536
|
-
// section
|
|
733
|
+
// `-m "<note>"` (the handoff steer): ADD a dated `## Requeue YYYY-MM-DD`
|
|
734
|
+
// section (before `## Acceptance criteria`, clear of a kept branch's done-move
|
|
735
|
+
// tail) to the item BODY where it already rests (pool or staging), via the SAME
|
|
537
736
|
// tree-less CAS move (same-folder rewrite with the body transform) — it NEVER
|
|
538
737
|
// stages/commits in the cwd tree. The handoff is OPTIONAL and NON-FATAL: a failed
|
|
539
738
|
// append degrades to a WARNING and the lock release below STILL runs, because the
|
|
@@ -564,7 +763,7 @@ export async function returnToBacklog(options) {
|
|
|
564
763
|
base,
|
|
565
764
|
sourceRel: bodyRel,
|
|
566
765
|
destRel: bodyRel,
|
|
567
|
-
transformBody: (body) =>
|
|
766
|
+
transformBody: (body) => insertRequeueNoteText(body, handoff),
|
|
568
767
|
commitMessage: `chore(${slug}): requeue handoff note`,
|
|
569
768
|
refNamespace: 'requeue',
|
|
570
769
|
env,
|
|
@@ -663,12 +862,20 @@ async function attemptReconcile(params) {
|
|
|
663
862
|
}
|
|
664
863
|
try {
|
|
665
864
|
const rebase = rebaseContinuedBranchOntoMain(worktree, arbMainRef, env);
|
|
666
|
-
if (rebase.kind
|
|
667
|
-
return {
|
|
865
|
+
if (rebase.kind !== 'clean') {
|
|
866
|
+
return {
|
|
867
|
+
kind: 'conflict',
|
|
868
|
+
detail: `rebase after re-sync ${describeContinueRebaseFailure(rebase)}`,
|
|
869
|
+
genuineConflict: rebase.kind === 'conflict',
|
|
870
|
+
};
|
|
668
871
|
}
|
|
669
872
|
// 4. Push the reconciled tip back (`--force-with-lease`, WORK branch only).
|
|
670
873
|
const observedTip = gitSoftRun(['rev-parse', '--verify', '--quiet', `${arbBranchRef}^{commit}`], cwd, env).stdout.trim();
|
|
671
874
|
const lease = observedTip === '' ? `${branch}:` : `${branch}:${observedTip}`;
|
|
875
|
+
// WRITE-SEAM EXEMPT: `attemptReconcile` backs the human-only
|
|
876
|
+
// `requeue --reconcile` verb, never a CI path, so this reconciled
|
|
877
|
+
// kept-branch push stays direct (task
|
|
878
|
+
// `ci-split-route-direct-writes-through-seams`).
|
|
672
879
|
const push = gitSoftRun([
|
|
673
880
|
'push',
|
|
674
881
|
arbiter,
|
|
@@ -2055,20 +2262,50 @@ const BOUNCE_BODY_PROBE_ORDER = {
|
|
|
2055
2262
|
spec: ['specs-ready', 'specs-proposed'],
|
|
2056
2263
|
observation: ['observations'],
|
|
2057
2264
|
};
|
|
2265
|
+
/** The body headings a requeue handoff note is inserted BEFORE, in preference
|
|
2266
|
+
* order (see {@link insertRequeueNoteText}). `## Prompt` is the fallback anchor:
|
|
2267
|
+
* every BUILDABLE task has one (`resolveTask` refuses a body without it), so a
|
|
2268
|
+
* buildable body never falls through to the tail. */
|
|
2269
|
+
const REQUEUE_NOTE_ANCHORS = [
|
|
2270
|
+
/^##\s+Acceptance criteria\s*$/m,
|
|
2271
|
+
/^##\s+Prompt\s*$/m,
|
|
2272
|
+
];
|
|
2058
2273
|
/**
|
|
2059
|
-
*
|
|
2060
|
-
* (
|
|
2061
|
-
* Body prose only (never a frontmatter field — WORK-CONTRACT
|
|
2062
|
-
* UTC `YYYY-MM-DD`; multiple notes on the same day are
|
|
2274
|
+
* Add a dated `## Requeue YYYY-MM-DD` handoff section to an item body's TEXT
|
|
2275
|
+
* (additive — never overwrites; repeated requeues accumulate a handoff log,
|
|
2276
|
+
* oldest first). Body prose only (never a frontmatter field — WORK-CONTRACT
|
|
2277
|
+
* rule 3). The date is UTC `YYYY-MM-DD`; multiple notes on the same day are
|
|
2278
|
+
* distinct blocks.
|
|
2279
|
+
*
|
|
2280
|
+
* PLACEMENT (task `requeue-handoff-note-does-not-conflict-with-the-kept-done-move`):
|
|
2281
|
+
* the section is inserted immediately BEFORE the `## Acceptance criteria`
|
|
2282
|
+
* heading, NOT at the end of the body. A kept work branch the next claim
|
|
2283
|
+
* CONTINUES from may already have done-moved this body AND appended its
|
|
2284
|
+
* `## Decisions` block at the END; a tail-appended note on `main` then collided
|
|
2285
|
+
* with that tail in the continue rebase (which never auto-resolves, ADR §10) and
|
|
2286
|
+
* bounced the item. Mid-body, the two edits are disjoint hunks and the rebase
|
|
2287
|
+
* merges them cleanly. A body with no `## Acceptance criteria` heading anchors on
|
|
2288
|
+
* `## Prompt` instead (a chore task written without acceptance criteria used to
|
|
2289
|
+
* fall back to the tail and still collide); only a body with NEITHER heading
|
|
2290
|
+
* (which is not buildable anyway) falls back to the end. The continue prompt reads every `## Requeue`
|
|
2291
|
+
* section wherever it sits (`extractRequeueNotes`), so the note still reaches
|
|
2292
|
+
* the continuing agent.
|
|
2063
2293
|
*
|
|
2064
2294
|
* A PURE string transform (it operates on the body CONTENT, not a file path) so
|
|
2065
2295
|
* the tree-less requeue can apply it to the blob read from `<arbiter>/main`
|
|
2066
2296
|
* without touching the cwd working tree.
|
|
2067
2297
|
*/
|
|
2068
|
-
function
|
|
2298
|
+
export function insertRequeueNoteText(content, message) {
|
|
2069
2299
|
const date = new Date().toISOString().slice(0, 10);
|
|
2070
|
-
const
|
|
2071
|
-
|
|
2300
|
+
const section = `${REQUEUE_HEADING_PREFIX} ${date}\n\n${message}\n`;
|
|
2301
|
+
const anchor = REQUEUE_NOTE_ANCHORS.map((re) => re.exec(content)).find((m) => m !== null);
|
|
2302
|
+
if (anchor === undefined || anchor === null) {
|
|
2303
|
+
const base = content.replace(/\s*$/, '');
|
|
2304
|
+
return `${base}\n\n${section}`;
|
|
2305
|
+
}
|
|
2306
|
+
const before = content.slice(0, anchor.index).replace(/\s*$/, '');
|
|
2307
|
+
const after = content.slice(anchor.index);
|
|
2308
|
+
return `${before}\n\n${section}\n${after}`;
|
|
2072
2309
|
}
|
|
2073
2310
|
/**
|
|
2074
2311
|
* Extract the prose written under the `## Needs attention` heading from an item
|