@maycombhq/atticus 2.0.0-beta.22 → 2.0.0-beta.24

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 (289) hide show
  1. package/dist/bin.js +12 -7
  2. package/dist/{chunk-J2JAKCIW.js → chunk-25CUJJTP.js} +511 -291
  3. package/dist/chunk-26AB2WNW.js +62 -0
  4. package/dist/{chunk-VBTP56CE.js → chunk-2ITYURTR.js} +9 -8
  5. package/dist/{chunk-6ZJ5A7AF.js → chunk-2JHE75RW.js} +13 -11
  6. package/dist/{chunk-QFWA2DPH.js → chunk-37UTWGU4.js} +8 -6
  7. package/dist/{chunk-VW62D6QE.js → chunk-3BEGKSDW.js} +14 -12
  8. package/dist/{chunk-3RM4UK6W.js → chunk-3FGQFDS4.js} +20 -18
  9. package/dist/{chunk-23XVSEV5.js → chunk-3NS4RS3C.js} +20 -18
  10. package/dist/{chunk-FSMSFDLD.js → chunk-3TGX4SJ3.js} +10 -7
  11. package/dist/{chunk-7JITZFJC.js → chunk-3UMKLB6P.js} +7 -5
  12. package/dist/chunk-3VS7RNEB.js +96 -0
  13. package/dist/{chunk-AJYXNTNZ.js → chunk-3XCCT2GR.js} +167 -42
  14. package/dist/{chunk-XERYFDB5.js → chunk-3XZRYQWU.js} +38 -34
  15. package/dist/{chunk-FUJM6RTF.js → chunk-432FGEVB.js} +9 -7
  16. package/dist/{chunk-SFUP7TTO.js → chunk-44QUCNPH.js} +7 -5
  17. package/dist/{chunk-O5PXQR67.js → chunk-4CS3PMIM.js} +15 -13
  18. package/dist/{chunk-RGERPOIV.js → chunk-4DCIUKIE.js} +22 -12
  19. package/dist/{chunk-RLDGWLQ7.js → chunk-4DX4DIND.js} +9 -7
  20. package/dist/chunk-4MNMOUU7.js +108 -0
  21. package/dist/{chunk-SLXZOMA6.js → chunk-4RKIOUPA.js} +9 -7
  22. package/dist/{chunk-AJQ72EBM.js → chunk-532HDXMM.js} +9 -7
  23. package/dist/{chunk-CADWLE2T.js → chunk-5EIKOU7L.js} +6 -4
  24. package/dist/{chunk-CQDGOPGH.js → chunk-5FPAKAGE.js} +7 -5
  25. package/dist/{chunk-IVBOQAGB.js → chunk-5FUFVNXB.js} +27 -3
  26. package/dist/{chunk-UUU4CLJG.js → chunk-5MKV4TV6.js} +5 -1
  27. package/dist/{chunk-ZQXZ2SES.js → chunk-5ORLKITZ.js} +23 -21
  28. package/dist/{chunk-OHVTTOPS.js → chunk-5PSKLTBR.js} +3 -3
  29. package/dist/{chunk-RUGXBPWI.js → chunk-5QF5W5P2.js} +10 -10
  30. package/dist/{chunk-BPK5P77O.js → chunk-5Z7L2TSR.js} +3 -3
  31. package/dist/{chunk-L27SV425.js → chunk-66DWUSNY.js} +22 -20
  32. package/dist/{chunk-JAVI7JSP.js → chunk-6FIYEB7M.js} +25 -22
  33. package/dist/{chunk-VY72R2XZ.js → chunk-6OZAQPU5.js} +532 -358
  34. package/dist/{chunk-AFWUDXEM.js → chunk-6TNQO76I.js} +34 -17
  35. package/dist/{chunk-WF7B67YE.js → chunk-6UTD5RQH.js} +18 -16
  36. package/dist/{chunk-HNM2YQT2.js → chunk-775FMPUB.js} +7 -7
  37. package/dist/{chunk-7ASNL4Q4.js → chunk-77AZRGWE.js} +19 -16
  38. package/dist/{chunk-WKUJ3KPV.js → chunk-7HWCEDPX.js} +7 -5
  39. package/dist/{chunk-G6X77UJZ.js → chunk-7U46TCRZ.js} +25 -22
  40. package/dist/{chunk-O45HFTFS.js → chunk-A3NUZJFI.js} +4 -2
  41. package/dist/{chunk-UPOY4YSQ.js → chunk-A4VDFIMR.js} +14 -12
  42. package/dist/{chunk-EMRIQUND.js → chunk-A53IYUCR.js} +87 -29
  43. package/dist/{chunk-S4PMJU6H.js → chunk-A6ZG3UOS.js} +108 -50
  44. package/dist/{chunk-PMUAJGLI.js → chunk-AAY6VPPO.js} +18 -16
  45. package/dist/{chunk-MG4ZL5RW.js → chunk-ABDE5IRC.js} +18 -16
  46. package/dist/{chunk-T6DQR5TV.js → chunk-AM7PYKVP.js} +15 -13
  47. package/dist/{chunk-SFSPGFCV.js → chunk-ANUMIPF6.js} +22 -20
  48. package/dist/{chunk-VTZMAJ3W.js → chunk-ASFRT33J.js} +11 -9
  49. package/dist/{chunk-7FTTA3HD.js → chunk-AWDCVZYO.js} +9 -7
  50. package/dist/{chunk-KFAVQZSX.js → chunk-B63NWU3P.js} +14 -12
  51. package/dist/{chunk-YYY3AZFE.js → chunk-BBZ6UKN3.js} +16 -5
  52. package/dist/{chunk-Q4K5WB2W.js → chunk-BFQ5IKQA.js} +12 -10
  53. package/dist/{chunk-ZFL7NY4F.js → chunk-BLVFHN3C.js} +73 -42
  54. package/dist/{chunk-MO6P2JZH.js → chunk-BQXAHIZ6.js} +10 -8
  55. package/dist/{chunk-Y2EQNWKV.js → chunk-BTS56NV7.js} +91 -41
  56. package/dist/{chunk-UGUP3ZM6.js → chunk-BWYW533C.js} +18 -16
  57. package/dist/{chunk-O7FDLW7L.js → chunk-BYKWWSXL.js} +14 -12
  58. package/dist/chunk-C7BB6IQT.js +147 -0
  59. package/dist/{chunk-JLUCKAEL.js → chunk-CCQWQFOT.js} +19 -17
  60. package/dist/{chunk-SYV5LHML.js → chunk-CCQZN6W3.js} +35 -33
  61. package/dist/{chunk-UCROWG2D.js → chunk-CFSBBLDD.js} +28 -25
  62. package/dist/{chunk-EIPTLPFC.js → chunk-CFSHLQPK.js} +26 -24
  63. package/dist/{chunk-2IIMFOPM.js → chunk-CI4D6VSU.js} +20 -18
  64. package/dist/{chunk-66PPNOON.js → chunk-CKRPMRFQ.js} +28 -25
  65. package/dist/{chunk-IUPG3UKI.js → chunk-CNF2EZ6S.js} +191 -125
  66. package/dist/chunk-CTJHEG6A.js +97 -0
  67. package/dist/{chunk-DOBQKHIF.js → chunk-CU7ZK7KP.js} +30 -29
  68. package/dist/{chunk-745DAZ4L.js → chunk-CZ75S2EZ.js} +886 -313
  69. package/dist/{chunk-LGFL54FP.js → chunk-D5CJEKZI.js} +11 -4
  70. package/dist/{chunk-PBPBMP2B.js → chunk-D5ZC7IMC.js} +5 -3
  71. package/dist/{chunk-LZ7NUC62.js → chunk-D63NU53X.js} +20 -18
  72. package/dist/{chunk-BO4KX37X.js → chunk-DCQSPSXU.js} +28 -23
  73. package/dist/{chunk-WXFLMQSR.js → chunk-DCRZ3OQ7.js} +8 -6
  74. package/dist/chunk-DD2AXECF.js +41 -0
  75. package/dist/{chunk-4EURQWQD.js → chunk-DF6DPCW2.js} +16 -14
  76. package/dist/{chunk-53T4O55J.js → chunk-DH3EQMIA.js} +5 -3
  77. package/dist/{chunk-ZX57KSEQ.js → chunk-DIXA74N7.js} +5 -3
  78. package/dist/{chunk-6ZGLAACW.js → chunk-DIYNRYXW.js} +2 -2
  79. package/dist/chunk-DYDNW4O6.js +52 -0
  80. package/dist/{chunk-P2V7QW4D.js → chunk-E7YDJH6B.js} +16 -14
  81. package/dist/chunk-EEKQI3U4.js +45 -0
  82. package/dist/{chunk-GZY6RUZ6.js → chunk-EHF2MBGR.js} +9 -4
  83. package/dist/chunk-EHXDB3SA.js +25 -0
  84. package/dist/{chunk-PJSJPMJI.js → chunk-ENZ3PI7L.js} +3 -3
  85. package/dist/{chunk-E3ISYXO3.js → chunk-EPQQ2XVM.js} +16 -14
  86. package/dist/{chunk-7IGKHZ4Z.js → chunk-ESJALLOK.js} +222 -213
  87. package/dist/chunk-ETQSQ2EC.js +33 -0
  88. package/dist/{chunk-MFR5OPBD.js → chunk-EUMXLSW5.js} +14 -6
  89. package/dist/{chunk-BTY3HZBO.js → chunk-F63F4NKT.js} +18 -16
  90. package/dist/{chunk-ZFFYNRIO.js → chunk-FDL2JOLB.js} +26 -22
  91. package/dist/{chunk-5SJZW52K.js → chunk-FFDVAV56.js} +24 -22
  92. package/dist/chunk-FFYOZ7PF.js +27 -0
  93. package/dist/{chunk-RXPJMEOW.js → chunk-FGW5TLGM.js} +24 -19
  94. package/dist/{chunk-UPS2DGFC.js → chunk-FL53R4SW.js} +1 -1
  95. package/dist/chunk-FYWLB7PO.js +38 -0
  96. package/dist/{chunk-FFLNS6VP.js → chunk-G3W7GNEP.js} +24 -18
  97. package/dist/chunk-G3ZFEHCX.js +925 -0
  98. package/dist/{chunk-YHCMZC2J.js → chunk-G67GOK4S.js} +10 -8
  99. package/dist/{chunk-2F4CYZKJ.js → chunk-GCMDDVIE.js} +14 -9
  100. package/dist/{chunk-QKUJMING.js → chunk-GFYVVTKH.js} +10 -8
  101. package/dist/chunk-GJVCBTSO.js +20722 -0
  102. package/dist/{chunk-VCTWPLAO.js → chunk-GKZDHXC2.js} +8 -8
  103. package/dist/{chunk-5BD2KYLE.js → chunk-GQFUEUC7.js} +18 -16
  104. package/dist/chunk-GQPP4P2E.js +33 -0
  105. package/dist/{chunk-42SIDKEU.js → chunk-GS7N3RFG.js} +51 -32
  106. package/dist/{chunk-LJXMYKZJ.js → chunk-GXQYEIYM.js} +7 -5
  107. package/dist/{chunk-VNU26RCO.js → chunk-H5EQOSTC.js} +43 -33
  108. package/dist/{chunk-W7VWI2YH.js → chunk-H7KERB6Q.js} +7 -5
  109. package/dist/{chunk-OUBGGKDU.js → chunk-HGDBM3A5.js} +5 -3
  110. package/dist/{chunk-JENSEMXF.js → chunk-HI7ADE4E.js} +1 -1
  111. package/dist/{chunk-CXJ6FUKN.js → chunk-HNPKCRCE.js} +1010 -330
  112. package/dist/{chunk-FPJPLKDW.js → chunk-HRHXTLUM.js} +40 -16
  113. package/dist/{chunk-57TDNMI3.js → chunk-HRYI22QU.js} +17 -15
  114. package/dist/{chunk-LO6P2VYG.js → chunk-HWNFFCGB.js} +5 -3
  115. package/dist/{chunk-XI2LCCYQ.js → chunk-HXFZX2BI.js} +12 -8
  116. package/dist/{chunk-H7KM7LZE.js → chunk-HYHV2P3G.js} +16 -13
  117. package/dist/{chunk-X3WY6MN3.js → chunk-IB66ZLDN.js} +10 -8
  118. package/dist/{chunk-3NFFJL5D.js → chunk-IJQHBK76.js} +1 -1
  119. package/dist/{chunk-LQJPN536.js → chunk-IK6LHW3E.js} +6 -4
  120. package/dist/{chunk-DCZWQLYT.js → chunk-IOHRX4KF.js} +26 -21
  121. package/dist/{chunk-2GF7OLF3.js → chunk-IRXZKKCG.js} +21 -15
  122. package/dist/{chunk-Z5IA3WDR.js → chunk-IUBBEU6O.js} +160 -81
  123. package/dist/{chunk-W62H2XSO.js → chunk-IWPO5AUT.js} +29 -26
  124. package/dist/{chunk-BEVTIBRH.js → chunk-J4K4C4T5.js} +31 -15
  125. package/dist/{chunk-WERM6KPJ.js → chunk-JCEYOSST.js} +14 -6
  126. package/dist/{chunk-HYU5VLGA.js → chunk-JCG2EBNB.js} +1 -1
  127. package/dist/{chunk-UNAGJYET.js → chunk-JFBVIMGY.js} +14 -12
  128. package/dist/chunk-JJ4SCGRJ.js +43 -0
  129. package/dist/{chunk-2Q5EDGEO.js → chunk-JLYH2QOE.js} +7 -5
  130. package/dist/{chunk-X4CXA2IL.js → chunk-JMH6TCZJ.js} +23 -21
  131. package/dist/{chunk-6PPOWY5E.js → chunk-JUHZBZPZ.js} +17 -13
  132. package/dist/{chunk-GUX3PTYM.js → chunk-JVMNEI7B.js} +3 -3
  133. package/dist/chunk-JYJMIAFS.js +44 -0
  134. package/dist/{chunk-34S2WGOB.js → chunk-KIY2WCN7.js} +7 -3
  135. package/dist/chunk-KVVNAUIG.js +66 -0
  136. package/dist/{chunk-M32BLWDH.js → chunk-KYO5HT4G.js} +14 -12
  137. package/dist/chunk-L27KUL5B.js +38 -0
  138. package/dist/chunk-L3PIN47C.js +18 -0
  139. package/dist/{chunk-IH2XURVQ.js → chunk-L6Z6TMIK.js} +5 -5
  140. package/dist/{chunk-E6ZIEVOI.js → chunk-LAGZBQHK.js} +16 -13
  141. package/dist/chunk-LBG4GMOR.js +68 -0
  142. package/dist/{chunk-UF4GLFBX.js → chunk-LDKP7OWQ.js} +33 -24
  143. package/dist/{chunk-ZQ7SKESZ.js → chunk-LELM7X5H.js} +13 -11
  144. package/dist/{chunk-INQHESFB.js → chunk-LIB6AUZS.js} +6 -4
  145. package/dist/{chunk-H5HBGNXU.js → chunk-LIQWFDOZ.js} +6 -4
  146. package/dist/{chunk-TYQBFTBR.js → chunk-LKUTBQ2Y.js} +8 -6
  147. package/dist/{chunk-7BR7IPOH.js → chunk-LOCJHNZI.js} +10 -8
  148. package/dist/{chunk-SQV37XO2.js → chunk-LTIXFLYE.js} +6 -6
  149. package/dist/{chunk-3NWDLGG6.js → chunk-M3RWF7MC.js} +33 -29
  150. package/dist/chunk-MA6UK7GX.js +42 -0
  151. package/dist/{chunk-ISUAAMGS.js → chunk-MCE74XMF.js} +25 -16
  152. package/dist/{chunk-EGQRREQH.js → chunk-MDTAZ6NE.js} +37 -24
  153. package/dist/{chunk-ZZK56BLP.js → chunk-MMOMKHAX.js} +6 -4
  154. package/dist/{chunk-P32RUW3B.js → chunk-MOWUP33K.js} +49 -15
  155. package/dist/{chunk-UOR2DTHH.js → chunk-MPATOMY5.js} +18 -14
  156. package/dist/{chunk-LNBQOP7D.js → chunk-MQFSEGTU.js} +23 -21
  157. package/dist/{chunk-2Q56PQPS.js → chunk-MT3FNSXO.js} +4 -4
  158. package/dist/{chunk-FZOJFH7Q.js → chunk-MUY5MAGM.js} +15 -12
  159. package/dist/{chunk-7DOR27HL.js → chunk-MVXMISNA.js} +9 -7
  160. package/dist/{chunk-CX4RZ2KS.js → chunk-MWN7CBVL.js} +5 -3
  161. package/dist/{chunk-BXYMYEJ4.js → chunk-MZWM73S2.js} +18 -17
  162. package/dist/chunk-NBZ7RKX3.js +46 -0
  163. package/dist/{chunk-EPCJQQWD.js → chunk-NC56V6KQ.js} +6 -4
  164. package/dist/{chunk-7UOMVMFG.js → chunk-NN6AXKFX.js} +17 -15
  165. package/dist/{chunk-BIGDQDHD.js → chunk-NOU5IBLM.js} +6 -4
  166. package/dist/{chunk-LFGTYX5U.js → chunk-NQDHRT2H.js} +20 -18
  167. package/dist/{chunk-KDNTAPLX.js → chunk-NTEPBOAF.js} +6 -4
  168. package/dist/{chunk-LYBNHMVZ.js → chunk-NTOPAOBY.js} +3 -3
  169. package/dist/{chunk-R44CYFPV.js → chunk-NX5IPHI3.js} +19 -16
  170. package/dist/{chunk-GCWRWSU7.js → chunk-O4ZWZZZT.js} +6 -4
  171. package/dist/chunk-OCU5S2XG.js +36 -0
  172. package/dist/{chunk-SU74NDMQ.js → chunk-OKSRK2LJ.js} +19 -17
  173. package/dist/{chunk-XD75VZIH.js → chunk-OSWOIFRQ.js} +9 -7
  174. package/dist/{chunk-PKBHS4AA.js → chunk-OSZTENIA.js} +54 -21
  175. package/dist/{chunk-NDCF4R6S.js → chunk-OTUBMKSG.js} +10 -8
  176. package/dist/{chunk-THDMSZ3R.js → chunk-OYKNPZCV.js} +2837 -693
  177. package/dist/{chunk-ZQ3ON2VQ.js → chunk-OYTSRNSZ.js} +8 -6
  178. package/dist/chunk-OYZ64UMQ.js +67 -0
  179. package/dist/{chunk-UF4AZOZB.js → chunk-PB3NCPRF.js} +10 -8
  180. package/dist/chunk-PIPJZIJE.js +47 -0
  181. package/dist/{chunk-2RLKFUUL.js → chunk-PIPYJTIL.js} +27 -24
  182. package/dist/{chunk-MZCGSXVR.js → chunk-PUMNCWHJ.js} +15 -13
  183. package/dist/{chunk-X5F3Q5LV.js → chunk-PZBNDFZ7.js} +35 -25
  184. package/dist/chunk-Q2ULHBCJ.js +59 -0
  185. package/dist/{chunk-ZJFRMSJT.js → chunk-Q5QSWV2R.js} +14 -12
  186. package/dist/{chunk-Q2TECDIT.js → chunk-QFDPX6C4.js} +2886 -20703
  187. package/dist/{chunk-WG5U3F5V.js → chunk-QGBS4GMS.js} +14 -12
  188. package/dist/{chunk-BTGPE6CR.js → chunk-QIDSEHJA.js} +17 -15
  189. package/dist/{chunk-Q6DFNVRJ.js → chunk-QJ3AYXVO.js} +14 -12
  190. package/dist/{chunk-EBL2R3YG.js → chunk-QK6CGRKK.js} +6 -4
  191. package/dist/{chunk-S7FCV7S5.js → chunk-QOC3Q4UU.js} +1 -1
  192. package/dist/{chunk-JJF6HALY.js → chunk-QPLNB2BM.js} +5 -3
  193. package/dist/chunk-QVF4KYIO.js +71 -0
  194. package/dist/{chunk-6OJQOPUN.js → chunk-QXXEO4TF.js} +5 -3
  195. package/dist/{chunk-F3P7N7SF.js → chunk-QYFNVQLK.js} +1 -1
  196. package/dist/{chunk-6MUGR4LS.js → chunk-R6CJOMPC.js} +106 -29
  197. package/dist/{chunk-BDKC6H5P.js → chunk-ROWZYQOI.js} +9 -7
  198. package/dist/{chunk-2MMCFP5C.js → chunk-RQAMZVWW.js} +10 -8
  199. package/dist/chunk-RQSUFGU2.js +55 -0
  200. package/dist/{chunk-SDKLKB6I.js → chunk-RRKM3GJA.js} +38 -28
  201. package/dist/{chunk-OHNCWBKF.js → chunk-RSHVSXPJ.js} +7 -5
  202. package/dist/chunk-RSKMV3VC.js +22 -0
  203. package/dist/{chunk-U76OWS3Q.js → chunk-RU5W7JJQ.js} +25 -23
  204. package/dist/{chunk-63YRMR6J.js → chunk-RYY554OA.js} +7 -5
  205. package/dist/{chunk-5NMKONLP.js → chunk-SGYQORAD.js} +7 -3
  206. package/dist/{chunk-JA5FI3QV.js → chunk-SLGUSFOD.js} +3 -3
  207. package/dist/{chunk-M3NANSDZ.js → chunk-SUAHNYNQ.js} +17 -15
  208. package/dist/{chunk-QAXW2N3B.js → chunk-SUYC5NP6.js} +34 -34
  209. package/dist/{chunk-FFTRTL6R.js → chunk-SWSGRRNO.js} +6 -4
  210. package/dist/{chunk-UWOJLHFT.js → chunk-SYLXQNPC.js} +38 -24
  211. package/dist/chunk-T24TBI7F.js +54 -0
  212. package/dist/chunk-T2HXLDY3.js +55 -0
  213. package/dist/{chunk-O4GXGGBX.js → chunk-T5NH5L7A.js} +16 -13
  214. package/dist/{chunk-KXITGYLF.js → chunk-TAR6T2RE.js} +4 -2
  215. package/dist/chunk-TBQHBOFF.js +324 -0
  216. package/dist/{chunk-LKOR5UET.js → chunk-TKE6ZJMM.js} +26 -24
  217. package/dist/chunk-TKEXS74L.js +52 -0
  218. package/dist/{chunk-J3IOLXWM.js → chunk-TXYMNKGM.js} +16 -14
  219. package/dist/{chunk-IDKCWSM5.js → chunk-U2JTTRKS.js} +401 -115
  220. package/dist/{chunk-TNR75OXT.js → chunk-U37ZOYJJ.js} +11 -8
  221. package/dist/{chunk-7MJSQTL5.js → chunk-U57VLY6X.js} +23 -21
  222. package/dist/{chunk-BHT7QK4G.js → chunk-U66RQUFC.js} +6 -4
  223. package/dist/chunk-UCFNHK5L.js +50 -0
  224. package/dist/{chunk-IFKEI4SA.js → chunk-UI6KNLSO.js} +31 -11
  225. package/dist/{chunk-7GJS6DNX.js → chunk-UKRJ2ISN.js} +13 -3
  226. package/dist/chunk-UWJOM457.js +232 -0
  227. package/dist/{chunk-D73UEXYW.js → chunk-UXO25YBN.js} +3 -3
  228. package/dist/chunk-VE2T5URA.js +51 -0
  229. package/dist/{chunk-C3RY6KU6.js → chunk-W4EG25TI.js} +513 -172
  230. package/dist/{chunk-O66DM6DJ.js → chunk-WAAPMZWO.js} +6 -4
  231. package/dist/{chunk-R7NYHMUU.js → chunk-WECCLSYY.js} +4884 -3669
  232. package/dist/chunk-WQDJGNJQ.js +45 -0
  233. package/dist/{chunk-UWMJKX5U.js → chunk-WWSCJBF6.js} +14 -12
  234. package/dist/{chunk-N3XIYPU3.js → chunk-X7HFXXTZ.js} +16 -13
  235. package/dist/chunk-X7XVMYIL.js +5 -0
  236. package/dist/{chunk-NR2UJWOC.js → chunk-XERIHPBF.js} +12 -9
  237. package/dist/{chunk-JRBFANFE.js → chunk-XKNISZ6N.js} +21 -18
  238. package/dist/{chunk-PPD7HTDP.js → chunk-XNH5ZWIA.js} +20 -18
  239. package/dist/{chunk-7IOWA5D5.js → chunk-XNW3EDCY.js} +13 -3
  240. package/dist/{chunk-2LGRMVCA.js → chunk-XPXOKHNZ.js} +13 -11
  241. package/dist/{chunk-ZJXLNDH4.js → chunk-XXRBAJ36.js} +14 -12
  242. package/dist/{chunk-EHA7RMZ3.js → chunk-YA2IJJ6N.js} +8 -6
  243. package/dist/{chunk-LGBMTVNT.js → chunk-YB5AKYVQ.js} +7 -5
  244. package/dist/{chunk-JB5LINEM.js → chunk-YDDLVBQ4.js} +3 -3
  245. package/dist/{chunk-PAQ2AS5E.js → chunk-YF6N45QN.js} +1 -1
  246. package/dist/{chunk-WMTRHUI5.js → chunk-YHWX5LPT.js} +23 -21
  247. package/dist/{chunk-KQGURXFU.js → chunk-YLZNTVZR.js} +36 -13
  248. package/dist/{chunk-NY2XSR5K.js → chunk-YUJTOALL.js} +118 -18
  249. package/dist/{chunk-VZALIKIF.js → chunk-Z5YDTIWQ.js} +19 -16
  250. package/dist/{chunk-LDLL7LB3.js → chunk-ZCU2UY47.js} +24 -22
  251. package/dist/{chunk-OWNCM4ZN.js → chunk-ZIAYNHHE.js} +197 -17
  252. package/dist/{chunk-WJF2CS6M.js → chunk-ZJ2W2RDE.js} +7 -5
  253. package/dist/{chunk-REWWDVQB.js → chunk-ZRQHSMPK.js} +6 -4
  254. package/dist/{chunk-O7XLYEFA.js → chunk-ZSD75FYI.js} +57 -23
  255. package/dist/chunk-ZSNNF26J.js +220 -0
  256. package/dist/{chunk-BQ4SQQC6.js → chunk-ZX6RAGE6.js} +11 -9
  257. package/dist/files.json +583 -515
  258. package/dist/packages/sdk/npm/index.js +6428 -4882
  259. package/dist/packages/ui/dist/assets/{elk-api-CIf-0gz5.js → elk-api--rH6Kdl4.js} +2 -2
  260. package/dist/packages/ui/dist/assets/index-Bf2immpE.css +1 -0
  261. package/dist/packages/ui/dist/assets/index-CH4nGIW3.js +62 -0
  262. package/dist/packages/ui/dist/index.html +2 -2
  263. package/package.json +6 -6
  264. package/dist/chunk-2SKB4O2E.js +0 -59
  265. package/dist/chunk-4U276ICE.js +0 -39
  266. package/dist/chunk-6H3Z5JHH.js +0 -64
  267. package/dist/chunk-AFZ3QA6W.js +0 -47
  268. package/dist/chunk-AVTBS4OW.js +0 -49
  269. package/dist/chunk-C4R4JLHE.js +0 -40
  270. package/dist/chunk-CBGGOQWU.js +0 -82
  271. package/dist/chunk-CMDXGQTS.js +0 -47
  272. package/dist/chunk-DLOBCJL6.js +0 -48
  273. package/dist/chunk-GIW4ZVDB.js +0 -39
  274. package/dist/chunk-IP74LCOQ.js +0 -57
  275. package/dist/chunk-IPHHDDC6.js +0 -45
  276. package/dist/chunk-KJXD4PNL.js +0 -50
  277. package/dist/chunk-KN5BXMWN.js +0 -44
  278. package/dist/chunk-MFHL5URL.js +0 -31
  279. package/dist/chunk-NXJ5URP6.js +0 -51
  280. package/dist/chunk-OMI6FPPN.js +0 -43
  281. package/dist/chunk-ONUPY3H6.js +0 -53
  282. package/dist/chunk-OTLDSZDV.js +0 -69
  283. package/dist/chunk-PSOFBQWB.js +0 -42
  284. package/dist/chunk-T4YPZIQN.js +0 -36
  285. package/dist/chunk-TUULXQRW.js +0 -420
  286. package/dist/chunk-WNKPRSGI.js +0 -36
  287. package/dist/packages/ui/dist/assets/index-CoK_Dl0D.js +0 -47
  288. package/dist/packages/ui/dist/assets/index-Dw20IRhQ.css +0 -1
  289. package/dist/{chunk-24XLDU72.js → chunk-PXMV2LLY.js} +3 -3
