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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/dist/bin.js +8 -4
  2. package/dist/chunk-265LWMOA.js +91 -0
  3. package/dist/chunk-26WBY34Y.js +37 -0
  4. package/dist/{chunk-UBBC2XSG.js → chunk-26Z7OGQW.js} +518 -93
  5. package/dist/chunk-2D7PWSOK.js +172 -0
  6. package/dist/{chunk-JCZIKA4C.js → chunk-2HH3UCZM.js} +4 -4
  7. package/dist/{chunk-GDLULHTC.js → chunk-2HTEMYTB.js} +12 -26
  8. package/dist/chunk-2UCRFXFZ.js +130 -0
  9. package/dist/{chunk-MVZVGYXH.js → chunk-2V2ZPQQU.js} +81 -13
  10. package/dist/{chunk-BOHJZTEQ.js → chunk-36RY7ZXM.js} +130 -71
  11. package/dist/{chunk-I3E7CX4H.js → chunk-37WE3LS2.js} +3 -3
  12. package/dist/{chunk-IPKHE5D6.js → chunk-3AQ2R5NL.js} +1520 -871
  13. package/dist/chunk-3G6S7LAA.js +43 -0
  14. package/dist/chunk-3J5I7ZOU.js +58 -0
  15. package/dist/{chunk-65NYPGRC.js → chunk-3LZ6P5EP.js} +1 -1
  16. package/dist/chunk-3SSTNB4E.js +191 -0
  17. package/dist/chunk-3TD6S4TC.js +49 -0
  18. package/dist/{chunk-3C7EYRFZ.js → chunk-3UTYPHN3.js} +1 -1
  19. package/dist/{chunk-G2B4ZQGH.js → chunk-3WON4G3M.js} +2 -2
  20. package/dist/{chunk-S3QNRWYR.js → chunk-42EPP7OB.js} +12 -12
  21. package/dist/chunk-455SYIIE.js +113 -0
  22. package/dist/{chunk-YISXLPHN.js → chunk-4B6BT75O.js} +166 -23
  23. package/dist/{chunk-C6EKFH7J.js → chunk-4CLK2RJO.js} +7 -7
  24. package/dist/chunk-4CYTJ5TZ.js +38 -0
  25. package/dist/{chunk-EYWIDJFU.js → chunk-4D62IZII.js} +5 -5
  26. package/dist/chunk-4FOAYLI4.js +328 -0
  27. package/dist/{chunk-7JUKDRSZ.js → chunk-4KNOJC6J.js} +294 -215
  28. package/dist/{chunk-YMZ3TNYB.js → chunk-4PYC2UGC.js} +2 -2
  29. package/dist/{chunk-27NKUS3X.js → chunk-4SLBCEPD.js} +2104 -726
  30. package/dist/chunk-4TKVU2I2.js +122 -0
  31. package/dist/{chunk-RUVFXE2L.js → chunk-4WXRPQDE.js} +448 -47
  32. package/dist/{chunk-7ZUIMTOU.js → chunk-5CMPVC3N.js} +24 -24
  33. package/dist/chunk-5G7ILBUG.js +66 -0
  34. package/dist/{chunk-HFQCFSJR.js → chunk-5PV7S2ZP.js} +3 -3
  35. package/dist/{chunk-FITWGOJ2.js → chunk-5QUOPNLN.js} +4 -4
  36. package/dist/{chunk-Z6LF7HQN.js → chunk-5TDRBOAV.js} +5 -5
  37. package/dist/{chunk-T6AIP7H5.js → chunk-5WERBKLE.js} +199 -63
  38. package/dist/{chunk-XPCM366L.js → chunk-62DLJSLV.js} +8 -8
  39. package/dist/{chunk-L24C55VN.js → chunk-64AADMTW.js} +99 -25
  40. package/dist/{chunk-K65BJIMT.js → chunk-67BP7HXL.js} +17 -17
  41. package/dist/chunk-6DQYZU2W.js +379 -0
  42. package/dist/{chunk-EDS2L2LD.js → chunk-6EXDI5GI.js} +52 -26
  43. package/dist/chunk-6FNAKCET.js +38 -0
  44. package/dist/{chunk-6IU67AEK.js → chunk-75ASLHBT.js} +21 -15
  45. package/dist/{chunk-A3GY6SOA.js → chunk-75ZOZFGH.js} +18 -18
  46. package/dist/{chunk-MGYZM27B.js → chunk-77O633L5.js} +49 -23
  47. package/dist/{chunk-GQ4N4WKF.js → chunk-7AB6OWTV.js} +3 -3
  48. package/dist/{chunk-M766ZJ6W.js → chunk-7CZHUZBL.js} +25 -25
  49. package/dist/{chunk-A7UPUQFY.js → chunk-7FHNFCHK.js} +643 -124
  50. package/dist/chunk-7FUIVIBG.js +415 -0
  51. package/dist/{chunk-6QSERWXH.js → chunk-7QPCGTPS.js} +21 -21
  52. package/dist/{chunk-LR3R6Z2A.js → chunk-A2G72UI4.js} +7 -7
  53. package/dist/{chunk-I4JRCD6M.js → chunk-AE4P57KK.js} +23 -17
  54. package/dist/{chunk-AVJDSJ2F.js → chunk-AHW3RY3X.js} +7 -7
  55. package/dist/chunk-AM6FP6JW.js +43 -0
  56. package/dist/{chunk-CSZ4C5N6.js → chunk-AOCWFA7T.js} +93 -10
  57. package/dist/{chunk-EPTBZ3GP.js → chunk-API5TOUB.js} +1 -1
  58. package/dist/{chunk-652QWTLZ.js → chunk-AZDITBCT.js} +3 -3
  59. package/dist/{chunk-DPUYDDQG.js → chunk-BA2HUMDN.js} +25 -3
  60. package/dist/chunk-BA3U7ALS.js +99 -0
  61. package/dist/{chunk-HVUPKCGJ.js → chunk-BC6KKZ67.js} +5 -5
  62. package/dist/{chunk-CKSITVS4.js → chunk-BEPCKDCP.js} +2554 -722
  63. package/dist/{chunk-3ALD2W2A.js → chunk-BPPU3PW7.js} +4 -4
  64. package/dist/{chunk-QRAOANID.js → chunk-BVWWPBKD.js} +21 -21
  65. package/dist/{chunk-ZDPAS56H.js → chunk-BXBCMGIQ.js} +7 -1
  66. package/dist/chunk-BXZ4PKIT.js +233 -0
  67. package/dist/chunk-C7CEK3KW.js +247 -0
  68. package/dist/chunk-CFH3QH26.js +29 -0
  69. package/dist/chunk-CG6CULP6.js +170 -0
  70. package/dist/chunk-CLD4RVTA.js +45 -0
  71. package/dist/{chunk-DKJA76CJ.js → chunk-CNPY4NTZ.js} +13 -13
  72. package/dist/chunk-CNU5Q2D5.js +575 -0
  73. package/dist/{chunk-T2UYZSCQ.js → chunk-COYN3UAN.js} +126 -23
  74. package/dist/{chunk-23W7VWKR.js → chunk-CPK7QSBG.js} +1360 -113
  75. package/dist/{chunk-4AK7IBVP.js → chunk-D2WSW4GU.js} +1 -1
  76. package/dist/{chunk-ABWHYWNI.js → chunk-D57MFJPP.js} +3 -3
  77. package/dist/chunk-D5KV5PSK.js +45 -0
  78. package/dist/chunk-D5MASS4I.js +48 -0
  79. package/dist/{chunk-7EOBHUMC.js → chunk-DCWN3HFV.js} +2 -2
  80. package/dist/{chunk-QSXK2RGH.js → chunk-DDJPM5YX.js} +2 -2
  81. package/dist/chunk-DN4A2Q2O.js +57 -0
  82. package/dist/{chunk-IHMLFRVV.js → chunk-DUPZPDCJ.js} +58 -16
  83. package/dist/{chunk-PRPPGYZG.js → chunk-E2VXBSIR.js} +4 -4
  84. package/dist/chunk-E57AOFYN.js +32 -0
  85. package/dist/{chunk-UGLN7QHV.js → chunk-ECLXZWAG.js} +12 -12
  86. package/dist/{chunk-5WG5YP4T.js → chunk-EDZ45WIR.js} +14 -14
  87. package/dist/chunk-EFCQSMXB.js +37 -0
  88. package/dist/{chunk-2ANOROX3.js → chunk-EZIN5E5B.js} +8 -8
  89. package/dist/{chunk-BWZ77RQT.js → chunk-F6H2RJ3N.js} +1 -1
  90. package/dist/{chunk-OLQJTJJU.js → chunk-FAJDKNSD.js} +7 -3
  91. package/dist/chunk-FGAGWYZB.js +47 -0
  92. package/dist/{chunk-4WBVUHXN.js → chunk-FLVZFTLQ.js} +18 -18
  93. package/dist/chunk-FQ6WH6PB.js +140 -0
  94. package/dist/{chunk-T6XQL73F.js → chunk-FRHD22WM.js} +61 -23
  95. package/dist/{chunk-XAKWMCXI.js → chunk-FVMPFCDS.js} +4 -4
  96. package/dist/{chunk-B2WLAWNJ.js → chunk-FY3QIRTL.js} +3 -3
  97. package/dist/{chunk-CPA6HPVR.js → chunk-FYBF5MB2.js} +15 -11
  98. package/dist/{chunk-V2YTAIQO.js → chunk-G5YJBNDZ.js} +21 -6
  99. package/dist/chunk-G6IQYM25.js +339 -0
  100. package/dist/chunk-G6X4YL4D.js +161 -0
  101. package/dist/{chunk-SJRGMG6A.js → chunk-GC2VK3JT.js} +25 -25
  102. package/dist/{chunk-SP2I63OO.js → chunk-GCS3FZOB.js} +77 -3
  103. package/dist/{chunk-6TACQN3N.js → chunk-GDZB57IU.js} +5 -5
  104. package/dist/chunk-GIFMBCTW.js +221 -0
  105. package/dist/{chunk-YY6ZQQBP.js → chunk-GK4PYVEC.js} +18 -8
  106. package/dist/{chunk-TDD55CJH.js → chunk-GNWAOVFQ.js} +6 -5
  107. package/dist/chunk-GS76RXQE.js +226 -0
  108. package/dist/{chunk-YYQN46FY.js → chunk-GSGIZ2OO.js} +23 -23
  109. package/dist/chunk-GUYL7RMK.js +60 -0
  110. package/dist/chunk-GX74YWR7.js +321 -0
  111. package/dist/chunk-HE3HRDNZ.js +122 -0
  112. package/dist/{chunk-AIOQPLA5.js → chunk-HGHRSF3E.js} +30 -12
  113. package/dist/{chunk-2RMYG36Q.js → chunk-HK3VOHIE.js} +198 -336
  114. package/dist/{chunk-QZSX3F7C.js → chunk-HS4BGB4G.js} +24 -22
  115. package/dist/{chunk-XY3P7JW7.js → chunk-HSZMPH5T.js} +834 -149
  116. package/dist/{chunk-L6SGQIR3.js → chunk-HWD4JPU7.js} +4 -2
  117. package/dist/{chunk-PCVDV3UZ.js → chunk-HXXP2NTE.js} +6 -6
  118. package/dist/{chunk-AA6YULYB.js → chunk-I2A3Z5AK.js} +7 -7
  119. package/dist/{chunk-N7IXEHK3.js → chunk-ICHDSWEY.js} +7 -7
  120. package/dist/chunk-IFFRGC3N.js +31 -0
  121. package/dist/{chunk-4BN53TG3.js → chunk-IFHDV6KQ.js} +31 -23
  122. package/dist/chunk-J2O4LFVI.js +80 -0
  123. package/dist/chunk-J5AAZ6OJ.js +161 -0
  124. package/dist/{chunk-ZMFPW66A.js → chunk-JAABT3DA.js} +3 -3
  125. package/dist/chunk-JITJP64K.js +34 -0
  126. package/dist/chunk-JKIGL3XQ.js +162 -0
  127. package/dist/chunk-JRVNXLZP.js +615 -0
  128. package/dist/chunk-JRXHON4E.js +41 -0
  129. package/dist/{chunk-DHPACDG7.js → chunk-JS6WMC3J.js} +8 -8
  130. package/dist/chunk-JU4QNJSR.js +62 -0
  131. package/dist/{chunk-PAMPPUR6.js → chunk-JYMIB5XY.js} +1697 -172
  132. package/dist/{chunk-RRTKKSLQ.js → chunk-JYTIHTIK.js} +8 -6
  133. package/dist/{chunk-3HI6Z55Y.js → chunk-K332XW7K.js} +324 -39
  134. package/dist/{chunk-GLUX4EEP.js → chunk-K6JB6XTX.js} +9 -9
  135. package/dist/chunk-KDAHXQIE.js +294 -0
  136. package/dist/chunk-KYZMRSPS.js +93 -0
  137. package/dist/chunk-L4CESDPB.js +22 -0
  138. package/dist/{chunk-NXFPS2LR.js → chunk-LEBR5NHW.js} +14 -14
  139. package/dist/chunk-LIJJCBQI.js +223 -0
  140. package/dist/{chunk-DE76JROX.js → chunk-LIRVU3HW.js} +16 -16
  141. package/dist/{chunk-JMSCMUCA.js → chunk-LN77DXBM.js} +145 -21
  142. package/dist/{chunk-JIITQXFB.js → chunk-LNWEWYCM.js} +2969 -788
  143. package/dist/{chunk-TANFV3MZ.js → chunk-LO3BLMVG.js} +3 -3
  144. package/dist/chunk-LPV6T362.js +250 -0
  145. package/dist/{chunk-2VHF7OXM.js → chunk-LQH4P45K.js} +1 -1
  146. package/dist/chunk-LU4MQVAL.js +41 -0
  147. package/dist/chunk-LWDNKE4X.js +273 -0
  148. package/dist/chunk-M4H2UG4R.js +218 -0
  149. package/dist/{chunk-6BVONWJ7.js → chunk-M6D2U3YM.js} +3 -3
  150. package/dist/chunk-MD7KUEJ3.js +514 -0
  151. package/dist/{chunk-66YVAGGM.js → chunk-MMZUN7ZO.js} +20 -20
  152. package/dist/chunk-MZGRDONP.js +916 -0
  153. package/dist/chunk-N3RUGTGV.js +39 -0
  154. package/dist/{chunk-JGZCG5VM.js → chunk-NCB6656Z.js} +7 -7
  155. package/dist/{chunk-4NDAAFQT.js → chunk-NRQ65LTQ.js} +7 -5
  156. package/dist/{chunk-UNM6ZOKP.js → chunk-NTAVOWYD.js} +145 -18
  157. package/dist/{chunk-3USYZGRF.js → chunk-NYOABJNK.js} +36 -27
  158. package/dist/{chunk-WVPJSRRJ.js → chunk-O4IKAIZ2.js} +24 -20
  159. package/dist/{chunk-D3PO4DOZ.js → chunk-ODMBPDDV.js} +51 -14
  160. package/dist/chunk-OKUB6RJA.js +533 -0
  161. package/dist/chunk-OMPENNWY.js +39 -0
  162. package/dist/chunk-OPQZISG3.js +25 -0
  163. package/dist/{chunk-5GGOLAKC.js → chunk-OV57AHCG.js} +26 -26
  164. package/dist/chunk-OZJ3JLYI.js +58 -0
  165. package/dist/{chunk-KEM4SDDP.js → chunk-P2VBXX7N.js} +11 -10
  166. package/dist/{chunk-S2A7YC3Q.js → chunk-PAINMSID.js} +10150 -1720
  167. package/dist/chunk-PKJAV25S.js +43 -0
  168. package/dist/{chunk-EBEW3XXQ.js → chunk-PNQLCRSS.js} +4 -4
  169. package/dist/{chunk-WY6PP6AA.js → chunk-PQH56YF6.js} +37 -5
  170. package/dist/chunk-PRTBPXYA.js +50 -0
  171. package/dist/{chunk-YEDDOYSC.js → chunk-PRW3HXM3.js} +2 -2
  172. package/dist/chunk-PRZ7KMWL.js +42 -0
  173. package/dist/{chunk-6M5NK3K3.js → chunk-PTQ3ZALZ.js} +42 -4
  174. package/dist/{chunk-5GDRCDQB.js → chunk-PUEWDYGP.js} +2 -2
  175. package/dist/chunk-Q26LDIUV.js +236 -0
  176. package/dist/{chunk-CR3MTH32.js → chunk-Q46QDDMF.js} +77 -7
  177. package/dist/chunk-QBNWF5ZU.js +19 -0
  178. package/dist/chunk-QE527XRY.js +342 -0
  179. package/dist/{chunk-CNUKCS2T.js → chunk-QHJJMZLX.js} +1518 -54
  180. package/dist/chunk-QJCJOMW3.js +425 -0
  181. package/dist/{chunk-VYDBJ73M.js → chunk-QKMRFNMA.js} +15 -15
  182. package/dist/chunk-QOOEYDNJ.js +317 -0
  183. package/dist/chunk-QSIDVFB7.js +45 -0
  184. package/dist/{chunk-R77KLRB3.js → chunk-RA33EYS4.js} +19 -18
  185. package/dist/{chunk-DFBCSHVT.js → chunk-RALY3E5U.js} +4 -4
  186. package/dist/{chunk-ZCJDOK2S.js → chunk-S2RY3BOD.js} +35 -21
  187. package/dist/chunk-S5LSDXV4.js +40 -0
  188. package/dist/chunk-SB5GRUFM.js +54 -0
  189. package/dist/chunk-SH27FYPF.js +150 -0
  190. package/dist/chunk-T74WQQGS.js +40 -0
  191. package/dist/{chunk-O3WI5KWW.js → chunk-TGVVUKTG.js} +2 -2
  192. package/dist/chunk-THN26IEF.js +48 -0
  193. package/dist/chunk-TJH2EUAZ.js +47 -0
  194. package/dist/{chunk-ZNCEKR4J.js → chunk-TQ4TG57V.js} +12 -8
  195. package/dist/{chunk-7FBGJFEE.js → chunk-TQTRWENN.js} +12 -12
  196. package/dist/{chunk-TYAID7B7.js → chunk-TSM6T6GQ.js} +23 -23
  197. package/dist/{chunk-DPZHZQKE.js → chunk-TW3KOSQK.js} +43 -10
  198. package/dist/{chunk-MC3H7736.js → chunk-TWQRPM76.js} +37 -4
  199. package/dist/chunk-TYD6I4CZ.js +109 -0
  200. package/dist/chunk-U3NBK4EU.js +420 -0
  201. package/dist/{chunk-6JCPI55B.js → chunk-UDXWIPCB.js} +47 -7
  202. package/dist/{chunk-MMOSZPWJ.js → chunk-UEVZZZU2.js} +4 -4
  203. package/dist/{chunk-JBTK5OP2.js → chunk-UF4UHCIG.js} +2 -2
  204. package/dist/{chunk-6JUBZBMW.js → chunk-UFE36WJH.js} +4 -4
  205. package/dist/{chunk-ONLS5QA5.js → chunk-URIKUID7.js} +12 -12
  206. package/dist/chunk-UYLBRRFK.js +1106 -0
  207. package/dist/chunk-UZACEG2C.js +515 -0
  208. package/dist/{chunk-7SW2QWLU.js → chunk-VAMHOHUU.js} +12 -12
  209. package/dist/{chunk-RZPYKDWS.js → chunk-VUVGX5L2.js} +1 -1
  210. package/dist/{chunk-Q4D5X7QB.js → chunk-VYOCPTUB.js} +44 -24
  211. package/dist/{chunk-CAQZUNOH.js → chunk-WAZEXEJH.js} +567 -3
  212. package/dist/chunk-WCEF7H6L.js +221 -0
  213. package/dist/{chunk-2DIQQJCB.js → chunk-WEOMJHPV.js} +12 -12
  214. package/dist/{chunk-FHH4I4ZV.js → chunk-WFU77T3A.js} +12 -6
  215. package/dist/chunk-WIWTJMMR.js +292 -0
  216. package/dist/{chunk-2BFCZ3RK.js → chunk-WNTIOBOG.js} +18 -18
  217. package/dist/{chunk-7WD63HU2.js → chunk-X2CUXTWU.js} +6 -6
  218. package/dist/chunk-X7EMBM5X.js +34 -0
  219. package/dist/chunk-XEQCQO66.js +33 -0
  220. package/dist/{chunk-F7HYOUFF.js → chunk-XG4WJHLQ.js} +20 -4
  221. package/dist/{chunk-EFHQ3TWP.js → chunk-XOL3GFW2.js} +171 -31
  222. package/dist/{chunk-NE2W3OO7.js → chunk-XQ3YZ4QW.js} +22 -22
  223. package/dist/{chunk-CEXSU4S6.js → chunk-Y6K3CJBU.js} +723 -85
  224. package/dist/{chunk-4RS5KZQD.js → chunk-YAH5IQAL.js} +5 -5
  225. package/dist/{chunk-64EQYWCA.js → chunk-YBOVNMHC.js} +51 -14
  226. package/dist/chunk-YF5DZCPN.js +1212 -0
  227. package/dist/chunk-YIGBJNH4.js +37 -0
  228. package/dist/{chunk-BKVWTZ6A.js → chunk-YJ3TBOTK.js} +25 -25
  229. package/dist/{chunk-Q5AMFEWD.js → chunk-YKTE2RU3.js} +2 -2
  230. package/dist/{chunk-7EKXJZ2Y.js → chunk-YO2PKTXT.js} +296 -37
  231. package/dist/{chunk-6J5OKA4Y.js → chunk-YTTNTQOX.js} +15 -15
  232. package/dist/{chunk-OT2O76OS.js → chunk-YWAKDNMH.js} +183 -33
  233. package/dist/{chunk-R6XF6UR3.js → chunk-YZDZOEV4.js} +4 -4
  234. package/dist/chunk-Z3QFH7YG.js +17 -0
  235. package/dist/{chunk-W5BVQF44.js → chunk-Z6VLC5X4.js} +17 -17
  236. package/dist/{chunk-HLJAXMM4.js → chunk-ZFQMMU5Y.js} +2 -2
  237. package/dist/{chunk-W3BQAZ3Q.js → chunk-ZKYRDV7A.js} +12 -12
  238. package/dist/{chunk-ZMAINWBW.js → chunk-ZLS6PU2O.js} +3 -3
  239. package/dist/{chunk-ZVM6AKKM.js → chunk-ZOSD4FXV.js} +3 -3
  240. package/dist/chunk-ZPDDEVQX.js +47 -0
  241. package/dist/{chunk-TXLH6WHQ.js → chunk-ZQLRCA2V.js} +11 -11
  242. package/dist/{chunk-HITVBIJS.js → chunk-ZX7235KR.js} +128 -54
  243. package/dist/{chunk-GT4I4ZWM.js → chunk-ZZFHLRQW.js} +18 -16
  244. package/dist/files.json +636 -364
  245. package/dist/packages/naysayer/constitution/constitution.yaml +19 -0
  246. package/dist/packages/sdk/npm/index.js +5614 -2343
  247. package/dist/packages/ui/dist/assets/{elk-api-tma0MCuh.js → elk-api-CowTnhEJ.js} +2 -2
  248. package/dist/packages/ui/dist/assets/index-Dw20IRhQ.css +1 -0
  249. package/dist/packages/ui/dist/assets/index-z2wv0d5d.js +47 -0
  250. package/dist/packages/ui/dist/index.html +2 -2
  251. package/package.json +4 -4
  252. package/dist/chunk-2BF2EYJV.js +0 -174
  253. package/dist/chunk-42EVSKME.js +0 -37
  254. package/dist/chunk-4BKGMUIK.js +0 -53
  255. package/dist/chunk-5KLGBXG5.js +0 -48
  256. package/dist/chunk-6BNC6EQ4.js +0 -41
  257. package/dist/chunk-6D2CQ5II.js +0 -41
  258. package/dist/chunk-7AVHLZGD.js +0 -45
  259. package/dist/chunk-D46WUV3T.js +0 -33
  260. package/dist/chunk-E36QOJMD.js +0 -47
  261. package/dist/chunk-FQXYPF7E.js +0 -147
  262. package/dist/chunk-GBRFVT63.js +0 -45
  263. package/dist/chunk-ICY36XCH.js +0 -34
  264. package/dist/chunk-J4K3KVLD.js +0 -131
  265. package/dist/chunk-JZU3H6UQ.js +0 -54
  266. package/dist/chunk-NN2ZQEB4.js +0 -38
  267. package/dist/chunk-PCOCACY3.js +0 -385
  268. package/dist/chunk-RTEYOSJY.js +0 -29
  269. package/dist/chunk-RVH5SUW5.js +0 -69
  270. package/dist/chunk-VN3DP4LQ.js +0 -43
  271. package/dist/chunk-XPTOBS2D.js +0 -48
  272. package/dist/packages/ui/dist/assets/index-B54fm9FQ.js +0 -29
  273. package/dist/packages/ui/dist/assets/index-DD_hufQz.css +0 -1
