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

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 (284) hide show
  1. package/dist/bin.js +8 -4
  2. package/dist/chunk-23XVSEV5.js +49 -0
  3. package/dist/{chunk-ZDPAS56H.js → chunk-24OXGB3P.js} +8 -2
  4. package/dist/{chunk-7EOBHUMC.js → chunk-24XLDU72.js} +4 -3
  5. package/dist/{chunk-CR3MTH32.js → chunk-2F4CYZKJ.js} +86 -11
  6. package/dist/{chunk-6IU67AEK.js → chunk-2GF7OLF3.js} +23 -15
  7. package/dist/chunk-2IIMFOPM.js +41 -0
  8. package/dist/chunk-2LGRMVCA.js +617 -0
  9. package/dist/{chunk-XPCM366L.js → chunk-2MMCFP5C.js} +10 -8
  10. package/dist/{chunk-JBTK5OP2.js → chunk-2Q56PQPS.js} +6 -4
  11. package/dist/{chunk-Z6LF7HQN.js → chunk-2Q5EDGEO.js} +7 -5
  12. package/dist/{chunk-3USYZGRF.js → chunk-2RLKFUUL.js} +38 -27
  13. package/dist/chunk-2SKB4O2E.js +59 -0
  14. package/dist/{chunk-SP2I63OO.js → chunk-34S2WGOB.js} +87 -4
  15. package/dist/{chunk-GQ4N4WKF.js → chunk-3NFFJL5D.js} +33 -27
  16. package/dist/{chunk-SJRGMG6A.js → chunk-3NWDLGG6.js} +28 -25
  17. package/dist/{chunk-4WBVUHXN.js → chunk-3RM4UK6W.js} +20 -18
  18. package/dist/chunk-42SIDKEU.js +583 -0
  19. package/dist/{chunk-GLUX4EEP.js → chunk-4EURQWQD.js} +20 -15
  20. package/dist/chunk-4U276ICE.js +39 -0
  21. package/dist/{chunk-ZMFPW66A.js → chunk-53T4O55J.js} +4 -3
  22. package/dist/{chunk-6J5OKA4Y.js → chunk-57TDNMI3.js} +17 -15
  23. package/dist/chunk-5BD2KYLE.js +57 -0
  24. package/dist/{chunk-7EFILTCI.js → chunk-5F7GFN2F.js} +28 -0
  25. package/dist/chunk-5NMKONLP.js +95 -0
  26. package/dist/{chunk-7ZUIMTOU.js → chunk-5SJZW52K.js} +26 -24
  27. package/dist/{chunk-4RS5KZQD.js → chunk-63YRMR6J.js} +6 -5
  28. package/dist/chunk-66PPNOON.js +62 -0
  29. package/dist/chunk-6H3Z5JHH.js +64 -0
  30. package/dist/{chunk-CEXSU4S6.js → chunk-6MUGR4LS.js} +775 -89
  31. package/dist/{chunk-QSXK2RGH.js → chunk-6OJQOPUN.js} +5 -3
  32. package/dist/{chunk-MVZVGYXH.js → chunk-6PPOWY5E.js} +84 -14
  33. package/dist/{chunk-7EKXJZ2Y.js → chunk-6ZGLAACW.js} +299 -38
  34. package/dist/chunk-6ZJ5A7AF.js +222 -0
  35. package/dist/{chunk-L24C55VN.js → chunk-745DAZ4L.js} +142 -30
  36. package/dist/{chunk-Q4D5X7QB.js → chunk-7ASNL4Q4.js} +46 -24
  37. package/dist/chunk-7BR7IPOH.js +35 -0
  38. package/dist/{chunk-7WD63HU2.js → chunk-7DOR27HL.js} +6 -6
  39. package/dist/chunk-7FTTA3HD.js +341 -0
  40. package/dist/{chunk-OLQJTJJU.js → chunk-7GJS6DNX.js} +12 -3
  41. package/dist/{chunk-7JUKDRSZ.js → chunk-7IGKHZ4Z.js} +347 -226
  42. package/dist/{chunk-G2B4ZQGH.js → chunk-7IOWA5D5.js} +11 -6
  43. package/dist/{chunk-EBEW3XXQ.js → chunk-7JITZFJC.js} +7 -5
  44. package/dist/chunk-7MJSQTL5.js +174 -0
  45. package/dist/{chunk-I4JRCD6M.js → chunk-7UOMVMFG.js} +25 -17
  46. package/dist/{chunk-YY6ZQQBP.js → chunk-AFWUDXEM.js} +19 -7
  47. package/dist/chunk-AFZ3QA6W.js +47 -0
  48. package/dist/chunk-AJQ72EBM.js +420 -0
  49. package/dist/chunk-AJYXNTNZ.js +317 -0
  50. package/dist/chunk-AVTBS4OW.js +49 -0
  51. package/dist/{chunk-FHH4I4ZV.js → chunk-BDKC6H5P.js} +12 -6
  52. package/dist/{chunk-IPKHE5D6.js → chunk-BEVTIBRH.js} +1526 -875
  53. package/dist/chunk-BHT7QK4G.js +162 -0
  54. package/dist/{chunk-6JUBZBMW.js → chunk-BIGDQDHD.js} +6 -4
  55. package/dist/{chunk-2BFCZ3RK.js → chunk-BO4KX37X.js} +20 -18
  56. package/dist/chunk-BPK5P77O.js +115 -0
  57. package/dist/chunk-BQ4SQQC6.js +59 -0
  58. package/dist/chunk-BQGDB6ZL.js +7342 -0
  59. package/dist/{chunk-2ANOROX3.js → chunk-BTGPE6CR.js} +11 -9
  60. package/dist/chunk-BTY3HZBO.js +93 -0
  61. package/dist/{chunk-DPZHZQKE.js → chunk-BXYMYEJ4.js} +44 -10
  62. package/dist/{chunk-2RMYG36Q.js → chunk-C3RY6KU6.js} +309 -346
  63. package/dist/chunk-C4R4JLHE.js +40 -0
  64. package/dist/chunk-CADWLE2T.js +18 -0
  65. package/dist/chunk-CBGGOQWU.js +82 -0
  66. package/dist/chunk-CMDXGQTS.js +47 -0
  67. package/dist/{chunk-MC3H7736.js → chunk-CQDGOPGH.js} +58 -18
  68. package/dist/{chunk-HFQCFSJR.js → chunk-CX4RZ2KS.js} +4 -3
  69. package/dist/{chunk-PAMPPUR6.js → chunk-CXJ6FUKN.js} +1852 -207
  70. package/dist/{chunk-ABWHYWNI.js → chunk-D73UEXYW.js} +3 -3
  71. package/dist/chunk-DCZWQLYT.js +1205 -0
  72. package/dist/chunk-DLOBCJL6.js +48 -0
  73. package/dist/{chunk-4BN53TG3.js → chunk-DOBQKHIF.js} +31 -23
  74. package/dist/chunk-E3ISYXO3.js +423 -0
  75. package/dist/{chunk-7SW2QWLU.js → chunk-E6ZIEVOI.js} +16 -13
  76. package/dist/chunk-EBL2R3YG.js +43 -0
  77. package/dist/{chunk-AIOQPLA5.js → chunk-EGQRREQH.js} +41 -15
  78. package/dist/chunk-EHA7RMZ3.js +58 -0
  79. package/dist/{chunk-M766ZJ6W.js → chunk-EIPTLPFC.js} +38 -27
  80. package/dist/chunk-EMRIQUND.js +517 -0
  81. package/dist/{chunk-DFBCSHVT.js → chunk-EPCJQQWD.js} +6 -4
  82. package/dist/{chunk-RZPYKDWS.js → chunk-F3P7N7SF.js} +1 -1
  83. package/dist/{chunk-R77KLRB3.js → chunk-FFLNS6VP.js} +21 -18
  84. package/dist/chunk-FFTRTL6R.js +26 -0
  85. package/dist/{chunk-IHMLFRVV.js → chunk-FPJPLKDW.js} +62 -16
  86. package/dist/{chunk-JCZIKA4C.js → chunk-FSMSFDLD.js} +5 -4
  87. package/dist/{chunk-AVJDSJ2F.js → chunk-FUJM6RTF.js} +8 -7
  88. package/dist/chunk-FZOJFH7Q.js +132 -0
  89. package/dist/{chunk-QRAOANID.js → chunk-G6X77UJZ.js} +23 -21
  90. package/dist/{chunk-3ALD2W2A.js → chunk-GCWRWSU7.js} +10 -4
  91. package/dist/chunk-GIW4ZVDB.js +39 -0
  92. package/dist/{chunk-B2WLAWNJ.js → chunk-GUX3PTYM.js} +3 -3
  93. package/dist/{chunk-DPUYDDQG.js → chunk-GZY6RUZ6.js} +25 -3
  94. package/dist/chunk-H4VO6WG3.js +10 -0
  95. package/dist/{chunk-MMOSZPWJ.js → chunk-H5HBGNXU.js} +5 -4
  96. package/dist/chunk-H7KM7LZE.js +229 -0
  97. package/dist/{chunk-AA6YULYB.js → chunk-HNM2YQT2.js} +7 -7
  98. package/dist/{chunk-3C7EYRFZ.js → chunk-HYU5VLGA.js} +1 -1
  99. package/dist/{chunk-XY3P7JW7.js → chunk-IDKCWSM5.js} +1032 -172
  100. package/dist/chunk-IFKEI4SA.js +237 -0
  101. package/dist/{chunk-F7HYOUFF.js → chunk-IGOE6KPG.js} +67 -22
  102. package/dist/{chunk-TDD55CJH.js → chunk-IH2XURVQ.js} +6 -5
  103. package/dist/chunk-INQHESFB.js +38 -0
  104. package/dist/chunk-IP74LCOQ.js +57 -0
  105. package/dist/chunk-IPHHDDC6.js +45 -0
  106. package/dist/{chunk-T6AIP7H5.js → chunk-ISUAAMGS.js} +110 -153
  107. package/dist/{chunk-A7UPUQFY.js → chunk-IUPG3UKI.js} +624 -319
  108. package/dist/{chunk-L6SGQIR3.js → chunk-IVBOQAGB.js} +7 -3
  109. package/dist/{chunk-27NKUS3X.js → chunk-J2JAKCIW.js} +2205 -796
  110. package/dist/{chunk-V2YTAIQO.js → chunk-J3IOLXWM.js} +24 -7
  111. package/dist/chunk-JA5FI3QV.js +142 -0
  112. package/dist/chunk-JAVI7JSP.js +49 -0
  113. package/dist/{chunk-HLJAXMM4.js → chunk-JB5LINEM.js} +6 -2
  114. package/dist/{chunk-2VHF7OXM.js → chunk-JENSEMXF.js} +1 -1
  115. package/dist/{chunk-6BVONWJ7.js → chunk-JJF6HALY.js} +4 -3
  116. package/dist/chunk-JLUCKAEL.js +38 -0
  117. package/dist/chunk-JRBFANFE.js +221 -0
  118. package/dist/{chunk-R6XF6UR3.js → chunk-KDNTAPLX.js} +4 -4
  119. package/dist/chunk-KFAVQZSX.js +33 -0
  120. package/dist/chunk-KJXD4PNL.js +50 -0
  121. package/dist/chunk-KN5BXMWN.js +44 -0
  122. package/dist/{chunk-PCVDV3UZ.js → chunk-KQGURXFU.js} +9 -7
  123. package/dist/{chunk-WY6PP6AA.js → chunk-KXITGYLF.js} +40 -6
  124. package/dist/{chunk-66YVAGGM.js → chunk-L27SV425.js} +22 -20
  125. package/dist/{chunk-NE2W3OO7.js → chunk-LDLL7LB3.js} +24 -22
  126. package/dist/chunk-LFGTYX5U.js +379 -0
  127. package/dist/{chunk-EYWIDJFU.js → chunk-LGBMTVNT.js} +7 -5
  128. package/dist/{chunk-Q5AMFEWD.js → chunk-LGFL54FP.js} +3 -2
  129. package/dist/{chunk-6TACQN3N.js → chunk-LJXMYKZJ.js} +7 -5
  130. package/dist/{chunk-BKVWTZ6A.js → chunk-LKOR5UET.js} +29 -26
  131. package/dist/chunk-LNBQOP7D.js +294 -0
  132. package/dist/{chunk-O3WI5KWW.js → chunk-LO6P2VYG.js} +2 -2
  133. package/dist/chunk-LQJPN536.js +122 -0
  134. package/dist/{chunk-YEDDOYSC.js → chunk-LYBNHMVZ.js} +29 -5
  135. package/dist/{chunk-A3GY6SOA.js → chunk-LZ7NUC62.js} +20 -18
  136. package/dist/chunk-M32BLWDH.js +37 -0
  137. package/dist/{chunk-VYDBJ73M.js → chunk-M3NANSDZ.js} +17 -15
  138. package/dist/chunk-MFHL5URL.js +31 -0
  139. package/dist/chunk-MFR5OPBD.js +109 -0
  140. package/dist/{chunk-DE76JROX.js → chunk-MG4ZL5RW.js} +32 -20
  141. package/dist/{chunk-N7IXEHK3.js → chunk-MO6P2JZH.js} +10 -8
  142. package/dist/{chunk-65NYPGRC.js → chunk-MUWDB4R4.js} +1 -1
  143. package/dist/chunk-MZCGSXVR.js +34 -0
  144. package/dist/{chunk-MGYZM27B.js → chunk-N3XIYPU3.js} +51 -23
  145. package/dist/chunk-NDCF4R6S.js +172 -0
  146. package/dist/{chunk-DHPACDG7.js → chunk-NR2UJWOC.js} +10 -8
  147. package/dist/chunk-NXJ5URP6.js +51 -0
  148. package/dist/{chunk-UNM6ZOKP.js → chunk-NY2XSR5K.js} +147 -18
  149. package/dist/{chunk-5GDRCDQB.js → chunk-O45HFTFS.js} +3 -2
  150. package/dist/{chunk-ONLS5QA5.js → chunk-O4GXGGBX.js} +14 -12
  151. package/dist/chunk-O5PXQR67.js +249 -0
  152. package/dist/{chunk-PRPPGYZG.js → chunk-O66DM6DJ.js} +6 -4
  153. package/dist/{chunk-KEM4SDDP.js → chunk-O7FDLW7L.js} +11 -8
  154. package/dist/{chunk-T2UYZSCQ.js → chunk-O7XLYEFA.js} +169 -29
  155. package/dist/{chunk-FITWGOJ2.js → chunk-OHNCWBKF.js} +4 -4
  156. package/dist/{chunk-652QWTLZ.js → chunk-OHVTTOPS.js} +3 -3
  157. package/dist/chunk-OMI6FPPN.js +43 -0
  158. package/dist/chunk-ONUPY3H6.js +53 -0
  159. package/dist/chunk-OTLDSZDV.js +69 -0
  160. package/dist/chunk-OUBGGKDU.js +22 -0
  161. package/dist/chunk-OWNCM4ZN.js +330 -0
  162. package/dist/{chunk-YISXLPHN.js → chunk-P2V7QW4D.js} +235 -35
  163. package/dist/{chunk-CNUKCS2T.js → chunk-P32RUW3B.js} +1632 -93
  164. package/dist/{chunk-BWZ77RQT.js → chunk-PAQ2AS5E.js} +1 -1
  165. package/dist/{chunk-ZMAINWBW.js → chunk-PBPBMP2B.js} +4 -3
  166. package/dist/{chunk-ZVM6AKKM.js → chunk-PJSJPMJI.js} +3 -3
  167. package/dist/{chunk-EFHQ3TWP.js → chunk-PKBHS4AA.js} +233 -56
  168. package/dist/{chunk-GT4I4ZWM.js → chunk-PMUAJGLI.js} +20 -16
  169. package/dist/chunk-PPD7HTDP.js +152 -0
  170. package/dist/chunk-PSOFBQWB.js +42 -0
  171. package/dist/{chunk-S2A7YC3Q.js → chunk-Q2TECDIT.js} +10694 -8896
  172. package/dist/chunk-Q4K5WB2W.js +42 -0
  173. package/dist/{chunk-UGLN7QHV.js → chunk-Q6DFNVRJ.js} +14 -12
  174. package/dist/chunk-QA4O2GGC.js +265 -0
  175. package/dist/chunk-QAXW2N3B.js +1216 -0
  176. package/dist/chunk-QBNWF5ZU.js +19 -0
  177. package/dist/chunk-QFWA2DPH.js +224 -0
  178. package/dist/{chunk-23W7VWKR.js → chunk-QKUJMING.js} +1363 -114
  179. package/dist/{chunk-NXFPS2LR.js → chunk-R44CYFPV.js} +16 -13
  180. package/dist/{chunk-CKSITVS4.js → chunk-R7NYHMUU.js} +2687 -786
  181. package/dist/chunk-REWWDVQB.js +162 -0
  182. package/dist/{chunk-JMSCMUCA.js → chunk-RGERPOIV.js} +145 -21
  183. package/dist/{chunk-6JCPI55B.js → chunk-RLDGWLQ7.js} +49 -7
  184. package/dist/chunk-RUGXBPWI.js +384 -0
  185. package/dist/{chunk-CPA6HPVR.js → chunk-RXPJMEOW.js} +18 -12
  186. package/dist/{chunk-3HI6Z55Y.js → chunk-S4PMJU6H.js} +339 -43
  187. package/dist/chunk-S5LSDXV4.js +40 -0
  188. package/dist/chunk-S7FCV7S5.js +51 -0
  189. package/dist/{chunk-5GGOLAKC.js → chunk-SDKLKB6I.js} +28 -26
  190. package/dist/chunk-SFSPGFCV.js +62 -0
  191. package/dist/{chunk-ZNCEKR4J.js → chunk-SFUP7TTO.js} +12 -8
  192. package/dist/{chunk-64EQYWCA.js → chunk-SLXZOMA6.js} +69 -19
  193. package/dist/chunk-SQV37XO2.js +273 -0
  194. package/dist/{chunk-K65BJIMT.js → chunk-SU74NDMQ.js} +19 -17
  195. package/dist/chunk-SYV5LHML.js +165 -0
  196. package/dist/chunk-T4YPZIQN.js +36 -0
  197. package/dist/chunk-T6DQR5TV.js +323 -0
  198. package/dist/{chunk-JIITQXFB.js → chunk-THDMSZ3R.js} +3075 -802
  199. package/dist/{chunk-JGZCG5VM.js → chunk-TNR75OXT.js} +7 -7
  200. package/dist/{chunk-D3PO4DOZ.js → chunk-TUULXQRW.js} +174 -15
  201. package/dist/chunk-TYQBFTBR.js +516 -0
  202. package/dist/chunk-U76OWS3Q.js +49 -0
  203. package/dist/{chunk-YYQN46FY.js → chunk-UCROWG2D.js} +27 -24
  204. package/dist/{chunk-6M5NK3K3.js → chunk-UF4AZOZB.js} +50 -10
  205. package/dist/chunk-UF4GLFBX.js +345 -0
  206. package/dist/{chunk-OT2O76OS.js → chunk-UGUP3ZM6.js} +240 -39
  207. package/dist/chunk-UNAGJYET.js +45 -0
  208. package/dist/{chunk-5WG5YP4T.js → chunk-UOR2DTHH.js} +16 -14
  209. package/dist/{chunk-S3QNRWYR.js → chunk-UPOY4YSQ.js} +14 -12
  210. package/dist/{chunk-EPTBZ3GP.js → chunk-UPS2DGFC.js} +1 -1
  211. package/dist/{chunk-4AK7IBVP.js → chunk-UUU4CLJG.js} +4 -2
  212. package/dist/{chunk-W3BQAZ3Q.js → chunk-UWMJKX5U.js} +14 -12
  213. package/dist/{chunk-QZSX3F7C.js → chunk-UWOJLHFT.js} +27 -23
  214. package/dist/chunk-VBTP56CE.js +535 -0
  215. package/dist/chunk-VCTWPLAO.js +211 -0
  216. package/dist/chunk-VNU26RCO.js +1215 -0
  217. package/dist/{chunk-CSZ4C5N6.js → chunk-VTZMAJ3W.js} +93 -10
  218. package/dist/{chunk-TXLH6WHQ.js → chunk-VW62D6QE.js} +14 -12
  219. package/dist/{chunk-CAQZUNOH.js → chunk-VY72R2XZ.js} +610 -3
  220. package/dist/{chunk-2DIQQJCB.js → chunk-VZALIKIF.js} +18 -15
  221. package/dist/{chunk-TYAID7B7.js → chunk-W62H2XSO.js} +25 -23
  222. package/dist/{chunk-HVUPKCGJ.js → chunk-W7VWI2YH.js} +9 -6
  223. package/dist/{chunk-TANFV3MZ.js → chunk-WERM6KPJ.js} +7 -4
  224. package/dist/{chunk-BOHJZTEQ.js → chunk-WF7B67YE.js} +208 -87
  225. package/dist/{chunk-7FBGJFEE.js → chunk-WG5U3F5V.js} +14 -12
  226. package/dist/{chunk-4NDAAFQT.js → chunk-WJF2CS6M.js} +8 -5
  227. package/dist/{chunk-XAKWMCXI.js → chunk-WKUJ3KPV.js} +4 -4
  228. package/dist/chunk-WMTRHUI5.js +103 -0
  229. package/dist/chunk-WNKPRSGI.js +36 -0
  230. package/dist/chunk-WXFLMQSR.js +223 -0
  231. package/dist/{chunk-RRTKKSLQ.js → chunk-X3WY6MN3.js} +8 -6
  232. package/dist/{chunk-ZCJDOK2S.js → chunk-X4CXA2IL.js} +47 -23
  233. package/dist/{chunk-UBBC2XSG.js → chunk-X5F3Q5LV.js} +560 -105
  234. package/dist/{chunk-C6EKFH7J.js → chunk-XD75VZIH.js} +9 -7
  235. package/dist/chunk-XERYFDB5.js +297 -0
  236. package/dist/chunk-XI2LCCYQ.js +420 -0
  237. package/dist/chunk-Y2EQNWKV.js +933 -0
  238. package/dist/{chunk-LR3R6Z2A.js → chunk-YHCMZC2J.js} +7 -7
  239. package/dist/chunk-YYY3AZFE.js +122 -0
  240. package/dist/{chunk-GDLULHTC.js → chunk-Z5IA3WDR.js} +19 -31
  241. package/dist/{chunk-T6XQL73F.js → chunk-ZFFYNRIO.js} +63 -23
  242. package/dist/{chunk-EDS2L2LD.js → chunk-ZFL7NY4F.js} +56 -27
  243. package/dist/{chunk-YMZ3TNYB.js → chunk-ZGULQAPZ.js} +7 -4
  244. package/dist/{chunk-4SKZDI62.js → chunk-ZIUFM5HT.js} +3 -1
  245. package/dist/{chunk-DKJA76CJ.js → chunk-ZJFRMSJT.js} +15 -13
  246. package/dist/chunk-ZJXLNDH4.js +239 -0
  247. package/dist/chunk-ZQ3ON2VQ.js +252 -0
  248. package/dist/{chunk-HITVBIJS.js → chunk-ZQ7SKESZ.js} +150 -415
  249. package/dist/{chunk-6QSERWXH.js → chunk-ZQXZ2SES.js} +24 -21
  250. package/dist/chunk-ZX57KSEQ.js +39 -0
  251. package/dist/{chunk-I3E7CX4H.js → chunk-ZZK56BLP.js} +5 -3
  252. package/dist/files.json +664 -368
  253. package/dist/packages/naysayer/constitution/constitution.yaml +19 -0
  254. package/dist/packages/sdk/npm/index.js +6194 -2542
  255. package/dist/packages/ui/dist/assets/{elk-api-tma0MCuh.js → elk-api-CIf-0gz5.js} +2 -2
  256. package/dist/packages/ui/dist/assets/index-CoK_Dl0D.js +47 -0
  257. package/dist/packages/ui/dist/assets/index-Dw20IRhQ.css +1 -0
  258. package/dist/packages/ui/dist/index.html +3 -2
  259. package/package.json +5 -5
  260. package/dist/chunk-2BF2EYJV.js +0 -174
  261. package/dist/chunk-42EVSKME.js +0 -37
  262. package/dist/chunk-4BKGMUIK.js +0 -53
  263. package/dist/chunk-5KLGBXG5.js +0 -48
  264. package/dist/chunk-6BNC6EQ4.js +0 -41
  265. package/dist/chunk-6D2CQ5II.js +0 -41
  266. package/dist/chunk-7AVHLZGD.js +0 -45
  267. package/dist/chunk-D46WUV3T.js +0 -33
  268. package/dist/chunk-E36QOJMD.js +0 -47
  269. package/dist/chunk-FQXYPF7E.js +0 -147
  270. package/dist/chunk-GBRFVT63.js +0 -45
  271. package/dist/chunk-ICY36XCH.js +0 -34
  272. package/dist/chunk-J4K3KVLD.js +0 -131
  273. package/dist/chunk-JZU3H6UQ.js +0 -54
  274. package/dist/chunk-NN2ZQEB4.js +0 -38
  275. package/dist/chunk-PCOCACY3.js +0 -385
  276. package/dist/chunk-RTEYOSJY.js +0 -29
  277. package/dist/chunk-RUVFXE2L.js +0 -666
  278. package/dist/chunk-RVH5SUW5.js +0 -69
  279. package/dist/chunk-VN3DP4LQ.js +0 -43
  280. package/dist/chunk-W5BVQF44.js +0 -36
  281. package/dist/chunk-WVPJSRRJ.js +0 -52
  282. package/dist/chunk-XPTOBS2D.js +0 -48
  283. package/dist/packages/ui/dist/assets/index-B54fm9FQ.js +0 -29
  284. package/dist/packages/ui/dist/assets/index-DD_hufQz.css +0 -1
