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/src/git.ts ADDED
@@ -0,0 +1,186 @@
1
+ import {spawnSync, spawn} from 'node:child_process';
2
+ import {mkdirSync} from 'node:fs';
3
+ import {dirname} from 'node:path';
4
+
5
+ /** Result of running a git (or any) command. */
6
+ export interface RunResult {
7
+ status: number;
8
+ stdout: string;
9
+ stderr: string;
10
+ }
11
+
12
+ /**
13
+ * Run a command synchronously in `cwd`, capturing output. A non-zero exit is NOT
14
+ * thrown here — callers inspect `status` (claim.sh's exit codes are meaningful).
15
+ */
16
+ export function run(
17
+ command: string,
18
+ args: string[],
19
+ cwd: string,
20
+ options: {input?: string; env?: NodeJS.ProcessEnv} = {},
21
+ ): RunResult {
22
+ const result = spawnSync(command, args, {
23
+ cwd,
24
+ encoding: 'utf8',
25
+ input: options.input,
26
+ env: options.env ?? process.env,
27
+ maxBuffer: 64 * 1024 * 1024,
28
+ });
29
+ if (result.error) {
30
+ throw new Error(`failed to spawn '${command}': ${result.error.message}`);
31
+ }
32
+ return {
33
+ status: result.status ?? -1,
34
+ stdout: result.stdout ?? '',
35
+ stderr: result.stderr ?? '',
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Async variant of {@link run}: spawns the command WITHOUT blocking the event
41
+ * loop, so two awaited calls genuinely run concurrently. Used to verify the
42
+ * claim race the way claim.sh's own verification does (truly simultaneous).
43
+ */
44
+ export function runAsync(
45
+ command: string,
46
+ args: string[],
47
+ cwd: string,
48
+ options: {input?: string; env?: NodeJS.ProcessEnv} = {},
49
+ ): Promise<RunResult> {
50
+ return new Promise((resolvePromise, reject) => {
51
+ const child = spawn(command, args, {
52
+ cwd,
53
+ env: options.env ?? process.env,
54
+ });
55
+ let stdout = '';
56
+ let stderr = '';
57
+ child.stdout.on('data', (chunk: Buffer) => {
58
+ stdout += chunk.toString('utf8');
59
+ });
60
+ child.stderr.on('data', (chunk: Buffer) => {
61
+ stderr += chunk.toString('utf8');
62
+ });
63
+ child.on('error', (err) =>
64
+ reject(new Error(`failed to spawn '${command}': ${err.message}`)),
65
+ );
66
+ child.on('close', (code) => {
67
+ resolvePromise({status: code ?? -1, stdout, stderr});
68
+ });
69
+ if (options.input !== undefined) {
70
+ child.stdin.end(options.input);
71
+ } else {
72
+ child.stdin.end();
73
+ }
74
+ });
75
+ }
76
+
77
+ /** Run `git <args>` in `cwd`; throws on non-zero exit (use `run` for soft checks). */
78
+ export function git(
79
+ args: string[],
80
+ cwd: string,
81
+ options: {input?: string; env?: NodeJS.ProcessEnv} = {},
82
+ ): string {
83
+ const result = run('git', args, cwd, options);
84
+ if (result.status !== 0) {
85
+ throw new Error(
86
+ `git ${args.join(' ')} failed (exit ${result.status}): ${result.stderr.trim()}`,
87
+ );
88
+ }
89
+ return result.stdout;
90
+ }
91
+
92
+ /**
93
+ * Move a tracked file with `git mv`, creating the destination directory first
94
+ * (`mkdir -p`). The `work/` contract requires this: git does not track empty
95
+ * dirs, so `work/done/` (or `work/in-progress/`) may not exist yet. No
96
+ * `.gitkeep` placeholders — the mover owns dir creation.
97
+ */
98
+ export function gitMv(from: string, to: string, cwd: string): void {
99
+ mkdirSync(dirname(toAbsolute(cwd, to)), {recursive: true});
100
+ git(['mv', from, to], cwd);
101
+ }
102
+
103
+ function toAbsolute(cwd: string, p: string): string {
104
+ return p.startsWith('/') ? p : `${cwd}/${p}`;
105
+ }
106
+
107
+ /**
108
+ * The pre-flight DIVERGENCE check for the in-place ff paths (`do` /
109
+ * `complete --merge`): how many commits local `main` is AHEAD of
110
+ * `<arbiter>/main` (`git rev-list --count <arbiter>/main..main`). A non-zero
111
+ * count means local `main` carries UNPUSHED commits the arbiter lacks — the task
112
+ * builds off `<arbiter>/main`, so its merge-back ff cannot apply, exactly the
113
+ * "checkout state that breaks the in-place flow" class the dirty-tree refusal
114
+ * guards. Returns 0 when local `main` is at/behind the arbiter (safe).
115
+ *
116
+ * Best-effort / SAFE-direction: if either ref cannot be resolved (no local
117
+ * `main`, an unreachable arbiter that left `<arbiter>/main` absent) the count
118
+ * cannot be computed, so we read it as 0 (do NOT block on an unknown) — the
119
+ * caller is expected to have fetched first, and a genuinely diverged main is the
120
+ * case we DO catch. Read-only.
121
+ */
122
+ export async function localMainAheadCount(
123
+ cwd: string,
124
+ arbiter: string,
125
+ env: NodeJS.ProcessEnv | undefined,
126
+ ): Promise<number> {
127
+ const res = await runAsync(
128
+ 'git',
129
+ ['rev-list', '--count', `${arbiter}/main..main`],
130
+ cwd,
131
+ {env},
132
+ );
133
+ if (res.status !== 0) {
134
+ return 0; // a ref did not resolve — cannot compute; do not block (safe).
135
+ }
136
+ const n = Number.parseInt(res.stdout.trim(), 10);
137
+ return Number.isFinite(n) ? n : 0;
138
+ }
139
+
140
+ /** How far local `main` has diverged from `<arbiter>/main`, both directions. */
141
+ export interface LocalMainDivergence {
142
+ /** Commits on local `main` the arbiter lacks (UNPUSHED — `main-divergence-guard`). */
143
+ ahead: number;
144
+ /** Commits on `<arbiter>/main` the local `main` lacks (behind — needs a pull/rebase). */
145
+ behind: number;
146
+ }
147
+
148
+ /**
149
+ * Read the DIVERGENCE of local `main` vs `<arbiter>/main` in BOTH directions
150
+ * (`git rev-list --left-right --count <arbiter>/main...main`): `ahead` =
151
+ * unpushed local commits the arbiter lacks (the `main-divergence-guard`
152
+ * framing), `behind` = arbiter commits the local tree lacks. This is the honest
153
+ * expression of the LOCAL working tree's staleness relative to the arbiter — the
154
+ * source of truth — for the cwd-local section of `scan`/`status` (it labels the
155
+ * section as possibly ahead of / behind the fetched arbiter `main`).
156
+ *
157
+ * Best-effort / SAFE: if either ref cannot be resolved (no local `main`, an
158
+ * unreachable arbiter so `<arbiter>/main` is absent) the divergence cannot be
159
+ * computed, so it reads as `{ahead: 0, behind: 0}` (in sync) — never throws. The
160
+ * caller is expected to have fetched the arbiter first; a genuinely diverged
161
+ * `main` is the case we DO catch. Read-only.
162
+ */
163
+ export async function localMainDivergence(
164
+ cwd: string,
165
+ arbiter: string,
166
+ env: NodeJS.ProcessEnv | undefined,
167
+ ): Promise<LocalMainDivergence> {
168
+ const res = await runAsync(
169
+ 'git',
170
+ ['rev-list', '--left-right', '--count', `${arbiter}/main...main`],
171
+ cwd,
172
+ {env},
173
+ );
174
+ if (res.status !== 0) {
175
+ return {ahead: 0, behind: 0}; // a ref did not resolve — read as in sync (safe).
176
+ }
177
+ // `--left-right --count A...B` prints `<behind>\t<ahead>` (left = A=arbiter
178
+ // commits B lacks = behind; right = B=local commits A lacks = ahead).
179
+ const parts = res.stdout.trim().split(/\s+/);
180
+ const behind = Number.parseInt(parts[0] ?? '', 10);
181
+ const ahead = Number.parseInt(parts[1] ?? '', 10);
182
+ return {
183
+ ahead: Number.isFinite(ahead) ? ahead : 0,
184
+ behind: Number.isFinite(behind) ? behind : 0,
185
+ };
186
+ }
package/src/github.ts ADDED
@@ -0,0 +1,468 @@
1
+ import {run, type RunResult} from './git.js';
2
+ import {ghFailureDetail} from './gh-failure.js';
3
+ import {realSleep, retryWithBackoff} from './retry-backoff.js';
4
+ import {
5
+ NoneProvider,
6
+ manualRequestText,
7
+ type ReviewProvider,
8
+ type OpenRequestInput,
9
+ type OpenRequestResult,
10
+ type PostPRCommentInput,
11
+ type PostPRCommentOnBranchInput,
12
+ type PostPRCommentResult,
13
+ } from './integrator.js';
14
+
15
+ /**
16
+ * The **GitHub** integration provider (ADR §6 in
17
+ * `docs/adr/execution-substrate-decisions.md`): the concrete `propose`-mode
18
+ * review-request step, implemented by shelling out to the `gh` CLI.
19
+ *
20
+ * It fulfils the provider seam introduced by `agent-workspaces`
21
+ * (`./integrator.ts`, with its `none` provider). The contract that seam encodes
22
+ * is load-bearing here:
23
+ *
24
+ * - The **universal, safety-bearing action is `git push`** — done by the seam
25
+ * BEFORE the provider is asked to open a request (`Integrator.integrate`).
26
+ * So by the time `openRequest` runs the branch is already on the arbiter and
27
+ * the work is SAFE regardless of what `gh` does (ADR §4/§6).
28
+ * - Therefore this provider **NEVER hard-fails**: if `gh` is missing or
29
+ * unauthenticated it degrades to the `none` behaviour (branch pushed + print
30
+ * manual-PR instructions) rather than throwing — a provider failure must
31
+ * leave a safe, pushed branch, not lost work.
32
+ * - It **NEVER `--force`s** anything (the only force in the system is the claim
33
+ * micro-commit's `--force-with-lease` inside claim.sh).
34
+ *
35
+ * Selection is driven PURELY by the ARBITER URL: a GitHub remote auto-selects
36
+ * this provider; any other arbiter (local `--bare`, a non-GitHub host) defaults
37
+ * to `none` (see {@link selectProvider}). There is NO `provider` override axis —
38
+ * the provider is fully determined by the arbiter; whether `gh` can actually open
39
+ * a PR is the IDENTITY's `providers.github` auth (or ambient `gh` auth), checked
40
+ * by {@link GitHubProvider.available}. The separate "suppress the PR" intent is
41
+ * the `noPR` config axis, layered ON TOP of this arbiter-derived provider (it
42
+ * does NOT pick a provider).
43
+ *
44
+ * The core never imports `gh`; ONLY this adapter shells out to it (the `gh`
45
+ * invocation lives entirely behind the `ReviewProvider` seam). Tests stub `gh`
46
+ * via the injectable `ghBin` (no network, no real GitHub).
47
+ */
48
+
49
+ /**
50
+ * The review-request providers dorfl knows about. This is the RETURN type
51
+ * of {@link selectProvider} (which provider the arbiter resolves to) — NOT a
52
+ * config OVERRIDE axis (there is none; the provider is purely arbiter-derived).
53
+ */
54
+ export type ProviderName = 'none' | 'github';
55
+
56
+ /** The default `gh` CLI binary name (resolved on `PATH`). */
57
+ export const DEFAULT_GH_BIN = 'gh';
58
+
59
+ /**
60
+ * True iff `url` is a GitHub arbiter remote, recognised across the URL shapes
61
+ * the arbiter can take (scp-like ssh `git@github.com:o/r.git`, `ssh://`,
62
+ * `https://`/`http://`). We match on the HOST being exactly `github.com` (or a
63
+ * `github.com` subdomain — GitHub Enterprise installs are out of scope and read
64
+ * as not-GitHub, the safe `none` default). A mere substring match is rejected so
65
+ * a lookalike host (`notgithub.com.evil`) never selects the GitHub provider.
66
+ */
67
+ export function isGitHubArbiterUrl(url: string): boolean {
68
+ const host = arbiterHost(url);
69
+ if (host === undefined) {
70
+ return false;
71
+ }
72
+ return host === 'github.com' || host.endsWith('.github.com');
73
+ }
74
+
75
+ /**
76
+ * Extract the bare host from an arbiter remote URL, or `undefined` for a local
77
+ * filesystem path (`file://...` / `/abs/path`) which has no host. Mirrors the
78
+ * `repo-mirror` URL handling (the four shapes the arbiter can take) but only
79
+ * needs the host for provider detection.
80
+ */
81
+ function arbiterHost(url: string): string | undefined {
82
+ const trimmed = url.trim();
83
+
84
+ if (!trimmed.includes('://')) {
85
+ // scp-like ssh: [user@]host:path (no `://`, a `:` before the path, NOT a
86
+ // plain absolute local path).
87
+ const scp = /^(?:[^@/]+@)?([^/:]+):(.+)$/;
88
+ const m = scp.exec(trimmed);
89
+ if (m && !trimmed.startsWith('/')) {
90
+ return m[1].toLowerCase();
91
+ }
92
+ return undefined; // a plain local path has no host
93
+ }
94
+
95
+ const rest = trimmed.slice(trimmed.indexOf('://') + 3);
96
+ const slash = rest.indexOf('/');
97
+ const authority = slash === -1 ? rest : rest.slice(0, slash);
98
+ const host = stripUserAndPort(authority).toLowerCase();
99
+ // `file://` yields an empty authority (file:///abs/path) → no host.
100
+ return host === '' ? undefined : host;
101
+ }
102
+
103
+ /** Drop `user@` and `:port` from an authority, leaving the bare host. */
104
+ function stripUserAndPort(authority: string): string {
105
+ const afterUser = authority.includes('@')
106
+ ? authority.slice(authority.lastIndexOf('@') + 1)
107
+ : authority;
108
+ const colon = afterUser.indexOf(':');
109
+ return colon === -1 ? afterUser : afterUser.slice(0, colon);
110
+ }
111
+
112
+ export interface SelectProviderOptions {
113
+ /**
114
+ * The arbiter remote URL (the SOLE determinant of the provider). `undefined`
115
+ * when it cannot be resolved — detection then yields `none` (the safe default).
116
+ */
117
+ arbiterUrl?: string;
118
+ /** The `gh` CLI binary the GitHub provider invokes (tests inject a stub). */
119
+ ghBin?: string;
120
+ }
121
+
122
+ /**
123
+ * Resolve the review-request provider for an integration (ADR §6), PURELY from
124
+ * the arbiter URL — there is NO override axis:
125
+ *
126
+ * - a `github.com` arbiter URL ⇒ the GitHub provider, else
127
+ * - the `none` provider (the safe default for unknown / local `--bare`
128
+ * arbiters, which have no review concept).
129
+ *
130
+ * The GitHub provider degrades to `none` behaviour at RUNTIME when `gh` is
131
+ * absent/unauthenticated (so it is safe to select it on URL alone — the work is
132
+ * already pushed by the seam, ADR §6); this keeps SELECTION a pure, testable
133
+ * function of the arbiter URL. The orthogonal "do not open a PR" INTENT is the
134
+ * `noPR` config axis (handled by the caller, layered on top — it does NOT pick a
135
+ * provider here), and whether `gh` is authed to actually open the PR is the
136
+ * identity's `providers.github` / ambient `gh` auth.
137
+ */
138
+ export function selectProvider(options: SelectProviderOptions): ReviewProvider {
139
+ if (options.arbiterUrl && isGitHubArbiterUrl(options.arbiterUrl)) {
140
+ return new GitHubProvider({ghBin: options.ghBin});
141
+ }
142
+ return new NoneProvider();
143
+ }
144
+
145
+ export interface GitHubProviderOptions {
146
+ /**
147
+ * The `gh` CLI binary (default `gh` on `PATH`). Tests inject a stub script so
148
+ * the seam is exercised without a real model / network / GitHub.
149
+ */
150
+ ghBin?: string;
151
+ /** The base branch PRs target. Default `main`. */
152
+ base?: string;
153
+ }
154
+
155
+ /**
156
+ * The GitHub provider: opens a PR for an already-pushed `work/<slug>` branch via
157
+ * `gh pr create`. It NEVER hard-fails — a missing/unauthenticated `gh` degrades
158
+ * to the `none` behaviour (the branch is already pushed; print manual-PR
159
+ * instructions) — and NEVER `--force`s anything. The created PR URL is parsed
160
+ * from `gh`'s stdout and returned so the caller can record it.
161
+ */
162
+ export class GitHubProvider implements ReviewProvider {
163
+ readonly name = 'github';
164
+ private readonly ghBin: string;
165
+ private readonly base: string;
166
+
167
+ constructor(options: GitHubProviderOptions = {}) {
168
+ this.ghBin = options.ghBin ?? DEFAULT_GH_BIN;
169
+ this.base = options.base ?? 'main';
170
+ }
171
+
172
+ /**
173
+ * Open a PR for `input.branch` via `gh pr create --base main --head <branch>`,
174
+ * passing an explicit `--title`/`--body` when the caller supplied them (the
175
+ * synthesised single-line title + the agent's summary body) and falling back to
176
+ * `--fill` ONLY when BOTH are absent (today's behaviour — no regression). A
177
+ * partial set (one present) still drops `--fill`: `--fill` and an explicit
178
+ * `--title`/`--body` are mutually exclusive to `gh`, so once we override either
179
+ * field we must supply both explicitly (the other defaults to the slug-derived
180
+ * title / an empty body rather than re-deriving a run-on subject). The branch
181
+ * is GUARANTEED to be on the arbiter already (the push is the seam's safety-
182
+ * bearing step), so any `gh` failure is non-fatal: we fall back to the same
183
+ * manual-instructions result the `none` provider returns. On success we parse
184
+ * the PR URL `gh` prints and surface it (recorded by the caller into the job
185
+ * record / `status`).
186
+ */
187
+ async openRequest(input: OpenRequestInput): Promise<OpenRequestResult> {
188
+ const args = [
189
+ 'pr',
190
+ 'create',
191
+ '--base',
192
+ this.base,
193
+ '--head',
194
+ input.branch,
195
+ ...prCreateContentArgs(input),
196
+ ];
197
+
198
+ // First attempt. A non-zero / missing `gh` can mean two VERY different things:
199
+ // - DETERMINISTIC: `gh` is missing or unauthenticated — retrying is pointless
200
+ // (every attempt fails identically); degrade IMMEDIATELY (today's
201
+ // behaviour, no wasted backoff).
202
+ // - TRANSIENT (OUTAGE): `gh` is present + authed but the network/API is down
203
+ // — RETRY with bounded backoff (the same shared helper the push uses)
204
+ // before degrading. This is a LOW-severity mode: the branch is already
205
+ // pushed (the seam's safety step), so the work is safe — only the review
206
+ // surface is missing. We do NOT gate requeue on it.
207
+ const first = this.runGh(args, input.cwd, input.env);
208
+ if (first !== undefined && first.status === 0) {
209
+ return this.parseOpened(input, first);
210
+ }
211
+
212
+ // Failed once — distinguish DETERMINISTIC (missing/unauth) from a TRANSIENT
213
+ // outage by an availability probe. Missing/unauth ⇒ degrade now (no retry).
214
+ // Thread the FAILED first attempt so the degrade surfaces the REAL `gh` cause
215
+ // (its stderr / the missing-binary detail), not a hard-coded auth guess.
216
+ //
217
+ // NOTE (degrade NARROWED): for a propose-with-PR-intent run (`noPR` unset) the
218
+ // start-of-run "`gh` unavailable/unauthed" case is now caught UP FRONT by the
219
+ // pre-flight `gh` auth probe (see `do.ts`'s pre-flight guard / `selectProvider`
220
+ // docs), so it never reaches this point as a silent degrade. The legitimate
221
+ // callers that still land here are: `noPR: true` (intended push-only — the
222
+ // caller does not even pass a GitHub provider, so this is moot), and a `gh`
223
+ // that went away AFTER a passing up-front probe (a transient mid-run loss).
224
+ if (!this.available(input.cwd, input.env)) {
225
+ return this.degrade(input, 'unavailable', first);
226
+ }
227
+
228
+ // `gh` IS available but the create failed — a transient outage. Retry the
229
+ // create with bounded backoff before a clean give-up into the OUTAGE degrade.
230
+ const attempt = await retryWithBackoff(
231
+ async () => {
232
+ const r = this.runGh(args, input.cwd, input.env);
233
+ if (r !== undefined && r.status === 0) {
234
+ return {ok: true as const, value: r};
235
+ }
236
+ return {
237
+ ok: false as const,
238
+ error: r?.stderr.trim() || 'gh pr create failed',
239
+ };
240
+ },
241
+ {sleep: input.sleep ?? realSleep, ...input.backoff},
242
+ );
243
+ if (!attempt.ok) {
244
+ return this.degrade(input, 'outage');
245
+ }
246
+ return this.parseOpened(input, attempt.value);
247
+ }
248
+
249
+ /** Map a successful `gh pr create` RunResult to an OpenRequestResult. */
250
+ private parseOpened(
251
+ input: OpenRequestInput,
252
+ result: RunResult,
253
+ ): OpenRequestResult {
254
+ const url = parsePrUrl(result.stdout);
255
+ if (url === undefined) {
256
+ // gh succeeded but we could not parse a URL — still treat the PR as
257
+ // opened (gh exited 0) but fall back to a generic confirmation.
258
+ return {
259
+ opened: true,
260
+ instruction: `Opened a GitHub PR for ${input.branch}.`,
261
+ };
262
+ }
263
+ return {
264
+ opened: true,
265
+ url,
266
+ instruction: `Opened a GitHub PR for ${input.branch}: ${url}`,
267
+ };
268
+ }
269
+
270
+ /**
271
+ * Post a follow-up COMMENT on an already-opened PR via
272
+ * `gh pr comment <url> --body <text>` (task `review-gate-pr-comment`),
273
+ * threading the PR by the `url` {@link openRequest} returned. The PR already
274
+ * exists (this runs AFTER the propose integrate), so any `gh` failure is
275
+ * non-fatal: a missing/unauthenticated `gh` DEGRADES to the same surface-the-
276
+ * text result the `none` provider returns — NEVER throws (ADR §6). The comment
277
+ * is ADVISORY: it changes no gate/verdict/merge logic. NEVER `--force`s.
278
+ */
279
+ postPRComment(input: PostPRCommentInput): PostPRCommentResult {
280
+ const result = this.runGh(
281
+ ['pr', 'comment', input.url, '--body', input.body],
282
+ input.cwd,
283
+ input.env,
284
+ );
285
+ // gh missing (spawn failed) OR non-zero exit (e.g. unauthenticated): the PR
286
+ // already exists and the review is in the run output, so degrade gracefully
287
+ // — NEVER throw (the comment is advisory; a failure must not lose work).
288
+ if (result === undefined || result.status !== 0) {
289
+ // Surface the REAL `gh` cause (its stderr, with the missing-binary special
290
+ // case) — NOT a hard-coded "unavailable or unauthenticated" guess that sends
291
+ // the operator chasing a phantom auth problem (mirrors `issue-provider.ts`).
292
+ const reason = ghFailureDetail(result);
293
+ return {
294
+ posted: false,
295
+ instruction:
296
+ `${reason} The review was not posted as a comment on ` +
297
+ `${input.url}. The review:\n${input.body}`,
298
+ };
299
+ }
300
+ return {
301
+ posted: true,
302
+ instruction: `Posted the review as a comment on ${input.url}.`,
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Post the review comment by RESOLVING the PR from the pushed `work/<slug>`
308
+ * BRANCH (task `review-comment-fallback-on-unparsed-pr-url`), the FALLBACK for
309
+ * when `gh pr create` opened a PR (exit 0) but its stdout url was unparseable so
310
+ * {@link openRequest} returned `{opened: true}` with NO `url`. We first RESOLVE
311
+ * the open PR's url from the branch (`gh pr view <branch> --json url --jq .url`):
312
+ *
313
+ * - a url comes back ⇒ a PR genuinely exists — post the comment on it via the
314
+ * url-keyed {@link postPRComment} (the audit trail is preserved);
315
+ * - nothing resolvable (no PR for the branch, or `gh` missing/unauthenticated)
316
+ * ⇒ an HONEST clean no-op (`posted: false`) — but only AFTER trying. The
317
+ * "no PR ⇒ no comment" rule holds; what changes is we no longer drop the
318
+ * comment when a PR DID open.
319
+ *
320
+ * Resolving the url first (rather than commenting on the branch directly) keeps
321
+ * the no-PR case a deterministic no-op and reuses the exact same comment
322
+ * mechanics as the url path. NEVER throws, NEVER `--force`s (ADR §6).
323
+ */
324
+ postPRCommentOnBranch(
325
+ input: PostPRCommentOnBranchInput,
326
+ ): PostPRCommentResult {
327
+ const url = this.resolvePrUrlForBranch(input.branch, input.cwd, input.env);
328
+ if (url === undefined) {
329
+ // No PR resolvable from the branch (truly none, or `gh` unavailable): an
330
+ // honest no-op — but only after trying. Surface the review text so it is
331
+ // never lost; nothing was posted.
332
+ return {
333
+ posted: false,
334
+ instruction:
335
+ `No open PR could be resolved for ${input.branch}, so the review ` +
336
+ `was not posted as a comment. The review:\n${input.body}`,
337
+ };
338
+ }
339
+ // A PR genuinely exists for the branch — comment on it via the url path.
340
+ return this.postPRComment({
341
+ cwd: input.cwd,
342
+ url,
343
+ body: input.body,
344
+ env: input.env,
345
+ });
346
+ }
347
+
348
+ /**
349
+ * Resolve the open PR's url for `branch` via `gh pr view <branch> --json url
350
+ * --jq .url`, or `undefined` when no PR is found / `gh` is missing or
351
+ * unauthenticated (a non-zero exit or a spawn failure). Read-only; mutates
352
+ * nothing. The result is parsed for a PR url (any surrounding chatter ignored)
353
+ * so a stray warning line never defeats the resolution.
354
+ */
355
+ private resolvePrUrlForBranch(
356
+ branch: string,
357
+ cwd: string,
358
+ env: NodeJS.ProcessEnv | undefined,
359
+ ): string | undefined {
360
+ const result = this.runGh(
361
+ ['pr', 'view', branch, '--json', 'url', '--jq', '.url'],
362
+ cwd,
363
+ env,
364
+ );
365
+ if (result === undefined || result.status !== 0) {
366
+ return undefined; // no PR for the branch, or gh missing/unauthenticated
367
+ }
368
+ return parsePrUrl(result.stdout);
369
+ }
370
+
371
+ /**
372
+ * Is `gh` available AND authenticated (so a PR can actually be opened)?
373
+ * `gh auth status` exits 0 when authenticated. A missing `gh` (spawn failure)
374
+ * or a non-zero exit both read as unavailable. Read-only; mutates nothing.
375
+ */
376
+ available(cwd: string, env?: NodeJS.ProcessEnv): boolean {
377
+ const result = this.runGh(['auth', 'status'], cwd, env);
378
+ return result !== undefined && result.status === 0;
379
+ }
380
+
381
+ /**
382
+ * Run `gh <args>` in `cwd`, returning the result, or `undefined` when `gh`
383
+ * cannot even be spawned (binary missing). `run` throws on a spawn error; we
384
+ * catch it here so a missing `gh` degrades rather than crashing the runner.
385
+ */
386
+ private runGh(
387
+ args: string[],
388
+ cwd: string,
389
+ env: NodeJS.ProcessEnv | undefined,
390
+ ): RunResult | undefined {
391
+ try {
392
+ return run(this.ghBin, args, cwd, {env});
393
+ } catch {
394
+ return undefined; // gh binary not found / not executable
395
+ }
396
+ }
397
+
398
+ /**
399
+ * The graceful-degradation result (identical SHAPE to the `none` provider's):
400
+ * the branch is already pushed (safe), only the PR is missing. The `reason`
401
+ * distinguishes the two LOW-severity degrade causes so the operator knows what
402
+ * to do: `unavailable` (`gh` missing/unauth — fix `gh`/auth) vs `outage`
403
+ * (transient network/API failure that survived the bounded retry — just re-run
404
+ * / open it manually). Both print the SAME manual `gh pr create` suggestion.
405
+ */
406
+ private degrade(
407
+ input: OpenRequestInput,
408
+ reason: 'unavailable' | 'outage',
409
+ /**
410
+ * The FAILED `gh pr create` result that triggered the `unavailable` degrade
411
+ * (`undefined` = `gh` binary missing). Threaded in so the `unavailable` arm
412
+ * surfaces the REAL cause rather than a hard-coded auth guess. The `outage`
413
+ * arm does not need it (its wording is already honest about the retried
414
+ * transient failure).
415
+ */
416
+ result?: RunResult,
417
+ ): OpenRequestResult {
418
+ // Echo the explicit title/body in the suggested manual command when present,
419
+ // so a human opening the PR by hand reuses the same content the autonomous
420
+ // path would have set (else fall back to the bare `--fill` suggestion).
421
+ const contentArgs = prCreateContentArgs(input);
422
+ const suggestion =
423
+ `gh pr create --base ${this.base} --head ${input.branch} ${contentArgs.join(' ')}`.trim();
424
+ const cause =
425
+ reason === 'outage'
426
+ ? '`gh pr create` failed after retries (a transient outage), so no PR ' +
427
+ 'was opened — the branch is pushed and the work is SAFE; re-run or ' +
428
+ 'open one manually, e.g. '
429
+ : // Surface the REAL `gh` cause (its stderr, with the missing-binary
430
+ // special case) — NOT a hard-coded "unavailable or unauthenticated"
431
+ // guess (mirrors `issue-provider.ts`).
432
+ `${ghFailureDetail(result)} No PR was opened — open one manually, e.g. `;
433
+ return {
434
+ opened: false,
435
+ instruction:
436
+ `Pushed ${input.branch} to ${input.arbiter}. ${cause}` +
437
+ `\`${suggestion}\`.` +
438
+ manualRequestText(input),
439
+ };
440
+ }
441
+ }
442
+
443
+ /**
444
+ * The CONTENT args for `gh pr create`: an explicit `--title`/`--body` when the
445
+ * caller supplied either (a partial set is completed so `--fill` is never mixed
446
+ * with an explicit field — `gh` forbids that), else the lone `--fill` (today's
447
+ * behaviour, no regression). Returned as a flat arg array so both the live
448
+ * invocation and the degraded suggestion build from one source of truth.
449
+ */
450
+ export function prCreateContentArgs(input: {
451
+ title?: string;
452
+ body?: string;
453
+ }): string[] {
454
+ if (input.title === undefined && input.body === undefined) {
455
+ return ['--fill'];
456
+ }
457
+ return ['--title', input.title ?? '', '--body', input.body ?? ''];
458
+ }
459
+
460
+ /**
461
+ * Parse the PR URL `gh pr create` prints to stdout. `gh` prints the PR URL as a
462
+ * line (often the only/last line); we pick the first GitHub PR URL we find. Any
463
+ * surrounding chatter is ignored. Returns `undefined` when no URL is present.
464
+ */
465
+ function parsePrUrl(stdout: string): string | undefined {
466
+ const match = stdout.match(/https?:\/\/\S+\/pull\/\d+/);
467
+ return match ? match[0] : undefined;
468
+ }