@maycombhq/atticus 2.0.0-beta.2 → 2.0.0-beta.21

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 (273) hide show
  1. package/dist/bin.js +8 -4
  2. package/dist/chunk-265LWMOA.js +91 -0
  3. package/dist/chunk-26WBY34Y.js +37 -0
  4. package/dist/{chunk-UBBC2XSG.js → chunk-26Z7OGQW.js} +518 -93
  5. package/dist/chunk-2D7PWSOK.js +172 -0
  6. package/dist/{chunk-JCZIKA4C.js → chunk-2HH3UCZM.js} +4 -4
  7. package/dist/{chunk-GDLULHTC.js → chunk-2HTEMYTB.js} +12 -26
  8. package/dist/chunk-2UCRFXFZ.js +130 -0
  9. package/dist/{chunk-MVZVGYXH.js → chunk-2V2ZPQQU.js} +81 -13
  10. package/dist/{chunk-BOHJZTEQ.js → chunk-36RY7ZXM.js} +130 -71
  11. package/dist/{chunk-I3E7CX4H.js → chunk-37WE3LS2.js} +3 -3
  12. package/dist/{chunk-IPKHE5D6.js → chunk-3AQ2R5NL.js} +1520 -871
  13. package/dist/chunk-3G6S7LAA.js +43 -0
  14. package/dist/chunk-3J5I7ZOU.js +58 -0
  15. package/dist/{chunk-65NYPGRC.js → chunk-3LZ6P5EP.js} +1 -1
  16. package/dist/chunk-3SSTNB4E.js +191 -0
  17. package/dist/chunk-3TD6S4TC.js +49 -0
  18. package/dist/{chunk-3C7EYRFZ.js → chunk-3UTYPHN3.js} +1 -1
  19. package/dist/{chunk-G2B4ZQGH.js → chunk-3WON4G3M.js} +2 -2
  20. package/dist/{chunk-S3QNRWYR.js → chunk-42EPP7OB.js} +12 -12
  21. package/dist/chunk-455SYIIE.js +113 -0
  22. package/dist/{chunk-YISXLPHN.js → chunk-4B6BT75O.js} +166 -23
  23. package/dist/{chunk-C6EKFH7J.js → chunk-4CLK2RJO.js} +7 -7
  24. package/dist/chunk-4CYTJ5TZ.js +38 -0
  25. package/dist/{chunk-EYWIDJFU.js → chunk-4D62IZII.js} +5 -5
  26. package/dist/chunk-4FOAYLI4.js +328 -0
  27. package/dist/{chunk-7JUKDRSZ.js → chunk-4KNOJC6J.js} +294 -215
  28. package/dist/{chunk-YMZ3TNYB.js → chunk-4PYC2UGC.js} +2 -2
  29. package/dist/{chunk-27NKUS3X.js → chunk-4SLBCEPD.js} +2104 -726
  30. package/dist/chunk-4TKVU2I2.js +122 -0
  31. package/dist/{chunk-RUVFXE2L.js → chunk-4WXRPQDE.js} +448 -47
  32. package/dist/{chunk-7ZUIMTOU.js → chunk-5CMPVC3N.js} +24 -24
  33. package/dist/chunk-5G7ILBUG.js +66 -0
  34. package/dist/{chunk-HFQCFSJR.js → chunk-5PV7S2ZP.js} +3 -3
  35. package/dist/{chunk-FITWGOJ2.js → chunk-5QUOPNLN.js} +4 -4
  36. package/dist/{chunk-Z6LF7HQN.js → chunk-5TDRBOAV.js} +5 -5
  37. package/dist/{chunk-T6AIP7H5.js → chunk-5WERBKLE.js} +199 -63
  38. package/dist/{chunk-XPCM366L.js → chunk-62DLJSLV.js} +8 -8
  39. package/dist/{chunk-L24C55VN.js → chunk-64AADMTW.js} +99 -25
  40. package/dist/{chunk-K65BJIMT.js → chunk-67BP7HXL.js} +17 -17
  41. package/dist/chunk-6DQYZU2W.js +379 -0
  42. package/dist/{chunk-EDS2L2LD.js → chunk-6EXDI5GI.js} +52 -26
  43. package/dist/chunk-6FNAKCET.js +38 -0
  44. package/dist/{chunk-6IU67AEK.js → chunk-75ASLHBT.js} +21 -15
  45. package/dist/{chunk-A3GY6SOA.js → chunk-75ZOZFGH.js} +18 -18
  46. package/dist/{chunk-MGYZM27B.js → chunk-77O633L5.js} +49 -23
  47. package/dist/{chunk-GQ4N4WKF.js → chunk-7AB6OWTV.js} +3 -3
  48. package/dist/{chunk-M766ZJ6W.js → chunk-7CZHUZBL.js} +25 -25
  49. package/dist/{chunk-A7UPUQFY.js → chunk-7FHNFCHK.js} +643 -124
  50. package/dist/chunk-7FUIVIBG.js +415 -0
  51. package/dist/{chunk-6QSERWXH.js → chunk-7QPCGTPS.js} +21 -21
  52. package/dist/{chunk-LR3R6Z2A.js → chunk-A2G72UI4.js} +7 -7
  53. package/dist/{chunk-I4JRCD6M.js → chunk-AE4P57KK.js} +23 -17
  54. package/dist/{chunk-AVJDSJ2F.js → chunk-AHW3RY3X.js} +7 -7
  55. package/dist/chunk-AM6FP6JW.js +43 -0
  56. package/dist/{chunk-CSZ4C5N6.js → chunk-AOCWFA7T.js} +93 -10
  57. package/dist/{chunk-EPTBZ3GP.js → chunk-API5TOUB.js} +1 -1
  58. package/dist/{chunk-652QWTLZ.js → chunk-AZDITBCT.js} +3 -3
  59. package/dist/{chunk-DPUYDDQG.js → chunk-BA2HUMDN.js} +25 -3
  60. package/dist/chunk-BA3U7ALS.js +99 -0
  61. package/dist/{chunk-HVUPKCGJ.js → chunk-BC6KKZ67.js} +5 -5
  62. package/dist/{chunk-CKSITVS4.js → chunk-BEPCKDCP.js} +2554 -722
  63. package/dist/{chunk-3ALD2W2A.js → chunk-BPPU3PW7.js} +4 -4
  64. package/dist/{chunk-QRAOANID.js → chunk-BVWWPBKD.js} +21 -21
  65. package/dist/{chunk-ZDPAS56H.js → chunk-BXBCMGIQ.js} +7 -1
  66. package/dist/chunk-BXZ4PKIT.js +233 -0
  67. package/dist/chunk-C7CEK3KW.js +247 -0
  68. package/dist/chunk-CFH3QH26.js +29 -0
  69. package/dist/chunk-CG6CULP6.js +170 -0
  70. package/dist/chunk-CLD4RVTA.js +45 -0
  71. package/dist/{chunk-DKJA76CJ.js → chunk-CNPY4NTZ.js} +13 -13
  72. package/dist/chunk-CNU5Q2D5.js +575 -0
  73. package/dist/{chunk-T2UYZSCQ.js → chunk-COYN3UAN.js} +126 -23
  74. package/dist/{chunk-23W7VWKR.js → chunk-CPK7QSBG.js} +1360 -113
  75. package/dist/{chunk-4AK7IBVP.js → chunk-D2WSW4GU.js} +1 -1
  76. package/dist/{chunk-ABWHYWNI.js → chunk-D57MFJPP.js} +3 -3
  77. package/dist/chunk-D5KV5PSK.js +45 -0
  78. package/dist/chunk-D5MASS4I.js +48 -0
  79. package/dist/{chunk-7EOBHUMC.js → chunk-DCWN3HFV.js} +2 -2
  80. package/dist/{chunk-QSXK2RGH.js → chunk-DDJPM5YX.js} +2 -2
  81. package/dist/chunk-DN4A2Q2O.js +57 -0
  82. package/dist/{chunk-IHMLFRVV.js → chunk-DUPZPDCJ.js} +58 -16
  83. package/dist/{chunk-PRPPGYZG.js → chunk-E2VXBSIR.js} +4 -4
  84. package/dist/chunk-E57AOFYN.js +32 -0
  85. package/dist/{chunk-UGLN7QHV.js → chunk-ECLXZWAG.js} +12 -12
  86. package/dist/{chunk-5WG5YP4T.js → chunk-EDZ45WIR.js} +14 -14
  87. package/dist/chunk-EFCQSMXB.js +37 -0
  88. package/dist/{chunk-2ANOROX3.js → chunk-EZIN5E5B.js} +8 -8
  89. package/dist/{chunk-BWZ77RQT.js → chunk-F6H2RJ3N.js} +1 -1
  90. package/dist/{chunk-OLQJTJJU.js → chunk-FAJDKNSD.js} +7 -3
  91. package/dist/chunk-FGAGWYZB.js +47 -0
  92. package/dist/{chunk-4WBVUHXN.js → chunk-FLVZFTLQ.js} +18 -18
  93. package/dist/chunk-FQ6WH6PB.js +140 -0
  94. package/dist/{chunk-T6XQL73F.js → chunk-FRHD22WM.js} +61 -23
  95. package/dist/{chunk-XAKWMCXI.js → chunk-FVMPFCDS.js} +4 -4
  96. package/dist/{chunk-B2WLAWNJ.js → chunk-FY3QIRTL.js} +3 -3
  97. package/dist/{chunk-CPA6HPVR.js → chunk-FYBF5MB2.js} +15 -11
  98. package/dist/{chunk-V2YTAIQO.js → chunk-G5YJBNDZ.js} +21 -6
  99. package/dist/chunk-G6IQYM25.js +339 -0
  100. package/dist/chunk-G6X4YL4D.js +161 -0
  101. package/dist/{chunk-SJRGMG6A.js → chunk-GC2VK3JT.js} +25 -25
  102. package/dist/{chunk-SP2I63OO.js → chunk-GCS3FZOB.js} +77 -3
  103. package/dist/{chunk-6TACQN3N.js → chunk-GDZB57IU.js} +5 -5
  104. package/dist/chunk-GIFMBCTW.js +221 -0
  105. package/dist/{chunk-YY6ZQQBP.js → chunk-GK4PYVEC.js} +18 -8
  106. package/dist/{chunk-TDD55CJH.js → chunk-GNWAOVFQ.js} +6 -5
  107. package/dist/chunk-GS76RXQE.js +226 -0
  108. package/dist/{chunk-YYQN46FY.js → chunk-GSGIZ2OO.js} +23 -23
  109. package/dist/chunk-GUYL7RMK.js +60 -0
  110. package/dist/chunk-GX74YWR7.js +321 -0
  111. package/dist/chunk-HE3HRDNZ.js +122 -0
  112. package/dist/{chunk-AIOQPLA5.js → chunk-HGHRSF3E.js} +30 -12
  113. package/dist/{chunk-2RMYG36Q.js → chunk-HK3VOHIE.js} +198 -336
  114. package/dist/{chunk-QZSX3F7C.js → chunk-HS4BGB4G.js} +24 -22
  115. package/dist/{chunk-XY3P7JW7.js → chunk-HSZMPH5T.js} +834 -149
  116. package/dist/{chunk-L6SGQIR3.js → chunk-HWD4JPU7.js} +4 -2
  117. package/dist/{chunk-PCVDV3UZ.js → chunk-HXXP2NTE.js} +6 -6
  118. package/dist/{chunk-AA6YULYB.js → chunk-I2A3Z5AK.js} +7 -7
  119. package/dist/{chunk-N7IXEHK3.js → chunk-ICHDSWEY.js} +7 -7
  120. package/dist/chunk-IFFRGC3N.js +31 -0
  121. package/dist/{chunk-4BN53TG3.js → chunk-IFHDV6KQ.js} +31 -23
  122. package/dist/chunk-J2O4LFVI.js +80 -0
  123. package/dist/chunk-J5AAZ6OJ.js +161 -0
  124. package/dist/{chunk-ZMFPW66A.js → chunk-JAABT3DA.js} +3 -3
  125. package/dist/chunk-JITJP64K.js +34 -0
  126. package/dist/chunk-JKIGL3XQ.js +162 -0
  127. package/dist/chunk-JRVNXLZP.js +615 -0
  128. package/dist/chunk-JRXHON4E.js +41 -0
  129. package/dist/{chunk-DHPACDG7.js → chunk-JS6WMC3J.js} +8 -8
  130. package/dist/chunk-JU4QNJSR.js +62 -0
  131. package/dist/{chunk-PAMPPUR6.js → chunk-JYMIB5XY.js} +1697 -172
  132. package/dist/{chunk-RRTKKSLQ.js → chunk-JYTIHTIK.js} +8 -6
  133. package/dist/{chunk-3HI6Z55Y.js → chunk-K332XW7K.js} +324 -39
  134. package/dist/{chunk-GLUX4EEP.js → chunk-K6JB6XTX.js} +9 -9
  135. package/dist/chunk-KDAHXQIE.js +294 -0
  136. package/dist/chunk-KYZMRSPS.js +93 -0
  137. package/dist/chunk-L4CESDPB.js +22 -0
  138. package/dist/{chunk-NXFPS2LR.js → chunk-LEBR5NHW.js} +14 -14
  139. package/dist/chunk-LIJJCBQI.js +223 -0
  140. package/dist/{chunk-DE76JROX.js → chunk-LIRVU3HW.js} +16 -16
  141. package/dist/{chunk-JMSCMUCA.js → chunk-LN77DXBM.js} +145 -21
  142. package/dist/{chunk-JIITQXFB.js → chunk-LNWEWYCM.js} +2969 -788
  143. package/dist/{chunk-TANFV3MZ.js → chunk-LO3BLMVG.js} +3 -3
  144. package/dist/chunk-LPV6T362.js +250 -0
  145. package/dist/{chunk-2VHF7OXM.js → chunk-LQH4P45K.js} +1 -1
  146. package/dist/chunk-LU4MQVAL.js +41 -0
  147. package/dist/chunk-LWDNKE4X.js +273 -0
  148. package/dist/chunk-M4H2UG4R.js +218 -0
  149. package/dist/{chunk-6BVONWJ7.js → chunk-M6D2U3YM.js} +3 -3
  150. package/dist/chunk-MD7KUEJ3.js +514 -0
  151. package/dist/{chunk-66YVAGGM.js → chunk-MMZUN7ZO.js} +20 -20
  152. package/dist/chunk-MZGRDONP.js +916 -0
  153. package/dist/chunk-N3RUGTGV.js +39 -0
  154. package/dist/{chunk-JGZCG5VM.js → chunk-NCB6656Z.js} +7 -7
  155. package/dist/{chunk-4NDAAFQT.js → chunk-NRQ65LTQ.js} +7 -5
  156. package/dist/{chunk-UNM6ZOKP.js → chunk-NTAVOWYD.js} +145 -18
  157. package/dist/{chunk-3USYZGRF.js → chunk-NYOABJNK.js} +36 -27
  158. package/dist/{chunk-WVPJSRRJ.js → chunk-O4IKAIZ2.js} +24 -20
  159. package/dist/{chunk-D3PO4DOZ.js → chunk-ODMBPDDV.js} +51 -14
  160. package/dist/chunk-OKUB6RJA.js +533 -0
  161. package/dist/chunk-OMPENNWY.js +39 -0
  162. package/dist/chunk-OPQZISG3.js +25 -0
  163. package/dist/{chunk-5GGOLAKC.js → chunk-OV57AHCG.js} +26 -26
  164. package/dist/chunk-OZJ3JLYI.js +58 -0
  165. package/dist/{chunk-KEM4SDDP.js → chunk-P2VBXX7N.js} +11 -10
  166. package/dist/{chunk-S2A7YC3Q.js → chunk-PAINMSID.js} +10150 -1720
  167. package/dist/chunk-PKJAV25S.js +43 -0
  168. package/dist/{chunk-EBEW3XXQ.js → chunk-PNQLCRSS.js} +4 -4
  169. package/dist/{chunk-WY6PP6AA.js → chunk-PQH56YF6.js} +37 -5
  170. package/dist/chunk-PRTBPXYA.js +50 -0
  171. package/dist/{chunk-YEDDOYSC.js → chunk-PRW3HXM3.js} +2 -2
  172. package/dist/chunk-PRZ7KMWL.js +42 -0
  173. package/dist/{chunk-6M5NK3K3.js → chunk-PTQ3ZALZ.js} +42 -4
  174. package/dist/{chunk-5GDRCDQB.js → chunk-PUEWDYGP.js} +2 -2
  175. package/dist/chunk-Q26LDIUV.js +236 -0
  176. package/dist/{chunk-CR3MTH32.js → chunk-Q46QDDMF.js} +77 -7
  177. package/dist/chunk-QBNWF5ZU.js +19 -0
  178. package/dist/chunk-QE527XRY.js +342 -0
  179. package/dist/{chunk-CNUKCS2T.js → chunk-QHJJMZLX.js} +1518 -54
  180. package/dist/chunk-QJCJOMW3.js +425 -0
  181. package/dist/{chunk-VYDBJ73M.js → chunk-QKMRFNMA.js} +15 -15
  182. package/dist/chunk-QOOEYDNJ.js +317 -0
  183. package/dist/chunk-QSIDVFB7.js +45 -0
  184. package/dist/{chunk-R77KLRB3.js → chunk-RA33EYS4.js} +19 -18
  185. package/dist/{chunk-DFBCSHVT.js → chunk-RALY3E5U.js} +4 -4
  186. package/dist/{chunk-ZCJDOK2S.js → chunk-S2RY3BOD.js} +35 -21
  187. package/dist/chunk-S5LSDXV4.js +40 -0
  188. package/dist/chunk-SB5GRUFM.js +54 -0
  189. package/dist/chunk-SH27FYPF.js +150 -0
  190. package/dist/chunk-T74WQQGS.js +40 -0
  191. package/dist/{chunk-O3WI5KWW.js → chunk-TGVVUKTG.js} +2 -2
  192. package/dist/chunk-THN26IEF.js +48 -0
  193. package/dist/chunk-TJH2EUAZ.js +47 -0
  194. package/dist/{chunk-ZNCEKR4J.js → chunk-TQ4TG57V.js} +12 -8
  195. package/dist/{chunk-7FBGJFEE.js → chunk-TQTRWENN.js} +12 -12
  196. package/dist/{chunk-TYAID7B7.js → chunk-TSM6T6GQ.js} +23 -23
  197. package/dist/{chunk-DPZHZQKE.js → chunk-TW3KOSQK.js} +43 -10
  198. package/dist/{chunk-MC3H7736.js → chunk-TWQRPM76.js} +37 -4
  199. package/dist/chunk-TYD6I4CZ.js +109 -0
  200. package/dist/chunk-U3NBK4EU.js +420 -0
  201. package/dist/{chunk-6JCPI55B.js → chunk-UDXWIPCB.js} +47 -7
  202. package/dist/{chunk-MMOSZPWJ.js → chunk-UEVZZZU2.js} +4 -4
  203. package/dist/{chunk-JBTK5OP2.js → chunk-UF4UHCIG.js} +2 -2
  204. package/dist/{chunk-6JUBZBMW.js → chunk-UFE36WJH.js} +4 -4
  205. package/dist/{chunk-ONLS5QA5.js → chunk-URIKUID7.js} +12 -12
  206. package/dist/chunk-UYLBRRFK.js +1106 -0
  207. package/dist/chunk-UZACEG2C.js +515 -0
  208. package/dist/{chunk-7SW2QWLU.js → chunk-VAMHOHUU.js} +12 -12
  209. package/dist/{chunk-RZPYKDWS.js → chunk-VUVGX5L2.js} +1 -1
  210. package/dist/{chunk-Q4D5X7QB.js → chunk-VYOCPTUB.js} +44 -24
  211. package/dist/{chunk-CAQZUNOH.js → chunk-WAZEXEJH.js} +567 -3
  212. package/dist/chunk-WCEF7H6L.js +221 -0
  213. package/dist/{chunk-2DIQQJCB.js → chunk-WEOMJHPV.js} +12 -12
  214. package/dist/{chunk-FHH4I4ZV.js → chunk-WFU77T3A.js} +12 -6
  215. package/dist/chunk-WIWTJMMR.js +292 -0
  216. package/dist/{chunk-2BFCZ3RK.js → chunk-WNTIOBOG.js} +18 -18
  217. package/dist/{chunk-7WD63HU2.js → chunk-X2CUXTWU.js} +6 -6
  218. package/dist/chunk-X7EMBM5X.js +34 -0
  219. package/dist/chunk-XEQCQO66.js +33 -0
  220. package/dist/{chunk-F7HYOUFF.js → chunk-XG4WJHLQ.js} +20 -4
  221. package/dist/{chunk-EFHQ3TWP.js → chunk-XOL3GFW2.js} +171 -31
  222. package/dist/{chunk-NE2W3OO7.js → chunk-XQ3YZ4QW.js} +22 -22
  223. package/dist/{chunk-CEXSU4S6.js → chunk-Y6K3CJBU.js} +723 -85
  224. package/dist/{chunk-4RS5KZQD.js → chunk-YAH5IQAL.js} +5 -5
  225. package/dist/{chunk-64EQYWCA.js → chunk-YBOVNMHC.js} +51 -14
  226. package/dist/chunk-YF5DZCPN.js +1212 -0
  227. package/dist/chunk-YIGBJNH4.js +37 -0
  228. package/dist/{chunk-BKVWTZ6A.js → chunk-YJ3TBOTK.js} +25 -25
  229. package/dist/{chunk-Q5AMFEWD.js → chunk-YKTE2RU3.js} +2 -2
  230. package/dist/{chunk-7EKXJZ2Y.js → chunk-YO2PKTXT.js} +296 -37
  231. package/dist/{chunk-6J5OKA4Y.js → chunk-YTTNTQOX.js} +15 -15
  232. package/dist/{chunk-OT2O76OS.js → chunk-YWAKDNMH.js} +183 -33
  233. package/dist/{chunk-R6XF6UR3.js → chunk-YZDZOEV4.js} +4 -4
  234. package/dist/chunk-Z3QFH7YG.js +17 -0
  235. package/dist/{chunk-W5BVQF44.js → chunk-Z6VLC5X4.js} +17 -17
  236. package/dist/{chunk-HLJAXMM4.js → chunk-ZFQMMU5Y.js} +2 -2
  237. package/dist/{chunk-W3BQAZ3Q.js → chunk-ZKYRDV7A.js} +12 -12
  238. package/dist/{chunk-ZMAINWBW.js → chunk-ZLS6PU2O.js} +3 -3
  239. package/dist/{chunk-ZVM6AKKM.js → chunk-ZOSD4FXV.js} +3 -3
  240. package/dist/chunk-ZPDDEVQX.js +47 -0
  241. package/dist/{chunk-TXLH6WHQ.js → chunk-ZQLRCA2V.js} +11 -11
  242. package/dist/{chunk-HITVBIJS.js → chunk-ZX7235KR.js} +128 -54
  243. package/dist/{chunk-GT4I4ZWM.js → chunk-ZZFHLRQW.js} +18 -16
  244. package/dist/files.json +636 -364
  245. package/dist/packages/naysayer/constitution/constitution.yaml +19 -0
  246. package/dist/packages/sdk/npm/index.js +5614 -2343
  247. package/dist/packages/ui/dist/assets/{elk-api-tma0MCuh.js → elk-api-CowTnhEJ.js} +2 -2
  248. package/dist/packages/ui/dist/assets/index-Dw20IRhQ.css +1 -0
  249. package/dist/packages/ui/dist/assets/index-z2wv0d5d.js +47 -0
  250. package/dist/packages/ui/dist/index.html +2 -2
  251. package/package.json +4 -4
  252. package/dist/chunk-2BF2EYJV.js +0 -174
  253. package/dist/chunk-42EVSKME.js +0 -37
  254. package/dist/chunk-4BKGMUIK.js +0 -53
  255. package/dist/chunk-5KLGBXG5.js +0 -48
  256. package/dist/chunk-6BNC6EQ4.js +0 -41
  257. package/dist/chunk-6D2CQ5II.js +0 -41
  258. package/dist/chunk-7AVHLZGD.js +0 -45
  259. package/dist/chunk-D46WUV3T.js +0 -33
  260. package/dist/chunk-E36QOJMD.js +0 -47
  261. package/dist/chunk-FQXYPF7E.js +0 -147
  262. package/dist/chunk-GBRFVT63.js +0 -45
  263. package/dist/chunk-ICY36XCH.js +0 -34
  264. package/dist/chunk-J4K3KVLD.js +0 -131
  265. package/dist/chunk-JZU3H6UQ.js +0 -54
  266. package/dist/chunk-NN2ZQEB4.js +0 -38
  267. package/dist/chunk-PCOCACY3.js +0 -385
  268. package/dist/chunk-RTEYOSJY.js +0 -29
  269. package/dist/chunk-RVH5SUW5.js +0 -69
  270. package/dist/chunk-VN3DP4LQ.js +0 -43
  271. package/dist/chunk-XPTOBS2D.js +0 -48
  272. package/dist/packages/ui/dist/assets/index-B54fm9FQ.js +0 -29
  273. package/dist/packages/ui/dist/assets/index-DD_hufQz.css +0 -1