@@ -0,0 +1,1205 @@
1
+ import { createRequire as __atticusCreateRequire } from "node:module";
2
+ import { fileURLToPath as __atticusFileURLToPath } from "node:url";
3
+ var require = __atticusCreateRequire(import.meta.url);
4
+ var __atticusUrl = (p) => new URL("./" + p, import.meta.url).href;
5
+ var __atticusPath = (p) => __atticusFileURLToPath(__atticusUrl(p));
6
+ import {
7
+ safeMessage
8
+ } from "./chunk-S7FCV7S5.js";
9
+ import {
10
+ checkoutOf
11
+ } from "./chunk-2F4CYZKJ.js";
12
+ import {
13
+ AI_LINE_BY,
14
+ AnswerMatch,
15
+ FactCorrection,
16
+ HOSTS_NONE,
17
+ JOINED_BY_AI,
18
+ JOINED_BY_ANSWER,
19
+ JOINED_BY_PERSON,
20
+ Question,
21
+ QuestionError,
22
+ RULE_AFTER_CORRECTIONS,
23
+ TARGETS_STEP_ID,
24
+ aiPause,
25
+ answerByWords,
26
+ answerQuestion,
27
+ auditPrecision,
28
+ batchRelOf,
29
+ callsOfQuestion,
30
+ catalogDirOf,
31
+ checkedProposals,
32
+ correctionLine,
33
+ decideOf,
34
+ deriveMatch,
35
+ factsDirOf,
36
+ factsRelOf,
37
+ isAiBy,
38
+ linkCandidates,
39
+ linksFor,
40
+ listBatches,
41
+ listQuestions,
42
+ loadOrgPack,
43
+ matchCovers,
44
+ newBatchId,
45
+ orgPackDirOf,
46
+ pairingBar,
47
+ parseAuditFile,
48
+ parseCorrections,
49
+ parseFacts,
50
+ proposalRelOf,
51
+ questionAiProblem,
52
+ questionBar,
53
+ questionsRelOf,
54
+ readBatch,
55
+ readQuestion,
56
+ ruleKindOf,
57
+ writeBatch,
58
+ writeQuestion
59
+ } from "./chunk-Q2TECDIT.js";
60
+ import {
61
+ FileChangedError,
62
+ withSharedFileLock,
63
+ writeFileAtomic
64
+ } from "./chunk-TUULXQRW.js";
65
+
66
+ // packages/cli/dist/ai-decide.js
67
+ import { mkdir, readdir, readFile, rm, stat } from "node:fs/promises";
68
+ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
69
+ var DecideError = class extends Error {
70
+ code;
71
+ constructor(code, message) {
72
+ super(message);
73
+ this.code = code;
74
+ }
75
+ };
76
+ var inAcpSession = (env = process.env) => !!env.ATTICUS_ACP_SESSION;
77
+ var AI_RUNTIME = "copilot-acp";
78
+ async function factsOf(root, repo) {
79
+ const text = await readFile(join(factsDirOf(root), `${repo}.jsonl`), "utf8").catch(() => "");
80
+ if (!text.trim())
81
+ return [];
82
+ const r = parseFacts(text);
83
+ return r.ok ? r.facts : [];
84
+ }
85
+ var correctionsFile = (root, repo) => join(factsDirOf(root), `${repo}.corrections.jsonl`);
86
+ var correctionsRel = (root, repo) => `${factsRelOf(root)}/${repo}.corrections.jsonl`;
87
+ async function correctionsOf(root, repo) {
88
+ const text = await readFile(correctionsFile(root, repo), "utf8").catch(() => "");
89
+ return parseCorrections(text).corrections;
90
+ }
91
+ async function correctedRepos(root) {
92
+ return (await readdir(factsDirOf(root)).catch(() => [])).filter((n) => n.endsWith(".corrections.jsonl")).map((n) => n.slice(0, -".corrections.jsonl".length)).sort();
93
+ }
94
+ async function rewriteCorrections(root, repo, o) {
95
+ const file = correctionsFile(root, repo);
96
+ return withSharedFileLock(file, async () => {
97
+ const text = await readFile(file, "utf8").catch(() => "");
98
+ const eol = /\r\n/.test(text) ? "\r\n" : "\n";
99
+ const lines = text.split(/\r?\n/).filter((l, i, all) => l !== "" || i < all.length - 1);
100
+ let removed = 0;
101
+ const gone = new Set((o.remove ?? []).map((l) => l.trim()));
102
+ const kept = lines.filter((l) => {
103
+ if (l.trim() && gone.has(l.trim())) {
104
+ gone.delete(l.trim());
105
+ removed++;
106
+ return false;
107
+ }
108
+ return true;
109
+ });
110
+ const have = new Set(kept.map((l) => l.trim()));
111
+ const wanted = o.pick ? await o.pick(parseCorrections(text).corrections) : o.add ?? [];
112
+ const add = wanted.filter((l) => !have.has(l.trim()));
113
+ const out = [...kept.filter((l) => l.trim() !== ""), ...add];
114
+ if (!removed && !add.length)
115
+ return { removed: 0, added: 0, ...o.pick ? { picked: [] } : {} };
116
+ await writeFileAtomic(file, out.length ? out.join(eol) + eol : "");
117
+ return { removed, added: add.length, ...o.pick ? { picked: add } : {} };
118
+ });
119
+ }
120
+ var callLikeOf = (c) => ({
121
+ kind: "call",
122
+ id: c.fact,
123
+ cite: { file: c.target.file, line: c.target.line, value: c.target.value }
124
+ });
125
+ function standingAi(corrections) {
126
+ return corrections.filter((c) => c.ai && linksFor(callLikeOf(c), corrections)[0] === c);
127
+ }
128
+ function subjectOfCall(f) {
129
+ if (f.callType === "event-topic" || f.callType === "mq-queue")
130
+ return { topic: f.path };
131
+ if (f.path?.startsWith("/"))
132
+ return { path: f.path };
133
+ return void 0;
134
+ }
135
+ async function coversCall(match, f, facts) {
136
+ const s = subjectOfCall(f);
137
+ if (s?.topic)
138
+ return matchCovers(match, s);
139
+ const { ruleCoversCall } = await import("./chunk-IFKEI4SA.js");
140
+ return ruleCoversCall(match, f, facts, { strict: true });
141
+ }
142
+ async function answeredByPerson(root, repo, facts) {
143
+ const questions = (await listQuestions(root, { step: TARGETS_STEP_ID })).questions;
144
+ const people = questions.filter((q) => q.state === "answered" && !!q.answer && !isAiBy(q.answer.by));
145
+ if (!people.length)
146
+ return /* @__PURE__ */ new Set();
147
+ const { estateRepos, targetsFromAnswers, TARGETS_SPLIT } = await import("./chunk-IFKEI4SA.js");
148
+ const byRepo = /* @__PURE__ */ new Map([[repo, facts]]);
149
+ const out = new Set(people.filter((q) => q.repo === repo && q.options[(q.answer.option ?? 0) - 1]?.label !== TARGETS_SPLIT).flatMap((q) => callsOfQuestion(q, byRepo).map((c) => c.id)));
150
+ const op = await loadOrgPack(orgPackDirOf(root));
151
+ const repoType = estateRepos(op).find((r) => r.id === repo)?.type;
152
+ const ai = {};
153
+ const named = targetsFromAnswers(repo, facts, questions, {
154
+ ...repoType ? { repoType } : {},
155
+ ai
156
+ });
157
+ for (const id of Object.keys(named))
158
+ if (!ai[id])
159
+ out.add(id);
160
+ return out;
161
+ }
162
+ async function aiAuditItems(root) {
163
+ const out = [];
164
+ for (const n of (await readdir(factsDirOf(root)).catch(() => [])).sort()) {
165
+ if (!n.endsWith(".audit.yaml"))
166
+ continue;
167
+ const r = parseAuditFile(await readFile(join(factsDirOf(root), n), "utf8").catch(() => ""));
168
+ if (r.ok)
169
+ out.push(...r.file.items.filter((i) => i.kind === "ai"));
170
+ }
171
+ return out;
172
+ }
173
+ async function decideState(root) {
174
+ const op = await loadOrgPack(orgPackDirOf(root));
175
+ const configured = decideOf(op.runtime);
176
+ const precision = auditPrecision(await aiAuditItems(root)).ai;
177
+ return {
178
+ configured,
179
+ now: aiPause(configured, precision),
180
+ precision,
181
+ decideIn: decideIn(op.runtime)
182
+ };
183
+ }
184
+ function decideIn(rt) {
185
+ if (rt.ai === "off")
186
+ return [];
187
+ const out = [];
188
+ if (rt.modes.allowed.includes("copilot-acp") && rt.assistants.allowed.includes("copilot"))
189
+ out.push("copilot-acp");
190
+ if (rt.modes.allowed.includes("hand-off"))
191
+ out.push("hand-off");
192
+ return out;
193
+ }
194
+ var notHere = (runtime, state) => runtime === "hand-off" && !state.decideIn.includes("hand-off") ? "runtime.yaml doesn't allow hand-off here (modes.allowed): a person confirms it" : void 0;
195
+ async function pairingCitesProblem(root, repos, lines) {
196
+ if (!lines.length)
197
+ return "it names no line it rests on";
198
+ const dirs = [];
199
+ for (const r of repos) {
200
+ const d = await checkoutOf(root, r).catch(() => void 0);
201
+ if (d)
202
+ dirs.push(d);
203
+ }
204
+ if (!dirs.length)
205
+ return "no checkout of either repo is here to check its lines";
206
+ for (const l of lines) {
207
+ const m = /^(.+):(\d+)$/.exec(l);
208
+ if (!m)
209
+ return `${l} isn't a path:line`;
210
+ const rel = m[1].replace(/\\/g, "/").replace(/^\.\//, "");
211
+ if (isAbsolute(rel) || rel.split("/").includes(".."))
212
+ return `${l} leaves the repo`;
213
+ let found = false;
214
+ for (const d of dirs) {
215
+ const file = resolve(d, rel);
216
+ const back = relative(d, file);
217
+ if (!back || back.startsWith("..") || isAbsolute(back))
218
+ continue;
219
+ const ok = await stat(file).then((s) => s.isFile(), () => false);
220
+ if (!ok)
221
+ continue;
222
+ const text = (await readFile(file, "utf8").catch(() => "")).split(/\r?\n/);
223
+ if ((text[Number(m[2]) - 1] ?? "").trim())
224
+ found = true;
225
+ }
226
+ if (!found)
227
+ return `${l} isn't a line with words on it in either checkout`;
228
+ }
229
+ return void 0;
230
+ }
231
+ async function linkRulesOf(root, repo) {
232
+ return (await listBatches(root)).batches.filter((b) => b.kind === "rule" && !b.undone && !!b.correction?.rule && b.correction.item.startsWith(`link:${repo}:`)).map((b) => ({ match: b.correction.rule.match, answer: b.correction.answer, batch: b.id }));
233
+ }
234
+ async function decideLinks(root, o) {
235
+ if (inAcpSession(o.env) || !o.proposals.length)
236
+ return void 0;
237
+ const state = await decideState(root);
238
+ if (state.configured.links === "propose")
239
+ return void 0;
240
+ const runtime = o.runtime ?? AI_RUNTIME;
241
+ const kept = [];
242
+ const off = notHere(runtime, state);
243
+ if (off) {
244
+ for (const p of o.proposals)
245
+ kept.push({ call: p.call, api: p.api, why: off });
246
+ return { mode: "propose", applied: [], kept };
247
+ }
248
+ const paused = state.now.paused?.why;
249
+ if (state.now.links === "propose") {
250
+ for (const p of o.proposals)
251
+ kept.push({ call: p.call, api: p.api, why: "deciding is paused: a person confirms it" });
252
+ return { mode: "propose", applied: [], kept, ...paused ? { paused } : {} };
253
+ }
254
+ const to = o.view.to.repo;
255
+ if (!to) {
256
+ for (const p of o.proposals)
257
+ kept.push({
258
+ call: p.call,
259
+ api: p.api,
260
+ why: "the AI pairs only with a repo's entry: a pairing with an outside system is a person's"
261
+ });
262
+ return { mode: "auto", applied: [], kept };
263
+ }
264
+ const at = (o.now ?? /* @__PURE__ */ new Date()).toISOString();
265
+ const batch = newBatchId(o.now ?? /* @__PURE__ */ new Date());
266
+ const rules = await linkRulesOf(root, o.view.from);
267
+ const applied = [];
268
+ const lines = [];
269
+ const items = [];
270
+ const calls = /* @__PURE__ */ new Map();
271
+ for (const p of o.proposals) {
272
+ const call = o.view.calls.find((c) => c.fact === p.call && c.status !== "paired");
273
+ const f = o.facts.find((x) => x.id === p.call && x.kind === "call");
274
+ const api = o.view.apis.find((a) => a.id === p.api && a.kind !== "operation");
275
+ if (!call || !f || !api) {
276
+ kept.push({ call: p.call, api: p.api, why: "the call or the API isn't on record as loose" });
277
+ continue;
278
+ }
279
+ let ruleAgrees = false;
280
+ let against;
281
+ for (const r2 of rules)
282
+ if (await coversCall(r2.match, f, o.facts)) {
283
+ if (r2.answer === to)
284
+ ruleAgrees = true;
285
+ else
286
+ against = r2;
287
+ break;
288
+ }
289
+ if (against) {
290
+ kept.push({
291
+ call: p.call,
292
+ api: p.api,
293
+ why: `a person's rule (${against.match}) says these calls go to ${against.answer}`
294
+ });
295
+ continue;
296
+ }
297
+ const cites = await pairingCitesProblem(root, [o.view.from, to], p.lines);
298
+ if (cites) {
299
+ kept.push({ call: p.call, api: p.api, why: `the citation check fails: ${cites}` });
300
+ continue;
301
+ }
302
+ const bar = pairingBar(call, p.api, { ruleAgrees });
303
+ if (!bar) {
304
+ kept.push({
305
+ call: p.call,
306
+ api: p.api,
307
+ why: "the shapes don't rank that API first and no person's rule says so: a person confirms it"
308
+ });
309
+ continue;
310
+ }
311
+ const line = correctionLine(FactCorrection.parse({
312
+ schemaVersion: 2,
313
+ fact: f.id,
314
+ target: { kind: "call", file: f.cite.file, line: f.cite.line, value: f.cite.value },
315
+ action: "link",
316
+ link: {
317
+ repo: to,
318
+ entry: api.id,
319
+ ...api.method ? { method: api.method } : {},
320
+ path: api.path
321
+ },
322
+ by: AI_LINE_BY,
323
+ at,
324
+ ai: { runtime, run: o.run, bar },
325
+ batch
326
+ }));
327
+ lines.push(line);
328
+ items.push({ kind: "link", repo: o.view.from, fact: f.id, line });
329
+ applied.push({ call: p.call, api: p.api, bar });
330
+ calls.set(line, f);
331
+ }
332
+ if (!lines.length)
333
+ return { mode: "auto", applied, kept };
334
+ const answered = /* @__PURE__ */ new Set();
335
+ const r = await rewriteCorrections(root, o.view.from, {
336
+ pick: async (now) => {
337
+ const byPerson = await answeredByPerson(root, o.view.from, o.facts);
338
+ return lines.filter((l) => {
339
+ const f = calls.get(l);
340
+ if (linksFor(f, now).some((c) => !c.ai))
341
+ return false;
342
+ if (byPerson.has(f.id)) {
343
+ answered.add(l);
344
+ return false;
345
+ }
346
+ return true;
347
+ });
348
+ }
349
+ });
350
+ const written = new Set(r.picked ?? []);
351
+ for (let i = applied.length - 1; i >= 0; i--) {
352
+ if (written.has(lines[i]))
353
+ continue;
354
+ kept.push({
355
+ call: applied[i].call,
356
+ api: applied[i].api,
357
+ why: answered.has(lines[i]) ? "a person answered where this call goes (its targets question): their word stands" : "a person has said where this call goes: their word stands"
358
+ });
359
+ applied.splice(i, 1);
360
+ items.splice(i, 1);
361
+ }
362
+ if (!applied.length)
363
+ return { mode: "auto", applied, kept };
364
+ await writeBatch(root, {
365
+ schema: 1,
366
+ id: batch,
367
+ kind: "ai",
368
+ at,
369
+ by: { kind: "ai", runtime, run: o.run },
370
+ applied: items,
371
+ reverted: []
372
+ });
373
+ return { mode: "auto", batch, applied, kept };
374
+ }
375
+ async function proposalsSnapshot(root) {
376
+ const out = /* @__PURE__ */ new Map();
377
+ for (const p of await checkedProposals(root)) {
378
+ const text = await readFile(join(root, ...p.file.split("/")), "utf8").catch(() => void 0);
379
+ if (text !== void 0)
380
+ out.set(p.id, text);
381
+ }
382
+ return out;
383
+ }
384
+ async function targetRuleVerdict(root, q, label, questions) {
385
+ const facts = await factsOf(root, q.repo);
386
+ const calls = callsOfQuestion(q, /* @__PURE__ */ new Map([[q.repo, facts]]));
387
+ if (!calls.length)
388
+ return void 0;
389
+ const op = await loadOrgPack(orgPackDirOf(root));
390
+ const { estateRepos, ruledTargets } = await import("./chunk-IFKEI4SA.js");
391
+ const repoType = estateRepos(op).find((r) => r.id === q.repo)?.type;
392
+ const ruled = ruledTargets(q.repo, facts, questions, {
393
+ ...repoType ? { repoType } : {},
394
+ strict: true
395
+ });
396
+ const labels = calls.map((c) => ruled.get(c.id)?.label);
397
+ if (labels.some((l) => l !== void 0 && l !== label))
398
+ return "against";
399
+ return labels.every((l) => l === label) ? "agrees" : void 0;
400
+ }
401
+ async function personLinkVerdict(root, q, label) {
402
+ const facts = await factsOf(root, q.repo);
403
+ const calls = callsOfQuestion(q, /* @__PURE__ */ new Map([[q.repo, facts]]));
404
+ if (!calls.length)
405
+ return void 0;
406
+ const corrections = await correctionsOf(root, q.repo);
407
+ if (calls.some((c) => linksFor(c, corrections).some((l) => !l.ai)))
408
+ return "a person said where its call goes on the canvas (a pairing or none): their word stands";
409
+ const rules = await linkRulesOf(root, q.repo);
410
+ for (const c of calls)
411
+ for (const r of rules)
412
+ if (await coversCall(r.match, c, facts)) {
413
+ if (r.answer !== label)
414
+ return `a person's rule (${r.match}) says these calls go to ${r.answer}`;
415
+ break;
416
+ }
417
+ return void 0;
418
+ }
419
+ async function decideAnswers(root, o) {
420
+ if (inAcpSession(o.env))
421
+ return void 0;
422
+ const state = await decideState(root);
423
+ if (state.configured.questions === "propose")
424
+ return void 0;
425
+ const runtime = o.runtime ?? AI_RUNTIME;
426
+ const proposals = (await checkedProposals(root)).filter((p) => p.ok && p.proposal && (!o.ids || o.ids.has(p.id)));
427
+ const kept = [];
428
+ const off = notHere(runtime, state);
429
+ if (off) {
430
+ for (const p of proposals)
431
+ kept.push({ id: p.id, why: off });
432
+ return { mode: "propose", applied: [], kept };
433
+ }
434
+ if (state.now.questions === "propose") {
435
+ for (const p of proposals)
436
+ kept.push({ id: p.id, why: "deciding is paused: a person confirms it" });
437
+ return {
438
+ mode: "propose",
439
+ applied: [],
440
+ kept,
441
+ ...state.now.paused ? { paused: state.now.paused.why } : {}
442
+ };
443
+ }
444
+ const at = (o.now ?? /* @__PURE__ */ new Date()).toISOString();
445
+ const batch = newBatchId(o.now ?? /* @__PURE__ */ new Date());
446
+ const everyTarget = (await listQuestions(root, { step: TARGETS_STEP_ID })).questions;
447
+ const applied = [];
448
+ const items = [];
449
+ for (const p of proposals) {
450
+ const q = await readQuestion(root, p.id).catch(() => void 0);
451
+ const option = p.proposal.answer.option;
452
+ if (!q)
453
+ continue;
454
+ const problem = questionAiProblem(q, option);
455
+ if (problem) {
456
+ kept.push({ id: p.id, why: problem });
457
+ continue;
458
+ }
459
+ const label = q.options[option - 1].label;
460
+ const { TARGETS_NO_EVIDENCE } = await import("./chunk-IFKEI4SA.js");
461
+ const shapesFirst = option === 1 && !q.options[0].means.includes(TARGETS_NO_EVIDENCE);
462
+ const rule = await targetRuleVerdict(root, q, label, everyTarget);
463
+ if (rule === "against") {
464
+ kept.push({ id: p.id, why: "a person's rule covers its calls and says otherwise" });
465
+ continue;
466
+ }
467
+ const declined = await personLinkVerdict(root, q, label);
468
+ if (declined) {
469
+ kept.push({ id: p.id, why: declined });
470
+ continue;
471
+ }
472
+ const bar = questionBar(q, option, { shapesFirst, ruleAgrees: rule === "agrees" });
473
+ if (!bar) {
474
+ kept.push({
475
+ id: p.id,
476
+ why: "the shapes don't list that option first and no person's rule says so: a person confirms it"
477
+ });
478
+ continue;
479
+ }
480
+ const by = { kind: "ai", runtime, run: o.run, bar };
481
+ const proposalFile = join(root, ...proposalRelOf(root, q.id).split("/"));
482
+ const proposalText = await readFile(proposalFile, "utf8").catch(() => void 0);
483
+ try {
484
+ await answerQuestion(root, q.id, {
485
+ option,
486
+ by,
487
+ at,
488
+ batch,
489
+ proposal: { by: p.proposal.by, at: p.proposal.at, cites: p.proposal.cites }
490
+ });
491
+ } catch (e) {
492
+ if (e instanceof QuestionError) {
493
+ kept.push({ id: p.id, why: e.message });
494
+ continue;
495
+ }
496
+ if (e instanceof FileChangedError) {
497
+ kept.push({ id: p.id, why: "a person changed it meanwhile: theirs stands" });
498
+ continue;
499
+ }
500
+ throw e;
501
+ }
502
+ await rm(proposalFile, { force: true });
503
+ items.push({
504
+ kind: "question",
505
+ id: q.id,
506
+ ...proposalText?.trim() && proposalText.length <= 65536 ? { proposal: proposalText } : {}
507
+ });
508
+ applied.push({ id: q.id, option, bar });
509
+ }
510
+ if (items.length)
511
+ await writeBatch(root, {
512
+ schema: 1,
513
+ id: batch,
514
+ kind: "ai",
515
+ at,
516
+ by: { kind: "ai", runtime, run: o.run },
517
+ applied: items,
518
+ reverted: []
519
+ });
520
+ return { mode: "auto", ...items.length ? { batch } : {}, applied, kept };
521
+ }
522
+ async function decisionsView(root) {
523
+ const state = await decideState(root);
524
+ const linkItems = [];
525
+ const lines = { byAi: 0, byPerson: 0 };
526
+ for (const repo of await correctedRepos(root)) {
527
+ const all = await correctionsOf(root, repo);
528
+ for (const c of all)
529
+ if (c.action === "link" && c.link && linksFor(callLikeOf(c), all)[0] === c) {
530
+ if (c.ai)
531
+ lines.byAi++;
532
+ else
533
+ lines.byPerson++;
534
+ }
535
+ for (const c of standingAi(all)) {
536
+ linkItems.push({
537
+ kind: "link",
538
+ item: `link:${repo}:${c.fact}`,
539
+ repo,
540
+ what: `${repo}'s call ${c.target.value} (${c.target.file}:${c.target.line}) \u2192 ${[c.link.method, c.link.path].filter(Boolean).join(" ")} on ${c.link.repo}`,
541
+ decided: c.link.entry ?? `${c.link.method ?? ""} ${c.link.path}`.trim(),
542
+ call: { fact: c.fact, file: c.target.file, line: c.target.line, value: c.target.value },
543
+ to: {
544
+ repo: c.link.repo,
545
+ ...c.link.entry ? { entry: c.link.entry } : {},
546
+ ...c.link.method ? { method: c.link.method } : {},
547
+ path: c.link.path
548
+ },
549
+ runtime: c.ai.runtime,
550
+ run: c.ai.run,
551
+ ...c.ai.bar ? { bar: c.ai.bar } : {},
552
+ ...c.batch ? { batch: c.batch } : {},
553
+ at: c.at,
554
+ cites: [`${repo} ${c.target.file}:${c.target.line}`]
555
+ });
556
+ }
557
+ }
558
+ const qs = (await listQuestions(root)).questions;
559
+ const questionItems = [];
560
+ const qCounts = { fromCode: 0, byPerson: 0, byAi: 0, open: 0, retired: 0 };
561
+ for (const q of qs) {
562
+ if (q.state === "open")
563
+ qCounts.open++;
564
+ else if (q.state === "retired")
565
+ qCounts.retired++;
566
+ else if (q.answer && isAiBy(q.answer.by)) {
567
+ qCounts.byAi++;
568
+ const option = q.answer.option ?? 0;
569
+ questionItems.push({
570
+ kind: "question",
571
+ item: q.id,
572
+ repo: q.repo,
573
+ what: `${q.question.trim()} AI: ${q.options[option - 1]?.label ?? ""}`,
574
+ decided: q.options[option - 1]?.label ?? "",
575
+ question: { text: q.question, option, options: q.options.map((x) => x.label) },
576
+ runtime: q.answer.by.runtime,
577
+ run: q.answer.by.run,
578
+ ...q.answer.by.bar ? { bar: q.answer.by.bar } : {},
579
+ ...q.answer.batch ? { batch: q.answer.batch } : {},
580
+ at: q.answer.at,
581
+ cites: (q.answer.proposal?.cites ?? []).map((c) => `${c.repo ?? q.repo} ${c.file}:${c.line}`)
582
+ });
583
+ } else
584
+ qCounts.byPerson++;
585
+ }
586
+ const linkCounts = { fromCode: 0, byPerson: 0, byAi: 0 };
587
+ const { readCatalog } = await import("./chunk-IFKEI4SA.js");
588
+ const cat = await readCatalog(join(catalogDirOf(root), "generated")).catch(() => void 0);
589
+ for (const r of cat?.records ?? []) {
590
+ if (r.kind !== "Interface")
591
+ continue;
592
+ const flags = r.flags ?? [];
593
+ if (flags.includes(JOINED_BY_AI))
594
+ linkCounts.byAi++;
595
+ else if (flags.includes(JOINED_BY_PERSON) || flags.includes(JOINED_BY_ANSWER))
596
+ linkCounts.byPerson++;
597
+ else
598
+ linkCounts.fromCode++;
599
+ }
600
+ const { batches, problems } = await listBatches(root);
601
+ return {
602
+ decide: {
603
+ configured: state.configured,
604
+ now: { links: state.now.links, questions: state.now.questions },
605
+ ...state.now.paused ? { paused: state.now.paused } : {},
606
+ precision: state.precision,
607
+ decideIn: state.decideIn
608
+ },
609
+ links: { counts: linkCounts, items: linkItems, lines },
610
+ questions: { counts: qCounts, items: questionItems },
611
+ batches: batches.map((b) => batchView(root, b)),
612
+ problems
613
+ };
614
+ }
615
+ function batchView(root, b) {
616
+ return {
617
+ id: b.id,
618
+ kind: b.kind,
619
+ at: b.at,
620
+ by: answerByWords(b.by),
621
+ ...isAiBy(b.by) ? { run: b.by.run } : b.correction?.run ? { run: b.correction.run } : {},
622
+ applied: b.applied.length,
623
+ reverted: b.reverted.length,
624
+ ...b.correction ? {
625
+ correction: {
626
+ item: b.correction.item,
627
+ answer: b.correction.answer,
628
+ ...b.correction.rule ? {
629
+ rule: {
630
+ kind: b.correction.rule.kind,
631
+ match: b.correction.rule.match,
632
+ from: b.correction.rule.from
633
+ }
634
+ } : {}
635
+ }
636
+ } : {},
637
+ ...b.undone ? { undone: b.undone } : {},
638
+ file: batchRelOf(root, b.id)
639
+ };
640
+ }
641
+ var counted = (spread) => ({
642
+ applied: spread.filter((s) => s.change === "applied").length,
643
+ confirmed: spread.filter((s) => s.change === "confirmed").length,
644
+ replaced: spread.filter((s) => s.change === "replaced").length,
645
+ reverted: spread.filter((s) => s.change === "reverted").length
646
+ });
647
+ async function shapeCount(root, shape) {
648
+ return (await listBatches(root)).batches.filter((b) => b.kind === "rule" && !b.undone && b.correction?.shape === shape).length + 1;
649
+ }
650
+ async function correctDecision(root, req, o) {
651
+ if (inAcpSession(o.env))
652
+ throw new DecideError("refused", "A correction is a person's: a Copilot session acts as no one (ADR 0171, round 32).");
653
+ return req.item.startsWith("link:") ? correctLink(root, req, o) : correctQuestion(root, req, o);
654
+ }
655
+ async function correctQuestion(root, req, o) {
656
+ const q = await readQuestion(root, req.item).catch(() => void 0);
657
+ if (!q)
658
+ throw new DecideError("not-found", `There is no question ${req.item}.`);
659
+ if (!q.answer || !isAiBy(q.answer.by))
660
+ throw new DecideError("conflict", `${q.id} isn't an AI decision: answer it as usual (atticus questions answer ${q.id}).`);
661
+ const aiBy = q.answer.by;
662
+ const option = req.none ? q.options.findIndex((x) => x.label === HOSTS_NONE) + 1 : req.option ?? 0;
663
+ if (!option || option > q.options.length)
664
+ throw new DecideError("bad", req.none ? `${q.id} has no "None of these" option: pick one of its ${q.options.length} options.` : `Pick one of ${q.id}'s ${q.options.length} options (from 1), or none.`);
665
+ const label = q.options[option - 1].label;
666
+ const aiLabel = q.options[(q.answer.option ?? 0) - 1]?.label ?? "";
667
+ const facts = await factsOf(root, q.repo);
668
+ const byRepo = /* @__PURE__ */ new Map([[q.repo, facts]]);
669
+ const calls = callsOfQuestion(q, byRepo);
670
+ const everyTarget = (await listQuestions(root, { step: TARGETS_STEP_ID })).questions;
671
+ const similar = req.similar !== false;
672
+ let rule;
673
+ let noRule;
674
+ if (similar) {
675
+ if (req.match) {
676
+ if (!AnswerMatch.safeParse(req.match).success || ruleKindOf(req.match) === "topic")
677
+ throw new DecideError("bad", `${req.match} isn't a rule a targets answer takes: a path prefix (/forge/limits/**) or a host pattern (*.payments.forge.internal).`);
678
+ rule = { kind: ruleKindOf(req.match), match: req.match, derived: false };
679
+ } else {
680
+ const subject = calls.map((c) => subjectOfCall(c)).find((s) => s?.path);
681
+ const siblings = everyTarget.filter((x) => x.id !== q.id && x.repo === q.repo && x.state === "answered" && x.answer && isAiBy(x.answer.by) && x.options[(x.answer.option ?? 0) - 1]?.label === aiLabel).flatMap((x) => callsOfQuestion(x, byRepo)).map((c) => subjectOfCall(c)).filter((s) => !!s?.path);
682
+ if (!subject)
683
+ noRule = "its calls have no path a rule can name: give one with match";
684
+ else {
685
+ const d = deriveMatch(subject, siblings);
686
+ if (d.match === "/**")
687
+ noRule = "the calls share no path narrower than every path: give a rule with match, or correct it alone";
688
+ else if (!AnswerMatch.safeParse(d.match).success)
689
+ noRule = `${d.match} isn't a rule a targets answer takes: give one with match`;
690
+ else
691
+ rule = { ...d, derived: true };
692
+ }
693
+ }
694
+ }
695
+ const at = (o.now ?? /* @__PURE__ */ new Date()).toISOString();
696
+ const batch = newBatchId(o.now ?? /* @__PURE__ */ new Date());
697
+ const plans = [];
698
+ if (rule) {
699
+ for (const x of everyTarget) {
700
+ if (x.id === q.id || x.repo !== q.repo || x.scope.level !== "repo")
701
+ continue;
702
+ const ai = x.state === "answered" && x.answer && isAiBy(x.answer.by);
703
+ if (x.state !== "open" && !ai)
704
+ continue;
705
+ const xc = callsOfQuestion(x, byRepo);
706
+ if (!xc.length)
707
+ continue;
708
+ let all = true;
709
+ for (const c of xc)
710
+ if (!await coversCall(rule.match, c, facts))
711
+ all = false;
712
+ if (!all)
713
+ continue;
714
+ const idx = x.options.findIndex((y) => y.label === label);
715
+ const was = ai ? x.options[(x.answer.option ?? 0) - 1]?.label : void 0;
716
+ const what = x.question.trim();
717
+ if (idx >= 0) {
718
+ const change = !ai ? "applied" : was === label ? "confirmed" : "replaced";
719
+ plans.push({
720
+ view: {
721
+ item: x.id,
722
+ repo: x.repo,
723
+ what,
724
+ ...was ? { was } : {},
725
+ now: label,
726
+ change
727
+ },
728
+ applied: { kind: "question", id: x.id, ...x.answer ? { before: x.answer } : {} },
729
+ write: async () => {
730
+ await answerQuestion(root, x.id, {
731
+ option: idx + 1,
732
+ by: o.by,
733
+ at,
734
+ batch,
735
+ rule: { from: q.id, match: rule.match }
736
+ });
737
+ }
738
+ });
739
+ } else if (ai)
740
+ plans.push({
741
+ view: { item: x.id, repo: x.repo, what, ...was ? { was } : {}, change: "reverted" },
742
+ reverted: { kind: "question", id: x.id, before: x.answer },
743
+ write: async () => {
744
+ const { answer: _a, ...rest } = x;
745
+ await writeQuestion(root, Question.parse({ ...rest, state: "open" }));
746
+ }
747
+ });
748
+ }
749
+ }
750
+ const spread = plans.map((p) => p.view);
751
+ const op = await loadOrgPack(orgPackDirOf(root));
752
+ const { estateRepos } = await import("./chunk-IFKEI4SA.js");
753
+ const repoType = estateRepos(op).find((r) => r.id === q.repo)?.type;
754
+ const shape = `question:${repoType ?? q.repo}:${rule?.match ?? calls[0]?.path ?? q.id}`;
755
+ const n = await shapeCount(root, shape);
756
+ const files = [`${questionsRelOf(root)}/`, ...req.preview ? [] : [batchRelOf(root, batch)]];
757
+ const result = {
758
+ written: !req.preview,
759
+ ...req.preview ? {} : { batch },
760
+ item: q.id,
761
+ answer: label,
762
+ ...rule ? { rule } : {},
763
+ ...similar && !rule && noRule ? { noRule } : {},
764
+ spread,
765
+ counts: counted(spread),
766
+ ...n >= RULE_AFTER_CORRECTIONS && repoType ? {
767
+ makeRule: {
768
+ corrections: n,
769
+ shape,
770
+ repo: q.repo,
771
+ command: `atticus rules draft --repo ${q.repo} --about "calls under ${rule?.match ?? calls[0]?.path ?? "these paths"} go to ${label}"`
772
+ }
773
+ } : {},
774
+ files: [...new Set(files)],
775
+ verify: [`atticus verify ${q.repo} --write`],
776
+ commit: `git add ${questionsRelOf(root)}/ ${batchRelOf(root, batch).replace(/\/[^/]+$/, "/")}
777
+ git commit -m "${safeMessage(`${q.repo}: an AI answer corrected${rule ? `, and spread by ${rule.match}` : ""}`)}"`
778
+ };
779
+ if (req.preview)
780
+ return result;
781
+ const before = q.answer;
782
+ try {
783
+ await answerQuestion(root, q.id, {
784
+ option,
785
+ by: o.by,
786
+ at,
787
+ batch,
788
+ ...rule ? { match: rule.match } : {}
789
+ });
790
+ } catch (e) {
791
+ if (e instanceof QuestionError)
792
+ throw new DecideError("bad", e.message);
793
+ throw e;
794
+ }
795
+ for (const p of plans)
796
+ await p.write();
797
+ await writeBatch(root, {
798
+ schema: 1,
799
+ id: batch,
800
+ kind: "rule",
801
+ at,
802
+ by: o.by,
803
+ correction: {
804
+ item: q.id,
805
+ answer: label,
806
+ ...rule ? { rule: { from: q.id, match: rule.match, kind: rule.kind } } : {},
807
+ run: aiBy.run,
808
+ shape
809
+ },
810
+ applied: [
811
+ { kind: "question", id: q.id, before },
812
+ ...plans.flatMap((p) => p.applied ? [p.applied] : [])
813
+ ],
814
+ reverted: plans.flatMap((p) => p.reverted ? [p.reverted] : [])
815
+ });
816
+ return result;
817
+ }
818
+ function parseLinkItem(item) {
819
+ const m = /^link:([A-Za-z0-9._-]{1,200}):(.+)$/.exec(item);
820
+ if (!m)
821
+ throw new DecideError("bad", `${item} isn't link:<repo>:<call fact id> or a question id.`);
822
+ return { repo: m[1], fact: m[2] };
823
+ }
824
+ async function correctLink(root, req, o) {
825
+ const { repo, fact } = parseLinkItem(req.item);
826
+ const facts = await factsOf(root, repo);
827
+ const f = facts.find((x) => x.id === fact && x.kind === "call");
828
+ if (!f)
829
+ throw new DecideError("not-found", `${repo} has no call ${fact} on record.`);
830
+ const corrections = await correctionsOf(root, repo);
831
+ const standing = linksFor(f, corrections)[0];
832
+ if (!standing?.ai || !standing.link?.repo)
833
+ throw new DecideError("conflict", `${repo}'s call ${fact} isn't paired by AI: correct it on the canvas (Connect to\u2026) as usual.`);
834
+ const aiRepo = standing.link.repo;
835
+ const none = req.none === true;
836
+ if (!none && (!req.api || !req.repo))
837
+ throw new DecideError("bad", "Say the right API and its repo ({ api, repo }), or none.");
838
+ const target = none ? void 0 : req.repo;
839
+ let entry;
840
+ if (target) {
841
+ entry = (await factsOf(root, target)).find((x) => x.id === req.api && x.kind === "entry");
842
+ if (!entry)
843
+ throw new DecideError("not-found", `${target} has no API ${req.api} on record.`);
844
+ }
845
+ const answer = target ?? "none";
846
+ const similar = req.similar !== false;
847
+ let rule;
848
+ let noRule;
849
+ const standingAll = standingAi(corrections);
850
+ if (similar) {
851
+ if (req.match)
852
+ rule = { kind: ruleKindOf(req.match, subjectOfCall(f)), match: req.match, derived: false };
853
+ else {
854
+ const subject = subjectOfCall(f);
855
+ const siblings = standingAll.filter((c) => c !== standing && c.link?.repo === aiRepo).map((c) => facts.find((x) => x.id === c.fact && x.kind === "call")).flatMap((x) => x ? [subjectOfCall(x)] : []).filter((s) => !!s);
856
+ if (!subject)
857
+ noRule = "the call's path is a name, not a path a rule can name: give one with match";
858
+ else {
859
+ const d = deriveMatch(subject, siblings);
860
+ if (d.match === "/**")
861
+ noRule = "the calls share no path narrower than every path: give a rule with match, or correct it alone";
862
+ else
863
+ rule = { ...d, derived: true };
864
+ }
865
+ }
866
+ }
867
+ const at = (o.now ?? /* @__PURE__ */ new Date()).toISOString();
868
+ const batch = newBatchId(o.now ?? /* @__PURE__ */ new Date());
869
+ const lineFor = (c, api, own) => correctionLine(FactCorrection.parse({
870
+ schemaVersion: 2,
871
+ fact: c.id,
872
+ target: { kind: "call", file: c.cite.file, line: c.cite.line, value: c.cite.value },
873
+ action: api ? "link" : "unlink",
874
+ ...api ? {
875
+ link: {
876
+ repo: target,
877
+ entry: api.id,
878
+ ...api.method ? { method: api.method.toUpperCase() } : {},
879
+ path: api.path
880
+ }
881
+ } : {},
882
+ by: o.by,
883
+ at,
884
+ batch,
885
+ ...own && rule ? { match: rule.match } : {},
886
+ ...!own && rule ? { rule: { from: req.item, match: rule.match } } : {}
887
+ }));
888
+ const ownLine = lineFor(f, entry ? { id: entry.id, ...entry.method ? { method: entry.method } : {}, path: entry.path } : void 0, true);
889
+ const spread = [];
890
+ const add = [ownLine];
891
+ const remove = [];
892
+ const appliedItems = [{ kind: "link", repo, fact: f.id, line: ownLine }];
893
+ const revertedItems = [];
894
+ if (rule) {
895
+ const { candidatesOf, settingsOf } = await import("./chunk-KN5BXMWN.js");
896
+ const box = { repo: target ?? aiRepo };
897
+ const cands = box.repo !== repo ? await candidatesOf(root, repo, box).catch(() => void 0) : void 0;
898
+ const loose = new Set((cands?.view.calls ?? []).filter((c) => c.status !== "paired").map((c) => c.fact));
899
+ const apis = (cands?.view.apis ?? []).filter((a) => a.kind !== "operation");
900
+ const settings = settingsOf(facts);
901
+ const bestOf = (c) => {
902
+ if (!target || !apis.length)
903
+ return void 0;
904
+ const s = linkCandidates({
905
+ from: repo,
906
+ facts: [c],
907
+ join: { joins: [], asks: [], misses: [], outside: [], left: [] },
908
+ apis,
909
+ pairs: {},
910
+ to: { repo: target },
911
+ settings
912
+ }).calls[0]?.suggestion?.api;
913
+ return s ? apis.find((a) => a.id === s) : void 0;
914
+ };
915
+ const words = (c) => `${repo}'s call ${[c.method?.toUpperCase(), c.path].filter(Boolean).join(" ")} (${c.cite.file}:${c.cite.line})`;
916
+ const byPerson = await answeredByPerson(root, repo, facts);
917
+ for (const c of facts) {
918
+ if (c.kind !== "call" || c.id === f.id)
919
+ continue;
920
+ if (!await coversCall(rule.match, c, facts))
921
+ continue;
922
+ const st = linksFor(c, corrections)[0];
923
+ if (st && !st.ai)
924
+ continue;
925
+ if (byPerson.has(c.id))
926
+ continue;
927
+ const item = `link:${repo}:${c.id}`;
928
+ const was = st?.ai ? `${st.link.repo} ${[st.link.method, st.link.path].filter(Boolean).join(" ")}` : void 0;
929
+ if (!st && !loose.has(c.id))
930
+ continue;
931
+ if (!target) {
932
+ const l = lineFor(c);
933
+ add.push(l);
934
+ appliedItems.push({ kind: "link", repo, fact: c.id, line: l });
935
+ spread.push({
936
+ item,
937
+ repo,
938
+ what: words(c),
939
+ ...was ? { was } : {},
940
+ now: "none",
941
+ change: st ? "replaced" : "applied"
942
+ });
943
+ continue;
944
+ }
945
+ const same = st?.ai && st.link?.repo === target;
946
+ const api = same ? {
947
+ id: st.link.entry ?? "",
948
+ ...st.link.method ? { method: st.link.method } : {},
949
+ path: st.link.path
950
+ } : bestOf(c);
951
+ if (api && api.id) {
952
+ const l = lineFor(c, api);
953
+ add.push(l);
954
+ appliedItems.push({ kind: "link", repo, fact: c.id, line: l });
955
+ spread.push({
956
+ item,
957
+ repo,
958
+ what: words(c),
959
+ ...was ? { was } : {},
960
+ now: `${target} ${[api.method, api.path].filter(Boolean).join(" ")}`,
961
+ change: !st ? "applied" : same ? "confirmed" : "replaced"
962
+ });
963
+ } else if (st?.ai) {
964
+ const l = correctionLine(st);
965
+ remove.push(l);
966
+ revertedItems.push({ kind: "link", repo, fact: c.id, line: l });
967
+ spread.push({ item, repo, what: words(c), ...was ? { was } : {}, change: "reverted" });
968
+ }
969
+ }
970
+ }
971
+ const op = await loadOrgPack(orgPackDirOf(root));
972
+ const { estateRepos } = await import("./chunk-IFKEI4SA.js");
973
+ const repoType = estateRepos(op).find((r) => r.id === repo)?.type;
974
+ const shape = `link:${repoType ?? repo}:${rule?.match ?? f.path}`;
975
+ const n = await shapeCount(root, shape);
976
+ const rel = correctionsRel(root, repo);
977
+ const result = {
978
+ written: !req.preview,
979
+ ...req.preview ? {} : { batch },
980
+ item: req.item,
981
+ answer: entry ? `${target} ${[entry.method?.toUpperCase(), entry.path].filter(Boolean).join(" ")}` : "none",
982
+ ...rule ? { rule } : {},
983
+ ...similar && !rule && noRule ? { noRule } : {},
984
+ spread,
985
+ counts: counted(spread),
986
+ ...n >= RULE_AFTER_CORRECTIONS && repoType && entry ? { makeRule: { corrections: n, shape, repo, line: ownLine } } : {},
987
+ files: [rel, ...req.preview ? [] : [batchRelOf(root, batch)]],
988
+ verify: [`atticus verify ${repo} --write`],
989
+ commit: `git add ${rel} ${batchRelOf(root, batch).replace(/\/[^/]+$/, "/")}
990
+ git commit -m "${safeMessage(`${repo}: an AI pairing corrected${rule ? `, and spread by ${rule.match}` : ""}`)}"`
991
+ };
992
+ if (req.preview)
993
+ return result;
994
+ await rewriteCorrections(root, repo, { remove, add });
995
+ await writeBatch(root, {
996
+ schema: 1,
997
+ id: batch,
998
+ kind: "rule",
999
+ at,
1000
+ by: o.by,
1001
+ correction: {
1002
+ item: req.item,
1003
+ answer,
1004
+ ...rule ? { rule: { from: req.item, match: rule.match, kind: rule.kind } } : {},
1005
+ run: standing.ai.run,
1006
+ shape
1007
+ },
1008
+ applied: appliedItems,
1009
+ reverted: revertedItems
1010
+ });
1011
+ return result;
1012
+ }
1013
+ async function batchStands(root, b) {
1014
+ for (const i of b.applied) {
1015
+ if (i.kind === "question") {
1016
+ const q = await readQuestion(root, i.id).catch(() => void 0);
1017
+ if (q?.answer?.batch === b.id)
1018
+ return true;
1019
+ } else {
1020
+ const text = await readFile(correctionsFile(root, i.repo), "utf8").catch(() => "");
1021
+ if (text.split(/\r?\n/).some((l) => l.trim() === i.line.trim()))
1022
+ return true;
1023
+ }
1024
+ }
1025
+ return false;
1026
+ }
1027
+ async function restoreProposal(root, q, text) {
1028
+ const rel = proposalRelOf(root, q.id);
1029
+ const file = join(root, ...rel.split("/"));
1030
+ if (await stat(file).then(() => true, () => false))
1031
+ return void 0;
1032
+ let out = text;
1033
+ const p = q.answer?.proposal;
1034
+ if (!out && p && q.answer?.option && p.cites.length) {
1035
+ const { stringify } = await import("./chunk-H4VO6WG3.js");
1036
+ out = stringify({
1037
+ schemaVersion: 1,
1038
+ answer: { option: q.answer.option },
1039
+ why: `Put back on Undo of the AI's answer: ${p.by} proposed it, citing the lines below.`,
1040
+ cites: p.cites,
1041
+ by: p.by,
1042
+ at: p.at
1043
+ });
1044
+ }
1045
+ if (!out)
1046
+ return void 0;
1047
+ await mkdir(dirname(file), { recursive: true });
1048
+ await writeFileAtomic(file, out);
1049
+ return rel.replace(/[^/]+$/, "");
1050
+ }
1051
+ async function undoBatch(root, id, o) {
1052
+ if (inAcpSession(o.env))
1053
+ throw new DecideError("refused", "Undo is a person's: a Copilot session acts as no one.");
1054
+ const b = await readBatch(root, id);
1055
+ if (!b)
1056
+ throw new DecideError("not-found", `There is no batch ${id}.`);
1057
+ if (b.undone)
1058
+ throw new DecideError("conflict", `${id} was undone by ${b.undone.by} on ${b.undone.at.slice(0, 10)}.`);
1059
+ let removed = 0;
1060
+ let restored = 0;
1061
+ const skipped = [];
1062
+ const files = /* @__PURE__ */ new Set();
1063
+ const repos = /* @__PURE__ */ new Set();
1064
+ const byRepo = /* @__PURE__ */ new Map();
1065
+ const of = (r) => {
1066
+ const x = byRepo.get(r) ?? { remove: [], add: [] };
1067
+ byRepo.set(r, x);
1068
+ return x;
1069
+ };
1070
+ const undoneBatches = /* @__PURE__ */ new Map();
1071
+ const isUndone = async (batch) => {
1072
+ if (!batch || batch === b.id)
1073
+ return false;
1074
+ if (!undoneBatches.has(batch))
1075
+ undoneBatches.set(batch, !!(await readBatch(root, batch).catch(() => void 0))?.undone);
1076
+ return undoneBatches.get(batch);
1077
+ };
1078
+ const batchOfLine = (line) => {
1079
+ try {
1080
+ return JSON.parse(line).batch;
1081
+ } catch {
1082
+ return void 0;
1083
+ }
1084
+ };
1085
+ const stands = await batchStands(root, b);
1086
+ if (!stands)
1087
+ throw new DecideError("conflict", `Nothing of ${id} stands now: each of its lines and answers was changed since, so there is nothing to undo.`);
1088
+ for (const i of b.applied)
1089
+ if (i.kind === "link")
1090
+ of(i.repo).remove.push(i.line);
1091
+ for (const i of b.reverted)
1092
+ if (i.kind === "link") {
1093
+ if (await isUndone(batchOfLine(i.line))) {
1094
+ skipped.push(`a line of an undone batch in ${correctionsRel(root, i.repo)}: not put back`);
1095
+ continue;
1096
+ }
1097
+ of(i.repo).add.push(i.line);
1098
+ }
1099
+ for (const [repo, x] of byRepo) {
1100
+ const r = await rewriteCorrections(root, repo, x);
1101
+ removed += r.removed;
1102
+ restored += r.added;
1103
+ if (r.removed < x.remove.length)
1104
+ skipped.push(`${x.remove.length - r.removed} of its lines in ${correctionsRel(root, repo)} were gone already`);
1105
+ files.add(correctionsRel(root, repo));
1106
+ repos.add(repo);
1107
+ }
1108
+ for (const i of [...b.applied].reverse()) {
1109
+ if (i.kind !== "question")
1110
+ continue;
1111
+ const q = await readQuestion(root, i.id).catch(() => void 0);
1112
+ if (!q || q.answer?.batch !== b.id) {
1113
+ skipped.push(`${i.id} was answered again since: left as it is`);
1114
+ continue;
1115
+ }
1116
+ if (b.kind === "ai" && isAiBy(q.answer.by)) {
1117
+ const restoredProposal = await restoreProposal(root, q, i.proposal);
1118
+ if (restoredProposal)
1119
+ files.add(restoredProposal);
1120
+ }
1121
+ const { answer: _a, ...rest } = q;
1122
+ const before = i.before && !await isUndone(i.before.batch) ? i.before : void 0;
1123
+ if (i.before && !before)
1124
+ skipped.push(`${i.id}: its earlier answer was an undone batch's, so it is open`);
1125
+ await writeQuestion(root, Question.parse(before ? { ...rest, state: "answered", answer: before } : { ...rest, state: "open" }));
1126
+ removed++;
1127
+ repos.add(q.repo);
1128
+ }
1129
+ for (const i of b.reverted) {
1130
+ if (i.kind !== "question" || !i.before)
1131
+ continue;
1132
+ const q = await readQuestion(root, i.id).catch(() => void 0);
1133
+ if (!q || q.state !== "open") {
1134
+ skipped.push(`${i.id} was answered since: the AI's answer isn't put back`);
1135
+ continue;
1136
+ }
1137
+ if (await isUndone(i.before.batch)) {
1138
+ skipped.push(`${i.id}: the AI's answer was an undone batch's, so it stays open`);
1139
+ continue;
1140
+ }
1141
+ await writeQuestion(root, Question.parse({ ...q, state: "answered", answer: i.before }));
1142
+ restored++;
1143
+ repos.add(q.repo);
1144
+ }
1145
+ if (b.applied.some((i) => i.kind === "question") || b.reverted.some((i) => i.kind === "question"))
1146
+ files.add(`${questionsRelOf(root)}/`);
1147
+ const at = (o.now ?? /* @__PURE__ */ new Date()).toISOString();
1148
+ const file = await writeBatch(root, { ...b, undone: { by: o.by, at } });
1149
+ files.add(file);
1150
+ return {
1151
+ batch: b.id,
1152
+ removed,
1153
+ restored,
1154
+ skipped,
1155
+ files: [...files],
1156
+ verify: [...repos].sort().map((r) => `atticus verify ${r} --write`),
1157
+ commit: `git add ${[...files].join(" ")}
1158
+ git commit -m "${safeMessage(`Undo ${b.id}`)}"`
1159
+ };
1160
+ }
1161
+ async function aiAuditCandidates(root, repo) {
1162
+ const out = [];
1163
+ for (const c of standingAi(await correctionsOf(root, repo)))
1164
+ out.push({
1165
+ id: `ai:link:${c.fact}`,
1166
+ kind: "ai",
1167
+ of: "link",
1168
+ claim: `AI paired ${c.target.value} with ${[c.link.method, c.link.path].filter(Boolean).join(" ")} on ${c.link.repo}`,
1169
+ cites: [`${repo} ${c.target.file}:${c.target.line}`],
1170
+ fact: c.fact,
1171
+ to: c.link.repo,
1172
+ decided: c.link.entry ?? c.link.path,
1173
+ run: c.ai.run
1174
+ });
1175
+ for (const q of (await listQuestions(root, { state: "answered" })).questions) {
1176
+ if (q.repo !== repo || !q.answer || !isAiBy(q.answer.by))
1177
+ continue;
1178
+ const label = q.options[(q.answer.option ?? 0) - 1]?.label ?? "";
1179
+ const cites = (q.answer.proposal?.cites ?? []).map((c) => `${c.repo ?? q.repo} ${c.file}:${c.line}`);
1180
+ out.push({
1181
+ id: `ai:question:${q.id}`,
1182
+ kind: "ai",
1183
+ of: "question",
1184
+ claim: `AI answered "${q.question.trim()}" with ${label}`,
1185
+ cites: cites.length ? cites : q.evidence.map((e) => `${q.repo} ${e}`),
1186
+ decided: label,
1187
+ run: q.answer.by.run
1188
+ });
1189
+ }
1190
+ return out;
1191
+ }
1192
+
1193
+ export {
1194
+ DecideError,
1195
+ inAcpSession,
1196
+ decideState,
1197
+ decideIn,
1198
+ decideLinks,
1199
+ proposalsSnapshot,
1200
+ decideAnswers,
1201
+ decisionsView,
1202
+ correctDecision,
1203
+ undoBatch,
1204
+ aiAuditCandidates
1205
+ };