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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/dist/bin.js +8 -4
  2. package/dist/chunk-23XVSEV5.js +49 -0
  3. package/dist/{chunk-ZDPAS56H.js → chunk-24OXGB3P.js} +8 -2
  4. package/dist/{chunk-7EOBHUMC.js → chunk-24XLDU72.js} +4 -3
  5. package/dist/{chunk-CR3MTH32.js → chunk-2F4CYZKJ.js} +86 -11
  6. package/dist/{chunk-6IU67AEK.js → chunk-2GF7OLF3.js} +23 -15
  7. package/dist/chunk-2IIMFOPM.js +41 -0
  8. package/dist/chunk-2LGRMVCA.js +617 -0
  9. package/dist/{chunk-XPCM366L.js → chunk-2MMCFP5C.js} +10 -8
  10. package/dist/{chunk-JBTK5OP2.js → chunk-2Q56PQPS.js} +6 -4
  11. package/dist/{chunk-Z6LF7HQN.js → chunk-2Q5EDGEO.js} +7 -5
  12. package/dist/{chunk-3USYZGRF.js → chunk-2RLKFUUL.js} +38 -27
  13. package/dist/chunk-2SKB4O2E.js +59 -0
  14. package/dist/{chunk-SP2I63OO.js → chunk-34S2WGOB.js} +87 -4
  15. package/dist/{chunk-GQ4N4WKF.js → chunk-3NFFJL5D.js} +33 -27
  16. package/dist/{chunk-SJRGMG6A.js → chunk-3NWDLGG6.js} +28 -25
  17. package/dist/{chunk-4WBVUHXN.js → chunk-3RM4UK6W.js} +20 -18
  18. package/dist/chunk-42SIDKEU.js +583 -0
  19. package/dist/{chunk-GLUX4EEP.js → chunk-4EURQWQD.js} +20 -15
  20. package/dist/chunk-4U276ICE.js +39 -0
  21. package/dist/{chunk-ZMFPW66A.js → chunk-53T4O55J.js} +4 -3
  22. package/dist/{chunk-6J5OKA4Y.js → chunk-57TDNMI3.js} +17 -15
  23. package/dist/chunk-5BD2KYLE.js +57 -0
  24. package/dist/{chunk-7EFILTCI.js → chunk-5F7GFN2F.js} +28 -0
  25. package/dist/chunk-5NMKONLP.js +95 -0
  26. package/dist/{chunk-7ZUIMTOU.js → chunk-5SJZW52K.js} +26 -24
  27. package/dist/{chunk-4RS5KZQD.js → chunk-63YRMR6J.js} +6 -5
  28. package/dist/chunk-66PPNOON.js +62 -0
  29. package/dist/chunk-6H3Z5JHH.js +64 -0
  30. package/dist/{chunk-CEXSU4S6.js → chunk-6MUGR4LS.js} +775 -89
  31. package/dist/{chunk-QSXK2RGH.js → chunk-6OJQOPUN.js} +5 -3
  32. package/dist/{chunk-MVZVGYXH.js → chunk-6PPOWY5E.js} +84 -14
  33. package/dist/{chunk-7EKXJZ2Y.js → chunk-6ZGLAACW.js} +299 -38
  34. package/dist/chunk-6ZJ5A7AF.js +222 -0
  35. package/dist/{chunk-L24C55VN.js → chunk-745DAZ4L.js} +142 -30
  36. package/dist/{chunk-Q4D5X7QB.js → chunk-7ASNL4Q4.js} +46 -24
  37. package/dist/chunk-7BR7IPOH.js +35 -0
  38. package/dist/{chunk-7WD63HU2.js → chunk-7DOR27HL.js} +6 -6
  39. package/dist/chunk-7FTTA3HD.js +341 -0
  40. package/dist/{chunk-OLQJTJJU.js → chunk-7GJS6DNX.js} +12 -3
  41. package/dist/{chunk-7JUKDRSZ.js → chunk-7IGKHZ4Z.js} +347 -226
  42. package/dist/{chunk-G2B4ZQGH.js → chunk-7IOWA5D5.js} +11 -6
  43. package/dist/{chunk-EBEW3XXQ.js → chunk-7JITZFJC.js} +7 -5
  44. package/dist/chunk-7MJSQTL5.js +174 -0
  45. package/dist/{chunk-I4JRCD6M.js → chunk-7UOMVMFG.js} +25 -17
  46. package/dist/{chunk-YY6ZQQBP.js → chunk-AFWUDXEM.js} +19 -7
  47. package/dist/chunk-AFZ3QA6W.js +47 -0
  48. package/dist/chunk-AJQ72EBM.js +420 -0
  49. package/dist/chunk-AJYXNTNZ.js +317 -0
  50. package/dist/chunk-AVTBS4OW.js +49 -0
  51. package/dist/{chunk-FHH4I4ZV.js → chunk-BDKC6H5P.js} +12 -6
  52. package/dist/{chunk-IPKHE5D6.js → chunk-BEVTIBRH.js} +1526 -875
  53. package/dist/chunk-BHT7QK4G.js +162 -0
  54. package/dist/{chunk-6JUBZBMW.js → chunk-BIGDQDHD.js} +6 -4
  55. package/dist/{chunk-2BFCZ3RK.js → chunk-BO4KX37X.js} +20 -18
  56. package/dist/chunk-BPK5P77O.js +115 -0
  57. package/dist/chunk-BQ4SQQC6.js +59 -0
  58. package/dist/chunk-BQGDB6ZL.js +7342 -0
  59. package/dist/{chunk-2ANOROX3.js → chunk-BTGPE6CR.js} +11 -9
  60. package/dist/chunk-BTY3HZBO.js +93 -0
  61. package/dist/{chunk-DPZHZQKE.js → chunk-BXYMYEJ4.js} +44 -10
  62. package/dist/{chunk-2RMYG36Q.js → chunk-C3RY6KU6.js} +309 -346
  63. package/dist/chunk-C4R4JLHE.js +40 -0
  64. package/dist/chunk-CADWLE2T.js +18 -0
  65. package/dist/chunk-CBGGOQWU.js +82 -0
  66. package/dist/chunk-CMDXGQTS.js +47 -0
  67. package/dist/{chunk-MC3H7736.js → chunk-CQDGOPGH.js} +58 -18
  68. package/dist/{chunk-HFQCFSJR.js → chunk-CX4RZ2KS.js} +4 -3
  69. package/dist/{chunk-PAMPPUR6.js → chunk-CXJ6FUKN.js} +1852 -207
  70. package/dist/{chunk-ABWHYWNI.js → chunk-D73UEXYW.js} +3 -3
  71. package/dist/chunk-DCZWQLYT.js +1205 -0
  72. package/dist/chunk-DLOBCJL6.js +48 -0
  73. package/dist/{chunk-4BN53TG3.js → chunk-DOBQKHIF.js} +31 -23
  74. package/dist/chunk-E3ISYXO3.js +423 -0
  75. package/dist/{chunk-7SW2QWLU.js → chunk-E6ZIEVOI.js} +16 -13
  76. package/dist/chunk-EBL2R3YG.js +43 -0
  77. package/dist/{chunk-AIOQPLA5.js → chunk-EGQRREQH.js} +41 -15
  78. package/dist/chunk-EHA7RMZ3.js +58 -0
  79. package/dist/{chunk-M766ZJ6W.js → chunk-EIPTLPFC.js} +38 -27
  80. package/dist/chunk-EMRIQUND.js +517 -0
  81. package/dist/{chunk-DFBCSHVT.js → chunk-EPCJQQWD.js} +6 -4
  82. package/dist/{chunk-RZPYKDWS.js → chunk-F3P7N7SF.js} +1 -1
  83. package/dist/{chunk-R77KLRB3.js → chunk-FFLNS6VP.js} +21 -18
  84. package/dist/chunk-FFTRTL6R.js +26 -0
  85. package/dist/{chunk-IHMLFRVV.js → chunk-FPJPLKDW.js} +62 -16
  86. package/dist/{chunk-JCZIKA4C.js → chunk-FSMSFDLD.js} +5 -4
  87. package/dist/{chunk-AVJDSJ2F.js → chunk-FUJM6RTF.js} +8 -7
  88. package/dist/chunk-FZOJFH7Q.js +132 -0
  89. package/dist/{chunk-QRAOANID.js → chunk-G6X77UJZ.js} +23 -21
  90. package/dist/{chunk-3ALD2W2A.js → chunk-GCWRWSU7.js} +10 -4
  91. package/dist/chunk-GIW4ZVDB.js +39 -0
  92. package/dist/{chunk-B2WLAWNJ.js → chunk-GUX3PTYM.js} +3 -3
  93. package/dist/{chunk-DPUYDDQG.js → chunk-GZY6RUZ6.js} +25 -3
  94. package/dist/chunk-H4VO6WG3.js +10 -0
  95. package/dist/{chunk-MMOSZPWJ.js → chunk-H5HBGNXU.js} +5 -4
  96. package/dist/chunk-H7KM7LZE.js +229 -0
  97. package/dist/{chunk-AA6YULYB.js → chunk-HNM2YQT2.js} +7 -7
  98. package/dist/{chunk-3C7EYRFZ.js → chunk-HYU5VLGA.js} +1 -1
  99. package/dist/{chunk-XY3P7JW7.js → chunk-IDKCWSM5.js} +1032 -172
  100. package/dist/chunk-IFKEI4SA.js +237 -0
  101. package/dist/{chunk-F7HYOUFF.js → chunk-IGOE6KPG.js} +67 -22
  102. package/dist/{chunk-TDD55CJH.js → chunk-IH2XURVQ.js} +6 -5
  103. package/dist/chunk-INQHESFB.js +38 -0
  104. package/dist/chunk-IP74LCOQ.js +57 -0
  105. package/dist/chunk-IPHHDDC6.js +45 -0
  106. package/dist/{chunk-T6AIP7H5.js → chunk-ISUAAMGS.js} +110 -153
  107. package/dist/{chunk-A7UPUQFY.js → chunk-IUPG3UKI.js} +624 -319
  108. package/dist/{chunk-L6SGQIR3.js → chunk-IVBOQAGB.js} +7 -3
  109. package/dist/{chunk-27NKUS3X.js → chunk-J2JAKCIW.js} +2205 -796
  110. package/dist/{chunk-V2YTAIQO.js → chunk-J3IOLXWM.js} +24 -7
  111. package/dist/chunk-JA5FI3QV.js +142 -0
  112. package/dist/chunk-JAVI7JSP.js +49 -0
  113. package/dist/{chunk-HLJAXMM4.js → chunk-JB5LINEM.js} +6 -2
  114. package/dist/{chunk-2VHF7OXM.js → chunk-JENSEMXF.js} +1 -1
  115. package/dist/{chunk-6BVONWJ7.js → chunk-JJF6HALY.js} +4 -3
  116. package/dist/chunk-JLUCKAEL.js +38 -0
  117. package/dist/chunk-JRBFANFE.js +221 -0
  118. package/dist/{chunk-R6XF6UR3.js → chunk-KDNTAPLX.js} +4 -4
  119. package/dist/chunk-KFAVQZSX.js +33 -0
  120. package/dist/chunk-KJXD4PNL.js +50 -0
  121. package/dist/chunk-KN5BXMWN.js +44 -0
  122. package/dist/{chunk-PCVDV3UZ.js → chunk-KQGURXFU.js} +9 -7
  123. package/dist/{chunk-WY6PP6AA.js → chunk-KXITGYLF.js} +40 -6
  124. package/dist/{chunk-66YVAGGM.js → chunk-L27SV425.js} +22 -20
  125. package/dist/{chunk-NE2W3OO7.js → chunk-LDLL7LB3.js} +24 -22
  126. package/dist/chunk-LFGTYX5U.js +379 -0
  127. package/dist/{chunk-EYWIDJFU.js → chunk-LGBMTVNT.js} +7 -5
  128. package/dist/{chunk-Q5AMFEWD.js → chunk-LGFL54FP.js} +3 -2
  129. package/dist/{chunk-6TACQN3N.js → chunk-LJXMYKZJ.js} +7 -5
  130. package/dist/{chunk-BKVWTZ6A.js → chunk-LKOR5UET.js} +29 -26
  131. package/dist/chunk-LNBQOP7D.js +294 -0
  132. package/dist/{chunk-O3WI5KWW.js → chunk-LO6P2VYG.js} +2 -2
  133. package/dist/chunk-LQJPN536.js +122 -0
  134. package/dist/{chunk-YEDDOYSC.js → chunk-LYBNHMVZ.js} +29 -5
  135. package/dist/{chunk-A3GY6SOA.js → chunk-LZ7NUC62.js} +20 -18
  136. package/dist/chunk-M32BLWDH.js +37 -0
  137. package/dist/{chunk-VYDBJ73M.js → chunk-M3NANSDZ.js} +17 -15
  138. package/dist/chunk-MFHL5URL.js +31 -0
  139. package/dist/chunk-MFR5OPBD.js +109 -0
  140. package/dist/{chunk-DE76JROX.js → chunk-MG4ZL5RW.js} +32 -20
  141. package/dist/{chunk-N7IXEHK3.js → chunk-MO6P2JZH.js} +10 -8
  142. package/dist/{chunk-65NYPGRC.js → chunk-MUWDB4R4.js} +1 -1
  143. package/dist/chunk-MZCGSXVR.js +34 -0
  144. package/dist/{chunk-MGYZM27B.js → chunk-N3XIYPU3.js} +51 -23
  145. package/dist/chunk-NDCF4R6S.js +172 -0
  146. package/dist/{chunk-DHPACDG7.js → chunk-NR2UJWOC.js} +10 -8
  147. package/dist/chunk-NXJ5URP6.js +51 -0
  148. package/dist/{chunk-UNM6ZOKP.js → chunk-NY2XSR5K.js} +147 -18
  149. package/dist/{chunk-5GDRCDQB.js → chunk-O45HFTFS.js} +3 -2
  150. package/dist/{chunk-ONLS5QA5.js → chunk-O4GXGGBX.js} +14 -12
  151. package/dist/chunk-O5PXQR67.js +249 -0
  152. package/dist/{chunk-PRPPGYZG.js → chunk-O66DM6DJ.js} +6 -4
  153. package/dist/{chunk-KEM4SDDP.js → chunk-O7FDLW7L.js} +11 -8
  154. package/dist/{chunk-T2UYZSCQ.js → chunk-O7XLYEFA.js} +169 -29
  155. package/dist/{chunk-FITWGOJ2.js → chunk-OHNCWBKF.js} +4 -4
  156. package/dist/{chunk-652QWTLZ.js → chunk-OHVTTOPS.js} +3 -3
  157. package/dist/chunk-OMI6FPPN.js +43 -0
  158. package/dist/chunk-ONUPY3H6.js +53 -0
  159. package/dist/chunk-OTLDSZDV.js +69 -0
  160. package/dist/chunk-OUBGGKDU.js +22 -0
  161. package/dist/chunk-OWNCM4ZN.js +330 -0
  162. package/dist/{chunk-YISXLPHN.js → chunk-P2V7QW4D.js} +235 -35
  163. package/dist/{chunk-CNUKCS2T.js → chunk-P32RUW3B.js} +1632 -93
  164. package/dist/{chunk-BWZ77RQT.js → chunk-PAQ2AS5E.js} +1 -1
  165. package/dist/{chunk-ZMAINWBW.js → chunk-PBPBMP2B.js} +4 -3
  166. package/dist/{chunk-ZVM6AKKM.js → chunk-PJSJPMJI.js} +3 -3
  167. package/dist/{chunk-EFHQ3TWP.js → chunk-PKBHS4AA.js} +233 -56
  168. package/dist/{chunk-GT4I4ZWM.js → chunk-PMUAJGLI.js} +20 -16
  169. package/dist/chunk-PPD7HTDP.js +152 -0
  170. package/dist/chunk-PSOFBQWB.js +42 -0
  171. package/dist/{chunk-S2A7YC3Q.js → chunk-Q2TECDIT.js} +10694 -8896
  172. package/dist/chunk-Q4K5WB2W.js +42 -0
  173. package/dist/{chunk-UGLN7QHV.js → chunk-Q6DFNVRJ.js} +14 -12
  174. package/dist/chunk-QA4O2GGC.js +265 -0
  175. package/dist/chunk-QAXW2N3B.js +1216 -0
  176. package/dist/chunk-QBNWF5ZU.js +19 -0
  177. package/dist/chunk-QFWA2DPH.js +224 -0
  178. package/dist/{chunk-23W7VWKR.js → chunk-QKUJMING.js} +1363 -114
  179. package/dist/{chunk-NXFPS2LR.js → chunk-R44CYFPV.js} +16 -13
  180. package/dist/{chunk-CKSITVS4.js → chunk-R7NYHMUU.js} +2687 -786
  181. package/dist/chunk-REWWDVQB.js +162 -0
  182. package/dist/{chunk-JMSCMUCA.js → chunk-RGERPOIV.js} +145 -21
  183. package/dist/{chunk-6JCPI55B.js → chunk-RLDGWLQ7.js} +49 -7
  184. package/dist/chunk-RUGXBPWI.js +384 -0
  185. package/dist/{chunk-CPA6HPVR.js → chunk-RXPJMEOW.js} +18 -12
  186. package/dist/{chunk-3HI6Z55Y.js → chunk-S4PMJU6H.js} +339 -43
  187. package/dist/chunk-S5LSDXV4.js +40 -0
  188. package/dist/chunk-S7FCV7S5.js +51 -0
  189. package/dist/{chunk-5GGOLAKC.js → chunk-SDKLKB6I.js} +28 -26
  190. package/dist/chunk-SFSPGFCV.js +62 -0
  191. package/dist/{chunk-ZNCEKR4J.js → chunk-SFUP7TTO.js} +12 -8
  192. package/dist/{chunk-64EQYWCA.js → chunk-SLXZOMA6.js} +69 -19
  193. package/dist/chunk-SQV37XO2.js +273 -0
  194. package/dist/{chunk-K65BJIMT.js → chunk-SU74NDMQ.js} +19 -17
  195. package/dist/chunk-SYV5LHML.js +165 -0
  196. package/dist/chunk-T4YPZIQN.js +36 -0
  197. package/dist/chunk-T6DQR5TV.js +323 -0
  198. package/dist/{chunk-JIITQXFB.js → chunk-THDMSZ3R.js} +3075 -802
  199. package/dist/{chunk-JGZCG5VM.js → chunk-TNR75OXT.js} +7 -7
  200. package/dist/{chunk-D3PO4DOZ.js → chunk-TUULXQRW.js} +174 -15
  201. package/dist/chunk-TYQBFTBR.js +516 -0
  202. package/dist/chunk-U76OWS3Q.js +49 -0
  203. package/dist/{chunk-YYQN46FY.js → chunk-UCROWG2D.js} +27 -24
  204. package/dist/{chunk-6M5NK3K3.js → chunk-UF4AZOZB.js} +50 -10
  205. package/dist/chunk-UF4GLFBX.js +345 -0
  206. package/dist/{chunk-OT2O76OS.js → chunk-UGUP3ZM6.js} +240 -39
  207. package/dist/chunk-UNAGJYET.js +45 -0
  208. package/dist/{chunk-5WG5YP4T.js → chunk-UOR2DTHH.js} +16 -14
  209. package/dist/{chunk-S3QNRWYR.js → chunk-UPOY4YSQ.js} +14 -12
  210. package/dist/{chunk-EPTBZ3GP.js → chunk-UPS2DGFC.js} +1 -1
  211. package/dist/{chunk-4AK7IBVP.js → chunk-UUU4CLJG.js} +4 -2
  212. package/dist/{chunk-W3BQAZ3Q.js → chunk-UWMJKX5U.js} +14 -12
  213. package/dist/{chunk-QZSX3F7C.js → chunk-UWOJLHFT.js} +27 -23
  214. package/dist/chunk-VBTP56CE.js +535 -0
  215. package/dist/chunk-VCTWPLAO.js +211 -0
  216. package/dist/chunk-VNU26RCO.js +1215 -0
  217. package/dist/{chunk-CSZ4C5N6.js → chunk-VTZMAJ3W.js} +93 -10
  218. package/dist/{chunk-TXLH6WHQ.js → chunk-VW62D6QE.js} +14 -12
  219. package/dist/{chunk-CAQZUNOH.js → chunk-VY72R2XZ.js} +610 -3
  220. package/dist/{chunk-2DIQQJCB.js → chunk-VZALIKIF.js} +18 -15
  221. package/dist/{chunk-TYAID7B7.js → chunk-W62H2XSO.js} +25 -23
  222. package/dist/{chunk-HVUPKCGJ.js → chunk-W7VWI2YH.js} +9 -6
  223. package/dist/{chunk-TANFV3MZ.js → chunk-WERM6KPJ.js} +7 -4
  224. package/dist/{chunk-BOHJZTEQ.js → chunk-WF7B67YE.js} +208 -87
  225. package/dist/{chunk-7FBGJFEE.js → chunk-WG5U3F5V.js} +14 -12
  226. package/dist/{chunk-4NDAAFQT.js → chunk-WJF2CS6M.js} +8 -5
  227. package/dist/{chunk-XAKWMCXI.js → chunk-WKUJ3KPV.js} +4 -4
  228. package/dist/chunk-WMTRHUI5.js +103 -0
  229. package/dist/chunk-WNKPRSGI.js +36 -0
  230. package/dist/chunk-WXFLMQSR.js +223 -0
  231. package/dist/{chunk-RRTKKSLQ.js → chunk-X3WY6MN3.js} +8 -6
  232. package/dist/{chunk-ZCJDOK2S.js → chunk-X4CXA2IL.js} +47 -23
  233. package/dist/{chunk-UBBC2XSG.js → chunk-X5F3Q5LV.js} +560 -105
  234. package/dist/{chunk-C6EKFH7J.js → chunk-XD75VZIH.js} +9 -7
  235. package/dist/chunk-XERYFDB5.js +297 -0
  236. package/dist/chunk-XI2LCCYQ.js +420 -0
  237. package/dist/chunk-Y2EQNWKV.js +933 -0
  238. package/dist/{chunk-LR3R6Z2A.js → chunk-YHCMZC2J.js} +7 -7
  239. package/dist/chunk-YYY3AZFE.js +122 -0
  240. package/dist/{chunk-GDLULHTC.js → chunk-Z5IA3WDR.js} +19 -31
  241. package/dist/{chunk-T6XQL73F.js → chunk-ZFFYNRIO.js} +63 -23
  242. package/dist/{chunk-EDS2L2LD.js → chunk-ZFL7NY4F.js} +56 -27
  243. package/dist/{chunk-YMZ3TNYB.js → chunk-ZGULQAPZ.js} +7 -4
  244. package/dist/{chunk-4SKZDI62.js → chunk-ZIUFM5HT.js} +3 -1
  245. package/dist/{chunk-DKJA76CJ.js → chunk-ZJFRMSJT.js} +15 -13
  246. package/dist/chunk-ZJXLNDH4.js +239 -0
  247. package/dist/chunk-ZQ3ON2VQ.js +252 -0
  248. package/dist/{chunk-HITVBIJS.js → chunk-ZQ7SKESZ.js} +150 -415
  249. package/dist/{chunk-6QSERWXH.js → chunk-ZQXZ2SES.js} +24 -21
  250. package/dist/chunk-ZX57KSEQ.js +39 -0
  251. package/dist/{chunk-I3E7CX4H.js → chunk-ZZK56BLP.js} +5 -3
  252. package/dist/files.json +664 -368
  253. package/dist/packages/naysayer/constitution/constitution.yaml +19 -0
  254. package/dist/packages/sdk/npm/index.js +6194 -2542
  255. package/dist/packages/ui/dist/assets/{elk-api-tma0MCuh.js → elk-api-CIf-0gz5.js} +2 -2
  256. package/dist/packages/ui/dist/assets/index-CoK_Dl0D.js +47 -0
  257. package/dist/packages/ui/dist/assets/index-Dw20IRhQ.css +1 -0
  258. package/dist/packages/ui/dist/index.html +3 -2
  259. package/package.json +5 -5
  260. package/dist/chunk-2BF2EYJV.js +0 -174
  261. package/dist/chunk-42EVSKME.js +0 -37
  262. package/dist/chunk-4BKGMUIK.js +0 -53
  263. package/dist/chunk-5KLGBXG5.js +0 -48
  264. package/dist/chunk-6BNC6EQ4.js +0 -41
  265. package/dist/chunk-6D2CQ5II.js +0 -41
  266. package/dist/chunk-7AVHLZGD.js +0 -45
  267. package/dist/chunk-D46WUV3T.js +0 -33
  268. package/dist/chunk-E36QOJMD.js +0 -47
  269. package/dist/chunk-FQXYPF7E.js +0 -147
  270. package/dist/chunk-GBRFVT63.js +0 -45
  271. package/dist/chunk-ICY36XCH.js +0 -34
  272. package/dist/chunk-J4K3KVLD.js +0 -131
  273. package/dist/chunk-JZU3H6UQ.js +0 -54
  274. package/dist/chunk-NN2ZQEB4.js +0 -38
  275. package/dist/chunk-PCOCACY3.js +0 -385
  276. package/dist/chunk-RTEYOSJY.js +0 -29
  277. package/dist/chunk-RUVFXE2L.js +0 -666
  278. package/dist/chunk-RVH5SUW5.js +0 -69
  279. package/dist/chunk-VN3DP4LQ.js +0 -43
  280. package/dist/chunk-W5BVQF44.js +0 -36
  281. package/dist/chunk-WVPJSRRJ.js +0 -52
  282. package/dist/chunk-XPTOBS2D.js +0 -48
  283. package/dist/packages/ui/dist/assets/index-B54fm9FQ.js +0 -29
  284. package/dist/packages/ui/dist/assets/index-DD_hufQz.css +0 -1