@@ -6,55 +6,58 @@ var __atticusPath = (p) => __atticusFileURLToPath(__atticusUrl(p));
6
6
  import {
7
7
  slug,
8
8
  writeGateRound
9
- } from "./chunk-2ANOROX3.js";
9
+ } from "./chunk-EZIN5E5B.js";
10
10
  import {
11
+ catchUpChangeBranch,
11
12
  changeWorktree,
12
13
  handDown,
13
14
  loadTask,
14
15
  openTaskWorktree,
15
- readChangeTasks
16
- } from "./chunk-OT2O76OS.js";
16
+ readChangeTasks,
17
+ setTaskDone
18
+ } from "./chunk-YWAKDNMH.js";
17
19
  import {
18
20
  buildEngineFor
19
- } from "./chunk-IPKHE5D6.js";
21
+ } from "./chunk-3AQ2R5NL.js";
20
22
  import {
21
23
  conform,
22
24
  readConformDeltas,
23
25
  readTaskSteps,
24
26
  renderTaskContext,
25
- taskContext
26
- } from "./chunk-CKSITVS4.js";
27
+ taskContext,
28
+ withBuildLine
29
+ } from "./chunk-BEPCKDCP.js";
27
30
  import {
28
31
  readChangeFiles,
29
32
  readRound,
33
+ readStoryIndex,
30
34
  roundsOf,
31
35
  writeQuarantineItems
32
- } from "./chunk-3HI6Z55Y.js";
36
+ } from "./chunk-K332XW7K.js";
33
37
  import {
34
38
  changeFolder,
35
39
  changeStore
36
- } from "./chunk-XY3P7JW7.js";
40
+ } from "./chunk-HSZMPH5T.js";
37
41
  import {
38
- AdapterError,
39
42
  createAdapters,
40
43
  fileStepStore,
41
44
  requireApproval
42
- } from "./chunk-7JUKDRSZ.js";
45
+ } from "./chunk-4KNOJC6J.js";
43
46
  import {
44
47
  scanEstate
45
- } from "./chunk-27NKUS3X.js";
48
+ } from "./chunk-4SLBCEPD.js";
46
49
  import {
47
50
  baseClonePath,
48
51
  createGit,
49
52
  toRepoRelative
50
- } from "./chunk-EFHQ3TWP.js";
53
+ } from "./chunk-XOL3GFW2.js";
51
54
  import {
52
55
  HandoffRuntime,
53
56
  buildContextPack,
54
57
  createRuntime,
55
58
  quarantineItems,
56
59
  toRunSummary
57
- } from "./chunk-CNUKCS2T.js";
60
+ } from "./chunk-QHJJMZLX.js";
58
61
  import {
59
62
  AgentDefinition,
60
63
  ChecklistPack,
@@ -74,10 +77,12 @@ import {
74
77
  stateDirOf,
75
78
  taskBranch,
76
79
  toCanonicalYaml
77
- } from "./chunk-S2A7YC3Q.js";
80
+ } from "./chunk-PAINMSID.js";
78
81
  import {
82
+ LockHeldError,
83
+ acquireLock,
79
84
  writeFileAtomic
80
- } from "./chunk-D3PO4DOZ.js";
85
+ } from "./chunk-ODMBPDDV.js";
81
86
  import {
82
87
  __toESM
83
88
  } from "./chunk-TV45EUGM.js";