@@ -13,6 +13,7 @@ import {
13
13
  STEP_CLASSES,
14
14
  changesDirOf,
15
15
  changesRelOf,
16
+ copilotAcpOf,
16
17
  currentSignal,
17
18
  differentThings,
18
19
  identifierWords,
@@ -27,14 +28,114 @@ import {
27
28
  runsRelOf,
28
29
  stateDirOf,
29
30
  stepModelsOf
30
- } from "./chunk-S2A7YC3Q.js";
31
+ } from "./chunk-PAINMSID.js";
31
32
  import {
32
33
  writeFileAtomic
33
- } from "./chunk-D3PO4DOZ.js";
34
+ } from "./chunk-ODMBPDDV.js";
34
35
  import {
35
36
  __toESM
36
37
  } from "./chunk-TV45EUGM.js";
37
38
 
39
+ // packages/ai/dist/person-only.js
40
+ var flag = (a, ...names) => a.some((x) => names.some((n) => x === n || x.startsWith(`${n}=`)));
41
+ var RULES = [
42
+ {
43
+ test: (w, a) => w[0] === "change" && w[1] === "release-prs" && flag(a, "--approve"),
44
+ why: "a person raises the release PRs into each repo's default branch (ADR 0184); a session never approves a push or a PR"
45
+ },
46
+ {
47
+ test: (w, a) => w[0] === "task" && w[1] === "run-ready" && flag(a, "--approve"),
48
+ why: "a person approves each ready task's push and PR into the change branch (ADR 0181); a session never approves a push or a PR"
49
+ },
50
+ { test: (w) => w[0] === "questions" && w[1] === "answer", why: "a person answers questions" },
51
+ {
52
+ // ADR 0181: the AI decides as itself, through Atticus; correcting it, spreading the
53
+ // correction and undoing a batch are a person's word.
54
+ test: (w) => w[0] === "questions" && (w[1] === "correct" || w[1] === "undo"),
55
+ why: "a person corrects an AI decision and undoes a batch of decisions (ADR 0181); the AI decides only as itself, through Atticus"
56
+ },
57
+ {
58
+ test: (w, a) => w[0] === "questions" && w[1] === "sheet" && flag(a, "--apply"),
59
+ why: "a person answers questions (questions sheet --apply answers as them)"
60
+ },
61
+ {
62
+ test: (w, a) => w[0] === "verify" && w[1] === "audit" && flag(a, "--right", "--wrong", "--unsure", "--answers"),
63
+ why: "a person answers an audit: its record says who confirmed each fact"
64
+ },
65
+ {
66
+ test: (w) => w[0] === "knowledge" && ["verify", "correct", "reject"].includes(w[1] ?? ""),
67
+ why: "a person verifies, corrects or rejects a knowledge item"
68
+ },
69
+ { test: (w) => w[1] === "accept", why: "a person accepts what is proposed" },
70
+ { test: (w) => w[0] === "baseline", why: "a person accepts the catalog as the baseline" },
71
+ { test: (w) => w[0] === "triage" && w[1] === "decide", why: "a person decides a triage item" },
72
+ { test: (w) => w[0] === "finding", why: "a person acts on a finding (it is recorded with them)" },
73
+ {
74
+ test: (w) => w[0] === "feature" && ["name", "link"].includes(w[1] ?? ""),
75
+ why: "a person names a feature or links it to work"
76
+ },
77
+ { test: (w) => w[0] === "todo" && w[1] === "done", why: "a person records a manual step done" },
78
+ {
79
+ test: (w) => {
80
+ const n = w[0] === "change" && w[1] === "needs" ? w.slice(1) : w;
81
+ return n[0] === "needs" && ["done", "skip"].includes(n[1] ?? "");
82
+ },
83
+ why: "a person records a need done or not needed"
84
+ },
85
+ { test: (_w, a) => flag(a, "--by"), why: "--by names a person; a session acts as no one" },
86
+ {
87
+ test: (_w, a) => flag(a, "--approve", "--send"),
88
+ why: "--approve and --send are a person's: a human approves every write to shared systems"
89
+ },
90
+ { test: (_w, a) => flag(a, "--as"), why: "--as names a person; a session acts as no one" },
91
+ {
92
+ test: (w, a) => w[0] === "rules" && (w[1] === "activate" || w[1] === "off" || w[1] === "add" && !flag(a, "--draft")),
93
+ why: "a person sets a reading rule active or off (a session drafts)"
94
+ },
95
+ {
96
+ test: (w) => w[0] === "initiative" && ["commit", "new", "plan", "request"].includes(w[1] ?? ""),
97
+ why: "a person starts, plans and records an initiative"
98
+ },
99
+ {
100
+ test: (w) => w[0] === "questions" && w[1] === "owner",
101
+ why: "an owner answers a knowledge gap's question"
102
+ },
103
+ { test: (w) => w[0] === "outcome" && w[1] === "record", why: "a person records an outcome" },
104
+ {
105
+ test: (_w, a) => flag(a, "--accept", "--accept-proposal"),
106
+ why: "a person accepts what is proposed (--accept is theirs)"
107
+ },
108
+ {
109
+ test: (w, a) => w[0] === "repo" && (w[1] === "add" || w[1] === "describe" && flag(a, "--description", "--reject")),
110
+ why: "a person adds a repo and writes or drops its description (a session drafts with --drafted)"
111
+ },
112
+ {
113
+ test: (w) => w[0] === "knowledge" && w[1] === "keep",
114
+ why: "a person keeps a knowledge item (it is recorded as verified by them)"
115
+ },
116
+ { test: (w) => w[0] === "alias", why: "a person decides what a name means" },
117
+ {
118
+ test: (w) => w[0] === "glossary" && ["define", "link", "alias"].includes(w[1] ?? ""),
119
+ why: "a person defines, links or aliases a glossary term"
120
+ },
121
+ {
122
+ // Seventh UX walk: shown by anyone; set (a handle given) only by a person, as in the app.
123
+ test: (w) => w[0] === "orgpack" && w[1] === "owner" && !!w[2],
124
+ why: "a person says who looks after the org pack"
125
+ }
126
+ ];
127
+ function personOnlyWhy(argv) {
128
+ const words2 = [];
129
+ for (const x of argv) {
130
+ if (x.startsWith("-"))
131
+ break;
132
+ words2.push(x);
133
+ }
134
+ return RULES.find((r) => r.test(words2, argv))?.why;
135
+ }
136
+ var isPersonsFactsFile = (name) => /\.audit\.yaml$|\.corrections\.jsonl$/i.test(windowsName(name));
137
+ var windowsName = (name) => name.replace(/:.*$/, "").replace(/[. ]+$/, "");
138
+
38
139
  // packages/ai/dist/context.js
