dorfl 0.0.0 → 0.1.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.
Files changed (619) hide show
  1. package/dist/advance-ci-template.d.ts +73 -0
  2. package/dist/advance-ci-template.d.ts.map +1 -0
  3. package/dist/advance-ci-template.js +104 -0
  4. package/dist/advance-ci-template.js.map +1 -0
  5. package/dist/advance-classify.d.ts +132 -0
  6. package/dist/advance-classify.d.ts.map +1 -0
  7. package/dist/advance-classify.js +120 -0
  8. package/dist/advance-classify.js.map +1 -0
  9. package/dist/advance-drivers.d.ts +182 -0
  10. package/dist/advance-drivers.d.ts.map +1 -0
  11. package/dist/advance-drivers.js +231 -0
  12. package/dist/advance-drivers.js.map +1 -0
  13. package/dist/advance-isolated.d.ts +156 -0
  14. package/dist/advance-isolated.d.ts.map +1 -0
  15. package/dist/advance-isolated.js +256 -0
  16. package/dist/advance-isolated.js.map +1 -0
  17. package/dist/advance-lifecycle-template.d.ts +107 -0
  18. package/dist/advance-lifecycle-template.d.ts.map +1 -0
  19. package/dist/advance-lifecycle-template.js +668 -0
  20. package/dist/advance-lifecycle-template.js.map +1 -0
  21. package/dist/advance-loop-driver.d.ts +325 -0
  22. package/dist/advance-loop-driver.d.ts.map +1 -0
  23. package/dist/advance-loop-driver.js +437 -0
  24. package/dist/advance-loop-driver.js.map +1 -0
  25. package/dist/advance-treeless-publish.d.ts +108 -0
  26. package/dist/advance-treeless-publish.d.ts.map +1 -0
  27. package/dist/advance-treeless-publish.js +71 -0
  28. package/dist/advance-treeless-publish.js.map +1 -0
  29. package/dist/advance.d.ts +340 -0
  30. package/dist/advance.d.ts.map +1 -0
  31. package/dist/advance.js +1122 -0
  32. package/dist/advance.js.map +1 -0
  33. package/dist/advancing-lock.d.ts +294 -0
  34. package/dist/advancing-lock.d.ts.map +1 -0
  35. package/dist/advancing-lock.js +594 -0
  36. package/dist/advancing-lock.js.map +1 -0
  37. package/dist/agent-launch.d.ts +79 -0
  38. package/dist/agent-launch.d.ts.map +1 -0
  39. package/dist/agent-launch.js +61 -0
  40. package/dist/agent-launch.js.map +1 -0
  41. package/dist/agent-stop.d.ts +149 -0
  42. package/dist/agent-stop.d.ts.map +1 -0
  43. package/dist/agent-stop.js +307 -0
  44. package/dist/agent-stop.js.map +1 -0
  45. package/dist/apply-decide.d.ts +127 -0
  46. package/dist/apply-decide.d.ts.map +1 -0
  47. package/dist/apply-decide.js +176 -0
  48. package/dist/apply-decide.js.map +1 -0
  49. package/dist/apply-merge-action.d.ts +206 -0
  50. package/dist/apply-merge-action.d.ts.map +1 -0
  51. package/dist/apply-merge-action.js +307 -0
  52. package/dist/apply-merge-action.js.map +1 -0
  53. package/dist/apply-persist.d.ts +174 -0
  54. package/dist/apply-persist.d.ts.map +1 -0
  55. package/dist/apply-persist.js +359 -0
  56. package/dist/apply-persist.js.map +1 -0
  57. package/dist/arbiter.d.ts +120 -0
  58. package/dist/arbiter.d.ts.map +1 -0
  59. package/dist/arbiter.js +255 -0
  60. package/dist/arbiter.js.map +1 -0
  61. package/dist/brand.d.ts +70 -0
  62. package/dist/brand.d.ts.map +1 -0
  63. package/dist/brand.js +84 -0
  64. package/dist/brand.js.map +1 -0
  65. package/dist/buildable-body.d.ts +132 -0
  66. package/dist/buildable-body.d.ts.map +1 -0
  67. package/dist/buildable-body.js +131 -0
  68. package/dist/buildable-body.js.map +1 -0
  69. package/dist/categorise.d.ts +66 -0
  70. package/dist/categorise.d.ts.map +1 -0
  71. package/dist/categorise.js +106 -0
  72. package/dist/categorise.js.map +1 -0
  73. package/dist/claim-cas.d.ts +117 -0
  74. package/dist/claim-cas.d.ts.map +1 -0
  75. package/dist/claim-cas.js +312 -0
  76. package/dist/claim-cas.js.map +1 -0
  77. package/dist/cli-spinner.d.ts +112 -0
  78. package/dist/cli-spinner.d.ts.map +1 -0
  79. package/dist/cli-spinner.js +157 -0
  80. package/dist/cli-spinner.js.map +1 -0
  81. package/dist/cli.d.ts +11 -0
  82. package/dist/cli.d.ts.map +1 -0
  83. package/dist/cli.js +3094 -0
  84. package/dist/cli.js.map +1 -0
  85. package/dist/close-job-template.d.ts +70 -0
  86. package/dist/close-job-template.d.ts.map +1 -0
  87. package/dist/close-job-template.js +180 -0
  88. package/dist/close-job-template.js.map +1 -0
  89. package/dist/close-job.d.ts +95 -0
  90. package/dist/close-job.d.ts.map +1 -0
  91. package/dist/close-job.js +226 -0
  92. package/dist/close-job.js.map +1 -0
  93. package/dist/complete.d.ts +361 -0
  94. package/dist/complete.d.ts.map +1 -0
  95. package/dist/complete.js +885 -0
  96. package/dist/complete.js.map +1 -0
  97. package/dist/concurrency.d.ts +68 -0
  98. package/dist/concurrency.d.ts.map +1 -0
  99. package/dist/concurrency.js +112 -0
  100. package/dist/concurrency.js.map +1 -0
  101. package/dist/config-override.d.ts +76 -0
  102. package/dist/config-override.d.ts.map +1 -0
  103. package/dist/config-override.js +50 -0
  104. package/dist/config-override.js.map +1 -0
  105. package/dist/config.d.ts +668 -0
  106. package/dist/config.d.ts.map +1 -0
  107. package/dist/config.js +241 -0
  108. package/dist/config.js.map +1 -0
  109. package/dist/continue-branch.d.ts +249 -0
  110. package/dist/continue-branch.d.ts.map +1 -0
  111. package/dist/continue-branch.js +389 -0
  112. package/dist/continue-branch.js.map +1 -0
  113. package/dist/cwd-section.d.ts +186 -0
  114. package/dist/cwd-section.d.ts.map +1 -0
  115. package/dist/cwd-section.js +209 -0
  116. package/dist/cwd-section.js.map +1 -0
  117. package/dist/decision-engine.d.ts +170 -0
  118. package/dist/decision-engine.d.ts.map +1 -0
  119. package/dist/decision-engine.js +136 -0
  120. package/dist/decision-engine.js.map +1 -0
  121. package/dist/detect.d.ts +17 -0
  122. package/dist/detect.d.ts.map +1 -0
  123. package/dist/detect.js +118 -0
  124. package/dist/detect.js.map +1 -0
  125. package/dist/do-autopick.d.ts +85 -0
  126. package/dist/do-autopick.d.ts.map +1 -0
  127. package/dist/do-autopick.js +112 -0
  128. package/dist/do-autopick.js.map +1 -0
  129. package/dist/do-config.d.ts +312 -0
  130. package/dist/do-config.d.ts.map +1 -0
  131. package/dist/do-config.js +358 -0
  132. package/dist/do-config.js.map +1 -0
  133. package/dist/do-remote-auto.d.ts +75 -0
  134. package/dist/do-remote-auto.d.ts.map +1 -0
  135. package/dist/do-remote-auto.js +111 -0
  136. package/dist/do-remote-auto.js.map +1 -0
  137. package/dist/do.d.ts +621 -0
  138. package/dist/do.d.ts.map +1 -0
  139. package/dist/do.js +1882 -0
  140. package/dist/do.js.map +1 -0
  141. package/dist/drop-source.d.ts +96 -0
  142. package/dist/drop-source.d.ts.map +1 -0
  143. package/dist/drop-source.js +91 -0
  144. package/dist/drop-source.js.map +1 -0
  145. package/dist/eligibility.d.ts +46 -0
  146. package/dist/eligibility.d.ts.map +1 -0
  147. package/dist/eligibility.js +34 -0
  148. package/dist/eligibility.js.map +1 -0
  149. package/dist/env-config.d.ts +51 -0
  150. package/dist/env-config.d.ts.map +1 -0
  151. package/dist/env-config.js +272 -0
  152. package/dist/env-config.js.map +1 -0
  153. package/dist/failure-cause.d.ts +70 -0
  154. package/dist/failure-cause.d.ts.map +1 -0
  155. package/dist/failure-cause.js +126 -0
  156. package/dist/failure-cause.js.map +1 -0
  157. package/dist/format.d.ts +43 -0
  158. package/dist/format.d.ts.map +1 -0
  159. package/dist/format.js +256 -0
  160. package/dist/format.js.map +1 -0
  161. package/dist/frontmatter.d.ts +215 -0
  162. package/dist/frontmatter.d.ts.map +1 -0
  163. package/dist/frontmatter.js +345 -0
  164. package/dist/frontmatter.js.map +1 -0
  165. package/dist/gate-readiness.d.ts +84 -0
  166. package/dist/gate-readiness.d.ts.map +1 -0
  167. package/dist/gate-readiness.js +103 -0
  168. package/dist/gate-readiness.js.map +1 -0
  169. package/dist/gc.d.ts +165 -0
  170. package/dist/gc.d.ts.map +1 -0
  171. package/dist/gc.js +313 -0
  172. package/dist/gc.js.map +1 -0
  173. package/dist/gh-failure.d.ts +42 -0
  174. package/dist/gh-failure.d.ts.map +1 -0
  175. package/dist/gh-failure.js +49 -0
  176. package/dist/gh-failure.js.map +1 -0
  177. package/dist/git.d.ts +75 -0
  178. package/dist/git.d.ts.map +1 -0
  179. package/dist/git.js +130 -0
  180. package/dist/git.js.map +1 -0
  181. package/dist/github.d.ts +187 -0
  182. package/dist/github.d.ts.map +1 -0
  183. package/dist/github.js +343 -0
  184. package/dist/github.js.map +1 -0
  185. package/dist/harness.d.ts +242 -0
  186. package/dist/harness.d.ts.map +1 -0
  187. package/dist/harness.js +157 -0
  188. package/dist/harness.js.map +1 -0
  189. package/dist/identity.d.ts +167 -0
  190. package/dist/identity.d.ts.map +1 -0
  191. package/dist/identity.js +231 -0
  192. package/dist/identity.js.map +1 -0
  193. package/dist/index.d.ts +147 -0
  194. package/dist/index.d.ts.map +1 -0
  195. package/dist/index.js +76 -0
  196. package/dist/index.js.map +1 -0
  197. package/dist/install-ci-branch-protection.d.ts +147 -0
  198. package/dist/install-ci-branch-protection.d.ts.map +1 -0
  199. package/dist/install-ci-branch-protection.js +166 -0
  200. package/dist/install-ci-branch-protection.js.map +1 -0
  201. package/dist/install-ci-capabilities/advance-lifecycle.d.ts +15 -0
  202. package/dist/install-ci-capabilities/advance-lifecycle.d.ts.map +1 -0
  203. package/dist/install-ci-capabilities/advance-lifecycle.js +28 -0
  204. package/dist/install-ci-capabilities/advance-lifecycle.js.map +1 -0
  205. package/dist/install-ci-capabilities/close-job.d.ts +13 -0
  206. package/dist/install-ci-capabilities/close-job.d.ts.map +1 -0
  207. package/dist/install-ci-capabilities/close-job.js +26 -0
  208. package/dist/install-ci-capabilities/close-job.js.map +1 -0
  209. package/dist/install-ci-capabilities/example-noop.d.ts +16 -0
  210. package/dist/install-ci-capabilities/example-noop.d.ts.map +1 -0
  211. package/dist/install-ci-capabilities/example-noop.js +23 -0
  212. package/dist/install-ci-capabilities/example-noop.js.map +1 -0
  213. package/dist/install-ci-capabilities/intake.d.ts +15 -0
  214. package/dist/install-ci-capabilities/intake.d.ts.map +1 -0
  215. package/dist/install-ci-capabilities/intake.js +28 -0
  216. package/dist/install-ci-capabilities/intake.js.map +1 -0
  217. package/dist/install-ci-capabilities/verify.d.ts +14 -0
  218. package/dist/install-ci-capabilities/verify.d.ts.map +1 -0
  219. package/dist/install-ci-capabilities/verify.js +27 -0
  220. package/dist/install-ci-capabilities/verify.js.map +1 -0
  221. package/dist/install-ci-core.d.ts +446 -0
  222. package/dist/install-ci-core.d.ts.map +1 -0
  223. package/dist/install-ci-core.js +760 -0
  224. package/dist/install-ci-core.js.map +1 -0
  225. package/dist/install-ci-github.d.ts +167 -0
  226. package/dist/install-ci-github.d.ts.map +1 -0
  227. package/dist/install-ci-github.js +315 -0
  228. package/dist/install-ci-github.js.map +1 -0
  229. package/dist/install-ci.d.ts +105 -0
  230. package/dist/install-ci.d.ts.map +1 -0
  231. package/dist/install-ci.js +363 -0
  232. package/dist/install-ci.js.map +1 -0
  233. package/dist/intake-event.d.ts +88 -0
  234. package/dist/intake-event.d.ts.map +1 -0
  235. package/dist/intake-event.js +66 -0
  236. package/dist/intake-event.js.map +1 -0
  237. package/dist/intake-marker.d.ts +95 -0
  238. package/dist/intake-marker.d.ts.map +1 -0
  239. package/dist/intake-marker.js +127 -0
  240. package/dist/intake-marker.js.map +1 -0
  241. package/dist/intake-triage.d.ts +48 -0
  242. package/dist/intake-triage.d.ts.map +1 -0
  243. package/dist/intake-triage.js +95 -0
  244. package/dist/intake-triage.js.map +1 -0
  245. package/dist/intake-trigger-template.d.ts +185 -0
  246. package/dist/intake-trigger-template.d.ts.map +1 -0
  247. package/dist/intake-trigger-template.js +449 -0
  248. package/dist/intake-trigger-template.js.map +1 -0
  249. package/dist/intake.d.ts +569 -0
  250. package/dist/intake.d.ts.map +1 -0
  251. package/dist/intake.js +1628 -0
  252. package/dist/intake.js.map +1 -0
  253. package/dist/integration-core.d.ts +539 -0
  254. package/dist/integration-core.d.ts.map +1 -0
  255. package/dist/integration-core.js +2195 -0
  256. package/dist/integration-core.js.map +1 -0
  257. package/dist/integrator.d.ts +343 -0
  258. package/dist/integrator.d.ts.map +1 -0
  259. package/dist/integrator.js +400 -0
  260. package/dist/integrator.js.map +1 -0
  261. package/dist/isolation.d.ts +219 -0
  262. package/dist/isolation.d.ts.map +1 -0
  263. package/dist/isolation.js +261 -0
  264. package/dist/isolation.js.map +1 -0
  265. package/dist/issue-provider.d.ts +349 -0
  266. package/dist/issue-provider.d.ts.map +1 -0
  267. package/dist/issue-provider.js +360 -0
  268. package/dist/issue-provider.js.map +1 -0
  269. package/dist/item-lock.d.ts +626 -0
  270. package/dist/item-lock.d.ts.map +1 -0
  271. package/dist/item-lock.js +1381 -0
  272. package/dist/item-lock.js.map +1 -0
  273. package/dist/item-path.d.ts +49 -0
  274. package/dist/item-path.d.ts.map +1 -0
  275. package/dist/item-path.js +66 -0
  276. package/dist/item-path.js.map +1 -0
  277. package/dist/ledger-lint.d.ts +129 -0
  278. package/dist/ledger-lint.d.ts.map +1 -0
  279. package/dist/ledger-lint.js +249 -0
  280. package/dist/ledger-lint.js.map +1 -0
  281. package/dist/ledger-read.d.ts +357 -0
  282. package/dist/ledger-read.d.ts.map +1 -0
  283. package/dist/ledger-read.js +442 -0
  284. package/dist/ledger-read.js.map +1 -0
  285. package/dist/ledger-write.d.ts +330 -0
  286. package/dist/ledger-write.d.ts.map +1 -0
  287. package/dist/ledger-write.js +411 -0
  288. package/dist/ledger-write.js.map +1 -0
  289. package/dist/lifecycle-gather.d.ts +30 -0
  290. package/dist/lifecycle-gather.d.ts.map +1 -0
  291. package/dist/lifecycle-gather.js +205 -0
  292. package/dist/lifecycle-gather.js.map +1 -0
  293. package/dist/lifecycle-pools.d.ts +180 -0
  294. package/dist/lifecycle-pools.d.ts.map +1 -0
  295. package/dist/lifecycle-pools.js +78 -0
  296. package/dist/lifecycle-pools.js.map +1 -0
  297. package/dist/merge-question-surfacer.d.ts +166 -0
  298. package/dist/merge-question-surfacer.d.ts.map +1 -0
  299. package/dist/merge-question-surfacer.js +297 -0
  300. package/dist/merge-question-surfacer.js.map +1 -0
  301. package/dist/mint-adr.d.ts +126 -0
  302. package/dist/mint-adr.d.ts.map +1 -0
  303. package/dist/mint-adr.js +257 -0
  304. package/dist/mint-adr.js.map +1 -0
  305. package/dist/mirror-pool-scan.d.ts +125 -0
  306. package/dist/mirror-pool-scan.d.ts.map +1 -0
  307. package/dist/mirror-pool-scan.js +104 -0
  308. package/dist/mirror-pool-scan.js.map +1 -0
  309. package/dist/needs-attention.d.ts +341 -0
  310. package/dist/needs-attention.d.ts.map +1 -0
  311. package/dist/needs-attention.js +900 -0
  312. package/dist/needs-attention.js.map +1 -0
  313. package/dist/orphan-sidecar.d.ts +79 -0
  314. package/dist/orphan-sidecar.d.ts.map +1 -0
  315. package/dist/orphan-sidecar.js +71 -0
  316. package/dist/orphan-sidecar.js.map +1 -0
  317. package/dist/output.d.ts +48 -0
  318. package/dist/output.d.ts.map +1 -0
  319. package/dist/output.js +66 -0
  320. package/dist/output.js.map +1 -0
  321. package/dist/pi-harness.d.ts +179 -0
  322. package/dist/pi-harness.d.ts.map +1 -0
  323. package/dist/pi-harness.js +342 -0
  324. package/dist/pi-harness.js.map +1 -0
  325. package/dist/placement.d.ts +99 -0
  326. package/dist/placement.d.ts.map +1 -0
  327. package/dist/placement.js +67 -0
  328. package/dist/placement.js.map +1 -0
  329. package/dist/prd-to-spec.d.ts +315 -0
  330. package/dist/prd-to-spec.d.ts.map +1 -0
  331. package/dist/prd-to-spec.js +684 -0
  332. package/dist/prd-to-spec.js.map +1 -0
  333. package/dist/prepare.d.ts +121 -0
  334. package/dist/prepare.d.ts.map +1 -0
  335. package/dist/prepare.js +140 -0
  336. package/dist/prepare.js.map +1 -0
  337. package/dist/prompt.d.ts +360 -0
  338. package/dist/prompt.d.ts.map +1 -0
  339. package/dist/prompt.js +499 -0
  340. package/dist/prompt.js.map +1 -0
  341. package/dist/protocol/ADR-FORMAT.md +47 -0
  342. package/dist/protocol/CLAIM-PROTOCOL.md +217 -0
  343. package/dist/protocol/REVIEW-PROTOCOL.md +119 -0
  344. package/dist/protocol/SURFACE-PROTOCOL.md +121 -0
  345. package/dist/protocol/TASKING-PROTOCOL.md +122 -0
  346. package/dist/protocol/WORK-CONTRACT.md +276 -0
  347. package/dist/protocol/spec-template.md +71 -0
  348. package/dist/protocol/task-template.md +65 -0
  349. package/dist/readiness.d.ts +66 -0
  350. package/dist/readiness.d.ts.map +1 -0
  351. package/dist/readiness.js +36 -0
  352. package/dist/readiness.js.map +1 -0
  353. package/dist/reap-branches.d.ts +102 -0
  354. package/dist/reap-branches.d.ts.map +1 -0
  355. package/dist/reap-branches.js +149 -0
  356. package/dist/reap-branches.js.map +1 -0
  357. package/dist/recover-isolated.d.ts +72 -0
  358. package/dist/recover-isolated.d.ts.map +1 -0
  359. package/dist/recover-isolated.js +188 -0
  360. package/dist/recover-isolated.js.map +1 -0
  361. package/dist/registry.d.ts +172 -0
  362. package/dist/registry.d.ts.map +1 -0
  363. package/dist/registry.js +296 -0
  364. package/dist/registry.js.map +1 -0
  365. package/dist/repo-config.d.ts +201 -0
  366. package/dist/repo-config.d.ts.map +1 -0
  367. package/dist/repo-config.js +414 -0
  368. package/dist/repo-config.js.map +1 -0
  369. package/dist/repo-key.d.ts +20 -0
  370. package/dist/repo-key.d.ts.map +1 -0
  371. package/dist/repo-key.js +68 -0
  372. package/dist/repo-key.js.map +1 -0
  373. package/dist/repo-mirror.d.ts +177 -0
  374. package/dist/repo-mirror.d.ts.map +1 -0
  375. package/dist/repo-mirror.js +271 -0
  376. package/dist/repo-mirror.js.map +1 -0
  377. package/dist/retry-backoff.d.ts +90 -0
  378. package/dist/retry-backoff.d.ts.map +1 -0
  379. package/dist/retry-backoff.js +98 -0
  380. package/dist/retry-backoff.js.map +1 -0
  381. package/dist/review-gate.d.ts +173 -0
  382. package/dist/review-gate.d.ts.map +1 -0
  383. package/dist/review-gate.js +261 -0
  384. package/dist/review-gate.js.map +1 -0
  385. package/dist/review-verdict.d.ts +149 -0
  386. package/dist/review-verdict.d.ts.map +1 -0
  387. package/dist/review-verdict.js +332 -0
  388. package/dist/review-verdict.js.map +1 -0
  389. package/dist/run.d.ts +221 -0
  390. package/dist/run.d.ts.map +1 -0
  391. package/dist/run.js +963 -0
  392. package/dist/run.js.map +1 -0
  393. package/dist/scan.d.ts +308 -0
  394. package/dist/scan.d.ts.map +1 -0
  395. package/dist/scan.js +374 -0
  396. package/dist/scan.js.map +1 -0
  397. package/dist/select-order.d.ts +75 -0
  398. package/dist/select-order.d.ts.map +1 -0
  399. package/dist/select-order.js +108 -0
  400. package/dist/select-order.js.map +1 -0
  401. package/dist/select-priority.d.ts +188 -0
  402. package/dist/select-priority.d.ts.map +1 -0
  403. package/dist/select-priority.js +80 -0
  404. package/dist/select-priority.js.map +1 -0
  405. package/dist/select.d.ts +25 -0
  406. package/dist/select.d.ts.map +1 -0
  407. package/dist/select.js +43 -0
  408. package/dist/select.js.map +1 -0
  409. package/dist/session-path.d.ts +36 -0
  410. package/dist/session-path.d.ts.map +1 -0
  411. package/dist/session-path.js +129 -0
  412. package/dist/session-path.js.map +1 -0
  413. package/dist/sidecar-apply.d.ts +83 -0
  414. package/dist/sidecar-apply.d.ts.map +1 -0
  415. package/dist/sidecar-apply.js +111 -0
  416. package/dist/sidecar-apply.js.map +1 -0
  417. package/dist/sidecar.d.ts +245 -0
  418. package/dist/sidecar.d.ts.map +1 -0
  419. package/dist/sidecar.js +481 -0
  420. package/dist/sidecar.js.map +1 -0
  421. package/dist/slug-namespace.d.ts +204 -0
  422. package/dist/slug-namespace.d.ts.map +1 -0
  423. package/dist/slug-namespace.js +229 -0
  424. package/dist/slug-namespace.js.map +1 -0
  425. package/dist/spec-complete.d.ts +44 -0
  426. package/dist/spec-complete.d.ts.map +1 -0
  427. package/dist/spec-complete.js +69 -0
  428. package/dist/spec-complete.js.map +1 -0
  429. package/dist/start.d.ts +97 -0
  430. package/dist/start.d.ts.map +1 -0
  431. package/dist/start.js +633 -0
  432. package/dist/start.js.map +1 -0
  433. package/dist/status.d.ts +199 -0
  434. package/dist/status.d.ts.map +1 -0
  435. package/dist/status.js +228 -0
  436. package/dist/status.js.map +1 -0
  437. package/dist/surface-gate.d.ts +162 -0
  438. package/dist/surface-gate.d.ts.map +1 -0
  439. package/dist/surface-gate.js +206 -0
  440. package/dist/surface-gate.js.map +1 -0
  441. package/dist/surface-persist.d.ts +86 -0
  442. package/dist/surface-persist.d.ts.map +1 -0
  443. package/dist/surface-persist.js +129 -0
  444. package/dist/surface-persist.js.map +1 -0
  445. package/dist/tasker-review-loop.d.ts +249 -0
  446. package/dist/tasker-review-loop.d.ts.map +1 -0
  447. package/dist/tasker-review-loop.js +369 -0
  448. package/dist/tasker-review-loop.js.map +1 -0
  449. package/dist/tasking-eligibility.d.ts +74 -0
  450. package/dist/tasking-eligibility.d.ts.map +1 -0
  451. package/dist/tasking-eligibility.js +52 -0
  452. package/dist/tasking-eligibility.js.map +1 -0
  453. package/dist/tasking-lock.d.ts +111 -0
  454. package/dist/tasking-lock.d.ts.map +1 -0
  455. package/dist/tasking-lock.js +256 -0
  456. package/dist/tasking-lock.js.map +1 -0
  457. package/dist/tasking.d.ts +275 -0
  458. package/dist/tasking.d.ts.map +1 -0
  459. package/dist/tasking.js +952 -0
  460. package/dist/tasking.js.map +1 -0
  461. package/dist/triage-gate.d.ts +127 -0
  462. package/dist/triage-gate.d.ts.map +1 -0
  463. package/dist/triage-gate.js +139 -0
  464. package/dist/triage-gate.js.map +1 -0
  465. package/dist/triage-persist.d.ts +163 -0
  466. package/dist/triage-persist.d.ts.map +1 -0
  467. package/dist/triage-persist.js +387 -0
  468. package/dist/triage-persist.js.map +1 -0
  469. package/dist/verdict-json.d.ts +32 -0
  470. package/dist/verdict-json.d.ts.map +1 -0
  471. package/dist/verdict-json.js +74 -0
  472. package/dist/verdict-json.js.map +1 -0
  473. package/dist/verify-workflow-template.d.ts +60 -0
  474. package/dist/verify-workflow-template.d.ts.map +1 -0
  475. package/dist/verify-workflow-template.js +126 -0
  476. package/dist/verify-workflow-template.js.map +1 -0
  477. package/dist/verify.d.ts +60 -0
  478. package/dist/verify.d.ts.map +1 -0
  479. package/dist/verify.js +62 -0
  480. package/dist/verify.js.map +1 -0
  481. package/dist/watch-session.d.ts +112 -0
  482. package/dist/watch-session.d.ts.map +1 -0
  483. package/dist/watch-session.js +347 -0
  484. package/dist/watch-session.js.map +1 -0
  485. package/dist/work-layout.d.ts +198 -0
  486. package/dist/work-layout.d.ts.map +1 -0
  487. package/dist/work-layout.js +217 -0
  488. package/dist/work-layout.js.map +1 -0
  489. package/dist/work-on.d.ts +154 -0
  490. package/dist/work-on.d.ts.map +1 -0
  491. package/dist/work-on.js +387 -0
  492. package/dist/work-on.js.map +1 -0
  493. package/dist/workspace.d.ts +224 -0
  494. package/dist/workspace.d.ts.map +1 -0
  495. package/dist/workspace.js +325 -0
  496. package/dist/workspace.js.map +1 -0
  497. package/package.json +46 -2
  498. package/src/advance-ci-template.ts +203 -0
  499. package/src/advance-classify.ts +197 -0
  500. package/src/advance-drivers.ts +414 -0
  501. package/src/advance-isolated.ts +432 -0
  502. package/src/advance-lifecycle-template.ts +791 -0
  503. package/src/advance-loop-driver.ts +745 -0
  504. package/src/advance-treeless-publish.ts +177 -0
  505. package/src/advance.ts +1564 -0
  506. package/src/advancing-lock.ts +988 -0
  507. package/src/agent-launch.ts +137 -0
  508. package/src/agent-stop.ts +361 -0
  509. package/src/apply-decide.ts +242 -0
  510. package/src/apply-merge-action.ts +502 -0
  511. package/src/apply-persist.ts +518 -0
  512. package/src/arbiter.ts +372 -0
  513. package/src/brand.ts +111 -0
  514. package/src/buildable-body.ts +196 -0
  515. package/src/categorise.ts +158 -0
  516. package/src/claim-cas.ts +513 -0
  517. package/src/cli-spinner.ts +225 -0
  518. package/src/cli.ts +4369 -0
  519. package/src/close-job-template.ts +236 -0
  520. package/src/close-job.ts +319 -0
  521. package/src/complete.ts +1379 -0
  522. package/src/concurrency.ts +151 -0
  523. package/src/config-override.ts +116 -0
  524. package/src/config.ts +883 -0
  525. package/src/continue-branch.ts +542 -0
  526. package/src/cwd-section.ts +392 -0
  527. package/src/decision-engine.ts +272 -0
  528. package/src/detect.ts +124 -0
  529. package/src/do-autopick.ts +223 -0
  530. package/src/do-config.ts +589 -0
  531. package/src/do-remote-auto.ts +197 -0
  532. package/src/do.ts +2623 -0
  533. package/src/drop-source.ts +194 -0
  534. package/src/eligibility.ts +79 -0
  535. package/src/env-config.ts +305 -0
  536. package/src/failure-cause.ts +142 -0
  537. package/src/format.ts +313 -0
  538. package/src/frontmatter.ts +485 -0
  539. package/src/gate-readiness.ts +147 -0
  540. package/src/gc.ts +510 -0
  541. package/src/gh-failure.ts +53 -0
  542. package/src/git.ts +186 -0
  543. package/src/github.ts +468 -0
  544. package/src/harness.ts +355 -0
  545. package/src/identity.ts +322 -0
  546. package/src/index.ts +785 -0
  547. package/src/install-ci-branch-protection.ts +255 -0
  548. package/src/install-ci-capabilities/advance-lifecycle.ts +34 -0
  549. package/src/install-ci-capabilities/close-job.ts +32 -0
  550. package/src/install-ci-capabilities/example-noop.ts +24 -0
  551. package/src/install-ci-capabilities/intake.ts +34 -0
  552. package/src/install-ci-capabilities/verify.ts +33 -0
  553. package/src/install-ci-core.ts +1088 -0
  554. package/src/install-ci-github.ts +376 -0
  555. package/src/install-ci.ts +552 -0
  556. package/src/intake-event.ts +102 -0
  557. package/src/intake-marker.ts +195 -0
  558. package/src/intake-triage.ts +138 -0
  559. package/src/intake-trigger-template.ts +591 -0
  560. package/src/intake.ts +2445 -0
  561. package/src/integration-core.ts +3065 -0
  562. package/src/integrator.ts +771 -0
  563. package/src/isolation.ts +484 -0
  564. package/src/issue-provider.ts +733 -0
  565. package/src/item-lock.ts +1858 -0
  566. package/src/item-path.ts +75 -0
  567. package/src/ledger-lint.ts +332 -0
  568. package/src/ledger-read.ts +924 -0
  569. package/src/ledger-write.ts +865 -0
  570. package/src/lifecycle-gather.ts +298 -0
  571. package/src/lifecycle-pools.ts +250 -0
  572. package/src/merge-question-surfacer.ts +496 -0
  573. package/src/mint-adr.ts +362 -0
  574. package/src/mirror-pool-scan.ts +240 -0
  575. package/src/needs-attention.ts +1506 -0
  576. package/src/orphan-sidecar.ts +150 -0
  577. package/src/output.ts +89 -0
  578. package/src/pi-harness.ts +403 -0
  579. package/src/placement.ts +131 -0
  580. package/src/prd-to-spec.ts +1023 -0
  581. package/src/prepare.ts +230 -0
  582. package/src/prompt.ts +760 -0
  583. package/src/readiness.ts +98 -0
  584. package/src/reap-branches.ts +278 -0
  585. package/src/recover-isolated.ts +276 -0
  586. package/src/registry.ts +475 -0
  587. package/src/repo-config.ts +550 -0
  588. package/src/repo-key.ts +74 -0
  589. package/src/repo-mirror.ts +367 -0
  590. package/src/retry-backoff.ts +130 -0
  591. package/src/review-gate.ts +389 -0
  592. package/src/review-verdict.ts +422 -0
  593. package/src/run.ts +1430 -0
  594. package/src/scan.ts +611 -0
  595. package/src/select-order.ts +143 -0
  596. package/src/select-priority.ts +266 -0
  597. package/src/select.ts +62 -0
  598. package/src/session-path.ts +153 -0
  599. package/src/sidecar-apply.ts +216 -0
  600. package/src/sidecar.ts +700 -0
  601. package/src/slug-namespace.ts +367 -0
  602. package/src/spec-complete.ts +118 -0
  603. package/src/start.ts +974 -0
  604. package/src/status.ts +441 -0
  605. package/src/surface-gate.ts +337 -0
  606. package/src/surface-persist.ts +241 -0
  607. package/src/tasker-review-loop.ts +671 -0
  608. package/src/tasking-eligibility.ts +114 -0
  609. package/src/tasking-lock.ts +416 -0
  610. package/src/tasking.ts +1438 -0
  611. package/src/triage-gate.ts +248 -0
  612. package/src/triage-persist.ts +570 -0
  613. package/src/verdict-json.ts +73 -0
  614. package/src/verify-workflow-template.ts +159 -0
  615. package/src/verify.ts +123 -0
  616. package/src/watch-session.ts +397 -0
  617. package/src/work-layout.ts +262 -0
  618. package/src/work-on.ts +660 -0
  619. package/src/workspace.ts +502 -0