@@ -3,6 +3,9 @@ import { fileURLToPath as __atticusFileURLToPath } from "node:url";
3
3
  var require = __atticusCreateRequire(import.meta.url);
4
4
  var __atticusUrl = (p) => new URL("./" + p, import.meta.url).href;
5
5
  var __atticusPath = (p) => __atticusFileURLToPath(__atticusUrl(p));
6
+ import {
7
+ commandWords
8
+ } from "./chunk-QA4O2GGC.js";
6
9
  import {
7
10
  ANSWERED_BY,
8
11
  AgentDefinition,
@@ -13,8 +16,10 @@ import {
13
16
  STEP_CLASSES,
14
17
  changesDirOf,
15
18
  changesRelOf,
19
+ copilotAcpOf,
16
20
  currentSignal,
17
21
  differentThings,
22
+ estimateTokens,
18
23
  identifierWords,
19
24
  judgmentKey,
20
25
  loadOrgPack,
@@ -22,19 +27,122 @@ import {
22
27
  namedBeyondAnswer,
23
28
  orgPackDirOf,
24
29
  quotedIn,
25
- require_dist,
26
30
  runsDirOf,
27
31
  runsRelOf,
28
32
  stateDirOf,
29
- stepModelsOf
30
- } from "./chunk-S2A7YC3Q.js";
33
+ stepModelsOf,
34
+ tokenUnits
35
+ } from "./chunk-Q2TECDIT.js";
31
36
  import {
32
37
  writeFileAtomic
33
- } from "./chunk-D3PO4DOZ.js";
38
+ } from "./chunk-TUULXQRW.js";
39
+ import {
40
+ require_dist
41
+ } from "./chunk-BQGDB6ZL.js";
34
42
  import {
35
43
  __toESM
36
44
  } from "./chunk-TV45EUGM.js";
37
45
 
46
+ // packages/ai/dist/person-only.js
47
+ var flag = (a, ...names) => a.some((x) => names.some((n) => x === n || x.startsWith(`${n}=`)));
48
+ var switchOn = (a, name) => a.some((x) => x === name || x.startsWith(`${name}=`) && /^(true)?$/i.test(x.slice(name.length + 1)));
49
+ var RULES = [
50
+ {
51
+ test: (w, a) => w[0] === "change" && w[1] === "release-prs" && flag(a, "--approve"),
52
+ why: "a person raises the release PRs into each repo's default branch (ADR 0184); a session never approves a push or a PR"
53
+ },
54
+ {
55
+ test: (w, a) => w[0] === "task" && w[1] === "run-ready" && flag(a, "--approve"),
56
+ 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"
57
+ },
58
+ { test: (w) => w[0] === "questions" && w[1] === "answer", why: "a person answers questions" },
59
+ {
60
+ // ADR 0181: the AI decides as itself, through Atticus; correcting it, spreading the
61
+ // correction and undoing a batch are a person's word.
62
+ test: (w) => w[0] === "questions" && (w[1] === "correct" || w[1] === "undo"),
63
+ why: "a person corrects an AI decision and undoes a batch of decisions (ADR 0181); the AI decides only as itself, through Atticus"
64
+ },
65
+ {
66
+ test: (w, a) => w[0] === "questions" && w[1] === "sheet" && flag(a, "--apply"),
67
+ why: "a person answers questions (questions sheet --apply answers as them)"
68
+ },
69
+ {
70
+ test: (w, a) => w[0] === "verify" && w[1] === "audit" && flag(a, "--right", "--wrong", "--unsure", "--answers"),
71
+ why: "a person answers an audit: its record says who confirmed each fact"
72
+ },
73
+ {
74
+ test: (w) => w[0] === "knowledge" && ["verify", "correct", "reject"].includes(w[1] ?? ""),
75
+ why: "a person verifies, corrects or rejects a knowledge item"
76
+ },
77
+ { test: (w) => w[1] === "accept", why: "a person accepts what is proposed" },
78
+ { test: (w) => w[0] === "baseline", why: "a person accepts the catalog as the baseline" },
79
+ { test: (w) => w[0] === "triage" && w[1] === "decide", why: "a person decides a triage item" },
80
+ { test: (w) => w[0] === "finding", why: "a person acts on a finding (it is recorded with them)" },
81
+ {
82
+ test: (w) => w[0] === "feature" && ["name", "link"].includes(w[1] ?? ""),
83
+ why: "a person names a feature or links it to work"
84
+ },
85
+ { test: (w) => w[0] === "todo" && w[1] === "done", why: "a person records a manual step done" },
86
+ {
87
+ test: (w) => {
88
+ const n = w[0] === "change" && w[1] === "needs" ? w.slice(1) : w;
89
+ return n[0] === "needs" && ["done", "skip"].includes(n[1] ?? "");
90
+ },
91
+ why: "a person records a need done or not needed"
92
+ },
93
+ { test: (_w, a) => flag(a, "--by"), why: "--by names a person; a session acts as no one" },
94
+ {
95
+ test: (_w, a) => flag(a, "--approve", "--send"),
96
+ why: "--approve and --send are a person's: a human approves every write to shared systems"
97
+ },
98
+ { test: (_w, a) => flag(a, "--as"), why: "--as names a person; a session acts as no one" },
99
+ {
100
+ test: (w, a) => w[0] === "rules" && (w[1] === "activate" || w[1] === "off" || w[1] === "add" && !switchOn(a, "--draft")),
101
+ why: "a person sets a reading rule active or off (a session drafts)"
102
+ },
103
+ {
104
+ test: (w) => w[0] === "initiative" && ["commit", "new", "plan", "request"].includes(w[1] ?? ""),
105
+ why: "a person starts, plans and records an initiative"
106
+ },
107
+ {
108
+ test: (w) => w[0] === "questions" && w[1] === "owner",
109
+ why: "an owner answers a knowledge gap's question"
110
+ },
111
+ { test: (w) => w[0] === "outcome" && w[1] === "record", why: "a person records an outcome" },
112
+ {
113
+ test: (_w, a) => flag(a, "--accept", "--accept-proposal"),
114
+ why: "a person accepts what is proposed (--accept is theirs)"
115
+ },
116
+ {
117
+ test: (w, a) => w[0] === "repo" && (w[1] === "add" || w[1] === "describe" && flag(a, "--description", "--reject")),
118
+ why: "a person adds a repo and writes or drops its description (a session drafts with --drafted)"
119
+ },
120
+ {
121
+ test: (w) => w[0] === "knowledge" && w[1] === "keep",
122
+ why: "a person keeps a knowledge item (it is recorded as verified by them)"
123
+ },
124
+ { test: (w) => w[0] === "alias", why: "a person decides what a name means" },
125
+ {
126
+ test: (w) => w[0] === "glossary" && ["define", "link", "alias"].includes(w[1] ?? ""),
127
+ why: "a person defines, links or aliases a glossary term"
128
+ },
129
+ {
130
+ // Seventh UX walk: shown by anyone; set (a handle given) only by a person, as in the app.
131
+ test: (w) => w[0] === "orgpack" && w[1] === "owner" && !!w[2],
132
+ why: "a person says who looks after the org pack"
133
+ }
134
+ ];
135
+ function withoutLegacy(argv) {
136
+ return argv[0] === "legacy" && argv[1] !== void 0 && !argv[1].startsWith("-") ? argv.slice(1) : argv;
137
+ }
138
+ function personOnlyWhy(argv) {
139
+ argv = withoutLegacy(argv);
140
+ const words2 = commandWords(argv);
141
+ return RULES.find((r) => r.test(words2, argv))?.why;
142
+ }
143
+ var isPersonsFactsFile = (name) => /\.audit\.yaml$|\.corrections\.jsonl$/i.test(windowsName(name));
144
+ var windowsName = (name) => name.replace(/:.*$/, "").replace(/[. ]+$/, "");
145
+
38
146
  // packages/ai/dist/context.js
39
147
  import { createHash as createHash2 } from "node:crypto";
