dorfl 0.0.0 → 0.1.1

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 +3100 -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 +208 -0
  162. package/dist/frontmatter.d.ts.map +1 -0
  163. package/dist/frontmatter.js +344 -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 +329 -0
  330. package/dist/prd-to-spec.d.ts.map +1 -0
  331. package/dist/prd-to-spec.js +706 -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 +363 -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 +951 -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 +4379 -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 +477 -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 +1059 -0
  581. package/src/prepare.ts +230 -0
  582. package/src/prompt.ts +763 -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 +1437 -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/harness.ts ADDED
@@ -0,0 +1,355 @@
1
+ import {spawnSync} from 'node:child_process';
2
+
3
+ /**
4
+ * The **harness seam** (ADR §5): how a job's command is launched and how its
5
+ * liveness is observed is pluggable behind an adapter; the core never hard-codes
6
+ * a specific tool.
7
+ *
8
+ * Crucially, **liveness is reported by the harness, NOT inferred from filesystem
9
+ * mtime**: a live agent can think for minutes without writing any files, so
10
+ * mtime would mistake a thinking agent for a dead one. Adapters answer liveness
11
+ * from the real signal (the PID, a session handle, …) — never mtime.
12
+ *
13
+ * This task ships the **null adapter** (records a PID, runs a configured
14
+ * command) so the substrate is testable standalone. The first real target (the
15
+ * `pi` adapter: liveness via PID + a pointer to the pi session dir/log,
16
+ * invocation via the pi CLI) is its own task.
17
+ */
18
+
19
+ /**
20
+ * The persisted harness block in a job's `.dorfl-job.json` record. It
21
+ * captures which adapter launched the job + the liveness pointer the adapter
22
+ * needs to answer `isAlive` later (so `gc`/`status` can re-derive liveness from
23
+ * a fresh process without re-launching). Adapter-specific fields are optional.
24
+ */
25
+ export interface HarnessRecord {
26
+ /** Which harness adapter owns this job (`null`, later `pi`, …). */
27
+ adapter: string;
28
+ /** OS process id of the launched command (the liveness anchor). */
29
+ pid?: number;
30
+ /** The command the adapter ran (for audit / re-launch). */
31
+ command?: string;
32
+ /** Adapter-specific session pointer (e.g. the pi session dir/log path). */
33
+ session?: string;
34
+ }
35
+
36
+ /** What a harness needs to launch one job's command. */
37
+ export interface LaunchInput {
38
+ /** The job's working directory (the worktree) — the command runs here. */
39
+ dir: string;
40
+ /** The slug being processed (for adapters that name/log per slug). */
41
+ slug: string;
42
+ /** The command to run (e.g. the configured `agentCmd`). */
43
+ command: string;
44
+ /** Optional prompt fed on the command's stdin. */
45
+ prompt?: string;
46
+ /**
47
+ * The model the agent should run on (the harness-agnostic routing intent, ADR
48
+ * §13). `undefined` ⇒ dorfl forces no model. The ADAPTER decides HOW
49
+ * this reaches its tool: the pi adapter passes `--model <model>` natively; the
50
+ * null/shell adapter substitutes a `{model}` placeholder in `command` (see
51
+ * {@link substituteModel}). auth/keys are NEVER carried here — they stay the
52
+ * harness's job.
53
+ */
54
+ model?: string;
55
+ /**
56
+ * The full pi session-FILE path the adapter passes as `--session <path>` (the
57
+ * caller generates it ONCE — before launch, so the `do --watch` tailer can tail
58
+ * the KNOWN path — via {@link generateSessionPath} from the resolved
59
+ * `sessionsDir` + cwd). Adapter-agnostic: the pi adapter uses it verbatim and
60
+ * records it in `PiHarnessRecord.session`; the null/shell adapter ignores it.
61
+ * `undefined` ⇒ the pi adapter falls back to a generated default for its cwd.
62
+ */
63
+ session?: string;
64
+ env?: NodeJS.ProcessEnv;
65
+ }
66
+
67
+ /**
68
+ * What a harness needs to launch one item's harness INTERACTIVELY (task
69
+ * `agent-interactive-launch`): a FOREGROUND human session in `dir`, inherited
70
+ * stdio, NO prepared prompt. This is the OPPOSITE shape to {@link LaunchInput}
71
+ * (which feeds a prompt on stdin and captures output for the autonomous path):
72
+ * here the human drives the agent, so there is nothing to feed and nothing to
73
+ * capture. A NEW seam intent, NOT a flag on {@link Harness.launch} (decision #1):
74
+ * `launch` is fundamentally spawnSync + prompt-on-stdin + capture-output, and a
75
+ * boolean would make its `LaunchResult` lie.
76
+ */
77
+ export interface InteractiveLaunchInput {
78
+ /** The onboarded working tree to start the session in (the command runs here). */
79
+ dir: string;
80
+ /** The slug being worked on (for adapters that name/log per slug). */
81
+ slug: string;
82
+ /**
83
+ * The resolved model the human starts pinned to (ADR §13 routing: flag > env
84
+ * > per-repo > global). `undefined` ⇒ no model forced. The pi adapter passes
85
+ * `--model <model>`; the human may still switch models inside the session.
86
+ */
87
+ model?: string;
88
+ /**
89
+ * The full pi session-FILE path passed as `--session <path>` so the human
90
+ * session is still recorded/visible (audit trail + the pi dashboard, decision
91
+ * #2). `undefined` ⇒ the pi adapter generates a default for `dir`.
92
+ */
93
+ session?: string;
94
+ env?: NodeJS.ProcessEnv;
95
+ }
96
+
97
+ /**
98
+ * The result of an interactive launch — there is NOTHING to capture (the human
99
+ * drove a foreground session; no prepared prompt, no piped output, no PID record
100
+ * to persist; it is NOT a tracked job, decision #3). The only useful signal is
101
+ * the harness's exit code, returned here. Callers may ignore it.
102
+ */
103
+ export interface InteractiveLaunchResult {
104
+ /** The harness process's exit code (0 = clean exit). */
105
+ exitCode: number;
106
+ }
107
+
108
+ /**
109
+ * What the human-face verbs (`start`/`work-on`) hand a launcher: just the
110
+ * onboarded WORKING TREE + the slug + env. The model + the pi `--session` path
111
+ * are resolved at the CLI boundary (where config lives) and BOUND INTO the
112
+ * injected closure, so the git-logic modules stay decoupled from `createHarness`
113
+ * / config resolution. The CLI's closure calls
114
+ * {@link Harness.launchInteractive} with the resolved model/session.
115
+ */
116
+ export interface InteractiveLaunchSite {
117
+ /** The slug being worked on. */
118
+ slug: string;
119
+ /** The onboarded working tree to start the foreground session in. */
120
+ dir: string;
121
+ /** Environment for the launched harness process. */
122
+ env?: NodeJS.ProcessEnv;
123
+ }
124
+
125
+ /**
126
+ * The injectable interactive launcher the human-face verbs call AFTER
127
+ * onboarding. The CLI binds the resolved harness + model + sessions-dir into it;
128
+ * tests inject a spy. A thin seam so `start.ts`/`work-on.ts` never import
129
+ * `createHarness` or resolve config.
130
+ */
131
+ export type InteractiveLauncher = (site: InteractiveLaunchSite) => void;
132
+
133
+ /** The `{model}` placeholder the null/shell adapter substitutes in `agentCmd`. */
134
+ export const MODEL_PLACEHOLDER = '{model}';
135
+
136
+ /**
137
+ * Inject the model ROUTING intent (ADR §13) into a shell `command` for the
138
+ * null/shell adapter, with three degradation rules so model routing is OFFERED,
139
+ * never FORCED:
140
+ *
141
+ * 1. `{model}` present + `model` set ⇒ substitute every occurrence.
142
+ * 2. `{model}` present + `model` unset ⇒ a clear config error (we never emit a
143
+ * literal `{model}` to the shell — that would silently misroute).
144
+ * 3. `{model}` absent ⇒ return `command` as-is (a user who bakes the model into
145
+ * `agentCmd`, or relies on the harness's own default, is untouched).
146
+ *
147
+ * dorfl only moves the model INTENT; auth/keys stay the harness's job.
148
+ */
149
+ export function substituteModel(
150
+ command: string,
151
+ model: string | undefined,
152
+ ): string {
153
+ if (!command.includes(MODEL_PLACEHOLDER)) {
154
+ return command; // rule 3: no placeholder ⇒ run as-is.
155
+ }
156
+ if (model === undefined || model === '') {
157
+ throw new Error(
158
+ `agentCmd contains a ${MODEL_PLACEHOLDER} placeholder but no model is ` +
159
+ `configured. Set a model (--model, DORFL_MODEL, per-repo, or ` +
160
+ `global config) or remove ${MODEL_PLACEHOLDER} from agentCmd.`,
161
+ );
162
+ }
163
+ return command.split(MODEL_PLACEHOLDER).join(model); // rule 1: substitute.
164
+ }
165
+
166
+ export interface LaunchResult {
167
+ /** True iff the launched command completed successfully. */
168
+ ok: boolean;
169
+ /** The harness block to persist in the job record (PID, command, …). */
170
+ record: HarnessRecord;
171
+ /** Failure detail when `ok` is false (the stderr/failure channel). */
172
+ detail?: string;
173
+ /**
174
+ * The agent's final ANSWER (task `harness-agent-output`): the concatenated
175
+ * `text` of the LAST assistant turn the invocation produced. This is the
176
+ * channel for the agent's OUTPUT on success — DISTINCT from {@link detail},
177
+ * which is the failure/`stderr` channel. `undefined` when the invocation
178
+ * produced no parseable assistant text.
179
+ *
180
+ * Per-adapter EXTRACTION from each tool's native channel (Option C, decided
181
+ * 2026-06-06): pi reads the last assistant message from the session `.jsonl`
182
+ * it wrote (via `watch-session.ts`'s shared reader); the null/shell adapter
183
+ * returns its captured (synchronous) command stdout. The forward-contract for
184
+ * an opencode adapter (not built yet) is to take the last assistant `text`
185
+ * part from its `--format json` stream — the SAME `output` field.
186
+ */
187
+ output?: string;
188
+ }
189
+
190
+ /**
191
+ * The harness seam. `launch` starts the job's command + returns the record (with
192
+ * the liveness anchor); `isAlive` answers liveness FROM THE HARNESS (PID/session
193
+ * — never mtime, ADR §5).
194
+ */
195
+ export interface Harness {
196
+ /** A stable adapter name (`null`, `pi`, …) stamped into the record. */
197
+ readonly adapter: string;
198
+ /** Launch the job's command; record the PID + liveness pointer. */
199
+ launch(input: LaunchInput): LaunchResult;
200
+ /**
201
+ * Launch the harness INTERACTIVELY (task `agent-interactive-launch`): a
202
+ * FOREGROUND human session in `input.dir` with INHERITED stdio and NO prepared
203
+ * prompt — the human drives it, and control returns when they exit. This is
204
+ * the human-facing counterpart to the autonomous {@link launch}; it is NOT a
205
+ * tracked job (no `.dorfl-job.json`, no PID/liveness record, no gate,
206
+ * decision #3), so it returns only an exit code. pi-only: the null adapter
207
+ * throws a clear pi-only error (decision #2).
208
+ */
209
+ launchInteractive(input: InteractiveLaunchInput): InteractiveLaunchResult;
210
+ /** Is the job still alive? Answered from the record's anchor, NOT mtime. */
211
+ isAlive(record: HarnessRecord): boolean;
212
+ }
213
+
214
+ /**
215
+ * Is this `spawnSync.error` a BENIGN failure of the prompt write, safe to
216
+ * ignore? The null/shell adapter feeds `input.prompt` to the child on stdin
217
+ * (`spawnSync('bash', …, {input})`). When the prompt is EMPTY — the autonomous
218
+ * review/arbiter launches that just shell out and capture stdout — a child that
219
+ * closes its stdin before the parent's (zero-byte) write surfaces as `EPIPE`
220
+ * under concurrent test load. That write failing is harmless: there was nothing
221
+ * to deliver, and the child's stdout/exit status are still captured normally.
222
+ * So we treat ONLY `EPIPE` as benign and let every OTHER spawn error (`ENOENT`,
223
+ * `EACCES`, buffer overflow, …) throw — those are real launch failures.
224
+ */
225
+ export function isBenignPromptWriteError(error: Error): boolean {
226
+ return (error as NodeJS.ErrnoException).code === 'EPIPE';
227
+ }
228
+
229
+ /**
230
+ * The **null adapter**: runs the configured command synchronously to completion
231
+ * in the job dir, recording the PID. Liveness is `process.kill(pid, 0)` against
232
+ * the recorded PID (the OS process table) — explicitly NOT a file mtime. Because
233
+ * it runs synchronously, the process has already exited by the time `launch`
234
+ * returns, so a finished job reads as not-alive (which is correct).
235
+ */
236
+ export class NullHarness implements Harness {
237
+ readonly adapter = 'null';
238
+
239
+ launch(input: LaunchInput): LaunchResult {
240
+ // BACKSTOP (config error, NOT a spawn failure): an empty/whitespace command
241
+ // resolves the null adapter to `bash -c ''`, which exits 0 with no output — a
242
+ // "successful" build that ran NOTHING. The `do`/`run`/`--remote` CLI sites
243
+ // already refuse this up-front (doNeedsAgentCmd), but THIS seam can be reached
244
+ // by other callers (tests, embeddings, future paths), so it must refuse too.
245
+ // Distinct from the `result.error` spawn-failure throw below: this names the
246
+ // config cause + the fix, in the voice of `launchInteractive`/`substituteModel`.
247
+ if (input.command.trim() === '') {
248
+ throw new Error(
249
+ 'no command to run: the null/shell adapter was launched with an empty ' +
250
+ 'agentCmd — nothing would run. Set `agentCmd` (--agent-cmd, per-repo, or ' +
251
+ 'global config) or configure `harness: pi`.',
252
+ );
253
+ }
254
+ // Inject the model routing intent into the shell command via the `{model}`
255
+ // placeholder (ADR §13) — offered, never forced (see substituteModel).
256
+ const command = substituteModel(input.command, input.model);
257
+ const result = spawnSync('bash', ['-c', command], {
258
+ cwd: input.dir,
259
+ encoding: 'utf8',
260
+ input: input.prompt,
261
+ env: input.env ?? process.env,
262
+ maxBuffer: 64 * 1024 * 1024,
263
+ });
264
+ if (result.error && !isBenignPromptWriteError(result.error)) {
265
+ throw new Error(
266
+ `failed to spawn harness command: ${result.error.message}`,
267
+ );
268
+ }
269
+ // Record the CHILD's PID (the liveness anchor) — not the runner's. The null
270
+ // adapter runs synchronously, so by the time we return the child has
271
+ // exited, and `isAlive` correctly reads it as not-alive (from the PID
272
+ // table, NOT a file mtime).
273
+ const record: HarnessRecord = {
274
+ adapter: this.adapter,
275
+ pid: result.pid,
276
+ command,
277
+ };
278
+ const status = result.status ?? -1;
279
+ // The null/shell adapter's OUTPUT is its captured stdout (trimmed): a
280
+ // synchronous spawn, so there is no stream-fragility caveat — the command's
281
+ // stdout IS its answer. `undefined` when empty (no answer to surface).
282
+ const stdout = (result.stdout ?? '').trim();
283
+ return {
284
+ ok: status === 0,
285
+ record,
286
+ detail: status === 0 ? undefined : (result.stderr ?? '').trim(),
287
+ output: stdout === '' ? undefined : stdout,
288
+ };
289
+ }
290
+
291
+ /**
292
+ * Interactive launch is NOT supported by the null/shell adapter (decision #2):
293
+ * its `agentCmd` is shaped for the captured, prompt-fed AUTONOMOUS path, so
294
+ * "interactive" has no clean meaning here. Throw a CLEAR pi-only error
295
+ * (mirroring `do --watch`'s fail-on-null decision) rather than silently
296
+ * shelling out the wrong way.
297
+ */
298
+ launchInteractive(_input: InteractiveLaunchInput): InteractiveLaunchResult {
299
+ throw new Error(
300
+ 'interactive launch requires the pi harness; configure `harness: pi` ' +
301
+ '(the null/shell adapter only supports the captured autonomous launch).',
302
+ );
303
+ }
304
+
305
+ isAlive(record: HarnessRecord): boolean {
306
+ return pidAlive(record.pid);
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Resolve the harness adapter that OWNS a given job record, keyed off the
312
+ * record's `adapter` field. The core (`status`, `watch`, `gc`) reads liveness
313
+ * for a heterogeneous set of jobs (some null, some pi) from their persisted
314
+ * records, so it must ask the RIGHT adapter per job — a pi job's liveness is the
315
+ * pi adapter's responsibility (PID + session pointer), not the null adapter's.
316
+ *
317
+ * Adapters register here lazily via {@link registerHarness}; an unknown adapter
318
+ * falls back to the null adapter (PID-only liveness — never mtime), which is a
319
+ * safe superset for any PID-anchored record.
320
+ */
321
+ export function resolveHarness(record: HarnessRecord): Harness {
322
+ return HARNESS_REGISTRY.get(record.adapter) ?? FALLBACK_HARNESS;
323
+ }
324
+
325
+ /**
326
+ * Register a harness adapter under its `adapter` name so {@link resolveHarness}
327
+ * can dispatch liveness to it. Idempotent (last registration wins). The pi
328
+ * adapter registers itself on import; tests may register stubs.
329
+ */
330
+ export function registerHarness(harness: Harness): void {
331
+ HARNESS_REGISTRY.set(harness.adapter, harness);
332
+ }
333
+
334
+ const FALLBACK_HARNESS = new NullHarness();
335
+ const HARNESS_REGISTRY = new Map<string, Harness>([
336
+ [FALLBACK_HARNESS.adapter, FALLBACK_HARNESS],
337
+ ]);
338
+
339
+ /**
340
+ * Is `pid` a live process? Uses signal 0 (`process.kill(pid, 0)`), which checks
341
+ * for existence/permission WITHOUT delivering a signal — the OS process table,
342
+ * never a filesystem mtime. Unknown/undefined PID ⇒ not alive.
343
+ */
344
+ export function pidAlive(pid: number | undefined): boolean {
345
+ if (pid === undefined || pid <= 0) {
346
+ return false;
347
+ }
348
+ try {
349
+ process.kill(pid, 0);
350
+ return true;
351
+ } catch (err) {
352
+ // EPERM means the process exists but we may not signal it ⇒ still alive.
353
+ return (err as NodeJS.ErrnoException).code === 'EPERM';
354
+ }
355
+ }
@@ -0,0 +1,322 @@
1
+ /**
2
+ * The **identity** feature: run the runner's git + provider operations as a
3
+ * configured entity (a bot), without mutating the user's global git/`gh` config.
4
+ *
5
+ * The mechanism is process-scoped environment overrides on the child processes
6
+ * the runner spawns (`git`, `gh`) — never a global mutation. So if the runner
7
+ * crashes mid-run the user's machine is untouched, and an absent identity is
8
+ * byte-for-byte today's ambient behaviour.
9
+ *
10
+ * # The three axes (keep these distinct — they are different concerns)
11
+ *
12
+ * 1. **commit label** (`name` / `email`) — the git author/committer strings
13
+ * stamped into the commit object. These are NOT authenticated: git never
14
+ * checks them against anything. Driven by `GIT_CONFIG_PARAMETERS`.
15
+ * 2. **git transport auth** (`auth`) — WHO pushes. Per-transport policy: an
16
+ * SSH key (or ambient ssh) drives `GIT_SSH_COMMAND`; HTTPS uses the ambient
17
+ * credential. This is the substrate concern — meaningful with NO provider.
18
+ * 3. **provider API auth** (`providers.github`) — WHO opens the PR / posts the
19
+ * comment, via `GH_TOKEN`. NEVER used as a git credential (git is SSH-first;
20
+ * GitHub is an additive layer). Optional: absent ⇒ `gh` degrades.
21
+ *
22
+ * The three axes SHOULD point at the same entity for a coherent bot (the token's
23
+ * GitHub account should be the account the SSH key is registered to), but nothing
24
+ * can verify that automatically — it is a documented coherence note, not a check.
25
+ *
26
+ * # Why `auth` is mandatory-explicit (no silent omission)
27
+ *
28
+ * `auth.ssh` and `auth.https` are BOTH required, each an explicit small union, so
29
+ * the dangerous "I set a bot provider token but left git auth ambient — and my
30
+ * remote is HTTPS, so I silently push as the human" misconfig is UNSPELLABLE by
31
+ * accident: pushing over ambient HTTPS requires literally writing
32
+ * `https: "ambient"`. A bot setup naturally writes `https: "never"`, which makes
33
+ * the leak a hard push-time failure instead of a silent wrong-account push.
34
+ */
35
+
36
+ /** The conventional `agents.alt` TLD never resolves to a real account (deliberate). */
37
+ export const DEFAULT_IDENTITY_NAME = 'dorfl';
38
+ export const DEFAULT_IDENTITY_EMAIL = 'dorfl@agents.alt';
39
+
40
+ /**
41
+ * Per-transport git-auth policy for SSH. A filesystem path PINS that key
42
+ * (`GIT_SSH_COMMAND -i <path>`); `"ambient"` lets ssh-agent / `~/.ssh/config`
43
+ * resolve the key; `"never"` FORBIDS the SSH transport (a hard push-time failure
44
+ * if the arbiter is an SSH remote). A `union of more` later (e.g. host options).
45
+ */
46
+ export type SshAuth = string | 'ambient' | 'never';
47
+
48
+ /**
49
+ * Per-transport git-auth policy for HTTPS. `"ambient"` uses whatever HTTPS
50
+ * credential the environment supplies (credential helper / cached PAT — e.g. the
51
+ * CI `actions/checkout` token); `"never"` FORBIDS the HTTPS transport (a hard
52
+ * push-time failure if the arbiter is an HTTPS remote). A token-pin member (the
53
+ * explicit HTTPS-push credential, distinct from the provider token) is a planned
54
+ * future addition — keep this a union so it grows without churn.
55
+ */
56
+ export type HttpsAuth = 'ambient' | 'never';
57
+
58
+ /** Git TRANSPORT auth — both transports stated, no silent-omission state. */
59
+ export interface GitAuth {
60
+ /** Policy for SSH pushes: a key path, `"ambient"`, or `"never"`. */
61
+ ssh: SshAuth;
62
+ /** Policy for HTTPS pushes: `"ambient"` or `"never"`. */
63
+ https: HttpsAuth;
64
+ }
65
+
66
+ /** Provider API auth — the `gh` token, by literal value OR an env-var name. */
67
+ export type GitHubProviderAuth = {token: string} | {tokenEnv: string};
68
+
69
+ /** The optional, pluggable review-request providers (matches `ProviderName`). */
70
+ export interface IdentityProviders {
71
+ /** GitHub provider API auth (`gh`). Absent ⇒ `gh` runs unauthenticated. */
72
+ github?: GitHubProviderAuth;
73
+ }
74
+
75
+ /**
76
+ * A configured runner identity (a bot). The WHOLE block is optional — absent ⇒
77
+ * fully ambient (today's behaviour, byte-for-byte). When present, `auth` is
78
+ * MANDATORY (both transports stated); `name`/`email` default in; `providers` is
79
+ * optional. HOST-ONLY: rejected in a per-repo `.dorfl.json` (it carries
80
+ * secrets and is per-machine), so it lives only in the global config.
81
+ */
82
+ export interface Identity {
83
+ /** Commit author/committer LABEL. Default {@link DEFAULT_IDENTITY_NAME}. */
84
+ name?: string;
85
+ /** Commit author/committer LABEL. Default {@link DEFAULT_IDENTITY_EMAIL}. */
86
+ email?: string;
87
+ /** Git transport auth (mandatory when identity present). */
88
+ auth: GitAuth;
89
+ /** Optional pluggable providers (GitHub today). */
90
+ providers?: IdentityProviders;
91
+ }
92
+
93
+ /** Which transport an arbiter remote URL pushes over. */
94
+ export type ArbiterTransport = 'ssh' | 'https' | 'local';
95
+
96
+ /**
97
+ * Classify the git transport an arbiter remote URL uses — the fact that selects
98
+ * WHICH `auth` policy (`ssh` vs `https`) applies at push time. Mirrors the four
99
+ * URL shapes `repo-mirror`/`github` already handle:
100
+ *
101
+ * - scp-like ssh (`git@host:org/repo.git`) and `ssh://` ⇒ `ssh`
102
+ * - `https://` / `http://` ⇒ `https`
103
+ * - `file://` / a plain local path ⇒ `local` (no transport auth applies)
104
+ */
105
+ export function arbiterTransport(url: string): ArbiterTransport {
106
+ const trimmed = url.trim();
107
+ if (!trimmed.includes('://')) {
108
+ // scp-like ssh: [user@]host:path (a `:` before the path, NOT a local path).
109
+ const scp = /^(?:[^@/]+@)?([^/:]+):(.+)$/;
110
+ if (scp.test(trimmed) && !trimmed.startsWith('/')) {
111
+ return 'ssh';
112
+ }
113
+ return 'local'; // a plain absolute path has no transport
114
+ }
115
+ const scheme = trimmed.slice(0, trimmed.indexOf('://')).toLowerCase();
116
+ if (scheme === 'ssh') {
117
+ return 'ssh';
118
+ }
119
+ if (scheme === 'https' || scheme === 'http') {
120
+ return 'https';
121
+ }
122
+ return 'local'; // file:// (or anything else) — no transport auth
123
+ }
124
+
125
+ /** A validation failure naming the offending field (load-time config error). */
126
+ export class IdentityConfigError extends Error {}
127
+
128
+ /** A push-time transport-coherence failure (forbidden transport for the arbiter). */
129
+ export class IdentityTransportError extends Error {}
130
+
131
+ /**
132
+ * Validate a present `identity` block at config-LOAD time (dumb — does NOT
133
+ * resolve any arbiter URL; the transport-coherence check is push-time). Throws
134
+ * an {@link IdentityConfigError} naming the offending field. The structural
135
+ * "auth mandatory / ssh+https stated" guarantee mostly rides on the type, but a
136
+ * JSON file is untyped, so we re-check it here for a human-facing message.
137
+ */
138
+ export function validateIdentity(identity: Identity): void {
139
+ if (identity.auth === undefined || identity.auth === null) {
140
+ throw new IdentityConfigError(
141
+ 'identity.auth is required when an identity is configured ' +
142
+ '(state both `ssh` and `https`).',
143
+ );
144
+ }
145
+ const {ssh, https} = identity.auth;
146
+ if (ssh === undefined || ssh === null || ssh === '') {
147
+ throw new IdentityConfigError(
148
+ 'identity.auth.ssh is required (a key path, "ambient", or "never").',
149
+ );
150
+ }
151
+ if (https !== 'ambient' && https !== 'never') {
152
+ throw new IdentityConfigError(
153
+ 'identity.auth.https must be "ambient" or "never".',
154
+ );
155
+ }
156
+ const github = identity.providers?.github;
157
+ if (github !== undefined) {
158
+ const hasToken = 'token' in github && github.token !== undefined;
159
+ const hasEnv = 'tokenEnv' in github && github.tokenEnv !== undefined;
160
+ if (hasToken && hasEnv) {
161
+ throw new IdentityConfigError(
162
+ 'identity.providers.github must set exactly one of `token` or ' +
163
+ '`tokenEnv`, not both.',
164
+ );
165
+ }
166
+ if (!hasToken && !hasEnv) {
167
+ throw new IdentityConfigError(
168
+ 'identity.providers.github must set `token` or `tokenEnv`.',
169
+ );
170
+ }
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Resolve the `gh` token for the GitHub provider from the identity, or
176
+ * `undefined` when no GitHub provider auth is configured. A `tokenEnv` is read
177
+ * from `env` at USE-time (so a missing env var surfaces here with a clear
178
+ * message), `token` is the literal value. `env` defaults to `process.env`.
179
+ */
180
+ export function resolveGitHubToken(
181
+ identity: Identity | undefined,
182
+ env: NodeJS.ProcessEnv = process.env,
183
+ ): string | undefined {
184
+ const github = identity?.providers?.github;
185
+ if (github === undefined) {
186
+ return undefined;
187
+ }
188
+ if ('token' in github && github.token !== undefined) {
189
+ return github.token;
190
+ }
191
+ if ('tokenEnv' in github && github.tokenEnv !== undefined) {
192
+ const value = env[github.tokenEnv];
193
+ if (value === undefined || value === '') {
194
+ throw new IdentityConfigError(
195
+ `identity.providers.github.tokenEnv names env var ` +
196
+ `"${github.tokenEnv}", which is unset or empty.`,
197
+ );
198
+ }
199
+ return value;
200
+ }
201
+ return undefined;
202
+ }
203
+
204
+ /**
205
+ * Build the process-scoped environment overrides for `identity`, merged over
206
+ * `base` (default `process.env`). Returns `base` UNCHANGED (same reference) when
207
+ * `identity` is `undefined` — the absent-identity path is byte-for-byte today's
208
+ * behaviour, so callers can pass the result straight through.
209
+ *
210
+ * When present it sets, on a COPY of `base`:
211
+ * - `GIT_CONFIG_PARAMETERS` — quoted `'user.name=…' 'user.email=…'` (defaults
212
+ * applied). Properly single-quoted (with `'\''` escaping) so a name/email
213
+ * containing a space or quote cannot break the parse.
214
+ * - `GIT_AUTHOR_NAME`/`GIT_AUTHOR_EMAIL`/`GIT_COMMITTER_NAME`/
215
+ * `GIT_COMMITTER_EMAIL` — set to the SAME bot name/email. This is
216
+ * LOAD-BEARING: the per-commit `GIT_AUTHOR_*`/`GIT_COMMITTER_*` env vars take
217
+ * PRECEDENCE over `user.name`/`user.email` (and thus over
218
+ * `GIT_CONFIG_PARAMETERS`). If the AMBIENT env already has them (some CI /
219
+ * tooling sets them), `GIT_CONFIG_PARAMETERS` alone would be SILENTLY ignored
220
+ * and the commit would be authored by the ambient identity — exactly the
221
+ * silent-fallback this feature exists to prevent. So we pin all four to the
222
+ * identity, making it win UNCONDITIONALLY over any ambient git identity.
223
+ * - `GIT_SSH_COMMAND` — `ssh -i <path> -o IdentitiesOnly=yes -o
224
+ * IdentityAgent=none` ONLY when `auth.ssh` is a key path. `"ambient"`/`"never"`
225
+ * set nothing (ambient ssh resolution; `"never"` is enforced by the push-time
226
+ * transport guard).
227
+ *
228
+ * `IdentityAgent=none` is LOAD-BEARING, NOT decoration: `IdentitiesOnly=yes`
229
+ * ALONE does NOT stop a running ssh-agent from offering its OWN keys — it only
230
+ * restricts which keys are tried to those whose public file is named, and an
231
+ * agent key matching a discoverable `~/.ssh/*.pub` is still offered FIRST. So
232
+ * with a personal key in the agent, the push could silently authenticate as
233
+ * the HUMAN (the wrong account) despite `-i <bot key>` — the exact silent-
234
+ * wrong-account failure mode this feature exists to prevent (the SSH-axis twin
235
+ * of the `GIT_AUTHOR_*` pinning below). `IdentityAgent=none` detaches the
236
+ * agent entirely, so ONLY the pinned key is offered — it wins unconditionally.
237
+ * - `GH_TOKEN` — ONLY when a GitHub provider token is configured (resolved at
238
+ * use-time). NEVER fed to git (the token is provider-API only).
239
+ */
240
+ export function identityEnv(
241
+ identity: Identity | undefined,
242
+ base: NodeJS.ProcessEnv = process.env,
243
+ ): NodeJS.ProcessEnv {
244
+ if (identity === undefined) {
245
+ return base;
246
+ }
247
+ const name = identity.name ?? DEFAULT_IDENTITY_NAME;
248
+ const email = identity.email ?? DEFAULT_IDENTITY_EMAIL;
249
+ const env: NodeJS.ProcessEnv = {...base};
250
+
251
+ // Commit LABEL (always set when an identity is present). GIT_CONFIG_PARAMETERS
252
+ // is a space-separated list of shell-quoted `key=value` pairs.
253
+ env.GIT_CONFIG_PARAMETERS = [
254
+ shellQuote(`user.name=${name}`),
255
+ shellQuote(`user.email=${email}`),
256
+ ].join(' ');
257
+ // Pin the per-commit author/committer env too — these OUTRANK `user.name`/
258
+ // `user.email`, so without them an ambient `GIT_AUTHOR_*`/`GIT_COMMITTER_*`
259
+ // would silently beat the identity (the silent-fallback failure mode). Setting
260
+ // them makes the identity win unconditionally.
261
+ env.GIT_AUTHOR_NAME = name;
262
+ env.GIT_AUTHOR_EMAIL = email;
263
+ env.GIT_COMMITTER_NAME = name;
264
+ env.GIT_COMMITTER_EMAIL = email;
265
+
266
+ // Git TRANSPORT auth — only a PINNED ssh key sets GIT_SSH_COMMAND.
267
+ // `IdentityAgent=none` is REQUIRED for the pin to actually hold: without it a
268
+ // running ssh-agent (e.g. with the human's personal key) can offer its own keys
269
+ // FIRST and silently push as the wrong account, despite `-i <bot key>`.
270
+ const ssh = identity.auth.ssh;
271
+ if (ssh !== 'ambient' && ssh !== 'never') {
272
+ env.GIT_SSH_COMMAND = `ssh -i ${shellQuote(ssh)} -o IdentitiesOnly=yes -o IdentityAgent=none`;
273
+ }
274
+
275
+ // Provider API auth — the gh token, NEVER a git credential.
276
+ const token = resolveGitHubToken(identity, base);
277
+ if (token !== undefined) {
278
+ env.GH_TOKEN = token;
279
+ }
280
+
281
+ return env;
282
+ }
283
+
284
+ /**
285
+ * Enforce the push-time transport-coherence rule: the `auth` policy for the
286
+ * arbiter's actual transport must not be `"never"`. Throws an
287
+ * {@link IdentityTransportError} with an actionable message (use a matching
288
+ * remote, or unset `identity`) when the transport is forbidden. A `local`
289
+ * arbiter (or an absent identity) has nothing to enforce.
290
+ */
291
+ export function assertTransportAllowed(
292
+ identity: Identity | undefined,
293
+ arbiterUrl: string,
294
+ ): void {
295
+ if (identity === undefined) {
296
+ return;
297
+ }
298
+ const transport = arbiterTransport(arbiterUrl);
299
+ if (transport === 'ssh' && identity.auth.ssh === 'never') {
300
+ throw new IdentityTransportError(
301
+ `identity forbids SSH (auth.ssh: "never") but arbiter ` +
302
+ `"${arbiterUrl}" is an SSH remote. Use an HTTPS remote, set ` +
303
+ `auth.ssh to a key path or "ambient", or unset identity.`,
304
+ );
305
+ }
306
+ if (transport === 'https' && identity.auth.https === 'never') {
307
+ throw new IdentityTransportError(
308
+ `identity forbids HTTPS (auth.https: "never") but arbiter ` +
309
+ `"${arbiterUrl}" is an HTTPS remote. Use an SSH remote, set ` +
310
+ `auth.https to "ambient", or unset identity.`,
311
+ );
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Single-quote a string for safe inclusion in a `GIT_CONFIG_PARAMETERS` /
317
+ * `GIT_SSH_COMMAND` value: wrap in single quotes and escape any embedded single
318
+ * quote as `'\''` (close-quote, escaped-quote, re-open-quote — the POSIX idiom).
319
+ */
320
+ function shellQuote(value: string): string {
321
+ return `'${value.replace(/'/g, `'\\''`)}'`;
322
+ }