@maycombhq/atticus 2.0.0-beta.21 → 2.0.0-beta.23
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 +12 -7
- package/dist/{chunk-BXBCMGIQ.js → chunk-24OXGB3P.js} +1 -1
- package/dist/{chunk-PRW3HXM3.js → chunk-27AJAKX7.js} +29 -5
- package/dist/{chunk-PQH56YF6.js → chunk-2QPJ4E4Z.js} +6 -4
- package/dist/{chunk-7CZHUZBL.js → chunk-2UMSHYCB.js} +38 -27
- package/dist/{chunk-2V2ZPQQU.js → chunk-2WUTCPPJ.js} +9 -7
- package/dist/{chunk-YF5DZCPN.js → chunk-2YSD6E6V.js} +38 -34
- package/dist/{chunk-QHJJMZLX.js → chunk-3424TLIJ.js} +204 -97
- package/dist/{chunk-62DLJSLV.js → chunk-3ASYYMOX.js} +10 -8
- package/dist/{chunk-XOL3GFW2.js → chunk-3EWKO457.js} +111 -43
- package/dist/{chunk-G5YJBNDZ.js → chunk-3EX5HCZD.js} +8 -6
- package/dist/{chunk-WFU77T3A.js → chunk-3MYBT62N.js} +5 -5
- package/dist/{chunk-6EXDI5GI.js → chunk-3UHV76UD.js} +72 -41
- package/dist/{chunk-LU4MQVAL.js → chunk-3ZA3AK2D.js} +11 -10
- package/dist/{chunk-P2VBXX7N.js → chunk-4ETO2FXE.js} +11 -9
- package/dist/{chunk-GK4PYVEC.js → chunk-4FLNCK6Q.js} +31 -14
- package/dist/{chunk-64AADMTW.js → chunk-4GAB5ZOZ.js} +943 -336
- package/dist/{chunk-FLVZFTLQ.js → chunk-4MYHETJ3.js} +20 -18
- package/dist/chunk-4R3TO4VL.js +94 -0
- package/dist/{chunk-7EFILTCI.js → chunk-5F7GFN2F.js} +28 -0
- package/dist/chunk-5MYE42AP.js +43 -0
- package/dist/chunk-5O7U67UA.js +57 -0
- package/dist/{chunk-MZGRDONP.js → chunk-5OXKCH4Z.js} +54 -37
- package/dist/{chunk-PUEWDYGP.js → chunk-5VTIWEWP.js} +3 -2
- package/dist/{chunk-3G6S7LAA.js → chunk-63NFFAGI.js} +14 -12
- package/dist/{chunk-LIJJCBQI.js → chunk-66AQ2JIU.js} +15 -16
- package/dist/chunk-6JVPBGQG.js +50 -0
- package/dist/{chunk-WAZEXEJH.js → chunk-6NCPLIIP.js} +167 -2
- package/dist/{chunk-D57MFJPP.js → chunk-6NN36LVK.js} +3 -3
- package/dist/{chunk-G6IQYM25.js → chunk-6R5VHR3N.js} +8 -6
- package/dist/{chunk-Z3QFH7YG.js → chunk-6RQOINER.js} +5 -4
- package/dist/{chunk-TQTRWENN.js → chunk-6RYB3EET.js} +14 -12
- package/dist/{chunk-FYBF5MB2.js → chunk-6SNTHK43.js} +13 -11
- package/dist/{chunk-FRHD22WM.js → chunk-6Y4FXOMI.js} +27 -23
- package/dist/{chunk-LWDNKE4X.js → chunk-6ZFF7XSL.js} +6 -6
- package/dist/{chunk-FQ6WH6PB.js → chunk-6ZSYLZ7O.js} +6 -4
- package/dist/{chunk-LQH4P45K.js → chunk-73CC73I4.js} +1 -1
- package/dist/{chunk-Q46QDDMF.js → chunk-73GFVW2L.js} +14 -9
- package/dist/{chunk-QKMRFNMA.js → chunk-73V2OONC.js} +17 -15
- package/dist/{chunk-FVMPFCDS.js → chunk-75OMRKY2.js} +4 -4
- package/dist/{chunk-XEQCQO66.js → chunk-7IFTSAHP.js} +10 -8
- package/dist/{chunk-4FOAYLI4.js → chunk-7K5OH45X.js} +139 -17
- package/dist/{chunk-3SSTNB4E.js → chunk-7NQAGYK4.js} +34 -14
- package/dist/{chunk-URIKUID7.js → chunk-7XWJ6ED2.js} +14 -12
- package/dist/{chunk-TYD6I4CZ.js → chunk-7XYLNQFO.js} +7 -7
- package/dist/{chunk-BPPU3PW7.js → chunk-7YQBDE5W.js} +10 -4
- package/dist/{chunk-CPK7QSBG.js → chunk-A4JXVO5O.js} +8 -6
- package/dist/{chunk-YJ3TBOTK.js → chunk-AFBCNZRZ.js} +29 -26
- package/dist/{chunk-TW3KOSQK.js → chunk-AGOLEMHK.js} +13 -13
- package/dist/chunk-AHFQHPFF.js +49 -0
- package/dist/{chunk-NTAVOWYD.js → chunk-APDN6UOR.js} +118 -18
- package/dist/chunk-AQRUQNFB.js +322 -0
- package/dist/{chunk-KYZMRSPS.js → chunk-AVMWESFZ.js} +6 -3
- package/dist/chunk-B4AEL3RF.js +1011 -0
- package/dist/{chunk-GS76RXQE.js → chunk-BAY4K55I.js} +15 -12
- package/dist/{chunk-4CLK2RJO.js → chunk-BFL4PO64.js} +9 -7
- package/dist/{chunk-GCS3FZOB.js → chunk-BFMTGNAQ.js} +15 -4
- package/dist/{chunk-YBOVNMHC.js → chunk-BP33TBLI.js} +29 -16
- package/dist/chunk-BQGDB6ZL.js +7342 -0
- package/dist/{chunk-BXZ4PKIT.js → chunk-BUUJ7N4O.js} +15 -11
- package/dist/{chunk-HGHRSF3E.js → chunk-BYBU2EIB.js} +38 -19
- package/dist/{chunk-TQ4TG57V.js → chunk-C6ORPLCN.js} +4 -4
- package/dist/{chunk-HWD4JPU7.js → chunk-CA3DKO4D.js} +27 -3
- package/dist/{chunk-YTTNTQOX.js → chunk-CFUDAW3R.js} +17 -15
- package/dist/{chunk-OPQZISG3.js → chunk-CJEBRJBS.js} +5 -4
- package/dist/{chunk-RALY3E5U.js → chunk-CKVBDVIW.js} +6 -4
- package/dist/{chunk-DUPZPDCJ.js → chunk-CMB7FXHJ.js} +42 -16
- package/dist/{chunk-YIGBJNH4.js → chunk-CQ7RF4QN.js} +5 -4
- package/dist/{chunk-YAH5IQAL.js → chunk-CS4BMJLL.js} +6 -5
- package/dist/{chunk-455SYIIE.js → chunk-CT6NINGR.js} +5 -3
- package/dist/chunk-CXTG6AWM.js +40 -0
- package/dist/{chunk-JYMIB5XY.js → chunk-CZ2ZS7AT.js} +170 -45
- package/dist/{chunk-K332XW7K.js → chunk-D6BVLTDV.js} +100 -33
- package/dist/chunk-DCRYOMTM.js +37 -0
- package/dist/{chunk-G6X4YL4D.js → chunk-DHKDH464.js} +5 -4
- package/dist/{chunk-JRVNXLZP.js → chunk-DSHRA72L.js} +14 -12
- package/dist/{chunk-LNWEWYCM.js → chunk-E3PDCQRH.js} +2813 -621
- package/dist/chunk-EHXDB3SA.js +25 -0
- package/dist/{chunk-EZIN5E5B.js → chunk-EMVZIOOD.js} +11 -9
- package/dist/{chunk-IFHDV6KQ.js → chunk-ENH6Z4TY.js} +21 -20
- package/dist/{chunk-YKTE2RU3.js → chunk-EVTI22PQ.js} +7 -2
- package/dist/{chunk-2D7PWSOK.js → chunk-EXJZBL5N.js} +22 -20
- package/dist/{chunk-77O633L5.js → chunk-FBCVC2GJ.js} +14 -12
- package/dist/{chunk-HS4BGB4G.js → chunk-FJVUHQPS.js} +37 -24
- package/dist/{chunk-4KNOJC6J.js → chunk-FL344WQD.js} +270 -221
- package/dist/{chunk-GNWAOVFQ.js → chunk-FMJYKLDY.js} +5 -5
- package/dist/chunk-FMR2D3AZ.js +41 -0
- package/dist/{chunk-PAINMSID.js → chunk-FPBUTZI5.js} +3102 -7859
- package/dist/{chunk-ZOSD4FXV.js → chunk-FQVSLBTV.js} +3 -3
- package/dist/chunk-FRAEQVYN.js +52 -0
- package/dist/{chunk-UDXWIPCB.js → chunk-FRCOKUU4.js} +9 -7
- package/dist/{chunk-UYLBRRFK.js → chunk-FSN6JFXB.js} +129 -27
- package/dist/{chunk-BC6KKZ67.js → chunk-FTLYXMHA.js} +9 -6
- package/dist/{chunk-FAJDKNSD.js → chunk-FVYZ4Y52.js} +16 -3
- package/dist/{chunk-TWQRPM76.js → chunk-G6EFXTUO.js} +23 -16
- package/dist/{chunk-ZFQMMU5Y.js → chunk-G7VBMOZH.js} +6 -2
- package/dist/{chunk-VYOCPTUB.js → chunk-GM4EFHUX.js} +17 -15
- package/dist/chunk-GOZLTLRY.js +232 -0
- package/dist/chunk-GPNMSX5H.js +36 -0
- package/dist/{chunk-OZJ3JLYI.js → chunk-GUGQSIQM.js} +10 -9
- package/dist/chunk-H4VO6WG3.js +10 -0
- package/dist/{chunk-QJCJOMW3.js → chunk-HJQVUOUL.js} +16 -18
- package/dist/chunk-HMWJWYE2.js +31 -0
- package/dist/{chunk-4TKVU2I2.js → chunk-HMZ2DRBC.js} +2 -2
- package/dist/{chunk-HK3VOHIE.js → chunk-HRS5O7VV.js} +609 -171
- package/dist/{chunk-7FUIVIBG.js → chunk-HUGQZQ2K.js} +13 -8
- package/dist/{chunk-QOOEYDNJ.js → chunk-ICBGVVRI.js} +10 -10
- package/dist/{chunk-XG4WJHLQ.js → chunk-IGOE6KPG.js} +49 -20
- package/dist/{chunk-4SLBCEPD.js → chunk-IKAW2KJU.js} +95 -64
- package/dist/{chunk-L4CESDPB.js → chunk-IMZFOMVX.js} +1 -1
- package/dist/{chunk-XQ3YZ4QW.js → chunk-ISG547IS.js} +24 -22
- package/dist/{chunk-BA2HUMDN.js → chunk-IYNCSYU4.js} +5 -2
- package/dist/{chunk-UEVZZZU2.js → chunk-J25YOUIZ.js} +5 -4
- package/dist/chunk-J2CDBSFP.js +69 -0
- package/dist/chunk-J2H7YG3K.js +34 -0
- package/dist/{chunk-O4IKAIZ2.js → chunk-J32IPTVQ.js} +28 -22
- package/dist/{chunk-3AQ2R5NL.js → chunk-J4CPHJUL.js} +11 -9
- package/dist/{chunk-VUVGX5L2.js → chunk-JFFKHIM6.js} +1 -1
- package/dist/chunk-JMEWJPF2.js +384 -0
- package/dist/{chunk-LO3BLMVG.js → chunk-JSP73CDW.js} +13 -5
- package/dist/chunk-JXAKYP45.js +63 -0
- package/dist/{chunk-PNQLCRSS.js → chunk-K4OXYSGS.js} +7 -5
- package/dist/{chunk-3J5I7ZOU.js → chunk-K4RNVDR4.js} +4 -4
- package/dist/{chunk-LEBR5NHW.js → chunk-K757G7AD.js} +18 -15
- package/dist/{chunk-AHW3RY3X.js → chunk-KDJ2YKAZ.js} +8 -7
- package/dist/{chunk-4WXRPQDE.js → chunk-KT6Q44CA.js} +178 -31
- package/dist/{chunk-EFCQSMXB.js → chunk-KTNOBTV5.js} +10 -4
- package/dist/chunk-KVVNAUIG.js +66 -0
- package/dist/{chunk-26Z7OGQW.js → chunk-L3RCQWVQ.js} +64 -31
- package/dist/{chunk-3WON4G3M.js → chunk-LHH5KG5A.js} +21 -6
- package/dist/{chunk-NCB6656Z.js → chunk-LM45GMMB.js} +11 -8
- package/dist/{chunk-2HH3UCZM.js → chunk-LO6Y7OTG.js} +5 -4
- package/dist/{chunk-36RY7ZXM.js → chunk-LPDTDFKA.js} +88 -26
- package/dist/{chunk-67BP7HXL.js → chunk-LSHSDC6S.js} +19 -17
- package/dist/{chunk-GDZB57IU.js → chunk-LZVHP7CT.js} +7 -5
- package/dist/{chunk-GC2VK3JT.js → chunk-M3EOFSPY.js} +28 -25
- package/dist/chunk-MBYYQHPM.js +31 -0
- package/dist/{chunk-HXXP2NTE.js → chunk-MEJ63LDG.js} +35 -12
- package/dist/{chunk-2UCRFXFZ.js → chunk-MH2ZK67S.js} +13 -11
- package/dist/{chunk-BEPCKDCP.js → chunk-MLGWSBF4.js} +5447 -4165
- package/dist/{chunk-NRQ65LTQ.js → chunk-MNIPPBCT.js} +6 -5
- package/dist/{chunk-3LZ6P5EP.js → chunk-MUWDB4R4.js} +1 -1
- package/dist/{chunk-KDAHXQIE.js → chunk-MWF4PXQR.js} +38 -34
- package/dist/{chunk-WNTIOBOG.js → chunk-N2YX6JMY.js} +20 -18
- package/dist/{chunk-FY3QIRTL.js → chunk-NAPHHWW2.js} +3 -3
- package/dist/{chunk-D2WSW4GU.js → chunk-NC755EKE.js} +8 -2
- package/dist/{chunk-BA3U7ALS.js → chunk-NCLZJCXA.js} +26 -22
- package/dist/chunk-NKJDO4UC.js +39 -0
- package/dist/chunk-NOYOFYAJ.js +59 -0
- package/dist/{chunk-LPV6T362.js → chunk-NROSSWMS.js} +8 -6
- package/dist/{chunk-ZKYRDV7A.js → chunk-OBUB3H72.js} +14 -12
- package/dist/{chunk-ZQLRCA2V.js → chunk-OCQWSFJD.js} +10 -8
- package/dist/{chunk-42EPP7OB.js → chunk-OK6JGLE7.js} +14 -12
- package/dist/{chunk-MD7KUEJ3.js → chunk-OPWGPQ2N.js} +9 -7
- package/dist/{chunk-SH27FYPF.js → chunk-OSYHGGL3.js} +20 -18
- package/dist/chunk-OXXZZ7HQ.js +50 -0
- package/dist/chunk-P22EPEBR.js +57 -0
- package/dist/chunk-P4YUT7W7.js +45 -0
- package/dist/chunk-PCCLVIDP.js +217 -0
- package/dist/chunk-PFULMC2D.js +48 -0
- package/dist/chunk-PGAMTKBI.js +16 -0
- package/dist/{chunk-Y6K3CJBU.js → chunk-PNSSE7JM.js} +152 -29
- package/dist/{chunk-3UTYPHN3.js → chunk-POEMZECG.js} +1 -1
- package/dist/{chunk-GSGIZ2OO.js → chunk-POSDBRKV.js} +27 -24
- package/dist/{chunk-YZDZOEV4.js → chunk-POSZFDSQ.js} +3 -3
- package/dist/{chunk-7AB6OWTV.js → chunk-PQQKZPBU.js} +31 -25
- package/dist/{chunk-K6JB6XTX.js → chunk-PRMUQUWN.js} +20 -15
- package/dist/{chunk-ICHDSWEY.js → chunk-PT4USJNN.js} +10 -8
- package/dist/{chunk-265LWMOA.js → chunk-PWXB5GBB.js} +18 -16
- package/dist/{chunk-DCWN3HFV.js → chunk-PXMV2LLY.js} +6 -5
- package/dist/{chunk-THN26IEF.js → chunk-PXW2RZGQ.js} +4 -1
- package/dist/{chunk-CG6CULP6.js → chunk-Q367UGYN.js} +7 -5
- package/dist/chunk-QA4O2GGC.js +265 -0
- package/dist/{chunk-7FHNFCHK.js → chunk-QAVRDONY.js} +225 -375
- package/dist/{chunk-VAMHOHUU.js → chunk-QBMLBCQH.js} +16 -13
- package/dist/{chunk-WEOMJHPV.js → chunk-QLQIFJP3.js} +18 -15
- package/dist/{chunk-UZACEG2C.js → chunk-QLWDIKO4.js} +84 -27
- package/dist/{chunk-ZZFHLRQW.js → chunk-QVVGJVVX.js} +18 -16
- package/dist/{chunk-WIWTJMMR.js → chunk-QX4MAMUG.js} +23 -21
- package/dist/{chunk-JYTIHTIK.js → chunk-QZWRPQTI.js} +6 -6
- package/dist/{chunk-5WERBKLE.js → chunk-RCG5IAAT.js} +55 -227
- package/dist/chunk-RGZFOKVO.js +106 -0
- package/dist/{chunk-C7CEK3KW.js → chunk-RLZFL76D.js} +7 -5
- package/dist/{chunk-PTQ3ZALZ.js → chunk-RPQITJNX.js} +14 -12
- package/dist/{chunk-JS6WMC3J.js → chunk-RQQYEDAC.js} +10 -8
- package/dist/chunk-RQSLHZ7T.js +36 -0
- package/dist/{chunk-API5TOUB.js → chunk-RRQUQAXP.js} +1 -1
- package/dist/chunk-RYQ4JCFT.js +65 -0
- package/dist/chunk-S35DIFJH.js +38 -0
- package/dist/{chunk-YWAKDNMH.js → chunk-S5GSQPIN.js} +70 -19
- package/dist/chunk-S5XFO4GY.js +42 -0
- package/dist/chunk-S6LW2RRC.js +25 -0
- package/dist/{chunk-TSM6T6GQ.js → chunk-S6W3D5GS.js} +25 -23
- package/dist/{chunk-5PV7S2ZP.js → chunk-S7GUZ45I.js} +4 -3
- package/dist/{chunk-MMZUN7ZO.js → chunk-SCT4CEF7.js} +22 -20
- package/dist/{chunk-AOCWFA7T.js → chunk-SK5RVP7X.js} +8 -8
- package/dist/chunk-SRTUETF5.js +50 -0
- package/dist/{chunk-E57AOFYN.js → chunk-SVGGMBJI.js} +15 -13
- package/dist/{chunk-OV57AHCG.js → chunk-SWNKO4C4.js} +35 -26
- package/dist/chunk-SYP56T2D.js +65 -0
- package/dist/{chunk-5CMPVC3N.js → chunk-T33TPFGI.js} +25 -23
- package/dist/{chunk-Q26LDIUV.js → chunk-T3FNG2H2.js} +18 -15
- package/dist/{chunk-UFE36WJH.js → chunk-T6MAWL5P.js} +6 -4
- package/dist/{chunk-LN77DXBM.js → chunk-T6MX7WXM.js} +14 -11
- package/dist/{chunk-WCEF7H6L.js → chunk-T7IIEDA3.js} +10 -7
- package/dist/{chunk-2HTEMYTB.js → chunk-TABH4RBZ.js} +163 -84
- package/dist/{chunk-YO2PKTXT.js → chunk-TDSCKP3V.js} +5 -3
- package/dist/{chunk-BVWWPBKD.js → chunk-TMFMXQEN.js} +23 -21
- package/dist/{chunk-4B6BT75O.js → chunk-TNCF26JK.js} +83 -26
- package/dist/{chunk-75ASLHBT.js → chunk-TUM52SOE.js} +21 -15
- package/dist/{chunk-ZLS6PU2O.js → chunk-TV56QLLV.js} +4 -3
- package/dist/{chunk-JKIGL3XQ.js → chunk-TVQSXWWV.js} +36 -33
- package/dist/{chunk-OKUB6RJA.js → chunk-TXNSQ24G.js} +14 -11
- package/dist/{chunk-4CYTJ5TZ.js → chunk-UALE35WK.js} +4 -3
- package/dist/{chunk-CNU5Q2D5.js → chunk-UJF7PIMP.js} +35 -27
- package/dist/chunk-UMCDODBX.js +53 -0
- package/dist/{chunk-M6D2U3YM.js → chunk-UTPIFH4I.js} +4 -3
- package/dist/{chunk-COYN3UAN.js → chunk-V7PEHQZU.js} +95 -26
- package/dist/{chunk-U3NBK4EU.js → chunk-VJFXQISZ.js} +8 -8
- package/dist/chunk-VJZI6KFP.js +47 -0
- package/dist/{chunk-ECLXZWAG.js → chunk-VK7WYA64.js} +14 -12
- package/dist/{chunk-DDJPM5YX.js → chunk-VKTXFFOZ.js} +5 -3
- package/dist/{chunk-LIRVU3HW.js → chunk-VNIN7Q6Q.js} +32 -20
- package/dist/{chunk-7QPCGTPS.js → chunk-VRO7KSGL.js} +24 -21
- package/dist/{chunk-AZDITBCT.js → chunk-W3AZE7LN.js} +3 -3
- package/dist/chunk-W4TNCEI4.js +44 -0
- package/dist/{chunk-S2RY3BOD.js → chunk-W5VYJWOG.js} +31 -21
- package/dist/{chunk-X2CUXTWU.js → chunk-WF3RCZNO.js} +6 -6
- package/dist/{chunk-4D62IZII.js → chunk-WOMQQWTO.js} +7 -5
- package/dist/{chunk-UF4UHCIG.js → chunk-WXVTYLVH.js} +6 -4
- package/dist/{chunk-EDZ45WIR.js → chunk-WYGTSZHR.js} +18 -14
- package/dist/{chunk-HSZMPH5T.js → chunk-WZYM5M4U.js} +592 -133
- package/dist/chunk-X5ZHDSLU.js +49 -0
- package/dist/chunk-X7XVMYIL.js +5 -0
- package/dist/chunk-X7ZKNSK4.js +41 -0
- package/dist/{chunk-QE527XRY.js → chunk-XAPXKFIS.js} +26 -23
- package/dist/{chunk-HE3HRDNZ.js → chunk-XF6TSZW2.js} +2 -2
- package/dist/{chunk-GX74YWR7.js → chunk-XFDDJQT7.js} +16 -14
- package/dist/{chunk-5QUOPNLN.js → chunk-XGO74QWR.js} +4 -4
- package/dist/chunk-XLZAAAPX.js +43 -0
- package/dist/{chunk-NYOABJNK.js → chunk-XMUWPA56.js} +26 -24
- package/dist/{chunk-M4H2UG4R.js → chunk-XNFM6WUK.js} +19 -16
- package/dist/{chunk-TGVVUKTG.js → chunk-XOMEQVLK.js} +2 -2
- package/dist/{chunk-A2G72UI4.js → chunk-Y2H7X3VI.js} +7 -7
- package/dist/{chunk-37WE3LS2.js → chunk-Y5IE6YKD.js} +5 -3
- package/dist/{chunk-IFFRGC3N.js → chunk-YD3KTW4H.js} +14 -12
- package/dist/{chunk-75ZOZFGH.js → chunk-YDCOZOER.js} +20 -18
- package/dist/{chunk-6DQYZU2W.js → chunk-YERAAEO4.js} +20 -20
- package/dist/{chunk-J5AAZ6OJ.js → chunk-YHMPDIRG.js} +5 -4
- package/dist/{chunk-CNPY4NTZ.js → chunk-Z2D4P3R3.js} +15 -13
- package/dist/{chunk-E2VXBSIR.js → chunk-Z3H27OMV.js} +6 -4
- package/dist/{chunk-AE4P57KK.js → chunk-Z3RAFU5B.js} +17 -15
- package/dist/{chunk-RA33EYS4.js → chunk-ZENHDXRZ.js} +23 -17
- package/dist/{chunk-TJH2EUAZ.js → chunk-ZFHFC74B.js} +20 -18
- package/dist/{chunk-4PYC2UGC.js → chunk-ZGULQAPZ.js} +7 -4
- package/dist/{chunk-4SKZDI62.js → chunk-ZIUFM5HT.js} +3 -1
- package/dist/{chunk-JAABT3DA.js → chunk-ZJGCGKA4.js} +4 -3
- package/dist/{chunk-GIFMBCTW.js → chunk-ZLQEQR3D.js} +10 -8
- package/dist/{chunk-I2A3Z5AK.js → chunk-ZNHQGG7J.js} +7 -7
- package/dist/{chunk-5TDRBOAV.js → chunk-ZNTTW4IT.js} +7 -5
- package/dist/{chunk-ZX7235KR.js → chunk-ZR6J4QFQ.js} +44 -383
- package/dist/{chunk-F6H2RJ3N.js → chunk-ZSNOILL5.js} +1 -1
- package/dist/files.json +585 -509
- package/dist/packages/sdk/npm/index.js +1491 -110
- package/dist/packages/ui/dist/assets/{elk-api-CowTnhEJ.js → elk-api-DxfAMOJq.js} +2 -2
- package/dist/packages/ui/dist/assets/index-Buit9TfP.js +62 -0
- package/dist/packages/ui/dist/assets/index-Jyc9dFeZ.css +1 -0
- package/dist/packages/ui/dist/index.html +3 -2
- package/package.json +3 -3
- package/dist/chunk-26WBY34Y.js +0 -37
- package/dist/chunk-3TD6S4TC.js +0 -49
- package/dist/chunk-5G7ILBUG.js +0 -66
- package/dist/chunk-6FNAKCET.js +0 -38
- package/dist/chunk-AM6FP6JW.js +0 -43
- package/dist/chunk-CFH3QH26.js +0 -29
- package/dist/chunk-CLD4RVTA.js +0 -45
- package/dist/chunk-D5KV5PSK.js +0 -45
- package/dist/chunk-D5MASS4I.js +0 -48
- package/dist/chunk-DN4A2Q2O.js +0 -57
- package/dist/chunk-FGAGWYZB.js +0 -47
- package/dist/chunk-GUYL7RMK.js +0 -60
- package/dist/chunk-J2O4LFVI.js +0 -80
- package/dist/chunk-JITJP64K.js +0 -34
- package/dist/chunk-JRXHON4E.js +0 -41
- package/dist/chunk-JU4QNJSR.js +0 -62
- package/dist/chunk-N3RUGTGV.js +0 -39
- package/dist/chunk-ODMBPDDV.js +0 -298
- package/dist/chunk-OMPENNWY.js +0 -39
- package/dist/chunk-PKJAV25S.js +0 -43
- package/dist/chunk-PRTBPXYA.js +0 -50
- package/dist/chunk-PRZ7KMWL.js +0 -42
- package/dist/chunk-QSIDVFB7.js +0 -45
- package/dist/chunk-SB5GRUFM.js +0 -54
- package/dist/chunk-T74WQQGS.js +0 -40
- package/dist/chunk-X7EMBM5X.js +0 -34
- package/dist/chunk-Z6VLC5X4.js +0 -36
- package/dist/chunk-ZPDDEVQX.js +0 -47
- package/dist/packages/ui/dist/assets/index-Dw20IRhQ.css +0 -1
- package/dist/packages/ui/dist/assets/index-z2wv0d5d.js +0 -47
|
@@ -6,24 +6,26 @@ var __atticusPath = (p) => __atticusFileURLToPath(__atticusUrl(p));
|
|
|
6
6
|
import {
|
|
7
7
|
STORE_MARKER,
|
|
8
8
|
addStoreReference,
|
|
9
|
+
archiveRefuses,
|
|
10
|
+
blockingIssues,
|
|
9
11
|
readStoreMarker,
|
|
10
12
|
readStoreVia
|
|
11
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-NC755EKE.js";
|
|
12
14
|
import {
|
|
13
15
|
AdapterError,
|
|
14
16
|
mergeBlockers,
|
|
15
17
|
requireApproval
|
|
16
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-FL344WQD.js";
|
|
17
19
|
import {
|
|
18
20
|
outsideProfileSystems,
|
|
19
21
|
readCatalog
|
|
20
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-IKAW2KJU.js";
|
|
21
23
|
import {
|
|
22
24
|
baseClonePath,
|
|
23
25
|
createGit,
|
|
24
26
|
readChangeRepos,
|
|
25
27
|
writeChangeRepos
|
|
26
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-3EWKO457.js";
|
|
27
29
|
import {
|
|
28
30
|
ChangeArtifact,
|
|
29
31
|
ChangeLifecycle,
|
|
@@ -40,23 +42,28 @@ import {
|
|
|
40
42
|
external_exports,
|
|
41
43
|
fastGateOf,
|
|
42
44
|
fastPathOf,
|
|
45
|
+
handleKey,
|
|
43
46
|
handoffBranch,
|
|
44
47
|
isAssistantResolution,
|
|
45
48
|
listQuestions,
|
|
46
49
|
loadOpenSpecSettings,
|
|
47
50
|
loadOrgPack,
|
|
51
|
+
nextOwnersOf,
|
|
48
52
|
openspecDirOf,
|
|
49
53
|
orgPackDirOf,
|
|
50
54
|
questionsRelOf,
|
|
51
55
|
readFlow,
|
|
52
56
|
readQuestion,
|
|
53
|
-
require_dist,
|
|
54
57
|
specFlowFiles,
|
|
58
|
+
taskBranch,
|
|
55
59
|
toCanonicalYaml
|
|
56
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-FPBUTZI5.js";
|
|
57
61
|
import {
|
|
58
62
|
writeFileAtomic
|
|
59
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-B4AEL3RF.js";
|
|
64
|
+
import {
|
|
65
|
+
require_dist
|
|
66
|
+
} from "./chunk-BQGDB6ZL.js";
|
|
60
67
|
import {
|
|
61
68
|
__toESM
|
|
62
69
|
} from "./chunk-TV45EUGM.js";
|
|
@@ -628,22 +635,33 @@ function changeStore(root) {
|
|
|
628
635
|
await writeFileAtomic(path, serializeChange(value));
|
|
629
636
|
return path;
|
|
630
637
|
},
|
|
638
|
+
listWithProblems,
|
|
631
639
|
async list() {
|
|
632
|
-
|
|
640
|
+
return (await listWithProblems()).changes;
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
async function listWithProblems() {
|
|
644
|
+
let names;
|
|
645
|
+
try {
|
|
646
|
+
names = (await readdir2(changesDirOf(root), { withFileTypes: true })).filter((d) => d.isDirectory() && d.name !== "archive" && RecordId.safeParse(d.name).success).map((d) => d.name).sort();
|
|
647
|
+
} catch {
|
|
648
|
+
return { changes: [], problems: [] };
|
|
649
|
+
}
|
|
650
|
+
const changes = [];
|
|
651
|
+
const problems = [];
|
|
652
|
+
for (const n of names) {
|
|
633
653
|
try {
|
|
634
|
-
names = (await readdir2(changesDirOf(root), { withFileTypes: true })).filter((d) => d.isDirectory() && d.name !== "archive" && RecordId.safeParse(d.name).success).map((d) => d.name).sort();
|
|
635
|
-
} catch {
|
|
636
|
-
return [];
|
|
637
|
-
}
|
|
638
|
-
const out = [];
|
|
639
|
-
for (const n of names) {
|
|
640
654
|
const c = await tryRead(n);
|
|
641
655
|
if (c)
|
|
642
|
-
|
|
656
|
+
changes.push(c);
|
|
657
|
+
} catch (e) {
|
|
658
|
+
if (!(e instanceof ChangeFileError))
|
|
659
|
+
throw e;
|
|
660
|
+
problems.push({ file: e.path, message: e.message });
|
|
643
661
|
}
|
|
644
|
-
return out;
|
|
645
662
|
}
|
|
646
|
-
|
|
663
|
+
return { changes, problems };
|
|
664
|
+
}
|
|
647
665
|
}
|
|
648
666
|
|
|
649
667
|
// packages/changes/dist/codeowners.js
|
|
@@ -1650,8 +1668,19 @@ async function checkFindings(root, change, gates) {
|
|
|
1650
1668
|
continue;
|
|
1651
1669
|
const round2 = Math.max(...rounds);
|
|
1652
1670
|
const dir = join7(base, String(round2));
|
|
1671
|
+
const files = (await readdir4(dir)).filter((f) => /\.ya?ml$/.test(f)).sort();
|
|
1672
|
+
const unfinished = {
|
|
1673
|
+
code: "round-unfinished",
|
|
1674
|
+
message: `Critic round ${round2} on the ${gate} gate didn't finish: run atticus critic ${change.id} --gate ${gate} again.`
|
|
1675
|
+
};
|
|
1676
|
+
let hasMeta = false;
|
|
1653
1677
|
try {
|
|
1654
1678
|
const meta = (0, import_yaml5.parse)(await readFile6(join7(dir, "meta", "round.yaml"), "utf8"));
|
|
1679
|
+
hasMeta = true;
|
|
1680
|
+
if (meta?.state === "in-progress") {
|
|
1681
|
+
reasons.push(unfinished);
|
|
1682
|
+
continue;
|
|
1683
|
+
}
|
|
1655
1684
|
for (const l of meta?.lenses ?? [])
|
|
1656
1685
|
if (l.state === "waiting")
|
|
1657
1686
|
reasons.push({
|
|
@@ -1665,7 +1694,10 @@ async function checkFindings(root, change, gates) {
|
|
|
1665
1694
|
});
|
|
1666
1695
|
} catch {
|
|
1667
1696
|
}
|
|
1668
|
-
|
|
1697
|
+
if (!hasMeta && files.length === 0) {
|
|
1698
|
+
reasons.push(unfinished);
|
|
1699
|
+
continue;
|
|
1700
|
+
}
|
|
1669
1701
|
for (const f of files) {
|
|
1670
1702
|
const rel = `review/${gate}/${round2}/${f}`;
|
|
1671
1703
|
let data;
|
|
@@ -1813,14 +1845,195 @@ function prApprovers(handoff2, approvers) {
|
|
|
1813
1845
|
}
|
|
1814
1846
|
|
|
1815
1847
|
// packages/changes/dist/assess.js
|
|
1816
|
-
import { readFile as
|
|
1817
|
-
import { join as
|
|
1848
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
1849
|
+
import { join as join11 } from "node:path";
|
|
1818
1850
|
|
|
1819
1851
|
// packages/changes/dist/release-prs.js
|
|
1852
|
+
var import_yaml8 = __toESM(require_dist(), 1);
|
|
1853
|
+
import { readFile as readFile9, writeFile } from "node:fs/promises";
|
|
1854
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
1855
|
+
import { join as join10 } from "node:path";
|
|
1856
|
+
|
|
1857
|
+
// packages/changes/dist/task-branches.js
|
|
1820
1858
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
1821
|
-
import { readFile as readFile8, writeFile } from "node:fs/promises";
|
|
1822
1859
|
import { existsSync } from "node:fs";
|
|
1860
|
+
import { readdir as readdir5, readFile as readFile8 } from "node:fs/promises";
|
|
1823
1861
|
import { join as join9 } from "node:path";
|
|
1862
|
+
var TASK_DECISION_FILE = "decision.yaml";
|
|
1863
|
+
var TaskDecision = external_exports.strictObject({
|
|
1864
|
+
schemaVersion: external_exports.literal(1),
|
|
1865
|
+
task: external_exports.string().min(1),
|
|
1866
|
+
branch: external_exports.string().min(1),
|
|
1867
|
+
/** The task branch's commit the person decided over. */
|
|
1868
|
+
commit: external_exports.string().regex(/^[0-9a-f]{7,64}$/),
|
|
1869
|
+
by: external_exports.string().min(1),
|
|
1870
|
+
at: external_exports.string().min(1),
|
|
1871
|
+
reason: external_exports.string().min(1)
|
|
1872
|
+
});
|
|
1873
|
+
async function taskRefs(root, id) {
|
|
1874
|
+
const dir = join9(changeFolder(root, id), "tasks");
|
|
1875
|
+
const out = [];
|
|
1876
|
+
for (const d of await readdir5(dir, { withFileTypes: true }).catch(() => [])) {
|
|
1877
|
+
if (!d.isDirectory())
|
|
1878
|
+
continue;
|
|
1879
|
+
const text = await readFile8(join9(dir, d.name, "task-run.yaml"), "utf8").catch(() => void 0);
|
|
1880
|
+
let y;
|
|
1881
|
+
try {
|
|
1882
|
+
y = text ? (0, import_yaml7.parse)(text) : void 0;
|
|
1883
|
+
} catch {
|
|
1884
|
+
y = void 0;
|
|
1885
|
+
}
|
|
1886
|
+
const task = String(y?.task ?? d.name);
|
|
1887
|
+
let branch;
|
|
1888
|
+
try {
|
|
1889
|
+
branch = typeof y?.branch === "string" ? y.branch : taskBranch(id, task);
|
|
1890
|
+
} catch {
|
|
1891
|
+
continue;
|
|
1892
|
+
}
|
|
1893
|
+
const pr = y?.pr;
|
|
1894
|
+
out.push({
|
|
1895
|
+
task,
|
|
1896
|
+
...typeof y?.repo === "string" ? { repo: y.repo } : {},
|
|
1897
|
+
branch,
|
|
1898
|
+
...typeof y?.state === "string" ? { state: y.state } : {},
|
|
1899
|
+
...pr && typeof pr.number === "number" && typeof pr.url === "string" ? { pr: { number: pr.number, url: pr.url } } : {},
|
|
1900
|
+
...y?.ticked ? { ticked: true } : {},
|
|
1901
|
+
...typeof y?.commit === "string" && /^[0-9a-f]{7,64}$/.test(y.commit) ? { commit: y.commit } : {}
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
return out;
|
|
1905
|
+
}
|
|
1906
|
+
function repoDir(root, r) {
|
|
1907
|
+
const dirs = [join9(root, r.worktree)];
|
|
1908
|
+
try {
|
|
1909
|
+
dirs.push(baseClonePath(root, r.id));
|
|
1910
|
+
} catch {
|
|
1911
|
+
}
|
|
1912
|
+
return dirs.find((d) => existsSync(d));
|
|
1913
|
+
}
|
|
1914
|
+
async function readTaskDecision(root, id, task) {
|
|
1915
|
+
const text = await readFile8(join9(changeFolder(root, id), "tasks", task, TASK_DECISION_FILE), "utf8").catch(() => void 0);
|
|
1916
|
+
if (text === void 0)
|
|
1917
|
+
return void 0;
|
|
1918
|
+
try {
|
|
1919
|
+
const r = TaskDecision.safeParse((0, import_yaml7.parse)(text));
|
|
1920
|
+
return r.success ? r.data : void 0;
|
|
1921
|
+
} catch {
|
|
1922
|
+
return void 0;
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
async function unmergedTaskBranches(root, id, o = {}) {
|
|
1926
|
+
const cr = await readChangeRepos(root, id).catch(() => void 0);
|
|
1927
|
+
if (!cr?.repos.length)
|
|
1928
|
+
return [];
|
|
1929
|
+
const git = o.git ?? createGit({ timeoutMs: 3e4 });
|
|
1930
|
+
const remote = o.remote ?? "origin";
|
|
1931
|
+
const from = changeBranch(id);
|
|
1932
|
+
const records = await taskRefs(root, id);
|
|
1933
|
+
const out = [];
|
|
1934
|
+
const sha = (dir, ref) => git(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], dir).then((x) => x.stdout.trim() || void 0, () => void 0);
|
|
1935
|
+
for (const r of cr.repos) {
|
|
1936
|
+
const dir = repoDir(root, r);
|
|
1937
|
+
if (!dir)
|
|
1938
|
+
continue;
|
|
1939
|
+
const listed = await git(["for-each-ref", "--format=%(refname)", `refs/heads/task/${id}/`], dir).then((x) => x.stdout.split(/\r?\n/).map((l) => l.trim().replace(/^refs\/heads\//, "")).filter(Boolean), () => []);
|
|
1940
|
+
const branches = /* @__PURE__ */ new Map();
|
|
1941
|
+
for (const b of listed) {
|
|
1942
|
+
const mine = records.find((x) => x.branch === b && (!x.repo || x.repo === r.id));
|
|
1943
|
+
const other = records.find((x) => x.branch === b);
|
|
1944
|
+
branches.set(b, mine ?? { task: other?.task ?? b.split("/").at(-1), branch: b });
|
|
1945
|
+
}
|
|
1946
|
+
for (const x of records)
|
|
1947
|
+
if (x.repo === r.id && !branches.has(x.branch))
|
|
1948
|
+
branches.set(x.branch, x);
|
|
1949
|
+
const refs = [...branches.values()].filter((x) => (!x.repo || x.repo === r.id) && (!o.task || x.task === o.task));
|
|
1950
|
+
if (!refs.length)
|
|
1951
|
+
continue;
|
|
1952
|
+
const not = [];
|
|
1953
|
+
if (await sha(dir, `refs/heads/${from}`))
|
|
1954
|
+
not.push(`refs/heads/${from}`);
|
|
1955
|
+
if (!o.offline) {
|
|
1956
|
+
const onHost = await git(["ls-remote", "--heads", remote, `refs/heads/${from}`], dir).then((x) => x.stdout.trim().split(/\s+/)[0] || void 0, () => void 0);
|
|
1957
|
+
if (onHost && !await sha(dir, onHost))
|
|
1958
|
+
await git(["fetch", "-q", remote, `+refs/heads/${from}:refs/remotes/${remote}/${from}`], dir).catch(() => void 0);
|
|
1959
|
+
if (onHost && await sha(dir, onHost))
|
|
1960
|
+
not.push(onHost);
|
|
1961
|
+
} else if (await sha(dir, `refs/remotes/${remote}/${from}`))
|
|
1962
|
+
not.push(`refs/remotes/${remote}/${from}`);
|
|
1963
|
+
for (const x of refs) {
|
|
1964
|
+
const tip = await sha(dir, `refs/heads/${x.branch}`);
|
|
1965
|
+
if (!tip)
|
|
1966
|
+
continue;
|
|
1967
|
+
const merged = x.ticked && x.commit ? await sha(dir, x.commit) : void 0;
|
|
1968
|
+
if (x.ticked && !merged)
|
|
1969
|
+
continue;
|
|
1970
|
+
const decided = await readTaskDecision(root, id, x.task);
|
|
1971
|
+
if (decided && decided.branch === x.branch && sameSha(decided.commit, tip))
|
|
1972
|
+
continue;
|
|
1973
|
+
const commits = await git([
|
|
1974
|
+
"rev-list",
|
|
1975
|
+
"--count",
|
|
1976
|
+
`refs/heads/${x.branch}`,
|
|
1977
|
+
...not.length || merged ? ["--not", ...not, ...merged ? [merged] : []] : []
|
|
1978
|
+
], dir).then((y) => Number(y.stdout.trim()) || 0, () => 0);
|
|
1979
|
+
if (commits > 0)
|
|
1980
|
+
out.push({
|
|
1981
|
+
task: x.task,
|
|
1982
|
+
repo: r.id,
|
|
1983
|
+
branch: x.branch,
|
|
1984
|
+
commits,
|
|
1985
|
+
...x.state ? { state: x.state } : {},
|
|
1986
|
+
...x.pr ? { pr: x.pr } : {}
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
return out.sort((a, b) => a.task < b.task ? -1 : a.task > b.task ? 1 : 0);
|
|
1991
|
+
}
|
|
1992
|
+
var sameSha = (a, b) => a.startsWith(b) || b.startsWith(a);
|
|
1993
|
+
function unmergedTaskWords(id, u) {
|
|
1994
|
+
const from = changeBranch(id);
|
|
1995
|
+
const n = `${u.commits} commit${u.commits === 1 ? "" : "s"}`;
|
|
1996
|
+
const what = u.state === "pr-open" && u.pr ? `its PR #${u.pr.number} isn't merged yet: a person merges it on the Git host (${u.pr.url}), then Sync records it` : u.state === "unverified" || u.state === "needs-person" || u.state === "failed" ? `it was never built and raised: Build and raise PR on the Task board (or Run again), then merge its PR into ${from}` : `raise its PR (Raise the task's PR on the Task board) and merge it into ${from}`;
|
|
1997
|
+
return `Task ${u.task}'s branch ${u.branch} in ${u.repo} has ${n} not in ${from}, so its code isn't in the change: ${what}. If its work isn't needed, mark the task done with a reason.`;
|
|
1998
|
+
}
|
|
1999
|
+
async function taskBranchReasons(root, id, o = {}) {
|
|
2000
|
+
return (await unmergedTaskBranches(root, id, o)).map((u) => ({
|
|
2001
|
+
code: "task-not-merged",
|
|
2002
|
+
message: unmergedTaskWords(id, u)
|
|
2003
|
+
}));
|
|
2004
|
+
}
|
|
2005
|
+
async function recordTaskDecision(root, id, task, o) {
|
|
2006
|
+
const reason = o.reason.trim();
|
|
2007
|
+
if (!reason)
|
|
2008
|
+
throw new ChangeError("invalid", `Say why task ${task}'s work isn't needed in ${id}: a reason is recorded with the decision.`);
|
|
2009
|
+
const branch = taskBranch(id, task);
|
|
2010
|
+
const git = o.git ?? createGit({ timeoutMs: 3e4 });
|
|
2011
|
+
const cr = await readChangeRepos(root, id).catch(() => void 0);
|
|
2012
|
+
let commit;
|
|
2013
|
+
for (const r of cr?.repos ?? []) {
|
|
2014
|
+
const dir = repoDir(root, r);
|
|
2015
|
+
if (!dir)
|
|
2016
|
+
continue;
|
|
2017
|
+
commit = await git(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}^{commit}`], dir).then((x) => x.stdout.trim() || void 0, () => void 0);
|
|
2018
|
+
if (commit)
|
|
2019
|
+
break;
|
|
2020
|
+
}
|
|
2021
|
+
if (!commit)
|
|
2022
|
+
throw new ChangeError("refused", `Task ${task} has no branch ${branch} here, so there is nothing to decide: mark it done.`);
|
|
2023
|
+
const d = TaskDecision.parse({
|
|
2024
|
+
schemaVersion: 1,
|
|
2025
|
+
task,
|
|
2026
|
+
branch,
|
|
2027
|
+
commit,
|
|
2028
|
+
by: o.by.trim(),
|
|
2029
|
+
at: o.at,
|
|
2030
|
+
reason
|
|
2031
|
+
});
|
|
2032
|
+
await writeFileAtomic(join9(changeFolder(root, id), "tasks", task, TASK_DECISION_FILE), toCanonicalYaml(d, ["schemaVersion", "task", "branch", "commit"]));
|
|
2033
|
+
return d;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
// packages/changes/dist/release-prs.js
|
|
1824
2037
|
var RELEASE_PR_STATES = [
|
|
1825
2038
|
"qa",
|
|
1826
2039
|
"release-ready",
|
|
@@ -1837,18 +2050,87 @@ var NothingFile = external_exports.strictObject({
|
|
|
1837
2050
|
commit: external_exports.string().regex(/^[0-9a-f]{7,64}$/).optional(),
|
|
1838
2051
|
at: external_exports.string().min(1),
|
|
1839
2052
|
by: external_exports.string().min(1)
|
|
1840
|
-
}))
|
|
2053
|
+
})),
|
|
2054
|
+
/**
|
|
2055
|
+
* Review round 48: the change branch's commit when Sync first read each release PR merged, so
|
|
2056
|
+
* a merged PR stands only while the branch is there (work landed since needs a PR of its own).
|
|
2057
|
+
*/
|
|
2058
|
+
merged: external_exports.array(external_exports.strictObject({
|
|
2059
|
+
repo: external_exports.string().min(1),
|
|
2060
|
+
number: external_exports.number().int().positive(),
|
|
2061
|
+
commit: external_exports.string().regex(/^[0-9a-f]{7,64}$/),
|
|
2062
|
+
at: external_exports.string().min(1)
|
|
2063
|
+
})).optional()
|
|
1841
2064
|
});
|
|
1842
|
-
async function
|
|
1843
|
-
const
|
|
2065
|
+
async function readReleaseFile(root, id) {
|
|
2066
|
+
const empty = { schemaVersion: 1, nothingToRelease: [] };
|
|
2067
|
+
const text = await readFile9(join10(changeFolder(root, id), RELEASE_PRS_FILE), "utf8").catch(() => void 0);
|
|
1844
2068
|
if (text === void 0)
|
|
1845
|
-
return
|
|
2069
|
+
return empty;
|
|
1846
2070
|
try {
|
|
1847
|
-
const r = NothingFile.safeParse((0,
|
|
1848
|
-
return r.success ? r.data
|
|
2071
|
+
const r = NothingFile.safeParse((0, import_yaml8.parse)(text));
|
|
2072
|
+
return r.success ? r.data : empty;
|
|
1849
2073
|
} catch {
|
|
1850
|
-
return
|
|
2074
|
+
return empty;
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
async function readNothing(root, id) {
|
|
2078
|
+
return (await readReleaseFile(root, id)).nothingToRelease;
|
|
2079
|
+
}
|
|
2080
|
+
async function writeReleaseFile(root, id, nothing, merged) {
|
|
2081
|
+
const byRepo = (xs) => [...xs].sort((a, b) => a.repo < b.repo ? -1 : a.repo > b.repo ? 1 : 0);
|
|
2082
|
+
await writeFile(join10(changeFolder(root, id), RELEASE_PRS_FILE), toCanonicalYaml(NothingFile.parse({
|
|
2083
|
+
schemaVersion: 1,
|
|
2084
|
+
nothingToRelease: byRepo(nothing),
|
|
2085
|
+
...merged.length ? { merged: byRepo(merged) } : {}
|
|
2086
|
+
})), "utf8");
|
|
2087
|
+
}
|
|
2088
|
+
function repoDir2(root, r) {
|
|
2089
|
+
const dirs = [join10(root, r.worktree)];
|
|
2090
|
+
try {
|
|
2091
|
+
dirs.push(baseClonePath(root, r.id));
|
|
2092
|
+
} catch {
|
|
2093
|
+
}
|
|
2094
|
+
return dirs.find((d) => existsSync2(d));
|
|
2095
|
+
}
|
|
2096
|
+
async function staleReleasePrs(root, id, o = {}) {
|
|
2097
|
+
const out = /* @__PURE__ */ new Set();
|
|
2098
|
+
const cr = await readChangeRepos(root, id).catch(() => void 0);
|
|
2099
|
+
const merged = (await readReleaseFile(root, id)).merged ?? [];
|
|
2100
|
+
if (!cr || !merged.length)
|
|
2101
|
+
return out;
|
|
2102
|
+
const git = o.git ?? createGit({ timeoutMs: 3e4 });
|
|
2103
|
+
const remote = o.remote ?? "origin";
|
|
2104
|
+
for (const r of cr.repos) {
|
|
2105
|
+
if (r.pr?.state !== "merged")
|
|
2106
|
+
continue;
|
|
2107
|
+
const entry = merged.find((x) => x.repo === r.id && x.number === r.pr.number);
|
|
2108
|
+
if (!entry)
|
|
2109
|
+
continue;
|
|
2110
|
+
const dir = repoDir2(root, r);
|
|
2111
|
+
if (!dir)
|
|
2112
|
+
continue;
|
|
2113
|
+
if (await movedPast(git, dir, remote, r.branch, entry.commit, o.offline))
|
|
2114
|
+
out.add(r.id);
|
|
1851
2115
|
}
|
|
2116
|
+
return out;
|
|
2117
|
+
}
|
|
2118
|
+
var lastFetched = (git, dir, remote, branch) => git(["rev-parse", "--verify", "--quiet", `refs/remotes/${remote}/${branch}^{commit}`], dir).then((x) => x.stdout.trim() || void 0, () => void 0);
|
|
2119
|
+
async function movedPast(git, dir, remote, branch, commit, offline) {
|
|
2120
|
+
const ref = `refs/heads/${branch}`;
|
|
2121
|
+
const known = (sha) => git(["cat-file", "-e", `${sha}^{commit}`], dir).then(() => true, () => false);
|
|
2122
|
+
const here = await git(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], dir).then((x) => x.stdout.trim() || void 0, () => void 0);
|
|
2123
|
+
const onHost = offline ? await lastFetched(git, dir, remote, branch) : await git(["ls-remote", "--heads", remote, ref], dir).then((x) => x.stdout.trim().split(/\s+/)[0] || void 0, () => void 0);
|
|
2124
|
+
if (!offline && onHost && !sameSha2(onHost, commit) && !await known(onHost))
|
|
2125
|
+
await git(["fetch", "-q", remote, `+${ref}:refs/remotes/${remote}/${branch}`], dir).catch(() => void 0);
|
|
2126
|
+
const ahead = async (sha) => {
|
|
2127
|
+
if (!sha || sameSha2(sha, commit))
|
|
2128
|
+
return false;
|
|
2129
|
+
if (!await known(sha) || !await known(commit))
|
|
2130
|
+
return true;
|
|
2131
|
+
return git(["merge-base", "--is-ancestor", sha, commit], dir).then(() => false, () => true);
|
|
2132
|
+
};
|
|
2133
|
+
return await ahead(here) || await ahead(onHost);
|
|
1852
2134
|
}
|
|
1853
2135
|
async function nothingToRelease(root, id, o = {}) {
|
|
1854
2136
|
const entries = await readNothing(root, id);
|
|
@@ -1866,22 +2148,19 @@ async function nothingToRelease(root, id, o = {}) {
|
|
|
1866
2148
|
}
|
|
1867
2149
|
return out;
|
|
1868
2150
|
async function moved(r, commit) {
|
|
1869
|
-
const
|
|
1870
|
-
try {
|
|
1871
|
-
dirs.push(baseClonePath(root, r.id));
|
|
1872
|
-
} catch {
|
|
1873
|
-
}
|
|
1874
|
-
const dir = dirs.find((d) => existsSync(d));
|
|
2151
|
+
const dir = repoDir2(root, r);
|
|
1875
2152
|
if (!dir)
|
|
1876
2153
|
return false;
|
|
1877
2154
|
const ref = `refs/heads/${r.branch}`;
|
|
1878
2155
|
const here = await git(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], dir).then((x) => x.stdout.trim() || void 0, () => void 0);
|
|
1879
|
-
const
|
|
1880
|
-
const
|
|
2156
|
+
const fetched = o.offline ? await lastFetched(git, dir, remote, r.branch) : void 0;
|
|
2157
|
+
const behind = !!fetched && !!commit && await git(["merge-base", "--is-ancestor", fetched, commit], dir).then(() => true, () => false);
|
|
2158
|
+
const onHost = o.offline ? behind ? void 0 : fetched : await git(["ls-remote", "--heads", remote, ref], dir).then((x) => x.stdout.trim().split(/\s+/)[0] || void 0, () => void 0);
|
|
2159
|
+
const at = (sha) => sha !== void 0 && (commit === void 0 || !sameSha2(sha, commit));
|
|
1881
2160
|
return at(here) || at(onHost);
|
|
1882
2161
|
}
|
|
1883
2162
|
}
|
|
1884
|
-
var
|
|
2163
|
+
var sameSha2 = (a, b) => a.startsWith(b) || b.startsWith(a);
|
|
1885
2164
|
var firstLine = (e) => (e instanceof Error ? e.message : String(e)).split("\n")[0].replace(/\.$/, "");
|
|
1886
2165
|
var prOf = (pr, now) => ({
|
|
1887
2166
|
url: pr.url,
|
|
@@ -1912,12 +2191,16 @@ async function raiseReleasePrs(root, id, o) {
|
|
|
1912
2191
|
const rows = [];
|
|
1913
2192
|
let changed2 = false;
|
|
1914
2193
|
const repos = cr.repos.map((r) => ({ ...r }));
|
|
1915
|
-
const
|
|
2194
|
+
const file = await readReleaseFile(root, id);
|
|
2195
|
+
const before = file.nothingToRelease;
|
|
1916
2196
|
const nothing = new Map(before.map((x) => [x.repo, x]));
|
|
2197
|
+
const stale = await staleReleasePrs(root, id, { git, remote });
|
|
2198
|
+
const unmerged = await unmergedTaskBranches(root, id, { git, remote });
|
|
1917
2199
|
for (const r of repos) {
|
|
1918
|
-
|
|
2200
|
+
const movedOn = r.pr?.state === "merged" && stale.has(r.id) ? `Release PR #${r.pr.number} merged before ${r.branch} moved on; this one carries what landed since.` : void 0;
|
|
2201
|
+
if (!live(r.pr) || movedOn)
|
|
1919
2202
|
nothing.delete(r.id);
|
|
1920
|
-
if (live(r.pr)) {
|
|
2203
|
+
if (live(r.pr) && !movedOn) {
|
|
1921
2204
|
rows.push({
|
|
1922
2205
|
repo: r.id,
|
|
1923
2206
|
outcome: "kept",
|
|
@@ -1926,6 +2209,15 @@ async function raiseReleasePrs(root, id, o) {
|
|
|
1926
2209
|
});
|
|
1927
2210
|
continue;
|
|
1928
2211
|
}
|
|
2212
|
+
const held = unmerged.filter((u) => u.repo === r.id);
|
|
2213
|
+
if (held.length) {
|
|
2214
|
+
rows.push({
|
|
2215
|
+
repo: r.id,
|
|
2216
|
+
outcome: "refused",
|
|
2217
|
+
message: `${r.id}: no release PR, since ${r.branch} lacks the code of ${held.length === 1 ? `task ${held[0].task}` : `tasks ${held.map((u) => u.task).join(", ")}`}. ${held.map((u) => unmergedTaskWords(id, u)).join(" ")}`
|
|
2218
|
+
});
|
|
2219
|
+
continue;
|
|
2220
|
+
}
|
|
1929
2221
|
if (r.branch !== expected) {
|
|
1930
2222
|
rows.push({
|
|
1931
2223
|
repo: r.id,
|
|
@@ -1964,9 +2256,9 @@ async function raiseReleasePrs(root, id, o) {
|
|
|
1964
2256
|
});
|
|
1965
2257
|
continue;
|
|
1966
2258
|
}
|
|
1967
|
-
const notes = [];
|
|
1968
|
-
const dir =
|
|
1969
|
-
if (
|
|
2259
|
+
const notes = movedOn ? [movedOn] : [];
|
|
2260
|
+
const dir = join10(root, r.worktree);
|
|
2261
|
+
if (existsSync2(dir)) {
|
|
1970
2262
|
const onHost = await git(["ls-remote", "--heads", remote, `refs/heads/${r.branch}`], dir).then((x) => x.stdout.trim() ? "yes" : "no").catch((e) => {
|
|
1971
2263
|
notes.push(`Atticus couldn't reach ${remote} (${firstLine(e)}): push ${r.branch} yourself if the host lacks it.`);
|
|
1972
2264
|
return "unknown";
|
|
@@ -2048,8 +2340,10 @@ async function raiseReleasePrs(root, id, o) {
|
|
|
2048
2340
|
if (changed2)
|
|
2049
2341
|
await writeChangeRepos(root, { ...cr, repos });
|
|
2050
2342
|
const after = [...nothing.values()].sort((a, b) => a.repo < b.repo ? -1 : 1);
|
|
2051
|
-
|
|
2052
|
-
|
|
2343
|
+
const mergedBefore = file.merged ?? [];
|
|
2344
|
+
const mergedAfter = mergedBefore.filter((x) => repos.some((r) => r.id === x.repo && r.pr?.number === x.number && r.pr.state === "merged"));
|
|
2345
|
+
if (JSON.stringify(after) !== JSON.stringify(before) || mergedAfter.length !== mergedBefore.length)
|
|
2346
|
+
await writeReleaseFile(root, id, after, mergedAfter);
|
|
2053
2347
|
return { change: id, rows };
|
|
2054
2348
|
}
|
|
2055
2349
|
async function syncReleasePrs(root, id, o) {
|
|
@@ -2060,6 +2354,9 @@ async function syncReleasePrs(root, id, o) {
|
|
|
2060
2354
|
const now = o.now ?? nowIso();
|
|
2061
2355
|
let changed2 = false;
|
|
2062
2356
|
const repos = cr.repos.map((r) => ({ ...r }));
|
|
2357
|
+
const file = await readReleaseFile(root, id);
|
|
2358
|
+
const merged = [...file.merged ?? []];
|
|
2359
|
+
let mergedChanged = false;
|
|
2063
2360
|
for (const r of repos) {
|
|
2064
2361
|
if (!r.pr)
|
|
2065
2362
|
continue;
|
|
@@ -2100,6 +2397,16 @@ async function syncReleasePrs(root, id, o) {
|
|
|
2100
2397
|
r.build = { ...r.build, status: build, at: now };
|
|
2101
2398
|
changed2 = true;
|
|
2102
2399
|
}
|
|
2400
|
+
if (pr.state === "merged" && !merged.some((x) => x.repo === r.id && x.number === pr.number)) {
|
|
2401
|
+
const commit = await branchTip(root, r, o.git, o.remote ?? "origin");
|
|
2402
|
+
if (commit) {
|
|
2403
|
+
for (let i = merged.length - 1; i >= 0; i--)
|
|
2404
|
+
if (merged[i].repo === r.id)
|
|
2405
|
+
merged.splice(i, 1);
|
|
2406
|
+
merged.push({ repo: r.id, number: pr.number, commit, at: now });
|
|
2407
|
+
mergedChanged = true;
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2103
2410
|
rows.push({
|
|
2104
2411
|
repo: r.id,
|
|
2105
2412
|
outcome: "kept",
|
|
@@ -2109,8 +2416,25 @@ async function syncReleasePrs(root, id, o) {
|
|
|
2109
2416
|
}
|
|
2110
2417
|
if (changed2)
|
|
2111
2418
|
await writeChangeRepos(root, { ...cr, repos });
|
|
2419
|
+
if (mergedChanged)
|
|
2420
|
+
await writeReleaseFile(root, id, file.nothingToRelease, merged);
|
|
2112
2421
|
return { change: id, rows };
|
|
2113
2422
|
}
|
|
2423
|
+
async function branchTip(root, r, g, remote) {
|
|
2424
|
+
const dir = repoDir2(root, r);
|
|
2425
|
+
if (!dir)
|
|
2426
|
+
return void 0;
|
|
2427
|
+
const git = g ?? createGit({ timeoutMs: 3e4 });
|
|
2428
|
+
const ref = `refs/heads/${r.branch}`;
|
|
2429
|
+
const onHost = await git(["ls-remote", "--heads", remote, ref], dir).then((x) => x.stdout.trim().split(/\s+/)[0] || void 0, () => void 0);
|
|
2430
|
+
if (onHost) {
|
|
2431
|
+
await git(["fetch", "-q", remote, `+${ref}:refs/remotes/${remote}/${r.branch}`], dir).catch(() => void 0);
|
|
2432
|
+
if (/^[0-9a-f]{7,64}$/.test(onHost))
|
|
2433
|
+
return onHost;
|
|
2434
|
+
}
|
|
2435
|
+
const here = await git(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], dir).then((x) => x.stdout.trim(), () => "");
|
|
2436
|
+
return /^[0-9a-f]{7,64}$/.test(here) ? here : void 0;
|
|
2437
|
+
}
|
|
2114
2438
|
function buildOf(pr) {
|
|
2115
2439
|
if (!pr.checks.length)
|
|
2116
2440
|
return void 0;
|
|
@@ -2121,11 +2445,11 @@ function buildOf(pr) {
|
|
|
2121
2445
|
return "passed";
|
|
2122
2446
|
}
|
|
2123
2447
|
async function requireMergedPrs(root) {
|
|
2124
|
-
const text = await
|
|
2448
|
+
const text = await readFile9(join10(orgPackDirOf(root), "process", "ci.yaml"), "utf8").catch(() => void 0);
|
|
2125
2449
|
if (text === void 0)
|
|
2126
2450
|
return true;
|
|
2127
2451
|
try {
|
|
2128
|
-
const v = (0,
|
|
2452
|
+
const v = (0, import_yaml8.parse)(text)?.archive?.requireMergedPrs;
|
|
2129
2453
|
return v !== false;
|
|
2130
2454
|
} catch {
|
|
2131
2455
|
return true;
|
|
@@ -2137,10 +2461,18 @@ async function releasePrReasons(root, id, o = {}) {
|
|
|
2137
2461
|
return [];
|
|
2138
2462
|
const merged = await requireMergedPrs(root);
|
|
2139
2463
|
const nothing = await nothingToRelease(root, id, o);
|
|
2140
|
-
const
|
|
2464
|
+
const stale = await staleReleasePrs(root, id, o);
|
|
2465
|
+
const out = await taskBranchReasons(root, id, o);
|
|
2141
2466
|
for (const r of cr.repos) {
|
|
2142
2467
|
if (!r.pr && nothing.has(r.id))
|
|
2143
2468
|
continue;
|
|
2469
|
+
if (r.pr?.state === "merged" && stale.has(r.id)) {
|
|
2470
|
+
out.push({
|
|
2471
|
+
code: "release-pr-stale",
|
|
2472
|
+
message: `${r.id}: ${r.branch} has commits since release PR #${r.pr.number} merged, so they haven't reached its default branch: raise the release PRs again (Release \u203A Raise the release PRs, or atticus change release-prs ${id} --approve).`
|
|
2473
|
+
});
|
|
2474
|
+
continue;
|
|
2475
|
+
}
|
|
2144
2476
|
if (!r.pr || r.pr.state === "closed")
|
|
2145
2477
|
out.push({
|
|
2146
2478
|
code: "release-pr-missing",
|
|
@@ -2202,7 +2534,11 @@ async function assess(ctx, change) {
|
|
|
2202
2534
|
...stageReasons.length ? [] : await checkMandatoryRounds(ctx.root, change, phaseGates(ctx, phase).filter((g) => mandatoryGates(ctx).includes(g))),
|
|
2203
2535
|
// ADR 0184: go/no-go is decided over the release PRs, each repo's change branch into its
|
|
2204
2536
|
// default branch, merged (unless the org pack's ci.yaml says archive.requireMergedPrs: false).
|
|
2205
|
-
|
|
2537
|
+
// Both read refs here only (the host's branches as last fetched): an assessment runs on every
|
|
2538
|
+
// page load (Home's cockpit), which never reaches the Git host; Sync and the release steps do.
|
|
2539
|
+
...phase === "release" ? await releasePrReasons(ctx.root, change.id, { offline: true }) : [],
|
|
2540
|
+
// App-only audit: Build ready waits for every task's work to be in the change branch.
|
|
2541
|
+
...phase === "build" ? await taskBranchReasons(ctx.root, change.id, { offline: true }) : []
|
|
2206
2542
|
];
|
|
2207
2543
|
const next = change.state === "returned" ? phaseState(phase) : nextState(type, phase);
|
|
2208
2544
|
const live2 = change.state === "returned" ? void 0 : liveHandoff(change);
|
|
@@ -2245,7 +2581,7 @@ async function changeReport(root, id) {
|
|
|
2245
2581
|
return { ...a, nextStep: nextStep(a, tasks), problems: ctx.problems };
|
|
2246
2582
|
}
|
|
2247
2583
|
async function taskTicks(root, id) {
|
|
2248
|
-
const text = await
|
|
2584
|
+
const text = await readFile10(join11(changeFolder(root, id), "tasks.md"), "utf8").catch(() => "");
|
|
2249
2585
|
const boxes = [...text.matchAll(/^\s*[-*]\s+\[([ xX])\]/gm)].map((m) => m[1] !== " ");
|
|
2250
2586
|
return boxes.length ? { done: boxes.filter(Boolean).length, total: boxes.length } : void 0;
|
|
2251
2587
|
}
|
|
@@ -2276,9 +2612,9 @@ function nextStep(a, tasks) {
|
|
|
2276
2612
|
}
|
|
2277
2613
|
|
|
2278
2614
|
// packages/changes/dist/new-change.js
|
|
2279
|
-
var
|
|
2280
|
-
import { mkdir, readFile as
|
|
2281
|
-
import { join as
|
|
2615
|
+
var import_yaml9 = __toESM(require_dist(), 1);
|
|
2616
|
+
import { mkdir, readFile as readFile11, writeFile as writeFile2 } from "node:fs/promises";
|
|
2617
|
+
import { join as join12 } from "node:path";
|
|
2282
2618
|
var nowIso2 = () => (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
2283
2619
|
var strip2 = (h) => h.startsWith("@") ? h.slice(1) : h;
|
|
2284
2620
|
function windowsUnsafeName(id) {
|
|
@@ -2290,7 +2626,7 @@ function slugify(title) {
|
|
|
2290
2626
|
}
|
|
2291
2627
|
async function exists(path) {
|
|
2292
2628
|
try {
|
|
2293
|
-
await
|
|
2629
|
+
await readFile11(path);
|
|
2294
2630
|
return true;
|
|
2295
2631
|
} catch {
|
|
2296
2632
|
return false;
|
|
@@ -2298,7 +2634,7 @@ async function exists(path) {
|
|
|
2298
2634
|
}
|
|
2299
2635
|
async function defaultSchema(root) {
|
|
2300
2636
|
try {
|
|
2301
|
-
const cfg = (0,
|
|
2637
|
+
const cfg = (0, import_yaml9.parse)(await readFile11(join12(openspecDirOf(root), "config.yaml"), "utf8"));
|
|
2302
2638
|
if (cfg && typeof cfg.schema === "string")
|
|
2303
2639
|
return cfg.schema;
|
|
2304
2640
|
} catch {
|
|
@@ -2322,17 +2658,17 @@ async function newChange(root, opts) {
|
|
|
2322
2658
|
const now = opts.now ?? nowIso2();
|
|
2323
2659
|
const by = strip2(opts.by);
|
|
2324
2660
|
const dir = changeFolder(root, id);
|
|
2325
|
-
if (opts.openspec && !await exists(
|
|
2661
|
+
if (opts.openspec && !await exists(join12(dir, ".openspec.yaml"))) {
|
|
2326
2662
|
await opts.openspec.newChange(id, { description: opts.title });
|
|
2327
2663
|
} else {
|
|
2328
2664
|
await mkdir(dir, { recursive: true });
|
|
2329
|
-
if (!await exists(
|
|
2330
|
-
await writeFile2(
|
|
2665
|
+
if (!await exists(join12(dir, ".openspec.yaml")))
|
|
2666
|
+
await writeFile2(join12(dir, ".openspec.yaml"), `schema: ${await defaultSchema(root)}
|
|
2331
2667
|
created: ${now.slice(0, 10)}
|
|
2332
2668
|
`, "utf8");
|
|
2333
2669
|
}
|
|
2334
|
-
if (!await exists(
|
|
2335
|
-
await writeFileAtomic(
|
|
2670
|
+
if (!await exists(join12(dir, "brief.md")))
|
|
2671
|
+
await writeFileAtomic(join12(dir, "brief.md"), renderTemplate(template, {
|
|
2336
2672
|
title: opts.title,
|
|
2337
2673
|
id,
|
|
2338
2674
|
type: type.id,
|
|
@@ -2372,7 +2708,7 @@ created: ${now.slice(0, 10)}
|
|
|
2372
2708
|
// packages/changes/dist/publish.js
|
|
2373
2709
|
import { rm } from "node:fs/promises";
|
|
2374
2710
|
import { randomUUID } from "node:crypto";
|
|
2375
|
-
import { join as
|
|
2711
|
+
import { join as join13, resolve } from "node:path";
|
|
2376
2712
|
function gitHandoffPublisher(opts = {}) {
|
|
2377
2713
|
const remote = opts.remote ?? "origin";
|
|
2378
2714
|
const env = opts.env ?? process.env;
|
|
@@ -2394,18 +2730,19 @@ function gitHandoffPublisher(opts = {}) {
|
|
|
2394
2730
|
const gitDir = await out(["rev-parse", "--absolute-git-dir"]);
|
|
2395
2731
|
await tryOut(["fetch", "--quiet", remote, base]);
|
|
2396
2732
|
await tryOut(["fetch", "--quiet", remote, branch]);
|
|
2397
|
-
const
|
|
2733
|
+
const onRemote = await tryOut([
|
|
2398
2734
|
"rev-parse",
|
|
2399
2735
|
"--verify",
|
|
2400
2736
|
"--quiet",
|
|
2401
2737
|
`refs/remotes/${remote}/${branch}^{commit}`
|
|
2402
|
-
])
|
|
2738
|
+
]);
|
|
2739
|
+
const start = onRemote ?? await tryOut([
|
|
2403
2740
|
"rev-parse",
|
|
2404
2741
|
"--verify",
|
|
2405
2742
|
"--quiet",
|
|
2406
2743
|
`refs/remotes/${remote}/${base}^{commit}`
|
|
2407
2744
|
]) ?? await out(["rev-parse", "--verify", `refs/heads/${base}^{commit}`]);
|
|
2408
|
-
const index =
|
|
2745
|
+
const index = join13(gitDir, `atticus-handoff-index-${process.pid}-${randomUUID()}`);
|
|
2409
2746
|
const staged = createGit({ env: { ...env, GIT_INDEX_FILE: index } });
|
|
2410
2747
|
try {
|
|
2411
2748
|
await staged(["read-tree", start], root);
|
|
@@ -2414,9 +2751,9 @@ function gitHandoffPublisher(opts = {}) {
|
|
|
2414
2751
|
const tree = (await staged(["write-tree"], root)).stdout.trim();
|
|
2415
2752
|
const startTree = await out(["rev-parse", `${start}^{tree}`]);
|
|
2416
2753
|
const commit = tree === startTree ? start : await out(["commit-tree", tree, "-p", start, "-m", message]);
|
|
2417
|
-
await out
|
|
2754
|
+
await keepLocalBranch(out, tryOut, branch, start, commit);
|
|
2418
2755
|
await out(["push", "--quiet", remote, `${commit}:refs/heads/${branch}`]);
|
|
2419
|
-
return { commit };
|
|
2756
|
+
return { commit, changed: commit !== onRemote };
|
|
2420
2757
|
} finally {
|
|
2421
2758
|
await rm(index, { force: true });
|
|
2422
2759
|
}
|
|
@@ -2424,15 +2761,49 @@ function gitHandoffPublisher(opts = {}) {
|
|
|
2424
2761
|
}
|
|
2425
2762
|
}
|
|
2426
2763
|
var queue = /* @__PURE__ */ new Map();
|
|
2764
|
+
async function handoffBranchPushed(root, branch, o = {}) {
|
|
2765
|
+
const git = createGit({ env: o.env ?? process.env });
|
|
2766
|
+
const sha = (ref) => git(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], root).then((x) => x.stdout.trim() || void 0, () => void 0);
|
|
2767
|
+
const here = await sha(`refs/heads/${branch}`);
|
|
2768
|
+
if (!here)
|
|
2769
|
+
return true;
|
|
2770
|
+
return await sha(`refs/remotes/${o.remote ?? "origin"}/${branch}`) === here;
|
|
2771
|
+
}
|
|
2772
|
+
async function pushHandoffBranch(root, branch, o) {
|
|
2773
|
+
requireApproval("git", o.approval);
|
|
2774
|
+
if (!/^handoff\//.test(branch))
|
|
2775
|
+
throw new Error(`${branch} isn't a hand-off branch`);
|
|
2776
|
+
const git = createGit({ env: o.env ?? process.env });
|
|
2777
|
+
const commit = (await git(["rev-parse", "--verify", `refs/heads/${branch}^{commit}`], root)).stdout.trim();
|
|
2778
|
+
await git(["push", "--quiet", o.remote ?? "origin", `refs/heads/${branch}:refs/heads/${branch}`], root);
|
|
2779
|
+
return { branch, commit };
|
|
2780
|
+
}
|
|
2781
|
+
async function keepLocalBranch(out, tryOut, branch, start, commit) {
|
|
2782
|
+
const ref = `refs/heads/${branch}`;
|
|
2783
|
+
const local = await tryOut(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`]);
|
|
2784
|
+
if (local === commit)
|
|
2785
|
+
return;
|
|
2786
|
+
const list = await tryOut(["worktree", "list", "--porcelain"]) ?? "";
|
|
2787
|
+
if (list.split(/\r?\n/).includes(`branch ${ref}`))
|
|
2788
|
+
return;
|
|
2789
|
+
if (!local) {
|
|
2790
|
+
await tryOut(["update-ref", ref, commit, ""]);
|
|
2791
|
+
return;
|
|
2792
|
+
}
|
|
2793
|
+
const own = await tryOut(["rev-list", "--count", `${start}..${local}`]);
|
|
2794
|
+
if (own === void 0 || own !== "0")
|
|
2795
|
+
return;
|
|
2796
|
+
await out(["update-ref", ref, commit, local]).catch(() => void 0);
|
|
2797
|
+
}
|
|
2427
2798
|
|
|
2428
2799
|
// packages/changes/dist/handoff.js
|
|
2429
|
-
import { readdir as
|
|
2430
|
-
import { join as
|
|
2800
|
+
import { readdir as readdir7, readFile as readFile13 } from "node:fs/promises";
|
|
2801
|
+
import { join as join15 } from "node:path";
|
|
2431
2802
|
|
|
2432
2803
|
// packages/changes/dist/drafted.js
|
|
2433
|
-
var
|
|
2434
|
-
import { mkdir as mkdir2, readdir as
|
|
2435
|
-
import { dirname, join as
|
|
2804
|
+
var import_yaml10 = __toESM(require_dist(), 1);
|
|
2805
|
+
import { mkdir as mkdir2, readdir as readdir6, readFile as readFile12, rm as rm2 } from "node:fs/promises";
|
|
2806
|
+
import { dirname, join as join14, relative, sep } from "node:path";
|
|
2436
2807
|
var CAPTURE_SCHEMA_VERSION = 1;
|
|
2437
2808
|
var DraftCapture = external_exports.object({
|
|
2438
2809
|
schemaVersion: external_exports.literal(CAPTURE_SCHEMA_VERSION),
|
|
@@ -2507,7 +2878,7 @@ var sameText = (text, recorded) => sha256(text) === recorded || sha256(text.repl
|
|
|
2507
2878
|
async function walk2(dir, rel = "") {
|
|
2508
2879
|
let entries;
|
|
2509
2880
|
try {
|
|
2510
|
-
entries = await
|
|
2881
|
+
entries = await readdir6(join14(dir, rel), { withFileTypes: true });
|
|
2511
2882
|
} catch {
|
|
2512
2883
|
return [];
|
|
2513
2884
|
}
|
|
@@ -2652,7 +3023,7 @@ async function captureHandoff(input) {
|
|
|
2652
3023
|
} else {
|
|
2653
3024
|
const texts = await Promise.all(recorded.map(async (r) => [
|
|
2654
3025
|
r,
|
|
2655
|
-
await
|
|
3026
|
+
await readFile12(join14(folder, ...r.path.split("/")), "utf8").catch(() => void 0)
|
|
2656
3027
|
]));
|
|
2657
3028
|
if (texts.every(([r, t]) => t !== void 0 && sameText(t, r.sha256))) {
|
|
2658
3029
|
from = "working-tree";
|
|
@@ -2716,10 +3087,10 @@ async function captureHandoff(input) {
|
|
|
2716
3087
|
} : {}
|
|
2717
3088
|
};
|
|
2718
3089
|
const p = capturePaths(name);
|
|
2719
|
-
await rm2(
|
|
2720
|
-
await rm2(
|
|
3090
|
+
await rm2(join14(folder, ...p.drafted.split("/")), { recursive: true, force: true });
|
|
3091
|
+
await rm2(join14(folder, ...p.merged.split("/")), { recursive: true, force: true });
|
|
2721
3092
|
const put = async (base, rel, text) => {
|
|
2722
|
-
const f =
|
|
3093
|
+
const f = join14(folder, ...base.split("/"), ...rel.split("/"));
|
|
2723
3094
|
await mkdir2(dirname(f), { recursive: true });
|
|
2724
3095
|
await writeFileAtomic(f, text);
|
|
2725
3096
|
};
|
|
@@ -2728,37 +3099,37 @@ async function captureHandoff(input) {
|
|
|
2728
3099
|
if (state === "captured")
|
|
2729
3100
|
for (const [rel, t] of mergedFiles)
|
|
2730
3101
|
await put(p.merged, rel, t);
|
|
2731
|
-
await mkdir2(
|
|
2732
|
-
await writeFileAtomic(
|
|
3102
|
+
await mkdir2(join14(folder, "stage"), { recursive: true });
|
|
3103
|
+
await writeFileAtomic(join14(folder, ...p.capture.split("/")), HEADER + (0, import_yaml10.stringify)(capture, { lineWidth: 0 }));
|
|
2733
3104
|
return { capture, file: p.capture };
|
|
2734
3105
|
}
|
|
2735
3106
|
async function readFolderFiles(dir) {
|
|
2736
3107
|
const out = /* @__PURE__ */ new Map();
|
|
2737
3108
|
for (const f of await walk2(dir))
|
|
2738
|
-
out.set(f, (await
|
|
3109
|
+
out.set(f, (await readFile12(join14(dir, ...f.split("/")), "utf8")).replace(/\r\n/g, "\n"));
|
|
2739
3110
|
return out;
|
|
2740
3111
|
}
|
|
2741
3112
|
async function changeFolders(root) {
|
|
2742
|
-
const base =
|
|
3113
|
+
const base = join14(root, ...changesRelOf(root).split("/"));
|
|
2743
3114
|
const out = [];
|
|
2744
|
-
const list = async (dir) => (await
|
|
3115
|
+
const list = async (dir) => (await readdir6(dir, { withFileTypes: true }).catch(() => [])).filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
2745
3116
|
for (const name of await list(base)) {
|
|
2746
3117
|
if (name === "archive")
|
|
2747
|
-
for (const a of await list(
|
|
2748
|
-
out.push(
|
|
3118
|
+
for (const a of await list(join14(base, "archive")))
|
|
3119
|
+
out.push(join14(base, "archive", a));
|
|
2749
3120
|
else
|
|
2750
|
-
out.push(
|
|
3121
|
+
out.push(join14(base, name));
|
|
2751
3122
|
}
|
|
2752
3123
|
return out;
|
|
2753
3124
|
}
|
|
2754
3125
|
async function readDraftPairs(root) {
|
|
2755
3126
|
const out = [];
|
|
2756
3127
|
for (const folder of await changeFolders(root)) {
|
|
2757
|
-
const names = (await
|
|
3128
|
+
const names = (await readdir6(join14(folder, "stage")).catch(() => [])).filter((f) => f.endsWith(".capture.yaml")).sort();
|
|
2758
3129
|
for (const f of names) {
|
|
2759
3130
|
let capture;
|
|
2760
3131
|
try {
|
|
2761
|
-
capture = DraftCapture.parse((0,
|
|
3132
|
+
capture = DraftCapture.parse((0, import_yaml10.parse)(await readFile12(join14(folder, "stage", f), "utf8")));
|
|
2762
3133
|
} catch {
|
|
2763
3134
|
continue;
|
|
2764
3135
|
}
|
|
@@ -2766,8 +3137,8 @@ async function readDraftPairs(root) {
|
|
|
2766
3137
|
out.push({
|
|
2767
3138
|
capture,
|
|
2768
3139
|
folder: relative(root, folder).split(sep).join("/"),
|
|
2769
|
-
drafted: await readFolderFiles(
|
|
2770
|
-
merged: await readFolderFiles(
|
|
3140
|
+
drafted: await readFolderFiles(join14(folder, ...p.drafted.split("/"))),
|
|
3141
|
+
merged: await readFolderFiles(join14(folder, ...p.merged.split("/")))
|
|
2771
3142
|
});
|
|
2772
3143
|
}
|
|
2773
3144
|
}
|
|
@@ -2787,8 +3158,8 @@ async function completeCaptures(root, ctx, o) {
|
|
|
2787
3158
|
continue;
|
|
2788
3159
|
for (const h of change.handoffs.filter((x) => x.state === "merged")) {
|
|
2789
3160
|
const { name } = await captureStageOf(ctx, change, h.phase);
|
|
2790
|
-
const file =
|
|
2791
|
-
const prior = await
|
|
3161
|
+
const file = join14(changeFolder(root, change.id), ...capturePaths(name).capture.split("/"));
|
|
3162
|
+
const prior = await readFile12(file, "utf8").then((t) => DraftCapture.safeParse((0, import_yaml10.parse)(t)), () => void 0);
|
|
2792
3163
|
if (prior?.success && prior.data.pr.number === h.pr.number && prior.data.state !== "waiting-for-merge")
|
|
2793
3164
|
continue;
|
|
2794
3165
|
const base = prior?.success ? prior.data.base : o.defaultBase ?? "main";
|
|
@@ -2812,6 +3183,7 @@ async function completeCaptures(root, ctx, o) {
|
|
|
2812
3183
|
// packages/changes/dist/handoff.js
|
|
2813
3184
|
var nowIso3 = () => (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
2814
3185
|
var strip3 = (h) => h.startsWith("@") ? h.slice(1) : h;
|
|
3186
|
+
var sameHandle = (a, b) => handleKey(a) === handleKey(b);
|
|
2815
3187
|
function metarepo(ctx, repo) {
|
|
2816
3188
|
const fromRuntime = ctx.orgPack.runtime.adapters.gitHost?.settings.metarepo;
|
|
2817
3189
|
const r = repo ?? (typeof fromRuntime === "string" ? fromRuntime : void 0);
|
|
@@ -2828,16 +3200,16 @@ async function load(root, id) {
|
|
|
2828
3200
|
}
|
|
2829
3201
|
async function walkReview(dir, gate) {
|
|
2830
3202
|
const out = [];
|
|
2831
|
-
const base =
|
|
3203
|
+
const base = join15(dir, "review", gate);
|
|
2832
3204
|
let rounds;
|
|
2833
3205
|
try {
|
|
2834
|
-
rounds = (await
|
|
3206
|
+
rounds = (await readdir7(base)).filter((r) => /^\d+$/.test(r)).sort((a, b) => Number(a) - Number(b));
|
|
2835
3207
|
} catch {
|
|
2836
3208
|
return [];
|
|
2837
3209
|
}
|
|
2838
3210
|
for (const r of rounds) {
|
|
2839
3211
|
try {
|
|
2840
|
-
for (const f of (await
|
|
3212
|
+
for (const f of (await readdir7(join15(base, r))).filter((x) => /\.ya?ml$/.test(x)).sort())
|
|
2841
3213
|
out.push(`review/${gate}/${r}/${f}`);
|
|
2842
3214
|
} catch {
|
|
2843
3215
|
}
|
|
@@ -2848,12 +3220,12 @@ async function keptPairFiles(dir) {
|
|
|
2848
3220
|
const out = [];
|
|
2849
3221
|
let entries;
|
|
2850
3222
|
try {
|
|
2851
|
-
entries = await
|
|
3223
|
+
entries = await readdir7(join15(dir, "stage"), { withFileTypes: true });
|
|
2852
3224
|
} catch {
|
|
2853
3225
|
return out;
|
|
2854
3226
|
}
|
|
2855
3227
|
const walk3 = async (rel) => {
|
|
2856
|
-
for (const e of await
|
|
3228
|
+
for (const e of await readdir7(join15(dir, ...rel.split("/")), { withFileTypes: true }).catch(() => [])) {
|
|
2857
3229
|
const p = `${rel}/${e.name}`;
|
|
2858
3230
|
if (e.isDirectory())
|
|
2859
3231
|
await walk3(p);
|
|
@@ -2887,15 +3259,20 @@ async function handoffFiles(ctx, a, phase) {
|
|
|
2887
3259
|
for (const f of await stageFiles(dir, step))
|
|
2888
3260
|
files.add(f);
|
|
2889
3261
|
}
|
|
2890
|
-
const present = async (f) =>
|
|
2891
|
-
for (const own of [
|
|
3262
|
+
const present = async (f) => readFile13(join15(dir, ...f.split("/"))).then(() => true, () => false);
|
|
3263
|
+
for (const own of [
|
|
3264
|
+
"stage/corrections.yaml",
|
|
3265
|
+
"stage/drafted.yaml",
|
|
3266
|
+
"stage/stories-numbers.yaml",
|
|
3267
|
+
"stage/stories-shape.yaml"
|
|
3268
|
+
])
|
|
2892
3269
|
if (await present(own))
|
|
2893
3270
|
files.add(own);
|
|
2894
3271
|
if (phase === "build") {
|
|
2895
3272
|
for (const extra of ["tasks.md", "repos.yaml"])
|
|
2896
3273
|
if (await present(extra))
|
|
2897
3274
|
files.add(extra);
|
|
2898
|
-
for (const t of await
|
|
3275
|
+
for (const t of await readdir7(join15(dir, "tasks"), { withFileTypes: true }).catch(() => []))
|
|
2899
3276
|
if (t.isDirectory() && await present(`tasks/${t.name}/report.md`))
|
|
2900
3277
|
files.add(`tasks/${t.name}/report.md`);
|
|
2901
3278
|
}
|
|
@@ -2918,6 +3295,11 @@ async function changeQuestionFiles(root, id) {
|
|
|
2918
3295
|
const rel = questionsRelOf(root);
|
|
2919
3296
|
return questions.filter((q) => namesChange(q.askedBy.command, id) || namesChange(q.rerun, id)).map((q) => `${rel}/${q.id}.yaml`).sort();
|
|
2920
3297
|
}
|
|
3298
|
+
function nextRoleOf(c, phase, person) {
|
|
3299
|
+
const n = nextOwnersOf(phase, c.owners);
|
|
3300
|
+
return n?.people.includes(person) ? ` (${n.role.replace(/-/g, " ")})` : "";
|
|
3301
|
+
}
|
|
3302
|
+
var nextRoleName = (phase) => (nextOwnersOf(phase, {})?.role ?? "reviewer").replace(/-/g, " ");
|
|
2921
3303
|
function prBody(a, phase, next, paths, reviewers, review) {
|
|
2922
3304
|
const c = a.change;
|
|
2923
3305
|
const lines2 = [
|
|
@@ -2933,7 +3315,7 @@ function prBody(a, phase, next, paths, reviewers, review) {
|
|
|
2933
3315
|
"",
|
|
2934
3316
|
"### Reviewers",
|
|
2935
3317
|
"",
|
|
2936
|
-
...reviewers.length ? reviewers.map((r) => `- @${r}`) : [
|
|
3318
|
+
...reviewers.length ? reviewers.map((r) => `- @${r}${nextRoleOf(c, phase, r)}`) : [`- None: name the ${nextRoleName(phase)} under the change's owners`],
|
|
2937
3319
|
"",
|
|
2938
3320
|
"### Risk",
|
|
2939
3321
|
"",
|
|
@@ -2964,7 +3346,7 @@ async function handoff(root, id, opts) {
|
|
|
2964
3346
|
await requireValid(opts.openspec, id);
|
|
2965
3347
|
const { files, artifacts } = await handoffFiles(ctx, a, phase);
|
|
2966
3348
|
const dir = changeFolder(root, id);
|
|
2967
|
-
const hashed = await Promise.all(files.map(async (path) => ({ path, sha256: sha256(await
|
|
3349
|
+
const hashed = await Promise.all(files.map(async (path) => ({ path, sha256: sha256(await readFile13(join15(dir, path))) })));
|
|
2968
3350
|
const authors = { ...change.authors };
|
|
2969
3351
|
for (const art of artifacts) {
|
|
2970
3352
|
const people = (opts.authors?.[art] ?? [by]).map(strip3);
|
|
@@ -2979,13 +3361,16 @@ async function handoff(root, id, opts) {
|
|
|
2979
3361
|
...questionFiles
|
|
2980
3362
|
];
|
|
2981
3363
|
const reviewers = [
|
|
2982
|
-
|
|
2983
|
-
|
|
3364
|
+
.../* @__PURE__ */ new Set([
|
|
3365
|
+
...files.flatMap((f) => ownersFor(ctx.codeowners, `${rel}/${id}/${f}`)),
|
|
3366
|
+
...nextOwnersOf(phase, change.owners)?.people ?? []
|
|
3367
|
+
])
|
|
3368
|
+
].filter((p) => sameHandle(p, by) === false).sort();
|
|
2984
3369
|
const live2 = change.state === "returned" ? void 0 : liveHandoff(change);
|
|
2985
3370
|
if (live2 && live2.phase === phase) {
|
|
2986
3371
|
const pr2 = await handoffPr(opts.gitHost, repo, id, live2);
|
|
2987
3372
|
if (pr2.state === "open" || pr2.state === "draft") {
|
|
2988
|
-
await opts.publisher?.publish({
|
|
3373
|
+
const published = await opts.publisher?.publish({
|
|
2989
3374
|
root,
|
|
2990
3375
|
branch,
|
|
2991
3376
|
base: pr2.base,
|
|
@@ -2993,7 +3378,9 @@ async function handoff(root, id, opts) {
|
|
|
2993
3378
|
message: `${handoffName(a.type, phase)}: update`,
|
|
2994
3379
|
approval: opts.approval
|
|
2995
3380
|
});
|
|
2996
|
-
|
|
3381
|
+
const unchanged = published ? published.changed === false : sameArtifacts(hashed, live2.artifacts);
|
|
3382
|
+
if (!unchanged)
|
|
3383
|
+
await opts.gitHost.comment(repo, pr2.number, `${by} updated the hand-off for another review.`, opts.approval);
|
|
2997
3384
|
const updated = {
|
|
2998
3385
|
...live2,
|
|
2999
3386
|
state: "open",
|
|
@@ -3014,6 +3401,13 @@ async function handoff(root, id, opts) {
|
|
|
3014
3401
|
live2.state = "closed";
|
|
3015
3402
|
live2.updatedAt = now;
|
|
3016
3403
|
}
|
|
3404
|
+
if (change.state === "returned") {
|
|
3405
|
+
const open = (await opts.gitHost.listPullRequests(repo, { head: branch })).find((p) => p.state === "open" || p.state === "draft");
|
|
3406
|
+
if (open) {
|
|
3407
|
+
const message = `PR #${open.number} from ${branch} is still open on the Git host (${open.url}): close it there first (the return asked for that), then resubmit the change.`;
|
|
3408
|
+
throw new ChangeError("refused", message, [{ code: "host-refused", message }]);
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3017
3411
|
const base = opts.base ?? (await opts.gitHost.getRepo(repo)).defaultBranch;
|
|
3018
3412
|
const next = a.next;
|
|
3019
3413
|
await opts.publisher?.publish({
|
|
@@ -3024,13 +3418,23 @@ async function handoff(root, id, opts) {
|
|
|
3024
3418
|
message: `${handoffName(a.type, phase)}: ${change.title}`,
|
|
3025
3419
|
approval: opts.approval
|
|
3026
3420
|
});
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3421
|
+
let pr;
|
|
3422
|
+
try {
|
|
3423
|
+
pr = await opts.gitHost.createPullRequest({
|
|
3424
|
+
repo,
|
|
3425
|
+
head: branch,
|
|
3426
|
+
base,
|
|
3427
|
+
title: `${change.title}: ${handoffName(a.type, phase)}`,
|
|
3428
|
+
body: prBody(a, phase, change.state === "returned" ? nextAfterResubmit(a, phase) : next, [...files.map((f) => `${rel}/${id}/${f}`), ...questionFiles], reviewers, opts.review)
|
|
3429
|
+
}, opts.approval);
|
|
3430
|
+
} catch (e) {
|
|
3431
|
+
if (!(e instanceof AdapterError) || e.code !== "conflict")
|
|
3432
|
+
throw e;
|
|
3433
|
+
const open = (await opts.gitHost.listPullRequests(repo, { head: branch }).catch(() => [])).filter((p) => p.base === base && (p.state === "open" || p.state === "draft")).at(0);
|
|
3434
|
+
if (!open)
|
|
3435
|
+
throw e;
|
|
3436
|
+
pr = open;
|
|
3437
|
+
}
|
|
3034
3438
|
const h = {
|
|
3035
3439
|
phase,
|
|
3036
3440
|
branch,
|
|
@@ -3057,6 +3461,10 @@ async function handoff(root, id, opts) {
|
|
|
3057
3461
|
});
|
|
3058
3462
|
return h;
|
|
3059
3463
|
}
|
|
3464
|
+
function sameArtifacts(a, b) {
|
|
3465
|
+
const key = (xs) => JSON.stringify([...xs].map((x) => `${x.path} ${x.sha256}`).sort());
|
|
3466
|
+
return key(a) === key(b);
|
|
3467
|
+
}
|
|
3060
3468
|
function nextAfterResubmit(a, phase) {
|
|
3061
3469
|
const next = a.type.phases[a.type.phases.indexOf(phase) + 1];
|
|
3062
3470
|
return next ? phaseState(next) : "released";
|
|
@@ -3255,10 +3663,15 @@ async function returnToPo(root, id, opts) {
|
|
|
3255
3663
|
async function requireValid(openspec, id) {
|
|
3256
3664
|
const r = await openspec.validate({ item: id, type: "change", strict: true });
|
|
3257
3665
|
const item = r.items[0];
|
|
3258
|
-
|
|
3666
|
+
const issues = item ? blockingIssues(item.issues) : [];
|
|
3667
|
+
if (!item || item.valid && issues.length === 0)
|
|
3259
3668
|
return;
|
|
3260
|
-
throw new ChangeError("refused", `${id} doesn't pass openspec validate --strict.`,
|
|
3669
|
+
throw new ChangeError("refused", `${id} doesn't pass openspec validate --strict.`, issues.map((i) => ({
|
|
3670
|
+
code: "openspec-invalid",
|
|
3671
|
+
message: `${i.path}: ${i.message}${archiveRefuses(i) ? ` ${ADDED_ONLY}` : ""}`
|
|
3672
|
+
})));
|
|
3261
3673
|
}
|
|
3674
|
+
var ADDED_ONLY = `A spec that openspec/specs doesn't have yet takes "## ADDED Requirements" only: change the delta's MODIFIED (or RENAMED, REMOVED) heading to ADDED, or run the stage that wrote it again.`;
|
|
3262
3675
|
async function archiveChange(root, id, opts) {
|
|
3263
3676
|
const { ctx, change } = await load(root, id);
|
|
3264
3677
|
const a = await assess(ctx, change);
|
|
@@ -3279,14 +3692,25 @@ async function archiveChange(root, id, opts) {
|
|
|
3279
3692
|
};
|
|
3280
3693
|
await changeStore(root).write(updated);
|
|
3281
3694
|
if (opts.openspec)
|
|
3282
|
-
|
|
3695
|
+
try {
|
|
3696
|
+
await opts.openspec.archive(id);
|
|
3697
|
+
} catch (e) {
|
|
3698
|
+
await changeStore(root).write(change);
|
|
3699
|
+
const words = (e instanceof Error ? e.message : String(e)).trim();
|
|
3700
|
+
throw new ChangeError("refused", `OpenSpec refused to archive ${id}, so nothing was archived.`, [
|
|
3701
|
+
{
|
|
3702
|
+
code: "openspec-invalid",
|
|
3703
|
+
message: `${words.replace(/\.?$/, ".")}${/target spec does not exist|only ADDED/i.test(words) ? ` ${ADDED_ONLY}` : " Fix what it says, then archive again (atticus openspec validate " + id + " --strict says more)."}`
|
|
3704
|
+
}
|
|
3705
|
+
]);
|
|
3706
|
+
}
|
|
3283
3707
|
return updated;
|
|
3284
3708
|
}
|
|
3285
3709
|
|
|
3286
3710
|
// packages/changes/dist/learn.js
|
|
3287
|
-
var
|
|
3288
|
-
import { readFile as
|
|
3289
|
-
import { join as
|
|
3711
|
+
var import_yaml11 = __toESM(require_dist(), 1);
|
|
3712
|
+
import { readFile as readFile14 } from "node:fs/promises";
|
|
3713
|
+
import { join as join16 } from "node:path";
|
|
3290
3714
|
var LEARN_SCHEMA_VERSION = 1;
|
|
3291
3715
|
var MAX_CELLS = 4e6;
|
|
3292
3716
|
var lines = (text) => {
|
|
@@ -3633,7 +4057,7 @@ async function pairTouches(root, p) {
|
|
|
3633
4057
|
let entry;
|
|
3634
4058
|
const yaml = (t) => {
|
|
3635
4059
|
try {
|
|
3636
|
-
const v = (0,
|
|
4060
|
+
const v = (0, import_yaml11.parse)(t);
|
|
3637
4061
|
return v && typeof v === "object" ? v : void 0;
|
|
3638
4062
|
} catch {
|
|
3639
4063
|
return void 0;
|
|
@@ -3675,7 +4099,7 @@ async function pairTouches(root, p) {
|
|
|
3675
4099
|
flows.push(m[1]);
|
|
3676
4100
|
}
|
|
3677
4101
|
}
|
|
3678
|
-
const change = yaml(await
|
|
4102
|
+
const change = yaml(await readFile14(join16(root, ...p.folder.split("/"), "change.yaml"), "utf8").catch(() => ""));
|
|
3679
4103
|
const touches = change?.touches ?? {};
|
|
3680
4104
|
for (const r of Array.isArray(touches.repos) ? touches.repos : [])
|
|
3681
4105
|
if (typeof r === "string")
|
|
@@ -3768,8 +4192,8 @@ async function detectConflicts(root) {
|
|
|
3768
4192
|
}
|
|
3769
4193
|
|
|
3770
4194
|
// packages/changes/dist/size.js
|
|
3771
|
-
import { readFile as
|
|
3772
|
-
import { join as
|
|
4195
|
+
import { readFile as readFile15 } from "node:fs/promises";
|
|
4196
|
+
import { join as join17 } from "node:path";
|
|
3773
4197
|
async function changeSize(ctx, change) {
|
|
3774
4198
|
const type = ctx.orgPack.changeTypes.types.find((t) => t.id === change.type);
|
|
3775
4199
|
if (!type)
|
|
@@ -3778,7 +4202,7 @@ async function changeSize(ctx, change) {
|
|
|
3778
4202
|
why: "standard",
|
|
3779
4203
|
words: `${change.type} isn't a change type in change-types.yaml, so ${change.id} takes the full path.`
|
|
3780
4204
|
};
|
|
3781
|
-
const brief = await
|
|
4205
|
+
const brief = await readFile15(join17(changeFolder(ctx.root, change.id), "brief.md"), "utf8").catch(() => "");
|
|
3782
4206
|
const f = fastPathOf(type, brief);
|
|
3783
4207
|
const gate = f.fast ? fastGateOf(type, ctx.orgPack.gates) : void 0;
|
|
3784
4208
|
const words = {
|
|
@@ -3792,13 +4216,13 @@ async function changeSize(ctx, change) {
|
|
|
3792
4216
|
}
|
|
3793
4217
|
|
|
3794
4218
|
// packages/changes/dist/openspec-stores.js
|
|
3795
|
-
import { existsSync as
|
|
3796
|
-
import { readFile as
|
|
4219
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
4220
|
+
import { readFile as readFile16, writeFile as writeFile3 } from "node:fs/promises";
|
|
3797
4221
|
import { homedir } from "node:os";
|
|
3798
|
-
import { basename, isAbsolute, join as
|
|
4222
|
+
import { basename, isAbsolute, join as join18, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
|
|
3799
4223
|
function storeDirOf(root, path) {
|
|
3800
4224
|
if (path === "~" || path.startsWith("~/") || path.startsWith("~\\"))
|
|
3801
|
-
return
|
|
4225
|
+
return join18(homedir(), path.slice(2));
|
|
3802
4226
|
return isAbsolute(path) ? resolve2(path) : resolve2(root, path);
|
|
3803
4227
|
}
|
|
3804
4228
|
function packRel(root) {
|
|
@@ -3828,7 +4252,7 @@ async function storeSpecLookup(root, capability) {
|
|
|
3828
4252
|
var REMOTE = /^[a-z][a-z0-9+.-]*:\/\//i;
|
|
3829
4253
|
var SCP = /^[^/\\]+@[^:/\\]+:/;
|
|
3830
4254
|
async function metarepoOrigin(root, git = createGit()) {
|
|
3831
|
-
if (!
|
|
4255
|
+
if (!existsSync3(join18(root, ".git")))
|
|
3832
4256
|
return void 0;
|
|
3833
4257
|
try {
|
|
3834
4258
|
const url = (await git(["remote", "get-url", "origin"], root)).stdout.trim();
|
|
@@ -3839,7 +4263,7 @@ async function metarepoOrigin(root, git = createGit()) {
|
|
|
3839
4263
|
return void 0;
|
|
3840
4264
|
}
|
|
3841
4265
|
}
|
|
3842
|
-
async function referenceMetarepoIn(root,
|
|
4266
|
+
async function referenceMetarepoIn(root, repoDir3, o = {}) {
|
|
3843
4267
|
const { settings } = await loadOpenSpecSettings(orgPackDirOf(root));
|
|
3844
4268
|
if (!settings.referenceInRepos)
|
|
3845
4269
|
return { action: "off" };
|
|
@@ -3851,8 +4275,8 @@ async function referenceMetarepoIn(root, repoDir, o = {}) {
|
|
|
3851
4275
|
file,
|
|
3852
4276
|
why: marker.missing ? `this metarepo isn't an OpenSpec store yet (no ${STORE_MARKER}): run atticus upgrade --openspec-store, commit the file, then hand down again` : `this metarepo's ${STORE_MARKER} can't be read (${marker.notes.join("; ")})`
|
|
3853
4277
|
};
|
|
3854
|
-
const path =
|
|
3855
|
-
const text = await
|
|
4278
|
+
const path = join18(repoDir3, "openspec", "config.yaml");
|
|
4279
|
+
const text = await readFile16(path, "utf8").catch(() => void 0);
|
|
3856
4280
|
if (text === void 0)
|
|
3857
4281
|
return {
|
|
3858
4282
|
action: "skipped",
|
|
@@ -3869,7 +4293,7 @@ async function referenceMetarepoIn(root, repoDir, o = {}) {
|
|
|
3869
4293
|
}
|
|
3870
4294
|
|
|
3871
4295
|
// packages/changes/dist/merge-record.js
|
|
3872
|
-
var
|
|
4296
|
+
var import_yaml12 = __toESM(require_dist(), 1);
|
|
3873
4297
|
import { isDeepStrictEqual } from "node:util";
|
|
3874
4298
|
var HANDOFF_RANK = {
|
|
3875
4299
|
open: 0,
|
|
@@ -3987,7 +4411,7 @@ function mergeChangeRecords(base, ours, theirs) {
|
|
|
3987
4411
|
}
|
|
3988
4412
|
function readRecord(text) {
|
|
3989
4413
|
try {
|
|
3990
|
-
const r = ChangeLifecycle.safeParse((0,
|
|
4414
|
+
const r = ChangeLifecycle.safeParse((0, import_yaml12.parse)(text));
|
|
3991
4415
|
return r.success ? r.data : void 0;
|
|
3992
4416
|
} catch {
|
|
3993
4417
|
return void 0;
|
|
@@ -4038,6 +4462,29 @@ async function setChangeOwners(root, id, owners) {
|
|
|
4038
4462
|
return r.data;
|
|
4039
4463
|
}
|
|
4040
4464
|
|
|
4465
|
+
// packages/changes/dist/edit-hash.js
|
|
4466
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
4467
|
+
function editText(file, text) {
|
|
4468
|
+
const lf = text.replace(/\r\n?/g, "\n");
|
|
4469
|
+
return isTasks(file) ? lf.replace(/^(\s*[-*]\s+\[)[ xX]?(\])/gm, "$1 $2") : lf;
|
|
4470
|
+
}
|
|
4471
|
+
function editSha(file, text) {
|
|
4472
|
+
const h = createHash2("sha256");
|
|
4473
|
+
if (typeof text !== "string" && !text.includes(13) && !isTasks(file))
|
|
4474
|
+
return h.update(text).digest("hex");
|
|
4475
|
+
const t = typeof text === "string" ? text : text.toString("utf8");
|
|
4476
|
+
return h.update(editText(file, t), "utf8").digest("hex");
|
|
4477
|
+
}
|
|
4478
|
+
function wroteThis(file, text, hash) {
|
|
4479
|
+
if (hash === void 0)
|
|
4480
|
+
return false;
|
|
4481
|
+
if (editSha(file, text) === hash)
|
|
4482
|
+
return true;
|
|
4483
|
+
const t = typeof text === "string" ? text : text.toString("utf8");
|
|
4484
|
+
return createHash2("sha256").update(t.replace(/\r\n?/g, "\n"), "utf8").digest("hex") === hash;
|
|
4485
|
+
}
|
|
4486
|
+
var isTasks = (file) => file.split(/[\\/]/).at(-1) === "tasks.md";
|
|
4487
|
+
|
|
4041
4488
|
export {
|
|
4042
4489
|
ChangeError,
|
|
4043
4490
|
readTables,
|
|
@@ -4104,8 +4551,15 @@ export {
|
|
|
4104
4551
|
workProgress,
|
|
4105
4552
|
privacyImpact,
|
|
4106
4553
|
prApprovers,
|
|
4554
|
+
TASK_DECISION_FILE,
|
|
4555
|
+
readTaskDecision,
|
|
4556
|
+
unmergedTaskBranches,
|
|
4557
|
+
unmergedTaskWords,
|
|
4558
|
+
taskBranchReasons,
|
|
4559
|
+
recordTaskDecision,
|
|
4107
4560
|
RELEASE_PR_STATES,
|
|
4108
4561
|
RELEASE_PRS_FILE,
|
|
4562
|
+
staleReleasePrs,
|
|
4109
4563
|
nothingToRelease,
|
|
4110
4564
|
raiseReleasePrs,
|
|
4111
4565
|
syncReleasePrs,
|
|
@@ -4121,6 +4575,8 @@ export {
|
|
|
4121
4575
|
slugify,
|
|
4122
4576
|
newChange,
|
|
4123
4577
|
gitHandoffPublisher,
|
|
4578
|
+
handoffBranchPushed,
|
|
4579
|
+
pushHandoffBranch,
|
|
4124
4580
|
CAPTURE_SCHEMA_VERSION,
|
|
4125
4581
|
DraftCapture,
|
|
4126
4582
|
capturePaths,
|
|
@@ -4160,5 +4616,8 @@ export {
|
|
|
4160
4616
|
mergeChangeText,
|
|
4161
4617
|
OWNER_ROLE_KEYS,
|
|
4162
4618
|
ChangeOwnersError,
|
|
4163
|
-
setChangeOwners
|
|
4619
|
+
setChangeOwners,
|
|
4620
|
+
editText,
|
|
4621
|
+
editSha,
|
|
4622
|
+
wroteThis
|
|
4164
4623
|
};
|