40
148
 
@@ -855,9 +963,16 @@ var PromptTooLong = class extends Error {
855
963
 
856
964
  // packages/ai/dist/context.js
857
965
  var sha2562 = (s) => createHash2("sha256").update(s, "utf8").digest("hex");
858
- function estimateTokens(text) {
859
- return Math.ceil(text.length / 4);
860
- }
966
+ var RequiredSourceLeftOut = class extends Error {
967
+ step;
968
+ left;
969
+ constructor(step, left) {
970
+ super(`atticus ${step} can't go without ${left.map((l) => `${l.origin}: ${l.reason}`).join("; ")}.`);
971
+ this.step = step;
972
+ this.left = left;
973
+ this.name = "RequiredSourceLeftOut";
974
+ }
975
+ };
861
976
  function wrapData(source, text) {
862
977
  const safe = escapeDelimiters(text).text;
863
978
  return `<atticus-data id="${attr(source.id)}" kind="${attr(source.kind)}" origin="${attr(source.origin)}">
@@ -870,10 +985,10 @@ function buildContextPack(given) {
870
985
  const maxTokens = given.maxTokens ?? currentPromptLimit();
871
986
  const o = { ...given, budget: fitBudget(given.budget, maxTokens) };
872
987
  if (maxTokens !== void 0) {
873
- const required = new Set(o.required ?? []);
874
- const needed = o.sources.filter((s) => s.trusted || required.has(s.id)).reduce((n, s) => n + estimateTokens(s.trusted ? s.text : wrapData(s, s.text)), estimateTokens(DATA_RULE));
988
+ const required2 = new Set(o.required ?? []);
989
+ const needed = o.sources.filter((s) => s.trusted || required2.has(s.id)).reduce((n, s) => n + estimateTokens(s.trusted ? s.text : wrapData(s, s.text)), estimateTokens(DATA_RULE));
875
990
  if (needed > o.budget)
876
- throw new PromptTooLong(o.step ?? o.agent, needed, o.budget, maxTokens, o.sources.filter((s) => !s.trusted && required.has(s.id)).map((s) => s.id), o.smaller);
991
+ throw new PromptTooLong(o.step ?? o.agent, needed, o.budget, maxTokens, o.sources.filter((s) => !s.trusted && required2.has(s.id)).map((s) => s.id), o.smaller);
877
992
  }
878
993
  const maxLevel = o.levels.indexOf(o.maxClassification);
879
994
  if (maxLevel === -1)
@@ -929,6 +1044,14 @@ function buildContextPack(given) {
929
1044
  }
930
1045
  if (total > o.budget)
931
1046
  throw new Error(`instructions alone (${total} tokens) exceed the ${o.budget}-token budget`);
1047
+ const required = new Set(o.required ?? []);
1048
+ const left = dropped.filter((d) => required.has(d.id));
1049
+ if (left.length)
1050
+ throw new RequiredSourceLeftOut(o.step ?? o.agent, left.map((d) => ({
1051
+ id: d.id,
1052
+ origin: o.sources.find((s) => s.id === d.id)?.origin ?? d.id,
1053
+ reason: d.reason
1054
+ })));
932
1055
  const prompt = parts.join("\n\n") + "\n";
933
1056
  return {
934
1057
  prompt,
@@ -947,6 +1070,11 @@ function buildContextPack(given) {
947
1070
  };
948
1071
  }
949
1072
 
1073
+ // packages/ai/dist/runtime.js
1074
+ import { randomBytes } from "node:crypto";
1075
+ import { mkdir } from "node:fs/promises";
1076
+ import { join } from "node:path";
1077
+
950
1078
  // packages/ai/dist/step-class.js
951
1079
  var STEP_CLASS_BY_AGENT = {
952
1080
  // read: the repo read into facts (atticus map, and its fix round for the facts rejected).
@@ -1018,6 +1146,10 @@ var NEXT_CLASS = {
1018
1146
  survey: "draft",
1019
1147
  verify: "read",
1020
1148
  map: "read",
1149
+ // ADR 0141: a mapped repo read again where its clone moved on.
1150
+ reread: "read",
1151
+ // ADR 0167: a read repo topped up for reading rules added since.
1152
+ rules: "read",
1021
1153
  spec: "draft",
1022
1154
  knowledge: "knowledge",
1023
1155
  feature: "draft",
@@ -1107,8 +1239,21 @@ function checkAllowed(kind, agent) {
1107
1239
  }
1108
1240
  function makeRunId(now, seq) {
1109
1241
  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}`;
1242
+ const tail2 = seq !== void 0 ? String(seq).padStart(4, "0") : randomBytes(3).toString("hex");
1243
+ return `run-${stamp}-${tail2}`;
1244
+ }
1245
+ async function claimRunDir(dir, next) {
1246
+ await mkdir(dir, { recursive: true });
1247
+ for (let i = 0; ; i++) {
1248
+ const runId = next();
1249
+ try {
1250
+ await mkdir(join(dir, runId));
1251
+ return runId;
1252
+ } catch (e) {
1253
+ if (e.code !== "EEXIST" || i >= 9999)
1254
+ throw e;
1255
+ }
1256
+ }
1112
1257
  }
1113
1258
  function toRunSummary(run) {
1114
1259
  return {
@@ -1128,7 +1273,10 @@ function toRunSummary(run) {
1128
1273
  ...run.tools ? { tools: run.tools } : {},
1129
1274
  ...run.request.retrieval ? { retrieval: run.request.retrieval } : {},
1130
1275
  stepClass: run.stepClass ?? stepClassOf(run.request),
1131
- ...run.model ? { model: run.model } : {}
1276
+ ...run.model ? { model: run.model } : {},
1277
+ ...run.assistant ? { assistant: run.assistant } : {},
1278
+ ...run.batch ? { batch: run.batch } : {},
1279
+ ...run.parts?.length ? { parts: run.parts } : {}
1132
1280
  };
1133
1281
  }
1134
1282
  var OneShotRuntime = class {
@@ -1145,17 +1293,32 @@ var OneShotRuntime = class {
1145
1293
  modelFor(_request) {
1146
1294
  return void 0;
1147
1295
  }
1296
+ /** The kind an agent's allowedRuntimes must name for this runtime (copilot-acp: hand-off too). */
1297
+ allowedAs(_agent) {
1298
+ return this.kind;
1299
+ }
1148
1300
  /** Keep a finished run where Model runs reads it (the model runtime, given a root). */
1149
1301
  async keep(_run) {
1150
1302
  }
1303
+ /**
1304
+ * The next run id: counted from 1 on a test's clock (deterministic), with a random tail on the
1305
+ * real one, so two commands' runtimes in one second don't share an id (round 46).
1306
+ */
1307
+ nextRunId(now) {
1308
+ return makeRunId(now, this.opts.now ? ++this.seq : void 0);
1309
+ }
1310
+ /** A new run's id; a runtime that keeps its runs in folders claims the folder (`claimRunDir`). */
1311
+ async newRunId(_request, now) {
1312
+ return this.nextRunId(now);
1313
+ }
1151
1314
  async prepare(request) {
1152
- checkAllowed(this.kind, request.agent);
1315
+ checkAllowed(this.allowedAs(request.agent), request.agent);
1153
1316
  if (request.pack.manifest.totalTokens > request.agent.tokenBudget) {
1154
1317
  throw new RuntimeError(`context pack (${request.pack.manifest.totalTokens} tokens) is over agent ${request.agent.id}'s budget of ${request.agent.tokenBudget}`);
1155
1318
  }
1156
1319
  const now = this.now();
1157
1320
  const run = {
1158
- runId: makeRunId(now, ++this.seq),
1321
+ runId: await this.newRunId(request, now),
1159
1322
  request,
1160
1323
  runtime: this.kind,
1161
1324
  state: "prepared",
@@ -1177,8 +1340,14 @@ var OneShotRuntime = class {
1177
1340
  return run;
1178
1341
  }
1179
1342
  try {
1180
- const { output, usage, tools } = await this.produce(run, signal);
1181
- run = transition(run, "produced", this.now(), { output, usage, ...tools ? { tools } : {} });
1343
+ const { output, usage, tools, model, assistant } = await this.produce(run, signal);
1344
+ run = transition(run, "produced", this.now(), {
1345
+ output,
1346
+ usage,
1347
+ ...tools ? { tools } : {},
1348
+ ...model ? { model } : {},
1349
+ ...assistant ? { assistant } : {}
1350
+ });
1182
1351
  const problems = await this.opts.validate?.(output, run.request) ?? [];
1183
1352
  run = problems.length === 0 ? transition(run, "validated", this.now()) : transition(run, "failed", this.now(), { errors: problems });
1184
1353
  } catch (e) {
@@ -1204,12 +1373,12 @@ var OneShotRuntime = class {
1204
1373
  };
1205
1374
 
1206
1375
  // packages/ai/dist/runtimes.js
1207
- import { mkdir as mkdir2, readdir as readdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
1208
- import { join as join2 } from "node:path";
1376
+ import { mkdir as mkdir3, readdir as readdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
1377
+ import { join as join3 } from "node:path";
1209
1378
 
1210
1379
  // packages/ai/dist/tools.js
1211
- import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
1212
- import { join } from "node:path";
1380
+ import { mkdir as mkdir2, readdir, readFile, writeFile } from "node:fs/promises";
1381
+ import { join as join2 } from "node:path";
1213
1382
  var ToolError = class extends Error {
1214
1383
  constructor(message) {
1215
1384
  super(message);
@@ -1291,8 +1460,18 @@ function guardToolText(name, raw, room) {
1291
1460
  if (estimateTokens(wrap(text)) > room) {
1292
1461
  const note = `
1293
1462
  \u2026 cut at ${room} tokens; ask for less (a smaller limit, fewer hops, one id).`;
1294
- const chars = Math.max(0, room * 4 - wrap("").length - note.length);
1295
- text = text.slice(0, chars) + note;
1463
+ const units = Math.max(0, room * 4 - tokenUnits(wrap("")) - tokenUnits(note));
1464
+ let end = 0;
1465
+ for (let used = 0; end < text.length; end++) {
1466
+ const c = text.charCodeAt(end);
1467
+ used += c < 128 ? 1 : c >= 56320 && c <= 57343 ? 0 : 4;
1468
+ if (used > units)
1469
+ break;
1470
+ }
1471
+ const last = text.charCodeAt(end - 1);
1472
+ if (end > 0 && last >= 55296 && last <= 56319)
1473
+ end--;
1474
+ text = text.slice(0, end) + note;
1296
1475
  }
1297
1476
  return wrap(text);
1298
1477
  }
@@ -1339,7 +1518,7 @@ async function recordToolCalls(root, runId, update) {
1339
1518
  if (!found)
1340
1519
  return void 0;
1341
1520
  const tools = update(found.run.tools);
1342
- await mkdir(join(found.file, ".."), { recursive: true });
1521
+ await mkdir2(join2(found.file, ".."), { recursive: true });
1343
1522
  await writeFile(found.file, JSON.stringify({ ...found.run, tools }, null, 2) + "\n", "utf8");
1344
1523
  return tools;
1345
1524
  }
@@ -1354,7 +1533,7 @@ async function runFile(root, runId) {
1354
1533
  for (const change of await readdir(runs).catch(() => [])) {
1355
1534
  if (change.includes(".."))
1356
1535
  continue;
1357
- const file = join(runs, change, runId, "run.json");
1536
+ const file = join2(runs, change, runId, "run.json");
1358
1537
  const text = await readFile(file, "utf8").catch(() => void 0);
1359
1538
  if (text)
1360
1539
  return { file, run: JSON.parse(text) };
@@ -1398,8 +1577,8 @@ var ReplayRuntime = class _ReplayRuntime extends OneShotRuntime {
1398
1577
  } catch {
1399
1578
  }
1400
1579
  for (const a of agents.sort()) {
1401
- for (const f of (await readdir2(join2(dir, a)).catch(() => [])).filter((x) => x.endsWith(".json")).sort()) {
1402
- out.push(Recording.parse(JSON.parse(await readFile2(join2(dir, a, f), "utf8"))));
1580
+ for (const f of (await readdir2(join3(dir, a)).catch(() => [])).filter((x) => x.endsWith(".json")).sort()) {
1581
+ out.push(Recording.parse(JSON.parse(await readFile2(join3(dir, a, f), "utf8"))));
1403
1582
  }
1404
1583
  }
1405
1584
  return new _ReplayRuntime(out, opts);
@@ -1427,8 +1606,8 @@ async function recordRun(live, request, dir, model, now = /* @__PURE__ */ new Da
1427
1606
  model,
1428
1607
  recordedAt: now.toISOString()
1429
1608
  };
1430
- await mkdir2(join2(dir, rec.agent), { recursive: true });
1431
- await writeFile2(join2(dir, rec.agent, `${rec.promptSha256}.json`), JSON.stringify(rec, null, 2) + "\n", "utf8");
1609
+ await mkdir3(join3(dir, rec.agent), { recursive: true });
1610
+ await writeFile2(join3(dir, rec.agent, `${rec.promptSha256}.json`), JSON.stringify(rec, null, 2) + "\n", "utf8");
1432
1611
  return rec;
1433
1612
  }
1434
1613
  var MockModelProvider = class {
@@ -1527,17 +1706,56 @@ ${DATA_RULE}`;
1527
1706
  async keep(run) {
1528
1707
  if (!this.mo.root)
1529
1708
  return;
1530
- const dir = join2(runsDirOf(this.mo.root), run.request.change, run.runId);
1531
- await mkdir2(dir, { recursive: true });
1532
- await writeFile2(join2(dir, "prompt.md"), run.request.pack.prompt, "utf8");
1533
- await writeFile2(join2(dir, "context-manifest.json"), JSON.stringify(run.request.pack.manifest, null, 2) + "\n", "utf8");
1534
- await writeFile2(join2(dir, "run.json"), JSON.stringify(run, null, 2) + "\n", "utf8");
1709
+ const dir = join3(runsDirOf(this.mo.root), run.request.change, run.runId);
1710
+ await mkdir3(dir, { recursive: true });
1711
+ await writeFile2(join3(dir, "prompt.md"), run.request.pack.prompt, "utf8");
1712
+ await writeFile2(join3(dir, "context-manifest.json"), JSON.stringify(run.request.pack.manifest, null, 2) + "\n", "utf8");
1713
+ await writeFile2(join3(dir, "run.json"), JSON.stringify(run, null, 2) + "\n", "utf8");
1714
+ }
1715
+ /**
1716
+ * Round 46: given a root, the run's folder is claimed with its id, so another command's run in
1717
+ * the same second (its runtime counts from 1 too) never gets this id and overwrites it.
1718
+ */
1719
+ async newRunId(request, now) {
1720
+ if (!this.mo.root)
1721
+ return super.newRunId(request, now);
1722
+ return claimRunDir(join3(runsDirOf(this.mo.root), request.change), () => this.nextRunId(now));
1535
1723
  }
1536
1724
  };
1537
1725
 
1538
1726
  // packages/ai/dist/handoff.js
1539
- import { mkdir as mkdir3, readdir as readdir3, readFile as readFile3, rm, stat, writeFile as writeFile3 } from "node:fs/promises";
1540
- import { join as join3 } from "node:path";
1727
+ import { mkdir as mkdir4, readdir as readdir3, readFile as readFile3, rm, stat, writeFile as writeFile3 } from "node:fs/promises";
1728
+ import { join as join4 } from "node:path";
1729
+ var BATCH_OUTPUT = "answers.md";
1730
+ var DEFAULT_BATCH_MAX_TOKENS = 6e4;
1731
+ var SECTION = /^===[ \t]*([a-z][a-z0-9-]*)[ \t]*$/;
1732
+ function batchSections(text) {
1733
+ const out = /* @__PURE__ */ new Map();
1734
+ let name;
1735
+ let lines = [];
1736
+ const end = () => {
1737
+ if (name === void 0)
1738
+ return;
1739
+ while (lines.length && !lines[0].trim())
1740
+ lines.shift();
1741
+ while (lines.length && !lines.at(-1).trim())
1742
+ lines.pop();
1743
+ const body = lines.length ? `${lines.join("\n")}
1744
+ ` : "";
1745
+ out.set(name, out.has(name) ? { text: body, twice: true } : { text: body });
1746
+ };
1747
+ for (const line of text.replace(/\r\n/g, "\n").split("\n")) {
1748
+ const m = SECTION.exec(line);
1749
+ if (m) {
1750
+ end();
1751
+ name = m[1];
1752
+ lines = [];
1753
+ } else
1754
+ lines.push(line);
1755
+ }
1756
+ end();
1757
+ return out;
1758
+ }
1541
1759
  var HandoffRuntime = class _HandoffRuntime {
1542
1760
  o;
1543
1761
  kind = "hand-off";
@@ -1546,12 +1764,12 @@ var HandoffRuntime = class _HandoffRuntime {
1546
1764
  this.o = o;
1547
1765
  }
1548
1766
  now = () => this.o.now?.() ?? /* @__PURE__ */ new Date();
1549
- runDir = (change, runId) => join3(runsDirOf(this.o.root), change, runId);
1550
- outputFile = (r) => r.request.outputIn === "run" ? join3(this.runDir(r.request.change, r.runId), r.request.outputPath) : join3(changesDirOf(this.o.root), r.request.change, r.request.outputPath);
1767
+ runDir = (change, runId) => join4(runsDirOf(this.o.root), change, runId);
1768
+ outputFile = (r) => r.request.outputIn === "run" ? join4(this.runDir(r.request.change, r.runId), r.request.outputPath) : join4(changesDirOf(this.o.root), r.request.change, r.request.outputPath);
1551
1769
  // Atomic: a step reading run.json while `handoff done` writes it never sees half a file.
1552
1770
  async save(run) {
1553
1771
  const dir = this.runDir(run.request.change, run.runId);
1554
- await writeFileAtomic(join3(dir, "run.json"), JSON.stringify(run, null, 2) + "\n");
1772
+ await writeFileAtomic(join4(dir, "run.json"), JSON.stringify(run, null, 2) + "\n");
1555
1773
  return run;
1556
1774
  }
1557
1775
  /** Where a run's prompt is, relative to the root (`atticus <step> --handoff` prints it). */
@@ -1563,6 +1781,39 @@ var HandoffRuntime = class _HandoffRuntime {
1563
1781
  const { outputPath, change } = run.request;
1564
1782
  return run.request.outputIn === "run" ? `${runsRel}/${change}/${run.runId}/${outputPath}` : `${changesRel}/${change}/${outputPath}`;
1565
1783
  }
1784
+ /**
1785
+ * A batched hand-off's prompt (ADR 0185): one section to write per part, then each part's own
1786
+ * prompt, whole and in order, under its name. It ends with the completion command.
1787
+ */
1788
+ static promptForBatch(run, parts, changesRel = "openspec/changes", runsRel = ".runs") {
1789
+ const { agent, change } = run.request;
1790
+ const where = _HandoffRuntime.outputRel(run, changesRel, runsRel);
1791
+ const n = parts.length;
1792
+ return [
1793
+ `# ${agent.id}: ${n} parts for change ${change}, in one answer`,
1794
+ "",
1795
+ agent.description,
1796
+ "",
1797
+ `Write the result to ${where}. Change no other files.`,
1798
+ "",
1799
+ `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.`,
1800
+ "",
1801
+ ...parts.flatMap((p) => [`=== ${p.name}`, `<the ${p.name} part's answer>`]),
1802
+ "",
1803
+ ...parts.flatMap((p, i) => [
1804
+ "---",
1805
+ "",
1806
+ `Part ${i + 1} of ${n}: ${p.name}. Its answer is the section "=== ${p.name}".`,
1807
+ "",
1808
+ p.prompt.trimEnd(),
1809
+ ""
1810
+ ]),
1811
+ "---",
1812
+ "",
1813
+ `When the file is complete, run: atticus handoff done ${run.runId}`,
1814
+ ""
1815
+ ].join("\n");
1816
+ }
1566
1817
  /** The prompt the person's assistant gets. It ends with the completion command. */
1567
1818
  static promptFor(run, changesRel = "openspec/changes", runsRel = ".runs") {
1568
1819
  const { agent, pack, outputPath, change } = run.request;
@@ -1580,15 +1831,93 @@ var HandoffRuntime = class _HandoffRuntime {
1580
1831
  ""
1581
1832
  ].join("\n");
1582
1833
  }
1834
+ /** A run id no run folder of the change has yet, its folder made (claimed) with it. */
1835
+ async freshId(change, now) {
1836
+ return claimRunDir(join4(runsDirOf(this.o.root), change), () => makeRunId(now, ++this.seq));
1837
+ }
1838
+ /**
1839
+ * Whether `parts` runs that wait together, `tokens` in all, are asked in one prompt (ADR 0185):
1840
+ * only when this runtime batches, for two parts or more, within the size a batch may hold.
1841
+ */
1842
+ canBatch(parts, tokens) {
1843
+ return !!this.o.batch && parts >= 2 && tokens <= (this.o.batchMaxTokens ?? DEFAULT_BATCH_MAX_TOKENS);
1844
+ }
1845
+ /**
1846
+ * Ask several waiting runs of one change in one prompt (ADR 0185). Each part keeps its own run,
1847
+ * prompt, pack and answer file, and can still be answered alone; the batch links them, and each
1848
+ * part names the batch. The batch's pack is its parts' packs together: their sources, each id
1849
+ * under its part's name, and their sizes added up. Run it (`run`) to hand it over.
1850
+ */
1851
+ async prepareBatch(o) {
1852
+ checkAllowed(this.kind, o.agent);
1853
+ if (o.parts.length < 2)
1854
+ throw new RuntimeError("a batched hand-off needs two parts or more");
1855
+ const twice = o.parts.find((p, i) => o.parts.findIndex((x) => x.name === p.name) !== i);
1856
+ if (twice)
1857
+ throw new RuntimeError(`a batched hand-off can't have two parts named ${twice.name}`);
1858
+ const parts = [];
1859
+ for (const p of o.parts) {
1860
+ const run2 = await this.load(p.runId);
1861
+ if (run2.request.change !== o.change)
1862
+ throw new RuntimeError(`run ${p.runId} isn't a run of ${o.change}`);
1863
+ if (run2.state !== "waiting" && run2.state !== "prepared")
1864
+ throw new RuntimeError(`run ${p.runId} is ${run2.state}: only a run still waiting for its answer can be batched`);
1865
+ if (run2.batch)
1866
+ throw new RuntimeError(`run ${p.runId} is already asked in ${run2.batch}`);
1867
+ parts.push({ name: p.name, run: run2 });
1868
+ }
1869
+ const now = this.now();
1870
+ const runId = await this.freshId(o.change, now);
1871
+ const manifests = parts.map((p) => ({ name: p.name, m: p.run.request.pack.manifest }));
1872
+ const totalTokens = manifests.reduce((n, x) => n + x.m.totalTokens, 0);
1873
+ const agent = { ...o.agent, tokenBudget: Math.max(o.agent.tokenBudget, totalTokens) };
1874
+ const run = {
1875
+ runId,
1876
+ request: {
1877
+ change: o.change,
1878
+ agent,
1879
+ pack: { prompt: "", manifest: manifests[0].m },
1880
+ outputPath: BATCH_OUTPUT,
1881
+ outputIn: "run",
1882
+ ...o.stepClass ? { stepClass: o.stepClass } : {}
1883
+ },
1884
+ runtime: this.kind,
1885
+ state: "prepared",
1886
+ attempt: 1,
1887
+ startedAt: now.toISOString(),
1888
+ errors: [],
1889
+ stepClass: o.stepClass ?? stepClassOf({ agent }),
1890
+ parts: parts.map((p) => ({ name: p.name, runId: p.run.runId }))
1891
+ };
1892
+ 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));
1893
+ const manifest = {
1894
+ schemaVersion: 1,
1895
+ change: o.change,
1896
+ agent: o.agent.id,
1897
+ createdAt: now.toISOString(),
1898
+ budget: manifests.reduce((n, x) => n + x.m.budget, 0),
1899
+ totalTokens,
1900
+ sources: manifests.flatMap((x) => x.m.sources.map((s) => ({ ...s, id: `${x.name}/${s.id}` }))),
1901
+ dropped: manifests.flatMap((x) => x.m.dropped.map((d) => ({ ...d, id: `${x.name}/${d.id}` }))),
1902
+ promptSha256: sha2562(prompt)
1903
+ };
1904
+ run.request.pack = { prompt, manifest };
1905
+ const dir = this.runDir(o.change, runId);
1906
+ await mkdir4(dir, { recursive: true });
1907
+ await writeFile3(join4(dir, "prompt.md"), prompt, "utf8");
1908
+ await writeFile3(join4(dir, "context-manifest.json"), JSON.stringify(manifest, null, 2) + "\n", "utf8");
1909
+ await this.save(run);
1910
+ for (const p of parts)
1911
+ await this.save({ ...p.run, batch: runId });
1912
+ return run;
1913
+ }
1583
1914
  async prepare(request) {
1584
1915
  checkAllowed(this.kind, request.agent);
1585
1916
  if (request.pack.manifest.totalTokens > request.agent.tokenBudget) {
1586
1917
  throw new RuntimeError(`context pack (${request.pack.manifest.totalTokens} tokens) is over agent ${request.agent.id}'s budget of ${request.agent.tokenBudget}`);
1587
1918
  }
1588
1919
  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);
1920
+ const runId = await this.freshId(request.change, now);
1592
1921
  const run = {
1593
1922
  runId,
1594
1923
  request,
@@ -1601,9 +1930,9 @@ var HandoffRuntime = class _HandoffRuntime {
1601
1930
  stepClass: stepClassOf(request)
1602
1931
  };
1603
1932
  const dir = this.runDir(request.change, run.runId);
1604
- await mkdir3(dir, { recursive: true });
1605
- await writeFile3(join3(dir, "prompt.md"), _HandoffRuntime.promptFor(run, changesRelOf(this.o.root), runsRelOf(this.o.root)), "utf8");
1606
- await writeFile3(join3(dir, "context-manifest.json"), JSON.stringify(request.pack.manifest, null, 2) + "\n", "utf8");
1933
+ await mkdir4(dir, { recursive: true });
1934
+ await writeFile3(join4(dir, "prompt.md"), _HandoffRuntime.promptFor(run, changesRelOf(this.o.root), runsRelOf(this.o.root)), "utf8");
1935
+ await writeFile3(join4(dir, "context-manifest.json"), JSON.stringify(request.pack.manifest, null, 2) + "\n", "utf8");
1607
1936
  return this.save(run);
1608
1937
  }
1609
1938
  /** Hand the prompt to the assistant; Atticus now waits. */
@@ -1622,6 +1951,8 @@ var HandoffRuntime = class _HandoffRuntime {
1622
1951
  async done(runId, o = {}) {
1623
1952
  let run = await this.load(runId);
1624
1953
  const model = o.model?.trim();
1954
+ if (run.parts?.length)
1955
+ return this.doneBatch(run, model);
1625
1956
  if (model)
1626
1957
  run = { ...run, model };
1627
1958
  if (run.state === "failed") {
@@ -1645,8 +1976,61 @@ var HandoffRuntime = class _HandoffRuntime {
1645
1976
  return run;
1646
1977
  if (this.now().getTime() - info.mtimeMs < (this.o.stableMs ?? 3e4))
1647
1978
  return run;
1979
+ if (run.parts?.length)
1980
+ return this.doneBatch(run);
1648
1981
  return this.validate(transition(run, "produced", this.now()));
1649
1982
  }
1983
+ /**
1984
+ * A batched hand-off's Done (ADR 0185): its answer is split into its parts' sections, each
1985
+ * written to its part's own answer file and checked there as that part's Done would check it.
1986
+ * A part that passes is in; a missing, doubled or failing section fails only its part, which can
1987
+ * be fixed in the batch (Done again checks only the parts still out) or answered alone. The
1988
+ * batch passes once every part is in; until then it fails, naming each part that is out and why.
1989
+ */
1990
+ async doneBatch(start, model) {
1991
+ let run = start;
1992
+ if (run.state === "validated" || run.state === "cancelled")
1993
+ return run;
1994
+ if (run.state === "failed")
1995
+ run = transition(transition(run, "prepared", this.now(), { attempt: run.attempt + 1, errors: [] }), "waiting", this.now());
1996
+ if (model)
1997
+ run = { ...run, model };
1998
+ const output = await readFile3(this.outputFile(run), "utf8").catch(() => void 0);
1999
+ if (output === void 0)
2000
+ return this.save(transition(run, "failed", this.now(), {
2001
+ errors: [`${run.request.outputPath} was not written`]
2002
+ }));
2003
+ const names = run.parts.map((p) => p.name);
2004
+ const sections = batchSections(output);
2005
+ if (!names.some((n) => sections.has(n)))
2006
+ return this.save(transition(run, "failed", this.now(), {
2007
+ output,
2008
+ errors: [
2009
+ `${run.request.outputPath} has no section of any part. Start each part's answer with its own line "=== <part>": ${names.map((n) => `=== ${n}`).join(", ")}.`
2010
+ ]
2011
+ }));
2012
+ run = transition(run, "produced", this.now(), { output });
2013
+ const errors = [];
2014
+ const runsRel = runsRelOf(this.o.root);
2015
+ for (const p of run.parts) {
2016
+ const part = await this.load(p.runId);
2017
+ if (part.state === "validated" || part.state === "cancelled")
2018
+ continue;
2019
+ const s = sections.get(p.name);
2020
+ const alone = `answer that part alone: its prompt is ${_HandoffRuntime.promptRel(part, runsRel)}.`;
2021
+ if (!s || s.twice) {
2022
+ 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}`);
2023
+ const why = `The batched answer (run ${run.runId}) has ${s ? 'two "=== ' + p.name + '" sections' : 'no "=== ' + p.name + '" section'}. Answer this part here.`;
2024
+ await this.save(part.state === "failed" ? { ...part, errors: [why] } : transition(part, "failed", this.now(), { errors: [why] }));
2025
+ continue;
2026
+ }
2027
+ await writeFile3(this.outputFile(part), s.text, "utf8");
2028
+ const r = await this.done(p.runId, model ? { model } : {});
2029
+ if (r.state !== "validated")
2030
+ errors.push(...r.errors.map((e) => `${p.name}: ${e}`));
2031
+ }
2032
+ return this.save(errors.length ? transition(run, "failed", this.now(), { errors }) : transition(run, "validated", this.now()));
2033
+ }
1650
2034
  /** Retry after a failure: a fresh attempt with the same request. */
1651
2035
  async retry(runId) {
1652
2036
  const run = await this.load(runId);
@@ -1667,7 +2051,7 @@ var HandoffRuntime = class _HandoffRuntime {
1667
2051
  throw new RuntimeError(`not a run id: ${runId}`);
1668
2052
  const runs = runsDirOf(this.o.root);
1669
2053
  for (const change of await readdir3(runs).catch(() => [])) {
1670
- const f = join3(runs, change, runId, "run.json");
2054
+ const f = join4(runs, change, runId, "run.json");
1671
2055
  const text = await readFile3(f, "utf8").catch(() => void 0);
1672
2056
  if (text)
1673
2057
  return JSON.parse(text);
@@ -1681,12 +2065,12 @@ async function pruneRuns(root, days, now = /* @__PURE__ */ new Date(), only) {
1681
2065
  const cutoff = now.getTime() - days * 864e5;
1682
2066
  const changes = only ? [only] : await readdir3(runs).catch(() => []);
1683
2067
  for (const change of changes) {
1684
- for (const runId of await readdir3(join3(runs, change)).catch(() => [])) {
1685
- const f = join3(runs, change, runId, "run.json");
2068
+ for (const runId of await readdir3(join4(runs, change)).catch(() => [])) {
2069
+ const f = join4(runs, change, runId, "run.json");
1686
2070
  const text = await readFile3(f, "utf8").catch(() => void 0);
1687
2071
  const started = text ? Date.parse(JSON.parse(text).startedAt) : NaN;
1688
2072
  if (!Number.isNaN(started) && started < cutoff) {
1689
- await rm(join3(runs, change, runId), { recursive: true, force: true });
2073
+ await rm(join4(runs, change, runId), { recursive: true, force: true });
1690
2074
  removed.push(`${change}/${runId}`);
1691
2075
  }
1692
2076
  }
@@ -1695,12 +2079,1070 @@ async function pruneRuns(root, days, now = /* @__PURE__ */ new Date(), only) {
1695
2079
  }
1696
2080
 
1697
2081
  // 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";
2082
+ import { existsSync as existsSync2 } from "node:fs";
2083
+ import { spawn as spawn2 } from "node:child_process";
2084
+ import { mkdir as mkdir6, mkdtemp, readFile as readFile5, rm as rm2, stat as stat3, writeFile as writeFile5 } from "node:fs/promises";
1700
2085
  import { tmpdir } from "node:os";
1701
- import { dirname, join as join4 } from "node:path";
2086
+ import { dirname as dirname2, join as join6 } from "node:path";
2087
+
2088
+ // packages/ai/dist/copilot-acp.js
2089
+ import { spawn } from "node:child_process";
2090
+ import { existsSync, realpathSync } from "node:fs";
2091
+ import { mkdir as mkdir5, readFile as readFile4, stat as stat2, writeFile as writeFile4 } from "node:fs/promises";
2092
+ import { basename, dirname, isAbsolute, join as join5, relative, resolve, sep } from "node:path";
2093
+ import { createInterface } from "node:readline";
2094
+
2095
+ // packages/ai/dist/acp.js
2096
+ var ACP_PROTOCOL_VERSION = 1;
2097
+ var ACP_METHODS = {
2098
+ initialize: "initialize",
2099
+ authenticate: "authenticate",
2100
+ sessionNew: "session/new",
2101
+ sessionSetModel: "session/set_model",
2102
+ sessionPrompt: "session/prompt",
2103
+ sessionCancel: "session/cancel",
2104
+ sessionUpdate: "session/update",
2105
+ requestPermission: "session/request_permission",
2106
+ readTextFile: "fs/read_text_file",
2107
+ writeTextFile: "fs/write_text_file",
2108
+ terminalCreate: "terminal/create",
2109
+ terminalOutput: "terminal/output",
2110
+ terminalWaitForExit: "terminal/wait_for_exit",
2111
+ terminalKill: "terminal/kill",
2112
+ terminalRelease: "terminal/release"
2113
+ };
2114
+ var ACP_ERRORS = {
2115
+ invalidParams: -32602,
2116
+ methodNotFound: -32601,
2117
+ internal: -32603,
2118
+ authRequired: -32e3
2119
+ };
2120
+ var AcpRpcError = class extends Error {
2121
+ code;
2122
+ data;
2123
+ constructor(code, message, data) {
2124
+ super(message);
2125
+ this.code = code;
2126
+ this.data = data;
2127
+ this.name = "AcpRpcError";
2128
+ }
2129
+ };
2130
+ var AcpClient = class {
2131
+ t;
2132
+ h;
2133
+ tap;
2134
+ next = 1;
2135
+ pending = /* @__PURE__ */ new Map();
2136
+ closed;
2137
+ constructor(t, h, tap = () => {
2138
+ }) {
2139
+ this.t = t;
2140
+ this.h = h;
2141
+ this.tap = tap;
2142
+ t.onLine((line) => this.receive(line));
2143
+ t.onClose((why) => {
2144
+ this.closed = why;
2145
+ for (const p of this.pending.values())
2146
+ p.reject(new AcpRpcError(ACP_ERRORS.internal, why));
2147
+ this.pending.clear();
2148
+ });
2149
+ }
2150
+ out(message) {
2151
+ const m = { jsonrpc: "2.0", ...message };
2152
+ this.tap("out", m);
2153
+ this.t.send(JSON.stringify(m));
2154
+ }
2155
+ request(method, params) {
2156
+ if (this.closed)
2157
+ return Promise.reject(new AcpRpcError(ACP_ERRORS.internal, this.closed));
2158
+ const id = this.next++;
2159
+ return new Promise((resolve2, reject) => {
2160
+ this.pending.set(id, { resolve: resolve2, reject });
2161
+ this.out({ id, method, params });
2162
+ });
2163
+ }
2164
+ notify(method, params) {
2165
+ if (!this.closed)
2166
+ this.out({ method, params });
2167
+ }
2168
+ receive(line) {
2169
+ if (!line.trim())
2170
+ return;
2171
+ let m;
2172
+ try {
2173
+ m = JSON.parse(line);
2174
+ } catch {
2175
+ this.tap("in", { notJson: line.slice(0, 500) });
2176
+ return;
2177
+ }
2178
+ this.tap("in", m);
2179
+ if (m.method === void 0 && m.id !== void 0) {
2180
+ const p = this.pending.get(Number(m.id));
2181
+ if (!p)
2182
+ return;
2183
+ this.pending.delete(Number(m.id));
2184
+ if (m.error)
2185
+ p.reject(new AcpRpcError(m.error.code, m.error.message, m.error.data));
2186
+ else
2187
+ p.resolve(m.result ?? null);
2188
+ return;
2189
+ }
2190
+ if (m.method === ACP_METHODS.sessionUpdate) {
2191
+ const u = m.params?.update;
2192
+ if (u && typeof u === "object")
2193
+ this.h.update(u);
2194
+ return;
2195
+ }
2196
+ if (m.id === void 0)
2197
+ return;
2198
+ const id = m.id;
2199
+ void this.answer(m.method ?? "", m.params ?? {}).then((result) => this.out({ id, result }), (e) => this.out({
2200
+ id,
2201
+ error: {
2202
+ code: e instanceof AcpRpcError ? e.code : ACP_ERRORS.invalidParams,
2203
+ message: e.message
2204
+ }
2205
+ }));
2206
+ }
2207
+ answer(method, p) {
2208
+ const s = (k) => typeof p[k] === "string" ? p[k] : "";
2209
+ switch (method) {
2210
+ case ACP_METHODS.readTextFile:
2211
+ return this.h.readTextFile({
2212
+ path: s("path"),
2213
+ ...typeof p.line === "number" ? { line: p.line } : {},
2214
+ ...typeof p.limit === "number" ? { limit: p.limit } : {}
2215
+ });
2216
+ case ACP_METHODS.writeTextFile:
2217
+ return this.h.writeTextFile({ path: s("path"), content: s("content") });
2218
+ case ACP_METHODS.requestPermission:
2219
+ return this.h.requestPermission({
2220
+ toolCall: p.toolCall ?? {},
2221
+ options: Array.isArray(p.options) ? p.options : []
2222
+ });
2223
+ case ACP_METHODS.terminalCreate:
2224
+ return this.h.terminalCreate({
2225
+ command: s("command"),
2226
+ ...Array.isArray(p.args) ? { args: p.args.map(String) } : {},
2227
+ ...typeof p.cwd === "string" ? { cwd: p.cwd } : {},
2228
+ ...Array.isArray(p.env) ? { env: p.env } : {},
2229
+ ...typeof p.outputByteLimit === "number" ? { outputByteLimit: p.outputByteLimit } : {}
2230
+ });
2231
+ case ACP_METHODS.terminalOutput:
2232
+ return this.h.terminalOutput({ terminalId: s("terminalId") });
2233
+ case ACP_METHODS.terminalWaitForExit:
2234
+ return this.h.terminalWaitForExit({ terminalId: s("terminalId") });
2235
+ case ACP_METHODS.terminalKill:
2236
+ return this.h.terminalKill({ terminalId: s("terminalId") });
2237
+ case ACP_METHODS.terminalRelease:
2238
+ return this.h.terminalRelease({ terminalId: s("terminalId") });
2239
+ default:
2240
+ return Promise.reject(new AcpRpcError(ACP_ERRORS.methodNotFound, `Atticus doesn't offer ${method}`));
2241
+ }
2242
+ }
2243
+ // ------------------------------------------------------------ the agent's methods
2244
+ initialize(clientInfo) {
2245
+ return this.request(ACP_METHODS.initialize, {
2246
+ protocolVersion: ACP_PROTOCOL_VERSION,
2247
+ clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: true },
2248
+ clientInfo
2249
+ });
2250
+ }
2251
+ newSession(cwd) {
2252
+ return this.request(ACP_METHODS.sessionNew, { cwd, mcpServers: [] });
2253
+ }
2254
+ setModel(sessionId, modelId) {
2255
+ return this.request(ACP_METHODS.sessionSetModel, { sessionId, modelId });
2256
+ }
2257
+ prompt(sessionId, text) {
2258
+ return this.request(ACP_METHODS.sessionPrompt, {
2259
+ sessionId,
2260
+ prompt: [{ type: "text", text }]
2261
+ });
2262
+ }
2263
+ cancel(sessionId) {
2264
+ this.notify(ACP_METHODS.sessionCancel, { sessionId });
2265
+ }
2266
+ };
2267
+ function chunkText(u) {
2268
+ const c = u.content;
2269
+ return c?.type === "text" && typeof c.text === "string" ? c.text : void 0;
2270
+ }
2271
+ var UPDATE = {
2272
+ message: "agent_message_chunk",
2273
+ thought: "agent_thought_chunk",
2274
+ toolCall: "tool_call",
2275
+ toolCallUpdate: "tool_call_update",
2276
+ plan: "plan"
2277
+ };
2278
+ function usageOf(u) {
2279
+ if (!u)
2280
+ return void 0;
2281
+ const n = (...ks) => {
2282
+ for (const k of ks)
2283
+ if (typeof u[k] === "number")
2284
+ return u[k];
2285
+ return void 0;
2286
+ };
2287
+ const i = n("inputTokens", "input_tokens", "promptTokens");
2288
+ const o = n("outputTokens", "output_tokens", "completionTokens");
2289
+ return i === void 0 && o === void 0 ? void 0 : {
2290
+ inputTokens: Math.max(0, Math.round(i ?? 0)),
2291
+ outputTokens: Math.max(0, Math.round(o ?? 0))
2292
+ };
2293
+ }
2294
+ var isAuthRequired = (e) => e instanceof AcpRpcError && (e.code === ACP_ERRORS.authRequired || /auth|sign.?in|log.?in/i.test(e.message));
2295
+
2296
+ // packages/ai/dist/copilot-acp.js
2297
+ function words(line) {
2298
+ const out = [];
2299
+ let cur = "";
2300
+ let quote;
2301
+ let any = false;
2302
+ let meta = false;
2303
+ for (const ch of line) {
2304
+ if (quote) {
2305
+ if (ch === quote)
2306
+ quote = void 0;
2307
+ else
2308
+ cur += ch;
2309
+ continue;
2310
+ }
2311
+ if (ch === '"' || ch === "'") {
2312
+ quote = ch;
2313
+ any = true;
2314
+ continue;
2315
+ }
2316
+ if (/\s/.test(ch)) {
2317
+ if (cur || any)
2318
+ out.push(cur);
2319
+ cur = "";
2320
+ any = false;
2321
+ continue;
2322
+ }
2323
+ if ("|&;<>`$(){}\n".includes(ch))
2324
+ meta = true;
2325
+ cur += ch;
2326
+ }
2327
+ if (cur || any)
2328
+ out.push(cur);
2329
+ return { words: out, meta: meta || quote !== void 0 };
2330
+ }
2331
+ function commandLineOf(line) {
2332
+ const w = words(line.trim()).words;
2333
+ if (!w.length)
2334
+ throw new RuntimeConfigLikeError("copilotAcp.command is empty");
2335
+ const args = w.slice(1);
2336
+ return { command: w[0], args: args.includes("--acp") ? args : [...args, "--acp"] };
2337
+ }
2338
+ var RuntimeConfigLikeError = class extends RuntimeError {
2339
+ };
2340
+ var PERSONS = [
2341
+ // What only a person does is personOnlyWhy's list (person-only.ts), shared with the CLI.
2342
+ {
2343
+ test: (a) => a[0] === "map" && a.includes("--all"),
2344
+ why: "this session is one step of atticus map --all; Atticus runs the loop, not the session"
2345
+ },
2346
+ {
2347
+ test: (a) => ["ui", "serve", "mcp"].includes(a[0] ?? ""),
2348
+ why: "a server that keeps running isn't a step's command"
2349
+ },
2350
+ {
2351
+ test: (a) => a.some((x) => x === "--root" || x.startsWith("--root=")),
2352
+ why: "the session works in this metarepo; --root points elsewhere"
2353
+ }
2354
+ ];
2355
+ var ATTICUS_NAMES = /* @__PURE__ */ new Set(["atticus", "atticus.cmd", "atticus.exe"]);
2356
+ function atticusArgvOf(command, args = []) {
2357
+ const head = words(command.trim());
2358
+ if (head.meta)
2359
+ return {
2360
+ refused: `Atticus runs no shell here, so a command line with | & ; < > $ or backquotes is refused: ${short(command)}. Run one atticus command at a time.`
2361
+ };
2362
+ const all = [...head.words, ...args];
2363
+ const program = all[0] ?? "";
2364
+ if (!ATTICUS_NAMES.has(program.toLowerCase()))
2365
+ return {
2366
+ 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.`
2367
+ };
2368
+ const argv = all.slice(1);
2369
+ if (!argv.length)
2370
+ return { refused: "atticus needs a command (atticus next, atticus verify <repo>, ...)" };
2371
+ const named = [...withoutLegacy(argv)];
2372
+ for (const p of PERSONS)
2373
+ if (p.test(named))
2374
+ return { refused: `Refused: ${p.why}.` };
2375
+ const hidden = argv[0] === "legacy" && argv[1]?.startsWith("-") && argv.slice(2).some((x) => !x.startsWith("-"));
2376
+ if (hidden || argv[0].startsWith("-") && !["--help", "--version", "-h"].includes(argv[0]))
2377
+ return {
2378
+ refused: `Put the command first: atticus <command> [arguments] (got ${short(argv.join(" "))})`
2379
+ };
2380
+ const person = personOnlyWhy(argv);
2381
+ if (person)
2382
+ return { refused: `Refused: ${person}; Atticus lets a session act as no one.` };
2383
+ return { argv };
2384
+ }
2385
+ var short = (s, n = 120) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
2386
+ function real(p) {
2387
+ let cur = resolve(p);
2388
+ const rest = [];
2389
+ for (; ; ) {
2390
+ try {
2391
+ return join5(realpathSync.native(cur), ...rest.reverse());
2392
+ } catch {
2393
+ const up = dirname(cur);
2394
+ if (up === cur)
2395
+ return resolve(p);
2396
+ rest.push(basename(cur));
2397
+ cur = up;
2398
+ }
2399
+ }
2400
+ }
2401
+ var sameOrUnder = (root, p) => {
2402
+ const r = relative(root, p);
2403
+ return r === "" || !r.startsWith("..") && !isAbsolute(r);
2404
+ };
2405
+ var caseOf = (p) => process.platform === "win32" ? p.toLowerCase() : p;
2406
+ var Paths = class {
2407
+ p;
2408
+ reads;
2409
+ writeDirs;
2410
+ files;
2411
+ constructor(p) {
2412
+ this.p = p;
2413
+ this.reads = p.readRoots.map((r) => caseOf(real(r)));
2414
+ this.writeDirs = p.writeRoots.map((r) => caseOf(real(r)));
2415
+ this.files = (p.writeFiles ?? []).map((f) => caseOf(real(f)));
2416
+ }
2417
+ readable(path) {
2418
+ if (!path || !isAbsolute(path))
2419
+ return `the path must be absolute (got ${short(path)})`;
2420
+ const r = caseOf(real(path));
2421
+ 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`;
2422
+ }
2423
+ writable(path) {
2424
+ if (!path || !isAbsolute(path))
2425
+ return `the path must be absolute (got ${short(path)})`;
2426
+ const r = caseOf(real(path));
2427
+ if (r.split(sep).includes(".git"))
2428
+ return `Atticus never lets a session write in .git (${short(path)})`;
2429
+ const parts = r.split(sep).slice(/^[A-Za-z]:$/.test(r.split(sep)[0] ?? "") ? 1 : 0);
2430
+ if (parts.some((x) => x !== "." && x !== ".." && (/[. ]$/.test(x) || x.includes(":"))))
2431
+ return `Atticus never lets a session write a name that ends in a dot or space or names a stream (${short(path)})`;
2432
+ if (isPersonsFactsFile(basename(r)))
2433
+ return `Atticus never lets a session write a person's record (${short(path)}: an audit's answers or a person's corrections)`;
2434
+ if (this.files.includes(r) || this.writeDirs.some((x) => sameOrUnder(x, r)))
2435
+ return void 0;
2436
+ const base = this.p.readRoots[0] ?? "";
2437
+ const rel = (x) => {
2438
+ const r2 = relative(base, x);
2439
+ return r2 && !r2.startsWith("..") && !isAbsolute(r2) ? r2.split(sep).join("/") : x;
2440
+ };
2441
+ const where = [
2442
+ ...this.p.writeRoots.map((d) => `${rel(d)}/`),
2443
+ ...(this.p.writeFiles ?? []).map(rel)
2444
+ ].join(", ");
2445
+ return `Atticus lets this session write only its step's result: it writes only under ${where || "nothing"}; ${short(path)} is refused`;
2446
+ }
2447
+ };
2448
+ var acpPathsOf = (p) => new Paths(p);
2449
+ var factsOnly = (root, factsDir) => ({
2450
+ readRoots: readRootsOf(root),
2451
+ writeRoots: [factsDir]
2452
+ });
2453
+ function readRootsOf(root) {
2454
+ const out = [root];
2455
+ const state = join5(stateDirOf(root), "workspace");
2456
+ if (!sameOrUnder(resolve(root), resolve(state)))
2457
+ out.push(state);
2458
+ return out;
2459
+ }
2460
+ var needsShell = (command, platform = process.platform) => platform === "win32" && !/\.(exe|com)$/i.test(command);
2461
+ var quoteForCmd = (a) => /[\s"]/.test(a) ? `"${a.replace(/"/g, '""')}"` : a;
2462
+ function killTree(child, platform = process.platform, run = spawn) {
2463
+ if (platform === "win32" && child.pid) {
2464
+ try {
2465
+ const k = run("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
2466
+ windowsHide: true,
2467
+ stdio: "ignore"
2468
+ });
2469
+ k.on("error", () => child.kill());
2470
+ return;
2471
+ } catch {
2472
+ }
2473
+ }
2474
+ child.kill();
2475
+ }
2476
+ var spawnAcpServer = (o) => {
2477
+ const shell = needsShell(o.command);
2478
+ let child;
2479
+ let err = "";
2480
+ let failed = () => {
2481
+ };
2482
+ let ok = () => {
2483
+ };
2484
+ const started = new Promise((res, rej) => {
2485
+ ok = res;
2486
+ failed = rej;
2487
+ });
2488
+ started.catch(() => void 0);
2489
+ try {
2490
+ 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 });
2491
+ } catch (e) {
2492
+ failed(e);
2493
+ const dead = { send: () => {
2494
+ }, onLine: () => {
2495
+ }, onClose: (fn) => fn(String(e)) };
2496
+ return { transport: dead, stderr: () => "", close: async () => {
2497
+ }, started };
2498
+ }
2499
+ const lines = [];
2500
+ const closes = [];
2501
+ let closed;
2502
+ const close = (why) => {
2503
+ if (closed)
2504
+ return;
2505
+ closed = why;
2506
+ for (const f of closes)
2507
+ f(why);
2508
+ };
2509
+ child.on("spawn", () => ok());
2510
+ child.on("error", (e) => {
2511
+ failed(e);
2512
+ close(`the Copilot language server couldn't be run: ${e.message}`);
2513
+ });
2514
+ child.on("exit", (code, signal) => close(`the Copilot language server ended (${code ?? signal ?? "no code"})`));
2515
+ for (const s of [child.stdin, child.stdout, child.stderr])
2516
+ s?.on("error", () => void 0);
2517
+ child.stderr?.setEncoding("utf8").on("data", (d) => {
2518
+ err = (err + d).slice(-64e3);
2519
+ });
2520
+ createInterface({ input: child.stdout }).on("line", (l) => {
2521
+ for (const f of lines)
2522
+ f(l);
2523
+ });
2524
+ return {
2525
+ started,
2526
+ stderr: () => err,
2527
+ transport: {
2528
+ send: (t) => {
2529
+ if (!closed)
2530
+ child.stdin?.write(`${t}
2531
+ `);
2532
+ },
2533
+ onLine: (f) => lines.push(f),
2534
+ onClose: (f) => closed ? f(closed) : closes.push(f)
2535
+ },
2536
+ close: async () => {
2537
+ if (closed)
2538
+ return;
2539
+ child.stdin?.end();
2540
+ await new Promise((res) => {
2541
+ const t = setTimeout(() => {
2542
+ killTree(child);
2543
+ res();
2544
+ }, 2e3);
2545
+ closes.push(() => {
2546
+ clearTimeout(t);
2547
+ res();
2548
+ });
2549
+ });
2550
+ }
2551
+ };
2552
+ };
2553
+ function atticusExec(entry, node = process.execPath) {
2554
+ return (argv, o) => new Promise((res) => {
2555
+ let output = "";
2556
+ const child = spawn(node, [entry, ...argv], {
2557
+ cwd: o.cwd,
2558
+ env: { ...process.env, ATTICUS_ACP_SESSION: "1" },
2559
+ stdio: ["ignore", "pipe", "pipe"],
2560
+ windowsHide: true,
2561
+ signal: o.signal
2562
+ });
2563
+ const take = (d) => {
2564
+ const t = d.toString("utf8");
2565
+ output = (output + t).slice(-1e6);
2566
+ o.onOutput?.(t);
2567
+ };
2568
+ child.stdout.on("data", take);
2569
+ child.stderr.on("data", take);
2570
+ child.on("error", (e) => res({ exitCode: 1, output: `${output}${e.message}
2571
+ ` }));
2572
+ child.on("close", (code, signal) => res({ exitCode: code, output, signal }));
2573
+ });
2574
+ }
2575
+ var AcpSignInError = class extends RuntimeError {
2576
+ constructor(message) {
2577
+ super(message);
2578
+ this.name = "AcpSignInError";
2579
+ }
2580
+ };
2581
+ var AcpSetupError = class extends RuntimeError {
2582
+ constructor(message) {
2583
+ super(message);
2584
+ this.name = "AcpSetupError";
2585
+ }
2586
+ };
2587
+ var MAX_NUDGES = 3;
2588
+ function carryOnPrompt(refusals) {
2589
+ return [
2590
+ "Atticus refused this, and you are not finished yet:",
2591
+ ...refusals.slice(-3).map((r) => `- ${oneLine(r, 300)}`),
2592
+ "",
2593
+ "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."
2594
+ ].join("\n");
2595
+ }
2596
+ function sumUsage(us) {
2597
+ if (!us.length)
2598
+ return void 0;
2599
+ const out = {};
2600
+ for (const u of us)
2601
+ for (const [k, v] of Object.entries(u))
2602
+ out[k] = typeof v === "number" ? (out[k] ?? 0) + v : out[k] ?? v;
2603
+ return out;
2604
+ }
2605
+ var ACP_OFFERED = [
2606
+ "fs/read_text_file",
2607
+ "fs/write_text_file",
2608
+ "terminal/create (atticus only)",
2609
+ "session/request_permission"
2610
+ ];
2611
+ var withTimeout = (p, ms, what) => new Promise((res, rej) => {
2612
+ const t = setTimeout(() => rej(new RuntimeError(`${what} took over ${Math.round(ms / 1e3)}s`)), ms);
2613
+ p.then((v) => {
2614
+ clearTimeout(t);
2615
+ res(v);
2616
+ }, (e) => {
2617
+ clearTimeout(t);
2618
+ rej(e);
2619
+ });
2620
+ });
2621
+ var oneLine = (s, n = 150) => short(s.replace(/\s+/g, " ").trim(), n);
2622
+ var signInLines = (stderr) => stderr.split(/\r?\n/).map((l) => l.trim()).filter((l) => /https?:\/\/|code|sign|log.?in|auth/i.test(l)).slice(-5);
2623
+ async function runAcpSession(o) {
2624
+ const { command, args } = commandLineOf(o.command);
2625
+ const server = (o.spawn ?? spawnAcpServer)({
2626
+ command,
2627
+ args,
2628
+ cwd: o.cwd,
2629
+ // beta.17: set on the server too, so an atticus command Copilot runs in its own shell (not
2630
+ // through Atticus's terminal) knows it is inside a session and hands off instead of starting
2631
+ // a Copilot session of its own (a session within a session, waiting on itself).
2632
+ env: { ...process.env, ...o.env ?? {}, ATTICUS_ACP_SESSION: "1", ATTICUS_ROOT: o.cwd }
2633
+ });
2634
+ const transcript = [];
2635
+ const paths = new Paths(o.policy);
2636
+ const calls = [];
2637
+ const refused = [];
2638
+ const say = (l) => o.onProgress?.(short(l, 160));
2639
+ let text = "";
2640
+ let pendingText = "";
2641
+ let agentCalls = 0;
2642
+ let textAtRefusal = 0;
2643
+ let cancelWhy;
2644
+ let sessionId;
2645
+ const abort = new AbortController();
2646
+ const flush = () => {
2647
+ if (pendingText.trim())
2648
+ say(` Copilot: ${oneLine(pendingText)}`);
2649
+ pendingText = "";
2650
+ };
2651
+ const record = (name, input, output, error) => {
2652
+ calls.push({
2653
+ round: 1,
2654
+ name,
2655
+ input,
2656
+ output: short(output, 2e3),
2657
+ tokens: estimateTokens(output),
2658
+ ...error ? { error: true } : {}
2659
+ });
2660
+ if (error) {
2661
+ textAtRefusal = text.length;
2662
+ refused.push(output);
2663
+ flush();
2664
+ say(` Refused: ${oneLine(output, 140)}`);
2665
+ }
2666
+ };
2667
+ const refuse = (name, input, why) => {
2668
+ record(name, input, why, true);
2669
+ throw new AcpRpcError(ACP_ERRORS.invalidParams, why);
2670
+ };
2671
+ const terminals = /* @__PURE__ */ new Map();
2672
+ let tn = 0;
2673
+ const box = {};
2674
+ const cancel = (why) => {
2675
+ if (cancelWhy)
2676
+ return;
2677
+ cancelWhy = why;
2678
+ flush();
2679
+ say(` Stopping the session: ${why}.`);
2680
+ if (sessionId)
2681
+ box.client?.cancel(sessionId);
2682
+ for (const t of terminals.values())
2683
+ t.kill.abort();
2684
+ };
2685
+ const handlers = {
2686
+ async readTextFile(p) {
2687
+ const why = paths.readable(p.path);
2688
+ if (why)
2689
+ return refuse("fs/read_text_file", { path: p.path }, why);
2690
+ const all = await readFile4(p.path, "utf8").catch((e) => {
2691
+ throw new AcpRpcError(ACP_ERRORS.invalidParams, `${p.path} can't be read: ${e.code ?? e.message}`);
2692
+ });
2693
+ let content = all;
2694
+ if (p.line !== void 0 || p.limit !== void 0) {
2695
+ const lines = all.split("\n");
2696
+ const from = Math.max(0, (p.line ?? 1) - 1);
2697
+ content = lines.slice(from, p.limit !== void 0 ? from + p.limit : void 0).join("\n");
2698
+ }
2699
+ record("fs/read_text_file", { path: p.path }, `${content.length} characters`);
2700
+ return { content };
2701
+ },
2702
+ async writeTextFile(p) {
2703
+ const why = paths.writable(p.path);
2704
+ if (why)
2705
+ return refuse("fs/write_text_file", { path: p.path }, why);
2706
+ await mkdir5(dirname(p.path), { recursive: true });
2707
+ await writeFile4(p.path, p.content, "utf8");
2708
+ record("fs/write_text_file", { path: p.path }, `${p.content.length} characters written`);
2709
+ return null;
2710
+ },
2711
+ async requestPermission(p) {
2712
+ const tc = p.toolCall;
2713
+ const why = permissionRefused(tc, paths);
2714
+ const pick = (kinds) => kinds.map((k) => p.options.find((x) => x.kind === k)).find(Boolean);
2715
+ const allow = why ? void 0 : pick(["allow_once"]);
2716
+ const input = {
2717
+ kind: tc.kind ?? "",
2718
+ title: tc.title ?? "",
2719
+ ...tc.locations?.length ? { locations: tc.locations.map((l) => l.path) } : {}
2720
+ };
2721
+ if (allow) {
2722
+ record(`permission:${tc.kind ?? "other"}`, input, `allowed once: ${tc.title ?? ""}`);
2723
+ return { outcome: { outcome: "selected", optionId: allow.optionId } };
2724
+ }
2725
+ record(`permission:${tc.kind ?? "other"}`, input, why ?? "Refused: the server offered only to allow it always; Atticus allows once at a time", true);
2726
+ const reject = pick(["reject_once", "reject_always"]);
2727
+ return reject ? { outcome: { outcome: "selected", optionId: reject.optionId } } : { outcome: { outcome: "cancelled" } };
2728
+ },
2729
+ async terminalCreate(p) {
2730
+ const a = atticusArgvOf(p.command, p.args ?? []);
2731
+ const input = { command: p.command, args: p.args ?? [] };
2732
+ if (a.refused !== void 0)
2733
+ return refuse("terminal/create", input, a.refused);
2734
+ const cwd = o.cwd;
2735
+ const id = `atticus-${++tn}`;
2736
+ const kill = new AbortController();
2737
+ flush();
2738
+ say(` atticus ${oneLine(a.argv.join(" "), 140)}`);
2739
+ const t = {
2740
+ output: "",
2741
+ kill,
2742
+ ...p.outputByteLimit ? { limit: p.outputByteLimit } : {}
2743
+ };
2744
+ t.done = o.exec(a.argv, {
2745
+ cwd,
2746
+ signal: kill.signal,
2747
+ onOutput: (s) => {
2748
+ t.output += s;
2749
+ if (t.limit && Buffer.byteLength(t.output) > t.limit)
2750
+ t.output = t.output.slice(-t.limit);
2751
+ }
2752
+ }).then((r) => {
2753
+ if (!t.output && r.output)
2754
+ t.output = r.output;
2755
+ t.exit = { exitCode: r.exitCode, signal: r.signal ?? null };
2756
+ record("terminal/create", input, `exit ${r.exitCode ?? "none"}: ${short(t.output, 1500)}`);
2757
+ return t.exit;
2758
+ });
2759
+ terminals.set(id, t);
2760
+ return { terminalId: id };
2761
+ },
2762
+ async terminalOutput(p) {
2763
+ const t = terminals.get(p.terminalId);
2764
+ if (!t)
2765
+ throw new AcpRpcError(ACP_ERRORS.invalidParams, `no terminal ${p.terminalId}`);
2766
+ return { output: t.output, truncated: false, ...t.exit ? { exitStatus: t.exit } : {} };
2767
+ },
2768
+ async terminalWaitForExit(p) {
2769
+ const t = terminals.get(p.terminalId);
2770
+ if (!t)
2771
+ throw new AcpRpcError(ACP_ERRORS.invalidParams, `no terminal ${p.terminalId}`);
2772
+ return t.done;
2773
+ },
2774
+ async terminalKill(p) {
2775
+ terminals.get(p.terminalId)?.kill.abort();
2776
+ return null;
2777
+ },
2778
+ async terminalRelease(p) {
2779
+ const t = terminals.get(p.terminalId);
2780
+ t?.kill.abort();
2781
+ terminals.delete(p.terminalId);
2782
+ return null;
2783
+ },
2784
+ update(u) {
2785
+ const kind = u.sessionUpdate;
2786
+ if (kind === UPDATE.message) {
2787
+ const t = chunkText(u);
2788
+ if (t) {
2789
+ text += t;
2790
+ pendingText += t;
2791
+ }
2792
+ } else if (kind === UPDATE.toolCall) {
2793
+ agentCalls++;
2794
+ flush();
2795
+ say(` \xB7 ${oneLine(String(u.title ?? u.kind ?? "a tool"), 140)}`);
2796
+ if (o.maxTurns !== void 0 && agentCalls > o.maxTurns)
2797
+ cancel(`maxTurns ${o.maxTurns}`);
2798
+ } else if (kind === UPDATE.plan) {
2799
+ const n = Array.isArray(u.entries) ? u.entries.length : 0;
2800
+ if (n)
2801
+ say(` Plan: ${n} steps`);
2802
+ }
2803
+ }
2804
+ };
2805
+ const client = new AcpClient(server.transport, handlers, (dir, m) => transcript.push(JSON.stringify({ dir, m })));
2806
+ box.client = client;
2807
+ const onAbort = () => cancel("stopped (Ctrl+C)");
2808
+ o.signal?.addEventListener("abort", onAbort, { once: true });
2809
+ let timer;
2810
+ try {
2811
+ let init;
2812
+ try {
2813
+ await server.started;
2814
+ init = await withTimeout(client.initialize({ name: "atticus", version: o.clientVersion ?? "2" }), 6e4, "The Copilot language server's initialize");
2815
+ } catch (e) {
2816
+ 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.`);
2817
+ }
2818
+ const assistant = {
2819
+ name: init.agentInfo?.name ?? basename(command).replace(/\.(cmd|exe)$/i, ""),
2820
+ ...init.agentInfo?.version ? { version: init.agentInfo.version } : {},
2821
+ ...typeof init.protocolVersion === "number" ? { protocolVersion: init.protocolVersion } : {}
2822
+ };
2823
+ let ns;
2824
+ try {
2825
+ ns = await withTimeout(client.newSession(o.cwd), 12e4, "Opening a Copilot session");
2826
+ } catch (e) {
2827
+ if (isAuthRequired(e)) {
2828
+ await new Promise((r) => setTimeout(r, 150));
2829
+ throw signInError(e, init, server.stderr());
2830
+ }
2831
+ throw new AcpSetupError(`The Copilot language server didn't open a session: ${firstLine(e)}`);
2832
+ }
2833
+ sessionId = ns.sessionId;
2834
+ let model = ns.models?.currentModelId;
2835
+ if (o.model && o.model !== model) {
2836
+ const offered = (ns.models?.availableModels ?? []).map((m) => m.modelId);
2837
+ if (!offered.includes(o.model))
2838
+ 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.`);
2839
+ await client.setModel(sessionId, o.model);
2840
+ model = o.model;
2841
+ }
2842
+ say(` Copilot session open (${assistant.name}${assistant.version ? ` ${assistant.version}` : ""}${model ? `, ${model}` : ""}).`);
2843
+ if (o.signal?.aborted)
2844
+ cancel("stopped (Ctrl+C)");
2845
+ timer = setTimeout(() => cancel("timeout"), o.timeoutMs ?? 30 * 6e4);
2846
+ let prompt = o.prompt;
2847
+ let answer = {
2848
+ stopReason: "end_turn"
2849
+ };
2850
+ const usages = [];
2851
+ for (let nudge = 0; ; nudge++) {
2852
+ const before = refused.length;
2853
+ const asked = client.prompt(sessionId, prompt);
2854
+ try {
2855
+ answer = await new Promise((res, rej) => {
2856
+ asked.then(res, rej);
2857
+ const watch = setInterval(() => {
2858
+ if (!cancelWhy)
2859
+ return;
2860
+ clearInterval(watch);
2861
+ setTimeout(() => res({ stopReason: "cancelled" }), 1e4);
2862
+ }, 50);
2863
+ asked.finally(() => clearInterval(watch)).catch(() => void 0);
2864
+ });
2865
+ } catch (e) {
2866
+ if (isAuthRequired(e))
2867
+ throw signInError(e, init, server.stderr());
2868
+ throw new RuntimeError(`The Copilot session failed: ${firstLine(e)}${tail(server.stderr())}`);
2869
+ }
2870
+ flush();
2871
+ if (answer.usage)
2872
+ usages.push(answer.usage);
2873
+ const fresh = refused.slice(before);
2874
+ const after = text.slice(textAtRefusal);
2875
+ const overIt = fresh.length > 0 && !!calls.at(-1)?.error && (!after.trim() || /cancel|refused|not allowed|can'?t|cannot|couldn'?t|unable/i.test(after));
2876
+ if (cancelWhy || !overIt || nudge >= MAX_NUDGES || !["end_turn", "cancelled"].includes(answer.stopReason))
2877
+ break;
2878
+ say(` Atticus: told Copilot why that was refused and to carry on (${nudge + 1} of ${MAX_NUDGES}).`);
2879
+ prompt = carryOnPrompt(fresh);
2880
+ }
2881
+ const usage = usageOf(sumUsage(usages));
2882
+ return {
2883
+ stopReason: cancelWhy ? "cancelled" : answer.stopReason,
2884
+ ...cancelWhy ? { stopped: cancelWhy } : {},
2885
+ ...model ? { model } : {},
2886
+ assistant,
2887
+ ...usage ? { usage } : {},
2888
+ text,
2889
+ toolCalls: calls,
2890
+ refused,
2891
+ agentToolCalls: agentCalls
2892
+ };
2893
+ } finally {
2894
+ clearTimeout(timer);
2895
+ o.signal?.removeEventListener("abort", onAbort);
2896
+ abort.abort();
2897
+ for (const t of terminals.values())
2898
+ t.kill.abort();
2899
+ await server.close().catch(() => void 0);
2900
+ if (o.transcript) {
2901
+ await mkdir5(dirname(o.transcript), { recursive: true });
2902
+ await writeFile4(o.transcript, transcript.join("\n") + (transcript.length ? "\n" : ""), "utf8");
2903
+ }
2904
+ }
2905
+ }
2906
+ var firstLine = (e) => String(e?.message ?? e).split("\n")[0];
2907
+ var tail = (stderr) => {
2908
+ const l = stderr.trim().split(/\r?\n/).slice(-2).join(" ").trim();
2909
+ return l ? ` (it said: ${short(l, 300)})` : "";
2910
+ };
2911
+ function signInError(e, init, stderr) {
2912
+ const how = (init.authMethods ?? []).map((m) => m.description || m.name).filter(Boolean).join("; ");
2913
+ const lines = signInLines(stderr);
2914
+ return new AcpSignInError([
2915
+ `GitHub Copilot isn't signed in here, so the run stopped. The Copilot language server said: ${firstLine(e)}`,
2916
+ ...lines.length ? [`It also said: ${lines.join(" ")}`] : [],
2917
+ ...how ? [`Its ways to sign in: ${how}.`] : [],
2918
+ "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."
2919
+ ].join("\n"));
2920
+ }
2921
+ function permissionRefused(tc, paths) {
2922
+ const locs = (tc.locations ?? []).map((l) => l.path);
2923
+ switch (tc.kind) {
2924
+ case "think":
2925
+ return void 0;
2926
+ case "read":
2927
+ case "search": {
2928
+ if (!locs.length)
2929
+ return tc.kind === "search" ? void 0 : "Refused: a read must say which file (use fs/read_text_file)";
2930
+ for (const l of locs) {
2931
+ const why = paths.readable(l);
2932
+ if (why)
2933
+ return why;
2934
+ }
2935
+ return void 0;
2936
+ }
2937
+ case "edit": {
2938
+ if (!locs.length)
2939
+ return "Refused: an edit must say which file it changes";
2940
+ for (const l of locs) {
2941
+ const why = paths.writable(l);
2942
+ if (why)
2943
+ return why;
2944
+ }
2945
+ return void 0;
2946
+ }
2947
+ case "execute": {
2948
+ const raw = tc.rawInput ?? {};
2949
+ const cmd = typeof raw.command === "string" ? raw.command : typeof raw.commandLine === "string" ? raw.commandLine : tc.title ?? "";
2950
+ const args = Array.isArray(raw.args) ? raw.args.map(String) : [];
2951
+ const a = atticusArgvOf(cmd, args);
2952
+ return a.refused;
2953
+ }
2954
+ default:
2955
+ 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)`;
2956
+ }
2957
+ }
2958
+ async function copilotAcpProbe(o) {
2959
+ const { command, args } = commandLineOf(o.command);
2960
+ const plain = args.filter((a) => a !== "--acp");
2961
+ const env = { ...process.env, ...o.env ?? {} };
2962
+ const version = await new Promise((res) => {
2963
+ const shell = needsShell(command);
2964
+ let out = "";
2965
+ let child;
2966
+ try {
2967
+ child = spawn(shell ? quoteForCmd(command) : command, [...shell ? plain.map(quoteForCmd) : plain, "--version"], {
2968
+ cwd: o.cwd,
2969
+ env,
2970
+ stdio: ["ignore", "pipe", "pipe"],
2971
+ windowsHide: true,
2972
+ shell
2973
+ });
2974
+ } catch (e) {
2975
+ res({ ok: false, text: e.message });
2976
+ return;
2977
+ }
2978
+ const t = setTimeout(() => killTree(child), o.timeoutMs ?? 6e4);
2979
+ child.stdout?.on("data", (d) => out += d.toString("utf8"));
2980
+ child.stderr?.on("data", (d) => out += d.toString("utf8"));
2981
+ child.on("error", (e) => {
2982
+ clearTimeout(t);
2983
+ res({ ok: false, text: e.message });
2984
+ });
2985
+ child.on("close", (code) => {
2986
+ clearTimeout(t);
2987
+ res({ ok: code === 0, text: out.trim() });
2988
+ });
2989
+ });
2990
+ if (!version.ok)
2991
+ return { found: false, said: oneLine(version.text, 200) };
2992
+ const v = version.text.split(/\r?\n/).find((l) => l.trim())?.trim();
2993
+ const server = (o.spawn ?? spawnAcpServer)({ command, args, cwd: o.cwd, env });
2994
+ const client = new AcpClient(server.transport, {
2995
+ readTextFile: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "doctor reads nothing")),
2996
+ writeTextFile: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "doctor writes nothing")),
2997
+ requestPermission: async () => ({ outcome: { outcome: "cancelled" } }),
2998
+ terminalCreate: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "doctor runs nothing")),
2999
+ terminalOutput: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "no terminal")),
3000
+ terminalWaitForExit: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "no terminal")),
3001
+ terminalKill: async () => null,
3002
+ terminalRelease: async () => null,
3003
+ update: () => {
3004
+ }
3005
+ });
3006
+ const base = { found: true, ...v ? { version: v } : {} };
3007
+ try {
3008
+ await server.started;
3009
+ await withTimeout(client.initialize({ name: "atticus-doctor", version: "2" }), o.timeoutMs ?? 6e4, "initialize");
3010
+ try {
3011
+ await withTimeout(client.newSession(o.cwd), o.timeoutMs ?? 6e4, "a new session");
3012
+ return { ...base, signedIn: true };
3013
+ } catch (e) {
3014
+ if (isAuthRequired(e)) {
3015
+ await new Promise((r) => setTimeout(r, 150));
3016
+ const lines = signInLines(server.stderr());
3017
+ return { ...base, signedIn: false, said: [firstLine(e), ...lines].join(" ") };
3018
+ }
3019
+ return { ...base, said: firstLine(e) };
3020
+ }
3021
+ } catch (e) {
3022
+ return { ...base, said: `the --acp handshake failed: ${firstLine(e)}` };
3023
+ } finally {
3024
+ await server.close().catch(() => void 0);
3025
+ }
3026
+ }
3027
+ var CopilotAcpRuntime = class extends OneShotRuntime {
3028
+ c;
3029
+ kind = "copilot-acp";
3030
+ constructor(c) {
3031
+ super({ ...c.now ? { now: c.now } : {}, ...c.validate ? { validate: c.validate } : {} });
3032
+ this.c = c;
3033
+ }
3034
+ allowedAs(agent) {
3035
+ return agent.allowedRuntimes.includes("copilot-acp") ? "copilot-acp" : "hand-off";
3036
+ }
3037
+ modelFor() {
3038
+ return this.c.model;
3039
+ }
3040
+ /** Review round 48: the run's folder is claimed, as a model run's is (claimRunDir). */
3041
+ async newRunId(request, now) {
3042
+ return claimRunDir(join5(runsDirOf(this.c.root), request.change), () => this.nextRunId(now));
3043
+ }
3044
+ async produce(run, signal) {
3045
+ const { request } = run;
3046
+ const root = this.c.root;
3047
+ const dir = join5(runsDirOf(root), request.change, run.runId);
3048
+ await mkdir5(dir, { recursive: true });
3049
+ const outRel = HandoffRuntime.outputRel(run, changesRelOf(root), runsRelOf(root));
3050
+ const prompt = HandoffRuntime.promptFor(run, changesRelOf(root), runsRelOf(root)).replace(/\nWhen the file is complete.*\n$/s, "\n") + (request.selfCheck ? `
3051
+ 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).
3052
+ ` : "") + `
3053
+ ${DATA_RULE}
3054
+ `;
3055
+ await writeFile4(join5(dir, "prompt.md"), prompt, "utf8");
3056
+ await writeFile4(join5(dir, "context-manifest.json"), JSON.stringify(request.pack.manifest, null, 2) + "\n", "utf8");
3057
+ const outputFile = request.outputIn === "run" ? join5(dir, request.outputPath) : join5(changesDirOf(root), request.change, request.outputPath);
3058
+ const before = (await stat2(outputFile).catch(() => void 0))?.mtimeMs;
3059
+ const r = await runAcpSession({
3060
+ command: this.c.command,
3061
+ cwd: root,
3062
+ prompt,
3063
+ policy: { readRoots: readRootsOf(root), writeRoots: [], writeFiles: [outputFile] },
3064
+ exec: this.c.exec ?? noExec,
3065
+ ...this.c.model ? { model: this.c.model } : {},
3066
+ ...this.c.maxTurns ? { maxTurns: this.c.maxTurns } : {},
3067
+ ...this.c.timeoutMs ? { timeoutMs: this.c.timeoutMs } : {},
3068
+ ...signal ? { signal } : {},
3069
+ ...this.c.onProgress ? { onProgress: this.c.onProgress } : {},
3070
+ ...this.c.env ? { env: this.c.env } : {},
3071
+ ...this.c.spawn ? { spawn: this.c.spawn } : {},
3072
+ ...this.c.clientVersion ? { clientVersion: this.c.clientVersion } : {},
3073
+ transcript: join5(dir, "transcript.jsonl")
3074
+ });
3075
+ const after = (await stat2(outputFile).catch(() => void 0))?.mtimeMs;
3076
+ const written = after !== void 0 && after !== before ? await readFile4(outputFile, "utf8") : void 0;
3077
+ const tools = {
3078
+ offered: ACP_OFFERED,
3079
+ calls: r.toolCalls,
3080
+ ...r.stopped ? { stopped: r.stopped } : {}
3081
+ };
3082
+ if (written === void 0 && r.stopReason !== "end_turn")
3083
+ throw Object.assign(new RuntimeError(`The Copilot session ended (${r.stopped ?? r.stopReason}) without writing ${outRel}.`), { tools });
3084
+ return {
3085
+ output: written ?? r.text,
3086
+ usage: r.usage ?? {
3087
+ inputTokens: request.pack.manifest.totalTokens,
3088
+ outputTokens: estimateTokens(r.text)
3089
+ },
3090
+ tools,
3091
+ ...r.model ? { model: r.model } : {},
3092
+ assistant: r.assistant
3093
+ };
3094
+ }
3095
+ /** Kept as a hand-off run is: run.json beside the prompt, so Model runs shows it. */
3096
+ async keep(run) {
3097
+ const dir = join5(runsDirOf(this.c.root), run.request.change, run.runId);
3098
+ await mkdir5(dir, { recursive: true });
3099
+ await writeFile4(join5(dir, "run.json"), JSON.stringify(run, null, 2) + "\n", "utf8");
3100
+ }
3101
+ };
3102
+ var noExec = async (argv) => ({
3103
+ exitCode: 127,
3104
+ output: `atticus ${argv.join(" ")}: this program can't run atticus commands for the session; run the step with the atticus command line.
3105
+ `
3106
+ });
3107
+ async function keepAcpRun(o) {
3108
+ const dir = join5(runsDirOf(o.root), o.change, o.runId);
3109
+ await mkdir5(dir, { recursive: true });
3110
+ if (!existsSync(join5(dir, "prompt.md")))
3111
+ await writeFile4(join5(dir, "prompt.md"), o.prompt, "utf8");
3112
+ const r = o.result;
3113
+ const run = {
3114
+ runId: o.runId,
3115
+ request: { change: o.change, agent: o.agent, outputPath: o.outputPath },
3116
+ runtime: "copilot-acp",
3117
+ state: o.state,
3118
+ attempt: 1,
3119
+ startedAt: o.startedAt,
3120
+ finishedAt: o.finishedAt,
3121
+ errors: o.errors,
3122
+ ...r?.usage ? { usage: r.usage } : {},
3123
+ ...r ? {
3124
+ tools: {
3125
+ offered: ACP_OFFERED,
3126
+ calls: r.toolCalls,
3127
+ ...r.stopped ? { stopped: r.stopped } : {}
3128
+ }
3129
+ } : {},
3130
+ stepClass: o.stepClass ?? stepClassOf({ agent: o.agent }),
3131
+ ...r?.model ? { model: r.model } : {},
3132
+ ...r ? { assistant: r.assistant } : {}
3133
+ };
3134
+ await writeFile4(join5(dir, "run.json"), JSON.stringify(run, null, 2) + "\n", "utf8");
3135
+ return dir;
3136
+ }
3137
+
3138
+ // packages/ai/dist/factory.js
1702
3139
  var RUNTIME_MODES = RuntimeKind.options;
1703
- var CONFIGURED = ["hand-off", "model", "headless-claude-code"];
3140
+ var CONFIGURED = [
3141
+ "hand-off",
3142
+ "model",
3143
+ "headless-claude-code",
3144
+ "copilot-acp"
3145
+ ];
1704
3146
  var RuntimeConfigError = class extends RuntimeError {
1705
3147
  constructor(message) {
1706
3148
  super(message);
@@ -1713,16 +3155,49 @@ var AiOffError = class extends RuntimeConfigError {
1713
3155
  }
1714
3156
  };
1715
3157
  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) => {
3158
+ return (i) => {
3159
+ const command = resolveWindowsCommand(o.command ?? "claude");
3160
+ const shell = isShim(command);
3161
+ let started;
3162
+ const end = () => {
3163
+ if (started)
3164
+ killTree(started);
3165
+ };
3166
+ if (shell && i.signal) {
3167
+ if (i.signal.aborted)
3168
+ queueMicrotask(end);
3169
+ else
3170
+ i.signal.addEventListener("abort", end, { once: true });
3171
+ }
3172
+ return collectChild(() => {
3173
+ started = spawn2(shell ? quoteForCmdAlways(command) : command, shell ? i.args.map(quoteForCmdAlways) : i.args, {
3174
+ cwd: i.cwd,
3175
+ env: { ...process.env, ...i.env },
3176
+ stdio: ["pipe", "pipe", "pipe"],
3177
+ windowsHide: true,
3178
+ shell,
3179
+ ...i.signal && !shell ? { signal: i.signal } : {}
3180
+ });
3181
+ return started;
3182
+ }, i.prompt, i.timeoutMs, i.cwd, process.platform, shell ? (c) => killTree(c) : void 0);
3183
+ };
3184
+ }
3185
+ var isShim = (command, platform = process.platform) => platform === "win32" && /\.(cmd|bat)$/i.test(command);
3186
+ function resolveWindowsCommand(command, env = process.env, platform = process.platform, exists = existsSync2) {
3187
+ if (platform !== "win32" || /[\\/]/.test(command) || /\.[a-z0-9]+$/i.test(command))
3188
+ return command;
3189
+ const exts = (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean);
3190
+ for (const dir of (env.Path ?? env.PATH ?? "").split(";").map((d) => d.trim().replace(/^"(.*)"$/, "$1")).filter(Boolean))
3191
+ for (const ext of exts) {
3192
+ const full = `${dir.replace(/[\\/]+$/, "")}\\${command}${ext.toLowerCase()}`;
3193
+ if (exists(full))
3194
+ return full;
3195
+ }
3196
+ return command;
3197
+ }
3198
+ var quoteForCmdAlways = (a) => `"${a.replace(/"/g, '""')}"`;
3199
+ function collectChild(start, prompt, timeoutMs, cwd, platform = process.platform, stop) {
3200
+ return new Promise((resolve2, reject) => {
1726
3201
  let done = false;
1727
3202
  const timer = {};
1728
3203
  const fail = (e) => {
@@ -1743,7 +3218,7 @@ function collectChild(start, prompt, timeoutMs, cwd, platform = process.platform
1743
3218
  }
1744
3219
  let stdout = "";
1745
3220
  let stderr = "";
1746
- timer.id = setTimeout(() => child.kill("SIGINT"), timeoutMs);
3221
+ timer.id = setTimeout(() => stop ? stop(child) : child.kill("SIGINT"), timeoutMs);
1747
3222
  for (const s of [child.stdin, child.stdout, child.stderr])
1748
3223
  s.on("error", fail);
1749
3224
  child.stdout.setEncoding("utf8").on("data", (d) => stdout += d);
@@ -1754,16 +3229,16 @@ function collectChild(start, prompt, timeoutMs, cwd, platform = process.platform
1754
3229
  return;
1755
3230
  done = true;
1756
3231
  clearTimeout(timer.id);
1757
- resolve({ exitCode: code, stdout, stderr });
3232
+ resolve2({ exitCode: code, stdout, stderr });
1758
3233
  });
1759
3234
  child.stdin.end(prompt, "utf8");
1760
3235
  });
1761
3236
  }
1762
- var cloneDirs = (root) => [join4(root, "workspace"), join4(stateDirOf(root), "workspace")];
3237
+ var cloneDirs = (root) => [join6(root, "workspace"), join6(stateDirOf(root), "workspace")];
1763
3238
  async function existingDirs(dirs) {
1764
3239
  const out = [];
1765
3240
  for (const d of [...new Set(dirs)])
1766
- if ((await stat2(d).catch(() => void 0))?.isDirectory())
3241
+ if ((await stat3(d).catch(() => void 0))?.isDirectory())
1767
3242
  out.push(d);
1768
3243
  return out;
1769
3244
  }
@@ -1800,9 +3275,9 @@ var HeadlessClaudeCodeRuntime = class _HeadlessClaudeCodeRuntime extends OneShot
1800
3275
  }
1801
3276
  async produce(run, signal) {
1802
3277
  const { request } = run;
1803
- const dir = join4(runsDirOf(this.h.root), request.change, run.runId);
3278
+ const dir = join6(runsDirOf(this.h.root), request.change, run.runId);
1804
3279
  const reviewer = request.agent.outputArtifact === "findings" && request.outputIn === "run";
1805
- const work = reviewer ? await mkdtemp(join4(tmpdir(), "atticus-review-")) : void 0;
3280
+ const work = reviewer ? await mkdtemp(join6(tmpdir(), "atticus-review-")) : void 0;
1806
3281
  const clones = work ? await existingDirs(cloneDirs(this.h.root)) : [];
1807
3282
  const base = work ? {
1808
3283
  cwd: work,
@@ -1816,27 +3291,27 @@ var HeadlessClaudeCodeRuntime = class _HeadlessClaudeCodeRuntime extends OneShot
1816
3291
  `Bash(${request.selfCheck.command}:*)`
1817
3292
  ]
1818
3293
  } : base;
1819
- await mkdir4(dir, { recursive: true });
1820
- const promptFile = join4(dir, "prompt.md");
3294
+ await mkdir6(dir, { recursive: true });
3295
+ const promptFile = join6(dir, "prompt.md");
1821
3296
  const self = reviewer ? void 0 : request.selfCheck;
1822
3297
  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
3298
  (self ? `
1824
3299
  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
3300
  ` : "");
1826
3301
  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))
3302
+ await writeFile5(promptFile, prompt, "utf8");
3303
+ await writeFile5(join6(dir, "context-manifest.json"), JSON.stringify(request.pack.manifest, null, 2) + "\n", "utf8");
3304
+ if (!await stat3(inv.cwd).catch(() => void 0))
1830
3305
  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);
3306
+ const outputFile = work ? join6(work, request.outputPath) : request.outputIn === "run" ? join6(dir, request.outputPath) : join6(changesDirOf(this.h.root), request.change, request.outputPath);
1832
3307
  try {
1833
3308
  return await this.runIn(run, dir, inv, prompt, promptFile, outputFile, signal);
1834
3309
  } finally {
1835
3310
  if (work) {
1836
- const kept = await readFile4(outputFile, "utf8").catch(() => void 0);
3311
+ const kept = await readFile5(outputFile, "utf8").catch(() => void 0);
1837
3312
  if (kept !== void 0) {
1838
- await mkdir4(dirname(join4(dir, request.outputPath)), { recursive: true });
1839
- await writeFile4(join4(dir, request.outputPath), kept, "utf8");
3313
+ await mkdir6(dirname2(join6(dir, request.outputPath)), { recursive: true });
3314
+ await writeFile5(join6(dir, request.outputPath), kept, "utf8");
1840
3315
  }
1841
3316
  await rm2(work, { recursive: true, force: true, maxRetries: 5 }).catch(() => void 0);
1842
3317
  }
@@ -1844,7 +3319,7 @@ Before you finish, check the file: run ${self.command} ${HandoffRuntime.outputRe
1844
3319
  }
1845
3320
  async runIn(run, dir, inv, prompt, promptFile, outputFile, signal) {
1846
3321
  const { request } = run;
1847
- const before = (await stat2(outputFile).catch(() => void 0))?.mtimeMs;
3322
+ const before = (await stat3(outputFile).catch(() => void 0))?.mtimeMs;
1848
3323
  const res = await this.runner({
1849
3324
  cwd: inv.cwd,
1850
3325
  prompt,
@@ -1860,7 +3335,7 @@ Before you finish, check the file: run ${self.command} ${HandoffRuntime.outputRe
1860
3335
  timeoutMs: this.h.timeoutMs ?? 30 * 6e4,
1861
3336
  ...signal ? { signal } : {}
1862
3337
  });
1863
- await writeFile4(join4(dir, "claude-output.json"), res.stdout, "utf8");
3338
+ await writeFile5(join6(dir, "claude-output.json"), res.stdout, "utf8");
1864
3339
  let parsed;
1865
3340
  try {
1866
3341
  parsed = JSON.parse(res.stdout);
@@ -1870,8 +3345,8 @@ Before you finish, check the file: run ${self.command} ${HandoffRuntime.outputRe
1870
3345
  const text = typeof parsed.result === "string" ? parsed.result : "";
1871
3346
  if (res.exitCode !== 0 || parsed.is_error === true)
1872
3347
  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;
3348
+ const after = (await stat3(outputFile).catch(() => void 0))?.mtimeMs;
3349
+ const written = after !== void 0 && after !== before ? await readFile5(outputFile, "utf8") : void 0;
1875
3350
  return {
1876
3351
  output: written ?? text,
1877
3352
  usage: {
@@ -1916,6 +3391,10 @@ var toolSource;
1916
3391
  function registerToolSource(source) {
1917
3392
  toolSource = source;
1918
3393
  }
3394
+ var acpRunner;
3395
+ function registerCopilotAcp(o) {
3396
+ acpRunner = o;
3397
+ }
1919
3398
  function classModels(rt, o) {
1920
3399
  const by = modelsByClass(rt, o.env ?? {});
1921
3400
  const out = {};
@@ -1937,17 +3416,19 @@ function classModels(rt, o) {
1937
3416
  }
1938
3417
  var told = /* @__PURE__ */ new WeakMap();
1939
3418
  var nonEmpty = async (file, request) => {
1940
- const text = await readFile4(file, "utf8").catch(() => "");
3419
+ const text = await readFile5(file, "utf8").catch(() => "");
1941
3420
  return text.trim() ? [] : [`${request.outputPath} is empty`];
1942
3421
  };
1943
3422
  async function createRuntime(orgPack, o) {
1944
3423
  const rt = orgPack.runtime;
1945
- const mode = o.mode ?? rt.modes.default;
3424
+ const asked = o.mode ?? rt.modes.default;
3425
+ const inSession = !!(o.env ?? process.env).ATTICUS_ACP_SESSION;
3426
+ const mode = asked === "copilot-acp" && inSession ? "hand-off" : asked;
1946
3427
  if (!RUNTIME_MODES.includes(mode))
1947
3428
  throw new RuntimeConfigError(`There is no AI mode called ${String(mode)}. Use one of: ${RUNTIME_MODES.join(", ")}.`);
1948
3429
  if (rt.ai === "off" && CONFIGURED.includes(mode))
1949
3430
  throw new AiOffError();
1950
- if (CONFIGURED.includes(mode) && !rt.modes.allowed.includes(mode))
3431
+ if (CONFIGURED.includes(mode) && !rt.modes.allowed.includes(mode) && !(inSession && asked === "copilot-acp"))
1951
3432
  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
3433
  const one = { ...o.now ? { now: o.now } : {}, ...o.validate ? { validate: o.validate } : {} };
1953
3434
  switch (mode) {
@@ -1955,7 +3436,9 @@ async function createRuntime(orgPack, o) {
1955
3436
  return new HandoffRuntime({
1956
3437
  root: o.root,
1957
3438
  validate: o.handoffValidate ?? nonEmpty,
1958
- ...o.now ? { now: o.now } : {}
3439
+ ...o.now ? { now: o.now } : {},
3440
+ // ADR 0185: a stage's critic lenses go to the person's assistant in one prompt.
3441
+ batch: true
1959
3442
  });
1960
3443
  case "model": {
1961
3444
  const cfg = rt.adapters.model;
@@ -1995,6 +3478,22 @@ async function createRuntime(orgPack, o) {
1995
3478
  ...o.validate ? { validate: o.validate } : {}
1996
3479
  });
1997
3480
  }
3481
+ case "copilot-acp": {
3482
+ if (!rt.assistants.allowed.includes("copilot"))
3483
+ throw new RuntimeConfigError("copilot-acp drives GitHub Copilot, which runtime.yaml doesn't list under assistants.allowed.");
3484
+ const c = copilotAcpOf(rt);
3485
+ return new CopilotAcpRuntime({
3486
+ root: o.root,
3487
+ command: c.command,
3488
+ ...c.model ? { model: c.model } : {},
3489
+ maxTurns: c.maxTurns,
3490
+ timeoutMs: c.timeoutMs,
3491
+ ...acpRunner,
3492
+ ...o.copilotAcp,
3493
+ ...o.now ? { now: o.now } : {},
3494
+ ...o.validate ? { validate: o.validate } : {}
3495
+ });
3496
+ }
1998
3497
  case "replay":
1999
3498
  if (o.recordings)
2000
3499
  return new ReplayRuntime(o.recordings, one);
@@ -2011,13 +3510,13 @@ var sayOnce = (line) => process.stderr.write(`${line}
2011
3510
  `);
2012
3511
  async function runtimeForCli(root, o = {}) {
2013
3512
  const env = o.env ?? process.env;
2014
- const op = await loadOrgPack(join4(orgPackDirOf(root)));
3513
+ const op = await loadOrgPack(join6(orgPackDirOf(root)));
2015
3514
  const bad = op.problems.filter((p) => p.file === "runtime.yaml");
2016
3515
  if (bad.length)
2017
3516
  throw new RuntimeConfigError(`org-pack/runtime.yaml has problems: ${bad.map((p) => `${p.path ? `${p.path}: ` : ""}${p.message}`).join("; ")}`);
2018
3517
  const asked = o.mode ?? env.ATTICUS_RUNTIME ?? op.runtime.modes.default;
2019
3518
  if (asked === "mock")
2020
- throw new RuntimeConfigError("Mock mode is for tests; use hand-off, model, headless-claude-code or replay.");
3519
+ throw new RuntimeConfigError("Mock mode is for tests; use hand-off, model, headless-claude-code, copilot-acp or replay.");
2021
3520
  const mode = asked;
2022
3521
  const runtime = await createRuntime(op, {
2023
3522
  root,
@@ -2025,13 +3524,14 @@ async function runtimeForCli(root, o = {}) {
2025
3524
  ...env.ATTICUS_REPLAY_DIR ? { replayDir: env.ATTICUS_REPLAY_DIR } : {},
2026
3525
  ...o.providers ? { providers: o.providers } : {},
2027
3526
  ...o.headless ? { headless: o.headless } : {},
3527
+ ...o.copilotAcp ? { copilotAcp: o.copilotAcp } : {},
2028
3528
  ...o.handoffValidate ? { handoffValidate: o.handoffValidate } : {},
2029
3529
  // ADR 0121 addendum: the person's model per kind of step, and a model passed over said once.
2030
3530
  env,
2031
3531
  onNote: o.onNote ?? sayOnce
2032
3532
  });
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 };
3533
+ 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.";
3534
+ return { runtime, mode: runtime.kind === "hand-off" ? "hand-off" : mode, describe };
2035
3535
  }
2036
3536
 
2037
3537
  // packages/ai/dist/attempts.js
@@ -2127,8 +3627,8 @@ var HashEmbedder = class {
2127
3627
  return { i: h.readUInt32BE(0) % this.dim, sign: h[4] & 1 ? 1 : -1 };
2128
3628
  };
2129
3629
  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)) {
3630
+ const words2 = [m[0].toLowerCase(), ...identifierWords(m[0])];
3631
+ for (const w of new Set(words2)) {
2132
3632
  if (w.length < 3)
2133
3633
  continue;
2134
3634
  const b = bucket(`w:${w}`);
@@ -2618,6 +4118,10 @@ function recordedJudge(byTexts, o = {}) {
2618
4118
  }
2619
4119
 
2620
4120
  export {
4121
+ withoutLegacy,
4122
+ personOnlyWhy,
4123
+ isPersonsFactsFile,
4124
+ windowsName,
2621
4125
  DEFENCES_VERSION,
2622
4126
  INSTRUCTION_RULES,
2623
4127
  riskAtLeast,
@@ -2651,7 +4155,7 @@ export {
2651
4155
  BIGGER_MODEL,
2652
4156
  PromptTooLong,
2653
4157
  sha2562 as sha256,
2654
- estimateTokens,
4158
+ RequiredSourceLeftOut,
2655
4159
  wrapData,
2656
4160
  DATA_RULE,
2657
4161
  buildContextPack,
@@ -2667,6 +4171,7 @@ export {
2667
4171
  RuntimeError,
2668
4172
  checkAllowed,
2669
4173
  makeRunId,
4174
+ claimRunDir,
2670
4175
  toRunSummary,
2671
4176
  OneShotRuntime,
2672
4177
  ToolError,
@@ -2683,12 +4188,45 @@ export {
2683
4188
  recordRun,
2684
4189
  MockModelProvider,
2685
4190
  ModelRuntime,
4191
+ BATCH_OUTPUT,
4192
+ DEFAULT_BATCH_MAX_TOKENS,
4193
+ batchSections,
2686
4194
  HandoffRuntime,
2687
4195
  pruneRuns,
4196
+ ACP_PROTOCOL_VERSION,
4197
+ ACP_METHODS,
4198
+ ACP_ERRORS,
4199
+ AcpRpcError,
4200
+ AcpClient,
4201
+ chunkText,
4202
+ UPDATE,
4203
+ usageOf,
4204
+ isAuthRequired,
4205
+ commandLineOf,
4206
+ atticusArgvOf,
4207
+ acpPathsOf,
4208
+ factsOnly,
4209
+ readRootsOf,
4210
+ needsShell,
4211
+ quoteForCmd,
4212
+ killTree,
4213
+ spawnAcpServer,
4214
+ atticusExec,
4215
+ AcpSignInError,
4216
+ AcpSetupError,
4217
+ MAX_NUDGES,
4218
+ carryOnPrompt,
4219
+ ACP_OFFERED,
4220
+ runAcpSession,
4221
+ copilotAcpProbe,
4222
+ CopilotAcpRuntime,
4223
+ keepAcpRun,
2688
4224
  RUNTIME_MODES,
2689
4225
  RuntimeConfigError,
2690
4226
  AiOffError,
2691
4227
  claudeCodeCliRunner,
4228
+ resolveWindowsCommand,
4229
+ quoteForCmdAlways,
2692
4230
  collectChild,
2693
4231
  posixPath,
2694
4232
  HeadlessClaudeCodeRuntime,
@@ -2699,6 +4237,7 @@ export {
2699
4237
  registeredModelProviders,
2700
4238
  clearModelProviders,
2701
4239
  registerToolSource,
4240
+ registerCopilotAcp,
2702
4241
  createRuntime,
2703
4242
  runtimeForCli,
2704
4243
  resumedAttempt,