@@ -6,56 +6,63 @@ var __atticusPath = (p) => __atticusFileURLToPath(__atticusUrl(p));
6
6
  import {
7
7
  STORE_MARKER,
8
8
  addStoreReference,
9
+ archiveRefuses,
10
+ blockingIssues,
9
11
  readStoreMarker,
10
12
  readStoreVia
11
- } from "./chunk-UUU4CLJG.js";
13
+ } from "./chunk-5MKV4TV6.js";
12
14
  import {
13
15
  AdapterError,
14
16
  mergeBlockers,
15
17
  requireApproval
16
- } from "./chunk-7IGKHZ4Z.js";
18
+ } from "./chunk-ESJALLOK.js";
17
19
  import {
18
20
  outsideProfileSystems,
19
21
  readCatalog
20
- } from "./chunk-J2JAKCIW.js";
22
+ } from "./chunk-25CUJJTP.js";
21
23
  import {
22
24
  baseClonePath,
23
25
  createGit,
24
26
  readChangeRepos,
25
27
  writeChangeRepos
26
- } from "./chunk-PKBHS4AA.js";
28
+ } from "./chunk-OSZTENIA.js";
27
29
  import {
28
- ChangeArtifact,
29
30
  ChangeLifecycle,
30
31
  ChangeTouches,
31
- Finding,
32
- PHASES,
33
- Phase,
34
- RecordId,
35
- TestType,
36
32
  askedGapQuestionId,
37
33
  changeBranch,
38
34
  changesDirOf,
39
35
  changesRelOf,
40
- external_exports,
41
- fastGateOf,
42
- fastPathOf,
36
+ handleKey,
43
37
  handoffBranch,
44
38
  isAssistantResolution,
45
39
  listQuestions,
46
- loadOpenSpecSettings,
47
- loadOrgPack,
40
+ nextOwnersOf,
48
41
  openspecDirOf,
49
42
  orgPackDirOf,
50
43
  questionsRelOf,
51
44
  readFlow,
52
45
  readQuestion,
53
46
  specFlowFiles,
47
+ taskBranch,
54
48
  toCanonicalYaml
55
- } from "./chunk-Q2TECDIT.js";
49
+ } from "./chunk-GJVCBTSO.js";
56
50
  import {
57
51
  writeFileAtomic
58
- } from "./chunk-TUULXQRW.js";
52
+ } from "./chunk-G3ZFEHCX.js";
53
+ import {
54
+ ChangeArtifact,
55
+ Finding,
56
+ PHASES,
57
+ Phase,
58
+ RecordId,
59
+ TestType,
60
+ external_exports,
61
+ fastGateOf,
62
+ fastPathOf,
63
+ loadOpenSpecSettings,
64
+ loadOrgPack
65
+ } from "./chunk-QFDPX6C4.js";
59
66
  import {
60
67
  require_dist
61
68
  } from "./chunk-BQGDB6ZL.js";