@@ -156,27 +161,162 @@ async function applyChanges(worktree, changes) {
156
161
 
157
162
  // packages/taskrun/dist/commands.js
158
163
  import { spawn } from "node:child_process";
164
+ var KEEP_OUTPUT = 4 * 1024 * 1024;
165
+ function tail(max = KEEP_OUTPUT) {
166
+ let text = "";
167
+ let dropped = 0;
168
+ return {
169
+ add(d) {
170
+ text += d;
171
+ if (text.length > max) {
172
+ dropped += text.length - max;
173
+ text = text.slice(text.length - max);
174
+ }
175
+ },
176
+ get text() {
177
+ return dropped ? `[${dropped} characters of output left out]
178
+ ${text}` : text;
179
+ }
180
+ };
181
+ }
182
+ function stopTree(child, signal = "SIGTERM") {
183
+ if (child.pid === void 0)
184
+ return;
185
+ if (process.platform === "win32") {
186
+ const k = spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], { windowsHide: true });
187
+ k.on("error", () => child.kill());
188
+ return;
189
+ }
190
+ try {
191
+ process.kill(-child.pid, signal);
192
+ } catch {
193
+ child.kill(signal);
194
+ }
195
+ }
196
+ var live = /* @__PURE__ */ new Set();
197
+ var SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
198
+ var stopping = false;
199
+ var stopRequested = () => stopping;
200
+ var stopper = new AbortController();
201
+ var stopSignal = stopper.signal;
202
+ function stopAllBuilds() {
203
+ stopping = true;
204
+ for (const c of live)
205
+ stopTree(c);
206
+ if (!stopper.signal.aborted)
207
+ stopper.abort();
208
+ }
209
+ var holds = 0;
210
+ var pending;
211
+ var SIGNAL_GRACE_MS = 1e4;
212
+ var onSignal = (sig) => {
213
+ stopAllBuilds();
214
+ if (process.listenerCount(sig) > 1)
215
+ return;
216
+ if (!pending) {
217
+ pending = sig;
218
+ setTimeout(raise, SIGNAL_GRACE_MS);
219
+ }
220
+ settle();
221
+ };
222
+ function raise() {
223
+ const sig = pending;
224
+ if (!sig)
225
+ return;
226
+ unhook();
227
+ process.kill(process.pid, sig);
228
+ }
229
+ function settle() {
230
+ if (holds > 0 || live.size > 0)
231
+ return;
232
+ if (pending)
233
+ raise();
234
+ else
235
+ unhook();
236
+ }
237
+ var onExit = () => {
238
+ for (const c of live)
239
+ stopTree(c, "SIGKILL");
240
+ };
241
+ var hooked = false;
242
+ function hook() {
243
+ if (hooked)
244
+ return;
245
+ hooked = true;
246
+ for (const s of SIGNALS)
247
+ process.prependListener(s, onSignal);
248
+ process.on("exit", onExit);
249
+ }
250
+ function unhook() {
251
+ if (!hooked)
252
+ return;
253
+ hooked = false;
254
+ for (const s of SIGNALS)
255
+ process.off(s, onSignal);
256
+ process.off("exit", onExit);
257
+ }
258
+ function holdSignals() {
259
+ holds++;
260
+ hook();
261
+ let released = false;
262
+ return () => {
263
+ if (released)
264
+ return;
265
+ released = true;
266
+ holds--;
267
+ settle();
268
+ };
269
+ }
270
+ var track = (c) => {
271
+ live.add(c);
272
+ hook();
273
+ };
274
+ var untrack = (c) => {
275
+ live.delete(c);
276
+ settle();
277
+ };
278
+ var STOP_GRACE_MS = 5e3;
159
279
  function shellCommandRunner() {
160
280
  return (command, cwd, o = {}) => new Promise((resolve) => {
281
+ if (stopping) {
282
+ resolve({ exitCode: null, stdout: "", stderr: "Atticus is stopping.", stopped: true });
283
+ return;
284
+ }
161
285
  const child = spawn(command, {
162
286
  cwd,
163
287
  shell: true,
164
288
  env: { ...process.env, ...o.env },
165
- windowsHide: true
166
- });
167
- let stdout = "";
168
- let stderr = "";
169
- const timer = setTimeout(() => child.kill(), o.timeoutMs ?? 30 * 6e4);
170
- child.stdout.setEncoding("utf8").on("data", (d) => stdout += d);
171
- child.stderr.setEncoding("utf8").on("data", (d) => stderr += d);
172
- child.on("error", (e) => {
173
- clearTimeout(timer);
174
- resolve({ exitCode: null, stdout, stderr: stderr + e.message });
289
+ windowsHide: true,
290
+ // Its own process group off Windows, so a timeout stops the build, not only the shell.
291
+ detached: process.platform !== "win32"
175
292
  });
176
- child.on("close", (code) => {
293
+ track(child);
294
+ const out = tail();
295
+ const err = tail();
296
+ let done2 = false;
297
+ let kill;
298
+ let drain;
299
+ const finish2 = (r) => {
300
+ if (done2)
301
+ return;
302
+ done2 = true;
177
303
  clearTimeout(timer);
178
- resolve({ exitCode: code, stdout, stderr });
304
+ clearTimeout(kill);
305
+ clearTimeout(drain);
306
+ untrack(child);
307
+ resolve(stopping ? { ...r, stopped: true } : r);
308
+ };
309
+ const timer = setTimeout(() => {
310
+ stopTree(child);
311
+ kill = setTimeout(() => stopTree(child, "SIGKILL"), STOP_GRACE_MS);
312
+ }, o.timeoutMs ?? 30 * 6e4);
313
+ child.stdout.setEncoding("utf8").on("data", (d) => out.add(d));
314
+ child.stderr.setEncoding("utf8").on("data", (d) => err.add(d));
315
+ child.on("error", (e) => finish2({ exitCode: null, stdout: out.text, stderr: err.text + e.message }));
316
+ child.on("exit", (code) => {
317
+ drain = setTimeout(() => finish2({ exitCode: code, stdout: out.text, stderr: err.text }), 2e3);
179
318
  });
319
+ child.on("close", (code) => finish2({ exitCode: code, stdout: out.text, stderr: err.text }));
180
320
  });
181
321
  }
182
322
 
@@ -189,13 +329,16 @@ var TaskRunState = external_exports.enum([
189
329
  "planned",
190
330
  /** Hand-off mode: the person's assistant is doing the step. */
191
331
  "waiting",
192
- /** Draft finished with a passing build, committed on the task branch. */
332
+ /**
333
+ * Draft finished with a passing build, committed on the task branch. Also a PR that wasn't
334
+ * raised (the push or the Git host failed): its note says why, and it can be raised again.
335
+ */
193
336
  "built",
194
337
  /** Draft finished but the repo has no build command, so nothing was checked. */
195
338
  "unverified",
196
339
  /** The PR from the task branch to the change branch is open. */
197
340
  "pr-open",
198
- /** The build still fails after the allowed fix rounds, or a PR can't be opened: a person takes over. */
341
+ /** The build still fails after the allowed fix rounds, or a step after it can't be done: a person takes over. */
199
342
  "needs-person",
200
343
  /** The AI run itself failed. */
201
344
  "failed"
@@ -234,6 +377,16 @@ var TaskRunRecord = external_exports.strictObject({
234
377
  changed: external_exports.array(external_exports.string()).default([]),
235
378
  commit: external_exports.string().optional(),
236
379
  pr: external_exports.strictObject({ number: external_exports.number().int().positive(), url: external_exports.string() }).optional(),
380
+ /**
381
+ * Seventh UX walk: when Atticus ticked the task in tasks.md because its PR merged. It ticks a
382
+ * task once, so a person who unticks it keeps it unticked.
383
+ */
384
+ ticked: external_exports.string().optional(),
385
+ /**
386
+ * Eighth UX walk: who last ticked (done) or unticked the task by hand on the Task board, and
387
+ * when, so a task Atticus ticked and a person ticked again says who did.
388
+ */
389
+ marked: external_exports.strictObject({ done: external_exports.boolean(), by: external_exports.string().min(1), at: external_exports.string() }).optional(),
237
390
  startedAt: external_exports.string(),
238
391
  finishedAt: external_exports.string().optional(),
239
392
  notes: external_exports.array(external_exports.string()).default([])
@@ -266,6 +419,23 @@ async function saveRunSummary(root, change, task, s) {
266
419
  await writeFileAtomic(join2(changeFolder(root, change), rel), toCanonicalYaml(RunSummary.parse(s), ["schemaVersion", "runId"]));
267
420
  return rel;
268
421
  }
422
+ async function taskRunOfRun(root, change, runId) {
423
+ for (const t of (await readdir(join2(changeFolder(root, change), "tasks"), { withFileTypes: true }).catch(() => [])).filter((d) => d.isDirectory())) {
424
+ const r = await readTaskRun(root, change, t.name).catch(() => void 0);
425
+ if (r && (r.waiting === runId || r.runs.includes(runId)))
426
+ return r;
427
+ }
428
+ return void 0;
429
+ }
430
+ async function findTaskRunOfRun(root, runId) {
431
+ const changes = changesDirOf(root);
432
+ for (const c of (await readdir(changes, { withFileTypes: true }).catch(() => [])).filter((d) => d.isDirectory() && d.name !== "archive")) {
433
+ const r = await taskRunOfRun(root, c.name, runId).catch(() => void 0);
434
+ if (r)
435
+ return r;
436
+ }
437
+ return void 0;
438
+ }
269
439
  async function findWaitingTaskRun(root, runId) {
270
440
  const changes = changesDirOf(root);
271
441
  for (const c of (await readdir(changes, { withFileTypes: true }).catch(() => [])).filter((d) => d.isDirectory())) {
@@ -374,19 +544,21 @@ ${s.body.trim()}`,
374
544
  trusted: true
375
545
  }))
376
546
  ];
377
- const artifact = (rel, priority) => {
547
+ const artifact = (rel, priority, text = (raw) => raw) => {
378
548
  const d = t.files.docs.get(rel);
379
549
  if (d)
380
550
  sources.push({
381
551
  id: rel,
382
552
  kind: "artifact",
383
553
  origin: `${changesRelOf(t.root)}/${t.change.id}/${rel}`,
384
- text: d.raw,
554
+ text: text(d.raw),
385
555
  classification: "internal",
386
556
  priority
387
557
  });
388
558
  };
389
- const context = await taskContext(t.root, t.change.id, t.task.id).catch(() => void 0);
559
+ const context = await taskContext(t.root, t.change.id, t.task.id, {
560
+ at: { worktree: p.worktreeRel, branch: taskBranch(t.change.id, t.task.id) }
561
+ }).catch(() => void 0);
390
562
  if (context)
391
563
  sources.push({
392
564
  id: "task-context",
@@ -397,7 +569,7 @@ ${s.body.trim()}`,
397
569
  priority: 35
398
570
  });
399
571
  for (const s of t.task.stories)
400
- artifact(`stories/${s}.md`, 30);
572
+ artifact(`stories/${s}.md`, 30, (raw) => withBuildLine(raw, t.repo.id, t.repo.build));
401
573
  for (const a of ["design.md", "interfaces.md", "mappings.md", "data.md"])
402
574
  artifact(a, 20);
403
575
  const needs = await readIf(join3(t.root, ...changesRelOf(t.root).split("/"), t.change.id, "needs.md"));
@@ -501,6 +673,7 @@ function gitScanAt(root, git) {
501
673
  return {
502
674
  records: s.records,
503
675
  files,
676
+ basis: s.basis?.[repo] ?? { from: "readers" },
504
677
  problems: s.problems.filter((p) => !p.repo || p.repo === repo).map((p) => `${p.repo ? `${p.repo}: ` : ""}${p.source}: ${p.message}`)
505
678
  };
506
679
  } finally {
@@ -654,7 +827,8 @@ async function conformChange(root, change, o = {}) {
654
827
  tasks,
655
828
  before: before.records,
656
829
  after: after.records,
657
- files: after.files
830
+ files: after.files,
831
+ basis: after.basis
658
832
  });
659
833
  const count = (s) => r.items.filter((i) => i.status === s).length;
660
834
  const result = {
@@ -814,7 +988,7 @@ async function aiStep(c, buildLog) {
814
988
  if (c.runtime instanceof HandoffRuntime) {
815
989
  await writeFile2(join5(runsDirOf(c.root), request.change, prepared.runId, "prompt.md"), handoffPrompt(c, prepared), "utf8");
816
990
  }
817
- const run = await c.runtime.run(prepared.runId);
991
+ const run = await c.runtime.run(prepared.runId, stopSignal);
818
992
  await summarise(c, run);
819
993
  return run;
820
994
  }
@@ -827,7 +1001,7 @@ function handoffPrompt(c, run) {
827
1001
  "",
828
1002
  run.request.pack.prompt.trimEnd(),
829
1003
  "",
830
- `When you are done, run: atticus handoff done ${run.runId}`,
1004
+ c.record.level === "pr" ? `When you are done, stop and ask the person to run: atticus handoff done ${run.runId} --approve (it pushes the branch and opens a PR, so the person runs it, never you)` : `When you are done, run: atticus handoff done ${run.runId}`,
831
1005
  ""
832
1006
  ].join("\n");
833
1007
  }
@@ -837,6 +1011,8 @@ async function build(c, runId, fixRun) {
837
1011
  return void 0;
838
1012
  const n = c.record.attempts.length + 1;
839
1013
  const res = await c.commands(command, c.worktree);
1014
+ if (res.stopped)
1015
+ c.stopped = true;
840
1016
  const logRel = `${runsRelOf(c.root)}/${c.t.change.id}/${runId}/build-${n}.log`;
841
1017
  await mkdir3(join5(runsDirOf(c.root), c.t.change.id, runId), { recursive: true });
842
1018
  await writeFile2(join5(c.root, logRel), `$ ${command}
@@ -856,14 +1032,24 @@ ${res.stderr}` : ""}
856
1032
  c.record.attempts.push(a);
857
1033
  return a;
858
1034
  }
1035
+ async function changedFiles(c) {
1036
+ const r = await c.git(["-c", "core.quotePath=false", "status", "--porcelain", "-z"], c.worktree);
1037
+ const parts = r.stdout.split("\0").filter(Boolean);
1038
+ const out = [];
1039
+ for (let k = 0; k < parts.length; k++) {
1040
+ const e = parts[k];
1041
+ if (/^[RC]/.test(e))
1042
+ k++;
1043
+ if (e.slice(3))
1044
+ out.push(e.slice(3));
1045
+ }
1046
+ return out;
1047
+ }
859
1048
  async function applyAnswer(c, run) {
860
1049
  if (c.runtime.kind === "headless-claude-code") {
861
- const changed = await c.git(["status", "--porcelain"], c.worktree);
862
- for (const l of changed.stdout.split("\n").filter(Boolean)) {
863
- const p = l.slice(3).trim();
1050
+ for (const p of await changedFiles(c))
864
1051
  if (!c.record.changed.includes(p))
865
1052
  c.record.changed.push(p);
866
- }
867
1053
  await writeReport(c, run.output ?? "");
868
1054
  return [];
869
1055
  }
@@ -892,7 +1078,8 @@ async function buildAndFix(c, runId) {
892
1078
  return;
893
1079
  }
894
1080
  let fixes = 0;
895
- while (!a.passed && fixes < c.maxFix && c.runtime.kind !== "hand-off") {
1081
+ const halted = () => c.stopped || stopRequested();
1082
+ while (!a.passed && !halted() && fixes < c.maxFix && c.runtime.kind !== "hand-off") {
896
1083
  fixes++;
897
1084
  const log = await import("node:fs/promises").then((fs) => fs.readFile(join5(c.root, a.log), "utf8"));
898
1085
  const fix = await aiStep(c, { command: a.command, text: log, attempt: fixes });
@@ -900,6 +1087,8 @@ async function buildAndFix(c, runId) {
900
1087
  c.record.notes.push(`Fix round ${fixes} failed: ${fix.errors.join("; ") || fix.state}.`);
901
1088
  break;
902
1089
  }
1090
+ if (halted())
1091
+ break;
903
1092
  const problems = await applyAnswer(c, fix);
904
1093
  if (problems.length) {
905
1094
  c.record.notes.push(`Fix round ${fixes} was not applied: ${problems.join("; ")}.`);
@@ -907,6 +1096,11 @@ async function buildAndFix(c, runId) {
907
1096
  }
908
1097
  a = await build(c, runId, fix.runId);
909
1098
  }
1099
+ if (halted()) {
1100
+ c.record.state = "needs-person";
1101
+ c.record.notes.push(`Atticus was stopped while the build ran, so nothing more was done; a person takes over in ${c.record.worktree}. See ${a.log}.`);
1102
+ return;
1103
+ }
910
1104
  if (!a.passed) {
911
1105
  c.record.state = "needs-person";
912
1106
  c.record.notes.push(`The build still fails after ${fixes} fix round${fixes === 1 ? "" : "s"}; a person takes over in ${c.record.worktree}. See ${a.log}.`);
@@ -918,8 +1112,9 @@ async function commit(c, runId) {
918
1112
  await c.git(["add", "-A", "--", "."], c.worktree);
919
1113
  const staged = (await c.git(["diff", "--cached", "--name-only"], c.worktree)).stdout.trim();
920
1114
  if (!staged) {
921
- c.record.notes.push("Nothing to commit.");
922
- return;
1115
+ c.record.state = "needs-person";
1116
+ c.record.notes.push(`The AI's answer changed nothing in ${c.record.branch}, so there is nothing to commit: run the task again, or do it by hand in ${c.record.worktree}.`);
1117
+ return false;
923
1118
  }
924
1119
  await c.git([
925
1120
  "commit",
@@ -933,6 +1128,7 @@ Atticus-Run: ${runId}
933
1128
  Requested-By: ${c.record.by}`
934
1129
  ], c.worktree);
935
1130
  c.record.commit = (await c.git(["rev-parse", "HEAD"], c.worktree)).stdout.trim();
1131
+ return true;
936
1132
  }
937
1133
  async function openPr(c) {
938
1134
  if (c.record.state !== "built") {
@@ -948,20 +1144,25 @@ async function openPr(c) {
948
1144
  return;
949
1145
  }
950
1146
  const base = changeBranch(c.t.change.id);
951
- const info = await c.gitHost.getRepo(c.t.repo.id);
952
- for (const b of [c.record.branch, base])
953
- if (info.protectedBranches.includes(b))
954
- throw new TaskRunError("refused", `${b} is protected in ${c.t.repo.id}; Run with AI never pushes to or opens a PR into a protected branch.`);
955
- if (base === info.defaultBranch)
956
- throw new TaskRunError("refused", `${base} is ${c.t.repo.id}'s default branch; task PRs go into the change branch.`);
957
- await c.git([
958
- "push",
959
- "-q",
960
- "origin",
961
- `refs/heads/${base}:refs/heads/${base}`,
962
- `refs/heads/${c.record.branch}:refs/heads/${c.record.branch}`
963
- ], c.worktree);
1147
+ if (!c.record.commit)
1148
+ throw new TaskRunError("refused", `Task ${c.t.task.id} has no commit to raise: run the task again, or do it by hand in ${c.record.worktree}.`);
1149
+ const head = (await c.git(["rev-parse", "--verify", "-q", `refs/heads/${c.record.branch}`], c.worktree).catch(() => ({ stdout: "" }))).stdout.trim();
1150
+ if (!head)
1151
+ throw new TaskRunError("refused", `Task ${c.t.task.id}'s branch ${c.record.branch} isn't in ${c.record.worktree} any more: run the task again.`);
1152
+ if (head !== c.record.commit)
1153
+ throw new TaskRunError("refused", `Task ${c.t.task.id}'s branch ${c.record.branch} has commits that weren't built (it is at ${head.slice(0, 12)}; the build passed at ${c.record.commit.slice(0, 12)}): run the task again so its build checks them, or push ${c.record.branch} and open its PR into ${base} yourself.`);
964
1154
  try {
1155
+ const info = await c.gitHost.getRepo(c.t.repo.id);
1156
+ for (const b of [c.record.branch, base])
1157
+ if (info.protectedBranches.includes(b))
1158
+ throw new TaskRunError("refused", `${b} is protected in ${c.t.repo.id}; Run with AI never pushes to or opens a PR into a protected branch.`);
1159
+ if (base === info.defaultBranch)
1160
+ throw new TaskRunError("refused", `${base} is ${c.t.repo.id}'s default branch; task PRs go into the change branch.`);
1161
+ const onHost = (await c.git(["ls-remote", "--heads", "origin", `refs/heads/${base}`], c.worktree)).stdout.trim();
1162
+ const refs = [`refs/heads/${c.record.branch}:refs/heads/${c.record.branch}`];
1163
+ if (!onHost)
1164
+ refs.unshift(`refs/heads/${base}:refs/heads/${base}`);
1165
+ await c.git(["push", "-q", ...refs.length > 1 ? ["--atomic"] : [], "origin", ...refs], c.worktree);
965
1166
  const pr = await c.gitHost.createPullRequest({
966
1167
  repo: c.t.repo.id,
967
1168
  head: c.record.branch,
@@ -979,15 +1180,18 @@ async function openPr(c) {
979
1180
  c.record.pr = { number: pr.number, url: pr.url };
980
1181
  c.record.state = "pr-open";
981
1182
  } catch (e) {
982
- if (e instanceof AdapterError) {
983
- c.record.state = "needs-person";
984
- c.record.notes.push(`The PR couldn't be opened: ${e.message}`);
985
- return;
986
- }
987
- throw e;
1183
+ if (e instanceof TaskRunError)
1184
+ throw e;
1185
+ c.record.notes.push(`${PR_NOT_RAISED} ${(e instanceof Error ? e.message : String(e)).replace(/\.?$/, ".")} The build still passes: fix that and raise the task's PR again (Raise the task's PR on the Task board), or push ${c.record.branch} and open its PR into ${base} yourself.`);
988
1186
  }
989
1187
  }
1188
+ var PR_NOT_RAISED = "The PR wasn't raised:";
990
1189
  async function finish(c, run) {
1190
+ if (stopRequested()) {
1191
+ c.record.state = "needs-person";
1192
+ c.record.notes.push(c.runtime.kind === "headless-claude-code" ? `Atticus was stopped while Claude Code worked, so nothing more was done; the worktree ${c.record.worktree} may hold some of its edits.` : `Atticus was stopped before the answer was applied, so nothing was written; run the task again.`);
1193
+ return done(c);
1194
+ }
991
1195
  if (c.record.level === "plan") {
992
1196
  if (c.runtime.kind !== "hand-off")
993
1197
  await writeFileAtomic(join5(changeFolder(c.root, c.t.change.id), run.request.outputPath), `${(run.output ?? "").trim()}
@@ -1003,39 +1207,233 @@ async function finish(c, run) {
1003
1207
  }
1004
1208
  }
1005
1209
  await buildAndFix(c, run.runId);
1006
- if (c.record.state === "built" || c.record.state === "unverified")
1007
- await commit(c, run.runId);
1210
+ await afterBuild(c, run.runId, c.record.state === "built" || c.record.state === "unverified");
1211
+ }
1212
+ return done(c);
1213
+ }
1214
+ async function afterBuild(c, runId, commitIt, first) {
1215
+ try {
1216
+ await first?.();
1217
+ if (commitIt && !await commit(c, runId))
1218
+ return;
1008
1219
  await conformAfterBuild(c);
1009
1220
  if (c.record.level === "pr")
1010
1221
  await openPr(c);
1222
+ } catch (e) {
1223
+ c.record.state = "needs-person";
1224
+ c.record.notes.push(`${e instanceof Error ? e.message : String(e)} \u2014 the work is in ${c.record.worktree} (branch ${c.record.branch}): finish it there by hand, or fix that and run the task again.`);
1011
1225
  }
1012
- return done(c);
1013
1226
  }
1014
1227
  async function done(c) {
1015
1228
  delete c.record.waiting;
1016
1229
  c.record.finishedAt = stamp2(c.now());
1017
1230
  return saveTaskRun(c.root, c.record);
1018
1231
  }
1232
+ function levelOf(t, asked) {
1233
+ const rt = t.ctx.orgPack.runtime;
1234
+ const cap = rt.autonomy.capPerRepo[t.repo.id];
1235
+ const capped = cap ? AUTONOMY[cap] : void 0;
1236
+ if (asked === void 0) {
1237
+ const level = AUTONOMY[rt.autonomy.default];
1238
+ return capped && LEVEL_RANK[level] > LEVEL_RANK[capped] ? capped : level;
1239
+ }
1240
+ if (capped && LEVEL_RANK[asked] > LEVEL_RANK[capped])
1241
+ throw new TaskRunError("refused", `${t.repo.id} allows Run with AI up to ${cap} (runtime.yaml autonomy.capPerRepo); ask for a lower level.`);
1242
+ return asked;
1243
+ }
1244
+ async function ownTaskPr(host, r, held) {
1245
+ const pr = await host.getPullRequest(r.repo, held.number);
1246
+ if (pr.head === r.branch)
1247
+ return pr;
1248
+ const mine = await host.listPullRequests(r.repo, { head: r.branch });
1249
+ const own = mine.find((x) => x.url === held.url) ?? mine.at(-1);
1250
+ if (own)
1251
+ return own;
1252
+ throw new TaskRunError("refused", `PR #${held.number} on the Git host is from ${pr.head}, not ${r.branch}, and no PR from ${r.branch} was found`);
1253
+ }
1254
+ async function refuseIfHeld(root, t, host) {
1255
+ const before = await readTaskRun(root, t.change.id, t.task.id);
1256
+ if (before?.state === "pr-open") {
1257
+ let state;
1258
+ let why = "";
1259
+ try {
1260
+ const h = host();
1261
+ if (!h)
1262
+ why = "no Git host is connected (runtime.yaml adapters.gitHost)";
1263
+ else if (before.pr)
1264
+ state = (await ownTaskPr(h, before, before.pr)).state;
1265
+ } catch (e) {
1266
+ why = e instanceof Error ? e.message : String(e);
1267
+ }
1268
+ if (before.pr && (state === "merged" || state === "closed"))
1269
+ return [`Its earlier PR ${before.pr.url} is ${state}.`];
1270
+ throw new TaskRunError("refused", `Task ${t.task.id}'s PR is open (${before.pr?.url ?? "see its run"}): running the task again would start over beside it. Merge or close the PR first, then run the task again.${why ? ` (Atticus couldn't ask the Git host whether it still is: ${why}.)` : ""}`);
1271
+ }
1272
+ const open = ["prepared", "waiting", "produced", "failed"];
1273
+ if (before?.state === "waiting" && before.waiting && open.includes(await handoffRunState(root, t.change.id, before.waiting) ?? ""))
1274
+ throw new TaskRunError("refused", `Task ${t.task.id} already waits on your assistant (run ${before.waiting}, in ${before.worktree}): finish it with Done on its run page (Model runs) or atticus handoff done ${before.waiting}, or Cancel it there and run the task again.`);
1275
+ return [];
1276
+ }
1277
+ async function taskPrState(root, changeId, taskId, o = {}) {
1278
+ const r = await readTaskRun(root, changeId, taskId).catch(() => void 0);
1279
+ if (r?.state !== "pr-open" || !r.pr)
1280
+ return void 0;
1281
+ const pr = r.pr;
1282
+ const ask = async () => {
1283
+ const host = o.gitHost ?? gitHostOf(root, await loadTask(root, changeId, taskId));
1284
+ if (!host)
1285
+ return void 0;
1286
+ const s = (await ownTaskPr(host, r, pr)).state;
1287
+ return s === "merged" || s === "closed" ? s : "open";
1288
+ };
1289
+ let timer;
1290
+ const late = new Promise((res) => {
1291
+ timer = setTimeout(() => res(void 0), o.timeoutMs ?? 3e3);
1292
+ });
1293
+ try {
1294
+ return await Promise.race([ask(), late]);
1295
+ } catch {
1296
+ return void 0;
1297
+ } finally {
1298
+ clearTimeout(timer);
1299
+ }
1300
+ }
1301
+ async function settleTaskPr(root, changeId, taskId, o = {}) {
1302
+ const r = await readTaskRun(root, changeId, taskId).catch(() => void 0);
1303
+ if (r?.state !== "pr-open" || !r.pr)
1304
+ return {};
1305
+ const recorded = r.pr;
1306
+ const ask = async () => {
1307
+ const host = o.gitHost ?? gitHostOf(root, await loadTask(root, changeId, taskId));
1308
+ if (!host)
1309
+ return void 0;
1310
+ return ownTaskPr(host, r, recorded);
1311
+ };
1312
+ let timer;
1313
+ const late = new Promise((res) => {
1314
+ timer = setTimeout(() => res(void 0), o.timeoutMs ?? 3e3);
1315
+ });
1316
+ const pr = await Promise.race([ask(), late]).catch(() => void 0).finally(() => clearTimeout(timer));
1317
+ if (!pr)
1318
+ return {};
1319
+ const state = pr.state === "merged" || pr.state === "closed" ? pr.state : "open";
1320
+ const cur = await readTaskRun(root, changeId, taskId).catch(() => void 0);
1321
+ if (cur?.state !== "pr-open" || cur.pr?.url !== recorded.url)
1322
+ return { state };
1323
+ let changed = false;
1324
+ if (pr.number !== recorded.number || pr.url !== recorded.url) {
1325
+ cur.pr = { number: pr.number, url: pr.url };
1326
+ changed = true;
1327
+ }
1328
+ let ticked = false;
1329
+ if (state === "merged" && !cur.ticked) {
1330
+ ticked = await setTaskDone(root, changeId, taskId, true);
1331
+ cur.ticked = stamp2((o.now ?? (() => /* @__PURE__ */ new Date()))());
1332
+ if (ticked)
1333
+ cur.notes.push(`Ticked ${taskId} in tasks.md: PR #${pr.number} merged on the Git host. The tick rides the change's build hand-off.`);
1334
+ changed = true;
1335
+ }
1336
+ if (changed)
1337
+ await saveTaskRun(root, cur);
1338
+ return { state, ...ticked ? { ticked: true } : {} };
1339
+ }
1340
+ function gitHostConnected(root, t, given) {
1341
+ try {
1342
+ return !!(given ?? gitHostOf(root, t));
1343
+ } catch {
1344
+ return false;
1345
+ }
1346
+ }
1347
+ async function previewTaskRun(root, changeId, taskId, o = {}) {
1348
+ const t = await loadTask(root, changeId, taskId);
1349
+ const level = levelOf(t, o.level);
1350
+ await refuseIfHeld(root, t, () => o.gitHost ?? gitHostOf(root, t));
1351
+ return {
1352
+ change: t.change.id,
1353
+ task: t.task.id,
1354
+ repo: t.repo.id,
1355
+ level,
1356
+ branch: taskBranch(t.change.id, t.task.id),
1357
+ gitHost: level === "pr" && !o.skipGitHost ? gitHostConnected(root, t, o.gitHost) : false
1358
+ };
1359
+ }
1360
+ async function cancelTaskRunWait(root, runId, o) {
1361
+ const r = await findWaitingTaskRun(root, runId);
1362
+ if (!r) {
1363
+ await o.cancelRun?.();
1364
+ return void 0;
1365
+ }
1366
+ const lock = await holdTask(root, r.change, r.task);
1367
+ try {
1368
+ const cur = await findWaitingTaskRun(root, runId);
1369
+ await o.cancelRun?.();
1370
+ if (!cur)
1371
+ return void 0;
1372
+ delete cur.waiting;
1373
+ cur.state = "failed";
1374
+ cur.notes.push(`Run ${runId} was cancelled by ${o.by}, so nothing more was done; run the task again.`);
1375
+ cur.finishedAt = stamp2((o.now ?? (() => /* @__PURE__ */ new Date()))());
1376
+ return await saveTaskRun(root, cur);
1377
+ } finally {
1378
+ await lock.release();
1379
+ }
1380
+ }
1381
+ async function handoffRunState(root, change, runId) {
1382
+ const text = await import("node:fs/promises").then((fs) => fs.readFile(join5(runsDirOf(root), change, runId, "run.json"), "utf8").catch(() => void 0));
1383
+ if (!text)
1384
+ return void 0;
1385
+ try {
1386
+ return JSON.parse(text).state;
1387
+ } catch {
1388
+ return void 0;
1389
+ }
1390
+ }
1391
+ async function holdTask(root, change, task) {
1392
+ try {
1393
+ return await acquireLock(root, `task-run-${change}-${task}`, `run of task ${task} of ${change}`, void 0, { maxAgeMs: 12 * 60 * 6e4 });
1394
+ } catch (e) {
1395
+ if (e instanceof LockHeldError)
1396
+ throw new TaskRunError("refused", e.message);
1397
+ throw e;
1398
+ }
1399
+ }
1019
1400
  async function runTask(root, changeId, taskId, o) {
1401
+ const lock = await holdTask(root, changeId, taskId);
1402
+ const release = holdSignals();
1403
+ try {
1404
+ return await runTaskHeld(root, changeId, taskId, o);
1405
+ } finally {
1406
+ await lock.release();
1407
+ release();
1408
+ }
1409
+ }
1410
+ async function runTaskHeld(root, changeId, taskId, o) {
1020
1411
  const now = o.now ?? (() => /* @__PURE__ */ new Date());
1021
1412
  const git = o.git ?? createGit();
1022
1413
  let t = await loadTask(root, changeId, taskId);
1023
1414
  const rt = t.ctx.orgPack.runtime;
1024
- const level = o.level ?? AUTONOMY[rt.autonomy.default];
1025
- const cap = rt.autonomy.capPerRepo[t.repo.id];
1026
- if (cap && LEVEL_RANK[level] > LEVEL_RANK[AUTONOMY[cap]])
1027
- throw new TaskRunError("refused", `${t.repo.id} allows Run with AI up to ${cap} (runtime.yaml autonomy.capPerRepo); ask for a lower level.`);
1415
+ const level = levelOf(t, o.level);
1416
+ const earlier = await refuseIfHeld(root, t, () => o.gitHost ?? gitHostOf(root, t));
1028
1417
  if (level === "pr") {
1029
1418
  try {
1030
1419
  requireApproval("git-host", o.approval);
1031
1420
  } catch {
1032
- throw new TaskRunError("refused", "The pr level pushes the task branch and opens a PR, which needs your approval: run it again with --approve.");
1421
+ throw new TaskRunError("refused", "The pr level pushes the task branch and opens a PR, which needs the person's yes: ask them to run it with --approve (an assistant never approves a push).");
1033
1422
  }
1034
1423
  }
1035
1424
  const engine = buildEngineFor(t.ctx.orgPack, t.repo.id);
1036
1425
  const changeDir = await changeWorktree(root, t.change.id, t.repo.id);
1037
1426
  const handed = engine === "speckit" ? `specs/${t.task.id}/plan.md` : `.atticus/tasks/${t.task.id}.md`;
1038
- const notes = [];
1427
+ const notes = [...earlier];
1428
+ try {
1429
+ const caught = await catchUpChangeBranch(root, t.change.id, t.task.id, t.repo.id, changeDir, git);
1430
+ if (caught)
1431
+ notes.push(caught);
1432
+ } catch (e) {
1433
+ if (e instanceof Error && e.name === "SpecKitError")
1434
+ throw new TaskRunError("refused", e.message);
1435
+ throw e;
1436
+ }
1039
1437
  if (!existsSync2(join5(changeDir, handed))) {
1040
1438
  const h = await handDown(root, t.change.id, t.task.id, { git });
1041
1439
  notes.push(`Handed the task down first (${h.feature} in ${h.repo}${h.commit ? `, commit ${h.commit.slice(0, 12)}` : ""}).`);
@@ -1097,16 +1495,36 @@ async function runTask(root, changeId, taskId, o) {
1097
1495
  record.waiting = run.runId;
1098
1496
  return saveTaskRun(root, record);
1099
1497
  }
1100
- if (run.state !== "validated") {
1498
+ if (run.state !== "validated" && !stopRequested()) {
1101
1499
  record.notes.push(`The AI run ended ${run.state}: ${run.errors.join("; ") || "no reason given"}.`);
1102
1500
  return done(c);
1103
1501
  }
1104
1502
  return finish(c, run);
1105
1503
  }
1106
1504
  async function completeTaskHandoff(root, runId, o = {}) {
1107
- const record = await findWaitingTaskRun(root, runId);
1108
- if (!record)
1505
+ const waiting = await findWaitingTaskRun(root, runId);
1506
+ if (!waiting)
1109
1507
  throw new TaskRunError("not-found", `No task run is waiting on ${runId}.`);
1508
+ if (waiting.level === "pr" && !o.approval)
1509
+ throw new TaskRunError("refused", `Task ${waiting.task} runs at the pr level, which pushes ${waiting.branch} and opens a PR: ask the person to run atticus handoff done ${runId} --approve (an assistant never approves a push).`);
1510
+ const lock = await holdTask(root, waiting.change, waiting.task);
1511
+ const release = holdSignals();
1512
+ try {
1513
+ const state = await handoffRunState(root, waiting.change, runId);
1514
+ if (state === void 0)
1515
+ throw new TaskRunError("refused", `Run ${runId} isn't on this machine (its files are kept where it was started): run the task again here (atticus task run ${waiting.change} ${waiting.task}).`);
1516
+ if (state === "cancelled")
1517
+ throw new TaskRunError("refused", `Run ${runId} was cancelled; run the task again (atticus task run ${waiting.change} ${waiting.task}).`);
1518
+ const record = await findWaitingTaskRun(root, runId);
1519
+ if (!record)
1520
+ throw new TaskRunError("not-found", `No task run is waiting on ${runId}.`);
1521
+ return await completeHeld(root, runId, record, o);
1522
+ } finally {
1523
+ await lock.release();
1524
+ release();
1525
+ }
1526
+ }
1527
+ async function completeHeld(root, runId, record, o) {
1110
1528
  const now = o.now ?? (() => /* @__PURE__ */ new Date());
1111
1529
  const git = o.git ?? createGit();
1112
1530
  const t = await loadTask(root, record.change, record.task);
@@ -1138,7 +1556,11 @@ async function completeTaskHandoff(root, runId, o = {}) {
1138
1556
  return [`${file.slice(root.length + 1)} is empty`];
1139
1557
  if (record.level === "plan")
1140
1558
  return [];
1559
+ if (stopRequested())
1560
+ return ["Atticus was stopped"];
1141
1561
  attempt = await build(c, runId);
1562
+ if (c.stopped)
1563
+ return ["Atticus was stopped while the build ran"];
1142
1564
  if (!attempt)
1143
1565
  return [];
1144
1566
  return attempt.passed ? [] : [`${attempt.command} failed; see ${attempt.log}`];
@@ -1154,19 +1576,32 @@ async function completeTaskHandoff(root, runId, o = {}) {
1154
1576
  record.state = attempt ? "built" : "unverified";
1155
1577
  if (!attempt)
1156
1578
  record.notes.push(`${t.repo.id} has no build command in repos.manifest.yaml, so the change wasn't built or tested.`);
1157
- const changed = await git(["status", "--porcelain"], c.worktree);
1158
- for (const l of changed.stdout.split("\n").filter(Boolean)) {
1159
- const p = l.slice(3).trim();
1160
- if (!record.changed.includes(p))
1161
- record.changed.push(p);
1162
- }
1163
- await commit(c, runId);
1164
- await conformAfterBuild(c);
1165
- if (record.level === "pr")
1166
- await openPr(c);
1579
+ await afterBuild(c, runId, true, async () => {
1580
+ for (const p of await changedFiles(c))
1581
+ if (!record.changed.includes(p))
1582
+ record.changed.push(p);
1583
+ });
1167
1584
  }
1168
1585
  return done(c);
1169
1586
  }
1587
+ if (c.stopped || stopRequested()) {
1588
+ if (c.stopped && record.attempts.at(-1)?.passed === false)
1589
+ record.attempts.pop();
1590
+ record.state = "waiting";
1591
+ record.waiting = runId;
1592
+ await handoff.retry(runId);
1593
+ await handoff.run(runId);
1594
+ record.notes.push(`Atticus was stopped while it checked the work, so nothing more was done; run atticus handoff done ${runId} again.`);
1595
+ return saveTaskRun(root, record);
1596
+ }
1597
+ if (!attempt) {
1598
+ record.state = "waiting";
1599
+ record.waiting = runId;
1600
+ await handoff.retry(runId);
1601
+ await handoff.run(runId);
1602
+ record.notes.push(`${run.errors.join("; ") || "The answer isn't there yet"}: write it, then run atticus handoff done ${runId} again.`);
1603
+ return saveTaskRun(root, record);
1604
+ }
1170
1605
  const builds = record.attempts.length;
1171
1606
  if (attempt && !attempt.passed && builds <= c.maxFix) {
1172
1607
  await handoff.retry(runId);
@@ -1178,15 +1613,207 @@ async function completeTaskHandoff(root, runId, o = {}) {
1178
1613
  record.notes.push(attempt && !attempt.passed ? `The build still fails after ${builds} attempts; a person takes over in ${record.worktree}.` : `The hand-off failed: ${run.errors.join("; ")}.`);
1179
1614
  return done(c);
1180
1615
  }
1616
+ async function raiseTaskPr(root, changeId, taskId, o) {
1617
+ try {
1618
+ requireApproval("git-host", o.approval);
1619
+ } catch {
1620
+ throw new TaskRunError("refused", "A task's PR pushes its branch and opens a PR, which needs the person's yes (an assistant never approves a push).");
1621
+ }
1622
+ const lock = await holdTask(root, changeId, taskId);
1623
+ try {
1624
+ const record = await readTaskRun(root, changeId, taskId);
1625
+ if (!record || record.level === "plan" || ["planned", "failed"].includes(record.state))
1626
+ throw new TaskRunError("refused", `Task ${taskId} hasn't been drafted yet: run it with AI first; its PR comes after the draft.`);
1627
+ if (record.state === "pr-open")
1628
+ throw new TaskRunError("refused", `Task ${taskId}'s PR is already open: ${record.pr?.url ?? "see its run"}.`);
1629
+ if (record.state === "waiting")
1630
+ throw new TaskRunError("refused", `Task ${taskId} still waits on your assistant (run ${record.waiting ?? "on its page"}): finish it with Done first; its PR comes after the build.`);
1631
+ const change = changeBranch(changeId);
1632
+ if (record.state === "unverified")
1633
+ throw new TaskRunError("refused", `Atticus opens a task's PR only after a passing build, and ${record.repo} has no build command in repos.manifest.yaml: add one and run task ${taskId} again, or push ${record.branch} and open its PR into ${change} yourself.`);
1634
+ if (record.state !== "built" || !record.commit)
1635
+ throw new TaskRunError("refused", `Task ${taskId} has no passing build to raise (it is ${record.state}): see its run's notes, then run it again.`);
1636
+ const t = await loadTask(root, changeId, taskId);
1637
+ const gitHost = o.gitHost ?? gitHostOf(root, t);
1638
+ if (!gitHost)
1639
+ throw new TaskRunError("refused", `No Git host is connected (runtime.yaml adapters.gitHost): push ${record.branch} and open its PR into ${change} yourself.`);
1640
+ const now = o.now ?? (() => /* @__PURE__ */ new Date());
1641
+ const c = {
1642
+ root,
1643
+ t,
1644
+ record,
1645
+ worktree: join5(root, record.worktree),
1646
+ runtime: void 0,
1647
+ commands: shellCommandRunner(),
1648
+ git: o.git ?? createGit(),
1649
+ gitHost,
1650
+ approval: o.approval,
1651
+ now,
1652
+ maxFix: t.ctx.orgPack.runtime.autonomy.maxFixRounds
1653
+ };
1654
+ await openPr(c);
1655
+ if (record.state === "pr-open")
1656
+ record.notes.push(`PR raised by ${o.approval.by} after the draft (${o.approval.ref}).`);
1657
+ return await done(c);
1658
+ } finally {
1659
+ await lock.release();
1660
+ }
1661
+ }
1181
1662
  async function isTaskRun(root, runId) {
1182
1663
  return await findWaitingTaskRun(root, runId) !== void 0;
1183
1664
  }
1184
1665
 
1666
+ // packages/taskrun/dist/ready.js
1667
+ var PAST = {
1668
+ waiting: "it is with your assistant: Done on its run carries on",
1669
+ built: "it is drafted: its PR is the next step",
1670
+ unverified: "it is drafted but not built: its repo has no build command",
1671
+ "pr-open": "its PR is open on the Git host",
1672
+ "needs-person": "it needs a person: carry on in its worktree, or Run with AI on it"
1673
+ };
1674
+ function sameRepoBefore(tasks, t) {
1675
+ const mine = tasks.slice(0, tasks.indexOf(t)).filter((x) => x.repo === t.repo);
1676
+ let cut = mine.length;
1677
+ if (t.parallel)
1678
+ while (cut > 0 && mine[cut - 1].parallel)
1679
+ cut--;
1680
+ return mine.slice(0, cut).filter((x) => !x.done).map((x) => x.id);
1681
+ }
1682
+ function planReadyTasks(o) {
1683
+ const deps = new Map(o.stories.map((s) => [s.id, s.dependsOn]));
1684
+ const rank = (repo) => {
1685
+ const i = o.repoOrder?.indexOf(repo) ?? -1;
1686
+ return i < 0 ? Number.MAX_SAFE_INTEGER : i;
1687
+ };
1688
+ const firstOfRepo = /* @__PURE__ */ new Map();
1689
+ o.tasks.forEach((t, i) => {
1690
+ if (!firstOfRepo.has(t.repo))
1691
+ firstOfRepo.set(t.repo, i);
1692
+ });
1693
+ const order = o.tasks.map((t, i) => ({ t, i })).sort((a, b) => rank(a.t.repo) - rank(b.t.repo) || firstOfRepo.get(a.t.repo) - firstOfRepo.get(b.t.repo) || a.i - b.i).map((x) => x.t);
1694
+ const out = [];
1695
+ for (const t of order) {
1696
+ if (t.done)
1697
+ continue;
1698
+ const before = new Set(t.stories.flatMap((s) => deps.get(s) ?? []));
1699
+ const byStory = o.tasks.filter((x) => x.id !== t.id && !x.done && x.stories.some((s) => before.has(s))).map((x) => x.id);
1700
+ const sameRepo = sameRepoBefore(o.tasks, t).filter((id) => !byStory.includes(id));
1701
+ const waitsFor = o.tasks.map((x) => x.id).filter((id) => byStory.includes(id) || sameRepo.includes(id));
1702
+ const past = t.state && !(t.state === "pr-open" && t.prSettled) ? PAST[t.state] : void 0;
1703
+ const named = [
1704
+ ...byStory,
1705
+ ...sameRepo.length ? [`${sameRepo.join(", ")} (same repo)`] : []
1706
+ ].join(", ");
1707
+ const why = waitsFor.length ? `it waits for ${waitsFor.length === 1 ? "task" : "tasks"} ${named} to be done first` : past;
1708
+ out.push({
1709
+ id: t.id,
1710
+ repo: t.repo,
1711
+ ready: !why,
1712
+ waitsFor,
1713
+ ...sameRepo.length ? { sameRepo } : {},
1714
+ ...why ? { why } : {}
1715
+ });
1716
+ }
1717
+ return { tasks: out, ready: out.filter((t) => t.ready).map((t) => t.id) };
1718
+ }
1719
+ async function readyTasksOf(root, change, o = {}) {
1720
+ const files = await readChangeFiles(changeFolder(root, change));
1721
+ const tasks = [];
1722
+ for (const t of readChangeTasks(files)) {
1723
+ const r = await readTaskRun(root, change, t.id).catch(() => void 0);
1724
+ const pr = o.prStates?.get(t.id);
1725
+ tasks.push({
1726
+ id: t.id,
1727
+ repo: t.repo,
1728
+ done: t.done,
1729
+ stories: t.stories,
1730
+ ...t.parallel ? { parallel: true } : {},
1731
+ ...r ? { state: r.state } : {},
1732
+ ...pr === "merged" || pr === "closed" ? { prSettled: pr } : {}
1733
+ });
1734
+ }
1735
+ return planReadyTasks({
1736
+ tasks,
1737
+ stories: readStoryIndex(files),
1738
+ ...o.repoOrder ? { repoOrder: o.repoOrder } : {}
1739
+ });
1740
+ }
1741
+ function needsPerson(r) {
1742
+ if (r.state === "failed")
1743
+ return r.notes.at(-1) ?? `the run for task ${r.task} failed`;
1744
+ if (r.state === "needs-person")
1745
+ return r.notes.at(-1) ?? `task ${r.task} needs a person`;
1746
+ if (r.state === "waiting")
1747
+ return `task ${r.task} is with your assistant: Done on its run first`;
1748
+ if (r.state === "unverified")
1749
+ return `task ${r.task} is drafted but ${r.repo} has no build command, so nothing was built`;
1750
+ if (r.level === "pr" && r.state === "built")
1751
+ return r.notes.at(-1) ?? `task ${r.task}'s PR wasn't raised`;
1752
+ return void 0;
1753
+ }
1754
+ async function runReadyTasks(root, change, o) {
1755
+ const plan = await readyTasksOf(root, change, {
1756
+ ...o.repoOrder ? { repoOrder: o.repoOrder } : {},
1757
+ ...o.prStates ? { prStates: o.prStates } : {}
1758
+ });
1759
+ const planned = o.only ? plan.ready.filter((id) => o.only.includes(id)) : plan.ready;
1760
+ const repoOf = new Map(plan.tasks.map((t) => [t.id, t.repo]));
1761
+ if (o.dryRun) {
1762
+ const previews = [];
1763
+ for (const task of planned)
1764
+ try {
1765
+ previews.push(await previewTaskRun(root, change, task, {
1766
+ ...o.level ? { level: o.level } : {},
1767
+ ...o.gitHost ? { gitHost: o.gitHost } : {}
1768
+ }));
1769
+ } catch (e) {
1770
+ previews.push({ task, refused: e.message });
1771
+ }
1772
+ return { planned, ran: [], previews };
1773
+ }
1774
+ const { only: _only, before, levelFor, progress, cancelled, repoOrder: _r, prStates: _p, dryRun: _d, ...run } = o;
1775
+ const ran = [];
1776
+ for (const [i, task] of planned.entries()) {
1777
+ const repo = repoOf.get(task) ?? "";
1778
+ if (cancelled?.())
1779
+ return { planned, ran, stopped: { task, why: "the run was cancelled" } };
1780
+ progress?.(i, planned.length, `Task ${task} on ${repo}`);
1781
+ const refusedBefore = await before?.(task);
1782
+ if (refusedBefore) {
1783
+ ran.push({ task, repo, refused: refusedBefore });
1784
+ return { planned, ran, stopped: { task, why: refusedBefore } };
1785
+ }
1786
+ let record;
1787
+ try {
1788
+ const level = run.level ?? await levelFor?.(task);
1789
+ record = await runTask(root, change, task, { ...run, ...level ? { level } : {} });
1790
+ } catch (e) {
1791
+ const why2 = e.message;
1792
+ ran.push({ task, repo, refused: why2 });
1793
+ return { planned, ran, stopped: { task, why: why2 } };
1794
+ }
1795
+ ran.push({ task, repo, record });
1796
+ const why = needsPerson(record);
1797
+ if (why)
1798
+ return { planned, ran, stopped: { task, why } };
1799
+ }
1800
+ progress?.(planned.length, planned.length, "Done");
1801
+ return { planned, ran };
1802
+ }
1803
+
1185
1804
  export {
1186
1805
  FILE_FORMAT,
1187
1806
  refusedPath,
1188
1807
  parseAnswer,
1189
1808
  applyChanges,
1809
+ KEEP_OUTPUT,
1810
+ tail,
1811
+ stopRequested,
1812
+ stopSignal,
1813
+ stopAllBuilds,
1814
+ SIGNAL_GRACE_MS,
1815
+ holdSignals,
1816
+ STOP_GRACE_MS,
1190
1817
  shellCommandRunner,
1191
1818
  TaskRunState,
1192
1819
  RunLevel,
@@ -1196,6 +1823,8 @@ export {
1196
1823
  saveTaskRun,
1197
1824
  readTaskRun,
1198
1825
  saveRunSummary,
1826
+ taskRunOfRun,
1827
+ findTaskRunOfRun,
1199
1828
  findWaitingTaskRun,
1200
1829
  TASK_RUNNER,
1201
1830
  taskRunnerAgent,
@@ -1211,7 +1840,16 @@ export {
1211
1840
  conformanceOf,
1212
1841
  conformAfterBuild,
1213
1842
  TaskRunError,
1843
+ taskPrState,
1844
+ settleTaskPr,
1845
+ previewTaskRun,
1846
+ cancelTaskRunWait,
1214
1847
  runTask,
1215
1848
  completeTaskHandoff,
1216
- isTaskRun
1849
+ raiseTaskPr,
1850
+ isTaskRun,
1851
+ planReadyTasks,
1852
+ readyTasksOf,
1853
+ needsPerson,
1854
+ runReadyTasks
1217
1855
  };