package/dist/run.js ADDED
@@ -0,0 +1,963 @@
1
+ import { resolvePromptGuidance } from './config.js';
2
+ import { resolveRepoConfig } from './repo-config.js';
3
+ import { scan } from './scan.js';
4
+ import { selectCandidates } from './select.js';
5
+ import { performClaim } from './claim-cas.js';
6
+ import { updateJobRecord, encodeWorkId } from './workspace.js';
7
+ import { encodeRepoKey } from './repo-mirror.js';
8
+ import { run as runProcess } from './git.js';
9
+ import { mkdirSync, readFileSync, rmSync } from 'node:fs';
10
+ import { ledgerWrite } from './ledger-write.js';
11
+ import { jobWorktreeStrategy, } from './isolation.js';
12
+ import { runConcurrent, createKeyedLock } from './concurrency.js';
13
+ import { createHarness } from './pi-harness.js';
14
+ import { generateSessionPath } from './session-path.js';
15
+ import { resolveTask, buildAgentPrompt, resolveContinueContext, resolvePromptGuidanceForItem, PromptError, } from './prompt.js';
16
+ import { parseStopSentinel, isWorkBranchDiffEmpty, emptyDiffStopReason, } from './agent-stop.js';
17
+ import { classifyFailureCause, failureCauseLabel, } from './failure-cause.js';
18
+ import { performIntegration } from './integration-core.js';
19
+ import { shouldFailProposePrIntent, PROPOSE_PR_INTENT_GH_UNAVAILABLE_MESSAGE, } from './do-config.js';
20
+ import { checkGatePreconditions, detectLockfileOnDisk, detectLockfileOnMirrorMain, } from './gate-readiness.js';
21
+ import { isGitHubArbiterUrl, GitHubProvider } from './github.js';
22
+ import { identityEnv, assertTransportAllowed } from './identity.js';
23
+ import { tmpdir } from 'node:os';
24
+ import { join, dirname } from 'node:path';
25
+ /** Is `repoPath` a BARE git repository (a registry hub mirror has no work tree)? */
26
+ function isBareRepo(repoPath, env) {
27
+ const result = runProcess('git', ['rev-parse', '--is-bare-repository'], repoPath, { env });
28
+ return result.status === 0 && result.stdout.trim() === 'true';
29
+ }
30
+ /**
31
+ * Claim a slug against a repo that may be EITHER a working checkout (the in-place
32
+ * test/`do` path) OR a BARE registry hub mirror (`run`'s production discovery).
33
+ *
34
+ * The claim CAS needs a NON-bare checkout with an `origin/main` tracking ref and
35
+ * a work tree to commit in (a bare mirror cannot `git mv`/`git commit`). So for a
36
+ * bare mirror we clone it into a throwaway claim dir under `workspace` and claim
37
+ * THERE against `origin` (the mirror URL) — the EXACT pattern `do --remote` uses
38
+ * (`do.ts` §2–3). For a non-bare checkout we claim in place against the configured
39
+ * arbiter remote, unchanged. The returned `fromRepo` is what the job-worktree
40
+ * strategy then resolves the mirror off (the claim clone, or the checkout).
41
+ */
42
+ async function claimAgainstRepo(opts) {
43
+ const { slug, repoPath, workspace, arbiter, env } = opts;
44
+ if (!isBareRepo(repoPath, env)) {
45
+ // In-place checkout: claim directly against the configured arbiter remote.
46
+ const claim = await performClaim({ slug, cwd: repoPath, arbiter, env });
47
+ return {
48
+ claim,
49
+ fromRepo: repoPath,
50
+ strategyArbiter: arbiter,
51
+ cleanup: () => { },
52
+ };
53
+ }
54
+ // Bare hub mirror (the registry): clone it into a throwaway claim dir and claim
55
+ // there against `origin` (the mirror URL = the arbiter). Keyed per slug so two
56
+ // in-flight jobs in the same mirror get DISTINCT claim clones (worktree
57
+ // isolation — no shared mutable state across in-flight jobs).
58
+ const mirrorUrl = runProcess('git', ['remote', 'get-url', 'origin'], repoPath, {
59
+ env,
60
+ }).stdout.trim();
61
+ const url = mirrorUrl !== '' ? mirrorUrl : `file://${repoPath}`;
62
+ const claimDir = join(workspace, 'claim', `${encodeRepoKey(url).split('/').join('__')}__${slug}`);
63
+ rmSync(claimDir, { recursive: true, force: true });
64
+ mkdirSync(dirname(claimDir), { recursive: true });
65
+ runProcess('git', ['clone', '--quiet', url, claimDir], dirname(claimDir), {
66
+ env,
67
+ });
68
+ const claim = await performClaim({
69
+ slug,
70
+ cwd: claimDir,
71
+ arbiter: 'origin',
72
+ env,
73
+ });
74
+ return {
75
+ claim,
76
+ fromRepo: claimDir,
77
+ // Inside the clone the arbiter is `origin` (the mirror URL).
78
+ strategyArbiter: 'origin',
79
+ cleanup: () => rmSync(claimDir, { recursive: true, force: true }),
80
+ };
81
+ }
82
+ /**
83
+ * Resolve the arbiter URL for `repoPath` PRE-CLAIM, the SAME way
84
+ * {@link claimAgainstRepo} derives the claim target. A BARE registry hub mirror's
85
+ * arbiter is its `origin` remote URL (falling back to `file://${repoPath}` when it
86
+ * has none); a working CHECKOUT's arbiter is the configured `arbiter` remote URL
87
+ * (falling back to `file://${repoPath}`). Used by the PR-INTENT pre-flight guard
88
+ * to know whether the arbiter is GitHub BEFORE the claim — it must not claim then
89
+ * refuse (that would strand the item in-progress on main). Read-only; mutates
90
+ * nothing.
91
+ */
92
+ function arbiterUrlForRepo(opts) {
93
+ const { repoPath, arbiter, env } = opts;
94
+ const remote = isBareRepo(repoPath, env) ? 'origin' : arbiter;
95
+ const res = runProcess('git', ['remote', 'get-url', remote], repoPath, { env });
96
+ const url = res.status === 0 ? res.stdout.trim() : '';
97
+ return url !== '' ? url : `file://${repoPath}`;
98
+ }
99
+ /**
100
+ * Run one supervised tick: claim up to `maxParallel` eligible items
101
+ * (≤ `perRepoMax` per repo), run the agent on each in an isolated **job
102
+ * worktree** (the shared execution substrate — hub mirror + worktree + seams),
103
+ * gate on acceptance tests, rebase onto the latest arbiter main, and integrate
104
+ * the green ones. The runner owns EVERY git-state transition (claim, done-move,
105
+ * completion commit, integration); the agent only edits code. A lost race (claim
106
+ * exit 2) is skipped cleanly; failing work never reaches `work/done/`; a rebase
107
+ * conflict is aborted and routed to needs-attention (ADR §10).
108
+ */
109
+ export async function runOnce(options) {
110
+ const config = options.config;
111
+ // Default discovery is the REGISTRY (the hub-mirror set, ADR §1) — the reframe
112
+ // that landed in `run-daemon-reframe` (work/done/). Callers that still operate
113
+ // on WORKING CHECKOUTS (the CLI / its tests) inject an explicit `report` built
114
+ // from working-tree paths ({@link scanRepoPaths}); without an injected report
115
+ // we fall back to the registry scan (async).
116
+ const report = options.report ?? (await scan(config, { override: options.override }));
117
+ const candidates = selectCandidates(report, {
118
+ maxParallel: config.maxParallel,
119
+ perRepoMax: config.perRepoMax,
120
+ });
121
+ // The launch harness: an explicit injection wins (tests); otherwise build the
122
+ // adapter the config selects (`harness: 'pi'` ⇒ the pi CLI; default ⇒ null,
123
+ // shelling out to `agentCmd`). pi specifics stay behind the seam.
124
+ const harness = options.harness ??
125
+ createHarness({ harness: config.harness, piBin: config.piBin });
126
+ // An explicitly-injected provider INSTANCE (tests / embedding) wins over
127
+ // per-item auto-detection; otherwise each item selects its own provider PURELY
128
+ // from its arbiter URL (see runOneItem). This is the resolved provider OBJECT,
129
+ // not a config override (there is none — the provider is arbiter-derived).
130
+ const provider = options.provider;
131
+ const workspace = options.workspace ?? config.workspacesDir;
132
+ const env = options.env;
133
+ // The per-repo claim serialiser: the ONLY shared-working-tree step in the
134
+ // otherwise-concurrent tick is the claim (it prepares its micro-commit in the
135
+ // repo's checkout/mirror). Two concurrent claims in ONE repo would corrupt each
136
+ // other's HEAD/index, so we serialise the CLAIM per repo (cheap — mv + commit +
137
+ // CAS push) while the agent run + the rebase-or-abort integration stay fully
138
+ // concurrent in each job's OWN worktree. Distinct repos claim in parallel.
139
+ const claimLock = createKeyedLock();
140
+ // The per-repo INTEGRATE serialiser — the SIBLING of `claimLock`, the same
141
+ // `createKeyedLock` primitive keyed on the same repo key. The land-on-`main`
142
+ // TAIL of merge-mode integration (fetch+rebase → `${branch}:main` push) is a
143
+ // shared-`main` step: two concurrent SAME-repo merge jobs both rebase onto the
144
+ // same pre-merge base and the loser's plain push is non-fast-forward (today it
145
+ // only works by benign timing). Serialising ONLY that tail per repo (the seam
146
+ // is applied INSIDE `performIntegration`, around step 4–5, NOT the whole call —
147
+ // the slow gate + Gate-2 review stay at the front, OUTSIDE the lock, so they
148
+ // run concurrently) makes the loser re-fetch + rebase onto the winner's
149
+ // now-advanced main, so its push is a clean fast-forward. Distinct repos
150
+ // integrate in parallel (per-repo key); a genuine same-repo code conflict
151
+ // routes exactly ONE job to needs-attention (it cannot both-land).
152
+ //
153
+ // This lock is the SIBLING-INTEGRATE serialiser ONLY. It does NOT cover the
154
+ // claim-vs-integrate race: a sibling same-repo CLAIM advances `<arbiter>/main`
155
+ // under the SEPARATE `claimLock` (above), which can land INSIDE this job's
156
+ // integrate push window. That is closed independently by the integrator's
157
+ // bounded re-rebase-and-retry on a non-fast-forward merge push (task
158
+ // `run-fleet-claim-integrate-and-sibling-rebase-concurrency-safe`, Race 1) — the
159
+ // two locks are NOT merged (merging would serialise the cheap claim behind the
160
+ // slow gated integrate, killing run's parallelism), the retry handles the
161
+ // cross-lock main-advance instead.
162
+ const integrateLock = createKeyedLock();
163
+ // GENUINELY CONCURRENT (ADR §3 — the whole point of `run`): run up to
164
+ // `maxParallel` `runOneItem`s IN FLIGHT at once, capped at `perRepoMax`
165
+ // concurrently per repo. The caps now bound ACTUAL in-flight execution, not just
166
+ // selection (this replaced the old `for (const c) { await runOneItem }` loop
167
+ // that ran selected candidates one-at-a-time). The substrate is parallel-ready —
168
+ // each slug → a distinct `work/<slug>` branch → a distinct job worktree, and the
169
+ // arbiter CAS serialises claims (a loser gets dropped) — so the only shared state
170
+ // across in-flight jobs is read-only config; each job owns its own worktree.
171
+ // Integration ordering is independent per job: each rebases-or-aborts onto a
172
+ // moving `<arbiter>/main` on its own, and a conflict routes only THAT job to
173
+ // needs-attention (the executor never lets one job's failure abort the others).
174
+ const settled = await runConcurrent({
175
+ items: candidates,
176
+ maxInFlight: config.maxParallel,
177
+ keyFor: (candidate) => candidate.repoPath,
178
+ perKeyMax: config.perRepoMax,
179
+ worker: (candidate) => runOneItem(candidate, {
180
+ config,
181
+ override: options.override,
182
+ workspace,
183
+ dorfl: options.dorfl,
184
+ harness,
185
+ reviewGate: options.reviewGate,
186
+ provider,
187
+ ghCanOpenPr: options.ghCanOpenPr,
188
+ openPr: options.openPr,
189
+ env,
190
+ onWarn: options.onWarn,
191
+ backoff: options.backoff,
192
+ sleep: options.sleep,
193
+ claimLock,
194
+ integrateLock,
195
+ }),
196
+ });
197
+ // `runOneItem` is total (it maps every failure to an `ItemResult` and never
198
+ // throws), so a captured `{error}` slot is a defensive last resort — surface it
199
+ // as a claim-error item rather than crashing the whole tick.
200
+ const items = settled.map((slot, i) => 'ok' in slot
201
+ ? slot.ok
202
+ : {
203
+ repoPath: candidates[i].repoPath,
204
+ slug: candidates[i].slug,
205
+ status: 'claim-error',
206
+ detail: slot.error?.message ?? String(slot.error),
207
+ });
208
+ const claimedAndDone = items.filter((i) => i.status === 'claimed-done').length;
209
+ const skipped = items.filter((i) => i.status === 'lost-race' || i.status === 'claim-contended').length;
210
+ const needsAttention = items.filter((i) => i.status === 'tests-failed' ||
211
+ i.status === 'needs-attention' ||
212
+ i.status === 'agent-stopped').length;
213
+ const failed = items.filter((i) => i.status === 'tests-failed' ||
214
+ i.status === 'needs-attention' ||
215
+ i.status === 'agent-stopped' ||
216
+ i.status === 'agent-failed' ||
217
+ // The FAILURE-CAUSE refinements of `agent-failed` count the SAME way (they
218
+ // are the same agent/run-failure routed to needs-attention, just labelled
219
+ // by cause).
220
+ i.status === 'transient-infra' ||
221
+ i.status === 'config-error' ||
222
+ // The surface to needs-attention did NOT land (lost the CAS race); the item
223
+ // is still in-progress on the arbiter — a genuine FAILURE (not a clean
224
+ // needs-attention), so it counts as failed, NOT in `needsAttention`.
225
+ i.status === 'surface-unmoved' ||
226
+ i.status === 'claim-error').length;
227
+ return { claimedAndDone, skipped, failed, needsAttention, items };
228
+ }
229
+ async function runOneItem(candidate, ctx) {
230
+ const { slug, repoPath } = candidate;
231
+ const base = { repoPath, slug, status: 'lost-race' };
232
+ // Resolve THIS repo's effective config against its own `.dorfl.json`
233
+ // layered over the global config (flag > per-repo > global > default). Each
234
+ // repo gets its own integration mode / arbiter, so repo A can be `merge`
235
+ // while repo B is `propose` in one tick.
236
+ const resolved = resolveRepoConfig({
237
+ repoPath,
238
+ global: ctx.config,
239
+ override: ctx.override,
240
+ });
241
+ const config = resolved.config;
242
+ if (resolved.message) {
243
+ ctx.onWarn?.(resolved.message);
244
+ }
245
+ // The IDENTITY env for this repo's GIT + provider operations (claim, push,
246
+ // integration, `gh`). Derived from the host-only `config.identity` (absent ⇒
247
+ // `ctx.env` unchanged, byte-for-byte ambient). This is the INTEGRATION-PATH
248
+ // env ONLY: the agent launch keeps the plain ambient `ctx.env` (the runner,
249
+ // not the agent, acts as the configured identity — design point 4). The push-
250
+ // time transport-coherence guard (`assertTransportAllowed`) fires before the
251
+ // integration push (where the arbiter URL is known), turning a forbidden
252
+ // transport into a clear error, never a silent wrong-account push.
253
+ let gitEnv;
254
+ try {
255
+ gitEnv = identityEnv(config.identity, ctx.env ?? process.env);
256
+ }
257
+ catch (err) {
258
+ // A configured identity that cannot be resolved (e.g. `tokenEnv` names an
259
+ // unset env var) is a CONFIG error — fail THIS item cleanly (surfaced), never
260
+ // crash the tick or silently fall back to an ambient credential.
261
+ const message = err.message;
262
+ ctx.onWarn?.(message);
263
+ return { ...base, status: 'config-error', detail: message };
264
+ }
265
+ // A per-ITEM context carrying `gitEnv` so the needs-attention save helpers
266
+ // (`saveAgentFailure`/`saveAgentStop`) push under the identity too. We rebind a
267
+ // COPY (never mutate the shared tick `ctx` — items run concurrently).
268
+ ctx = { ...ctx, gitEnv };
269
+ // 0. PR-INTENT pre-flight guard — the AUTONOMOUS mirror of in-place `performDo`
270
+ // step 3c. The SAME predicate, run UP FRONT here (per-repo config resolved,
271
+ // BEFORE the claim) so a `propose` item on a GitHub arbiter that INTENDS a PR
272
+ // (`noPR` unset) fails fast when `gh` genuinely cannot open one, instead of
273
+ // letting integration silently degrade to manual-PR instructions. CRITICAL: the
274
+ // probe runs BEFORE the claim — claiming then refusing would strand the item
275
+ // in-progress on main (the claim precedes `prepare()`). The arbiter URL is
276
+ // derived from `repoPath` the SAME way `claimAgainstRepo` derives the claim
277
+ // target (`arbiterUrlForRepo`). The PROBE is the signal, NOT a config check —
278
+ // an absent `providers.github` identity falls back to AMBIENT `gh` auth (the
279
+ // probe reports it available), so a working ambient setup PROCEEDS. A true
280
+ // result returns a CLEAN PRE-CLAIM item result on the `config-error` failure-
281
+ // cause status (a wiring/config failure, NOT a task fault), with NO claim,
282
+ // build, or half-built needs-attention surface — and it never crashes the tick
283
+ // or aborts siblings (the result is returned; `runConcurrent` continues).
284
+ // REUSES the predicate + message so the in-place + autonomous paths cannot
285
+ // drift.
286
+ {
287
+ const arbiterUrl = arbiterUrlForRepo({
288
+ repoPath,
289
+ arbiter: config.defaultArbiter,
290
+ env: gitEnv,
291
+ });
292
+ const probe = ctx.ghCanOpenPr ??
293
+ ((probeCwd, probeEnv) => new GitHubProvider().available(probeCwd, probeEnv));
294
+ if (shouldFailProposePrIntent({
295
+ mode: config.integration,
296
+ arbiterIsGitHub: isGitHubArbiterUrl(arbiterUrl),
297
+ noPR: config.noPR,
298
+ ghCanOpenPr: () => probe(repoPath, gitEnv),
299
+ })) {
300
+ return {
301
+ ...base,
302
+ status: 'config-error',
303
+ detail: PROPOSE_PR_INTENT_GH_UNAVAILABLE_MESSAGE,
304
+ };
305
+ }
306
+ }
307
+ // 0b. STATIC fresh-worktree-gate readiness guard — the fleet mirror of
308
+ // `performDo` step 3d / `performDoRemote` step 1c (task
309
+ // `do-fails-fast-when-acceptance-gate-statically-unrunnable`). When the
310
+ // fresh-worktree gate is ON AND `prepare` resolves to no commands AND a
311
+ // lockfile is present in the repo, the throwaway worktree the gate runs in
312
+ // will have no installed deps, so the gate cannot run. Fail this item
313
+ // CLEANLY before the claim (no claim, no isolate, no agent, no surface) so a
314
+ // fleet tick never burns a build to discover a STATIC config gap and never
315
+ // routes correct work to needs-attention for this reason. Surfaced on the
316
+ // same `config-error` axis the PR-intent guard above uses (a wiring/config
317
+ // fault, not a task fault). The repo discovery is either a working checkout
318
+ // (in-place tests) OR a BARE hub mirror (production fleet); detect the
319
+ // lockfile from whichever shape `repoPath` is. Deps-only — there is no
320
+ // verify-unset case (the gate substitutes `DEFAULT_VERIFY_COMMAND`).
321
+ {
322
+ const lockfile = detectLockfileOnDisk(repoPath) ??
323
+ detectLockfileOnMirrorMain(repoPath, gitEnv);
324
+ const guard = checkGatePreconditions({
325
+ freshWorktreeGate: config.freshWorktreeGate,
326
+ prepare: config.prepare,
327
+ lockfile,
328
+ });
329
+ if (guard !== undefined) {
330
+ return { ...base, status: 'config-error', detail: guard.message };
331
+ }
332
+ }
333
+ // 1. Claim (the runner's first git-state transition) via the in-process CAS.
334
+ // `claimAgainstRepo` handles BOTH discovery shapes: a working CHECKOUT (the
335
+ // in-place test/`do` path — claim directly) and a BARE registry hub mirror
336
+ // (`run`'s production discovery — claim in a throwaway clone, since a bare
337
+ // repo cannot `git mv`/`git commit`; the SAME pattern `do --remote` uses). It
338
+ // returns the `fromRepo`/`strategyArbiter` the worktree strategy resolves its
339
+ // mirror off (kept alive until AFTER prepare). `performClaim` is async, so two
340
+ // awaited claims over one slug genuinely race — the arbiter ref-CAS picks the
341
+ // winner.
342
+ const doClaim = () => claimAgainstRepo({
343
+ slug,
344
+ repoPath,
345
+ workspace: ctx.workspace,
346
+ arbiter: config.defaultArbiter,
347
+ env: gitEnv,
348
+ });
349
+ // Serialise the claim PER REPO (it prepares its micro-commit in a checkout/clone
350
+ // of the repo) so two in-flight jobs in the same repo do not stomp on each
351
+ // other; the arbiter CAS then picks the winner across machines. Different repos
352
+ // (and everything AFTER the claim) run concurrently.
353
+ const repoClaim = ctx.claimLock
354
+ ? await ctx.claimLock(repoPath, doClaim)
355
+ : await doClaim();
356
+ const claim = repoClaim.claim;
357
+ if (claim.outcome === 'lost') {
358
+ repoClaim.cleanup();
359
+ return { ...base, status: 'lost-race' };
360
+ }
361
+ if (claim.outcome === 'contended') {
362
+ repoClaim.cleanup();
363
+ return { ...base, status: 'claim-contended' };
364
+ }
365
+ if (claim.outcome === 'usage-error') {
366
+ repoClaim.cleanup();
367
+ return { ...base, status: 'claim-error', detail: claim.message };
368
+ }
369
+ // 2. Isolate via the isolation-strategy seam (ADR §3). `run` always selects
370
+ // the JOB-WORKTREE strategy: materialise the hub mirror + cut a per-job
371
+ // worktree off the freshly-fetched `<hub>/main` in the agents' area
372
+ // (ADR §1/§2). The seam yields a UNIFORM HANDLE (dir/branch/arbiterRemote/
373
+ // arbiterUrl + a strategy-appropriate teardown) that the post-claim pipeline
374
+ // below reads from — never a concrete `Job` — so the SAME steps serve the
375
+ // in-place strategy too (wired by `do-in-place`). The mirror is keyed off
376
+ // the arbiter URL resolved from this repo, so jobs reuse it (fetch, not
377
+ // re-clone) across the run.
378
+ const strategy = jobWorktreeStrategy({
379
+ // In-place: the checkout. Bare-mirror: the throwaway claim CLONE (still alive)
380
+ // — the strategy resolves the mirror URL off it at prepare time, then we drop it.
381
+ fromRepo: repoClaim.fromRepo,
382
+ arbiter: repoClaim.strategyArbiter,
383
+ workspacesDir: ctx.workspace,
384
+ });
385
+ let tree;
386
+ try {
387
+ tree = strategy.prepare({ slug, env: gitEnv });
388
+ // The claim clone (bare-mirror path) has done its job: the mirror is
389
+ // materialised + the worktree cut. Drop it (no-op for the in-place path).
390
+ repoClaim.cleanup();
391
+ // 2a. CONTINUE rebase conflict (ADR §14 + §10): a requeue kept a
392
+ // `work/<slug>` whose commits did not replay cleanly onto the current
393
+ // main at onboard-time (aborted, never auto-resolved). Route the item to
394
+ // needs-attention TREE-LESSLY via the SAME `#89` mechanism `requeue` uses
395
+ // for the reverse direction — the rebase was ABORTED, so this worktree's
396
+ // `work/<slug>` tip == the arbiter tip (the kept branch, unchanged,
397
+ // after-commit). The DURABLE artifact is that branch on the arbiter + the
398
+ // main surface (ADR §14: the job worktree is a disposable cache; recovery
399
+ // flows through the branch + folder-native surfaces, NOT by editing the
400
+ // worktree). So the surface is purely the one-file `in-progress/ →
401
+ // needs-attention/` ledger move + reason — no branch push, no worktree
402
+ // mutation. Because the branch is provably on the arbiter, the §4 reap
403
+ // predicate still HOLDS and this worktree is reaped — more §14-aligned.
404
+ if (tree.continueRebaseConflict) {
405
+ const reason = `continuing the kept ${tree.branch}: rebase onto the latest main ` +
406
+ 'conflicted (aborted, never auto-resolved) — resolve against the latest ' +
407
+ 'main, or `requeue --reset` to discard and start fresh';
408
+ updateJobRecord(tree.dir, { state: 'needs-attention', reason });
409
+ const surfaced = await ledgerWrite.applyTreelessNeedsAttentionTransition({
410
+ cwd: tree.dir,
411
+ slug,
412
+ reason,
413
+ arbiter: tree.arbiterRemote,
414
+ env: gitEnv,
415
+ });
416
+ if (!surfaced.moved) {
417
+ return surfaceUnmovedItemResult({ base, tree, slug, reason, surfaced });
418
+ }
419
+ return { ...base, status: 'needs-attention', detail: reason };
420
+ }
421
+ // 2b. CONTINUE reconcile-push TERMINAL failure (the stale-lease-strand bug):
422
+ // the onboard reconcile push of the kept (already-committed) work branch
423
+ // FAILED terminally (stale-lease cap exhausted, or a non-stale-lease
424
+ // rejection / unreachable arbiter). The push helper THROWS; `createJob`
425
+ // CATCHES it and flags `continuePushFailure` so the tick does NOT crash
426
+ // leaving the task silently in-progress on the arbiter. Surface to
427
+ // needs-attention TREE-LESSLY via the SAME `#89` mechanism `requeue` uses —
428
+ // the kept branch already on the arbiter from the prior requeue
429
+ // (after-commit, recoverable), so the surface is purely the one-file ledger
430
+ // move + reason (no branch push, no worktree) — instead of running the agent.
431
+ if (tree.continuePushFailure !== undefined) {
432
+ const reason = `continuing the kept ${tree.branch}: publishing the rebased work branch ` +
433
+ `to the arbiter failed terminally (${tree.continuePushFailure}) — the ` +
434
+ 'kept branch is left intact on the arbiter (recoverable); `requeue` to ' +
435
+ 'retry once the churn settles, or `requeue --reset` to discard and start ' +
436
+ 'fresh';
437
+ updateJobRecord(tree.dir, { state: 'needs-attention', reason });
438
+ const surfaced = await ledgerWrite.applyTreelessNeedsAttentionTransition({
439
+ cwd: tree.dir,
440
+ slug,
441
+ reason,
442
+ arbiter: tree.arbiterRemote,
443
+ env: gitEnv,
444
+ });
445
+ if (!surfaced.moved) {
446
+ return surfaceUnmovedItemResult({ base, tree, slug, reason, surfaced });
447
+ }
448
+ return { ...base, status: 'needs-attention', detail: reason };
449
+ }
450
+ // 3. Build the prompt — the SAME dual-use assembly `dorfl prompt`
451
+ // emits: the canonical wrapper (+ source prd) + the task's ## Prompt.
452
+ let prompt;
453
+ try {
454
+ // CONTINUE-aware resolution: only on a continue (the job continued a kept
455
+ // arbiter `work/<slug>`) may the task already be in `work/done/`; admit
456
+ // `done/` ONLY behind the tip-vs-arbiter stranded gate (story 5). In a bare
457
+ // hub mirror's worktree the refs are the LOCAL heads `work/<slug>` / `main`.
458
+ const task = resolveTask(tree.dir, slug, tree.continued
459
+ ? {
460
+ cwd: tree.dir,
461
+ branchRef: tree.branch,
462
+ mainRef: 'main',
463
+ env: gitEnv,
464
+ }
465
+ : undefined);
466
+ // CONTINUE-mode (the `agent-prompt-continue-context` task): when the job
467
+ // CONTINUED a kept arbiter `work/<slug>` (a requeue), inject the continue
468
+ // block (prior diff + reason + handoff note). REUSE the SAME continue-
469
+ // detection — in a bare hub mirror's worktree the refs are the LOCAL heads
470
+ // `work/<slug>` and `main` (after `ensureMirror`'s mirror-style fetch).
471
+ const continueContext = tree.continued
472
+ ? resolveContinueContext({
473
+ cwd: tree.dir,
474
+ slug,
475
+ arbiter: tree.arbiterRemote,
476
+ branchRef: tree.branch,
477
+ mainRef: 'main',
478
+ content: readFileSync(task.path, 'utf8'),
479
+ env: gitEnv,
480
+ })
481
+ : undefined;
482
+ // Thread the resolved per-repo nudge through the per-item override layer
483
+ // (a task or prd may pin `promptGuidance.testFirst` in its frontmatter,
484
+ // superseding the repo policy for THIS item) before the wrapper is built.
485
+ const itemGuidance = resolvePromptGuidanceForItem({
486
+ cwd: tree.dir,
487
+ repoResolved: resolvePromptGuidance(config),
488
+ taskContent: readFileSync(task.path, 'utf8'),
489
+ });
490
+ prompt = buildAgentPrompt(task.slug, task.prd, task.taskPrompt, {
491
+ cwd: tree.dir,
492
+ continueContext,
493
+ promptGuidance: itemGuidance,
494
+ });
495
+ }
496
+ catch (err) {
497
+ if (err instanceof PromptError) {
498
+ return await saveAgentFailure(base, tree, slug, err.message, ctx);
499
+ }
500
+ throw err;
501
+ }
502
+ // 4. Run the agent — via the injected runner (tests) or the harness seam
503
+ // (null adapter by default), shelling out to the configured agentCmd. The
504
+ // resolved per-repo `model` (ADR §13) flows through the seam to the adapter;
505
+ // a `{model}`-in-agentCmd misconfiguration surfaces as agent-failed.
506
+ let agent;
507
+ try {
508
+ agent = runAgent(ctx, tree, prompt, slug, config.agentCmd, config.model, config.sessionsDir);
509
+ }
510
+ catch (err) {
511
+ return await saveAgentFailure(base, tree, slug, err.message, ctx);
512
+ }
513
+ if (!agent.ok) {
514
+ return await saveAgentFailure(base, tree, slug, agent.detail ?? `the agent failed to build '${slug}'.`, ctx);
515
+ }
516
+ // 4b. HONOR a deliberate STOP (task `agent-stop-signal`) — the SAME detection
517
+ // in-place/remote `do` run, mirrored here. The agent exited cleanly but the
518
+ // CLAIM-PROTOCOL wrapper tells it to STOP on a DRIFTED/ambiguous task; an
519
+ // in-band sentinel carries its reason VERBATIM, and the empty-diff backstop
520
+ // catches a stop without one. Either routes to needs-attention (surfaced on
521
+ // the arbiter) and SKIPS the gate + Gate-2 (the whole `performIntegration`
522
+ // band) — a clean STOP is NOT "a build that changed nothing".
523
+ const sentinel = parseStopSentinel(agent.output);
524
+ const stopReason = sentinel !== undefined
525
+ ? sentinel.reason
526
+ : (await isWorkBranchDiffEmpty({
527
+ cwd: tree.dir,
528
+ arbiter: tree.arbiterRemote,
529
+ env: gitEnv,
530
+ }))
531
+ ? emptyDiffStopReason(slug)
532
+ : undefined;
533
+ if (stopReason !== undefined) {
534
+ return await saveAgentStop(base, tree, slug, stopReason, ctx);
535
+ }
536
+ // 5–7 (CONVERGED). The whole gate → review → done-move → commit → rebase →
537
+ // integrate band — plus the needs-attention routing on any failure — now runs
538
+ // through the SHARED `performIntegration` core (`integration-core.ts`, the
539
+ // run/do convergence prd). `run` no longer forks its own gate / done-move /
540
+ // completion commit / `Integrator`+`integrateWithRebase`: that closed all
541
+ // three drift instances at once (the fleet now gets the review gate, the PR
542
+ // title/body, AND the per-repo language-agnostic `verify` gate instead of the
543
+ // old test-only `pnpm -r test` floor). The HEAD above (claim, isolate, agent,
544
+ // failure-save) and the TAIL below (job record + worktree reap) stay here;
545
+ // the band is what they share. `run` is ALWAYS autonomous, so it ALWAYS
546
+ // passes `surfaceArbiter` (every failure surfaces on the arbiter's main +
547
+ // pushes the branch). The injected `openPr` legacy bridge is forwarded to the
548
+ // core unchanged; absent it the core selects the provider PURELY from the
549
+ // arbiter URL (a GitHub remote ⇒ `gh pr create`). The per-repo `noPR` INTENT
550
+ // (suppress the PR) rides separately — it does not pick a provider.
551
+ //
552
+ // `performIntegration` THROWS a plain `Error` for a misconfigured gate
553
+ // (`review` on with no `reviewGate` wired) — `run`'s CLI always wires one when
554
+ // `config.review` is on, so that is a defensive case, but it must NOT crash
555
+ // the whole tick. We catch it and route the item through the same
556
+ // work-preserving needs-attention seam an agent failure uses (`saveAgentFailure`)
557
+ // so the worktree is handled and the run continues to the next item.
558
+ // Push-time transport-coherence guard (identity feature): refuse a forbidden
559
+ // transport for THIS arbiter's actual URL rather than silently pushing under
560
+ // an ambient credential. A no-op when no identity is configured.
561
+ try {
562
+ assertTransportAllowed(config.identity, tree.arbiterUrl);
563
+ }
564
+ catch (err) {
565
+ return await saveAgentFailure(base, tree, slug, err.message, ctx);
566
+ }
567
+ let core;
568
+ try {
569
+ core = await performIntegration({
570
+ cwd: tree.dir,
571
+ // The arbiter remote name valid inside the isolated tree (job-worktree:
572
+ // the mirror's clone remote `origin`), NOT the source repo's
573
+ // `defaultArbiter` name.
574
+ arbiter: tree.arbiterRemote,
575
+ slug,
576
+ // Claim no longer moves the body (task
577
+ // `cutover-claim-body-stays-and-complete-sources-from-backlog`): a
578
+ // freshly-built task RESTS in `tasks/ready/` on `main`, so the done-move
579
+ // sources from there.
580
+ source: 'tasks-ready',
581
+ recovering: false,
582
+ // `run` is ALWAYS autonomous → surface every failure on the arbiter's
583
+ // main AND push the work branch (DATA, not a caller-identity flag).
584
+ surfaceArbiter: tree.arbiterRemote,
585
+ // The per-repo, language-agnostic gate (ADR §8) — the protocol-conformance
586
+ // fix: `run` now honours `config.verify` instead of the deleted
587
+ // `defaultTestGate`'s hardcoded `pnpm -r test`.
588
+ verify: config.verify,
589
+ // The per-repo ENV-PREP step (`prepare`), sequenced ONCE before the first
590
+ // `verify` on the fresh job worktree so it has deps (a fresh worktree off
591
+ // the mirror has no `node_modules`). Unset ⇒ a no-op; never baked into verify.
592
+ prepare: config.prepare,
593
+ // FRESH-WORKTREE GATE (task `gate-on-rebased-tip-fresh-worktree`): run the
594
+ // acceptance gate against the REBASED tip in a clean throwaway worktree (the
595
+ // tree that integrates) so a green gate provably describes the merged
596
+ // artifact. Passed UNCONDITIONALLY (the resolved flag) at ANY `perRepoMax`:
597
+ // the two PRE-EXISTING run-fleet same-repo races the gate's latency used to
598
+ // make deterministic are now CLOSED on their own merits (task
599
+ // `run-fleet-claim-integrate-and-sibling-rebase-concurrency-safe`) — RACE 1
600
+ // (claim-vs-integrate non-fast-forward push) by the integrator's bounded
601
+ // re-rebase-and-retry on the merge push, RACE 2 (sibling-slug divergent-base
602
+ // ledger rebase) by the step-4 sibling-ledger reconciliation arm — so the
603
+ // `perRepoMax === 1` downgrade is REMOVED and the fresh rebased-tip gate runs
604
+ // on the `run` fleet at any same-repo parallelism. Single-job callers
605
+ // (`do`/`--isolated`/`--remote`/`complete`) already pass it unconditionally.
606
+ freshWorktreeGate: config.freshWorktreeGate,
607
+ // The cross-job merge-serialiser CAS-retry cap (config `mergeRetries`) —
608
+ // the git-alone FLOOR of the cross-job land queue (prd `land-time-reverify-
609
+ // and-parallel-merge-ceiling` Story 5 / Applied Answer q1 (a)). Threaded
610
+ // from the per-repo resolved config so a wide-matrix CI's raised cap actually
611
+ // reaches the merge loop — across separate `run` fleet jobs the CAS loop IS
612
+ // the queue (`integrateLock` only serialises sibling integrates in ONE process).
613
+ mergeRetries: config.mergeRetries,
614
+ // Gate 2 (PR/code review): the per-repo resolved flags ride from `config`;
615
+ // only the gate SEAM is threaded through `ctx` (the CLI wires the prod
616
+ // `harnessReviewGate()` only when `config.review` is on).
617
+ review: config.review,
618
+ reviewModel: config.reviewModel,
619
+ reviewMaxRounds: config.reviewMaxRounds,
620
+ reviewGate: ctx.reviewGate,
621
+ mode: config.integration,
622
+ // PR-INTENT: the per-repo `noPR` (suppress the PR even on an authed GitHub
623
+ // arbiter). NOT a provider choice — the provider is purely arbiter-derived.
624
+ noPR: config.noPR,
625
+ // Provider: an injected `openPr` wins (legacy test bridge); otherwise the
626
+ // core selects PURELY from the arbiter URL (a GitHub remote ⇒ `gh pr
627
+ // create`, else push-only `none`). `providerInstance` (the resolved object
628
+ // the `run` seam injects) STAYS — it is a DIFFERENT `provider`.
629
+ providerInstance: ctx.provider,
630
+ openPr: ctx.openPr,
631
+ // The per-repo INTEGRATE serialiser (sibling of the claim lock): the
632
+ // core applies it around ONLY the rebase-to-integrate TAIL, keyed on
633
+ // the repo path (the same key the claim lock uses), so two same-repo
634
+ // merge jobs land on `main` one-at-a-time. Absent on single-job paths.
635
+ integrateLock: ctx.integrateLock,
636
+ integrateLockKey: repoPath,
637
+ // Half A/B: the synthesised single-line title + the agent's surfaced
638
+ // final summary as the PR body (the core scaffolds the task-pointer
639
+ // header). `title` is synthesised inside the core from the task's
640
+ // frontmatter; `body` is the agent output (undefined ⇒ `--fill`).
641
+ body: agent.output,
642
+ env: gitEnv,
643
+ // The review AGENT (Gate 2) launches AMBIENT — never the identity env
644
+ // (an agent must not act as the bot; only the runner's git ops do).
645
+ agentEnv: ctx.env,
646
+ });
647
+ }
648
+ catch (err) {
649
+ // A thrown core error (misconfigured gate, or an unexpected plumbing
650
+ // failure) — SAVE the work + route to needs-attention, never crash the tick.
651
+ return await saveAgentFailure(base, tree, slug, err.message, ctx);
652
+ }
653
+ // TAIL: map the core's DATA outcome onto the job record + `ItemStatus`. The
654
+ // core already ran the gate/review/move/commit/rebase/integrate AND did the
655
+ // needs-attention routing; `run`'s tail does ONLY the job-record write + (in
656
+ // `finally`) the worktree reap. `run` NEVER switches/ff/deletes branches
657
+ // (that is `do`'s in-place tail; a job worktree is reaped, not switched).
658
+ if (core.outcome === 'gate-failed') {
659
+ updateJobRecord(tree.dir, {
660
+ state: 'needs-attention',
661
+ reason: core.reason,
662
+ });
663
+ return { ...base, status: 'tests-failed', detail: core.reason };
664
+ }
665
+ if (core.outcome === 'review-unparseable') {
666
+ // Gate 2 RAN but its verdict was UNPARSEABLE (malformed JSON). The core already
667
+ // routed it work-preservingly (branch pushed + surfaced). FAILURE-CAUSE axis,
668
+ // NOT a reviewer block: classify the parse-failure phrase the core recorded →
669
+ // `transient-infra` (re-run the SAME work — the stochastic gate + the parser's
670
+ // repair pass make a re-run far more likely to parse), the SAME
671
+ // `classifyFailureCause` `do` uses, so the cross-path label agrees. The job
672
+ // record carries the classified status; the worktree is retained by the §4 reap.
673
+ const cause = classifyFailureCause(core.reason);
674
+ updateJobRecord(tree.dir, {
675
+ state: 'needs-attention',
676
+ reason: core.reason,
677
+ });
678
+ return {
679
+ ...base,
680
+ status: failureCauseToItemStatus(cause),
681
+ detail: core.reason,
682
+ };
683
+ }
684
+ if (core.outcome === 'prepare-failed' ||
685
+ core.outcome === 'review-blocked' ||
686
+ core.outcome === 'rebase-conflict' ||
687
+ core.outcome === 'invariant-violation') {
688
+ // `prepare-failed`: the env-prep (install) step was red, so the env could
689
+ // not be made ready and `verify` was NOT run — distinct from a `tests-failed`
690
+ // red gate. Route it to needs-attention like the others (a human fixes the
691
+ // prepare command, then re-runs); the core already surfaced the bounce.
692
+ // `invariant-violation`: the one-slug-one-folder guard FAILED LOUD (the
693
+ // arbiter already holds the slug in >1 status folder — a corrupt ledger).
694
+ // The core integrated NOTHING. On the LEAST-supervised caller this MUST
695
+ // NOT fall through to the SUCCESS branch (state:'done' / 'claimed-done'
696
+ // with no prUrl) — that would misreport a refusal as a completed job, the
697
+ // opposite of fail-loud. Route it to needs-attention like a rebase conflict
698
+ // (a human resolves the duplicate, then re-runs); `complete.ts` mirrors this
699
+ // refusal with exit 1.
700
+ updateJobRecord(tree.dir, {
701
+ state: 'needs-attention',
702
+ reason: core.reason,
703
+ });
704
+ return { ...base, status: 'needs-attention', detail: core.reason };
705
+ }
706
+ // SUCCESS: the core integrated. Record the PR/MR URL (when a provider opened
707
+ // one) on the job, surfaced by `status`.
708
+ const prUrl = core.integration?.url;
709
+ updateJobRecord(tree.dir, { state: 'done', prUrl });
710
+ return { ...base, status: 'claimed-done', integration: core.integration };
711
+ }
712
+ finally {
713
+ // Strategy-appropriate teardown via the uniform handle (ADR §4). Job-worktree:
714
+ // re-apply the provably-safe deletion predicate and remove the worktree ONLY
715
+ // if it holds (clean tree AND the branch tip reachable on the arbiter — merged
716
+ // or pushed). One rule, no done-vs-failed special-casing: a claimed-done job
717
+ // is on the arbiter → reaped; a tests-failed / needs-attention / un-pushed job
718
+ // is NOT → retained (the worktree is the needs-attention signal; `gc` catches
719
+ // up). In-place: a NO-OP (the checkout is never reaped). NEVER `--force` here.
720
+ if (tree) {
721
+ tree.teardown();
722
+ }
723
+ }
724
+ }
725
+ /**
726
+ * Run the agent against the isolated tree. Prefers the injected `dorfl`
727
+ * (tests / custom embeddings); otherwise launches `agentCmd` through the harness
728
+ * seam (recording the PID in the job's harness block, when there is one).
729
+ */
730
+ function runAgent(ctx, tree, prompt, slug, agentCmd, model, sessionsDir) {
731
+ if (ctx.dorfl) {
732
+ return ctx.dorfl({ cwd: tree.dir, prompt, slug, env: ctx.env });
733
+ }
734
+ // Generate the full pi session-FILE path (task `session-path-pi-default`):
735
+ // `<sessionsDir>/<work-id>-<unique>.jsonl`, or pi's per-cwd default folder when
736
+ // `sessionsDir` is unset. The work-id (arbiter URL + slug) is `run`'s natural
737
+ // unique-per-claim id. Threaded through the seam so the pi adapter passes
738
+ // `--session <path>` (never `--session-dir` into the worktree).
739
+ const session = generateSessionPath({
740
+ sessionsDir,
741
+ cwd: tree.dir,
742
+ id: encodeWorkId(tree.arbiterUrl, slug),
743
+ });
744
+ const launched = ctx.harness.launch({
745
+ dir: tree.dir,
746
+ slug,
747
+ command: agentCmd,
748
+ prompt,
749
+ // The model routing intent (ADR §13) — the adapter decides HOW it reaches
750
+ // its tool (pi: `--model`; null/shell: `{model}` placeholder).
751
+ model,
752
+ session,
753
+ env: ctx.env,
754
+ });
755
+ updateJobRecord(tree.dir, { harness: launched.record });
756
+ // Surface the agent's FINAL SUMMARY (`LaunchResult.output`) — the source channel
757
+ // for the propose-mode PR body — instead of dropping it (mirrors `do`'s
758
+ // `runDoAgent`). Absent (no parseable assistant text) ⇒ undefined ⇒ `--fill`.
759
+ return { ok: launched.ok, detail: launched.detail, output: launched.output };
760
+ }
761
+ /**
762
+ * SAVE the partial work of a FAILED agent instead of dropping it (closing the
763
+ * fifth-and-last instance of the recurring asymmetry —
764
+ * `work/notes/observations/run-agent-failure-does-not-save-work.md`). `run`'s
765
+ * agent-failure return points (prompt-assembly fail / `runAgent` throw /
766
+ * `agent.ok === false`) used to BARE-RETURN `agent-failed`, leaving whatever the
767
+ * agent edited only on the LOCAL work branch in the (disposable, possibly remote)
768
+ * job worktree — not on the arbiter, so a requeue-continue on a DIFFERENT machine
769
+ * (or after a `gc` reap) re-cut fresh off main and orphaned it.
770
+ *
771
+ * This mirrors `do.ts`'s `saveAgentFailure`: route the failure through the SAME
772
+ * ledger write seam's needs-attention transition the gate-fail / integrate-
773
+ * conflict bounces use — which (with the arbiter) saves the agent's work as a wip
774
+ * commit, `git mv`s the item to needs-attention/ with the failure detail recorded
775
+ * as the reason, surfaces the move-only commit on the arbiter's `main`
776
+ * (OBSERVABLE), AND pushes the `work/<slug>` branch (RECOVERABLE — the durable
777
+ * artifact a requeue-continue lands the next agent on; continue-detection reads
778
+ * <arbiter>/work/<slug> ahead of main). The push is best-effort — an unreachable
779
+ * arbiter leaves the retained worktree + the local commits standing (the genuinely
780
+ * un-pushed case). The status is the classified failure CAUSE (`transient-infra` /
781
+ * `config-error` where knowable, else the conservative generic `agent-failed`);
782
+ * only the work-preserving side-effect now matches the gate-fail path.
783
+ */
784
+ async function saveAgentFailure(base, tree, slug, detail, ctx) {
785
+ // Classify the failure CAUSE (best-effort + conservative) from the surfaced
786
+ // detail via the SAME `classifyFailureCause` `do` uses — so a thrown CORE config/
787
+ // wiring error reads as `config-error` (NOT `agent-failed`) on BOTH paths, closing
788
+ // the cross-path divergence; a harness-surfaced model/connection outage reads as
789
+ // `transient-infra`; an unrecognised cause stays the generic `agent-failed`. The
790
+ // cause LABEL prefixes the recorded reason so the cause is legible on the
791
+ // needs-attention route; `agent-failed` keeps the historical "agent failed:"
792
+ // prefix (no reason-prose regression).
793
+ const cause = classifyFailureCause(detail);
794
+ const reason = `${failureCauseLabel(cause)}: ${detail}`;
795
+ updateJobRecord(tree.dir, { state: 'needs-attention', reason });
796
+ await ledgerWrite.applyNeedsAttentionTransition({
797
+ cwd: tree.dir,
798
+ slug,
799
+ reason,
800
+ // Autonomous (`run`): surface on the arbiter's main AND push the work branch
801
+ // (the seam does both now), so the fleet's failed-agent work is cross-machine
802
+ // recoverable via requeue-continue. The route is fault-tolerant: a git outage
803
+ // is retried with bounded backoff then gives up cleanly (never hangs the tick).
804
+ arbiter: tree.arbiterRemote,
805
+ env: ctx.gitEnv ?? ctx.env,
806
+ backoff: ctx.backoff,
807
+ sleep: ctx.sleep,
808
+ });
809
+ return { ...base, status: failureCauseToItemStatus(cause), detail };
810
+ }
811
+ /**
812
+ * Map a {@link FailureCause} onto the `run` {@link ItemStatus}. The cause names
813
+ * ARE the status names (the FAILURE-CAUSE axis reuses the terminal vocabulary), so
814
+ * this is identity — a single helper documents the mapping + keeps the `do`/`run`
815
+ * sites symmetric (`do` has the twin `failureCauseToDoOutcome`).
816
+ */
817
+ function failureCauseToItemStatus(cause) {
818
+ return cause;
819
+ }
820
+ /**
821
+ * Build the HONEST {@link ItemResult} for a CONTINUE-site surface that did NOT
822
+ * land on the arbiter (`{moved: false}`). The tree-less `in-progress/ →
823
+ * needs-attention/` move lost the CAS race against a busy arbiter (its
824
+ * contention-retry cap exhausted) or had no arbiter to publish to, so the item is
825
+ * STILL in-progress on the arbiter — reporting a clean `needs-attention` would
826
+ * mislead (it claims the surface landed, when it did not). The DISTINCT
827
+ * `surface-unmoved` status carries `reasonNotMoved` so the caller/human can tell
828
+ * it apart from a successful surface and retry/resolve.
829
+ *
830
+ * The local job record was set to `state: 'needs-attention'` (its LOCAL intent,
831
+ * recorded regardless of the arbiter move) right before the surface; on a
832
+ * `moved: false` we OVERWRITE its reason so that local record does not
833
+ * confusingly claim a landed surface either.
834
+ */
835
+ function surfaceUnmovedItemResult(params) {
836
+ const { base, tree, slug, reason, surfaced } = params;
837
+ const detail = `'${slug}' could NOT be surfaced to needs-attention — the surface did not ` +
838
+ `reach the arbiter's main; the item is still IN-PROGRESS on the arbiter ` +
839
+ `(retry/resolve). ${surfaced.reasonNotMoved ?? reason}`;
840
+ updateJobRecord(tree.dir, { state: 'needs-attention', reason: detail });
841
+ return { ...base, status: 'surface-unmoved', detail };
842
+ }
843
+ /**
844
+ * Route a DELIBERATE agent STOP (task `agent-stop-signal`) to needs-attention
845
+ * through the SAME work-preserving seam `saveAgentFailure` uses, but as the
846
+ * DISTINCT `agent-stopped` status (NOT `agent-failed` — the agent did not error;
847
+ * NOT `tests-failed`/`needs-attention` — there was no red gate / rebase conflict).
848
+ * The agent's STOP reason is recorded VERBATIM; the job record names it honestly.
849
+ * The `performIntegration` band (gate + Gate-2) is NEVER reached.
850
+ */
851
+ async function saveAgentStop(base, tree, slug, reason, ctx) {
852
+ updateJobRecord(tree.dir, { state: 'needs-attention', reason });
853
+ await ledgerWrite.applyNeedsAttentionTransition({
854
+ cwd: tree.dir,
855
+ slug,
856
+ reason,
857
+ // Autonomous (`run`): surface on the arbiter's main AND push the work branch
858
+ // (the seam does both), so the stopped item is cross-machine visible/recoverable.
859
+ arbiter: tree.arbiterRemote,
860
+ env: ctx.gitEnv ?? ctx.env,
861
+ backoff: ctx.backoff,
862
+ sleep: ctx.sleep,
863
+ });
864
+ return { ...base, status: 'agent-stopped', detail: reason };
865
+ }
866
+ /** A throwaway default workspace under the OS temp dir (CLI convenience). */
867
+ export function defaultRunWorkspace() {
868
+ return join(tmpdir(), 'dorfl-workspace');
869
+ }
870
+ const realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
871
+ /**
872
+ * `run` (no flag) — the cross-repo, parallel, **forever-looping daemon** (ADR §3):
873
+ * loop the supervised concurrent tick over the registry until a stop bound
874
+ * (max-iterations / max-duration / a stop signal) or forever (the future system
875
+ * service). Each tick claims + runs a CONCURRENT batch ({@link runOnce}’s
876
+ * `maxParallel`/`perRepoMax` in-flight execution), integrates, then the loop
877
+ * continues. This absorbs the retired `watch` verb’s bounded-session + surface-
878
+ * failures behaviour: a stuck item (timeout / red gate / rebase conflict) is
879
+ * routed through the EXISTING ledger needs-attention seam INSIDE the tick
880
+ * (`runOneItem` → `applyNeedsAttentionTransition`, surfaced on `main`) — the loop
881
+ * does NOT infinite-retry it and adds NO bespoke failure reporting; it just keeps
882
+ * ticking. `run --once` is exactly ONE tick (call {@link runOnce} directly, the
883
+ * debug/test affordance — NOT the CI path; CI is `do`).
884
+ *
885
+ * The loop owns ONLY scheduling (when/whether to tick); the TICK owns one batch’s
886
+ * work — kept separable so advance-loop can swap the tick later (see {@link
887
+ * RunTick}).
888
+ */
889
+ export async function runLoop(options) {
890
+ const tick = options.tick ?? runOnce;
891
+ const now = options.now ?? Date.now;
892
+ const sleep = options.sleep ?? realSleep;
893
+ const intervalMs = options.intervalMs ?? 0;
894
+ const start = now();
895
+ const deadline = options.maxDurationMs !== undefined
896
+ ? start + options.maxDurationMs
897
+ : undefined;
898
+ // The per-tick options are the RunOnceOptions subset of RunLoopOptions; the
899
+ // loop-only knobs (bounds / seams / callbacks) are not forwarded to the tick.
900
+ const tickOptions = {
901
+ config: options.config,
902
+ report: options.report,
903
+ workspace: options.workspace,
904
+ dorfl: options.dorfl,
905
+ harness: options.harness,
906
+ reviewGate: options.reviewGate,
907
+ provider: options.provider,
908
+ openPr: options.openPr,
909
+ env: options.env,
910
+ agentId: options.agentId,
911
+ onWarn: options.onWarn,
912
+ };
913
+ const ticks = [];
914
+ let stoppedBy = 'max-iterations';
915
+ // eslint-disable-next-line no-constant-condition
916
+ while (true) {
917
+ // Stop-condition checks BEFORE running a tick (so a zero-iteration / already-
918
+ // expired / pre-signalled session does no work).
919
+ if (options.stop?.()) {
920
+ stoppedBy = 'signal';
921
+ break;
922
+ }
923
+ if (options.maxIterations !== undefined &&
924
+ ticks.length >= options.maxIterations) {
925
+ stoppedBy = 'max-iterations';
926
+ break;
927
+ }
928
+ if (deadline !== undefined && now() >= deadline) {
929
+ stoppedBy = 'max-duration';
930
+ break;
931
+ }
932
+ const result = await tick(tickOptions);
933
+ ticks.push(result);
934
+ options.onTick?.(result, ticks.length);
935
+ // Re-check the bounds AFTER the tick so we never sleep past a stop condition.
936
+ if (options.maxIterations !== undefined &&
937
+ ticks.length >= options.maxIterations) {
938
+ stoppedBy = 'max-iterations';
939
+ break;
940
+ }
941
+ if (deadline !== undefined && now() >= deadline) {
942
+ stoppedBy = 'max-duration';
943
+ break;
944
+ }
945
+ if (options.stop?.()) {
946
+ stoppedBy = 'signal';
947
+ break;
948
+ }
949
+ if (intervalMs > 0) {
950
+ await sleep(intervalMs);
951
+ }
952
+ }
953
+ return {
954
+ iterations: ticks.length,
955
+ stoppedBy,
956
+ claimedAndDone: ticks.reduce((n, t) => n + t.claimedAndDone, 0),
957
+ skipped: ticks.reduce((n, t) => n + t.skipped, 0),
958
+ failed: ticks.reduce((n, t) => n + t.failed, 0),
959
+ needsAttention: ticks.reduce((n, t) => n + t.needsAttention, 0),
960
+ ticks,
961
+ };
962
+ }
963
+ //# sourceMappingURL=run.js.map