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