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
@@ -0,0 +1,150 @@
1
+ import {existsSync, readdirSync} from 'node:fs';
2
+ import {join} from 'node:path';
3
+ import {run} from './git.js';
4
+ import {resolveSidecarIdentity} from './sidecar.js';
5
+ import {resolveItemPathByIdentity} from './item-path.js';
6
+ import {workFolderPath, workFolderRel} from './work-layout.js';
7
+
8
+ /**
9
+ * The **orphan-sidecar reaper** — the WORKING-TREE counterpart of the job-worktree
10
+ * and remote-branch reapers (`gc.ts` / `reap-branches.ts`), folded into `dorfl gc`
11
+ * (prd `agentic-question-resolution-retire-disposition-vocabulary`, US #10).
12
+ *
13
+ * A question sidecar is a tooling-owned file `work/questions/<type>-<slug>.md`
14
+ * keyed on its source item's `(type, slug)` identity (`sidecarPathFor`). The
15
+ * contract is that notes/sidecars leave by DELETION (git history is the archive),
16
+ * so when a human deletes the source observation (or task/prd) out-of-band, its
17
+ * sidecar is ORPHANED.
18
+ *
19
+ * WHY THIS IS A SWEEP, NOT AN APPLY STEP. An orphan's source item is GONE, so it
20
+ * is in NO lifecycle pool. The advance driver enumerates ITEMS in the pools and
21
+ * looks up THEIR sidecars; it never enumerates orphaned sidecars. So no per-item
22
+ * `advance` tick (`apply`/`no-op`) ever runs on an orphan — the classifier never
23
+ * sees it. The orphan's only on-disk trace is the sidecar file itself. Therefore
24
+ * this reap enumerates `work/questions/` DIRECTLY and checks each sidecar's source
25
+ * existence by IDENTITY.
26
+ *
27
+ * The existence check REUSES the keystone's extracted `resolveItemPathByIdentity`
28
+ * (`item-path.ts`, the neutral re-exported seam) — the same working-tree,
29
+ * by-identity "does the source item exist?" resolver the apply rung uses — never a
30
+ * forked second resolver. A sidecar whose source EXISTS is left untouched; a
31
+ * sidecar whose source is ABSENT is `git rm`'d (deletion, not a `git mv`: the
32
+ * sidecar leaves by deletion, recoverable from git history).
33
+ */
34
+
35
+ /** A sidecar the orphan sweep reaped (its source item was absent). */
36
+ export interface ReapedSidecar {
37
+ /** The repo-relative sidecar path that was removed (`work/questions/<type>-<slug>.md`). */
38
+ path: string;
39
+ /** The canonical namespaced identity the sidecar was keyed on (`<namespace>:<slug>`). */
40
+ item: string;
41
+ }
42
+
43
+ /** A sidecar the orphan sweep retained (its source item still exists). */
44
+ export interface RetainedSidecar {
45
+ path: string;
46
+ item: string;
47
+ /** The repo-relative path of the live source item the sidecar belongs to. */
48
+ sourcePath: string;
49
+ }
50
+
51
+ export interface SweepOrphanSidecarsInput {
52
+ /**
53
+ * The repo CHECKOUT to sweep — its working tree holds `work/questions/` and the
54
+ * lifecycle folders the existence check scans. In CI this is the checked-out
55
+ * repo (`process.cwd()`); the sweep operates on whatever checkout `gc` runs in.
56
+ */
57
+ cwd: string;
58
+ /** Sink for human-readable progress notes (per reaped / retained sidecar). */
59
+ note?: (message: string) => void;
60
+ /**
61
+ * Do NOT actually `git rm` — only REPORT what WOULD be reaped vs retained. A
62
+ * read-only preview; the existence predicate still runs so the report is exact.
63
+ */
64
+ dryRun?: boolean;
65
+ env?: NodeJS.ProcessEnv;
66
+ }
67
+
68
+ export interface SweepOrphanSidecarsResult {
69
+ /** The sidecars reaped this sweep (source absent). Empty on dry-run. */
70
+ reaped: ReapedSidecar[];
71
+ /** The sidecars retained, each with the live source path it belongs to. */
72
+ retained: RetainedSidecar[];
73
+ /** On `dryRun`, the sidecars that WOULD be reaped (not actually removed). */
74
+ wouldReap: ReapedSidecar[];
75
+ }
76
+
77
+ /**
78
+ * Sweep `work/questions/` in `cwd` and `git rm` each sidecar whose
79
+ * `(type, slug)` source item is ABSENT (working-tree existence via
80
+ * {@link resolveItemPathByIdentity}). A sidecar whose source EXISTS is left
81
+ * untouched. The reap is a `git rm` (the sidecar leaves by deletion; git history
82
+ * is the archive), and each reaped/retained sidecar is reported.
83
+ *
84
+ * Working-tree based: it reads `work/questions/` + the lifecycle folders from the
85
+ * checkout `gc` runs in; no arbiter ref query beyond the existence check. Idempotent
86
+ * — a re-run over an already-clean tree reaps nothing.
87
+ */
88
+ export function sweepOrphanSidecars(
89
+ input: SweepOrphanSidecarsInput,
90
+ ): SweepOrphanSidecarsResult {
91
+ const note = input.note ?? (() => {});
92
+ const env = input.env;
93
+ const dryRun = input.dryRun === true;
94
+ const reaped: ReapedSidecar[] = [];
95
+ const retained: RetainedSidecar[] = [];
96
+ const wouldReap: ReapedSidecar[] = [];
97
+
98
+ const questionsDir = workFolderPath(input.cwd, 'questions');
99
+ if (!existsSync(questionsDir)) {
100
+ return {reaped, retained, wouldReap};
101
+ }
102
+
103
+ for (const entry of readdirSync(questionsDir)) {
104
+ if (!entry.endsWith('.md')) {
105
+ continue; // sidecars are `<type>-<slug>.md` — ignore stray non-md files
106
+ }
107
+ // The filename IS the identity: `<type>-<slug>.md`. `resolveSidecarIdentity`
108
+ // accepts the `<type>-<slug>` form (the same resolver `sidecarPathFor`
109
+ // derives the path FROM), giving the canonical `(type, slug, item)`.
110
+ const stem = entry.slice(0, -'.md'.length);
111
+ const {item} = resolveSidecarIdentity(stem.replace('-', ':'));
112
+ const path = `${workFolderRel('questions')}/${entry}`;
113
+
114
+ const sourcePath = resolveItemPathByIdentity(input.cwd, item);
115
+ if (sourcePath !== undefined) {
116
+ // The source item still exists ⇒ a LIVE sidecar ⇒ leave it untouched.
117
+ retained.push({path, item, sourcePath});
118
+ note(`Retained ${path}: source ${item} still exists (${sourcePath}).`);
119
+ continue;
120
+ }
121
+
122
+ // Source ABSENT ⇒ ORPHAN ⇒ reap. Report (dry-run) or `git rm` (the real
123
+ // sweep). Deletion, never a `git mv`: the sidecar leaves by deletion and is
124
+ // recoverable from git history.
125
+ if (dryRun) {
126
+ wouldReap.push({path, item});
127
+ note(`Would reap ${path} (orphan; source ${item} is gone).`);
128
+ continue;
129
+ }
130
+ const rm = run('git', ['rm', '--quiet', '--', path], input.cwd, {env});
131
+ if (rm.status !== 0) {
132
+ // A failed `git rm` is NOT a reap; surface it but keep sweeping the rest.
133
+ // Tolerate "did not match any files" (a concurrent reap / untracked file)
134
+ // by reporting it as kept with the error, never crashing the sweep.
135
+ note(
136
+ `Failed to git rm ${path} (${rm.stderr.trim() || 'unknown error'}); kept.`,
137
+ );
138
+ continue;
139
+ }
140
+ reaped.push({path, item});
141
+ note(`Reaped ${path} (orphan; source ${item} is gone).`);
142
+ }
143
+
144
+ return {reaped, retained, wouldReap};
145
+ }
146
+
147
+ /** The absolute `work/questions/` dir under a checkout (re-exported convenience). */
148
+ export function questionsDirPath(cwd: string): string {
149
+ return join(cwd, workFolderRel('questions'));
150
+ }
package/src/output.ts ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Tiny, dependency-free terminal-output helpers shared by the CLI's
3
+ * human-facing messages. Two concerns live here:
4
+ *
5
+ * - `shouldUseColor` — the TTY/`NO_COLOR` decision (color ONLY when stdout is
6
+ * an interactive TTY and `NO_COLOR` is unset), so the same rule is applied
7
+ * everywhere and is unit-testable without a real terminal.
8
+ * - `formatProposeNextStep` — the visually-distinct "branch pushed; open the
9
+ * review" block emitted after a `propose`-mode completion. It is the ONE
10
+ * thing the human must act on, so it stands out: a blank line before and
11
+ * after, a heading marker, and (on a TTY) ANSI color. Piped/redirected
12
+ * output is plain so logs and pipes stay clean.
13
+ *
14
+ * Cosmetic only — none of this changes gate/done-move/commit/integrate behaviour.
15
+ */
16
+
17
+ /** Minimal shape of the stream we inspect (so tests can pass a fake). */
18
+ export interface TtyLike {
19
+ isTTY?: boolean;
20
+ }
21
+
22
+ /**
23
+ * Decide whether to emit ANSI color: true iff `stream` is an interactive TTY
24
+ * AND `NO_COLOR` is not set (https://no-color.org/ — ANY non-empty value
25
+ * disables color). Plain (false) when piped/redirected or non-interactive, so
26
+ * captured logs never carry escape codes.
27
+ */
28
+ export function shouldUseColor(
29
+ stream: TtyLike | undefined,
30
+ env: NodeJS.ProcessEnv = process.env,
31
+ ): boolean {
32
+ // NO_COLOR: presence (even empty string) disables color, per the convention.
33
+ if (env.NO_COLOR !== undefined) {
34
+ return false;
35
+ }
36
+ return stream?.isTTY === true;
37
+ }
38
+
39
+ // A small, conventional ANSI palette — bold + a bright cyan heading, reset.
40
+ const BOLD = '\u001b[1m';
41
+ const CYAN = '\u001b[36m';
42
+ const RESET = '\u001b[0m';
43
+
44
+ /** Wrap `text` in `codes` + reset when `color`, else return it unchanged. */
45
+ function paint(text: string, color: boolean, ...codes: string[]): string {
46
+ return color ? `${codes.join('')}${text}${RESET}` : text;
47
+ }
48
+
49
+ export interface ProposeNextStepInput {
50
+ /** The pushed work branch (e.g. `work/<slug>`). */
51
+ branch: string;
52
+ /** The arbiter remote the branch was pushed to. */
53
+ arbiter: string;
54
+ /** True iff a provider actually opened a review request (vs. push-only). */
55
+ requestOpened: boolean;
56
+ /** Emit ANSI color (TTY) vs. plain text (piped / `NO_COLOR`). */
57
+ color: boolean;
58
+ }
59
+
60
+ /**
61
+ * Build the propose-mode next-step block: the human's single call to action.
62
+ * It is surrounded by blank lines and led by a heading marker so it cannot be
63
+ * lost in surrounding log noise; on a TTY the heading is bold-cyan, the branch
64
+ * ref is bold, and the next command(s) stand out. The content is accurate to
65
+ * the actual push: the branch/ref that was pushed and the exact next command.
66
+ *
67
+ * Returns the multi-line string (leading + trailing blank line included) so the
68
+ * caller can print it as one unit.
69
+ */
70
+ export function formatProposeNextStep(input: ProposeNextStepInput): string {
71
+ const {branch, arbiter, requestOpened, color} = input;
72
+ const ref = `${arbiter}/${branch}`;
73
+
74
+ const heading = paint('▶ Next step — review required', color, BOLD, CYAN);
75
+ const branchLine = requestOpened
76
+ ? `Pushed ${paint(branch, color, BOLD)} to ${ref} and opened a review.`
77
+ : `Pushed ${paint(branch, color, BOLD)} to ${ref}.`;
78
+
79
+ const lines: string[] = ['', heading, branchLine];
80
+ if (requestOpened) {
81
+ lines.push('Open the review request to land it on main.');
82
+ } else {
83
+ // No provider review created — give the exact command to open one.
84
+ lines.push('Open a PR/MR to land it on main, e.g.:');
85
+ lines.push(` ${paint(`gh pr create --head ${branch}`, color, BOLD)}`);
86
+ }
87
+ lines.push('');
88
+ return lines.join('\n');
89
+ }
@@ -0,0 +1,403 @@
1
+ import {spawn, spawnSync} from 'node:child_process';
2
+ import {existsSync, readFileSync} from 'node:fs';
3
+ import {
4
+ NullHarness,
5
+ pidAlive,
6
+ registerHarness,
7
+ type Harness,
8
+ type HarnessRecord,
9
+ type InteractiveLaunchInput,
10
+ type InteractiveLaunchResult,
11
+ type LaunchInput,
12
+ type LaunchResult,
13
+ } from './harness.js';
14
+ import {generateSessionPath} from './session-path.js';
15
+ import {lastAssistantText} from './watch-session.js';
16
+ import type {HarnessAdapter} from './config.js';
17
+
18
+ /**
19
+ * The **pi** harness adapter (ADR §5) — the first real agent harness
20
+ * `dorfl` drives. It fulfils the harness seam introduced by
21
+ * `agent-workspaces` (`./harness.ts`): launch a job's work-agent command in its
22
+ * worktree, and report liveness from **pi-native signals**.
23
+ *
24
+ * Two design commitments from the task + ADR §5, both encoded here:
25
+ *
26
+ * 1. **Invocation** is the standard work-agent prompt (the constant wrapper +
27
+ * the task's `## Prompt`, assembled by `./prompt.ts`) fed to the pi CLI on
28
+ * stdin, running non-interactively (`--print`) inside the job worktree.
29
+ * 2. **Liveness** is reported from the **PID** (process alive?) PLUS a pointer
30
+ * to the pi **session file** (real activity + an audit trail) — explicitly
31
+ * **NOT filesystem mtime**: a live agent can think for minutes without
32
+ * writing any files, so mtime would mistake a thinking agent for a dead one.
33
+ *
34
+ * ## Session location: `--session <full-path>` (task `session-path-pi-default`)
35
+ *
36
+ * The adapter passes a **deterministic FULL session-FILE path** as `--session
37
+ * <path>` (NOT `--session-dir <dir>`). The caller GENERATES that path once
38
+ * (before launch, so `do --watch` can tail the known path) via {@link
39
+ * generateSessionPath} and threads it in as `LaunchInput.session`; when omitted,
40
+ * the adapter generates a default for its own cwd. pi creates+writes the session
41
+ * at exactly that path (it CREATES a non-existent `--session` file) and
42
+ * `--session` takes precedence over `--session-dir` (verified vs pinned pi
43
+ * source). The default lands under pi's per-cwd sessions folder, so the
44
+ * pi-remote dashboard sees the session and the in-place checkout stays clean.
45
+ * The arg is ABSOLUTE and ends `.jsonl` — required, else pi treats it as a
46
+ * session-ID lookup and exits 1 (see {@link generateSessionPath}).
47
+ *
48
+ * pi specifics stay BEHIND this adapter; the core (`run`, `status`, `do`) talks
49
+ * only to the `Harness` interface. Where running real pi in CI is impractical,
50
+ * the pi CLI is stubbed (see `pi-harness.test.ts`) via the injectable `piBin`.
51
+ *
52
+ * ## Seam contract (what an adapter promises the core)
53
+ *
54
+ * - `launch(input)` runs the work-agent command for ONE job in `input.dir`
55
+ * (the worktree), feeding `input.prompt` to the agent. It returns
56
+ * `{ok, record, detail?}`: `ok` iff the agent completed successfully, and a
57
+ * `record` to persist in `.dorfl-job.json` carrying the **liveness
58
+ * anchor** (`pid`) plus the pi `session` FILE path. The core treats the call
59
+ * as blocking (it runs the test gate immediately after).
60
+ * - `isAlive(record)` answers liveness FROM THE RECORD'S ANCHOR (PID/session),
61
+ * never mtime, so a separate `status`/`do` process can re-derive liveness
62
+ * from a fresh process WITHOUT re-launching the agent.
63
+ */
64
+
65
+ /** The default pi CLI binary name (resolved on `PATH`). */
66
+ export const DEFAULT_PI_BIN = 'pi';
67
+
68
+ export interface PiHarnessOptions {
69
+ /**
70
+ * The pi CLI binary (default `pi` on `PATH`). Tests inject a stub script here
71
+ * so the seam can be exercised without a real model call / network.
72
+ */
73
+ piBin?: string;
74
+ /**
75
+ * Extra arguments inserted before the `--print` invocation (e.g. a pinned
76
+ * `--model`). The adapter always supplies `--print` + `--session <path>`;
77
+ * these layer on top for operator control.
78
+ */
79
+ extraArgs?: string[];
80
+ }
81
+
82
+ /**
83
+ * The pi harness block persisted in a job record. It extends the base
84
+ * {@link HarnessRecord} with pi's concrete liveness pointer — the **session
85
+ * file** — alongside the PID. `gc`/`status` re-derive liveness from these without
86
+ * re-launching pi.
87
+ */
88
+ export interface PiHarnessRecord extends HarnessRecord {
89
+ adapter: 'pi';
90
+ /** Absolute path to the pi session `.jsonl` file (the activity + audit pointer). */
91
+ session?: string;
92
+ }
93
+
94
+ /**
95
+ * The pi adapter. Invocation: `pi [--model <model>] --print --session
96
+ * <full-path>.jsonl [extra]` run in the worktree with the work-agent prompt on
97
+ * stdin. The model is passed NATIVELY as `--model <model>` when set (ADR §13 —
98
+ * the routing intent dorfl controls); auth/keys stay pi's job, never
99
+ * dorfl's. Liveness: the PID is the authoritative "is it running?"
100
+ * signal; the recorded `session` file is the activity + audit pointer surfaced
101
+ * alongside it. NEVER mtime (ADR §5).
102
+ */
103
+ export class PiHarness implements Harness {
104
+ readonly adapter = 'pi';
105
+ private readonly piBin: string;
106
+ private readonly extraArgs: string[];
107
+
108
+ constructor(options: PiHarnessOptions = {}) {
109
+ this.piBin = options.piBin ?? DEFAULT_PI_BIN;
110
+ this.extraArgs = options.extraArgs ?? [];
111
+ }
112
+
113
+ /**
114
+ * Resolve the full session-FILE path for a launch. The CALLER normally
115
+ * generates this (via {@link generateSessionPath}) and passes it in
116
+ * `input.session` so the watcher knows it BEFORE launch; when omitted (e.g. a
117
+ * direct adapter call), generate a default under pi's per-cwd folder from the
118
+ * launch dir. Either way the result is absolute and ends `.jsonl`.
119
+ */
120
+ private resolveSessionFile(input: LaunchInput): string {
121
+ return (
122
+ input.session ?? generateSessionPath({cwd: input.dir, id: input.slug})
123
+ );
124
+ }
125
+
126
+ /** Build the pi argv: `[--model m] [extra] --print --session <file>`. */
127
+ private buildArgs(input: LaunchInput, sessionFile: string): string[] {
128
+ // The model ROUTING intent (ADR §13): when set, pass it NATIVELY as
129
+ // `--model <model>`. dorfl only chooses the model; pi owns auth/keys.
130
+ const modelArgs =
131
+ input.model !== undefined && input.model !== ''
132
+ ? ['--model', input.model]
133
+ : [];
134
+ // Non-interactive (`--print`): pi processes the prompt and exits. We pass
135
+ // the FULL session FILE path (`--session`, never `--session-dir`): pi
136
+ // creates+writes it there, it is visible to the dashboard, and nothing
137
+ // lands in the checkout. The operator's `extraArgs` still layer on.
138
+ return [
139
+ ...modelArgs,
140
+ ...this.extraArgs,
141
+ '--print',
142
+ '--session',
143
+ sessionFile,
144
+ ];
145
+ }
146
+
147
+ launch(input: LaunchInput): LaunchResult {
148
+ const sessionFile = this.resolveSessionFile(input);
149
+ const args = this.buildArgs(input, sessionFile);
150
+ const result = spawnSync(this.piBin, args, {
151
+ // Spawn pi with cwd = the repo/worktree dir so the NEW session's header
152
+ // `cwd` groups it correctly in the dashboard (invariant #3) — the folder
153
+ // does NOT imply the repo.
154
+ cwd: input.dir,
155
+ encoding: 'utf8',
156
+ input: input.prompt,
157
+ env: input.env ?? process.env,
158
+ maxBuffer: 64 * 1024 * 1024,
159
+ });
160
+ if (result.error) {
161
+ throw new Error(
162
+ `failed to spawn pi (${this.piBin}): ${result.error.message}`,
163
+ );
164
+ }
165
+ // Record the pi child's PID (the liveness anchor) + the exact session FILE
166
+ // path pi used (the pi-native activity + audit trail). Liveness later reads
167
+ // these — NOT a filesystem mtime (ADR §5).
168
+ const record: PiHarnessRecord = {
169
+ adapter: 'pi',
170
+ pid: result.pid,
171
+ command: [this.piBin, ...args].join(' '),
172
+ session: sessionFile,
173
+ };
174
+ const status = result.status ?? -1;
175
+ return {
176
+ ok: status === 0,
177
+ record,
178
+ detail: status === 0 ? undefined : (result.stderr ?? '').trim(),
179
+ // The agent's ANSWER (task `harness-agent-output`): the LAST assistant
180
+ // turn's text read from the session `.jsonl` pi just wrote — NOT piped
181
+ // stdout (which is drained). Shares `watch-session.ts`'s reader.
182
+ output: readLastAssistantText(sessionFile),
183
+ };
184
+ }
185
+
186
+ /**
187
+ * The ASYNC twin of {@link launch} — IDENTICAL semantics (same `--print
188
+ * --session <file>` invocation, same prompt on stdin, output still CAPTURED,
189
+ * same `LaunchResult` shape: PID anchor + session pointer + ok/detail), but
190
+ * launched NON-BLOCKING with `spawn` instead of the synchronous `spawnSync`.
191
+ * This is the one structural carve-out the `do --watch` observer needs (task
192
+ * `do-watch`): `spawnSync` blocks the event loop until pi exits, so NOTHING
193
+ * could tail the growing session `.jsonl` concurrently. `launchAsync` runs pi
194
+ * alongside the tailer; the WHOLE launch delta is `spawnSync` → `spawn`. The
195
+ * prompt is still fed on stdin and stdout/stderr are still captured; we read
196
+ * the `.jsonl` LOG, never piped stdout.
197
+ *
198
+ * ## Resolve on `exit`, NOT `close` (runner-hang fix)
199
+ *
200
+ * The promise resolves on the child's **`exit`** event (pi itself terminated),
201
+ * NOT `close`. `close` fires only once EVERY stdio pipe of the child is closed
202
+ * — which includes pipes INHERITED by any grandchild pi spawned (an MCP server,
203
+ * a model proxy, a subshell). If such a grandchild OUTLIVES pi holding the
204
+ * inherited stdout/stderr write end, `close` never fires and this promise never
205
+ * resolves — the `advance --watch` surface/triage/apply leg then finishes its
206
+ * work but its awaited launch hangs forever, burning a CI runner (and one of the
207
+ * `max-parallel` slots) until cancelled. `exit` fires the instant pi exits, so
208
+ * we key completion off pi's OWN death, not its descendants'. We still read the
209
+ * agent's answer from the `.jsonl` (final once pi exited, independent of
210
+ * stdout), then DESTROY our end of the stdio pipes so a leaked grandchild's
211
+ * inherited FDs release what they can. A lingering grandchild may still hold an
212
+ * OS pipe end open (keeping the event loop non-empty); the CLI verbs that call
213
+ * this path `process.exit(code)` after the awaited result, which is the
214
+ * belt-and-suspenders backstop bounding any such residual leak.
215
+ */
216
+ launchAsync(input: LaunchInput): Promise<LaunchResult> {
217
+ const sessionFile = this.resolveSessionFile(input);
218
+ const args = this.buildArgs(input, sessionFile);
219
+ const record: PiHarnessRecord = {
220
+ adapter: 'pi',
221
+ command: [this.piBin, ...args].join(' '),
222
+ session: sessionFile,
223
+ };
224
+ return new Promise<LaunchResult>((resolve, reject) => {
225
+ const child = spawn(this.piBin, args, {
226
+ // Same as `launch`: spawn in the repo/worktree dir so the session
227
+ // header `cwd` groups the dashboard correctly (invariant #3).
228
+ cwd: input.dir,
229
+ env: input.env ?? process.env,
230
+ stdio: ['pipe', 'pipe', 'pipe'],
231
+ });
232
+ record.pid = child.pid; // the liveness anchor, recorded like spawnSync.
233
+ let stderr = '';
234
+ child.stderr?.on('data', (chunk: Buffer) => {
235
+ stderr += chunk.toString('utf8');
236
+ });
237
+ // Output is CAPTURED (not piped through) — `--watch` reads the .jsonl log,
238
+ // not stdout. We drain stdout so the pipe never fills and stalls pi.
239
+ child.stdout?.on('data', () => {});
240
+ // Guard so `exit` and a late `error` never double-settle the promise.
241
+ let settled = false;
242
+ child.on('error', (err) => {
243
+ if (settled) {
244
+ return;
245
+ }
246
+ settled = true;
247
+ reject(new Error(`failed to spawn pi (${this.piBin}): ${err.message}`));
248
+ });
249
+ // Resolve on `exit` (pi itself terminated), NOT `close`: `close` waits for
250
+ // EVERY child stdio pipe to close, including any INHERITED by a grandchild
251
+ // pi spawned that outlives it — which would hang this promise forever (see
252
+ // the doc-comment above). Then destroy our stdio ends to release the pipes.
253
+ child.on('exit', (code) => {
254
+ if (settled) {
255
+ return;
256
+ }
257
+ settled = true;
258
+ // Release our end of the stdio pipes so a leaked grandchild's inherited
259
+ // FDs stop keeping our streams referenced; `unref` the child handle too.
260
+ child.stdout?.destroy();
261
+ child.stderr?.destroy();
262
+ child.stdin?.destroy();
263
+ child.unref?.();
264
+ const status = code ?? -1;
265
+ resolve({
266
+ ok: status === 0,
267
+ record,
268
+ detail: status === 0 ? undefined : stderr.trim(),
269
+ // Read the agent's ANSWER from the `.jsonl` at `exit` — the same
270
+ // last-assistant-text read `launch` does at return (task
271
+ // `harness-agent-output`); the process has exited so the log is final.
272
+ output: readLastAssistantText(sessionFile),
273
+ });
274
+ });
275
+ // Feed the same prepared prompt on stdin, then close it (pi reads to EOF).
276
+ if (input.prompt !== undefined) {
277
+ child.stdin?.write(input.prompt);
278
+ }
279
+ child.stdin?.end();
280
+ });
281
+ }
282
+
283
+ /**
284
+ * Launch pi INTERACTIVELY (task `agent-interactive-launch`, decision #2): a
285
+ * FOREGROUND human session in `input.dir`. The whole delta from {@link launch}
286
+ * is the stdio contract:
287
+ *
288
+ * - **NO `--print`** — a real interactive session the human types into (the
289
+ * autonomous form is `pi --print …`, prompt on stdin, captured).
290
+ * - **`stdio: 'inherit'`** — the human's terminal IS pi's terminal (foreground).
291
+ * - **NO piped prompt** — the human drives; nothing is fed on stdin.
292
+ * - **`--model <model>`** still flows in when set (ADR §13: the resolved
293
+ * routing pins the human's starting model; they may switch inside pi).
294
+ * - **`--session <path>`** is STILL passed so the human session is recorded /
295
+ * dashboard-visible (audit trail), exactly as the autonomous path records it.
296
+ *
297
+ * It BLOCKS in the foreground until the human exits (`spawnSync` + inherited
298
+ * stdio), then returns their exit code. It is NOT a tracked job (decision #3):
299
+ * no `.dorfl-job.json`, no PID/liveness record, no gate — there is
300
+ * nothing to capture, so it returns only the exit code.
301
+ */
302
+ launchInteractive(input: InteractiveLaunchInput): InteractiveLaunchResult {
303
+ const sessionFile = this.resolveSessionFile({
304
+ dir: input.dir,
305
+ slug: input.slug,
306
+ command: '',
307
+ session: input.session,
308
+ });
309
+ // The model ROUTING intent (ADR §13): when set, pass it NATIVELY as
310
+ // `--model <model>`. dorfl only chooses the model; pi owns auth/keys.
311
+ const modelArgs =
312
+ input.model !== undefined && input.model !== ''
313
+ ? ['--model', input.model]
314
+ : [];
315
+ // NO `--print` (a real foreground session), but STILL `--session <path>` so
316
+ // the human session is recorded + dashboard-visible. The operator's
317
+ // `extraArgs` still layer on.
318
+ const args = [...modelArgs, ...this.extraArgs, '--session', sessionFile];
319
+ const result = spawnSync(this.piBin, args, {
320
+ // Run in the onboarded working tree so the session header `cwd` groups it
321
+ // correctly in the dashboard (invariant #3) and the human starts there.
322
+ cwd: input.dir,
323
+ // INHERIT the human's stdio: their terminal IS pi's terminal (foreground,
324
+ // interactive) — the opposite of the captured autonomous launch.
325
+ stdio: 'inherit',
326
+ env: input.env ?? process.env,
327
+ });
328
+ if (result.error) {
329
+ throw new Error(
330
+ `failed to spawn pi (${this.piBin}): ${result.error.message}`,
331
+ );
332
+ }
333
+ return {exitCode: result.status ?? -1};
334
+ }
335
+
336
+ isAlive(record: HarnessRecord): boolean {
337
+ return pidAlive(record.pid);
338
+ }
339
+
340
+ /**
341
+ * The recorded pi session-FILE pointer for a job — the pi-native activity +
342
+ * audit trail surfaced alongside PID liveness. `undefined` when the record has
343
+ * no session pointer (e.g. a non-pi or legacy record). Existence on disk is
344
+ * reported separately so callers can distinguish "recorded but gone" from
345
+ * "never recorded".
346
+ */
347
+ sessionPointer(record: HarnessRecord): string | undefined {
348
+ return record.session;
349
+ }
350
+ }
351
+
352
+ /**
353
+ * Does a job record carry a live pi session file on disk? Combines the recorded
354
+ * pointer with an `existsSync` check. This is the pi-native "is there an audit
355
+ * trail to look at?" signal — distinct from PID liveness, and STILL not mtime
356
+ * (we check existence, never modification time).
357
+ */
358
+ export function piSessionExists(record: HarnessRecord): boolean {
359
+ return record.session !== undefined && existsSync(record.session);
360
+ }
361
+
362
+ /**
363
+ * Read the LAST assistant message's text from the pi session `.jsonl` at
364
+ * `sessionFile` — the agent's final ANSWER, surfaced as `LaunchResult.output`
365
+ * (task `harness-agent-output`). Called by BOTH `launch` (at return) and
366
+ * `launchAsync` (at `close`), AFTER pi has exited so the log is complete.
367
+ *
368
+ * It REUSES `watch-session.ts`'s {@link lastAssistantText} (one `.jsonl` parser,
369
+ * not two). An absent file (pi never wrote it) yields `undefined`, as does a log
370
+ * with no assistant text — a read error is never thrown back into the launch.
371
+ */
372
+ function readLastAssistantText(sessionFile: string): string | undefined {
373
+ let jsonl: string;
374
+ try {
375
+ jsonl = readFileSync(sessionFile, 'utf8');
376
+ } catch {
377
+ return undefined; // no session log on disk — no answer to surface.
378
+ }
379
+ return lastAssistantText(jsonl);
380
+ }
381
+
382
+ // Register the pi adapter so `status`/`do`/`gc` resolve liveness for `pi` jobs
383
+ // to THIS adapter (PID + session pointer) rather than the null fallback. A
384
+ // default-configured instance is sufficient for liveness (the binary/extra args
385
+ // only matter for `launch`, which the core does via an explicit instance).
386
+ registerHarness(new PiHarness());
387
+
388
+ /**
389
+ * Build the harness that LAUNCHES jobs for a run, from config (ADR §5): `pi`
390
+ * ⇒ the pi adapter (invoking `config.piBin`); anything else ⇒ the null adapter
391
+ * (shelling out to `agentCmd`). This is the single place the core turns the
392
+ * declared `harness` selector into a concrete adapter, keeping pi specifics
393
+ * behind the seam.
394
+ */
395
+ export function createHarness(options: {
396
+ harness?: HarnessAdapter;
397
+ piBin?: string;
398
+ }): Harness {
399
+ if (options.harness === 'pi') {
400
+ return new PiHarness({piBin: options.piBin});
401
+ }
402
+ return new NullHarness();
403
+ }