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
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **What the apply phase does with the agent job's result** (spec
|
|
3
|
+
* `ci-agent-job-without-write-token` §8 "Agent result", decision 5 of ADR
|
|
4
|
+
* `ci-agent-job-holds-no-write-token`, task `ci-split-agent-result-and-reruns`).
|
|
5
|
+
*
|
|
6
|
+
* The apply job receives `needs.agent.result` (`--agent-result`). It is part of
|
|
7
|
+
* the HOSTILE channel: `success` is only the precondition for reading the
|
|
8
|
+
* artifact, never evidence that its content is good. Every other result never
|
|
9
|
+
* reads the artifact:
|
|
10
|
+
*
|
|
11
|
+
* - `failure`: surface the item to needs-attention (the lock is released);
|
|
12
|
+
* - `cancelled`: GitHub reports a TIMED-OUT job as `cancelled` too (measured,
|
|
13
|
+
* finding `github-actions-job-timeout-reported-as-cancelled`), so the apply
|
|
14
|
+
* job reads the agent job from the Actions API ({@link detectAgentTimeout}).
|
|
15
|
+
* A timeout surfaces; a real cancel only releases the lock; anything it
|
|
16
|
+
* cannot read surfaces (the safe side);
|
|
17
|
+
* - `skipped`: accepted only when the lock job said `needsAgent: false` (the
|
|
18
|
+
* apply job then runs the deterministic rung itself); otherwise it is a
|
|
19
|
+
* failure.
|
|
20
|
+
*
|
|
21
|
+
* This module DECIDES; each path split acts on the decision (its surface and
|
|
22
|
+
* its release differ: a task lock, an intake label).
|
|
23
|
+
*/
|
|
24
|
+
/** The values of `needs.<job>.result` GitHub Actions reports. */
|
|
25
|
+
export declare const AGENT_JOB_RESULTS: readonly ["success", "failure", "cancelled", "skipped"];
|
|
26
|
+
/** `needs.agent.result`, as the apply job receives it. */
|
|
27
|
+
export type AgentJobResult = (typeof AGENT_JOB_RESULTS)[number];
|
|
28
|
+
/** A malformed `--agent-result` or `--agent-timeout-minutes`. */
|
|
29
|
+
export declare class AgentResultUsageError extends Error {
|
|
30
|
+
readonly name = "AgentResultUsageError";
|
|
31
|
+
}
|
|
32
|
+
/** Parse `--agent-result` (exactly one of {@link AGENT_JOB_RESULTS}). */
|
|
33
|
+
export declare function parseAgentJobResult(raw: string): AgentJobResult;
|
|
34
|
+
/** Parse `--agent-timeout-minutes` (a positive integer, the lock output). */
|
|
35
|
+
export declare function parseAgentTimeoutMinutes(raw: string): number;
|
|
36
|
+
/**
|
|
37
|
+
* The fragment of GitHub's timeout annotation ("The job has exceeded the maximum
|
|
38
|
+
* execution time of <duration>"), matched as a substring only.
|
|
39
|
+
*/
|
|
40
|
+
export declare const TIMEOUT_ANNOTATION_FRAGMENT = "exceeded the maximum execution time";
|
|
41
|
+
/**
|
|
42
|
+
* The tolerance under `agentTimeoutMinutes` at which the agent job's duration
|
|
43
|
+
* already counts as a timeout: the job clock may start after `started_at`.
|
|
44
|
+
*/
|
|
45
|
+
export declare const TIMEOUT_TOLERANCE_MS = 60000;
|
|
46
|
+
/** The most pages {@link detectAgentTimeout} reads from one listing. */
|
|
47
|
+
export declare const MAX_API_PAGES = 50;
|
|
48
|
+
/**
|
|
49
|
+
* One GET against the GitHub REST API: the status, the parsed JSON body and the
|
|
50
|
+
* `rel="next"` page URL from the `Link` header. Tests stub it.
|
|
51
|
+
*/
|
|
52
|
+
export type GithubApiGet = (url: string) => Promise<{
|
|
53
|
+
status: number;
|
|
54
|
+
body: unknown;
|
|
55
|
+
next?: string;
|
|
56
|
+
}>;
|
|
57
|
+
/** How a cancelled agent job ended, as far as the Actions API tells. */
|
|
58
|
+
export type CancelVerdict =
|
|
59
|
+
/** The job hit its `timeout-minutes` (either signal said so). */
|
|
60
|
+
{
|
|
61
|
+
kind: 'timeout';
|
|
62
|
+
why: string;
|
|
63
|
+
}
|
|
64
|
+
/** A real cancel (a human, or a newer run's concurrency). */
|
|
65
|
+
| {
|
|
66
|
+
kind: 'cancel';
|
|
67
|
+
why: string;
|
|
68
|
+
}
|
|
69
|
+
/** The API could not be read, or the job not found: treated as a timeout. */
|
|
70
|
+
| {
|
|
71
|
+
kind: 'unreadable';
|
|
72
|
+
why: string;
|
|
73
|
+
};
|
|
74
|
+
/** Where the Actions API reads of {@link detectAgentTimeout} go. */
|
|
75
|
+
export interface ActionsRunRef {
|
|
76
|
+
/** `GITHUB_API_URL` (default `https://api.github.com`). */
|
|
77
|
+
apiUrl: string;
|
|
78
|
+
/** `GITHUB_REPOSITORY` (`owner/repo`). */
|
|
79
|
+
repository: string;
|
|
80
|
+
/** `GITHUB_RUN_ID`. */
|
|
81
|
+
runId: string;
|
|
82
|
+
/** `GITHUB_RUN_ATTEMPT`. */
|
|
83
|
+
runAttempt: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The run this apply job belongs to, from the Actions environment, or
|
|
87
|
+
* `undefined` when any part is missing (the caller then surfaces).
|
|
88
|
+
*/
|
|
89
|
+
export declare function actionsRunRefFromEnv(env: NodeJS.ProcessEnv): ActionsRunRef | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* A {@link GithubApiGet} over `fetch` authenticated with `GITHUB_TOKEN` ONLY:
|
|
92
|
+
* the job's own token, which the apply job grants `actions: read` and
|
|
93
|
+
* `checks: read`. Never `GH_TOKEN` / `DORFL_GH_TOKEN` (the write credential has
|
|
94
|
+
* no business reading this). `undefined` when `GITHUB_TOKEN` is not set.
|
|
95
|
+
*/
|
|
96
|
+
export declare function githubTokenApiGet(env: NodeJS.ProcessEnv): GithubApiGet | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* Is this job the item's agent job? Inside a called workflow the job is named
|
|
99
|
+
* `<caller job> / agent`; a workflow that is not called names it `agent`.
|
|
100
|
+
*/
|
|
101
|
+
export declare function isAgentJobName(name: string): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Tell a timed-out agent job from a cancelled one (decision 5). Two signals,
|
|
104
|
+
* either one meaning timeout:
|
|
105
|
+
*
|
|
106
|
+
* - an annotation of the agent job's check run containing
|
|
107
|
+
* {@link TIMEOUT_ANNOTATION_FRAGMENT}, read across EVERY page;
|
|
108
|
+
* - the job's `completed_at - started_at` (written by GitHub, not the agent)
|
|
109
|
+
* reaching `agentTimeoutMinutes` minus {@link TIMEOUT_TOLERANCE_MS}.
|
|
110
|
+
*
|
|
111
|
+
* Anything it cannot establish (no token, an API error, no single agent job in
|
|
112
|
+
* this run attempt, no timestamps, no trusted timeout) is `unreadable`, which
|
|
113
|
+
* the caller surfaces. Annotation text is agent-controllable (a job can write
|
|
114
|
+
* `::error::` lines): it is only substring-matched, and NEVER copied into the
|
|
115
|
+
* verdict, a note or the output.
|
|
116
|
+
*/
|
|
117
|
+
export declare function detectAgentTimeout(params: {
|
|
118
|
+
get: GithubApiGet | undefined;
|
|
119
|
+
run: ActionsRunRef | undefined;
|
|
120
|
+
agentTimeoutMinutes: number | undefined;
|
|
121
|
+
}): Promise<CancelVerdict>;
|
|
122
|
+
/** What the apply phase does, given the agent job's result. */
|
|
123
|
+
export type AgentResultDecision =
|
|
124
|
+
/** `success`: read and validate the handoff. */
|
|
125
|
+
{
|
|
126
|
+
action: 'read-handoff';
|
|
127
|
+
}
|
|
128
|
+
/** `skipped` with `needsAgent: false`: run the deterministic rung itself. */
|
|
129
|
+
| {
|
|
130
|
+
action: 'deterministic';
|
|
131
|
+
}
|
|
132
|
+
/** Surface the item to needs-attention (and release the lock); no artifact read. */
|
|
133
|
+
| {
|
|
134
|
+
action: 'surface';
|
|
135
|
+
reason: string;
|
|
136
|
+
}
|
|
137
|
+
/** Only release the lock (a real cancel); no artifact read. */
|
|
138
|
+
| {
|
|
139
|
+
action: 'release';
|
|
140
|
+
reason: string;
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Decide what the apply phase does with `needs.agent.result` (decision 5).
|
|
144
|
+
* `detectTimeout` is called only for `cancelled`.
|
|
145
|
+
*/
|
|
146
|
+
export declare function decideAgentResult(params: {
|
|
147
|
+
result: AgentJobResult;
|
|
148
|
+
needsAgent: boolean | undefined;
|
|
149
|
+
detectTimeout: () => Promise<CancelVerdict>;
|
|
150
|
+
}): Promise<AgentResultDecision>;
|
|
151
|
+
//# sourceMappingURL=ci-agent-result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-agent-result.d.ts","sourceRoot":"","sources":["../src/ci-agent-result.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **What the apply phase does with the agent job's result** (spec
|
|
3
|
+
* `ci-agent-job-without-write-token` §8 "Agent result", decision 5 of ADR
|
|
4
|
+
* `ci-agent-job-holds-no-write-token`, task `ci-split-agent-result-and-reruns`).
|
|
5
|
+
*
|
|
6
|
+
* The apply job receives `needs.agent.result` (`--agent-result`). It is part of
|
|
7
|
+
* the HOSTILE channel: `success` is only the precondition for reading the
|
|
8
|
+
* artifact, never evidence that its content is good. Every other result never
|
|
9
|
+
* reads the artifact:
|
|
10
|
+
*
|
|
11
|
+
* - `failure`: surface the item to needs-attention (the lock is released);
|
|
12
|
+
* - `cancelled`: GitHub reports a TIMED-OUT job as `cancelled` too (measured,
|
|
13
|
+
* finding `github-actions-job-timeout-reported-as-cancelled`), so the apply
|
|
14
|
+
* job reads the agent job from the Actions API ({@link detectAgentTimeout}).
|
|
15
|
+
* A timeout surfaces; a real cancel only releases the lock; anything it
|
|
16
|
+
* cannot read surfaces (the safe side);
|
|
17
|
+
* - `skipped`: accepted only when the lock job said `needsAgent: false` (the
|
|
18
|
+
* apply job then runs the deterministic rung itself); otherwise it is a
|
|
19
|
+
* failure.
|
|
20
|
+
*
|
|
21
|
+
* This module DECIDES; each path split acts on the decision (its surface and
|
|
22
|
+
* its release differ: a task lock, an intake label).
|
|
23
|
+
*/
|
|
24
|
+
/** The values of `needs.<job>.result` GitHub Actions reports. */
|
|
25
|
+
export const AGENT_JOB_RESULTS = [
|
|
26
|
+
'success',
|
|
27
|
+
'failure',
|
|
28
|
+
'cancelled',
|
|
29
|
+
'skipped',
|
|
30
|
+
];
|
|
31
|
+
/** A malformed `--agent-result` or `--agent-timeout-minutes`. */
|
|
32
|
+
export class AgentResultUsageError extends Error {
|
|
33
|
+
name = 'AgentResultUsageError';
|
|
34
|
+
}
|
|
35
|
+
/** Parse `--agent-result` (exactly one of {@link AGENT_JOB_RESULTS}). */
|
|
36
|
+
export function parseAgentJobResult(raw) {
|
|
37
|
+
if (AGENT_JOB_RESULTS.includes(raw)) {
|
|
38
|
+
return raw;
|
|
39
|
+
}
|
|
40
|
+
throw new AgentResultUsageError(`--agent-result must be one of ${AGENT_JOB_RESULTS.join(', ')} ` +
|
|
41
|
+
`(needs.agent.result); got ${JSON.stringify(raw.slice(0, 40))}`);
|
|
42
|
+
}
|
|
43
|
+
/** Parse `--agent-timeout-minutes` (a positive integer, the lock output). */
|
|
44
|
+
export function parseAgentTimeoutMinutes(raw) {
|
|
45
|
+
const n = /^[0-9]{1,9}$/.test(raw) ? Number(raw) : Number.NaN;
|
|
46
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
47
|
+
throw new AgentResultUsageError('--agent-timeout-minutes must be a positive integer ' +
|
|
48
|
+
'(needs.lock.outputs.agentTimeoutMinutes)');
|
|
49
|
+
}
|
|
50
|
+
return n;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The fragment of GitHub's timeout annotation ("The job has exceeded the maximum
|
|
54
|
+
* execution time of <duration>"), matched as a substring only.
|
|
55
|
+
*/
|
|
56
|
+
export const TIMEOUT_ANNOTATION_FRAGMENT = 'exceeded the maximum execution time';
|
|
57
|
+
/**
|
|
58
|
+
* The tolerance under `agentTimeoutMinutes` at which the agent job's duration
|
|
59
|
+
* already counts as a timeout: the job clock may start after `started_at`.
|
|
60
|
+
*/
|
|
61
|
+
export const TIMEOUT_TOLERANCE_MS = 60_000;
|
|
62
|
+
/** The most pages {@link detectAgentTimeout} reads from one listing. */
|
|
63
|
+
export const MAX_API_PAGES = 50;
|
|
64
|
+
/**
|
|
65
|
+
* The run this apply job belongs to, from the Actions environment, or
|
|
66
|
+
* `undefined` when any part is missing (the caller then surfaces).
|
|
67
|
+
*/
|
|
68
|
+
export function actionsRunRefFromEnv(env) {
|
|
69
|
+
const repository = env.GITHUB_REPOSITORY;
|
|
70
|
+
const runId = env.GITHUB_RUN_ID;
|
|
71
|
+
const runAttempt = env.GITHUB_RUN_ATTEMPT;
|
|
72
|
+
if (repository === undefined ||
|
|
73
|
+
!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repository) ||
|
|
74
|
+
runId === undefined ||
|
|
75
|
+
!/^[0-9]+$/.test(runId) ||
|
|
76
|
+
runAttempt === undefined ||
|
|
77
|
+
!/^[0-9]+$/.test(runAttempt)) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
const apiUrl = (env.GITHUB_API_URL ?? 'https://api.github.com').replace(/\/+$/, '');
|
|
81
|
+
return { apiUrl, repository, runId, runAttempt };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* A {@link GithubApiGet} over `fetch` authenticated with `GITHUB_TOKEN` ONLY:
|
|
85
|
+
* the job's own token, which the apply job grants `actions: read` and
|
|
86
|
+
* `checks: read`. Never `GH_TOKEN` / `DORFL_GH_TOKEN` (the write credential has
|
|
87
|
+
* no business reading this). `undefined` when `GITHUB_TOKEN` is not set.
|
|
88
|
+
*/
|
|
89
|
+
export function githubTokenApiGet(env) {
|
|
90
|
+
const token = env.GITHUB_TOKEN?.trim();
|
|
91
|
+
if (token === undefined || token === '')
|
|
92
|
+
return undefined;
|
|
93
|
+
return async (url) => {
|
|
94
|
+
const res = await fetch(url, {
|
|
95
|
+
headers: {
|
|
96
|
+
accept: 'application/vnd.github+json',
|
|
97
|
+
authorization: `Bearer ${token}`,
|
|
98
|
+
'x-github-api-version': '2022-11-28',
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
let body;
|
|
102
|
+
try {
|
|
103
|
+
body = await res.json();
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
body = undefined;
|
|
107
|
+
}
|
|
108
|
+
const link = res.headers.get('link') ?? '';
|
|
109
|
+
const next = /<([^>]+)>;\s*rel="next"/.exec(link)?.[1];
|
|
110
|
+
return { status: res.status, body, next };
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* GET every page of a listing (following `rel="next"`), handing each page's
|
|
115
|
+
* body to `onPage`. Throws on a non-200 page, on a next URL outside `apiUrl`,
|
|
116
|
+
* or past {@link MAX_API_PAGES}.
|
|
117
|
+
*/
|
|
118
|
+
async function eachPage(get, apiUrl, first, onPage) {
|
|
119
|
+
let url = first;
|
|
120
|
+
for (let page = 1; url !== undefined; page++) {
|
|
121
|
+
if (page > MAX_API_PAGES) {
|
|
122
|
+
throw new Error(`more than ${MAX_API_PAGES} pages`);
|
|
123
|
+
}
|
|
124
|
+
if (!url.startsWith(`${apiUrl}/`)) {
|
|
125
|
+
throw new Error('a next page points outside the API');
|
|
126
|
+
}
|
|
127
|
+
const r = await get(url);
|
|
128
|
+
if (r.status !== 200)
|
|
129
|
+
throw new Error(`HTTP ${r.status}`);
|
|
130
|
+
onPage(r.body);
|
|
131
|
+
url = r.next;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Is this job the item's agent job? Inside a called workflow the job is named
|
|
136
|
+
* `<caller job> / agent`; a workflow that is not called names it `agent`.
|
|
137
|
+
*/
|
|
138
|
+
export function isAgentJobName(name) {
|
|
139
|
+
return name === 'agent' || name.endsWith(' / agent');
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Tell a timed-out agent job from a cancelled one (decision 5). Two signals,
|
|
143
|
+
* either one meaning timeout:
|
|
144
|
+
*
|
|
145
|
+
* - an annotation of the agent job's check run containing
|
|
146
|
+
* {@link TIMEOUT_ANNOTATION_FRAGMENT}, read across EVERY page;
|
|
147
|
+
* - the job's `completed_at - started_at` (written by GitHub, not the agent)
|
|
148
|
+
* reaching `agentTimeoutMinutes` minus {@link TIMEOUT_TOLERANCE_MS}.
|
|
149
|
+
*
|
|
150
|
+
* Anything it cannot establish (no token, an API error, no single agent job in
|
|
151
|
+
* this run attempt, no timestamps, no trusted timeout) is `unreadable`, which
|
|
152
|
+
* the caller surfaces. Annotation text is agent-controllable (a job can write
|
|
153
|
+
* `::error::` lines): it is only substring-matched, and NEVER copied into the
|
|
154
|
+
* verdict, a note or the output.
|
|
155
|
+
*/
|
|
156
|
+
export async function detectAgentTimeout(params) {
|
|
157
|
+
const { get, run, agentTimeoutMinutes } = params;
|
|
158
|
+
if (get === undefined) {
|
|
159
|
+
return {
|
|
160
|
+
kind: 'unreadable',
|
|
161
|
+
why: 'GITHUB_TOKEN is not set, so the agent job could not be read',
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
if (run === undefined) {
|
|
165
|
+
return {
|
|
166
|
+
kind: 'unreadable',
|
|
167
|
+
why: 'GITHUB_REPOSITORY, GITHUB_RUN_ID or GITHUB_RUN_ATTEMPT is not set, ' +
|
|
168
|
+
'so the agent job could not be read',
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const repo = `${run.apiUrl}/repos/${run.repository}`;
|
|
172
|
+
const agents = [];
|
|
173
|
+
try {
|
|
174
|
+
await eachPage(get, run.apiUrl, `${repo}/actions/runs/${run.runId}/attempts/${run.runAttempt}/jobs?per_page=100`, (body) => {
|
|
175
|
+
const jobs = body?.jobs;
|
|
176
|
+
if (!Array.isArray(jobs))
|
|
177
|
+
throw new Error('no jobs list');
|
|
178
|
+
for (const job of jobs) {
|
|
179
|
+
if (typeof job.name !== 'string' || !isAgentJobName(job.name)) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (typeof job.id !== 'number' || !Number.isSafeInteger(job.id)) {
|
|
183
|
+
throw new Error('an agent job without an id');
|
|
184
|
+
}
|
|
185
|
+
agents.push({
|
|
186
|
+
id: job.id,
|
|
187
|
+
startedAt: typeof job.started_at === 'string' ? job.started_at : undefined,
|
|
188
|
+
completedAt: typeof job.completed_at === 'string'
|
|
189
|
+
? job.completed_at
|
|
190
|
+
: undefined,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
return {
|
|
197
|
+
kind: 'unreadable',
|
|
198
|
+
why: `the jobs of run ${run.runId} attempt ${run.runAttempt} could not be read (${errorText(err)})`,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
if (agents.length !== 1) {
|
|
202
|
+
return {
|
|
203
|
+
kind: 'unreadable',
|
|
204
|
+
why: `run ${run.runId} attempt ${run.runAttempt} has ${agents.length} ` +
|
|
205
|
+
`jobs named '/ agent', not exactly one`,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const agent = agents[0];
|
|
209
|
+
// Signal 1: the duration GitHub recorded (the agent cannot write it).
|
|
210
|
+
const started = Date.parse(agent.startedAt ?? '');
|
|
211
|
+
const completed = Date.parse(agent.completedAt ?? '');
|
|
212
|
+
let durationKnown = false;
|
|
213
|
+
if (Number.isFinite(started) && Number.isFinite(completed)) {
|
|
214
|
+
durationKnown = true;
|
|
215
|
+
if (agentTimeoutMinutes !== undefined &&
|
|
216
|
+
completed - started >= agentTimeoutMinutes * 60_000 - TIMEOUT_TOLERANCE_MS) {
|
|
217
|
+
const minutes = Math.floor((completed - started) / 60_000);
|
|
218
|
+
return {
|
|
219
|
+
kind: 'timeout',
|
|
220
|
+
why: `the agent job ran ${minutes} minute(s), within a minute of its ` +
|
|
221
|
+
`${agentTimeoutMinutes}-minute timeout`,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Signal 2: GitHub's timeout annotation, on ANY page.
|
|
226
|
+
let annotated = false;
|
|
227
|
+
try {
|
|
228
|
+
await eachPage(get, run.apiUrl, `${repo}/check-runs/${agent.id}/annotations?per_page=100`, (body) => {
|
|
229
|
+
if (!Array.isArray(body))
|
|
230
|
+
throw new Error('no annotations list');
|
|
231
|
+
for (const a of body) {
|
|
232
|
+
for (const field of [a.message, a.title]) {
|
|
233
|
+
if (typeof field === 'string' &&
|
|
234
|
+
field.includes(TIMEOUT_ANNOTATION_FRAGMENT)) {
|
|
235
|
+
annotated = true;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
return {
|
|
243
|
+
kind: 'unreadable',
|
|
244
|
+
why: `the annotations of the agent job could not be read (${errorText(err)})`,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (annotated) {
|
|
248
|
+
return {
|
|
249
|
+
kind: 'timeout',
|
|
250
|
+
why: "the agent job carries GitHub's timeout annotation",
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
if (!durationKnown) {
|
|
254
|
+
return {
|
|
255
|
+
kind: 'unreadable',
|
|
256
|
+
why: 'the agent job has no start or completion time',
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
if (agentTimeoutMinutes === undefined) {
|
|
260
|
+
return {
|
|
261
|
+
kind: 'unreadable',
|
|
262
|
+
why: 'no trusted agent timeout was given, so its duration cannot be judged',
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
kind: 'cancel',
|
|
267
|
+
why: 'the agent job was cancelled before its timeout',
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/** Only dorfl's own words: an error thrown by a listing above, or the status. */
|
|
271
|
+
function errorText(err) {
|
|
272
|
+
// Our own thrown messages carry no API text; a fetch failure's message is
|
|
273
|
+
// the runtime's, never the annotation body.
|
|
274
|
+
return err instanceof Error ? err.message.slice(0, 200) : 'unknown error';
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Decide what the apply phase does with `needs.agent.result` (decision 5).
|
|
278
|
+
* `detectTimeout` is called only for `cancelled`.
|
|
279
|
+
*/
|
|
280
|
+
export async function decideAgentResult(params) {
|
|
281
|
+
switch (params.result) {
|
|
282
|
+
case 'success':
|
|
283
|
+
return { action: 'read-handoff' };
|
|
284
|
+
case 'skipped':
|
|
285
|
+
if (params.needsAgent === false)
|
|
286
|
+
return { action: 'deterministic' };
|
|
287
|
+
return {
|
|
288
|
+
action: 'surface',
|
|
289
|
+
reason: 'the agent job was skipped although the lock job said the item ' +
|
|
290
|
+
'needs an agent (treated as an agent failure); the handoff was not read',
|
|
291
|
+
};
|
|
292
|
+
case 'failure':
|
|
293
|
+
return {
|
|
294
|
+
action: 'surface',
|
|
295
|
+
reason: 'the agent job failed (see its log in the workflow run); the handoff ' +
|
|
296
|
+
'was not read',
|
|
297
|
+
};
|
|
298
|
+
case 'cancelled': {
|
|
299
|
+
const verdict = await params.detectTimeout();
|
|
300
|
+
if (verdict.kind === 'cancel') {
|
|
301
|
+
return {
|
|
302
|
+
action: 'release',
|
|
303
|
+
reason: `${verdict.why}; the handoff was not read`,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
const what = verdict.kind === 'timeout'
|
|
307
|
+
? `the agent job timed out: ${verdict.why}`
|
|
308
|
+
: `the agent job was cancelled and it could not be told whether it ` +
|
|
309
|
+
`timed out (${verdict.why}), so it is treated as a timeout`;
|
|
310
|
+
return { action: 'surface', reason: `${what}; the handoff was not read` };
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=ci-agent-result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-agent-result.js","sourceRoot":"","sources":["../src/ci-agent-result.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **The apply phase's validation of a handoff** (spec
|
|
3
|
+
* `ci-agent-job-without-write-token`, ADR `ci-agent-job-holds-no-write-token`
|
|
4
|
+
* decisions 3 and 4, task `ci-split-apply-rejects-hostile-bundle`).
|
|
5
|
+
*
|
|
6
|
+
* The apply job holds a write token and runs no agent. It reads the agent job's
|
|
7
|
+
* artifact as HOSTILE: every target, mode and policy comes from TRUSTED inputs
|
|
8
|
+
* (the lock job's outputs, the workflow inputs, the tree at `baseSha`, the
|
|
9
|
+
* arbiter), never from the artifact. {@link validateApplyHandoff} is the one
|
|
10
|
+
* unit the path splits call BEFORE any write. It either returns the validated
|
|
11
|
+
* handoff (the bundle's tip fetched to {@link INCOMING_TIP_REF} in the apply
|
|
12
|
+
* checkout, the recomputed integration mode, the ledger report) or throws a
|
|
13
|
+
* {@link HandoffRejected} whose `rule` and message name the broken rule, having
|
|
14
|
+
* written nothing from the artifact anywhere: not to the arbiter, and not even
|
|
15
|
+
* into the apply checkout's object store.
|
|
16
|
+
*
|
|
17
|
+
* How "nothing is fetched into the repository" holds: the bundle is first
|
|
18
|
+
* fetched into a throwaway QUARANTINE repository whose object store borrows the
|
|
19
|
+
* apply checkout's objects (read-only, through `objects/info/alternates`), and
|
|
20
|
+
* every history, path and size check runs there. Only an accepted bundle is
|
|
21
|
+
* then fetched into the apply checkout, with the same command.
|
|
22
|
+
*
|
|
23
|
+
* The LFS objects (decision 6, task `ci-split-handoff-lfs-objects`): the new
|
|
24
|
+
* commits' blobs are scanned for pointers in the quarantine, and every object
|
|
25
|
+
* is checked against its pointer (`ci-handoff-lfs.ts`) before the import. The
|
|
26
|
+
* push of the objects (before any ref) is the path split's first write.
|
|
27
|
+
*
|
|
28
|
+
* Out of scope here: the agent-result, lock-ownership and re-run rules (wired
|
|
29
|
+
* by the path splits).
|
|
30
|
+
*/
|
|
31
|
+
import type { IntegrationMode } from './config.js';
|
|
32
|
+
import { type HandoffRung } from './ci-handoff-format.js';
|
|
33
|
+
import { type HandoffLfsObject, type ReadHandoff } from './ci-handoff.js';
|
|
34
|
+
/** The apply checkout's ref an accepted bundle's tip is fetched to. */
|
|
35
|
+
export declare const INCOMING_TIP_REF = "refs/dorfl/incoming/tip";
|
|
36
|
+
/** The most new commits (`tip ^<arbiter>/main`) a bundle may carry. */
|
|
37
|
+
export declare const MAX_NEW_COMMITS = 200;
|
|
38
|
+
/** The reason for a merge commit in the range (spec, "History"). */
|
|
39
|
+
export declare const MERGE_COMMIT_REASON = "the work branch contains a merge commit; rebase it and requeue";
|
|
40
|
+
/**
|
|
41
|
+
* The protected path rule a repository path falls under, or `undefined`. The
|
|
42
|
+
* fixed built-in list of decision 3 (not a config key): `.github/`,
|
|
43
|
+
* `CODEOWNERS` (root, `docs/`, `.github/`), the repository config (`dorfl.json`
|
|
44
|
+
* and its legacy dotfile, which dorfl still reads), `.lfsconfig`, and
|
|
45
|
+
* `.gitattributes` at ANY depth (a nested one sets merge attributes for its
|
|
46
|
+
* subtree just like the root one). Matched case-insensitively, so a
|
|
47
|
+
* `.GitHub/` that a case-insensitive checkout would fold into `.github/` is
|
|
48
|
+
* caught too.
|
|
49
|
+
*/
|
|
50
|
+
export declare function protectedPathOf(path: string): string | undefined;
|
|
51
|
+
/** The trusted facts the apply job validates a handoff against. */
|
|
52
|
+
export interface ApplyTrust {
|
|
53
|
+
/** The item this run carries (lock output / workflow input). */
|
|
54
|
+
item: string;
|
|
55
|
+
/** The rung the lock job classified. */
|
|
56
|
+
rung: HandoffRung;
|
|
57
|
+
/** The arbiter's `main` the lock job classified the item at. */
|
|
58
|
+
baseSha: string;
|
|
59
|
+
/** The arbiter git remote of the apply checkout. */
|
|
60
|
+
arbiter: string;
|
|
61
|
+
/** The integration mode the workflow asked for (before the recomputed rules). */
|
|
62
|
+
integrationMode: IntegrationMode;
|
|
63
|
+
}
|
|
64
|
+
/** A handoff that passed every rule. */
|
|
65
|
+
export interface ApplyHandoff {
|
|
66
|
+
handoff: ReadHandoff;
|
|
67
|
+
/**
|
|
68
|
+
* The integration mode to land with: `merge` only when the trusted
|
|
69
|
+
* `integrationMode` is `merge` AND the untrusted-origin rule, recomputed from
|
|
70
|
+
* the task at `baseSha`, does not force `propose`.
|
|
71
|
+
*/
|
|
72
|
+
mode: IntegrationMode;
|
|
73
|
+
/** Whether the untrusted-origin rule turned a trusted `merge` into `propose`. */
|
|
74
|
+
forcedPropose: boolean;
|
|
75
|
+
/** The accepted bundle, when the handoff carries one. */
|
|
76
|
+
bundle?: {
|
|
77
|
+
/** The work branch name (`workBranchRef` of the trusted item). */
|
|
78
|
+
workBranch: string;
|
|
79
|
+
/** The validated tip, now at {@link INCOMING_TIP_REF} in the apply checkout. */
|
|
80
|
+
tip: string;
|
|
81
|
+
/** The new commits (`tip ^<arbiter>/main`), newest first. */
|
|
82
|
+
newCommits: string[];
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* The artifact's LFS objects, each referenced by a pointer of the new
|
|
86
|
+
* commits and checked against it (size and sha256), sorted by oid. The path
|
|
87
|
+
* split pushes them before any ref.
|
|
88
|
+
*/
|
|
89
|
+
lfsObjects: HandoffLfsObject[];
|
|
90
|
+
/** `work/` paths the bundle changes outside this item's own transition (propose only). */
|
|
91
|
+
ledgerOutsideItem: string[];
|
|
92
|
+
/** The PR-body section listing {@link ledgerOutsideItem}, when there are any. */
|
|
93
|
+
ledgerReport?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The untrusted-origin build-propose rule (ADR `untrusted-origin-build-checkpoint`,
|
|
97
|
+
* `integration-core.ts`), recomputed from the task AT `baseSha` in the apply
|
|
98
|
+
* checkout, never from the bundle (whose done-move could strip the stamp).
|
|
99
|
+
* Scope as in `performIntegration`: the task BUILD transition only; CI passes
|
|
100
|
+
* no explicit `--merge`, so there is no override. Any copy of the task at
|
|
101
|
+
* `baseSha` stamped `originTrust: untrusted` forces `propose`.
|
|
102
|
+
*/
|
|
103
|
+
export declare function recomputeIntegrationMode(params: {
|
|
104
|
+
repo: string;
|
|
105
|
+
baseSha: string;
|
|
106
|
+
item: string;
|
|
107
|
+
integrationMode: IntegrationMode;
|
|
108
|
+
/** Whether the handoff is a task build (`integrate` on the build rung). */
|
|
109
|
+
build: boolean;
|
|
110
|
+
env?: NodeJS.ProcessEnv;
|
|
111
|
+
}): {
|
|
112
|
+
mode: IntegrationMode;
|
|
113
|
+
forcedPropose: boolean;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* The PR-body section that lists the `work/` paths a propose-mode bundle
|
|
117
|
+
* changes outside its own item (decision 3, user story 23). The path names come
|
|
118
|
+
* from the hostile bundle, so each is JSON-quoted inside a code fence longer
|
|
119
|
+
* than any backtick run, which keeps a crafted name from closing the fence or
|
|
120
|
+
* starting a heading; the list is bounded.
|
|
121
|
+
*/
|
|
122
|
+
export declare function renderLedgerReportSection(paths: readonly string[]): string;
|
|
123
|
+
/**
|
|
124
|
+
* Validate the agent job's handoff before the apply job writes anything.
|
|
125
|
+
*
|
|
126
|
+
* `dir` is the downloaded artifact under `runnerTemp`; `repo` is the apply
|
|
127
|
+
* job's own checkout of the trusted base, whose `trust.arbiter` remote is
|
|
128
|
+
* fetched fresh here. The steps, each a rejection ({@link HandoffRejected})
|
|
129
|
+
* naming its rule:
|
|
130
|
+
*
|
|
131
|
+
* 1. the artifact (`readHandoff`): layout, sizes, schema, `item` equal to the
|
|
132
|
+
* trusted item, an intent kind the trusted rung can produce;
|
|
133
|
+
* 2. the bundle's one ref must be `refs/heads/<workBranchRef(type, slug)>` of
|
|
134
|
+
* the trusted item, and its prerequisites must exist in the apply checkout;
|
|
135
|
+
* 3. in the quarantine: fetch that ref only, with `transfer.fsckObjects`;
|
|
136
|
+
* `baseSha` is an ancestor of the tip; the new set `tip ^<arbiter>/main` is
|
|
137
|
+
* non-empty, at most {@link MAX_NEW_COMMITS} and has no merge commit; per
|
|
138
|
+
* new commit, no protected path ({@link protectedPathOf}), no gitlink, no
|
|
139
|
+
* symlink resolving outside the repository, no blob over the limit;
|
|
140
|
+
* 4. the `work/` ledger rule on the net change: only this item's own
|
|
141
|
+
* transition and new `work/notes/*` files (ADRs live outside `work/`);
|
|
142
|
+
* anything else is rejected in `merge` mode and reported in `propose` mode;
|
|
143
|
+
* 5. the LFS rule (`checkLfsObjects`): every blob the new commits add or
|
|
144
|
+
* change that parses as a pointer (strict spec v1; a blob that only looks
|
|
145
|
+
* like one is rejected) needs its object in `lfs/`, of exactly its size and
|
|
146
|
+
* hashing to its oid; no object may be unreferenced; the size limit holds;
|
|
147
|
+
* 6. only then the bundle is fetched into the apply checkout at
|
|
148
|
+
* {@link INCOMING_TIP_REF}. Nothing is written to the apply checkout's LFS
|
|
149
|
+
* store here: the path split pushes {@link ApplyHandoff.lfsObjects} before
|
|
150
|
+
* any ref (`pushLfsObjects`).
|
|
151
|
+
*
|
|
152
|
+
* The integration mode is recomputed ({@link recomputeIntegrationMode}) before
|
|
153
|
+
* the ledger rule, which depends on it.
|
|
154
|
+
*/
|
|
155
|
+
export declare function validateApplyHandoff(params: {
|
|
156
|
+
dir: string;
|
|
157
|
+
runnerTemp: string;
|
|
158
|
+
repo: string;
|
|
159
|
+
trust: ApplyTrust;
|
|
160
|
+
env?: NodeJS.ProcessEnv;
|
|
161
|
+
}): ApplyHandoff;
|
|
162
|
+
//# sourceMappingURL=ci-handoff-apply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-handoff-apply.d.ts","sourceRoot":"","sources":["../src/ci-handoff-apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,aAAa,CAAC;AACjD,OAAO,EAGN,KAAK,WAAW,EAChB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEN,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,MAAM,iBAAiB,CAAC;AAmBzB,uEAAuE;AACvE,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAE1D,uEAAuE;AACvE,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,mEACiC,CAAC;AAiBlE;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAehE;AAMD,mEAAmE;AACnE,MAAM,WAAW,UAAU;IAC1B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,IAAI,EAAE,WAAW,CAAC;IAClB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,eAAe,EAAE,eAAe,CAAC;CACjC;AAED,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,IAAI,EAAE,eAAe,CAAC;IACtB,iFAAiF;IACjF,aAAa,EAAE,OAAO,CAAC;IACvB,yDAAyD;IACzD,MAAM,CAAC,EAAE;QACR,kEAAkE;QAClE,UAAU,EAAE,MAAM,CAAC;QACnB,gFAAgF;QAChF,GAAG,EAAE,MAAM,CAAC;QACZ,6DAA6D;QAC7D,UAAU,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF;;;;OAIG;IACH,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,0FAA0F;IAC1F,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAMD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,eAAe,CAAC;IACjC,2EAA2E;IAC3E,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB,GAAG;IAAC,IAAI,EAAE,eAAe,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAC,CAgBlD;AAMD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAqB1E;AAwUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB,GAAG,YAAY,CAwIf"}
|