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/src/prompt.ts
CHANGED
|
@@ -242,6 +242,8 @@ export function wrapper(
|
|
|
242
242
|
protocolPath?: string;
|
|
243
243
|
cwd?: string;
|
|
244
244
|
promptGuidance?: {testFirst?: boolean};
|
|
245
|
+
/** The folder the body was resolved from; see {@link retargetBodyFolder}. */
|
|
246
|
+
taskFolder?: TaskFolder;
|
|
245
247
|
} = {},
|
|
246
248
|
): string {
|
|
247
249
|
const protocolPath = resolveProtocolDoc(
|
|
@@ -251,10 +253,72 @@ export function wrapper(
|
|
|
251
253
|
);
|
|
252
254
|
const protocol = readFileSync(protocolPath, 'utf8');
|
|
253
255
|
const template = extractCanonicalWrapperTemplate(protocol);
|
|
254
|
-
const resolved =
|
|
256
|
+
const resolved = retargetSpecFolder(
|
|
257
|
+
retargetBodyFolder(
|
|
258
|
+
applyPromptGuidance(template, options.promptGuidance),
|
|
259
|
+
options.taskFolder,
|
|
260
|
+
),
|
|
261
|
+
spec,
|
|
262
|
+
options.cwd,
|
|
263
|
+
);
|
|
255
264
|
return resolved.replace(/<slug>/g, slug).replace(/<spec>/g, spec ?? '<spec>');
|
|
256
265
|
}
|
|
257
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Point the wrapper's source-spec mention at the folder the spec ACTUALLY rests
|
|
269
|
+
* in. The canonical wrapper assumes `work/specs/ready/<spec>.md`, but once a spec
|
|
270
|
+
* has been tasked it rests in `work/specs/tasked/`, so builds of its tasks were
|
|
271
|
+
* told to read a file that does not exist. Located with {@link findSpecPath} (the
|
|
272
|
+
* same ready-then-tasked lookup the per-item prompt-guidance layer uses). No
|
|
273
|
+
* `cwd`, no spec, or a spec in `specs/ready/` (or nowhere) leaves the text as is.
|
|
274
|
+
*/
|
|
275
|
+
function retargetSpecFolder(
|
|
276
|
+
template: string,
|
|
277
|
+
spec: string | undefined,
|
|
278
|
+
cwd: string | undefined,
|
|
279
|
+
): string {
|
|
280
|
+
if (spec === undefined || cwd === undefined) {
|
|
281
|
+
return template;
|
|
282
|
+
}
|
|
283
|
+
const found = findSpecPath(cwd, spec);
|
|
284
|
+
if (found === undefined || found === workItemPath(cwd, 'specs-ready', spec)) {
|
|
285
|
+
return template;
|
|
286
|
+
}
|
|
287
|
+
return template
|
|
288
|
+
.split(`${workFolderRel('specs-ready')}/<spec>.md`)
|
|
289
|
+
.join(`${workFolderRel('specs-tasked')}/<spec>.md`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Point the wrapper's body-path mentions at the folder the body was ACTUALLY
|
|
294
|
+
* resolved from. The canonical wrapper (CLAIM-PROTOCOL.md) describes the normal
|
|
295
|
+
* case, a claim from the pool, so it names `work/tasks/ready/<slug>.md`. Under
|
|
296
|
+
* `do --allow-backlog` the body rests in `work/tasks/backlog/` (and a stranded
|
|
297
|
+
* continue resolves it from `work/tasks/done/`), and telling the agent the wrong
|
|
298
|
+
* path made build agents file observations about it.
|
|
299
|
+
*
|
|
300
|
+
* A TEXT rewrite of the extracted template, not a new placeholder: a target repo's
|
|
301
|
+
* adopted `work/protocol/CLAIM-PROTOCOL.md` may predate any placeholder, and the
|
|
302
|
+
* rewrite still works on it. Pool bodies (`tasks-ready`) and an omitted folder
|
|
303
|
+
* leave the wrapper byte-identical to the canonical text.
|
|
304
|
+
*/
|
|
305
|
+
function retargetBodyFolder(
|
|
306
|
+
template: string,
|
|
307
|
+
folder: TaskFolder | undefined,
|
|
308
|
+
): string {
|
|
309
|
+
if (folder === undefined || folder === 'tasks-ready') {
|
|
310
|
+
return template;
|
|
311
|
+
}
|
|
312
|
+
const pool = workFolderRel('tasks-ready');
|
|
313
|
+
const actual = workFolderRel(folder);
|
|
314
|
+
const poolBare = pool.slice(`${WORK_ROOT}/`.length);
|
|
315
|
+
return template
|
|
316
|
+
.split(`${pool}/<slug>.md`)
|
|
317
|
+
.join(`${actual}/<slug>.md`)
|
|
318
|
+
.split(`body ${poolBare}/ ->`)
|
|
319
|
+
.join(`body ${actual}/ ->`);
|
|
320
|
+
}
|
|
321
|
+
|
|
258
322
|
/**
|
|
259
323
|
* The CONTINUE context that turns the fresh-start assembly into a continue-mode
|
|
260
324
|
* one (the `agent-prompt-continue-context` task). It is OPT-IN state inherited
|
|
@@ -434,6 +498,8 @@ export function buildAgentPrompt(
|
|
|
434
498
|
cwd?: string;
|
|
435
499
|
continueContext?: ContinueContext;
|
|
436
500
|
promptGuidance?: {testFirst?: boolean};
|
|
501
|
+
/** The folder the task body was resolved from (`ResolvedTask.folder`). */
|
|
502
|
+
taskFolder?: TaskFolder;
|
|
437
503
|
} = {},
|
|
438
504
|
): string {
|
|
439
505
|
const head = wrapper(slug, spec, options);
|
|
@@ -754,5 +820,6 @@ export function renderPrompt(options: PromptOptions): string {
|
|
|
754
820
|
protocolPath: options.protocolPath,
|
|
755
821
|
cwd: options.cwd,
|
|
756
822
|
promptGuidance: resolvedGuidance,
|
|
823
|
+
taskFolder: task.folder,
|
|
757
824
|
});
|
|
758
825
|
}
|
package/src/reap-branches.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import {run} from './git.js';
|
|
2
2
|
import {isProvablyMergedForReap} from './gc.js';
|
|
3
|
+
import {
|
|
4
|
+
classifyTerminalItemLocks,
|
|
5
|
+
reconcileTerminalItemLocks,
|
|
6
|
+
} from './item-lock.js';
|
|
3
7
|
import {parseWorkBranchRef} from './slug-namespace.js';
|
|
4
8
|
import type {SidecarType} from './sidecar.js';
|
|
5
9
|
|
|
@@ -178,6 +182,9 @@ export function sweepRemoteMergedBranches(
|
|
|
178
182
|
input.cwd,
|
|
179
183
|
{env},
|
|
180
184
|
);
|
|
185
|
+
// WRITE-SEAM EXEMPT: `gc --remote-branches` runs in a no-agent job (or by
|
|
186
|
+
// a human), never in a CI agent job, so this merged-branch delete stays a
|
|
187
|
+
// direct push (task `ci-split-route-direct-writes-through-seams`).
|
|
181
188
|
const del = run(
|
|
182
189
|
'git',
|
|
183
190
|
['push', input.arbiter, '--delete', branch],
|
|
@@ -209,6 +216,106 @@ export function sweepRemoteMergedBranches(
|
|
|
209
216
|
return {reaped, retained, wouldReap};
|
|
210
217
|
}
|
|
211
218
|
|
|
219
|
+
export interface SweepTerminalItemLocksInput {
|
|
220
|
+
/**
|
|
221
|
+
* A local repo (a checkout or a hub mirror) whose `<arbiter>` remote points at
|
|
222
|
+
* the arbiter whose per-item locks to sweep. Only refs are read + deleted.
|
|
223
|
+
*/
|
|
224
|
+
cwd: string;
|
|
225
|
+
/** The arbiter remote name (the SAME one the branch sweep targets). */
|
|
226
|
+
arbiter: string;
|
|
227
|
+
/** Sink for human-readable progress notes (per released / kept lock). */
|
|
228
|
+
note?: (message: string) => void;
|
|
229
|
+
/** Only REPORT which locks WOULD be released (the `--dry-run` preview). */
|
|
230
|
+
dryRun?: boolean;
|
|
231
|
+
env?: NodeJS.ProcessEnv;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface SweepTerminalItemLocksResult {
|
|
235
|
+
/** Lock entries whose item is terminal on main and whose ref was deleted. */
|
|
236
|
+
released: string[];
|
|
237
|
+
/** On `dryRun`, the lock entries that WOULD be released (nothing deleted). */
|
|
238
|
+
wouldRelease: string[];
|
|
239
|
+
/** Lock entries left HELD because the item is not terminal on main. */
|
|
240
|
+
kept: string[];
|
|
241
|
+
/**
|
|
242
|
+
* Locks left HELD because their classification or release faulted, including
|
|
243
|
+
* a lease REJECTED because the ref moved between the read and the delete.
|
|
244
|
+
*/
|
|
245
|
+
errors: {entry: string; message: string}[];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Release every per-item lock whose item is already TERMINAL on the arbiter's
|
|
250
|
+
* `main` (task `ci-releases-locks-of-terminal-items`). It rides the SAME
|
|
251
|
+
* `gc --remote-branches` invocation the scheduled `reap-merged-branches` CI job
|
|
252
|
+
* runs, so the locks a merged propose PR leaves behind stop accumulating in CI
|
|
253
|
+
* (where no later claim of that item ever comes to release them) WITHOUT any
|
|
254
|
+
* change to the generated workflows.
|
|
255
|
+
*
|
|
256
|
+
* It is NOT a second mechanism: it is exactly the terminal-lock reconcile behind
|
|
257
|
+
* `status --reconcile-locks` and the claim path
|
|
258
|
+
* ({@link reconcileTerminalItemLocks}): ONE predicate (the item's body rests in a
|
|
259
|
+
* terminal folder on `<arbiter>/main`), every delete leased on the sha that was
|
|
260
|
+
* read (`--force-with-lease`, never forced), every uncertainty resolved towards
|
|
261
|
+
* KEEPING the lock. SCOPE is the one arbiter the branch sweep targets (the
|
|
262
|
+
* `<arbiter>` remote of `cwd`). `dryRun` uses the read-only twin
|
|
263
|
+
* ({@link classifyTerminalItemLocks}). Best-effort and never throws.
|
|
264
|
+
*/
|
|
265
|
+
export async function sweepTerminalItemLocks(
|
|
266
|
+
input: SweepTerminalItemLocksInput,
|
|
267
|
+
): Promise<SweepTerminalItemLocksResult> {
|
|
268
|
+
const note = input.note ?? (() => {});
|
|
269
|
+
const out: SweepTerminalItemLocksResult = {
|
|
270
|
+
released: [],
|
|
271
|
+
wouldRelease: [],
|
|
272
|
+
kept: [],
|
|
273
|
+
errors: [],
|
|
274
|
+
};
|
|
275
|
+
try {
|
|
276
|
+
if (input.dryRun === true) {
|
|
277
|
+
const classified = await classifyTerminalItemLocks(
|
|
278
|
+
input.cwd,
|
|
279
|
+
input.arbiter,
|
|
280
|
+
input.env,
|
|
281
|
+
);
|
|
282
|
+
out.wouldRelease = classified.terminal.map((l) => l.entry);
|
|
283
|
+
out.kept = classified.inFlight.map((l) => l.entry);
|
|
284
|
+
out.errors = classified.errors;
|
|
285
|
+
} else {
|
|
286
|
+
const rec = await reconcileTerminalItemLocks(
|
|
287
|
+
input.cwd,
|
|
288
|
+
input.arbiter,
|
|
289
|
+
input.env,
|
|
290
|
+
);
|
|
291
|
+
out.released = rec.released;
|
|
292
|
+
const errored = new Set(rec.errors.map((e) => e.entry));
|
|
293
|
+
// `kept` in the reconcile report ALSO lists a terminal lock whose release
|
|
294
|
+
// was refused; that one is reported under `errors` instead, so the two
|
|
295
|
+
// lists here stay disjoint.
|
|
296
|
+
out.kept = rec.kept.filter((entry) => !errored.has(entry));
|
|
297
|
+
out.errors = rec.errors;
|
|
298
|
+
}
|
|
299
|
+
} catch (err) {
|
|
300
|
+
out.errors.push({
|
|
301
|
+
entry: '(locks)',
|
|
302
|
+
message: err instanceof Error ? err.message : String(err),
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
for (const entry of out.wouldRelease) {
|
|
306
|
+
note(
|
|
307
|
+
`Would release lock ${entry} (item terminal on main) on ${input.arbiter}.`,
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
for (const entry of out.released) {
|
|
311
|
+
note(`Released lock ${entry} (item terminal on main) on ${input.arbiter}.`);
|
|
312
|
+
}
|
|
313
|
+
for (const e of out.errors) {
|
|
314
|
+
note(`Kept lock ${e.entry}: ${e.message}`);
|
|
315
|
+
}
|
|
316
|
+
return out;
|
|
317
|
+
}
|
|
318
|
+
|
|
212
319
|
/** Push a retained branch into the result + emit its note. */
|
|
213
320
|
function retain(
|
|
214
321
|
retained: RetainedBranch[],
|
package/src/ref-write.ts
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import {runAsync, type RunResult} from './git.js';
|
|
2
|
+
import {
|
|
3
|
+
pushContinuedBranchWithStaleLeaseRetry,
|
|
4
|
+
type ContinuedPushResult,
|
|
5
|
+
} from './continue-branch.js';
|
|
6
|
+
import {
|
|
7
|
+
routeToNeedsAttention,
|
|
8
|
+
deleteRemoteWorkBranchIfPresent,
|
|
9
|
+
type RouteToNeedsAttentionOptions,
|
|
10
|
+
type RouteToNeedsAttentionResult,
|
|
11
|
+
type DeleteRemoteWorkBranchOptions,
|
|
12
|
+
type DeleteRemoteWorkBranchResult,
|
|
13
|
+
} from './needs-attention.js';
|
|
14
|
+
import {
|
|
15
|
+
pushTreelessResult,
|
|
16
|
+
type PushTreelessResultParams,
|
|
17
|
+
} from './advance-treeless-publish.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The **ref-write seam**: the sibling of the ledger-transition write seam
|
|
21
|
+
* ({@link import('./ledger-write.js').LedgerWriteStrategy}) for every network
|
|
22
|
+
* write a CI code path reaches that is NOT a `work/` ledger transition, the
|
|
23
|
+
* review provider, the issue provider or the integrator: the per-item lock ref
|
|
24
|
+
* create / amend / leased delete, the continued work-branch rebase push, the
|
|
25
|
+
* work-branch save (commit WIP + push, without a surface), the remote work-branch
|
|
26
|
+
* delete, the tasking candidates branch push, the tree-less `HEAD:main`
|
|
27
|
+
* publish and the Git LFS object upload.
|
|
28
|
+
*
|
|
29
|
+
* Why it exists (spec `ci-agent-job-without-write-token`, ADR
|
|
30
|
+
* `ci-agent-job-holds-no-write-token`, task
|
|
31
|
+
* `ci-split-route-direct-writes-through-seams`): the CI phase mode records every
|
|
32
|
+
* write in the agent phase and performs it in the apply phase, so every write
|
|
33
|
+
* must be VISIBLE at a seam. Before this seam these sites pushed directly.
|
|
34
|
+
*
|
|
35
|
+
* It is a PURE REFACTOR, the same shape as the ledger seam: exactly ONE strategy
|
|
36
|
+
* ({@link currentRefWrite}) that does exactly what each call site did before (the
|
|
37
|
+
* same git argument lists, the same helpers), no mode, no config. Each method is
|
|
38
|
+
* named for the write's INTENT, not the git plumbing, so a recording strategy can
|
|
39
|
+
* capture "what was about to be written" rather than a raw argument list.
|
|
40
|
+
*
|
|
41
|
+
* A test swaps a method with `vi.spyOn(refWrite, '<method>')` (the same pattern
|
|
42
|
+
* the `ledgerWrite` / `ledgerRead` seams use). The guard test
|
|
43
|
+
* `write-sites-through-seams.test.ts` fails on any new direct `git push` or `gh`
|
|
44
|
+
* write outside the seam implementations and the documented exempt sites.
|
|
45
|
+
*/
|
|
46
|
+
export interface RefWriteStrategy {
|
|
47
|
+
/**
|
|
48
|
+
* CREATE a per-item lock ref on the arbiter: push `<commit>:<ref>` with the
|
|
49
|
+
* create-only lease `--force-with-lease=<ref>:` (succeeds iff the ref is
|
|
50
|
+
* absent). Returns the raw push result; the caller interprets it (`acquired`
|
|
51
|
+
* vs contended). CI phase: lock.
|
|
52
|
+
*/
|
|
53
|
+
createLockRef(input: LockRefCreateInput): Promise<RunResult>;
|
|
54
|
+
/**
|
|
55
|
+
* DELETE a held per-item lock ref on the arbiter, leased on the sha the caller
|
|
56
|
+
* read (`push --delete <ref> --force-with-lease=<ref>:<expectedSha>`). CI
|
|
57
|
+
* phase: apply (the lease is on the lock job's `lockSha`).
|
|
58
|
+
*/
|
|
59
|
+
deleteLockRef(input: LockRefDeleteInput): Promise<RunResult>;
|
|
60
|
+
/**
|
|
61
|
+
* REPLACE a held per-item lock ref on the arbiter with a new lock commit,
|
|
62
|
+
* leased on the sha the caller read (`push <commit>:<ref>
|
|
63
|
+
* --force-with-lease=<ref>:<expectedSha>`): the amend of a held lock (the
|
|
64
|
+
* propose-kept marker, and the answered-merge takeover of a lock carrying
|
|
65
|
+
* it). A concurrent change to the ref rejects the push; it is never forced.
|
|
66
|
+
* CI phase: lock (the takeover) and apply (the marker).
|
|
67
|
+
*/
|
|
68
|
+
replaceLockRef(input: LockRefReplaceInput): Promise<RunResult>;
|
|
69
|
+
/**
|
|
70
|
+
* Push the CONTINUED (rebased) kept `work/<slug>` branch with a lease on the
|
|
71
|
+
* tip observed before the rebase, surviving a stale lease by re-fetching and
|
|
72
|
+
* re-rebasing (see {@link pushContinuedBranchWithStaleLeaseRetry}). Throws
|
|
73
|
+
* exactly as that helper does. CI phase: apply (ADR decision 7).
|
|
74
|
+
*/
|
|
75
|
+
pushContinuedBranch(input: ContinuedBranchPushInput): ContinuedPushResult;
|
|
76
|
+
/**
|
|
77
|
+
* Push an already-rebased work branch ONCE with a lease on the tip observed
|
|
78
|
+
* earlier (`<commit>:refs/heads/<branch>
|
|
79
|
+
* --force-with-lease=refs/heads/<branch>:<expectedTip>`), with NO retry and NO
|
|
80
|
+
* re-rebase: a stale lease is returned for the caller to report. The CI apply
|
|
81
|
+
* phase's continue push (ADR `ci-agent-job-holds-no-write-token` decision 7:
|
|
82
|
+
* the agent job rebased the kept branch locally, and the lease is the lock
|
|
83
|
+
* job's `continueTip`). CI phase: apply.
|
|
84
|
+
*/
|
|
85
|
+
pushLeasedWorkBranch(input: LeasedWorkBranchPushInput): Promise<RunResult>;
|
|
86
|
+
/**
|
|
87
|
+
* SAVE the work branch: commit any uncommitted work as a wip commit and push
|
|
88
|
+
* the work branch to the arbiter, WITHOUT surfacing the item (the recoverable
|
|
89
|
+
* half of a needs-attention route, see {@link routeToNeedsAttention}). Used by
|
|
90
|
+
* the deadline checkpoint save. CI phase: apply.
|
|
91
|
+
*/
|
|
92
|
+
saveWorkBranch(
|
|
93
|
+
input: RouteToNeedsAttentionOptions,
|
|
94
|
+
): Promise<RouteToNeedsAttentionResult>;
|
|
95
|
+
/**
|
|
96
|
+
* DELETE the remote `work/task-<slug>` branch on the arbiter (write-through:
|
|
97
|
+
* local refs first, then the arbiter delete; already-gone is tolerated, see
|
|
98
|
+
* {@link deleteRemoteWorkBranchIfPresent}). CI phase: apply.
|
|
99
|
+
*/
|
|
100
|
+
deleteRemoteWorkBranch(
|
|
101
|
+
input: DeleteRemoteWorkBranchOptions,
|
|
102
|
+
): Promise<DeleteRemoteWorkBranchResult>;
|
|
103
|
+
/**
|
|
104
|
+
* Push the tasking candidates branch (`work/spec-<slug>`) to the arbiter, a
|
|
105
|
+
* plain `git push <arbiter> <branch>` (best-effort at the caller). CI phase:
|
|
106
|
+
* apply.
|
|
107
|
+
*/
|
|
108
|
+
pushTaskingCandidatesBranch(
|
|
109
|
+
input: TaskingCandidatesPushInput,
|
|
110
|
+
): Promise<RunResult>;
|
|
111
|
+
/**
|
|
112
|
+
* Publish a tree-less rung's local commit to the arbiter's `main` (`git push
|
|
113
|
+
* HEAD:main` with the bounded re-fetch + rebase retry, never `--force`, see
|
|
114
|
+
* {@link pushTreelessResult}). CI phase: apply.
|
|
115
|
+
*/
|
|
116
|
+
publishTreelessResult(input: PushTreelessResultParams): Promise<void>;
|
|
117
|
+
/**
|
|
118
|
+
* UPLOAD Git LFS objects already in `cwd`'s local LFS store to the arbiter's
|
|
119
|
+
* LFS endpoint (`git lfs push --object-id <arbiter> <oids>`, in batches),
|
|
120
|
+
* BEFORE any ref that points at them (ADR `ci-agent-job-holds-no-write-token`
|
|
121
|
+
* decision 6). Returns the first failing batch's result, else the last one.
|
|
122
|
+
* CI phase: apply.
|
|
123
|
+
*/
|
|
124
|
+
pushLfsObjects(input: LfsObjectsPushInput): Promise<RunResult>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Input of {@link RefWriteStrategy.pushLfsObjects}. */
|
|
128
|
+
export interface LfsObjectsPushInput {
|
|
129
|
+
/** The arbiter remote name (its LFS endpoint comes from `cwd`'s config and `.lfsconfig`). */
|
|
130
|
+
arbiter: string;
|
|
131
|
+
/** The sha256 oids to upload (each already in the local store). */
|
|
132
|
+
oids: readonly string[];
|
|
133
|
+
/** Working clone the push runs in. */
|
|
134
|
+
cwd: string;
|
|
135
|
+
/** Environment for the child git process. */
|
|
136
|
+
env: NodeJS.ProcessEnv | undefined;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** How many oids one `git lfs push --object-id` is given. */
|
|
140
|
+
const LFS_PUSH_BATCH = 100;
|
|
141
|
+
|
|
142
|
+
/** Input of {@link RefWriteStrategy.createLockRef}. */
|
|
143
|
+
export interface LockRefCreateInput {
|
|
144
|
+
/** The arbiter remote name. */
|
|
145
|
+
arbiter: string;
|
|
146
|
+
/** The full lock ref (`refs/dorfl/lock/<entry>`). */
|
|
147
|
+
ref: string;
|
|
148
|
+
/** The prepared (parentless) lock commit to publish at {@link ref}. */
|
|
149
|
+
commit: string;
|
|
150
|
+
/** Working clone the push runs in. */
|
|
151
|
+
cwd: string;
|
|
152
|
+
/** Environment for the child git process. */
|
|
153
|
+
env: NodeJS.ProcessEnv | undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Input of {@link RefWriteStrategy.deleteLockRef}. */
|
|
157
|
+
export interface LockRefDeleteInput {
|
|
158
|
+
/** The arbiter remote name. */
|
|
159
|
+
arbiter: string;
|
|
160
|
+
/** The full lock ref (`refs/dorfl/lock/<entry>`). */
|
|
161
|
+
ref: string;
|
|
162
|
+
/** The ref's sha the caller read; the delete is leased on it. */
|
|
163
|
+
expectedSha: string;
|
|
164
|
+
/** Working clone the push runs in. */
|
|
165
|
+
cwd: string;
|
|
166
|
+
/** Environment for the child git process. */
|
|
167
|
+
env: NodeJS.ProcessEnv | undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Input of {@link RefWriteStrategy.replaceLockRef}. */
|
|
171
|
+
export interface LockRefReplaceInput {
|
|
172
|
+
/** The arbiter remote name. */
|
|
173
|
+
arbiter: string;
|
|
174
|
+
/** The full lock ref (`refs/dorfl/lock/<entry>`). */
|
|
175
|
+
ref: string;
|
|
176
|
+
/** The prepared (parentless) lock commit to publish at {@link ref}. */
|
|
177
|
+
commit: string;
|
|
178
|
+
/** The ref's sha the caller read; the replace is leased on it. */
|
|
179
|
+
expectedSha: string;
|
|
180
|
+
/** Working clone the push runs in. */
|
|
181
|
+
cwd: string;
|
|
182
|
+
/** Environment for the child git process. */
|
|
183
|
+
env: NodeJS.ProcessEnv | undefined;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Input of {@link RefWriteStrategy.pushContinuedBranch}. */
|
|
187
|
+
export type ContinuedBranchPushInput = Parameters<
|
|
188
|
+
typeof pushContinuedBranchWithStaleLeaseRetry
|
|
189
|
+
>[0];
|
|
190
|
+
|
|
191
|
+
/** Input of {@link RefWriteStrategy.pushLeasedWorkBranch}. */
|
|
192
|
+
export interface LeasedWorkBranchPushInput {
|
|
193
|
+
/** The arbiter remote name. */
|
|
194
|
+
arbiter: string;
|
|
195
|
+
/** The work branch (`work/task-<slug>`), unqualified. */
|
|
196
|
+
branch: string;
|
|
197
|
+
/** The commit to publish as the branch's tip. */
|
|
198
|
+
commit: string;
|
|
199
|
+
/** The branch tip the caller observed on the arbiter; the push is leased on it. */
|
|
200
|
+
expectedTip: string;
|
|
201
|
+
/** Working clone the push runs in. */
|
|
202
|
+
cwd: string;
|
|
203
|
+
/** Environment for the child git process. */
|
|
204
|
+
env: NodeJS.ProcessEnv | undefined;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Input of {@link RefWriteStrategy.pushTaskingCandidatesBranch}. */
|
|
208
|
+
export interface TaskingCandidatesPushInput {
|
|
209
|
+
/** The arbiter remote name. */
|
|
210
|
+
arbiter: string;
|
|
211
|
+
/** The candidates branch (`work/spec-<slug>`). */
|
|
212
|
+
branch: string;
|
|
213
|
+
/** Working clone the push runs in. */
|
|
214
|
+
cwd: string;
|
|
215
|
+
/** Environment for the child git process. */
|
|
216
|
+
env: NodeJS.ProcessEnv | undefined;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* The ONLY ref-write strategy: current behaviour, the exact git argument lists
|
|
221
|
+
* and helpers the call sites used before they were routed through the seam.
|
|
222
|
+
*/
|
|
223
|
+
export const currentRefWrite: RefWriteStrategy = {
|
|
224
|
+
createLockRef({arbiter, ref, commit, cwd, env}) {
|
|
225
|
+
return runAsync(
|
|
226
|
+
'git',
|
|
227
|
+
['push', arbiter, `${commit}:${ref}`, `--force-with-lease=${ref}:`],
|
|
228
|
+
cwd,
|
|
229
|
+
{env},
|
|
230
|
+
);
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
deleteLockRef({arbiter, ref, expectedSha, cwd, env}) {
|
|
234
|
+
return runAsync(
|
|
235
|
+
'git',
|
|
236
|
+
[
|
|
237
|
+
'push',
|
|
238
|
+
arbiter,
|
|
239
|
+
'--delete',
|
|
240
|
+
ref,
|
|
241
|
+
`--force-with-lease=${ref}:${expectedSha}`,
|
|
242
|
+
],
|
|
243
|
+
cwd,
|
|
244
|
+
{env},
|
|
245
|
+
);
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
replaceLockRef({arbiter, ref, commit, expectedSha, cwd, env}) {
|
|
249
|
+
return runAsync(
|
|
250
|
+
'git',
|
|
251
|
+
[
|
|
252
|
+
'push',
|
|
253
|
+
arbiter,
|
|
254
|
+
`${commit}:${ref}`,
|
|
255
|
+
`--force-with-lease=${ref}:${expectedSha}`,
|
|
256
|
+
],
|
|
257
|
+
cwd,
|
|
258
|
+
{env},
|
|
259
|
+
);
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
pushContinuedBranch(input) {
|
|
263
|
+
return pushContinuedBranchWithStaleLeaseRetry(input);
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
pushLeasedWorkBranch({arbiter, branch, commit, expectedTip, cwd, env}) {
|
|
267
|
+
const ref = `refs/heads/${branch}`;
|
|
268
|
+
return runAsync(
|
|
269
|
+
'git',
|
|
270
|
+
[
|
|
271
|
+
'push',
|
|
272
|
+
arbiter,
|
|
273
|
+
`${commit}:${ref}`,
|
|
274
|
+
`--force-with-lease=${ref}:${expectedTip}`,
|
|
275
|
+
],
|
|
276
|
+
cwd,
|
|
277
|
+
{env},
|
|
278
|
+
);
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
saveWorkBranch(input) {
|
|
282
|
+
return routeToNeedsAttention(input);
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
deleteRemoteWorkBranch(input) {
|
|
286
|
+
return deleteRemoteWorkBranchIfPresent(input);
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
pushTaskingCandidatesBranch({arbiter, branch, cwd, env}) {
|
|
290
|
+
return runAsync('git', ['push', arbiter, branch], cwd, {env});
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
publishTreelessResult(input) {
|
|
294
|
+
return pushTreelessResult(input);
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
async pushLfsObjects({arbiter, oids, cwd, env}) {
|
|
298
|
+
let last: RunResult = {status: 0, stdout: '', stderr: ''};
|
|
299
|
+
for (let i = 0; i < oids.length; i += LFS_PUSH_BATCH) {
|
|
300
|
+
last = await runAsync(
|
|
301
|
+
'git',
|
|
302
|
+
[
|
|
303
|
+
'lfs',
|
|
304
|
+
'push',
|
|
305
|
+
'--object-id',
|
|
306
|
+
arbiter,
|
|
307
|
+
...oids.slice(i, i + LFS_PUSH_BATCH),
|
|
308
|
+
],
|
|
309
|
+
cwd,
|
|
310
|
+
{env},
|
|
311
|
+
);
|
|
312
|
+
if (last.status !== 0) return last;
|
|
313
|
+
}
|
|
314
|
+
return last;
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* The active ref-write strategy. There is exactly one (current behaviour); this
|
|
320
|
+
* indirection is the seam's single insertion point, NOT a selectable mode. Call
|
|
321
|
+
* sites go through `refWrite.<method>(...)` so a test (and later the CI phase
|
|
322
|
+
* mode) can replace a method on this object.
|
|
323
|
+
*/
|
|
324
|
+
export const refWrite: RefWriteStrategy = {...currentRefWrite};
|
package/src/repo-config.ts
CHANGED
|
@@ -176,16 +176,15 @@ export const REPO_ALLOWED_KEYS = [
|
|
|
176
176
|
// same chain as `integration`/`autoBuild`. It REPLACES the old `autoTriage`
|
|
177
177
|
// boolean (no alias; no external users owed a migration window, 2026-06-12).
|
|
178
178
|
'observationTriage',
|
|
179
|
-
// `mergeQuestions` (the
|
|
179
|
+
// `mergeQuestions` (the 2-state `off|ask` gate over the MERGE-QUESTION
|
|
180
180
|
// SURFACER — spec `land-time-reverify-and-parallel-merge-ceiling` Story 17 /
|
|
181
181
|
// task `merge-questions-gate-axis`) is a genuine repo property exactly like
|
|
182
182
|
// `observationTriage`: whether THIS repo's unmerged `work/*` branches surface
|
|
183
|
-
// as merge-questions
|
|
184
|
-
//
|
|
185
|
-
// `
|
|
186
|
-
//
|
|
187
|
-
//
|
|
188
|
-
// (flag > env > per-repo > global > default `ask`).
|
|
183
|
+
// as merge-questions is agreed by all collaborators + travels with the repo.
|
|
184
|
+
// SEPARATE axis from `observationTriage` (never rides it) with a HIGHER
|
|
185
|
+
// default (`ask`, never `off`: a dropped merge-question means pushed work
|
|
186
|
+
// never lands). Resolved per-repo through the SAME precedence chain as the
|
|
187
|
+
// rest of the gate family (env > per-repo > global > default `ask`).
|
|
189
188
|
'mergeQuestions',
|
|
190
189
|
// `surfaceBlockers` (the BOOLEAN gate over DECLARED blocked work — whether a
|
|
191
190
|
// task/spec carrying `needsAnswers:true` is rendered into a question sidecar) is a
|
|
@@ -256,7 +255,8 @@ export const REPO_ALLOWED_KEYS = [
|
|
|
256
255
|
// is agreed by all collaborators in a wide-matrix CI repo + travels with the
|
|
257
256
|
// repo. Resolved per-repo through the SAME chain as `freshWorktreeGate`
|
|
258
257
|
// (flag > env > per-repo > global > default). Safety is unchanged — a lost
|
|
259
|
-
// CAS still costs only a re-rebase
|
|
258
|
+
// CAS still costs only a re-rebase and a retried push (no re-gate), never a
|
|
259
|
+
// `--force`.
|
|
260
260
|
'mergeRetries',
|
|
261
261
|
// `strictMergeApproval` (the OPT-IN strictness layered on the OQ6
|
|
262
262
|
// stale-approval default — spec `land-time-reverify-and-parallel-merge-ceiling`
|