@@ -1840,14 +1847,195 @@ function prApprovers(handoff2, approvers) {
1840
1847
  }
1841
1848
 
1842
1849
  // packages/changes/dist/assess.js
1843
- import { readFile as readFile9 } from "node:fs/promises";
1844
- import { join as join10 } from "node:path";
1850
+ import { readFile as readFile10 } from "node:fs/promises";
1851
+ import { join as join11 } from "node:path";
1845
1852
 
1846
1853
  // packages/changes/dist/release-prs.js
1854
+ var import_yaml8 = __toESM(require_dist(), 1);
1855
+ import { readFile as readFile9, writeFile } from "node:fs/promises";
1856
+ import { existsSync as existsSync2 } from "node:fs";
1857
+ import { join as join10 } from "node:path";
1858
+
1859
+ // packages/changes/dist/task-branches.js
1847
1860
  var import_yaml7 = __toESM(require_dist(), 1);
1848
- import { readFile as readFile8, writeFile } from "node:fs/promises";
1849
1861
  import { existsSync } from "node:fs";
1862
+ import { readdir as readdir5, readFile as readFile8 } from "node:fs/promises";
1850
1863
  import { join as join9 } from "node:path";
1864
+ var TASK_DECISION_FILE = "decision.yaml";
1865
+ var TaskDecision = external_exports.strictObject({
1866
+ schemaVersion: external_exports.literal(1),
1867
+ task: external_exports.string().min(1),
1868
+ branch: external_exports.string().min(1),
1869
+ /** The task branch's commit the person decided over. */
1870
+ commit: external_exports.string().regex(/^[0-9a-f]{7,64}$/),
1871
+ by: external_exports.string().min(1),
1872
+ at: external_exports.string().min(1),
1873
+ reason: external_exports.string().min(1)
1874
+ });
1875
+ async function taskRefs(root, id) {
1876
+ const dir = join9(changeFolder(root, id), "tasks");
1877
+ const out = [];
1878
+ for (const d of await readdir5(dir, { withFileTypes: true }).catch(() => [])) {
1879
+ if (!d.isDirectory())
1880
+ continue;
1881
+ const text = await readFile8(join9(dir, d.name, "task-run.yaml"), "utf8").catch(() => void 0);
1882
+ let y;
1883
+ try {
1884
+ y = text ? (0, import_yaml7.parse)(text) : void 0;
1885
+ } catch {
1886
+ y = void 0;
1887
+ }
1888
+ const task = String(y?.task ?? d.name);
1889
+ let branch;
1890
+ try {
1891
+ branch = typeof y?.branch === "string" ? y.branch : taskBranch(id, task);
1892
+ } catch {
1893
+ continue;
1894
+ }
1895
+ const pr = y?.pr;
1896
+ out.push({
1897
+ task,
1898
+ ...typeof y?.repo === "string" ? { repo: y.repo } : {},
1899
+ branch,
1900
+ ...typeof y?.state === "string" ? { state: y.state } : {},
1901
+ ...pr && typeof pr.number === "number" && typeof pr.url === "string" ? { pr: { number: pr.number, url: pr.url } } : {},
1902
+ ...y?.ticked ? { ticked: true } : {},
1903
+ ...typeof y?.commit === "string" && /^[0-9a-f]{7,64}$/.test(y.commit) ? { commit: y.commit } : {}
1904
+ });
1905
+ }
1906
+ return out;
1907
+ }
1908
+ function repoDir(root, r) {
1909
+ const dirs = [join9(root, r.worktree)];
1910
+ try {
1911
+ dirs.push(baseClonePath(root, r.id));
1912
+ } catch {
1913
+ }
1914
+ return dirs.find((d) => existsSync(d));
1915
+ }
1916
+ async function readTaskDecision(root, id, task) {
1917
+ const text = await readFile8(join9(changeFolder(root, id), "tasks", task, TASK_DECISION_FILE), "utf8").catch(() => void 0);
1918
+ if (text === void 0)
1919
+ return void 0;
1920
+ try {
1921
+ const r = TaskDecision.safeParse((0, import_yaml7.parse)(text));
1922
+ return r.success ? r.data : void 0;
1923
+ } catch {
1924
+ return void 0;
1925
+ }
1926
+ }
1927
+ async function unmergedTaskBranches(root, id, o = {}) {
1928
+ const cr = await readChangeRepos(root, id).catch(() => void 0);
1929
+ if (!cr?.repos.length)
1930
+ return [];
1931
+ const git = o.git ?? createGit({ timeoutMs: 3e4 });
1932
+ const remote = o.remote ?? "origin";
1933
+ const from = changeBranch(id);
1934
+ const records = await taskRefs(root, id);
1935
+ const out = [];
1936
+ const sha = (dir, ref) => git(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], dir).then((x) => x.stdout.trim() || void 0, () => void 0);
1937
+ for (const r of cr.repos) {
1938
+ const dir = repoDir(root, r);
1939
+ if (!dir)
1940
+ continue;
1941
+ const listed = await git(["for-each-ref", "--format=%(refname)", `refs/heads/task/${id}/`], dir).then((x) => x.stdout.split(/\r?\n/).map((l) => l.trim().replace(/^refs\/heads\//, "")).filter(Boolean), () => []);
1942
+ const branches = /* @__PURE__ */ new Map();
1943
+ for (const b of listed) {
1944
+ const mine = records.find((x) => x.branch === b && (!x.repo || x.repo === r.id));
1945
+ const other = records.find((x) => x.branch === b);
1946
+ branches.set(b, mine ?? { task: other?.task ?? b.split("/").at(-1), branch: b });
1947
+ }
1948
+ for (const x of records)
1949
+ if (x.repo === r.id && !branches.has(x.branch))
1950
+ branches.set(x.branch, x);
1951
+ const refs = [...branches.values()].filter((x) => (!x.repo || x.repo === r.id) && (!o.task || x.task === o.task));
1952
+ if (!refs.length)
1953
+ continue;
1954
+ const not = [];
1955
+ if (await sha(dir, `refs/heads/${from}`))
1956
+ not.push(`refs/heads/${from}`);
1957
+ if (!o.offline) {
1958
+ const onHost = await git(["ls-remote", "--heads", remote, `refs/heads/${from}`], dir).then((x) => x.stdout.trim().split(/\s+/)[0] || void 0, () => void 0);
1959
+ if (onHost && !await sha(dir, onHost))
1960
+ await git(["fetch", "-q", remote, `+refs/heads/${from}:refs/remotes/${remote}/${from}`], dir).catch(() => void 0);
1961
+ if (onHost && await sha(dir, onHost))
1962
+ not.push(onHost);
1963
+ } else if (await sha(dir, `refs/remotes/${remote}/${from}`))
1964
+ not.push(`refs/remotes/${remote}/${from}`);
1965
+ for (const x of refs) {
1966
+ const tip = await sha(dir, `refs/heads/${x.branch}`);
1967
+ if (!tip)
1968
+ continue;
1969
+ const merged = x.ticked && x.commit ? await sha(dir, x.commit) : void 0;
1970
+ if (x.ticked && !merged)
1971
+ continue;
1972
+ const decided = await readTaskDecision(root, id, x.task);
1973
+ if (decided && decided.branch === x.branch && sameSha(decided.commit, tip))
1974
+ continue;
1975
+ const commits = await git([
1976
+ "rev-list",
1977
+ "--count",
1978
+ `refs/heads/${x.branch}`,
1979
+ ...not.length || merged ? ["--not", ...not, ...merged ? [merged] : []] : []
1980
+ ], dir).then((y) => Number(y.stdout.trim()) || 0, () => 0);
1981
+ if (commits > 0)
1982
+ out.push({
1983
+ task: x.task,
1984
+ repo: r.id,
1985
+ branch: x.branch,
1986
+ commits,
1987
+ ...x.state ? { state: x.state } : {},
1988
+ ...x.pr ? { pr: x.pr } : {}
1989
+ });
1990
+ }
1991
+ }
1992
+ return out.sort((a, b) => a.task < b.task ? -1 : a.task > b.task ? 1 : 0);
1993
+ }
1994
+ var sameSha = (a, b) => a.startsWith(b) || b.startsWith(a);
1995
+ function unmergedTaskWords(id, u) {
1996
+ const from = changeBranch(id);
1997
+ const n = `${u.commits} commit${u.commits === 1 ? "" : "s"}`;
1998
+ const what = u.state === "pr-open" && u.pr ? `its PR #${u.pr.number} isn't merged yet: a person merges it on the Git host (${u.pr.url}), then Sync records it` : u.state === "unverified" || u.state === "needs-person" || u.state === "failed" ? `it was never built and raised: Build and raise PR on the Task board (or Run again), then merge its PR into ${from}` : `raise its PR (Raise the task's PR on the Task board) and merge it into ${from}`;
1999
+ return `Task ${u.task}'s branch ${u.branch} in ${u.repo} has ${n} not in ${from}, so its code isn't in the change: ${what}. If its work isn't needed, mark the task done with a reason.`;
2000
+ }
2001
+ async function taskBranchReasons(root, id, o = {}) {
2002
+ return (await unmergedTaskBranches(root, id, o)).map((u) => ({
2003
+ code: "task-not-merged",
2004
+ message: unmergedTaskWords(id, u)
2005
+ }));
2006
+ }
2007
+ async function recordTaskDecision(root, id, task, o) {
2008
+ const reason = o.reason.trim();
2009
+ if (!reason)
2010
+ throw new ChangeError("invalid", `Say why task ${task}'s work isn't needed in ${id}: a reason is recorded with the decision.`);
2011
+ const branch = taskBranch(id, task);
2012
+ const git = o.git ?? createGit({ timeoutMs: 3e4 });
2013
+ const cr = await readChangeRepos(root, id).catch(() => void 0);
2014
+ let commit;
2015
+ for (const r of cr?.repos ?? []) {
2016
+ const dir = repoDir(root, r);
2017
+ if (!dir)
2018
+ continue;
2019
+ commit = await git(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}^{commit}`], dir).then((x) => x.stdout.trim() || void 0, () => void 0);
2020
+ if (commit)
2021
+ break;
2022
+ }
2023
+ if (!commit)
2024
+ throw new ChangeError("refused", `Task ${task} has no branch ${branch} here, so there is nothing to decide: mark it done.`);
2025
+ const d = TaskDecision.parse({
2026
+ schemaVersion: 1,
2027
+ task,
2028
+ branch,
2029
+ commit,
2030
+ by: o.by.trim(),
2031
+ at: o.at,
2032
+ reason
2033
+ });
2034
+ await writeFileAtomic(join9(changeFolder(root, id), "tasks", task, TASK_DECISION_FILE), toCanonicalYaml(d, ["schemaVersion", "task", "branch", "commit"]));
2035
+ return d;
2036
+ }
2037
+
2038
+ // packages/changes/dist/release-prs.js
1851
2039
  var RELEASE_PR_STATES = [
1852
2040
  "qa",
1853
2041
  "release-ready",
@@ -1878,11 +2066,11 @@ var NothingFile = external_exports.strictObject({
1878
2066
  });
1879
2067
  async function readReleaseFile(root, id) {
1880
2068
  const empty = { schemaVersion: 1, nothingToRelease: [] };
1881
- const text = await readFile8(join9(changeFolder(root, id), RELEASE_PRS_FILE), "utf8").catch(() => void 0);
2069
+ const text = await readFile9(join10(changeFolder(root, id), RELEASE_PRS_FILE), "utf8").catch(() => void 0);
1882
2070
  if (text === void 0)
1883
2071
  return empty;
1884
2072
  try {
1885
- const r = NothingFile.safeParse((0, import_yaml7.parse)(text));
2073
+ const r = NothingFile.safeParse((0, import_yaml8.parse)(text));
1886
2074
  return r.success ? r.data : empty;
1887
2075
  } catch {
1888
2076
  return empty;
@@ -1893,19 +2081,19 @@ async function readNothing(root, id) {
1893
2081
  }
1894
2082
  async function writeReleaseFile(root, id, nothing, merged) {
1895
2083
  const byRepo = (xs) => [...xs].sort((a, b) => a.repo < b.repo ? -1 : a.repo > b.repo ? 1 : 0);
1896
- await writeFile(join9(changeFolder(root, id), RELEASE_PRS_FILE), toCanonicalYaml(NothingFile.parse({
2084
+ await writeFile(join10(changeFolder(root, id), RELEASE_PRS_FILE), toCanonicalYaml(NothingFile.parse({
1897
2085
  schemaVersion: 1,
1898
2086
  nothingToRelease: byRepo(nothing),
1899
2087
  ...merged.length ? { merged: byRepo(merged) } : {}
1900
2088
  })), "utf8");
1901
2089
  }
1902
- function repoDir(root, r) {
1903
- const dirs = [join9(root, r.worktree)];
2090
+ function repoDir2(root, r) {
2091
+ const dirs = [join10(root, r.worktree)];
1904
2092
  try {
1905
2093
  dirs.push(baseClonePath(root, r.id));
1906
2094
  } catch {
1907
2095
  }
1908
- return dirs.find((d) => existsSync(d));
2096
+ return dirs.find((d) => existsSync2(d));
1909
2097
  }
1910
2098
  async function staleReleasePrs(root, id, o = {}) {
1911
2099
  const out = /* @__PURE__ */ new Set();
@@ -1921,23 +2109,24 @@ async function staleReleasePrs(root, id, o = {}) {
1921
2109
  const entry = merged.find((x) => x.repo === r.id && x.number === r.pr.number);
1922
2110
  if (!entry)
1923
2111
  continue;
1924
- const dir = repoDir(root, r);
2112
+ const dir = repoDir2(root, r);
1925
2113
  if (!dir)
1926
2114
  continue;
1927
- if (await movedPast(git, dir, remote, r.branch, entry.commit))
2115
+ if (await movedPast(git, dir, remote, r.branch, entry.commit, o.offline))
1928
2116
  out.add(r.id);
1929
2117
  }
1930
2118
  return out;
1931
2119
  }
1932
- async function movedPast(git, dir, remote, branch, commit) {
2120
+ var lastFetched = (git, dir, remote, branch) => git(["rev-parse", "--verify", "--quiet", `refs/remotes/${remote}/${branch}^{commit}`], dir).then((x) => x.stdout.trim() || void 0, () => void 0);
2121
+ async function movedPast(git, dir, remote, branch, commit, offline) {
1933
2122
  const ref = `refs/heads/${branch}`;
1934
2123
  const known = (sha) => git(["cat-file", "-e", `${sha}^{commit}`], dir).then(() => true, () => false);
1935
2124
  const here = await git(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], dir).then((x) => x.stdout.trim() || void 0, () => void 0);
1936
- const onHost = await git(["ls-remote", "--heads", remote, ref], dir).then((x) => x.stdout.trim().split(/\s+/)[0] || void 0, () => void 0);
1937
- if (onHost && !sameSha(onHost, commit) && !await known(onHost))
2125
+ const onHost = offline ? await lastFetched(git, dir, remote, branch) : await git(["ls-remote", "--heads", remote, ref], dir).then((x) => x.stdout.trim().split(/\s+/)[0] || void 0, () => void 0);
2126
+ if (!offline && onHost && !sameSha2(onHost, commit) && !await known(onHost))
1938
2127
  await git(["fetch", "-q", remote, `+${ref}:refs/remotes/${remote}/${branch}`], dir).catch(() => void 0);
1939
2128
  const ahead = async (sha) => {
1940
- if (!sha || sameSha(sha, commit))
2129
+ if (!sha || sameSha2(sha, commit))
1941
2130
  return false;
1942
2131
  if (!await known(sha) || !await known(commit))
1943
2132
  return true;
@@ -1961,17 +2150,19 @@ async function nothingToRelease(root, id, o = {}) {
1961
2150
  }
1962
2151
  return out;
1963
2152
  async function moved(r, commit) {
1964
- const dir = repoDir(root, r);
2153
+ const dir = repoDir2(root, r);
1965
2154
  if (!dir)
1966
2155
  return false;
1967
2156
  const ref = `refs/heads/${r.branch}`;
1968
2157
  const here = await git(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], dir).then((x) => x.stdout.trim() || void 0, () => void 0);
1969
- const onHost = await git(["ls-remote", "--heads", remote, ref], dir).then((x) => x.stdout.trim().split(/\s+/)[0] || void 0, () => void 0);
1970
- const at = (sha) => sha !== void 0 && (commit === void 0 || !sameSha(sha, commit));
2158
+ const fetched = o.offline ? await lastFetched(git, dir, remote, r.branch) : void 0;
2159
+ const behind = !!fetched && !!commit && await git(["merge-base", "--is-ancestor", fetched, commit], dir).then(() => true, () => false);
2160
+ const onHost = o.offline ? behind ? void 0 : fetched : await git(["ls-remote", "--heads", remote, ref], dir).then((x) => x.stdout.trim().split(/\s+/)[0] || void 0, () => void 0);
2161
+ const at = (sha) => sha !== void 0 && (commit === void 0 || !sameSha2(sha, commit));
1971
2162
  return at(here) || at(onHost);
1972
2163
  }
1973
2164
  }
1974
- var sameSha = (a, b) => a.startsWith(b) || b.startsWith(a);
2165
+ var sameSha2 = (a, b) => a.startsWith(b) || b.startsWith(a);
1975
2166
  var firstLine = (e) => (e instanceof Error ? e.message : String(e)).split("\n")[0].replace(/\.$/, "");
1976
2167
  var prOf = (pr, now) => ({
1977
2168
  url: pr.url,
@@ -2006,6 +2197,7 @@ async function raiseReleasePrs(root, id, o) {
2006
2197
  const before = file.nothingToRelease;
2007
2198
  const nothing = new Map(before.map((x) => [x.repo, x]));
2008
2199
  const stale = await staleReleasePrs(root, id, { git, remote });
2200
+ const unmerged = await unmergedTaskBranches(root, id, { git, remote });
2009
2201
  for (const r of repos) {
2010
2202
  const movedOn = r.pr?.state === "merged" && stale.has(r.id) ? `Release PR #${r.pr.number} merged before ${r.branch} moved on; this one carries what landed since.` : void 0;
2011
2203
  if (!live(r.pr) || movedOn)
@@ -2019,6 +2211,15 @@ async function raiseReleasePrs(root, id, o) {
2019
2211
  });
2020
2212
  continue;
2021
2213
  }
2214
+ const held = unmerged.filter((u) => u.repo === r.id);
2215
+ if (held.length) {
2216
+ rows.push({
2217
+ repo: r.id,
2218
+ outcome: "refused",
2219
+ message: `${r.id}: no release PR, since ${r.branch} lacks the code of ${held.length === 1 ? `task ${held[0].task}` : `tasks ${held.map((u) => u.task).join(", ")}`}. ${held.map((u) => unmergedTaskWords(id, u)).join(" ")}`
2220
+ });
2221
+ continue;
2222
+ }
2022
2223
  if (r.branch !== expected) {
2023
2224
  rows.push({
2024
2225
  repo: r.id,
@@ -2058,8 +2259,8 @@ async function raiseReleasePrs(root, id, o) {
2058
2259
  continue;
2059
2260
  }
2060
2261
  const notes = movedOn ? [movedOn] : [];
2061
- const dir = join9(root, r.worktree);
2062
- if (existsSync(dir)) {
2262
+ const dir = join10(root, r.worktree);
2263
+ if (existsSync2(dir)) {
2063
2264
  const onHost = await git(["ls-remote", "--heads", remote, `refs/heads/${r.branch}`], dir).then((x) => x.stdout.trim() ? "yes" : "no").catch((e) => {
2064
2265
  notes.push(`Atticus couldn't reach ${remote} (${firstLine(e)}): push ${r.branch} yourself if the host lacks it.`);
2065
2266
  return "unknown";
@@ -2222,7 +2423,7 @@ async function syncReleasePrs(root, id, o) {
2222
2423
  return { change: id, rows };
2223
2424
  }
2224
2425
  async function branchTip(root, r, g, remote) {
2225
- const dir = repoDir(root, r);
2426
+ const dir = repoDir2(root, r);
2226
2427
  if (!dir)
2227
2428
  return void 0;
2228
2429
  const git = g ?? createGit({ timeoutMs: 3e4 });
@@ -2246,11 +2447,11 @@ function buildOf(pr) {
2246
2447
  return "passed";
2247
2448
  }
2248
2449
  async function requireMergedPrs(root) {
2249
- const text = await readFile8(join9(orgPackDirOf(root), "process", "ci.yaml"), "utf8").catch(() => void 0);
2450
+ const text = await readFile9(join10(orgPackDirOf(root), "process", "ci.yaml"), "utf8").catch(() => void 0);
2250
2451
  if (text === void 0)
2251
2452
  return true;
2252
2453
  try {
2253
- const v = (0, import_yaml7.parse)(text)?.archive?.requireMergedPrs;
2454
+ const v = (0, import_yaml8.parse)(text)?.archive?.requireMergedPrs;
2254
2455
  return v !== false;
2255
2456
  } catch {
2256
2457
  return true;
@@ -2263,7 +2464,7 @@ async function releasePrReasons(root, id, o = {}) {
2263
2464
  const merged = await requireMergedPrs(root);
2264
2465
  const nothing = await nothingToRelease(root, id, o);
2265
2466
  const stale = await staleReleasePrs(root, id, o);
2266
- const out = [];
2467
+ const out = await taskBranchReasons(root, id, o);
2267
2468
  for (const r of cr.repos) {
2268
2469
  if (!r.pr && nothing.has(r.id))
2269
2470
  continue;
@@ -2335,7 +2536,11 @@ async function assess(ctx, change) {
2335
2536
  ...stageReasons.length ? [] : await checkMandatoryRounds(ctx.root, change, phaseGates(ctx, phase).filter((g) => mandatoryGates(ctx).includes(g))),
2336
2537
  // ADR 0184: go/no-go is decided over the release PRs, each repo's change branch into its
2337
2538
  // default branch, merged (unless the org pack's ci.yaml says archive.requireMergedPrs: false).
2338
- ...phase === "release" ? await releasePrReasons(ctx.root, change.id) : []
2539
+ // Both read refs here only (the host's branches as last fetched): an assessment runs on every
2540
+ // page load (Home's cockpit), which never reaches the Git host; Sync and the release steps do.
2541
+ ...phase === "release" ? await releasePrReasons(ctx.root, change.id, { offline: true }) : [],
2542
+ // App-only audit: Build ready waits for every task's work to be in the change branch.
2543
+ ...phase === "build" ? await taskBranchReasons(ctx.root, change.id, { offline: true }) : []
2339
2544
  ];
2340
2545
  const next = change.state === "returned" ? phaseState(phase) : nextState(type, phase);
2341
2546
  const live2 = change.state === "returned" ? void 0 : liveHandoff(change);
@@ -2378,7 +2583,7 @@ async function changeReport(root, id) {
2378
2583
  return { ...a, nextStep: nextStep(a, tasks), problems: ctx.problems };
2379
2584
  }
2380
2585
  async function taskTicks(root, id) {
2381
- const text = await readFile9(join10(changeFolder(root, id), "tasks.md"), "utf8").catch(() => "");
2586
+ const text = await readFile10(join11(changeFolder(root, id), "tasks.md"), "utf8").catch(() => "");
2382
2587
  const boxes = [...text.matchAll(/^\s*[-*]\s+\[([ xX])\]/gm)].map((m) => m[1] !== " ");
2383
2588
  return boxes.length ? { done: boxes.filter(Boolean).length, total: boxes.length } : void 0;
2384
2589
  }
@@ -2409,9 +2614,9 @@ function nextStep(a, tasks) {
2409
2614
  }
2410
2615
 
2411
2616
  // packages/changes/dist/new-change.js
2412
- var import_yaml8 = __toESM(require_dist(), 1);
2413
- import { mkdir, readFile as readFile10, writeFile as writeFile2 } from "node:fs/promises";
2414
- import { join as join11 } from "node:path";
2617
+ var import_yaml9 = __toESM(require_dist(), 1);
2618
+ import { mkdir, readFile as readFile11, writeFile as writeFile2 } from "node:fs/promises";
2619
+ import { join as join12 } from "node:path";
2415
2620
  var nowIso2 = () => (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
2416
2621
  var strip2 = (h) => h.startsWith("@") ? h.slice(1) : h;
2417
2622
  function windowsUnsafeName(id) {
@@ -2423,7 +2628,7 @@ function slugify(title) {
2423
2628
  }
2424
2629
  async function exists(path) {
2425
2630
  try {
2426
- await readFile10(path);
2631
+ await readFile11(path);
2427
2632
  return true;
2428
2633
  } catch {
2429
2634
  return false;
@@ -2431,7 +2636,7 @@ async function exists(path) {
2431
2636
  }
2432
2637
  async function defaultSchema(root) {
2433
2638
  try {
2434
- const cfg = (0, import_yaml8.parse)(await readFile10(join11(openspecDirOf(root), "config.yaml"), "utf8"));
2639
+ const cfg = (0, import_yaml9.parse)(await readFile11(join12(openspecDirOf(root), "config.yaml"), "utf8"));
2435
2640
  if (cfg && typeof cfg.schema === "string")
2436
2641
  return cfg.schema;
2437
2642
  } catch {
@@ -2455,17 +2660,17 @@ async function newChange(root, opts) {
2455
2660
  const now = opts.now ?? nowIso2();
2456
2661
  const by = strip2(opts.by);
2457
2662
  const dir = changeFolder(root, id);
2458
- if (opts.openspec && !await exists(join11(dir, ".openspec.yaml"))) {
2663
+ if (opts.openspec && !await exists(join12(dir, ".openspec.yaml"))) {
2459
2664
  await opts.openspec.newChange(id, { description: opts.title });
2460
2665
  } else {
2461
2666
  await mkdir(dir, { recursive: true });
2462
- if (!await exists(join11(dir, ".openspec.yaml")))
2463
- await writeFile2(join11(dir, ".openspec.yaml"), `schema: ${await defaultSchema(root)}
2667
+ if (!await exists(join12(dir, ".openspec.yaml")))
2668
+ await writeFile2(join12(dir, ".openspec.yaml"), `schema: ${await defaultSchema(root)}
2464
2669
  created: ${now.slice(0, 10)}
2465
2670
  `, "utf8");
2466
2671
  }
2467
- if (!await exists(join11(dir, "brief.md")))
2468
- await writeFileAtomic(join11(dir, "brief.md"), renderTemplate(template, {
2672
+ if (!await exists(join12(dir, "brief.md")))
2673
+ await writeFileAtomic(join12(dir, "brief.md"), renderTemplate(template, {
2469
2674
  title: opts.title,
2470
2675
  id,
2471
2676
  type: type.id,
@@ -2505,7 +2710,7 @@ created: ${now.slice(0, 10)}
2505
2710
  // packages/changes/dist/publish.js
2506
2711
  import { rm } from "node:fs/promises";
2507
2712
  import { randomUUID } from "node:crypto";
2508
- import { join as join12, resolve } from "node:path";
2713
+ import { join as join13, resolve } from "node:path";
2509
2714
  function gitHandoffPublisher(opts = {}) {
2510
2715
  const remote = opts.remote ?? "origin";
2511
2716
  const env = opts.env ?? process.env;
@@ -2539,7 +2744,7 @@ function gitHandoffPublisher(opts = {}) {
2539
2744
  "--quiet",
2540
2745
  `refs/remotes/${remote}/${base}^{commit}`
2541
2746
  ]) ?? await out(["rev-parse", "--verify", `refs/heads/${base}^{commit}`]);
2542
- const index = join12(gitDir, `atticus-handoff-index-${process.pid}-${randomUUID()}`);
2747
+ const index = join13(gitDir, `atticus-handoff-index-${process.pid}-${randomUUID()}`);
2543
2748
  const staged = createGit({ env: { ...env, GIT_INDEX_FILE: index } });
2544
2749
  try {
2545
2750
  await staged(["read-tree", start], root);
@@ -2548,8 +2753,8 @@ function gitHandoffPublisher(opts = {}) {
2548
2753
  const tree = (await staged(["write-tree"], root)).stdout.trim();
2549
2754
  const startTree = await out(["rev-parse", `${start}^{tree}`]);
2550
2755
  const commit = tree === startTree ? start : await out(["commit-tree", tree, "-p", start, "-m", message]);
2551
- await out(["push", "--quiet", remote, `${commit}:refs/heads/${branch}`]);
2552
2756
  await keepLocalBranch(out, tryOut, branch, start, commit);
2757
+ await out(["push", "--quiet", remote, `${commit}:refs/heads/${branch}`]);
2553
2758
  return { commit, changed: commit !== onRemote };
2554
2759
  } finally {
2555
2760
  await rm(index, { force: true });
@@ -2558,6 +2763,23 @@ function gitHandoffPublisher(opts = {}) {
2558
2763
  }
2559
2764
  }
2560
2765
  var queue = /* @__PURE__ */ new Map();
2766
+ async function handoffBranchPushed(root, branch, o = {}) {
2767
+ const git = createGit({ env: o.env ?? process.env });
2768
+ const sha = (ref) => git(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], root).then((x) => x.stdout.trim() || void 0, () => void 0);
2769
+ const here = await sha(`refs/heads/${branch}`);
2770
+ if (!here)
2771
+ return true;
2772
+ return await sha(`refs/remotes/${o.remote ?? "origin"}/${branch}`) === here;
2773
+ }
2774
+ async function pushHandoffBranch(root, branch, o) {
2775
+ requireApproval("git", o.approval);
2776
+ if (!/^handoff\//.test(branch))
2777
+ throw new Error(`${branch} isn't a hand-off branch`);
2778
+ const git = createGit({ env: o.env ?? process.env });
2779
+ const commit = (await git(["rev-parse", "--verify", `refs/heads/${branch}^{commit}`], root)).stdout.trim();
2780
+ await git(["push", "--quiet", o.remote ?? "origin", `refs/heads/${branch}:refs/heads/${branch}`], root);
2781
+ return { branch, commit };
2782
+ }
2561
2783
  async function keepLocalBranch(out, tryOut, branch, start, commit) {
2562
2784
  const ref = `refs/heads/${branch}`;
2563
2785
  const local = await tryOut(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`]);
@@ -2577,13 +2799,13 @@ async function keepLocalBranch(out, tryOut, branch, start, commit) {
2577
2799
  }
2578
2800
 
2579
2801
  // packages/changes/dist/handoff.js
2580
- import { readdir as readdir6, readFile as readFile12 } from "node:fs/promises";
2581
- import { join as join14 } from "node:path";
2802
+ import { readdir as readdir7, readFile as readFile13 } from "node:fs/promises";
2803
+ import { join as join15 } from "node:path";
2582
2804
 
2583
2805
  // packages/changes/dist/drafted.js
2584
- var import_yaml9 = __toESM(require_dist(), 1);
2585
- import { mkdir as mkdir2, readdir as readdir5, readFile as readFile11, rm as rm2 } from "node:fs/promises";
2586
- import { dirname, join as join13, relative, sep } from "node:path";
2806
+ var import_yaml10 = __toESM(require_dist(), 1);
2807
+ import { mkdir as mkdir2, readdir as readdir6, readFile as readFile12, rm as rm2 } from "node:fs/promises";
2808
+ import { dirname, join as join14, relative, sep } from "node:path";
2587
2809
  var CAPTURE_SCHEMA_VERSION = 1;
2588
2810
  var DraftCapture = external_exports.object({
2589
2811
  schemaVersion: external_exports.literal(CAPTURE_SCHEMA_VERSION),
@@ -2658,7 +2880,7 @@ var sameText = (text, recorded) => sha256(text) === recorded || sha256(text.repl
2658
2880
  async function walk2(dir, rel = "") {
2659
2881
  let entries;
2660
2882
  try {
2661
- entries = await readdir5(join13(dir, rel), { withFileTypes: true });
2883
+ entries = await readdir6(join14(dir, rel), { withFileTypes: true });
2662
2884
  } catch {
2663
2885
  return [];
2664
2886
  }
@@ -2803,7 +3025,7 @@ async function captureHandoff(input) {
2803
3025
  } else {
2804
3026
  const texts = await Promise.all(recorded.map(async (r) => [
2805
3027
  r,
2806
- await readFile11(join13(folder, ...r.path.split("/")), "utf8").catch(() => void 0)
3028
+ await readFile12(join14(folder, ...r.path.split("/")), "utf8").catch(() => void 0)
2807
3029
  ]));
2808
3030
  if (texts.every(([r, t]) => t !== void 0 && sameText(t, r.sha256))) {
2809
3031
  from = "working-tree";
@@ -2867,10 +3089,10 @@ async function captureHandoff(input) {
2867
3089
  } : {}
2868
3090
  };
2869
3091
  const p = capturePaths(name);
2870
- await rm2(join13(folder, ...p.drafted.split("/")), { recursive: true, force: true });
2871
- await rm2(join13(folder, ...p.merged.split("/")), { recursive: true, force: true });
3092
+ await rm2(join14(folder, ...p.drafted.split("/")), { recursive: true, force: true });
3093
+ await rm2(join14(folder, ...p.merged.split("/")), { recursive: true, force: true });
2872
3094
  const put = async (base, rel, text) => {
2873
- const f = join13(folder, ...base.split("/"), ...rel.split("/"));
3095
+ const f = join14(folder, ...base.split("/"), ...rel.split("/"));
2874
3096
  await mkdir2(dirname(f), { recursive: true });
2875
3097
  await writeFileAtomic(f, text);
2876
3098
  };
@@ -2879,37 +3101,37 @@ async function captureHandoff(input) {
2879
3101
  if (state === "captured")
2880
3102
  for (const [rel, t] of mergedFiles)
2881
3103
  await put(p.merged, rel, t);
2882
- await mkdir2(join13(folder, "stage"), { recursive: true });
2883
- await writeFileAtomic(join13(folder, ...p.capture.split("/")), HEADER + (0, import_yaml9.stringify)(capture, { lineWidth: 0 }));
3104
+ await mkdir2(join14(folder, "stage"), { recursive: true });
3105
+ await writeFileAtomic(join14(folder, ...p.capture.split("/")), HEADER + (0, import_yaml10.stringify)(capture, { lineWidth: 0 }));
2884
3106
  return { capture, file: p.capture };
2885
3107
  }
2886
3108
  async function readFolderFiles(dir) {
2887
3109
  const out = /* @__PURE__ */ new Map();
2888
3110
  for (const f of await walk2(dir))
2889
- out.set(f, (await readFile11(join13(dir, ...f.split("/")), "utf8")).replace(/\r\n/g, "\n"));
3111
+ out.set(f, (await readFile12(join14(dir, ...f.split("/")), "utf8")).replace(/\r\n/g, "\n"));
2890
3112
  return out;
2891
3113
  }
2892
3114
  async function changeFolders(root) {
2893
- const base = join13(root, ...changesRelOf(root).split("/"));
3115
+ const base = join14(root, ...changesRelOf(root).split("/"));
2894
3116
  const out = [];
2895
- const list = async (dir) => (await readdir5(dir, { withFileTypes: true }).catch(() => [])).filter((e) => e.isDirectory()).map((e) => e.name).sort();
3117
+ const list = async (dir) => (await readdir6(dir, { withFileTypes: true }).catch(() => [])).filter((e) => e.isDirectory()).map((e) => e.name).sort();
2896
3118
  for (const name of await list(base)) {
2897
3119
  if (name === "archive")
2898
- for (const a of await list(join13(base, "archive")))
2899
- out.push(join13(base, "archive", a));
3120
+ for (const a of await list(join14(base, "archive")))
3121
+ out.push(join14(base, "archive", a));
2900
3122
  else
2901
- out.push(join13(base, name));
3123
+ out.push(join14(base, name));
2902
3124
  }
2903
3125
  return out;
2904
3126
  }
2905
3127
  async function readDraftPairs(root) {
2906
3128
  const out = [];
2907
3129
  for (const folder of await changeFolders(root)) {
2908
- const names = (await readdir5(join13(folder, "stage")).catch(() => [])).filter((f) => f.endsWith(".capture.yaml")).sort();
3130
+ const names = (await readdir6(join14(folder, "stage")).catch(() => [])).filter((f) => f.endsWith(".capture.yaml")).sort();
2909
3131
  for (const f of names) {
2910
3132
  let capture;
2911
3133
  try {
2912
- capture = DraftCapture.parse((0, import_yaml9.parse)(await readFile11(join13(folder, "stage", f), "utf8")));
3134
+ capture = DraftCapture.parse((0, import_yaml10.parse)(await readFile12(join14(folder, "stage", f), "utf8")));
2913
3135
  } catch {
2914
3136
  continue;
2915
3137
  }
@@ -2917,8 +3139,8 @@ async function readDraftPairs(root) {
2917
3139
  out.push({
2918
3140
  capture,
2919
3141
  folder: relative(root, folder).split(sep).join("/"),
2920
- drafted: await readFolderFiles(join13(folder, ...p.drafted.split("/"))),
2921
- merged: await readFolderFiles(join13(folder, ...p.merged.split("/")))
3142
+ drafted: await readFolderFiles(join14(folder, ...p.drafted.split("/"))),
3143
+ merged: await readFolderFiles(join14(folder, ...p.merged.split("/")))
2922
3144
  });
2923
3145
  }
2924
3146
  }
@@ -2938,8 +3160,8 @@ async function completeCaptures(root, ctx, o) {
2938
3160
  continue;
2939
3161
  for (const h of change.handoffs.filter((x) => x.state === "merged")) {
2940
3162
  const { name } = await captureStageOf(ctx, change, h.phase);
2941
- const file = join13(changeFolder(root, change.id), ...capturePaths(name).capture.split("/"));
2942
- const prior = await readFile11(file, "utf8").then((t) => DraftCapture.safeParse((0, import_yaml9.parse)(t)), () => void 0);
3163
+ const file = join14(changeFolder(root, change.id), ...capturePaths(name).capture.split("/"));
3164
+ const prior = await readFile12(file, "utf8").then((t) => DraftCapture.safeParse((0, import_yaml10.parse)(t)), () => void 0);
2943
3165
  if (prior?.success && prior.data.pr.number === h.pr.number && prior.data.state !== "waiting-for-merge")
2944
3166
  continue;
2945
3167
  const base = prior?.success ? prior.data.base : o.defaultBase ?? "main";
@@ -2963,6 +3185,7 @@ async function completeCaptures(root, ctx, o) {
2963
3185
  // packages/changes/dist/handoff.js
2964
3186
  var nowIso3 = () => (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
2965
3187
  var strip3 = (h) => h.startsWith("@") ? h.slice(1) : h;
3188
+ var sameHandle = (a, b) => handleKey(a) === handleKey(b);
2966
3189
  function metarepo(ctx, repo) {
2967
3190
  const fromRuntime = ctx.orgPack.runtime.adapters.gitHost?.settings.metarepo;
2968
3191
  const r = repo ?? (typeof fromRuntime === "string" ? fromRuntime : void 0);
@@ -2979,16 +3202,16 @@ async function load(root, id) {
2979
3202
  }
2980
3203
  async function walkReview(dir, gate) {
2981
3204
  const out = [];
2982
- const base = join14(dir, "review", gate);
3205
+ const base = join15(dir, "review", gate);
2983
3206
  let rounds;
2984
3207
  try {
2985
- rounds = (await readdir6(base)).filter((r) => /^\d+$/.test(r)).sort((a, b) => Number(a) - Number(b));
3208
+ rounds = (await readdir7(base)).filter((r) => /^\d+$/.test(r)).sort((a, b) => Number(a) - Number(b));
2986
3209
  } catch {
2987
3210
  return [];
2988
3211
  }
2989
3212
  for (const r of rounds) {
2990
3213
  try {
2991
- for (const f of (await readdir6(join14(base, r))).filter((x) => /\.ya?ml$/.test(x)).sort())
3214
+ for (const f of (await readdir7(join15(base, r))).filter((x) => /\.ya?ml$/.test(x)).sort())
2992
3215
  out.push(`review/${gate}/${r}/${f}`);
2993
3216
  } catch {
2994
3217
  }
@@ -2999,12 +3222,12 @@ async function keptPairFiles(dir) {
2999
3222
  const out = [];
3000
3223
  let entries;
3001
3224
  try {
3002
- entries = await readdir6(join14(dir, "stage"), { withFileTypes: true });
3225
+ entries = await readdir7(join15(dir, "stage"), { withFileTypes: true });
3003
3226
  } catch {
3004
3227
  return out;
3005
3228
  }
3006
3229
  const walk3 = async (rel) => {
3007
- for (const e of await readdir6(join14(dir, ...rel.split("/")), { withFileTypes: true }).catch(() => [])) {
3230
+ for (const e of await readdir7(join15(dir, ...rel.split("/")), { withFileTypes: true }).catch(() => [])) {
3008
3231
  const p = `${rel}/${e.name}`;
3009
3232
  if (e.isDirectory())
3010
3233
  await walk3(p);
@@ -3038,15 +3261,20 @@ async function handoffFiles(ctx, a, phase) {
3038
3261
  for (const f of await stageFiles(dir, step))
3039
3262
  files.add(f);
3040
3263
  }
3041
- const present = async (f) => readFile12(join14(dir, ...f.split("/"))).then(() => true, () => false);
3042
- for (const own of ["stage/corrections.yaml", "stage/drafted.yaml"])
3264
+ const present = async (f) => readFile13(join15(dir, ...f.split("/"))).then(() => true, () => false);
3265
+ for (const own of [
3266
+ "stage/corrections.yaml",
3267
+ "stage/drafted.yaml",
3268
+ "stage/stories-numbers.yaml",
3269
+ "stage/stories-shape.yaml"
3270
+ ])
3043
3271
  if (await present(own))
3044
3272
  files.add(own);
3045
3273
  if (phase === "build") {
3046
3274
  for (const extra of ["tasks.md", "repos.yaml"])
3047
3275
  if (await present(extra))
3048
3276
  files.add(extra);
3049
- for (const t of await readdir6(join14(dir, "tasks"), { withFileTypes: true }).catch(() => []))
3277
+ for (const t of await readdir7(join15(dir, "tasks"), { withFileTypes: true }).catch(() => []))
3050
3278
  if (t.isDirectory() && await present(`tasks/${t.name}/report.md`))
3051
3279
  files.add(`tasks/${t.name}/report.md`);
3052
3280
  }
@@ -3069,6 +3297,11 @@ async function changeQuestionFiles(root, id) {
3069
3297
  const rel = questionsRelOf(root);
3070
3298
  return questions.filter((q) => namesChange(q.askedBy.command, id) || namesChange(q.rerun, id)).map((q) => `${rel}/${q.id}.yaml`).sort();
3071
3299
  }
3300
+ function nextRoleOf(c, phase, person) {
3301
+ const n = nextOwnersOf(phase, c.owners);
3302
+ return n?.people.includes(person) ? ` (${n.role.replace(/-/g, " ")})` : "";
3303
+ }
3304
+ var nextRoleName = (phase) => (nextOwnersOf(phase, {})?.role ?? "reviewer").replace(/-/g, " ");
3072
3305
  function prBody(a, phase, next, paths, reviewers, review) {
3073
3306
  const c = a.change;
3074
3307
  const lines2 = [
@@ -3084,7 +3317,7 @@ function prBody(a, phase, next, paths, reviewers, review) {
3084
3317
  "",
3085
3318
  "### Reviewers",
3086
3319
  "",
3087
- ...reviewers.length ? reviewers.map((r) => `- @${r}`) : ["- None"],
3320
+ ...reviewers.length ? reviewers.map((r) => `- @${r}${nextRoleOf(c, phase, r)}`) : [`- None: name the ${nextRoleName(phase)} under the change's owners`],
3088
3321
  "",
3089
3322
  "### Risk",
3090
3323
  "",
@@ -3115,7 +3348,7 @@ async function handoff(root, id, opts) {
3115
3348
  await requireValid(opts.openspec, id);
3116
3349
  const { files, artifacts } = await handoffFiles(ctx, a, phase);
3117
3350
  const dir = changeFolder(root, id);
3118
- const hashed = await Promise.all(files.map(async (path) => ({ path, sha256: sha256(await readFile12(join14(dir, path))) })));
3351
+ const hashed = await Promise.all(files.map(async (path) => ({ path, sha256: sha256(await readFile13(join15(dir, path))) })));
3119
3352
  const authors = { ...change.authors };
3120
3353
  for (const art of artifacts) {
3121
3354
  const people = (opts.authors?.[art] ?? [by]).map(strip3);
@@ -3130,8 +3363,11 @@ async function handoff(root, id, opts) {
3130
3363
  ...questionFiles
3131
3364
  ];
3132
3365
  const reviewers = [
3133
- ...new Set(files.flatMap((f) => ownersFor(ctx.codeowners, `${rel}/${id}/${f}`)))
3134
- ].filter((p) => p !== by).sort();
3366
+ .../* @__PURE__ */ new Set([
3367
+ ...files.flatMap((f) => ownersFor(ctx.codeowners, `${rel}/${id}/${f}`)),
3368
+ ...nextOwnersOf(phase, change.owners)?.people ?? []
3369
+ ])
3370
+ ].filter((p) => sameHandle(p, by) === false).sort();
3135
3371
  const live2 = change.state === "returned" ? void 0 : liveHandoff(change);
3136
3372
  if (live2 && live2.phase === phase) {
3137
3373
  const pr2 = await handoffPr(opts.gitHost, repo, id, live2);
@@ -3429,10 +3665,15 @@ async function returnToPo(root, id, opts) {
3429
3665
  async function requireValid(openspec, id) {
3430
3666
  const r = await openspec.validate({ item: id, type: "change", strict: true });
3431
3667
  const item = r.items[0];
3432
- if (!item || item.valid)
3668
+ const issues = item ? blockingIssues(item.issues) : [];
3669
+ if (!item || item.valid && issues.length === 0)
3433
3670
  return;
3434
- throw new ChangeError("refused", `${id} doesn't pass openspec validate --strict.`, item.issues.filter((i) => i.level !== "INFO").map((i) => ({ code: "openspec-invalid", message: `${i.path}: ${i.message}` })));
3671
+ throw new ChangeError("refused", `${id} doesn't pass openspec validate --strict.`, issues.map((i) => ({
3672
+ code: "openspec-invalid",
3673
+ message: `${i.path}: ${i.message}${archiveRefuses(i) ? ` ${ADDED_ONLY}` : ""}`
3674
+ })));
3435
3675
  }
3676
+ var ADDED_ONLY = `A spec that openspec/specs doesn't have yet takes "## ADDED Requirements" only: change the delta's MODIFIED (or RENAMED, REMOVED) heading to ADDED, or run the stage that wrote it again.`;
3436
3677
  async function archiveChange(root, id, opts) {
3437
3678
  const { ctx, change } = await load(root, id);
3438
3679
  const a = await assess(ctx, change);
@@ -3453,14 +3694,25 @@ async function archiveChange(root, id, opts) {
3453
3694
  };
3454
3695
  await changeStore(root).write(updated);
3455
3696
  if (opts.openspec)
3456
- await opts.openspec.archive(id);
3697
+ try {
3698
+ await opts.openspec.archive(id);
3699
+ } catch (e) {
3700
+ await changeStore(root).write(change);
3701
+ const words = (e instanceof Error ? e.message : String(e)).trim();
3702
+ throw new ChangeError("refused", `OpenSpec refused to archive ${id}, so nothing was archived.`, [
3703
+ {
3704
+ code: "openspec-invalid",
3705
+ message: `${words.replace(/\.?$/, ".")}${/target spec does not exist|only ADDED/i.test(words) ? ` ${ADDED_ONLY}` : " Fix what it says, then archive again (atticus openspec validate " + id + " --strict says more)."}`
3706
+ }
3707
+ ]);
3708
+ }
3457
3709
  return updated;
3458
3710
  }
3459
3711
 
3460
3712
  // packages/changes/dist/learn.js
3461
- var import_yaml10 = __toESM(require_dist(), 1);
3462
- import { readFile as readFile13 } from "node:fs/promises";
3463
- import { join as join15 } from "node:path";
3713
+ var import_yaml11 = __toESM(require_dist(), 1);
3714
+ import { readFile as readFile14 } from "node:fs/promises";
3715
+ import { join as join16 } from "node:path";
3464
3716
  var LEARN_SCHEMA_VERSION = 1;
3465
3717
  var MAX_CELLS = 4e6;
3466
3718
  var lines = (text) => {
@@ -3807,7 +4059,7 @@ async function pairTouches(root, p) {
3807
4059
  let entry;
3808
4060
  const yaml = (t) => {
3809
4061
  try {
3810
- const v = (0, import_yaml10.parse)(t);
4062
+ const v = (0, import_yaml11.parse)(t);
3811
4063
  return v && typeof v === "object" ? v : void 0;
3812
4064
  } catch {
3813
4065
  return void 0;
@@ -3849,7 +4101,7 @@ async function pairTouches(root, p) {
3849
4101
  flows.push(m[1]);
3850
4102
  }
3851
4103
  }
3852
- const change = yaml(await readFile13(join15(root, ...p.folder.split("/"), "change.yaml"), "utf8").catch(() => ""));
4104
+ const change = yaml(await readFile14(join16(root, ...p.folder.split("/"), "change.yaml"), "utf8").catch(() => ""));
3853
4105
  const touches = change?.touches ?? {};
3854
4106
  for (const r of Array.isArray(touches.repos) ? touches.repos : [])
3855
4107
  if (typeof r === "string")
@@ -3942,8 +4194,8 @@ async function detectConflicts(root) {
3942
4194
  }
3943
4195
 
3944
4196
  // packages/changes/dist/size.js
3945
- import { readFile as readFile14 } from "node:fs/promises";
3946
- import { join as join16 } from "node:path";
4197
+ import { readFile as readFile15 } from "node:fs/promises";
4198
+ import { join as join17 } from "node:path";
3947
4199
  async function changeSize(ctx, change) {
3948
4200
  const type = ctx.orgPack.changeTypes.types.find((t) => t.id === change.type);
3949
4201
  if (!type)
@@ -3952,7 +4204,7 @@ async function changeSize(ctx, change) {
3952
4204
  why: "standard",
3953
4205
  words: `${change.type} isn't a change type in change-types.yaml, so ${change.id} takes the full path.`
3954
4206
  };
3955
- const brief = await readFile14(join16(changeFolder(ctx.root, change.id), "brief.md"), "utf8").catch(() => "");
4207
+ const brief = await readFile15(join17(changeFolder(ctx.root, change.id), "brief.md"), "utf8").catch(() => "");
3956
4208
  const f = fastPathOf(type, brief);
3957
4209
  const gate = f.fast ? fastGateOf(type, ctx.orgPack.gates) : void 0;
3958
4210
  const words = {
@@ -3966,13 +4218,13 @@ async function changeSize(ctx, change) {
3966
4218
  }
3967
4219
 
3968
4220
  // packages/changes/dist/openspec-stores.js
3969
- import { existsSync as existsSync2 } from "node:fs";
3970
- import { readFile as readFile15, writeFile as writeFile3 } from "node:fs/promises";
4221
+ import { existsSync as existsSync3 } from "node:fs";
4222
+ import { readFile as readFile16, writeFile as writeFile3 } from "node:fs/promises";
3971
4223
  import { homedir } from "node:os";
3972
- import { basename, isAbsolute, join as join17, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
4224
+ import { basename, isAbsolute, join as join18, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
3973
4225
  function storeDirOf(root, path) {
3974
4226
  if (path === "~" || path.startsWith("~/") || path.startsWith("~\\"))
3975
- return join17(homedir(), path.slice(2));
4227
+ return join18(homedir(), path.slice(2));
3976
4228
  return isAbsolute(path) ? resolve2(path) : resolve2(root, path);
3977
4229
  }
3978
4230
  function packRel(root) {
@@ -4002,7 +4254,7 @@ async function storeSpecLookup(root, capability) {
4002
4254
  var REMOTE = /^[a-z][a-z0-9+.-]*:\/\//i;
4003
4255
  var SCP = /^[^/\\]+@[^:/\\]+:/;
4004
4256
  async function metarepoOrigin(root, git = createGit()) {
4005
- if (!existsSync2(join17(root, ".git")))
4257
+ if (!existsSync3(join18(root, ".git")))
4006
4258
  return void 0;
4007
4259
  try {
4008
4260
  const url = (await git(["remote", "get-url", "origin"], root)).stdout.trim();
@@ -4013,7 +4265,7 @@ async function metarepoOrigin(root, git = createGit()) {
4013
4265
  return void 0;
4014
4266
  }
4015
4267
  }
4016
- async function referenceMetarepoIn(root, repoDir2, o = {}) {
4268
+ async function referenceMetarepoIn(root, repoDir3, o = {}) {
4017
4269
  const { settings } = await loadOpenSpecSettings(orgPackDirOf(root));
4018
4270
  if (!settings.referenceInRepos)
4019
4271
  return { action: "off" };
@@ -4025,8 +4277,8 @@ async function referenceMetarepoIn(root, repoDir2, o = {}) {
4025
4277
  file,
4026
4278
  why: marker.missing ? `this metarepo isn't an OpenSpec store yet (no ${STORE_MARKER}): run atticus upgrade --openspec-store, commit the file, then hand down again` : `this metarepo's ${STORE_MARKER} can't be read (${marker.notes.join("; ")})`
4027
4279
  };
4028
- const path = join17(repoDir2, "openspec", "config.yaml");
4029
- const text = await readFile15(path, "utf8").catch(() => void 0);
4280
+ const path = join18(repoDir3, "openspec", "config.yaml");
4281
+ const text = await readFile16(path, "utf8").catch(() => void 0);
4030
4282
  if (text === void 0)
4031
4283
  return {
4032
4284
  action: "skipped",
@@ -4043,7 +4295,7 @@ async function referenceMetarepoIn(root, repoDir2, o = {}) {
4043
4295
  }
4044
4296
 
4045
4297
  // packages/changes/dist/merge-record.js
4046
- var import_yaml11 = __toESM(require_dist(), 1);
4298
+ var import_yaml12 = __toESM(require_dist(), 1);
4047
4299
  import { isDeepStrictEqual } from "node:util";
4048
4300
  var HANDOFF_RANK = {
4049
4301
  open: 0,
@@ -4161,7 +4413,7 @@ function mergeChangeRecords(base, ours, theirs) {
4161
4413
  }
4162
4414
  function readRecord(text) {
4163
4415
  try {
4164
- const r = ChangeLifecycle.safeParse((0, import_yaml11.parse)(text));
4416
+ const r = ChangeLifecycle.safeParse((0, import_yaml12.parse)(text));
4165
4417
  return r.success ? r.data : void 0;
4166
4418
  } catch {
4167
4419
  return void 0;
@@ -4212,6 +4464,29 @@ async function setChangeOwners(root, id, owners) {
4212
4464
  return r.data;
4213
4465
  }
4214
4466
 
4467
+ // packages/changes/dist/edit-hash.js
4468
+ import { createHash as createHash2 } from "node:crypto";
4469
+ function editText(file, text) {
4470
+ const lf = text.replace(/\r\n?/g, "\n");
4471
+ return isTasks(file) ? lf.replace(/^(\s*[-*]\s+\[)[ xX]?(\])/gm, "$1 $2") : lf;
4472
+ }
4473
+ function editSha(file, text) {
4474
+ const h = createHash2("sha256");
4475
+ if (typeof text !== "string" && !text.includes(13) && !isTasks(file))
4476
+ return h.update(text).digest("hex");
4477
+ const t = typeof text === "string" ? text : text.toString("utf8");
4478
+ return h.update(editText(file, t), "utf8").digest("hex");
4479
+ }
4480
+ function wroteThis(file, text, hash) {
4481
+ if (hash === void 0)
4482
+ return false;
4483
+ if (editSha(file, text) === hash)
4484
+ return true;
4485
+ const t = typeof text === "string" ? text : text.toString("utf8");
4486
+ return createHash2("sha256").update(t.replace(/\r\n?/g, "\n"), "utf8").digest("hex") === hash;
4487
+ }
4488
+ var isTasks = (file) => file.split(/[\\/]/).at(-1) === "tasks.md";
4489
+
4215
4490
  export {
4216
4491
  ChangeError,
4217
4492
  readTables,
@@ -4278,6 +4553,12 @@ export {
4278
4553
  workProgress,
4279
4554
  privacyImpact,
4280
4555
  prApprovers,
4556
+ TASK_DECISION_FILE,
4557
+ readTaskDecision,
4558
+ unmergedTaskBranches,
4559
+ unmergedTaskWords,
4560
+ taskBranchReasons,
4561
+ recordTaskDecision,
4281
4562
  RELEASE_PR_STATES,
4282
4563
  RELEASE_PRS_FILE,
4283
4564
  staleReleasePrs,
@@ -4296,6 +4577,8 @@ export {
4296
4577
  slugify,
4297
4578
  newChange,
4298
4579
  gitHandoffPublisher,
4580
+ handoffBranchPushed,
4581
+ pushHandoffBranch,
4299
4582
  CAPTURE_SCHEMA_VERSION,
4300
4583
  DraftCapture,
4301
4584
  capturePaths,
@@ -4335,5 +4618,8 @@ export {
4335
4618
  mergeChangeText,
4336
4619
  OWNER_ROLE_KEYS,
4337
4620
  ChangeOwnersError,
4338
- setChangeOwners
4621
+ setChangeOwners,
4622
+ editText,
4623
+ editSha,
4624
+ wroteThis
4339
4625
  };