39
140
  import { createHash as createHash2 } from "node:crypto";
40
141
 
@@ -1018,6 +1119,10 @@ var NEXT_CLASS = {
1018
1119
  survey: "draft",
1019
1120
  verify: "read",
1020
1121
  map: "read",
1122
+ // ADR 0141: a mapped repo read again where its clone moved on.
1123
+ reread: "read",
1124
+ // ADR 0167: a read repo topped up for reading rules added since.
1125
+ rules: "read",
1021
1126
  spec: "draft",
1022
1127
  knowledge: "knowledge",
1023
1128
  feature: "draft",
@@ -1107,8 +1212,8 @@ function checkAllowed(kind, agent) {
1107
1212
  }
1108
1213
  function makeRunId(now, seq) {
1109
1214
  const stamp = now.toISOString().replace(/[-:TZ.]/g, "").slice(0, 14);
1110
- const tail = seq !== void 0 ? String(seq).padStart(4, "0") : Math.random().toString(36).slice(2, 8);
1111
- return `run-${stamp}-${tail}`;
1215
+ const tail2 = seq !== void 0 ? String(seq).padStart(4, "0") : Math.random().toString(36).slice(2, 8);
1216
+ return `run-${stamp}-${tail2}`;
1112
1217
  }
1113
1218
  function toRunSummary(run) {
1114
1219
  return {
@@ -1128,7 +1233,10 @@ function toRunSummary(run) {
1128
1233
  ...run.tools ? { tools: run.tools } : {},
1129
1234
  ...run.request.retrieval ? { retrieval: run.request.retrieval } : {},
1130
1235
  stepClass: run.stepClass ?? stepClassOf(run.request),
1131
- ...run.model ? { model: run.model } : {}
1236
+ ...run.model ? { model: run.model } : {},
1237
+ ...run.assistant ? { assistant: run.assistant } : {},
1238
+ ...run.batch ? { batch: run.batch } : {},
1239
+ ...run.parts?.length ? { parts: run.parts } : {}
1132
1240
  };
1133
1241
  }
1134
1242
  var OneShotRuntime = class {
@@ -1145,11 +1253,15 @@ var OneShotRuntime = class {
1145
1253
  modelFor(_request) {
1146
1254
  return void 0;
1147
1255
  }
1256
+ /** The kind an agent's allowedRuntimes must name for this runtime (copilot-acp: hand-off too). */
1257
+ allowedAs(_agent) {
1258
+ return this.kind;
1259
+ }
1148
1260
  /** Keep a finished run where Model runs reads it (the model runtime, given a root). */
1149
1261
  async keep(_run) {
1150
1262
  }
1151
1263
  async prepare(request) {
1152
- checkAllowed(this.kind, request.agent);
1264
+ checkAllowed(this.allowedAs(request.agent), request.agent);
1153
1265
  if (request.pack.manifest.totalTokens > request.agent.tokenBudget) {
1154
1266
  throw new RuntimeError(`context pack (${request.pack.manifest.totalTokens} tokens) is over agent ${request.agent.id}'s budget of ${request.agent.tokenBudget}`);
1155
1267
  }
@@ -1177,8 +1289,14 @@ var OneShotRuntime = class {
1177
1289
  return run;
1178
1290
  }
1179
1291
  try {
1180
- const { output, usage, tools } = await this.produce(run, signal);
1181
- run = transition(run, "produced", this.now(), { output, usage, ...tools ? { tools } : {} });
1292
+ const { output, usage, tools, model, assistant } = await this.produce(run, signal);
1293
+ run = transition(run, "produced", this.now(), {
1294
+ output,
1295
+ usage,
1296
+ ...tools ? { tools } : {},
1297
+ ...model ? { model } : {},
1298
+ ...assistant ? { assistant } : {}
1299
+ });
1182
1300
  const problems = await this.opts.validate?.(output, run.request) ?? [];
1183
1301
  run = problems.length === 0 ? transition(run, "validated", this.now()) : transition(run, "failed", this.now(), { errors: problems });
1184
1302
  } catch (e) {
@@ -1538,6 +1656,36 @@ ${DATA_RULE}`;
1538
1656
  // packages/ai/dist/handoff.js
1539
1657
  import { mkdir as mkdir3, readdir as readdir3, readFile as readFile3, rm, stat, writeFile as writeFile3 } from "node:fs/promises";
1540
1658
  import { join as join3 } from "node:path";
1659
+ var BATCH_OUTPUT = "answers.md";
1660
+ var DEFAULT_BATCH_MAX_TOKENS = 6e4;
1661
+ var SECTION = /^===[ \t]*([a-z][a-z0-9-]*)[ \t]*$/;
1662
+ function batchSections(text) {
1663
+ const out = /* @__PURE__ */ new Map();
1664
+ let name;
1665
+ let lines = [];
1666
+ const end = () => {
1667
+ if (name === void 0)
1668
+ return;
1669
+ while (lines.length && !lines[0].trim())
1670
+ lines.shift();
1671
+ while (lines.length && !lines.at(-1).trim())
1672
+ lines.pop();
1673
+ const body = lines.length ? `${lines.join("\n")}
1674
+ ` : "";
1675
+ out.set(name, out.has(name) ? { text: body, twice: true } : { text: body });
1676
+ };
1677
+ for (const line of text.replace(/\r\n/g, "\n").split("\n")) {
1678
+ const m = SECTION.exec(line);
1679
+ if (m) {
1680
+ end();
1681
+ name = m[1];
1682
+ lines = [];
1683
+ } else
1684
+ lines.push(line);
1685
+ }
1686
+ end();
1687
+ return out;
1688
+ }
1541
1689
  var HandoffRuntime = class _HandoffRuntime {
1542
1690
  o;
1543
1691
  kind = "hand-off";
@@ -1563,6 +1711,39 @@ var HandoffRuntime = class _HandoffRuntime {
1563
1711
  const { outputPath, change } = run.request;
1564
1712
  return run.request.outputIn === "run" ? `${runsRel}/${change}/${run.runId}/${outputPath}` : `${changesRel}/${change}/${outputPath}`;
1565
1713
  }
1714
+ /**
1715
+ * A batched hand-off's prompt (ADR 0185): one section to write per part, then each part's own
1716
+ * prompt, whole and in order, under its name. It ends with the completion command.
1717
+ */
1718
+ static promptForBatch(run, parts, changesRel = "openspec/changes", runsRel = ".runs") {
1719
+ const { agent, change } = run.request;
1720
+ const where = _HandoffRuntime.outputRel(run, changesRel, runsRel);
1721
+ const n = parts.length;
1722
+ return [
1723
+ `# ${agent.id}: ${n} parts for change ${change}, in one answer`,
1724
+ "",
1725
+ agent.description,
1726
+ "",
1727
+ `Write the result to ${where}. Change no other files.`,
1728
+ "",
1729
+ `The file holds one section per part below. Start each section with a line that holds only "=== " and the part's name, then write that part's answer exactly as the part asks for it, and nothing else. Answer each part from its own instructions and its own data only: the parts are separate. Leave no part out. Atticus checks each section on its own, as if that part were answered alone: a section that is missing or fails its check is asked for again, and the others are kept.`,
1730
+ "",
1731
+ ...parts.flatMap((p) => [`=== ${p.name}`, `<the ${p.name} part's answer>`]),
1732
+ "",
1733
+ ...parts.flatMap((p, i) => [
1734
+ "---",
1735
+ "",
1736
+ `Part ${i + 1} of ${n}: ${p.name}. Its answer is the section "=== ${p.name}".`,
1737
+ "",
1738
+ p.prompt.trimEnd(),
1739
+ ""
1740
+ ]),
1741
+ "---",
1742
+ "",
1743
+ `When the file is complete, run: atticus handoff done ${run.runId}`,
1744
+ ""
1745
+ ].join("\n");
1746
+ }
1566
1747
  /** The prompt the person's assistant gets. It ends with the completion command. */
1567
1748
  static promptFor(run, changesRel = "openspec/changes", runsRel = ".runs") {
1568
1749
  const { agent, pack, outputPath, change } = run.request;
@@ -1580,15 +1761,96 @@ var HandoffRuntime = class _HandoffRuntime {
1580
1761
  ""
1581
1762
  ].join("\n");
1582
1763
  }
1764
+ /** A run id no run folder of the change has yet. */
1765
+ async freshId(change, now) {
1766
+ let runId = makeRunId(now, ++this.seq);
1767
+ while (await stat(this.runDir(change, runId)).catch(() => void 0))
1768
+ runId = makeRunId(now, ++this.seq);
1769
+ return runId;
1770
+ }
1771
+ /**
1772
+ * Whether `parts` runs that wait together, `tokens` in all, are asked in one prompt (ADR 0185):
1773
+ * only when this runtime batches, for two parts or more, within the size a batch may hold.
1774
+ */
1775
+ canBatch(parts, tokens) {
1776
+ return !!this.o.batch && parts >= 2 && tokens <= (this.o.batchMaxTokens ?? DEFAULT_BATCH_MAX_TOKENS);
1777
+ }
1778
+ /**
1779
+ * Ask several waiting runs of one change in one prompt (ADR 0185). Each part keeps its own run,
1780
+ * prompt, pack and answer file, and can still be answered alone; the batch links them, and each
1781
+ * part names the batch. The batch's pack is its parts' packs together: their sources, each id
1782
+ * under its part's name, and their sizes added up. Run it (`run`) to hand it over.
1783
+ */
1784
+ async prepareBatch(o) {
1785
+ checkAllowed(this.kind, o.agent);
1786
+ if (o.parts.length < 2)
1787
+ throw new RuntimeError("a batched hand-off needs two parts or more");
1788
+ const twice = o.parts.find((p, i) => o.parts.findIndex((x) => x.name === p.name) !== i);
1789
+ if (twice)
1790
+ throw new RuntimeError(`a batched hand-off can't have two parts named ${twice.name}`);
1791
+ const parts = [];
1792
+ for (const p of o.parts) {
1793
+ const run2 = await this.load(p.runId);
1794
+ if (run2.request.change !== o.change)
1795
+ throw new RuntimeError(`run ${p.runId} isn't a run of ${o.change}`);
1796
+ if (run2.state !== "waiting" && run2.state !== "prepared")
1797
+ throw new RuntimeError(`run ${p.runId} is ${run2.state}: only a run still waiting for its answer can be batched`);
1798
+ if (run2.batch)
1799
+ throw new RuntimeError(`run ${p.runId} is already asked in ${run2.batch}`);
1800
+ parts.push({ name: p.name, run: run2 });
1801
+ }
1802
+ const now = this.now();
1803
+ const runId = await this.freshId(o.change, now);
1804
+ const manifests = parts.map((p) => ({ name: p.name, m: p.run.request.pack.manifest }));
1805
+ const totalTokens = manifests.reduce((n, x) => n + x.m.totalTokens, 0);
1806
+ const agent = { ...o.agent, tokenBudget: Math.max(o.agent.tokenBudget, totalTokens) };
1807
+ const run = {
1808
+ runId,
1809
+ request: {
1810
+ change: o.change,
1811
+ agent,
1812
+ pack: { prompt: "", manifest: manifests[0].m },
1813
+ outputPath: BATCH_OUTPUT,
1814
+ outputIn: "run",
1815
+ ...o.stepClass ? { stepClass: o.stepClass } : {}
1816
+ },
1817
+ runtime: this.kind,
1818
+ state: "prepared",
1819
+ attempt: 1,
1820
+ startedAt: now.toISOString(),
1821
+ errors: [],
1822
+ stepClass: o.stepClass ?? stepClassOf({ agent }),
1823
+ parts: parts.map((p) => ({ name: p.name, runId: p.run.runId }))
1824
+ };
1825
+ const prompt = _HandoffRuntime.promptForBatch(run, parts.map((p) => ({ name: p.name, prompt: p.run.request.pack.prompt })), changesRelOf(this.o.root), runsRelOf(this.o.root));
1826
+ const manifest = {
1827
+ schemaVersion: 1,
1828
+ change: o.change,
1829
+ agent: o.agent.id,
1830
+ createdAt: now.toISOString(),
1831
+ budget: manifests.reduce((n, x) => n + x.m.budget, 0),
1832
+ totalTokens,
1833
+ sources: manifests.flatMap((x) => x.m.sources.map((s) => ({ ...s, id: `${x.name}/${s.id}` }))),
1834
+ dropped: manifests.flatMap((x) => x.m.dropped.map((d) => ({ ...d, id: `${x.name}/${d.id}` }))),
1835
+ promptSha256: sha2562(prompt)
1836
+ };
1837
+ run.request.pack = { prompt, manifest };
1838
+ const dir = this.runDir(o.change, runId);
1839
+ await mkdir3(dir, { recursive: true });
1840
+ await writeFile3(join3(dir, "prompt.md"), prompt, "utf8");
1841
+ await writeFile3(join3(dir, "context-manifest.json"), JSON.stringify(manifest, null, 2) + "\n", "utf8");
1842
+ await this.save(run);
1843
+ for (const p of parts)
1844
+ await this.save({ ...p.run, batch: runId });
1845
+ return run;
1846
+ }
1583
1847
  async prepare(request) {
1584
1848
  checkAllowed(this.kind, request.agent);
1585
1849
  if (request.pack.manifest.totalTokens > request.agent.tokenBudget) {
1586
1850
  throw new RuntimeError(`context pack (${request.pack.manifest.totalTokens} tokens) is over agent ${request.agent.id}'s budget of ${request.agent.tokenBudget}`);
1587
1851
  }
1588
1852
  const now = this.now();
1589
- let runId = makeRunId(now, ++this.seq);
1590
- while (await stat(this.runDir(request.change, runId)).catch(() => void 0))
1591
- runId = makeRunId(now, ++this.seq);
1853
+ const runId = await this.freshId(request.change, now);
1592
1854
  const run = {
1593
1855
  runId,
1594
1856
  request,
@@ -1622,6 +1884,8 @@ var HandoffRuntime = class _HandoffRuntime {
1622
1884
  async done(runId, o = {}) {
1623
1885
  let run = await this.load(runId);
1624
1886
  const model = o.model?.trim();
1887
+ if (run.parts?.length)
1888
+ return this.doneBatch(run, model);
1625
1889
  if (model)
1626
1890
  run = { ...run, model };
1627
1891
  if (run.state === "failed") {
@@ -1645,8 +1909,61 @@ var HandoffRuntime = class _HandoffRuntime {
1645
1909
  return run;
1646
1910
  if (this.now().getTime() - info.mtimeMs < (this.o.stableMs ?? 3e4))
1647
1911
  return run;
1912
+ if (run.parts?.length)
1913
+ return this.doneBatch(run);
1648
1914
  return this.validate(transition(run, "produced", this.now()));
1649
1915
  }
1916
+ /**
1917
+ * A batched hand-off's Done (ADR 0185): its answer is split into its parts' sections, each
1918
+ * written to its part's own answer file and checked there as that part's Done would check it.
1919
+ * A part that passes is in; a missing, doubled or failing section fails only its part, which can
1920
+ * be fixed in the batch (Done again checks only the parts still out) or answered alone. The
1921
+ * batch passes once every part is in; until then it fails, naming each part that is out and why.
1922
+ */
1923
+ async doneBatch(start, model) {
1924
+ let run = start;
1925
+ if (run.state === "validated" || run.state === "cancelled")
1926
+ return run;
1927
+ if (run.state === "failed")
1928
+ run = transition(transition(run, "prepared", this.now(), { attempt: run.attempt + 1, errors: [] }), "waiting", this.now());
1929
+ if (model)
1930
+ run = { ...run, model };
1931
+ const output = await readFile3(this.outputFile(run), "utf8").catch(() => void 0);
1932
+ if (output === void 0)
1933
+ return this.save(transition(run, "failed", this.now(), {
1934
+ errors: [`${run.request.outputPath} was not written`]
1935
+ }));
1936
+ const names = run.parts.map((p) => p.name);
1937
+ const sections = batchSections(output);
1938
+ if (!names.some((n) => sections.has(n)))
1939
+ return this.save(transition(run, "failed", this.now(), {
1940
+ output,
1941
+ errors: [
1942
+ `${run.request.outputPath} has no section of any part. Start each part's answer with its own line "=== <part>": ${names.map((n) => `=== ${n}`).join(", ")}.`
1943
+ ]
1944
+ }));
1945
+ run = transition(run, "produced", this.now(), { output });
1946
+ const errors = [];
1947
+ const runsRel = runsRelOf(this.o.root);
1948
+ for (const p of run.parts) {
1949
+ const part = await this.load(p.runId);
1950
+ if (part.state === "validated" || part.state === "cancelled")
1951
+ continue;
1952
+ const s = sections.get(p.name);
1953
+ const alone = `answer that part alone: its prompt is ${_HandoffRuntime.promptRel(part, runsRel)}.`;
1954
+ if (!s || s.twice) {
1955
+ errors.push(s ? `${p.name}: the answer has two "=== ${p.name}" sections. Keep one, or ${alone}` : `${p.name}: the answer has no "=== ${p.name}" section. Add it, or ${alone}`);
1956
+ const why = `The batched answer (run ${run.runId}) has ${s ? 'two "=== ' + p.name + '" sections' : 'no "=== ' + p.name + '" section'}. Answer this part here.`;
1957
+ await this.save(part.state === "failed" ? { ...part, errors: [why] } : transition(part, "failed", this.now(), { errors: [why] }));
1958
+ continue;
1959
+ }
1960
+ await writeFile3(this.outputFile(part), s.text, "utf8");
1961
+ const r = await this.done(p.runId, model ? { model } : {});
1962
+ if (r.state !== "validated")
1963
+ errors.push(...r.errors.map((e) => `${p.name}: ${e}`));
1964
+ }
1965
+ return this.save(errors.length ? transition(run, "failed", this.now(), { errors }) : transition(run, "validated", this.now()));
1966
+ }
1650
1967
  /** Retry after a failure: a fresh attempt with the same request. */
1651
1968
  async retry(runId) {
1652
1969
  const run = await this.load(runId);
@@ -1695,12 +2012,1064 @@ async function pruneRuns(root, days, now = /* @__PURE__ */ new Date(), only) {
1695
2012
  }
1696
2013
 
1697
2014
  // packages/ai/dist/factory.js
1698
- import { spawn } from "node:child_process";
1699
- import { mkdir as mkdir4, mkdtemp, readFile as readFile4, rm as rm2, stat as stat2, writeFile as writeFile4 } from "node:fs/promises";
2015
+ import { existsSync as existsSync2 } from "node:fs";
2016
+ import { spawn as spawn2 } from "node:child_process";
2017
+ import { mkdir as mkdir5, mkdtemp, readFile as readFile5, rm as rm2, stat as stat3, writeFile as writeFile5 } from "node:fs/promises";
1700
2018
  import { tmpdir } from "node:os";
1701
- import { dirname, join as join4 } from "node:path";
2019
+ import { dirname as dirname2, join as join5 } from "node:path";
2020
+
2021
+ // packages/ai/dist/copilot-acp.js
2022
+ import { spawn } from "node:child_process";
2023
+ import { existsSync, realpathSync } from "node:fs";
2024
+ import { mkdir as mkdir4, readFile as readFile4, stat as stat2, writeFile as writeFile4 } from "node:fs/promises";
2025
+ import { basename, dirname, isAbsolute, join as join4, relative, resolve, sep } from "node:path";
2026
+ import { createInterface } from "node:readline";
2027
+
2028
+ // packages/ai/dist/acp.js
2029
+ var ACP_PROTOCOL_VERSION = 1;
2030
+ var ACP_METHODS = {
2031
+ initialize: "initialize",
2032
+ authenticate: "authenticate",
2033
+ sessionNew: "session/new",
2034
+ sessionSetModel: "session/set_model",
2035
+ sessionPrompt: "session/prompt",
2036
+ sessionCancel: "session/cancel",
2037
+ sessionUpdate: "session/update",
2038
+ requestPermission: "session/request_permission",
2039
+ readTextFile: "fs/read_text_file",
2040
+ writeTextFile: "fs/write_text_file",
2041
+ terminalCreate: "terminal/create",
2042
+ terminalOutput: "terminal/output",
2043
+ terminalWaitForExit: "terminal/wait_for_exit",
2044
+ terminalKill: "terminal/kill",
2045
+ terminalRelease: "terminal/release"
2046
+ };
2047
+ var ACP_ERRORS = {
2048
+ invalidParams: -32602,
2049
+ methodNotFound: -32601,
2050
+ internal: -32603,
2051
+ authRequired: -32e3
2052
+ };
2053
+ var AcpRpcError = class extends Error {
2054
+ code;
2055
+ data;
2056
+ constructor(code, message, data) {
2057
+ super(message);
2058
+ this.code = code;
2059
+ this.data = data;
2060
+ this.name = "AcpRpcError";
2061
+ }
2062
+ };
2063
+ var AcpClient = class {
2064
+ t;
2065
+ h;
2066
+ tap;
2067
+ next = 1;
2068
+ pending = /* @__PURE__ */ new Map();
2069
+ closed;
2070
+ constructor(t, h, tap = () => {
2071
+ }) {
2072
+ this.t = t;
2073
+ this.h = h;
2074
+ this.tap = tap;
2075
+ t.onLine((line) => this.receive(line));
2076
+ t.onClose((why) => {
2077
+ this.closed = why;
2078
+ for (const p of this.pending.values())
2079
+ p.reject(new AcpRpcError(ACP_ERRORS.internal, why));
2080
+ this.pending.clear();
2081
+ });
2082
+ }
2083
+ out(message) {
2084
+ const m = { jsonrpc: "2.0", ...message };
2085
+ this.tap("out", m);
2086
+ this.t.send(JSON.stringify(m));
2087
+ }
2088
+ request(method, params) {
2089
+ if (this.closed)
2090
+ return Promise.reject(new AcpRpcError(ACP_ERRORS.internal, this.closed));
2091
+ const id = this.next++;
2092
+ return new Promise((resolve2, reject) => {
2093
+ this.pending.set(id, { resolve: resolve2, reject });
2094
+ this.out({ id, method, params });
2095
+ });
2096
+ }
2097
+ notify(method, params) {
2098
+ if (!this.closed)
2099
+ this.out({ method, params });
2100
+ }
2101
+ receive(line) {
2102
+ if (!line.trim())
2103
+ return;
2104
+ let m;
2105
+ try {
2106
+ m = JSON.parse(line);
2107
+ } catch {
2108
+ this.tap("in", { notJson: line.slice(0, 500) });
2109
+ return;
2110
+ }
2111
+ this.tap("in", m);
2112
+ if (m.method === void 0 && m.id !== void 0) {
2113
+ const p = this.pending.get(Number(m.id));
2114
+ if (!p)
2115
+ return;
2116
+ this.pending.delete(Number(m.id));
2117
+ if (m.error)
2118
+ p.reject(new AcpRpcError(m.error.code, m.error.message, m.error.data));
2119
+ else
2120
+ p.resolve(m.result ?? null);
2121
+ return;
2122
+ }
2123
+ if (m.method === ACP_METHODS.sessionUpdate) {
2124
+ const u = m.params?.update;
2125
+ if (u && typeof u === "object")
2126
+ this.h.update(u);
2127
+ return;
2128
+ }
2129
+ if (m.id === void 0)
2130
+ return;
2131
+ const id = m.id;
2132
+ void this.answer(m.method ?? "", m.params ?? {}).then((result) => this.out({ id, result }), (e) => this.out({
2133
+ id,
2134
+ error: {
2135
+ code: e instanceof AcpRpcError ? e.code : ACP_ERRORS.invalidParams,
2136
+ message: e.message
2137
+ }
2138
+ }));
2139
+ }
2140
+ answer(method, p) {
2141
+ const s = (k) => typeof p[k] === "string" ? p[k] : "";
2142
+ switch (method) {
2143
+ case ACP_METHODS.readTextFile:
2144
+ return this.h.readTextFile({
2145
+ path: s("path"),
2146
+ ...typeof p.line === "number" ? { line: p.line } : {},
2147
+ ...typeof p.limit === "number" ? { limit: p.limit } : {}
2148
+ });
2149
+ case ACP_METHODS.writeTextFile:
2150
+ return this.h.writeTextFile({ path: s("path"), content: s("content") });
2151
+ case ACP_METHODS.requestPermission:
2152
+ return this.h.requestPermission({
2153
+ toolCall: p.toolCall ?? {},
2154
+ options: Array.isArray(p.options) ? p.options : []
2155
+ });
2156
+ case ACP_METHODS.terminalCreate:
2157
+ return this.h.terminalCreate({
2158
+ command: s("command"),
2159
+ ...Array.isArray(p.args) ? { args: p.args.map(String) } : {},
2160
+ ...typeof p.cwd === "string" ? { cwd: p.cwd } : {},
2161
+ ...Array.isArray(p.env) ? { env: p.env } : {},
2162
+ ...typeof p.outputByteLimit === "number" ? { outputByteLimit: p.outputByteLimit } : {}
2163
+ });
2164
+ case ACP_METHODS.terminalOutput:
2165
+ return this.h.terminalOutput({ terminalId: s("terminalId") });
2166
+ case ACP_METHODS.terminalWaitForExit:
2167
+ return this.h.terminalWaitForExit({ terminalId: s("terminalId") });
2168
+ case ACP_METHODS.terminalKill:
2169
+ return this.h.terminalKill({ terminalId: s("terminalId") });
2170
+ case ACP_METHODS.terminalRelease:
2171
+ return this.h.terminalRelease({ terminalId: s("terminalId") });
2172
+ default:
2173
+ return Promise.reject(new AcpRpcError(ACP_ERRORS.methodNotFound, `Atticus doesn't offer ${method}`));
2174
+ }
2175
+ }
2176
+ // ------------------------------------------------------------ the agent's methods
2177
+ initialize(clientInfo) {
2178
+ return this.request(ACP_METHODS.initialize, {
2179
+ protocolVersion: ACP_PROTOCOL_VERSION,
2180
+ clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: true },
2181
+ clientInfo
2182
+ });
2183
+ }
2184
+ newSession(cwd) {
2185
+ return this.request(ACP_METHODS.sessionNew, { cwd, mcpServers: [] });
2186
+ }
2187
+ setModel(sessionId, modelId) {
2188
+ return this.request(ACP_METHODS.sessionSetModel, { sessionId, modelId });
2189
+ }
2190
+ prompt(sessionId, text) {
2191
+ return this.request(ACP_METHODS.sessionPrompt, {
2192
+ sessionId,
2193
+ prompt: [{ type: "text", text }]
2194
+ });
2195
+ }
2196
+ cancel(sessionId) {
2197
+ this.notify(ACP_METHODS.sessionCancel, { sessionId });
2198
+ }
2199
+ };
2200
+ function chunkText(u) {
2201
+ const c = u.content;
2202
+ return c?.type === "text" && typeof c.text === "string" ? c.text : void 0;
2203
+ }
2204
+ var UPDATE = {
2205
+ message: "agent_message_chunk",
2206
+ thought: "agent_thought_chunk",
2207
+ toolCall: "tool_call",
2208
+ toolCallUpdate: "tool_call_update",
2209
+ plan: "plan"
2210
+ };
2211
+ function usageOf(u) {
2212
+ if (!u)
2213
+ return void 0;
2214
+ const n = (...ks) => {
2215
+ for (const k of ks)
2216
+ if (typeof u[k] === "number")
2217
+ return u[k];
2218
+ return void 0;
2219
+ };
2220
+ const i = n("inputTokens", "input_tokens", "promptTokens");
2221
+ const o = n("outputTokens", "output_tokens", "completionTokens");
2222
+ return i === void 0 && o === void 0 ? void 0 : {
2223
+ inputTokens: Math.max(0, Math.round(i ?? 0)),
2224
+ outputTokens: Math.max(0, Math.round(o ?? 0))
2225
+ };
2226
+ }
2227
+ var isAuthRequired = (e) => e instanceof AcpRpcError && (e.code === ACP_ERRORS.authRequired || /auth|sign.?in|log.?in/i.test(e.message));
2228
+
2229
+ // packages/ai/dist/copilot-acp.js
2230
+ function words(line) {
2231
+ const out = [];
2232
+ let cur = "";
2233
+ let quote;
2234
+ let any = false;
2235
+ let meta = false;
2236
+ for (const ch of line) {
2237
+ if (quote) {
2238
+ if (ch === quote)
2239
+ quote = void 0;
2240
+ else
2241
+ cur += ch;
2242
+ continue;
2243
+ }
2244
+ if (ch === '"' || ch === "'") {
2245
+ quote = ch;
2246
+ any = true;
2247
+ continue;
2248
+ }
2249
+ if (/\s/.test(ch)) {
2250
+ if (cur || any)
2251
+ out.push(cur);
2252
+ cur = "";
2253
+ any = false;
2254
+ continue;
2255
+ }
2256
+ if ("|&;<>`$(){}\n".includes(ch))
2257
+ meta = true;
2258
+ cur += ch;
2259
+ }
2260
+ if (cur || any)
2261
+ out.push(cur);
2262
+ return { words: out, meta: meta || quote !== void 0 };
2263
+ }
2264
+ function commandLineOf(line) {
2265
+ const w = words(line.trim()).words;
2266
+ if (!w.length)
2267
+ throw new RuntimeConfigLikeError("copilotAcp.command is empty");
2268
+ const args = w.slice(1);
2269
+ return { command: w[0], args: args.includes("--acp") ? args : [...args, "--acp"] };
2270
+ }
2271
+ var RuntimeConfigLikeError = class extends RuntimeError {
2272
+ };
2273
+ var PERSONS = [
2274
+ // What only a person does is personOnlyWhy's list (person-only.ts), shared with the CLI.
2275
+ {
2276
+ test: (a) => a[0] === "map" && a.includes("--all"),
2277
+ why: "this session is one step of atticus map --all; Atticus runs the loop, not the session"
2278
+ },
2279
+ {
2280
+ test: (a) => ["ui", "serve", "mcp"].includes(a[0] ?? ""),
2281
+ why: "a server that keeps running isn't a step's command"
2282
+ },
2283
+ {
2284
+ test: (a) => a.some((x) => x === "--root" || x.startsWith("--root=")),
2285
+ why: "the session works in this metarepo; --root points elsewhere"
2286
+ }
2287
+ ];
2288
+ var ATTICUS_NAMES = /* @__PURE__ */ new Set(["atticus", "atticus.cmd", "atticus.exe"]);
2289
+ function atticusArgvOf(command, args = []) {
2290
+ const head = words(command.trim());
2291
+ if (head.meta)
2292
+ return {
2293
+ refused: `Atticus runs no shell here, so a command line with | & ; < > $ or backquotes is refused: ${short(command)}. Run one atticus command at a time.`
2294
+ };
2295
+ const all = [...head.words, ...args];
2296
+ const program = all[0] ?? "";
2297
+ if (!ATTICUS_NAMES.has(program.toLowerCase()))
2298
+ return {
2299
+ refused: `Atticus runs only atticus commands in this session (atticus <command> <arguments>); ${short([program, ...all.slice(1)].join(" "))} is refused. Read files with your file tools; write only under facts/ or the step's result file.`
2300
+ };
2301
+ const argv = all.slice(1);
2302
+ if (!argv.length)
2303
+ return { refused: "atticus needs a command (atticus next, atticus verify <repo>, ...)" };
2304
+ for (const p of PERSONS)
2305
+ if (p.test(argv))
2306
+ return { refused: `Refused: ${p.why}.` };
2307
+ if (argv[0].startsWith("-") && !["--help", "--version", "-h"].includes(argv[0]))
2308
+ return {
2309
+ refused: `Put the command first: atticus <command> [arguments] (got ${short(argv.join(" "))})`
2310
+ };
2311
+ const person = personOnlyWhy(argv);
2312
+ if (person)
2313
+ return { refused: `Refused: ${person}; Atticus lets a session act as no one.` };
2314
+ return { argv };
2315
+ }
2316
+ var short = (s, n = 120) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
2317
+ function real(p) {
2318
+ let cur = resolve(p);
2319
+ const rest = [];
2320
+ for (; ; ) {
2321
+ try {
2322
+ return join4(realpathSync.native(cur), ...rest.reverse());
2323
+ } catch {
2324
+ const up = dirname(cur);
2325
+ if (up === cur)
2326
+ return resolve(p);
2327
+ rest.push(basename(cur));
2328
+ cur = up;
2329
+ }
2330
+ }
2331
+ }
2332
+ var sameOrUnder = (root, p) => {
2333
+ const r = relative(root, p);
2334
+ return r === "" || !r.startsWith("..") && !isAbsolute(r);
2335
+ };
2336
+ var caseOf = (p) => process.platform === "win32" ? p.toLowerCase() : p;
2337
+ var Paths = class {
2338
+ p;
2339
+ reads;
2340
+ writeDirs;
2341
+ files;
2342
+ constructor(p) {
2343
+ this.p = p;
2344
+ this.reads = p.readRoots.map((r) => caseOf(real(r)));
2345
+ this.writeDirs = p.writeRoots.map((r) => caseOf(real(r)));
2346
+ this.files = (p.writeFiles ?? []).map((f) => caseOf(real(f)));
2347
+ }
2348
+ readable(path) {
2349
+ if (!path || !isAbsolute(path))
2350
+ return `the path must be absolute (got ${short(path)})`;
2351
+ const r = caseOf(real(path));
2352
+ return this.reads.some((x) => sameOrUnder(x, r)) ? void 0 : `Atticus lets this session read only under the metarepo and its clones; ${short(path)} is outside`;
2353
+ }
2354
+ writable(path) {
2355
+ if (!path || !isAbsolute(path))
2356
+ return `the path must be absolute (got ${short(path)})`;
2357
+ const r = caseOf(real(path));
2358
+ if (r.split(sep).includes(".git"))
2359
+ return `Atticus never lets a session write in .git (${short(path)})`;
2360
+ const parts = r.split(sep).slice(/^[A-Za-z]:$/.test(r.split(sep)[0] ?? "") ? 1 : 0);
2361
+ if (parts.some((x) => x !== "." && x !== ".." && (/[. ]$/.test(x) || x.includes(":"))))
2362
+ return `Atticus never lets a session write a name that ends in a dot or space or names a stream (${short(path)})`;
2363
+ if (isPersonsFactsFile(basename(r)))
2364
+ return `Atticus never lets a session write a person's record (${short(path)}: an audit's answers or a person's corrections)`;
2365
+ if (this.files.includes(r) || this.writeDirs.some((x) => sameOrUnder(x, r)))
2366
+ return void 0;
2367
+ const base = this.p.readRoots[0] ?? "";
2368
+ const rel = (x) => {
2369
+ const r2 = relative(base, x);
2370
+ return r2 && !r2.startsWith("..") && !isAbsolute(r2) ? r2.split(sep).join("/") : x;
2371
+ };
2372
+ const where = [
2373
+ ...this.p.writeRoots.map((d) => `${rel(d)}/`),
2374
+ ...(this.p.writeFiles ?? []).map(rel)
2375
+ ].join(", ");
2376
+ return `Atticus lets this session write only its step's result: it writes only under ${where || "nothing"}; ${short(path)} is refused`;
2377
+ }
2378
+ };
2379
+ var acpPathsOf = (p) => new Paths(p);
2380
+ var factsOnly = (root, factsDir) => ({
2381
+ readRoots: readRootsOf(root),
2382
+ writeRoots: [factsDir]
2383
+ });
2384
+ function readRootsOf(root) {
2385
+ const out = [root];
2386
+ const state = join4(stateDirOf(root), "workspace");
2387
+ if (!sameOrUnder(resolve(root), resolve(state)))
2388
+ out.push(state);
2389
+ return out;
2390
+ }
2391
+ var needsShell = (command, platform = process.platform) => platform === "win32" && !/\.(exe|com)$/i.test(command);
2392
+ var quoteForCmd = (a) => /[\s"]/.test(a) ? `"${a.replace(/"/g, '""')}"` : a;
2393
+ function killTree(child, platform = process.platform, run = spawn) {
2394
+ if (platform === "win32" && child.pid) {
2395
+ try {
2396
+ const k = run("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
2397
+ windowsHide: true,
2398
+ stdio: "ignore"
2399
+ });
2400
+ k.on("error", () => child.kill());
2401
+ return;
2402
+ } catch {
2403
+ }
2404
+ }
2405
+ child.kill();
2406
+ }
2407
+ var spawnAcpServer = (o) => {
2408
+ const shell = needsShell(o.command);
2409
+ let child;
2410
+ let err = "";
2411
+ let failed = () => {
2412
+ };
2413
+ let ok = () => {
2414
+ };
2415
+ const started = new Promise((res, rej) => {
2416
+ ok = res;
2417
+ failed = rej;
2418
+ });
2419
+ started.catch(() => void 0);
2420
+ try {
2421
+ child = spawn(shell ? quoteForCmd(o.command) : o.command, shell ? o.args.map(quoteForCmd) : o.args, { cwd: o.cwd, env: o.env, stdio: ["pipe", "pipe", "pipe"], windowsHide: true, shell });
2422
+ } catch (e) {
2423
+ failed(e);
2424
+ const dead = { send: () => {
2425
+ }, onLine: () => {
2426
+ }, onClose: (fn) => fn(String(e)) };
2427
+ return { transport: dead, stderr: () => "", close: async () => {
2428
+ }, started };
2429
+ }
2430
+ const lines = [];
2431
+ const closes = [];
2432
+ let closed;
2433
+ const close = (why) => {
2434
+ if (closed)
2435
+ return;
2436
+ closed = why;
2437
+ for (const f of closes)
2438
+ f(why);
2439
+ };
2440
+ child.on("spawn", () => ok());
2441
+ child.on("error", (e) => {
2442
+ failed(e);
2443
+ close(`the Copilot language server couldn't be run: ${e.message}`);
2444
+ });
2445
+ child.on("exit", (code, signal) => close(`the Copilot language server ended (${code ?? signal ?? "no code"})`));
2446
+ for (const s of [child.stdin, child.stdout, child.stderr])
2447
+ s?.on("error", () => void 0);
2448
+ child.stderr?.setEncoding("utf8").on("data", (d) => {
2449
+ err = (err + d).slice(-64e3);
2450
+ });
2451
+ createInterface({ input: child.stdout }).on("line", (l) => {
2452
+ for (const f of lines)
2453
+ f(l);
2454
+ });
2455
+ return {
2456
+ started,
2457
+ stderr: () => err,
2458
+ transport: {
2459
+ send: (t) => {
2460
+ if (!closed)
2461
+ child.stdin?.write(`${t}
2462
+ `);
2463
+ },
2464
+ onLine: (f) => lines.push(f),
2465
+ onClose: (f) => closed ? f(closed) : closes.push(f)
2466
+ },
2467
+ close: async () => {
2468
+ if (closed)
2469
+ return;
2470
+ child.stdin?.end();
2471
+ await new Promise((res) => {
2472
+ const t = setTimeout(() => {
2473
+ killTree(child);
2474
+ res();
2475
+ }, 2e3);
2476
+ closes.push(() => {
2477
+ clearTimeout(t);
2478
+ res();
2479
+ });
2480
+ });
2481
+ }
2482
+ };
2483
+ };
2484
+ function atticusExec(entry, node = process.execPath) {
2485
+ return (argv, o) => new Promise((res) => {
2486
+ let output = "";
2487
+ const child = spawn(node, [entry, ...argv], {
2488
+ cwd: o.cwd,
2489
+ env: { ...process.env, ATTICUS_ACP_SESSION: "1" },
2490
+ stdio: ["ignore", "pipe", "pipe"],
2491
+ windowsHide: true,
2492
+ signal: o.signal
2493
+ });
2494
+ const take = (d) => {
2495
+ const t = d.toString("utf8");
2496
+ output = (output + t).slice(-1e6);
2497
+ o.onOutput?.(t);
2498
+ };
2499
+ child.stdout.on("data", take);
2500
+ child.stderr.on("data", take);
2501
+ child.on("error", (e) => res({ exitCode: 1, output: `${output}${e.message}
2502
+ ` }));
2503
+ child.on("close", (code, signal) => res({ exitCode: code, output, signal }));
2504
+ });
2505
+ }
2506
+ var AcpSignInError = class extends RuntimeError {
2507
+ constructor(message) {
2508
+ super(message);
2509
+ this.name = "AcpSignInError";
2510
+ }
2511
+ };
2512
+ var AcpSetupError = class extends RuntimeError {
2513
+ constructor(message) {
2514
+ super(message);
2515
+ this.name = "AcpSetupError";
2516
+ }
2517
+ };
2518
+ var MAX_NUDGES = 3;
2519
+ function carryOnPrompt(refusals) {
2520
+ return [
2521
+ "Atticus refused this, and you are not finished yet:",
2522
+ ...refusals.slice(-3).map((r) => `- ${oneLine(r, 300)}`),
2523
+ "",
2524
+ "Carry on with the step. Use your own file tools to find, view and search files: they are allowed and need no shell. Don't run shell commands (cd, dir, Get-ChildItem, Select-String, Get-Content, grep, find); the only command Atticus runs is one `atticus ...` command at a time, with nothing piped or chained. The step says where its files are. Finish what the step asks for (the facts, or the result file it names), then stop."
2525
+ ].join("\n");
2526
+ }
2527
+ function sumUsage(us) {
2528
+ if (!us.length)
2529
+ return void 0;
2530
+ const out = {};
2531
+ for (const u of us)
2532
+ for (const [k, v] of Object.entries(u))
2533
+ out[k] = typeof v === "number" ? (out[k] ?? 0) + v : out[k] ?? v;
2534
+ return out;
2535
+ }
2536
+ var ACP_OFFERED = [
2537
+ "fs/read_text_file",
2538
+ "fs/write_text_file",
2539
+ "terminal/create (atticus only)",
2540
+ "session/request_permission"
2541
+ ];
2542
+ var withTimeout = (p, ms, what) => new Promise((res, rej) => {
2543
+ const t = setTimeout(() => rej(new RuntimeError(`${what} took over ${Math.round(ms / 1e3)}s`)), ms);
2544
+ p.then((v) => {
2545
+ clearTimeout(t);
2546
+ res(v);
2547
+ }, (e) => {
2548
+ clearTimeout(t);
2549
+ rej(e);
2550
+ });
2551
+ });
2552
+ var oneLine = (s, n = 150) => short(s.replace(/\s+/g, " ").trim(), n);
2553
+ var signInLines = (stderr) => stderr.split(/\r?\n/).map((l) => l.trim()).filter((l) => /https?:\/\/|code|sign|log.?in|auth/i.test(l)).slice(-5);
2554
+ async function runAcpSession(o) {
2555
+ const { command, args } = commandLineOf(o.command);
2556
+ const server = (o.spawn ?? spawnAcpServer)({
2557
+ command,
2558
+ args,
2559
+ cwd: o.cwd,
2560
+ // beta.17: set on the server too, so an atticus command Copilot runs in its own shell (not
2561
+ // through Atticus's terminal) knows it is inside a session and hands off instead of starting
2562
+ // a Copilot session of its own (a session within a session, waiting on itself).
2563
+ env: { ...process.env, ...o.env ?? {}, ATTICUS_ACP_SESSION: "1", ATTICUS_ROOT: o.cwd }
2564
+ });
2565
+ const transcript = [];
2566
+ const paths = new Paths(o.policy);
2567
+ const calls = [];
2568
+ const refused = [];
2569
+ const say = (l) => o.onProgress?.(short(l, 160));
2570
+ let text = "";
2571
+ let pendingText = "";
2572
+ let agentCalls = 0;
2573
+ let textAtRefusal = 0;
2574
+ let cancelWhy;
2575
+ let sessionId;
2576
+ const abort = new AbortController();
2577
+ const flush = () => {
2578
+ if (pendingText.trim())
2579
+ say(` Copilot: ${oneLine(pendingText)}`);
2580
+ pendingText = "";
2581
+ };
2582
+ const record = (name, input, output, error) => {
2583
+ calls.push({
2584
+ round: 1,
2585
+ name,
2586
+ input,
2587
+ output: short(output, 2e3),
2588
+ tokens: estimateTokens(output),
2589
+ ...error ? { error: true } : {}
2590
+ });
2591
+ if (error) {
2592
+ textAtRefusal = text.length;
2593
+ refused.push(output);
2594
+ flush();
2595
+ say(` Refused: ${oneLine(output, 140)}`);
2596
+ }
2597
+ };
2598
+ const refuse = (name, input, why) => {
2599
+ record(name, input, why, true);
2600
+ throw new AcpRpcError(ACP_ERRORS.invalidParams, why);
2601
+ };
2602
+ const terminals = /* @__PURE__ */ new Map();
2603
+ let tn = 0;
2604
+ const box = {};
2605
+ const cancel = (why) => {
2606
+ if (cancelWhy)
2607
+ return;
2608
+ cancelWhy = why;
2609
+ flush();
2610
+ say(` Stopping the session: ${why}.`);
2611
+ if (sessionId)
2612
+ box.client?.cancel(sessionId);
2613
+ for (const t of terminals.values())
2614
+ t.kill.abort();
2615
+ };
2616
+ const handlers = {
2617
+ async readTextFile(p) {
2618
+ const why = paths.readable(p.path);
2619
+ if (why)
2620
+ return refuse("fs/read_text_file", { path: p.path }, why);
2621
+ const all = await readFile4(p.path, "utf8").catch((e) => {
2622
+ throw new AcpRpcError(ACP_ERRORS.invalidParams, `${p.path} can't be read: ${e.code ?? e.message}`);
2623
+ });
2624
+ let content = all;
2625
+ if (p.line !== void 0 || p.limit !== void 0) {
2626
+ const lines = all.split("\n");
2627
+ const from = Math.max(0, (p.line ?? 1) - 1);
2628
+ content = lines.slice(from, p.limit !== void 0 ? from + p.limit : void 0).join("\n");
2629
+ }
2630
+ record("fs/read_text_file", { path: p.path }, `${content.length} characters`);
2631
+ return { content };
2632
+ },
2633
+ async writeTextFile(p) {
2634
+ const why = paths.writable(p.path);
2635
+ if (why)
2636
+ return refuse("fs/write_text_file", { path: p.path }, why);
2637
+ await mkdir4(dirname(p.path), { recursive: true });
2638
+ await writeFile4(p.path, p.content, "utf8");
2639
+ record("fs/write_text_file", { path: p.path }, `${p.content.length} characters written`);
2640
+ return null;
2641
+ },
2642
+ async requestPermission(p) {
2643
+ const tc = p.toolCall;
2644
+ const why = permissionRefused(tc, paths);
2645
+ const pick = (kinds) => kinds.map((k) => p.options.find((x) => x.kind === k)).find(Boolean);
2646
+ const allow = why ? void 0 : pick(["allow_once"]);
2647
+ const input = {
2648
+ kind: tc.kind ?? "",
2649
+ title: tc.title ?? "",
2650
+ ...tc.locations?.length ? { locations: tc.locations.map((l) => l.path) } : {}
2651
+ };
2652
+ if (allow) {
2653
+ record(`permission:${tc.kind ?? "other"}`, input, `allowed once: ${tc.title ?? ""}`);
2654
+ return { outcome: { outcome: "selected", optionId: allow.optionId } };
2655
+ }
2656
+ record(`permission:${tc.kind ?? "other"}`, input, why ?? "Refused: the server offered only to allow it always; Atticus allows once at a time", true);
2657
+ const reject = pick(["reject_once", "reject_always"]);
2658
+ return reject ? { outcome: { outcome: "selected", optionId: reject.optionId } } : { outcome: { outcome: "cancelled" } };
2659
+ },
2660
+ async terminalCreate(p) {
2661
+ const a = atticusArgvOf(p.command, p.args ?? []);
2662
+ const input = { command: p.command, args: p.args ?? [] };
2663
+ if (a.refused !== void 0)
2664
+ return refuse("terminal/create", input, a.refused);
2665
+ const cwd = o.cwd;
2666
+ const id = `atticus-${++tn}`;
2667
+ const kill = new AbortController();
2668
+ flush();
2669
+ say(` atticus ${oneLine(a.argv.join(" "), 140)}`);
2670
+ const t = {
2671
+ output: "",
2672
+ kill,
2673
+ ...p.outputByteLimit ? { limit: p.outputByteLimit } : {}
2674
+ };
2675
+ t.done = o.exec(a.argv, {
2676
+ cwd,
2677
+ signal: kill.signal,
2678
+ onOutput: (s) => {
2679
+ t.output += s;
2680
+ if (t.limit && Buffer.byteLength(t.output) > t.limit)
2681
+ t.output = t.output.slice(-t.limit);
2682
+ }
2683
+ }).then((r) => {
2684
+ if (!t.output && r.output)
2685
+ t.output = r.output;
2686
+ t.exit = { exitCode: r.exitCode, signal: r.signal ?? null };
2687
+ record("terminal/create", input, `exit ${r.exitCode ?? "none"}: ${short(t.output, 1500)}`);
2688
+ return t.exit;
2689
+ });
2690
+ terminals.set(id, t);
2691
+ return { terminalId: id };
2692
+ },
2693
+ async terminalOutput(p) {
2694
+ const t = terminals.get(p.terminalId);
2695
+ if (!t)
2696
+ throw new AcpRpcError(ACP_ERRORS.invalidParams, `no terminal ${p.terminalId}`);
2697
+ return { output: t.output, truncated: false, ...t.exit ? { exitStatus: t.exit } : {} };
2698
+ },
2699
+ async terminalWaitForExit(p) {
2700
+ const t = terminals.get(p.terminalId);
2701
+ if (!t)
2702
+ throw new AcpRpcError(ACP_ERRORS.invalidParams, `no terminal ${p.terminalId}`);
2703
+ return t.done;
2704
+ },
2705
+ async terminalKill(p) {
2706
+ terminals.get(p.terminalId)?.kill.abort();
2707
+ return null;
2708
+ },
2709
+ async terminalRelease(p) {
2710
+ const t = terminals.get(p.terminalId);
2711
+ t?.kill.abort();
2712
+ terminals.delete(p.terminalId);
2713
+ return null;
2714
+ },
2715
+ update(u) {
2716
+ const kind = u.sessionUpdate;
2717
+ if (kind === UPDATE.message) {
2718
+ const t = chunkText(u);
2719
+ if (t) {
2720
+ text += t;
2721
+ pendingText += t;
2722
+ }
2723
+ } else if (kind === UPDATE.toolCall) {
2724
+ agentCalls++;
2725
+ flush();
2726
+ say(` \xB7 ${oneLine(String(u.title ?? u.kind ?? "a tool"), 140)}`);
2727
+ if (o.maxTurns !== void 0 && agentCalls > o.maxTurns)
2728
+ cancel(`maxTurns ${o.maxTurns}`);
2729
+ } else if (kind === UPDATE.plan) {
2730
+ const n = Array.isArray(u.entries) ? u.entries.length : 0;
2731
+ if (n)
2732
+ say(` Plan: ${n} steps`);
2733
+ }
2734
+ }
2735
+ };
2736
+ const client = new AcpClient(server.transport, handlers, (dir, m) => transcript.push(JSON.stringify({ dir, m })));
2737
+ box.client = client;
2738
+ const onAbort = () => cancel("stopped (Ctrl+C)");
2739
+ o.signal?.addEventListener("abort", onAbort, { once: true });
2740
+ let timer;
2741
+ try {
2742
+ let init;
2743
+ try {
2744
+ await server.started;
2745
+ init = await withTimeout(client.initialize({ name: "atticus", version: o.clientVersion ?? "2" }), 6e4, "The Copilot language server's initialize");
2746
+ } catch (e) {
2747
+ throw new AcpSetupError(`Atticus couldn't start the Copilot language server (${o.command}): ${firstLine(e)}${tail(server.stderr())}. Check copilotAcp.command in runtime.yaml, and that ${command} --help lists --acp.`);
2748
+ }
2749
+ const assistant = {
2750
+ name: init.agentInfo?.name ?? basename(command).replace(/\.(cmd|exe)$/i, ""),
2751
+ ...init.agentInfo?.version ? { version: init.agentInfo.version } : {},
2752
+ ...typeof init.protocolVersion === "number" ? { protocolVersion: init.protocolVersion } : {}
2753
+ };
2754
+ let ns;
2755
+ try {
2756
+ ns = await withTimeout(client.newSession(o.cwd), 12e4, "Opening a Copilot session");
2757
+ } catch (e) {
2758
+ if (isAuthRequired(e)) {
2759
+ await new Promise((r) => setTimeout(r, 150));
2760
+ throw signInError(e, init, server.stderr());
2761
+ }
2762
+ throw new AcpSetupError(`The Copilot language server didn't open a session: ${firstLine(e)}`);
2763
+ }
2764
+ sessionId = ns.sessionId;
2765
+ let model = ns.models?.currentModelId;
2766
+ if (o.model && o.model !== model) {
2767
+ const offered = (ns.models?.availableModels ?? []).map((m) => m.modelId);
2768
+ if (!offered.includes(o.model))
2769
+ throw new AcpSetupError(`The Copilot language server doesn't offer the model ${o.model} (it offers ${offered.join(", ") || "no list"}): change copilotAcp.model in runtime.yaml, or leave it out for Copilot's own.`);
2770
+ await client.setModel(sessionId, o.model);
2771
+ model = o.model;
2772
+ }
2773
+ say(` Copilot session open (${assistant.name}${assistant.version ? ` ${assistant.version}` : ""}${model ? `, ${model}` : ""}).`);
2774
+ if (o.signal?.aborted)
2775
+ cancel("stopped (Ctrl+C)");
2776
+ timer = setTimeout(() => cancel("timeout"), o.timeoutMs ?? 30 * 6e4);
2777
+ let prompt = o.prompt;
2778
+ let answer = {
2779
+ stopReason: "end_turn"
2780
+ };
2781
+ const usages = [];
2782
+ for (let nudge = 0; ; nudge++) {
2783
+ const before = refused.length;
2784
+ const asked = client.prompt(sessionId, prompt);
2785
+ try {
2786
+ answer = await new Promise((res, rej) => {
2787
+ asked.then(res, rej);
2788
+ const watch = setInterval(() => {
2789
+ if (!cancelWhy)
2790
+ return;
2791
+ clearInterval(watch);
2792
+ setTimeout(() => res({ stopReason: "cancelled" }), 1e4);
2793
+ }, 50);
2794
+ asked.finally(() => clearInterval(watch)).catch(() => void 0);
2795
+ });
2796
+ } catch (e) {
2797
+ if (isAuthRequired(e))
2798
+ throw signInError(e, init, server.stderr());
2799
+ throw new RuntimeError(`The Copilot session failed: ${firstLine(e)}${tail(server.stderr())}`);
2800
+ }
2801
+ flush();
2802
+ if (answer.usage)
2803
+ usages.push(answer.usage);
2804
+ const fresh = refused.slice(before);
2805
+ const after = text.slice(textAtRefusal);
2806
+ const overIt = fresh.length > 0 && !!calls.at(-1)?.error && (!after.trim() || /cancel|refused|not allowed|can'?t|cannot|couldn'?t|unable/i.test(after));
2807
+ if (cancelWhy || !overIt || nudge >= MAX_NUDGES || !["end_turn", "cancelled"].includes(answer.stopReason))
2808
+ break;
2809
+ say(` Atticus: told Copilot why that was refused and to carry on (${nudge + 1} of ${MAX_NUDGES}).`);
2810
+ prompt = carryOnPrompt(fresh);
2811
+ }
2812
+ const usage = usageOf(sumUsage(usages));
2813
+ return {
2814
+ stopReason: cancelWhy ? "cancelled" : answer.stopReason,
2815
+ ...cancelWhy ? { stopped: cancelWhy } : {},
2816
+ ...model ? { model } : {},
2817
+ assistant,
2818
+ ...usage ? { usage } : {},
2819
+ text,
2820
+ toolCalls: calls,
2821
+ refused,
2822
+ agentToolCalls: agentCalls
2823
+ };
2824
+ } finally {
2825
+ clearTimeout(timer);
2826
+ o.signal?.removeEventListener("abort", onAbort);
2827
+ abort.abort();
2828
+ for (const t of terminals.values())
2829
+ t.kill.abort();
2830
+ await server.close().catch(() => void 0);
2831
+ if (o.transcript) {
2832
+ await mkdir4(dirname(o.transcript), { recursive: true });
2833
+ await writeFile4(o.transcript, transcript.join("\n") + (transcript.length ? "\n" : ""), "utf8");
2834
+ }
2835
+ }
2836
+ }
2837
+ var firstLine = (e) => String(e?.message ?? e).split("\n")[0];
2838
+ var tail = (stderr) => {
2839
+ const l = stderr.trim().split(/\r?\n/).slice(-2).join(" ").trim();
2840
+ return l ? ` (it said: ${short(l, 300)})` : "";
2841
+ };
2842
+ function signInError(e, init, stderr) {
2843
+ const how = (init.authMethods ?? []).map((m) => m.description || m.name).filter(Boolean).join("; ");
2844
+ const lines = signInLines(stderr);
2845
+ return new AcpSignInError([
2846
+ `GitHub Copilot isn't signed in here, so the run stopped. The Copilot language server said: ${firstLine(e)}`,
2847
+ ...lines.length ? [`It also said: ${lines.join(" ")}`] : [],
2848
+ ...how ? [`Its ways to sign in: ${how}.`] : [],
2849
+ "Sign in yourself (Copilot's sign-in in your editor, or the link and code above), then run the command again. Atticus never enters or keeps your credentials."
2850
+ ].join("\n"));
2851
+ }
2852
+ function permissionRefused(tc, paths) {
2853
+ const locs = (tc.locations ?? []).map((l) => l.path);
2854
+ switch (tc.kind) {
2855
+ case "think":
2856
+ return void 0;
2857
+ case "read":
2858
+ case "search": {
2859
+ if (!locs.length)
2860
+ return tc.kind === "search" ? void 0 : "Refused: a read must say which file (use fs/read_text_file)";
2861
+ for (const l of locs) {
2862
+ const why = paths.readable(l);
2863
+ if (why)
2864
+ return why;
2865
+ }
2866
+ return void 0;
2867
+ }
2868
+ case "edit": {
2869
+ if (!locs.length)
2870
+ return "Refused: an edit must say which file it changes";
2871
+ for (const l of locs) {
2872
+ const why = paths.writable(l);
2873
+ if (why)
2874
+ return why;
2875
+ }
2876
+ return void 0;
2877
+ }
2878
+ case "execute": {
2879
+ const raw = tc.rawInput ?? {};
2880
+ const cmd = typeof raw.command === "string" ? raw.command : typeof raw.commandLine === "string" ? raw.commandLine : tc.title ?? "";
2881
+ const args = Array.isArray(raw.args) ? raw.args.map(String) : [];
2882
+ const a = atticusArgvOf(cmd, args);
2883
+ return a.refused;
2884
+ }
2885
+ default:
2886
+ return `Refused: Atticus doesn't let this session ${tc.kind ?? "do"} ${short(tc.title ?? "that")} (it may read the metarepo, write its step's result and run atticus commands)`;
2887
+ }
2888
+ }
2889
+ async function copilotAcpProbe(o) {
2890
+ const { command, args } = commandLineOf(o.command);
2891
+ const plain = args.filter((a) => a !== "--acp");
2892
+ const env = { ...process.env, ...o.env ?? {} };
2893
+ const version = await new Promise((res) => {
2894
+ const shell = needsShell(command);
2895
+ let out = "";
2896
+ let child;
2897
+ try {
2898
+ child = spawn(shell ? quoteForCmd(command) : command, [...shell ? plain.map(quoteForCmd) : plain, "--version"], {
2899
+ cwd: o.cwd,
2900
+ env,
2901
+ stdio: ["ignore", "pipe", "pipe"],
2902
+ windowsHide: true,
2903
+ shell
2904
+ });
2905
+ } catch (e) {
2906
+ res({ ok: false, text: e.message });
2907
+ return;
2908
+ }
2909
+ const t = setTimeout(() => killTree(child), o.timeoutMs ?? 6e4);
2910
+ child.stdout?.on("data", (d) => out += d.toString("utf8"));
2911
+ child.stderr?.on("data", (d) => out += d.toString("utf8"));
2912
+ child.on("error", (e) => {
2913
+ clearTimeout(t);
2914
+ res({ ok: false, text: e.message });
2915
+ });
2916
+ child.on("close", (code) => {
2917
+ clearTimeout(t);
2918
+ res({ ok: code === 0, text: out.trim() });
2919
+ });
2920
+ });
2921
+ if (!version.ok)
2922
+ return { found: false, said: oneLine(version.text, 200) };
2923
+ const v = version.text.split(/\r?\n/).find((l) => l.trim())?.trim();
2924
+ const server = (o.spawn ?? spawnAcpServer)({ command, args, cwd: o.cwd, env });
2925
+ const client = new AcpClient(server.transport, {
2926
+ readTextFile: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "doctor reads nothing")),
2927
+ writeTextFile: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "doctor writes nothing")),
2928
+ requestPermission: async () => ({ outcome: { outcome: "cancelled" } }),
2929
+ terminalCreate: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "doctor runs nothing")),
2930
+ terminalOutput: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "no terminal")),
2931
+ terminalWaitForExit: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "no terminal")),
2932
+ terminalKill: async () => null,
2933
+ terminalRelease: async () => null,
2934
+ update: () => {
2935
+ }
2936
+ });
2937
+ const base = { found: true, ...v ? { version: v } : {} };
2938
+ try {
2939
+ await server.started;
2940
+ await withTimeout(client.initialize({ name: "atticus-doctor", version: "2" }), o.timeoutMs ?? 6e4, "initialize");
2941
+ try {
2942
+ await withTimeout(client.newSession(o.cwd), o.timeoutMs ?? 6e4, "a new session");
2943
+ return { ...base, signedIn: true };
2944
+ } catch (e) {
2945
+ if (isAuthRequired(e)) {
2946
+ await new Promise((r) => setTimeout(r, 150));
2947
+ const lines = signInLines(server.stderr());
2948
+ return { ...base, signedIn: false, said: [firstLine(e), ...lines].join(" ") };
2949
+ }
2950
+ return { ...base, said: firstLine(e) };
2951
+ }
2952
+ } catch (e) {
2953
+ return { ...base, said: `the --acp handshake failed: ${firstLine(e)}` };
2954
+ } finally {
2955
+ await server.close().catch(() => void 0);
2956
+ }
2957
+ }
2958
+ var CopilotAcpRuntime = class extends OneShotRuntime {
2959
+ c;
2960
+ kind = "copilot-acp";
2961
+ constructor(c) {
2962
+ super({ ...c.now ? { now: c.now } : {}, ...c.validate ? { validate: c.validate } : {} });
2963
+ this.c = c;
2964
+ }
2965
+ allowedAs(agent) {
2966
+ return agent.allowedRuntimes.includes("copilot-acp") ? "copilot-acp" : "hand-off";
2967
+ }
2968
+ modelFor() {
2969
+ return this.c.model;
2970
+ }
2971
+ async produce(run, signal) {
2972
+ const { request } = run;
2973
+ const root = this.c.root;
2974
+ const dir = join4(runsDirOf(root), request.change, run.runId);
2975
+ await mkdir4(dir, { recursive: true });
2976
+ const outRel = HandoffRuntime.outputRel(run, changesRelOf(root), runsRelOf(root));
2977
+ const prompt = HandoffRuntime.promptFor(run, changesRelOf(root), runsRelOf(root)).replace(/\nWhen the file is complete.*\n$/s, "\n") + (request.selfCheck ? `
2978
+ Before you finish, check the file: run ${request.selfCheck.command} ${outRel}. Fix each problem it lists and run it again, until it says the file is clean (at most ${request.selfCheck.limit} times).
2979
+ ` : "") + `
2980
+ ${DATA_RULE}
2981
+ `;
2982
+ await writeFile4(join4(dir, "prompt.md"), prompt, "utf8");
2983
+ await writeFile4(join4(dir, "context-manifest.json"), JSON.stringify(request.pack.manifest, null, 2) + "\n", "utf8");
2984
+ const outputFile = request.outputIn === "run" ? join4(dir, request.outputPath) : join4(changesDirOf(root), request.change, request.outputPath);
2985
+ const before = (await stat2(outputFile).catch(() => void 0))?.mtimeMs;
2986
+ const r = await runAcpSession({
2987
+ command: this.c.command,
2988
+ cwd: root,
2989
+ prompt,
2990
+ policy: { readRoots: readRootsOf(root), writeRoots: [], writeFiles: [outputFile] },
2991
+ exec: this.c.exec ?? noExec,
2992
+ ...this.c.model ? { model: this.c.model } : {},
2993
+ ...this.c.maxTurns ? { maxTurns: this.c.maxTurns } : {},
2994
+ ...this.c.timeoutMs ? { timeoutMs: this.c.timeoutMs } : {},
2995
+ ...signal ? { signal } : {},
2996
+ ...this.c.onProgress ? { onProgress: this.c.onProgress } : {},
2997
+ ...this.c.env ? { env: this.c.env } : {},
2998
+ ...this.c.spawn ? { spawn: this.c.spawn } : {},
2999
+ ...this.c.clientVersion ? { clientVersion: this.c.clientVersion } : {},
3000
+ transcript: join4(dir, "transcript.jsonl")
3001
+ });
3002
+ const after = (await stat2(outputFile).catch(() => void 0))?.mtimeMs;
3003
+ const written = after !== void 0 && after !== before ? await readFile4(outputFile, "utf8") : void 0;
3004
+ const tools = {
3005
+ offered: ACP_OFFERED,
3006
+ calls: r.toolCalls,
3007
+ ...r.stopped ? { stopped: r.stopped } : {}
3008
+ };
3009
+ if (written === void 0 && r.stopReason !== "end_turn")
3010
+ throw Object.assign(new RuntimeError(`The Copilot session ended (${r.stopped ?? r.stopReason}) without writing ${outRel}.`), { tools });
3011
+ return {
3012
+ output: written ?? r.text,
3013
+ usage: r.usage ?? {
3014
+ inputTokens: request.pack.manifest.totalTokens,
3015
+ outputTokens: estimateTokens(r.text)
3016
+ },
3017
+ tools,
3018
+ ...r.model ? { model: r.model } : {},
3019
+ assistant: r.assistant
3020
+ };
3021
+ }
3022
+ /** Kept as a hand-off run is: run.json beside the prompt, so Model runs shows it. */
3023
+ async keep(run) {
3024
+ const dir = join4(runsDirOf(this.c.root), run.request.change, run.runId);
3025
+ await mkdir4(dir, { recursive: true });
3026
+ await writeFile4(join4(dir, "run.json"), JSON.stringify(run, null, 2) + "\n", "utf8");
3027
+ }
3028
+ };
3029
+ var noExec = async (argv) => ({
3030
+ exitCode: 127,
3031
+ output: `atticus ${argv.join(" ")}: this program can't run atticus commands for the session; run the step with the atticus command line.
3032
+ `
3033
+ });
3034
+ async function keepAcpRun(o) {
3035
+ const dir = join4(runsDirOf(o.root), o.change, o.runId);
3036
+ await mkdir4(dir, { recursive: true });
3037
+ if (!existsSync(join4(dir, "prompt.md")))
3038
+ await writeFile4(join4(dir, "prompt.md"), o.prompt, "utf8");
3039
+ const r = o.result;
3040
+ const run = {
3041
+ runId: o.runId,
3042
+ request: { change: o.change, agent: o.agent, outputPath: o.outputPath },
3043
+ runtime: "copilot-acp",
3044
+ state: o.state,
3045
+ attempt: 1,
3046
+ startedAt: o.startedAt,
3047
+ finishedAt: o.finishedAt,
3048
+ errors: o.errors,
3049
+ ...r?.usage ? { usage: r.usage } : {},
3050
+ ...r ? {
3051
+ tools: {
3052
+ offered: ACP_OFFERED,
3053
+ calls: r.toolCalls,
3054
+ ...r.stopped ? { stopped: r.stopped } : {}
3055
+ }
3056
+ } : {},
3057
+ stepClass: o.stepClass ?? stepClassOf({ agent: o.agent }),
3058
+ ...r?.model ? { model: r.model } : {},
3059
+ ...r ? { assistant: r.assistant } : {}
3060
+ };
3061
+ await writeFile4(join4(dir, "run.json"), JSON.stringify(run, null, 2) + "\n", "utf8");
3062
+ return dir;
3063
+ }
3064
+
3065
+ // packages/ai/dist/factory.js
1702
3066
  var RUNTIME_MODES = RuntimeKind.options;
1703
- var CONFIGURED = ["hand-off", "model", "headless-claude-code"];
3067
+ var CONFIGURED = [
3068
+ "hand-off",
3069
+ "model",
3070
+ "headless-claude-code",
3071
+ "copilot-acp"
3072
+ ];
1704
3073
  var RuntimeConfigError = class extends RuntimeError {
1705
3074
  constructor(message) {
1706
3075
  super(message);
@@ -1713,16 +3082,49 @@ var AiOffError = class extends RuntimeConfigError {
1713
3082
  }
1714
3083
  };
1715
3084
  function claudeCodeCliRunner(o = {}) {
1716
- return (i) => collectChild(() => spawn(o.command ?? "claude", i.args, {
1717
- cwd: i.cwd,
1718
- env: { ...process.env, ...i.env },
1719
- stdio: ["pipe", "pipe", "pipe"],
1720
- windowsHide: true,
1721
- ...i.signal ? { signal: i.signal } : {}
1722
- }), i.prompt, i.timeoutMs, i.cwd);
1723
- }
1724
- function collectChild(start, prompt, timeoutMs, cwd, platform = process.platform) {
1725
- return new Promise((resolve, reject) => {
3085
+ return (i) => {
3086
+ const command = resolveWindowsCommand(o.command ?? "claude");
3087
+ const shell = isShim(command);
3088
+ let started;
3089
+ const end = () => {
3090
+ if (started)
3091
+ killTree(started);
3092
+ };
3093
+ if (shell && i.signal) {
3094
+ if (i.signal.aborted)
3095
+ queueMicrotask(end);
3096
+ else
3097
+ i.signal.addEventListener("abort", end, { once: true });
3098
+ }
3099
+ return collectChild(() => {
3100
+ started = spawn2(shell ? quoteForCmdAlways(command) : command, shell ? i.args.map(quoteForCmdAlways) : i.args, {
3101
+ cwd: i.cwd,
3102
+ env: { ...process.env, ...i.env },
3103
+ stdio: ["pipe", "pipe", "pipe"],
3104
+ windowsHide: true,
3105
+ shell,
3106
+ ...i.signal && !shell ? { signal: i.signal } : {}
3107
+ });
3108
+ return started;
3109
+ }, i.prompt, i.timeoutMs, i.cwd, process.platform, shell ? (c) => killTree(c) : void 0);
3110
+ };
3111
+ }
3112
+ var isShim = (command, platform = process.platform) => platform === "win32" && /\.(cmd|bat)$/i.test(command);
3113
+ function resolveWindowsCommand(command, env = process.env, platform = process.platform, exists = existsSync2) {
3114
+ if (platform !== "win32" || /[\\/]/.test(command) || /\.[a-z0-9]+$/i.test(command))
3115
+ return command;
3116
+ const exts = (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean);
3117
+ for (const dir of (env.Path ?? env.PATH ?? "").split(";").map((d) => d.trim().replace(/^"(.*)"$/, "$1")).filter(Boolean))
3118
+ for (const ext of exts) {
3119
+ const full = `${dir.replace(/[\\/]+$/, "")}\\${command}${ext.toLowerCase()}`;
3120
+ if (exists(full))
3121
+ return full;
3122
+ }
3123
+ return command;
3124
+ }
3125
+ var quoteForCmdAlways = (a) => `"${a.replace(/"/g, '""')}"`;
3126
+ function collectChild(start, prompt, timeoutMs, cwd, platform = process.platform, stop) {
3127
+ return new Promise((resolve2, reject) => {
1726
3128
  let done = false;
1727
3129
  const timer = {};
1728
3130
  const fail = (e) => {
@@ -1743,7 +3145,7 @@ function collectChild(start, prompt, timeoutMs, cwd, platform = process.platform
1743
3145
  }
1744
3146
  let stdout = "";
1745
3147
  let stderr = "";
1746
- timer.id = setTimeout(() => child.kill("SIGINT"), timeoutMs);
3148
+ timer.id = setTimeout(() => stop ? stop(child) : child.kill("SIGINT"), timeoutMs);
1747
3149
  for (const s of [child.stdin, child.stdout, child.stderr])
1748
3150
  s.on("error", fail);
1749
3151
  child.stdout.setEncoding("utf8").on("data", (d) => stdout += d);
@@ -1754,16 +3156,16 @@ function collectChild(start, prompt, timeoutMs, cwd, platform = process.platform
1754
3156
  return;
1755
3157
  done = true;
1756
3158
  clearTimeout(timer.id);
1757
- resolve({ exitCode: code, stdout, stderr });
3159
+ resolve2({ exitCode: code, stdout, stderr });
1758
3160
  });
1759
3161
  child.stdin.end(prompt, "utf8");
1760
3162
  });
1761
3163
  }
1762
- var cloneDirs = (root) => [join4(root, "workspace"), join4(stateDirOf(root), "workspace")];
3164
+ var cloneDirs = (root) => [join5(root, "workspace"), join5(stateDirOf(root), "workspace")];
1763
3165
  async function existingDirs(dirs) {
1764
3166
  const out = [];
1765
3167
  for (const d of [...new Set(dirs)])
1766
- if ((await stat2(d).catch(() => void 0))?.isDirectory())
3168
+ if ((await stat3(d).catch(() => void 0))?.isDirectory())
1767
3169
  out.push(d);
1768
3170
  return out;
1769
3171
  }
@@ -1800,9 +3202,9 @@ var HeadlessClaudeCodeRuntime = class _HeadlessClaudeCodeRuntime extends OneShot
1800
3202
  }
1801
3203
  async produce(run, signal) {
1802
3204
  const { request } = run;
1803
- const dir = join4(runsDirOf(this.h.root), request.change, run.runId);
3205
+ const dir = join5(runsDirOf(this.h.root), request.change, run.runId);
1804
3206
  const reviewer = request.agent.outputArtifact === "findings" && request.outputIn === "run";
1805
- const work = reviewer ? await mkdtemp(join4(tmpdir(), "atticus-review-")) : void 0;
3207
+ const work = reviewer ? await mkdtemp(join5(tmpdir(), "atticus-review-")) : void 0;
1806
3208
  const clones = work ? await existingDirs(cloneDirs(this.h.root)) : [];
1807
3209
  const base = work ? {
1808
3210
  cwd: work,
@@ -1816,27 +3218,27 @@ var HeadlessClaudeCodeRuntime = class _HeadlessClaudeCodeRuntime extends OneShot
1816
3218
  `Bash(${request.selfCheck.command}:*)`
1817
3219
  ]
1818
3220
  } : base;
1819
- await mkdir4(dir, { recursive: true });
1820
- const promptFile = join4(dir, "prompt.md");
3221
+ await mkdir5(dir, { recursive: true });
3222
+ const promptFile = join5(dir, "prompt.md");
1821
3223
  const self = reviewer ? void 0 : request.selfCheck;
1822
3224
  const handoff = HandoffRuntime.promptFor(run, changesRelOf(this.h.root), runsRelOf(this.h.root)).replace(/\nWhen the file is complete.*\n$/s, "\n") + // W3a: the drafter checks its own file with the stage's checks before it finishes.
1823
3225
  (self ? `
1824
3226
  Before you finish, check the file: run ${self.command} ${HandoffRuntime.outputRel(run, changesRelOf(this.h.root), runsRelOf(this.h.root))}. Fix each problem it lists and run it again, until it says the file is clean (at most ${self.limit} times).
1825
3227
  ` : "");
1826
3228
  const prompt = reviewer ? handoff.replace(`Write the result to ${HandoffRuntime.outputRel(run, changesRelOf(this.h.root), runsRelOf(this.h.root))}.`, `Write the result to ${request.outputPath}.${clones.length ? ` The metarepo is at ${this.h.root}: a folder named relative to the metarepo (the repos' clones under workspace/) is there, to read, never to edit.` : ""}`) : handoff;
1827
- await writeFile4(promptFile, prompt, "utf8");
1828
- await writeFile4(join4(dir, "context-manifest.json"), JSON.stringify(request.pack.manifest, null, 2) + "\n", "utf8");
1829
- if (!await stat2(inv.cwd).catch(() => void 0))
3229
+ await writeFile5(promptFile, prompt, "utf8");
3230
+ await writeFile5(join5(dir, "context-manifest.json"), JSON.stringify(request.pack.manifest, null, 2) + "\n", "utf8");
3231
+ if (!await stat3(inv.cwd).catch(() => void 0))
1830
3232
  throw new RuntimeError(`the worktree ${inv.cwd} doesn't exist`);
1831
- const outputFile = work ? join4(work, request.outputPath) : request.outputIn === "run" ? join4(dir, request.outputPath) : join4(changesDirOf(this.h.root), request.change, request.outputPath);
3233
+ const outputFile = work ? join5(work, request.outputPath) : request.outputIn === "run" ? join5(dir, request.outputPath) : join5(changesDirOf(this.h.root), request.change, request.outputPath);
1832
3234
  try {
1833
3235
  return await this.runIn(run, dir, inv, prompt, promptFile, outputFile, signal);
1834
3236
  } finally {
1835
3237
  if (work) {
1836
- const kept = await readFile4(outputFile, "utf8").catch(() => void 0);
3238
+ const kept = await readFile5(outputFile, "utf8").catch(() => void 0);
1837
3239
  if (kept !== void 0) {
1838
- await mkdir4(dirname(join4(dir, request.outputPath)), { recursive: true });
1839
- await writeFile4(join4(dir, request.outputPath), kept, "utf8");
3240
+ await mkdir5(dirname2(join5(dir, request.outputPath)), { recursive: true });
3241
+ await writeFile5(join5(dir, request.outputPath), kept, "utf8");
1840
3242
  }
1841
3243
  await rm2(work, { recursive: true, force: true, maxRetries: 5 }).catch(() => void 0);
1842
3244
  }
@@ -1844,7 +3246,7 @@ Before you finish, check the file: run ${self.command} ${HandoffRuntime.outputRe
1844
3246
  }
1845
3247
  async runIn(run, dir, inv, prompt, promptFile, outputFile, signal) {
1846
3248
  const { request } = run;
1847
- const before = (await stat2(outputFile).catch(() => void 0))?.mtimeMs;
3249
+ const before = (await stat3(outputFile).catch(() => void 0))?.mtimeMs;
1848
3250
  const res = await this.runner({
1849
3251
  cwd: inv.cwd,
1850
3252
  prompt,
@@ -1860,7 +3262,7 @@ Before you finish, check the file: run ${self.command} ${HandoffRuntime.outputRe
1860
3262
  timeoutMs: this.h.timeoutMs ?? 30 * 6e4,
1861
3263
  ...signal ? { signal } : {}
1862
3264
  });
1863
- await writeFile4(join4(dir, "claude-output.json"), res.stdout, "utf8");
3265
+ await writeFile5(join5(dir, "claude-output.json"), res.stdout, "utf8");
1864
3266
  let parsed;
1865
3267
  try {
1866
3268
  parsed = JSON.parse(res.stdout);
@@ -1870,8 +3272,8 @@ Before you finish, check the file: run ${self.command} ${HandoffRuntime.outputRe
1870
3272
  const text = typeof parsed.result === "string" ? parsed.result : "";
1871
3273
  if (res.exitCode !== 0 || parsed.is_error === true)
1872
3274
  throw new RuntimeError(`Claude Code reported a failure: ${text || res.stderr.trim()}`);
1873
- const after = (await stat2(outputFile).catch(() => void 0))?.mtimeMs;
1874
- const written = after !== void 0 && after !== before ? await readFile4(outputFile, "utf8") : void 0;
3275
+ const after = (await stat3(outputFile).catch(() => void 0))?.mtimeMs;
3276
+ const written = after !== void 0 && after !== before ? await readFile5(outputFile, "utf8") : void 0;
1875
3277
  return {
1876
3278
  output: written ?? text,
1877
3279
  usage: {
@@ -1916,6 +3318,10 @@ var toolSource;
1916
3318
  function registerToolSource(source) {
1917
3319
  toolSource = source;
1918
3320
  }
3321
+ var acpRunner;
3322
+ function registerCopilotAcp(o) {
3323
+ acpRunner = o;
3324
+ }
1919
3325
  function classModels(rt, o) {
1920
3326
  const by = modelsByClass(rt, o.env ?? {});
1921
3327
  const out = {};
@@ -1937,17 +3343,19 @@ function classModels(rt, o) {
1937
3343
  }
1938
3344
  var told = /* @__PURE__ */ new WeakMap();
1939
3345
  var nonEmpty = async (file, request) => {
1940
- const text = await readFile4(file, "utf8").catch(() => "");
3346
+ const text = await readFile5(file, "utf8").catch(() => "");
1941
3347
  return text.trim() ? [] : [`${request.outputPath} is empty`];
1942
3348
  };
1943
3349
  async function createRuntime(orgPack, o) {
1944
3350
  const rt = orgPack.runtime;
1945
- const mode = o.mode ?? rt.modes.default;
3351
+ const asked = o.mode ?? rt.modes.default;
3352
+ const inSession = !!(o.env ?? process.env).ATTICUS_ACP_SESSION;
3353
+ const mode = asked === "copilot-acp" && inSession ? "hand-off" : asked;
1946
3354
  if (!RUNTIME_MODES.includes(mode))
1947
3355
  throw new RuntimeConfigError(`There is no AI mode called ${String(mode)}. Use one of: ${RUNTIME_MODES.join(", ")}.`);
1948
3356
  if (rt.ai === "off" && CONFIGURED.includes(mode))
1949
3357
  throw new AiOffError();
1950
- if (CONFIGURED.includes(mode) && !rt.modes.allowed.includes(mode))
3358
+ if (CONFIGURED.includes(mode) && !rt.modes.allowed.includes(mode) && !(inSession && asked === "copilot-acp"))
1951
3359
  throw new RuntimeConfigError(`runtime.yaml doesn't allow ${mode} mode (allowed: ${rt.modes.allowed.join(", ")}). Change modes.allowed in a pull request, or pick an allowed mode.`);
1952
3360
  const one = { ...o.now ? { now: o.now } : {}, ...o.validate ? { validate: o.validate } : {} };
1953
3361
  switch (mode) {
@@ -1955,7 +3363,9 @@ async function createRuntime(orgPack, o) {
1955
3363
  return new HandoffRuntime({
1956
3364
  root: o.root,
1957
3365
  validate: o.handoffValidate ?? nonEmpty,
1958
- ...o.now ? { now: o.now } : {}
3366
+ ...o.now ? { now: o.now } : {},
3367
+ // ADR 0185: a stage's critic lenses go to the person's assistant in one prompt.
3368
+ batch: true
1959
3369
  });
1960
3370
  case "model": {
1961
3371
  const cfg = rt.adapters.model;
@@ -1995,6 +3405,22 @@ async function createRuntime(orgPack, o) {
1995
3405
  ...o.validate ? { validate: o.validate } : {}
1996
3406
  });
1997
3407
  }
3408
+ case "copilot-acp": {
3409
+ if (!rt.assistants.allowed.includes("copilot"))
3410
+ throw new RuntimeConfigError("copilot-acp drives GitHub Copilot, which runtime.yaml doesn't list under assistants.allowed.");
3411
+ const c = copilotAcpOf(rt);
3412
+ return new CopilotAcpRuntime({
3413
+ root: o.root,
3414
+ command: c.command,
3415
+ ...c.model ? { model: c.model } : {},
3416
+ maxTurns: c.maxTurns,
3417
+ timeoutMs: c.timeoutMs,
3418
+ ...acpRunner,
3419
+ ...o.copilotAcp,
3420
+ ...o.now ? { now: o.now } : {},
3421
+ ...o.validate ? { validate: o.validate } : {}
3422
+ });
3423
+ }
1998
3424
  case "replay":
1999
3425
  if (o.recordings)
2000
3426
  return new ReplayRuntime(o.recordings, one);
@@ -2011,13 +3437,13 @@ var sayOnce = (line) => process.stderr.write(`${line}
2011
3437
  `);
2012
3438
  async function runtimeForCli(root, o = {}) {
2013
3439
  const env = o.env ?? process.env;
2014
- const op = await loadOrgPack(join4(orgPackDirOf(root)));
3440
+ const op = await loadOrgPack(join5(orgPackDirOf(root)));
2015
3441
  const bad = op.problems.filter((p) => p.file === "runtime.yaml");
2016
3442
  if (bad.length)
2017
3443
  throw new RuntimeConfigError(`org-pack/runtime.yaml has problems: ${bad.map((p) => `${p.path ? `${p.path}: ` : ""}${p.message}`).join("; ")}`);
2018
3444
  const asked = o.mode ?? env.ATTICUS_RUNTIME ?? op.runtime.modes.default;
2019
3445
  if (asked === "mock")
2020
- throw new RuntimeConfigError("Mock mode is for tests; use hand-off, model, headless-claude-code or replay.");
3446
+ throw new RuntimeConfigError("Mock mode is for tests; use hand-off, model, headless-claude-code, copilot-acp or replay.");
2021
3447
  const mode = asked;
2022
3448
  const runtime = await createRuntime(op, {
2023
3449
  root,
@@ -2025,13 +3451,14 @@ async function runtimeForCli(root, o = {}) {
2025
3451
  ...env.ATTICUS_REPLAY_DIR ? { replayDir: env.ATTICUS_REPLAY_DIR } : {},
2026
3452
  ...o.providers ? { providers: o.providers } : {},
2027
3453
  ...o.headless ? { headless: o.headless } : {},
3454
+ ...o.copilotAcp ? { copilotAcp: o.copilotAcp } : {},
2028
3455
  ...o.handoffValidate ? { handoffValidate: o.handoffValidate } : {},
2029
3456
  // ADR 0121 addendum: the person's model per kind of step, and a model passed over said once.
2030
3457
  env,
2031
3458
  onNote: o.onNote ?? sayOnce
2032
3459
  });
2033
- const describe = mode === "hand-off" ? "AI steps are handed to your assistant: Atticus writes the prompt and waits for atticus handoff done." : mode === "model" ? `AI steps call the ${op.runtime.adapters.model?.type ?? "configured"} model directly.` : mode === "headless-claude-code" ? "AI steps run in headless Claude Code." : "AI steps replay recorded answers.";
2034
- return { runtime, mode, describe };
3460
+ const describe = runtime.kind === "hand-off" ? "AI steps are handed to your assistant: Atticus writes the prompt and waits for atticus handoff done." : mode === "model" ? `AI steps call the ${op.runtime.adapters.model?.type ?? "configured"} model directly.` : mode === "headless-claude-code" ? "AI steps run in headless Claude Code." : mode === "copilot-acp" ? "AI steps run in GitHub Copilot, unattended, one new session each (copilot-acp)." : "AI steps replay recorded answers.";
3461
+ return { runtime, mode: runtime.kind === "hand-off" ? "hand-off" : mode, describe };
2035
3462
  }
2036
3463
 
2037
3464
  // packages/ai/dist/attempts.js
@@ -2127,8 +3554,8 @@ var HashEmbedder = class {
2127
3554
  return { i: h.readUInt32BE(0) % this.dim, sign: h[4] & 1 ? 1 : -1 };
2128
3555
  };
2129
3556
  for (const m of text.matchAll(/[A-Za-z0-9]+/g)) {
2130
- const words = [m[0].toLowerCase(), ...identifierWords(m[0])];
2131
- for (const w of new Set(words)) {
3557
+ const words2 = [m[0].toLowerCase(), ...identifierWords(m[0])];
3558
+ for (const w of new Set(words2)) {
2132
3559
  if (w.length < 3)
2133
3560
  continue;
2134
3561
  const b = bucket(`w:${w}`);
@@ -2618,6 +4045,9 @@ function recordedJudge(byTexts, o = {}) {
2618
4045
  }
2619
4046
 
2620
4047
  export {
4048
+ personOnlyWhy,
4049
+ isPersonsFactsFile,
4050
+ windowsName,
2621
4051
  DEFENCES_VERSION,
2622
4052
  INSTRUCTION_RULES,
2623
4053
  riskAtLeast,
@@ -2683,12 +4113,45 @@ export {
2683
4113
  recordRun,
2684
4114
  MockModelProvider,
2685
4115
  ModelRuntime,
4116
+ BATCH_OUTPUT,
4117
+ DEFAULT_BATCH_MAX_TOKENS,
4118
+ batchSections,
2686
4119
  HandoffRuntime,
2687
4120
  pruneRuns,
4121
+ ACP_PROTOCOL_VERSION,
4122
+ ACP_METHODS,
4123
+ ACP_ERRORS,
4124
+ AcpRpcError,
4125
+ AcpClient,
4126
+ chunkText,
4127
+ UPDATE,
4128
+ usageOf,
4129
+ isAuthRequired,
4130
+ commandLineOf,
4131
+ atticusArgvOf,
4132
+ acpPathsOf,
4133
+ factsOnly,
4134
+ readRootsOf,
4135
+ needsShell,
4136
+ quoteForCmd,
4137
+ killTree,
4138
+ spawnAcpServer,
4139
+ atticusExec,
4140
+ AcpSignInError,
4141
+ AcpSetupError,
4142
+ MAX_NUDGES,
4143
+ carryOnPrompt,
4144
+ ACP_OFFERED,
4145
+ runAcpSession,
4146
+ copilotAcpProbe,
4147
+ CopilotAcpRuntime,
4148
+ keepAcpRun,
2688
4149
  RUNTIME_MODES,
2689
4150
  RuntimeConfigError,
2690
4151
  AiOffError,
2691
4152
  claudeCodeCliRunner,
4153
+ resolveWindowsCommand,
4154
+ quoteForCmdAlways,
2692
4155
  collectChild,
2693
4156
  posixPath,
2694
4157
  HeadlessClaudeCodeRuntime,
@@ -2699,6 +4162,7 @@ export {
2699
4162
  registeredModelProviders,
2700
4163
  clearModelProviders,
2701
4164
  registerToolSource,
4165
+ registerCopilotAcp,
2702
4166
  createRuntime,
2703
4167
  runtimeForCli,
2704
4168
  resumedAttempt,