@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
|
@@ -3,6 +3,11 @@ import { fileURLToPath as __atticusFileURLToPath } from "node:url";
|
|
|
3
3
|
var require = __atticusCreateRequire(import.meta.url);
|
|
4
4
|
var __atticusUrl = (p) => new URL("./" + p, import.meta.url).href;
|
|
5
5
|
var __atticusPath = (p) => __atticusFileURLToPath(__atticusUrl(p));
|
|
6
|
+
import {
|
|
7
|
+
readRound,
|
|
8
|
+
reviewedGates,
|
|
9
|
+
roundsOf
|
|
10
|
+
} from "./chunk-D6BVLTDV.js";
|
|
6
11
|
import {
|
|
7
12
|
QueryError,
|
|
8
13
|
askLookup,
|
|
@@ -10,21 +15,16 @@ import {
|
|
|
10
15
|
impact,
|
|
11
16
|
openIndex,
|
|
12
17
|
translate
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import {
|
|
15
|
-
readRound,
|
|
16
|
-
reviewedGates,
|
|
17
|
-
roundsOf
|
|
18
|
-
} from "./chunk-K332XW7K.js";
|
|
18
|
+
} from "./chunk-RCG5IAAT.js";
|
|
19
19
|
import {
|
|
20
20
|
changeFolder,
|
|
21
21
|
changeStore
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-WZYM5M4U.js";
|
|
23
23
|
import {
|
|
24
24
|
baseClonePath,
|
|
25
25
|
gitUser,
|
|
26
26
|
loadRepos
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-3EWKO457.js";
|
|
28
28
|
import {
|
|
29
29
|
API_VERSION,
|
|
30
30
|
DEFAULT_PORT,
|
|
@@ -32,7 +32,10 @@ import {
|
|
|
32
32
|
RECORD_KINDS,
|
|
33
33
|
RecordId,
|
|
34
34
|
Severity,
|
|
35
|
+
api_exports,
|
|
36
|
+
asksOfFinding,
|
|
35
37
|
catalogDirOf,
|
|
38
|
+
catalogMayHaveChangedAt,
|
|
36
39
|
factsDirOf,
|
|
37
40
|
fastPathOf,
|
|
38
41
|
inputsDirOf,
|
|
@@ -44,14 +47,17 @@ import {
|
|
|
44
47
|
proposalsDirOf,
|
|
45
48
|
questionOfLens,
|
|
46
49
|
questionsDirOf,
|
|
50
|
+
rolesOfPerson,
|
|
47
51
|
runsDirOf,
|
|
48
52
|
specsDirOf,
|
|
49
53
|
withSignal
|
|
50
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-FPBUTZI5.js";
|
|
51
55
|
import {
|
|
52
56
|
FileChangedError,
|
|
53
|
-
SCHEMA_VERSION
|
|
54
|
-
|
|
57
|
+
SCHEMA_VERSION,
|
|
58
|
+
printToCurrent,
|
|
59
|
+
withPrinter
|
|
60
|
+
} from "./chunk-B4AEL3RF.js";
|
|
55
61
|
|
|
56
62
|
// packages/server/dist/http.js
|
|
57
63
|
var HttpError = class extends Error {
|
|
@@ -135,125 +141,73 @@ function intParam(q, name, min, max) {
|
|
|
135
141
|
}
|
|
136
142
|
var strParam = (q, name) => q.get(name) || void 0;
|
|
137
143
|
|
|
138
|
-
// packages/server/dist/server.js
|
|
139
|
-
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
140
|
-
import { createServer } from "node:http";
|
|
141
|
-
|
|
142
|
-
// packages/server/dist/jobs.js
|
|
143
|
-
var JobManager = class {
|
|
144
|
-
publish;
|
|
145
|
-
now;
|
|
146
|
-
jobs = /* @__PURE__ */ new Map();
|
|
147
|
-
cancelledIds = /* @__PURE__ */ new Set();
|
|
148
|
-
aborts = /* @__PURE__ */ new Map();
|
|
149
|
-
seq = 0;
|
|
150
|
-
/** Round 41: every running job of a kind, in start order (a later one never hides an earlier). */
|
|
151
|
-
running = /* @__PURE__ */ new Map();
|
|
152
|
-
constructor(publish, now = () => /* @__PURE__ */ new Date()) {
|
|
153
|
-
this.publish = publish;
|
|
154
|
-
this.now = now;
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* A running job of a kind, if any: the earliest still running (one scan at a time: a second
|
|
158
|
-
* ask gets 409).
|
|
159
|
-
*/
|
|
160
|
-
runningOf(kind) {
|
|
161
|
-
for (const id of this.running.get(kind) ?? []) {
|
|
162
|
-
const j = this.jobs.get(id);
|
|
163
|
-
if (j?.state === "running")
|
|
164
|
-
return j;
|
|
165
|
-
}
|
|
166
|
-
return void 0;
|
|
167
|
-
}
|
|
168
|
-
get(id) {
|
|
169
|
-
return this.jobs.get(id);
|
|
170
|
-
}
|
|
171
|
-
start(kind, work) {
|
|
172
|
-
const id = `job-${++this.seq}`;
|
|
173
|
-
const job = {
|
|
174
|
-
id,
|
|
175
|
-
kind,
|
|
176
|
-
state: "running",
|
|
177
|
-
progress: { done: 0, total: 0, message: "Starting" },
|
|
178
|
-
startedAt: this.now().toISOString(),
|
|
179
|
-
errors: []
|
|
180
|
-
};
|
|
181
|
-
this.jobs.set(id, job);
|
|
182
|
-
const ofKind = this.running.get(kind) ?? /* @__PURE__ */ new Set();
|
|
183
|
-
ofKind.add(id);
|
|
184
|
-
this.running.set(kind, ofKind);
|
|
185
|
-
const abort = new AbortController();
|
|
186
|
-
this.aborts.set(id, abort);
|
|
187
|
-
const cancelled = this.cancelledIds;
|
|
188
|
-
const control = {
|
|
189
|
-
progress: (done, total, message) => {
|
|
190
|
-
job.progress = { done, total, message };
|
|
191
|
-
this.publish({ type: "job.progress", jobId: id, done, total, message });
|
|
192
|
-
},
|
|
193
|
-
get cancelled() {
|
|
194
|
-
return cancelled.has(id);
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
void (async () => {
|
|
198
|
-
try {
|
|
199
|
-
const out = await withSignal(abort.signal, () => work(control));
|
|
200
|
-
if (out?.result)
|
|
201
|
-
job.result = out.result;
|
|
202
|
-
if (out?.errors?.length)
|
|
203
|
-
job.errors.push(...out.errors);
|
|
204
|
-
job.state = this.cancelledIds.has(id) ? "cancelled" : job.errors.length ? "failed" : "done";
|
|
205
|
-
} catch (e) {
|
|
206
|
-
if (this.cancelledIds.has(id))
|
|
207
|
-
job.state = "cancelled";
|
|
208
|
-
else {
|
|
209
|
-
job.errors.push(e instanceof Error ? e.message : String(e));
|
|
210
|
-
job.state = "failed";
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
this.aborts.delete(id);
|
|
214
|
-
job.finishedAt = this.now().toISOString();
|
|
215
|
-
ofKind.delete(id);
|
|
216
|
-
if (!ofKind.size && this.running.get(kind) === ofKind)
|
|
217
|
-
this.running.delete(kind);
|
|
218
|
-
this.publish({ type: "job.done", jobId: id, state: job.state });
|
|
219
|
-
})();
|
|
220
|
-
return job;
|
|
221
|
-
}
|
|
222
|
-
/** Ask a running job to stop; false when it already finished. */
|
|
223
|
-
cancel(id) {
|
|
224
|
-
const j = this.jobs.get(id);
|
|
225
|
-
if (!j || j.state !== "running")
|
|
226
|
-
return false;
|
|
227
|
-
this.cancelledIds.add(id);
|
|
228
|
-
this.aborts.get(id)?.abort();
|
|
229
|
-
return true;
|
|
230
|
-
}
|
|
231
|
-
/** Wait for a job to finish (tests and the CLI). */
|
|
232
|
-
async settle(id, timeoutMs = 6e4) {
|
|
233
|
-
const start = Date.now();
|
|
234
|
-
for (; ; ) {
|
|
235
|
-
const j = this.jobs.get(id);
|
|
236
|
-
if (!j)
|
|
237
|
-
throw new Error(`No job ${id}`);
|
|
238
|
-
if (j.state !== "running" && j.state !== "queued")
|
|
239
|
-
return j;
|
|
240
|
-
if (Date.now() - start > timeoutMs)
|
|
241
|
-
throw new Error(`Job ${id} did not finish`);
|
|
242
|
-
await new Promise((r) => setTimeout(r, 20));
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
|
|
247
144
|
// packages/server/dist/routes.js
|
|
145
|
+
import { existsSync } from "node:fs";
|
|
248
146
|
import { readFile, stat } from "node:fs/promises";
|
|
249
147
|
import { join } from "node:path";
|
|
250
148
|
var queues = /* @__PURE__ */ new Map();
|
|
251
|
-
|
|
149
|
+
var checked = /* @__PURE__ */ new Map();
|
|
150
|
+
var TRUST_MS = 3e4;
|
|
151
|
+
var following = /* @__PURE__ */ new Set();
|
|
152
|
+
var changes = /* @__PURE__ */ new Map();
|
|
153
|
+
function trustIndexBetweenChanges(root, on) {
|
|
154
|
+
if (on)
|
|
155
|
+
following.add(root);
|
|
156
|
+
else {
|
|
157
|
+
following.delete(root);
|
|
158
|
+
checked.delete(root);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function indexFilesChanged(root) {
|
|
162
|
+
for (const r of root ? [root] : [...following, ...checked.keys()]) {
|
|
163
|
+
checked.delete(r);
|
|
164
|
+
changes.set(r, (changes.get(r) ?? 0) + 1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
var embedding = /* @__PURE__ */ new Map();
|
|
168
|
+
var asked = /* @__PURE__ */ new Map();
|
|
169
|
+
function embedSoon(root) {
|
|
170
|
+
if (embedding.has(root) || process.env.ATTICUS_EMBEDDINGS === "off")
|
|
171
|
+
return;
|
|
172
|
+
const step = () => {
|
|
173
|
+
if (Date.now() - (asked.get(root) ?? 0) < 1500) {
|
|
174
|
+
embedding.set(root, setTimeout(step, 1e3).unref());
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
void withIndex(root, (ix) => ix.embed({ max: 8 }), { meaning: true }).then((n) => n > 0, () => false).then((more) => {
|
|
178
|
+
if (more && embedding.has(root))
|
|
179
|
+
embedding.set(root, setTimeout(step, 50).unref());
|
|
180
|
+
else
|
|
181
|
+
embedding.delete(root);
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
embedding.set(root, setTimeout(step, 2e3).unref());
|
|
185
|
+
}
|
|
186
|
+
function stopEmbedding(root) {
|
|
187
|
+
const t = embedding.get(root);
|
|
188
|
+
if (t)
|
|
189
|
+
clearTimeout(t);
|
|
190
|
+
embedding.delete(root);
|
|
191
|
+
}
|
|
192
|
+
async function withIndex(root, f, o = {}) {
|
|
193
|
+
if (!o.meaning)
|
|
194
|
+
asked.set(root, Date.now());
|
|
252
195
|
const before = queues.get(root) ?? Promise.resolve();
|
|
253
196
|
const mine = before.then(async () => {
|
|
254
|
-
const
|
|
197
|
+
const trusted = following.has(root) && Date.now() - (checked.get(root) ?? -Infinity) < TRUST_MS;
|
|
198
|
+
const at = changes.get(root) ?? 0;
|
|
199
|
+
const ix = await openIndex(root, {
|
|
200
|
+
embedOnOpen: 0,
|
|
201
|
+
// Only search and ask compare by meaning; the counts, lists and graph never need the model.
|
|
202
|
+
...o.meaning ? {} : { embeddings: "off" },
|
|
203
|
+
...trusted ? { trusted: true } : {}
|
|
204
|
+
});
|
|
205
|
+
if (!trusted && following.has(root) && (changes.get(root) ?? 0) === at)
|
|
206
|
+
checked.set(root, Date.now());
|
|
207
|
+
if (!trusted && !o.meaning)
|
|
208
|
+
embedSoon(root);
|
|
255
209
|
try {
|
|
256
|
-
return f(ix);
|
|
210
|
+
return await f(ix);
|
|
257
211
|
} finally {
|
|
258
212
|
ix.close();
|
|
259
213
|
}
|
|
@@ -316,7 +270,9 @@ function apiRoutes(r, ctx) {
|
|
|
316
270
|
root,
|
|
317
271
|
openspec: layoutOf(root).openspec.replace(/\/+$/, ""),
|
|
318
272
|
user: ctx.user,
|
|
319
|
-
full: ctx.full === true
|
|
273
|
+
full: ctx.full === true,
|
|
274
|
+
// ADR 0190: in a folder that isn't a metarepo yet, the app offers to create one.
|
|
275
|
+
metarepo: existsSync(join(root, "org-pack")) || existsSync(join(root, ".atticus", "org-pack"))
|
|
320
276
|
}
|
|
321
277
|
})).add("GET", "/api/catalog/kinds", async () => ({
|
|
322
278
|
status: 200,
|
|
@@ -356,26 +312,25 @@ function apiRoutes(r, ctx) {
|
|
|
356
312
|
const q = strParam(query, "q");
|
|
357
313
|
if (!q)
|
|
358
314
|
throw badRequest("Ask a question: ?q=<plain words>.");
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
};
|
|
315
|
+
const knowledge = ctx.askKnowledge ? await ctx.askKnowledge(q).catch(() => void 0) : void 0;
|
|
316
|
+
const answer = await withIndex(root, (ix) => {
|
|
317
|
+
const asked2 = translate(q, askLookup(ix));
|
|
318
|
+
if (asked2.action === "impact")
|
|
319
|
+
return { question: q, ...asked2, impact: impact(ix, asked2.id, 4) };
|
|
320
|
+
if (asked2.action === "owner") {
|
|
321
|
+
const r2 = ix.find(asked2.id)[0];
|
|
322
|
+
const owner = r2?.owner ?? r2?.ownerComponent ?? (r2 ? ix.find(String(r2.system ?? ""))[0]?.owner : void 0);
|
|
323
|
+
return { question: q, ...asked2, owner: owner ?? null };
|
|
324
|
+
}
|
|
325
|
+
try {
|
|
326
|
+
return { question: q, ...asked2, result: ix.query(asked2.query, { limit: 60 }) };
|
|
327
|
+
} catch (e) {
|
|
328
|
+
if (e instanceof QueryError)
|
|
329
|
+
return { question: q, ...asked2, error: e.message };
|
|
330
|
+
throw e;
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
return { status: 200, body: knowledge ? { ...answer, knowledge } : answer };
|
|
379
334
|
}).add("GET", "/api/graph", async ({ query }) => {
|
|
380
335
|
const depth = intParam(query, "depth", 1, 6);
|
|
381
336
|
const o = {
|
|
@@ -449,7 +404,7 @@ function apiRoutes(r, ctx) {
|
|
|
449
404
|
if (!res)
|
|
450
405
|
throw notFound(`There is no record ${params.id} in the catalog.`);
|
|
451
406
|
const near = /* @__PURE__ */ new Set([...res.systems, params.id, ...res.reach.affected.map((a) => a.id)]);
|
|
452
|
-
const
|
|
407
|
+
const changes2 = (await changeStore(root).list()).filter((c) => c.systems.some((s) => near.has(s)) || [...c.touches.records, ...c.touches.tables, ...c.touches.dataStores].some((x) => near.has(x))).map((c) => ({
|
|
453
408
|
id: c.id,
|
|
454
409
|
title: c.title,
|
|
455
410
|
state: c.state,
|
|
@@ -466,7 +421,7 @@ function apiRoutes(r, ctx) {
|
|
|
466
421
|
call: res.owners,
|
|
467
422
|
ownerUnknown: res.unowned,
|
|
468
423
|
watch: res.watch,
|
|
469
|
-
recentChanges:
|
|
424
|
+
recentChanges: changes2
|
|
470
425
|
}
|
|
471
426
|
};
|
|
472
427
|
}).add("GET", "/api/repos", async () => {
|
|
@@ -479,13 +434,18 @@ function apiRoutes(r, ctx) {
|
|
|
479
434
|
return { status: 200, body };
|
|
480
435
|
}).add("GET", "/api/changes", async ({ query }) => {
|
|
481
436
|
const state = strParam(query, "state");
|
|
482
|
-
const
|
|
437
|
+
const changes2 = (await changeStore(root).list()).filter((c) => !state || c.state === state);
|
|
483
438
|
const body = [];
|
|
484
|
-
const
|
|
485
|
-
|
|
439
|
+
const op = await loadOrgPack(orgPackDirOf(root)).catch(() => void 0);
|
|
440
|
+
const types = op?.changeTypes.types ?? [];
|
|
441
|
+
const custom = op?.roles?.custom ?? [];
|
|
442
|
+
for (const c of changes2.sort((a, b) => a.id.localeCompare(b.id))) {
|
|
486
443
|
const type = types.find((t) => t.id === c.type);
|
|
487
444
|
const fast = !!type && (type.size === "small" || !!type.smallWhenBriefSays) && fastPathOf(type, await readFile(join(changeFolder(root, c.id), "brief.md"), "utf8").catch(() => "")).fast;
|
|
488
|
-
body.push(
|
|
445
|
+
body.push({
|
|
446
|
+
...summary(c, await latestFindings(root, c.id), fast),
|
|
447
|
+
yourRoles: rolesOfPerson(ctx.user, c.owners ?? {}, custom)
|
|
448
|
+
});
|
|
489
449
|
}
|
|
490
450
|
return { status: 200, body };
|
|
491
451
|
}).add("GET", "/api/findings", async ({ query }) => {
|
|
@@ -496,13 +456,16 @@ function apiRoutes(r, ctx) {
|
|
|
496
456
|
const state = strParam(query, "state");
|
|
497
457
|
const lens = enumParam(query, "lens", Lens.options);
|
|
498
458
|
const severity = enumParam(query, "severity", Severity.options);
|
|
459
|
+
const asks = enumParam(query, "asks", ["business", "design", "delivery"]);
|
|
499
460
|
const ids = change ? [change] : (await changeStore(root).list()).map((c) => c.id).sort();
|
|
500
461
|
const body = [];
|
|
501
462
|
for (const id of ids)
|
|
502
|
-
for (const f of await latestFindings(root, id))
|
|
463
|
+
for (const f of await latestFindings(root, id)) {
|
|
464
|
+
const level = asksOfFinding(f);
|
|
503
465
|
if ((!gate || f.gate === gate) && (!state || f.state === state) && // A lens filter asks its question: an old lens name finds what its question raised.
|
|
504
|
-
(!lens || questionOfLens(f.lens) === questionOfLens(lens)) && (!severity || f.severity === severity))
|
|
505
|
-
body.push(f);
|
|
466
|
+
(!lens || questionOfLens(f.lens) === questionOfLens(lens)) && (!severity || f.severity === severity) && (!asks || level === asks))
|
|
467
|
+
body.push({ ...f, asks: level });
|
|
468
|
+
}
|
|
506
469
|
return { status: 200, body };
|
|
507
470
|
}).add("GET", "/api/findings/{changeId}/{findingId}", async ({ params }) => {
|
|
508
471
|
if (!RecordId.safeParse(params.changeId).success)
|
|
@@ -549,6 +512,224 @@ function apiRoutes(r, ctx) {
|
|
|
549
512
|
});
|
|
550
513
|
}
|
|
551
514
|
|
|
515
|
+
// packages/server/dist/server.js
|
|
516
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
517
|
+
import { createServer } from "node:http";
|
|
518
|
+
|
|
519
|
+
// packages/server/dist/jobs.js
|
|
520
|
+
var JOB_LINES = 5e3;
|
|
521
|
+
var JOBS_KEPT = 100;
|
|
522
|
+
var jobLine = (line) => printToCurrent(line);
|
|
523
|
+
var JobManager = class {
|
|
524
|
+
publish;
|
|
525
|
+
now;
|
|
526
|
+
jobs = /* @__PURE__ */ new Map();
|
|
527
|
+
cancelledIds = /* @__PURE__ */ new Set();
|
|
528
|
+
aborts = /* @__PURE__ */ new Map();
|
|
529
|
+
seq = 0;
|
|
530
|
+
/** Round 41: every running job of a kind, in start order (a later one never hides an earlier). */
|
|
531
|
+
running = /* @__PURE__ */ new Map();
|
|
532
|
+
printed = /* @__PURE__ */ new Map();
|
|
533
|
+
metas = /* @__PURE__ */ new Map();
|
|
534
|
+
listeners = /* @__PURE__ */ new Set();
|
|
535
|
+
ends = /* @__PURE__ */ new Map();
|
|
536
|
+
constructor(publish, now = () => /* @__PURE__ */ new Date()) {
|
|
537
|
+
this.publish = publish;
|
|
538
|
+
this.now = now;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* A running job of a kind, if any: the earliest still running (one scan at a time: a second
|
|
542
|
+
* ask gets 409).
|
|
543
|
+
*/
|
|
544
|
+
runningOf(kind) {
|
|
545
|
+
for (const id of this.running.get(kind) ?? []) {
|
|
546
|
+
const j = this.jobs.get(id);
|
|
547
|
+
if (j?.state === "running")
|
|
548
|
+
return j;
|
|
549
|
+
}
|
|
550
|
+
return void 0;
|
|
551
|
+
}
|
|
552
|
+
get(id) {
|
|
553
|
+
return this.jobs.get(id);
|
|
554
|
+
}
|
|
555
|
+
/** Every job kept, newest first (ADR 0187). */
|
|
556
|
+
list() {
|
|
557
|
+
return [...this.jobs.values()].reverse();
|
|
558
|
+
}
|
|
559
|
+
/** What a job belongs to, as it was started. */
|
|
560
|
+
metaOf(id) {
|
|
561
|
+
return this.metas.get(id);
|
|
562
|
+
}
|
|
563
|
+
/** A job's printed lines from a line on (or its last `max`), and how many it printed. */
|
|
564
|
+
linesOf(id, from, max = JOB_LINES) {
|
|
565
|
+
const p = this.printed.get(id);
|
|
566
|
+
if (!p)
|
|
567
|
+
return void 0;
|
|
568
|
+
const total = p.from + p.lines.length;
|
|
569
|
+
const start = from === void 0 ? Math.max(total - max, p.from) : Math.max(Math.min(from, total), p.from);
|
|
570
|
+
return { from: start, lines: p.lines.slice(start - p.from, start - p.from + max), total };
|
|
571
|
+
}
|
|
572
|
+
/** Hear each job's new lines and changes of state. */
|
|
573
|
+
subscribe(f) {
|
|
574
|
+
this.listeners.add(f);
|
|
575
|
+
return () => this.listeners.delete(f);
|
|
576
|
+
}
|
|
577
|
+
tell(c) {
|
|
578
|
+
for (const f of this.listeners) {
|
|
579
|
+
try {
|
|
580
|
+
f(c);
|
|
581
|
+
} catch {
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
print(job, text) {
|
|
586
|
+
const p = this.printed.get(job.id);
|
|
587
|
+
if (!p)
|
|
588
|
+
return;
|
|
589
|
+
const lines = String(text).split(/\r?\n/);
|
|
590
|
+
const at = p.from + p.lines.length;
|
|
591
|
+
p.lines.push(...lines);
|
|
592
|
+
if (p.lines.length > JOB_LINES) {
|
|
593
|
+
const drop = p.lines.length - JOB_LINES;
|
|
594
|
+
p.lines.splice(0, drop);
|
|
595
|
+
p.from += drop;
|
|
596
|
+
}
|
|
597
|
+
this.tell({ type: "lines", job, at, lines });
|
|
598
|
+
}
|
|
599
|
+
/** Finished jobs past JOBS_KEPT go, oldest first; running ones stay. */
|
|
600
|
+
forget() {
|
|
601
|
+
let over = this.jobs.size - JOBS_KEPT;
|
|
602
|
+
if (over <= 0)
|
|
603
|
+
return;
|
|
604
|
+
for (const [id, j] of this.jobs) {
|
|
605
|
+
if (over <= 0)
|
|
606
|
+
break;
|
|
607
|
+
if (j.state === "running" || j.state === "queued")
|
|
608
|
+
continue;
|
|
609
|
+
this.jobs.delete(id);
|
|
610
|
+
this.printed.delete(id);
|
|
611
|
+
this.metas.delete(id);
|
|
612
|
+
this.cancelledIds.delete(id);
|
|
613
|
+
over--;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
start(kind, work, o = {}) {
|
|
617
|
+
const id = `job-${++this.seq}`;
|
|
618
|
+
const job = {
|
|
619
|
+
id,
|
|
620
|
+
kind,
|
|
621
|
+
state: "running",
|
|
622
|
+
progress: { done: 0, total: 0, message: "Starting" },
|
|
623
|
+
...o.title ? { title: o.title } : {},
|
|
624
|
+
startedAt: this.now().toISOString(),
|
|
625
|
+
errors: []
|
|
626
|
+
};
|
|
627
|
+
this.jobs.set(id, job);
|
|
628
|
+
this.printed.set(id, { from: 0, lines: [] });
|
|
629
|
+
if (o.meta)
|
|
630
|
+
this.metas.set(id, { ...o.meta });
|
|
631
|
+
this.forget();
|
|
632
|
+
const ofKind = this.running.get(kind) ?? /* @__PURE__ */ new Set();
|
|
633
|
+
ofKind.add(id);
|
|
634
|
+
this.running.set(kind, ofKind);
|
|
635
|
+
const abort = new AbortController();
|
|
636
|
+
this.aborts.set(id, abort);
|
|
637
|
+
const cancelled = this.cancelledIds;
|
|
638
|
+
const line = (text) => this.print(job, text);
|
|
639
|
+
const control = {
|
|
640
|
+
progress: (done, total, message) => {
|
|
641
|
+
job.progress = { done, total, message };
|
|
642
|
+
this.publish({ type: "job.progress", jobId: id, done, total, message });
|
|
643
|
+
this.tell({ type: "state", job });
|
|
644
|
+
},
|
|
645
|
+
line,
|
|
646
|
+
get cancelled() {
|
|
647
|
+
return cancelled.has(id);
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
this.tell({ type: "state", job });
|
|
651
|
+
void (async () => {
|
|
652
|
+
try {
|
|
653
|
+
const out = await withPrinter(line, () => withSignal(abort.signal, () => work(control)));
|
|
654
|
+
if (out?.result)
|
|
655
|
+
job.result = out.result;
|
|
656
|
+
if (out?.errors?.length)
|
|
657
|
+
job.errors.push(...out.errors);
|
|
658
|
+
job.state = this.cancelledIds.has(id) ? "cancelled" : job.errors.length ? "failed" : "done";
|
|
659
|
+
} catch (e) {
|
|
660
|
+
if (this.cancelledIds.has(id))
|
|
661
|
+
job.state = "cancelled";
|
|
662
|
+
else {
|
|
663
|
+
job.errors.push(e instanceof Error ? e.message : String(e));
|
|
664
|
+
job.state = "failed";
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
this.aborts.delete(id);
|
|
668
|
+
const p = this.printed.get(id);
|
|
669
|
+
if (p && p.from + p.lines.length === 0) {
|
|
670
|
+
const said = job.result?.lines;
|
|
671
|
+
const end = [
|
|
672
|
+
...Array.isArray(said) ? said.filter((l) => typeof l === "string") : [],
|
|
673
|
+
...job.errors.filter((e) => !(Array.isArray(said) && said.includes(e)))
|
|
674
|
+
];
|
|
675
|
+
if (end.length)
|
|
676
|
+
line(end.join("\n"));
|
|
677
|
+
}
|
|
678
|
+
job.finishedAt = this.now().toISOString();
|
|
679
|
+
ofKind.delete(id);
|
|
680
|
+
if (!ofKind.size && this.running.get(kind) === ofKind)
|
|
681
|
+
this.running.delete(kind);
|
|
682
|
+
this.publish({ type: "job.done", jobId: id, state: job.state });
|
|
683
|
+
this.tell({ type: "state", job });
|
|
684
|
+
this.ends.get(id)?.();
|
|
685
|
+
this.ends.delete(id);
|
|
686
|
+
})();
|
|
687
|
+
return job;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Run work the caller waits for as a job (ADR 0187): the route keeps its answer, and the
|
|
691
|
+
* Console shows what it printed. Resolves with the work's value, or throws its error.
|
|
692
|
+
*/
|
|
693
|
+
track(kind, work, o = {}) {
|
|
694
|
+
return new Promise((resolve2, reject) => {
|
|
695
|
+
let value;
|
|
696
|
+
let failed;
|
|
697
|
+
const job = this.start(kind, async (c) => {
|
|
698
|
+
try {
|
|
699
|
+
value = await work(c);
|
|
700
|
+
} catch (e) {
|
|
701
|
+
failed = { e };
|
|
702
|
+
throw e;
|
|
703
|
+
}
|
|
704
|
+
}, o);
|
|
705
|
+
this.ends.set(job.id, () => failed ? reject(failed.e) : resolve2(value));
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
/** Ask a running job to stop; false when it already finished. */
|
|
709
|
+
cancel(id) {
|
|
710
|
+
const j = this.jobs.get(id);
|
|
711
|
+
if (!j || j.state !== "running")
|
|
712
|
+
return false;
|
|
713
|
+
this.cancelledIds.add(id);
|
|
714
|
+
this.aborts.get(id)?.abort();
|
|
715
|
+
return true;
|
|
716
|
+
}
|
|
717
|
+
/** Wait for a job to finish (tests and the CLI). */
|
|
718
|
+
async settle(id, timeoutMs = 6e4) {
|
|
719
|
+
const start = Date.now();
|
|
720
|
+
for (; ; ) {
|
|
721
|
+
const j = this.jobs.get(id);
|
|
722
|
+
if (!j)
|
|
723
|
+
throw new Error(`No job ${id}`);
|
|
724
|
+
if (j.state !== "running" && j.state !== "queued")
|
|
725
|
+
return j;
|
|
726
|
+
if (Date.now() - start > timeoutMs)
|
|
727
|
+
throw new Error(`Job ${id} did not finish`);
|
|
728
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
|
|
552
733
|
// packages/server/dist/static.js
|
|
553
734
|
import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
554
735
|
import { extname, join as join2, normalize, resolve, sep } from "node:path";
|
|
@@ -580,7 +761,7 @@ function appCsp(port, embed) {
|
|
|
580
761
|
].join("; ");
|
|
581
762
|
}
|
|
582
763
|
var escapeAttr = (s) => s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
583
|
-
async function staticFile(givenDir, path, token) {
|
|
764
|
+
async function staticFile(givenDir, path, token, pageKey) {
|
|
584
765
|
const dir = resolve(givenDir);
|
|
585
766
|
let rel;
|
|
586
767
|
try {
|
|
@@ -600,7 +781,12 @@ async function staticFile(givenDir, path, token) {
|
|
|
600
781
|
const ext = extname(target).toLowerCase();
|
|
601
782
|
const type = TYPES[ext] ?? "application/octet-stream";
|
|
602
783
|
if (ext === ".html") {
|
|
603
|
-
const
|
|
784
|
+
const tokenMeta = `<meta name="atticus-token" content="${escapeAttr(token)}" />`;
|
|
785
|
+
const keyMeta = pageKey === void 0 ? "" : `<meta name="atticus-page-key" content="${escapeAttr(pageKey)}" />`;
|
|
786
|
+
let html = (await readFile2(target, "utf8")).replace(/<meta name="atticus-token" content="[^"]*"\s*\/?>/, () => tokenMeta);
|
|
787
|
+
if (keyMeta)
|
|
788
|
+
html = /<meta name="atticus-page-key" content="[^"]*"\s*\/?>/.test(html) ? html.replace(/<meta name="atticus-page-key" content="[^"]*"\s*\/?>/, () => keyMeta) : html.replace(tokenMeta, () => `${tokenMeta}
|
|
789
|
+
${keyMeta}`);
|
|
604
790
|
return { status: 200, type, body: html, cache: "no-store" };
|
|
605
791
|
}
|
|
606
792
|
return {
|
|
@@ -612,12 +798,121 @@ async function staticFile(givenDir, path, token) {
|
|
|
612
798
|
};
|
|
613
799
|
}
|
|
614
800
|
|
|
801
|
+
// packages/server/dist/confirm.js
|
|
802
|
+
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
803
|
+
var CONFIRM_TTL_MS = 12e4;
|
|
804
|
+
var MAX_OPEN = 256;
|
|
805
|
+
var Confirmations = class {
|
|
806
|
+
now;
|
|
807
|
+
open = /* @__PURE__ */ new Map();
|
|
808
|
+
constructor(now = () => Date.now()) {
|
|
809
|
+
this.now = now;
|
|
810
|
+
}
|
|
811
|
+
issue(write, target) {
|
|
812
|
+
const t = this.now();
|
|
813
|
+
for (const [k, v] of this.open)
|
|
814
|
+
if (v.until < t)
|
|
815
|
+
this.open.delete(k);
|
|
816
|
+
while (this.open.size >= MAX_OPEN)
|
|
817
|
+
this.open.delete(this.open.keys().next().value);
|
|
818
|
+
const confirmation = randomBytes(32).toString("base64url");
|
|
819
|
+
const until = t + CONFIRM_TTL_MS;
|
|
820
|
+
this.open.set(confirmation, { write, target, until });
|
|
821
|
+
return { confirmation, write, target, expiresAt: new Date(until).toISOString() };
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Whether `given` confirms this write of this target now. It is spent whatever the answer, so a
|
|
825
|
+
* confirmation is never tried twice: a replay, another target or another write is refused.
|
|
826
|
+
*/
|
|
827
|
+
take(write, target, given) {
|
|
828
|
+
if (typeof given !== "string" || !given)
|
|
829
|
+
return false;
|
|
830
|
+
const c = this.open.get(given);
|
|
831
|
+
if (!c)
|
|
832
|
+
return false;
|
|
833
|
+
this.open.delete(given);
|
|
834
|
+
return c.write === write && c.target === target && this.now() <= c.until;
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
function sameSecret(a, b) {
|
|
838
|
+
const x = Buffer.from(a);
|
|
839
|
+
const y = Buffer.from(b);
|
|
840
|
+
return x.length === y.length && timingSafeEqual(x, y);
|
|
841
|
+
}
|
|
842
|
+
var WITHOUT_THE_APP = {
|
|
843
|
+
handoff: {
|
|
844
|
+
what: "Raising a hand-off opens a PR",
|
|
845
|
+
cli: "atticus change handoff <change> --approve"
|
|
846
|
+
},
|
|
847
|
+
"release-prs": {
|
|
848
|
+
what: "Raising the release PRs pushes the change branch and opens PRs",
|
|
849
|
+
cli: "atticus change release-prs <change> --approve"
|
|
850
|
+
},
|
|
851
|
+
merge: { what: "Merging a ready PR", cli: "atticus change sync <change> --approve" },
|
|
852
|
+
"task-pr": {
|
|
853
|
+
what: "Raising a task's PR pushes its branch and opens a PR",
|
|
854
|
+
cli: "atticus task run <change> <task> --level pr --approve"
|
|
855
|
+
},
|
|
856
|
+
"digest-send": {
|
|
857
|
+
what: "Sending the digest posts a message",
|
|
858
|
+
cli: "atticus digest --send"
|
|
859
|
+
},
|
|
860
|
+
propose: {
|
|
861
|
+
what: "Propose for review pushes a branch and opens a PR",
|
|
862
|
+
cli: "git commit, push and open the PR yourself"
|
|
863
|
+
},
|
|
864
|
+
"step-run": {
|
|
865
|
+
what: "Running a step with a team's tool acts on their systems",
|
|
866
|
+
cli: "atticus todo run <step> --with <executor> --approve <you> --inputs <sha-256>"
|
|
867
|
+
},
|
|
868
|
+
"ai-model": {
|
|
869
|
+
what: "Changing where runtime.yaml sends the model's key (its provider, keyEnv or address)",
|
|
870
|
+
cli: "edit runtime.yaml yourself and propose it for review"
|
|
871
|
+
},
|
|
872
|
+
// Review round 50: committing them doesn't stand for the person's yes (the assistant can
|
|
873
|
+
// commit); the address the person last confirmed does (kept outside the metarepo).
|
|
874
|
+
"ai-test": {
|
|
875
|
+
what: "Testing the model settings sends the key to an address you haven't confirmed",
|
|
876
|
+
cli: "a step in model mode yourself"
|
|
877
|
+
},
|
|
878
|
+
// ADR 0191: the plan's work items written to a live tracker, and an owner question sent.
|
|
879
|
+
"work-items": {
|
|
880
|
+
what: "Putting the plan's stories and tasks in the work tracker writes work items",
|
|
881
|
+
cli: "atticus ado sync <change> --approve <you>"
|
|
882
|
+
},
|
|
883
|
+
"owner-ask": {
|
|
884
|
+
what: "Sending an owner question posts a message",
|
|
885
|
+
cli: "copy the question and ask the owner yourself"
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
function needsConfirmation(write) {
|
|
889
|
+
const w = WITHOUT_THE_APP[write];
|
|
890
|
+
return new HttpError(403, "This needs a person's confirmation", `${w.what}, which a person confirms: click it in the Atticus app, or run ${w.cli} in a terminal. The session token alone (atticus ui --show-token, for assistants and scripts) never approves a write to a shared system (ADR 0186).`, { confirm: write });
|
|
891
|
+
}
|
|
892
|
+
function requireConfirmation(c, write, target, given) {
|
|
893
|
+
if (!c.take(write, target, given))
|
|
894
|
+
throw needsConfirmation(write);
|
|
895
|
+
}
|
|
896
|
+
|
|
615
897
|
// packages/server/dist/watch.js
|
|
616
898
|
import { statSync, watch } from "node:fs";
|
|
617
899
|
import { join as join3, relative, sep as sep2 } from "node:path";
|
|
618
900
|
var SKIP = /* @__PURE__ */ new Set([".git", "node_modules", ".index", "workspace", "logs", ".vitest-cache"]);
|
|
619
|
-
var TEMP = /(~|\.swp|\.swx|\.tmp|\.crdownload|\.part)$/i;
|
|
901
|
+
var TEMP = /(~|\.swp|\.swx|\.tmp|\.crdownload|\.part|(^|\/)\.doctor-\d+)$/i;
|
|
620
902
|
var posix = (p) => p.split(sep2).join("/");
|
|
903
|
+
function onlyRead(abs, seen, since) {
|
|
904
|
+
let s;
|
|
905
|
+
try {
|
|
906
|
+
s = statSync(abs);
|
|
907
|
+
} catch {
|
|
908
|
+
seen.delete(abs);
|
|
909
|
+
return false;
|
|
910
|
+
}
|
|
911
|
+
const now = `${s.size}:${s.mtimeMs}:${s.ctimeMs}`;
|
|
912
|
+
const was = seen.get(abs);
|
|
913
|
+
seen.set(abs, now);
|
|
914
|
+
return was !== void 0 ? was === now : Math.max(s.mtimeMs, s.ctimeMs) < since;
|
|
915
|
+
}
|
|
621
916
|
var isDir = (p) => {
|
|
622
917
|
try {
|
|
623
918
|
return statSync(p).isDirectory();
|
|
@@ -640,6 +935,8 @@ function watchMetarepo(o) {
|
|
|
640
935
|
};
|
|
641
936
|
const problems = [];
|
|
642
937
|
const pending = /* @__PURE__ */ new Set();
|
|
938
|
+
const stamps = /* @__PURE__ */ new Map();
|
|
939
|
+
const since = Date.now();
|
|
643
940
|
let timer;
|
|
644
941
|
let first = 0;
|
|
645
942
|
let closed = false;
|
|
@@ -685,17 +982,39 @@ function watchMetarepo(o) {
|
|
|
685
982
|
const unique = [...new Set(all)].sort();
|
|
686
983
|
return unique.filter((d) => !unique.some((p) => p !== d && d.startsWith(p + sep2)));
|
|
687
984
|
};
|
|
985
|
+
const logsDir = join3(root, ".atticus", "logs");
|
|
986
|
+
const runLogDirs = [join3(logsDir, "running"), join3(logsDir, "runs")];
|
|
987
|
+
const runLogDelay = o.runLogDelayMs ?? 200;
|
|
988
|
+
let runLogTimer;
|
|
989
|
+
let runLogLast = 0;
|
|
990
|
+
const runLogChanged = () => {
|
|
991
|
+
if (runLogTimer || !o.onRunLog)
|
|
992
|
+
return;
|
|
993
|
+
runLogTimer = setTimeout(() => {
|
|
994
|
+
runLogTimer = void 0;
|
|
995
|
+
runLogLast = Date.now();
|
|
996
|
+
if (!closed)
|
|
997
|
+
o.onRunLog?.();
|
|
998
|
+
}, Math.max(runLogLast + runLogDelay - Date.now(), 0));
|
|
999
|
+
};
|
|
688
1000
|
const follow = (dir, recursive) => {
|
|
689
1001
|
if (closed || watchers.has(dir) || !isDir(dir))
|
|
690
1002
|
return;
|
|
691
1003
|
try {
|
|
692
|
-
const w = watch(dir, { recursive }, (
|
|
1004
|
+
const w = watch(dir, { recursive }, (event, name) => {
|
|
1005
|
+
if (dir === logsDir)
|
|
1006
|
+
return attach();
|
|
1007
|
+
if (runLogDirs.includes(dir))
|
|
1008
|
+
return runLogChanged();
|
|
693
1009
|
if (!recursive && name) {
|
|
694
1010
|
attach();
|
|
695
1011
|
if (watchers.has(join3(dir, String(name))))
|
|
696
1012
|
return;
|
|
697
1013
|
}
|
|
698
|
-
|
|
1014
|
+
const abs = name ? join3(dir, String(name)) : dir;
|
|
1015
|
+
if (event === "change" && process.platform === "win32" && onlyRead(abs, stamps, since))
|
|
1016
|
+
return;
|
|
1017
|
+
note(abs);
|
|
699
1018
|
});
|
|
700
1019
|
w.on("error", (e) => {
|
|
701
1020
|
w.close();
|
|
@@ -730,16 +1049,22 @@ function watchMetarepo(o) {
|
|
|
730
1049
|
follow(join3(root, ".atticus"), false);
|
|
731
1050
|
for (const d of folders())
|
|
732
1051
|
follow(d, true);
|
|
1052
|
+
if (o.onRunLog) {
|
|
1053
|
+
follow(logsDir, false);
|
|
1054
|
+
for (const d of runLogDirs)
|
|
1055
|
+
follow(d, false);
|
|
1056
|
+
}
|
|
733
1057
|
};
|
|
734
1058
|
attach();
|
|
735
1059
|
return {
|
|
736
1060
|
get following() {
|
|
737
|
-
return [...watchers.keys()].filter((d) => d !== root && d !== join3(root, ".atticus")).map((d) => posix(relative(root, d))).sort();
|
|
1061
|
+
return [...watchers.keys()].filter((d) => d !== root && d !== join3(root, ".atticus") && d !== logsDir && !runLogDirs.includes(d)).map((d) => posix(relative(root, d))).sort();
|
|
738
1062
|
},
|
|
739
1063
|
problems,
|
|
740
1064
|
close() {
|
|
741
1065
|
closed = true;
|
|
742
1066
|
clearTimeout(timer);
|
|
1067
|
+
clearTimeout(runLogTimer);
|
|
743
1068
|
for (const w of watchers.values())
|
|
744
1069
|
w.close();
|
|
745
1070
|
watchers.clear();
|
|
@@ -863,9 +1188,27 @@ function upgrade(req, sock, onClose) {
|
|
|
863
1188
|
}
|
|
864
1189
|
|
|
865
1190
|
// packages/server/dist/server.js
|
|
1191
|
+
var JOB_KINDS = {
|
|
1192
|
+
scan: true,
|
|
1193
|
+
sync: true,
|
|
1194
|
+
reconcile: true,
|
|
1195
|
+
index: true,
|
|
1196
|
+
intake: true,
|
|
1197
|
+
step: true,
|
|
1198
|
+
local: true,
|
|
1199
|
+
work: true
|
|
1200
|
+
};
|
|
866
1201
|
var EventHub = class {
|
|
1202
|
+
root;
|
|
867
1203
|
sockets = /* @__PURE__ */ new Set();
|
|
868
1204
|
listeners = /* @__PURE__ */ new Set();
|
|
1205
|
+
/**
|
|
1206
|
+
* `root`: each file.changed event is published saying whether it can change the catalog
|
|
1207
|
+
* (`catalog`, beta.23 review), by the layout the org pack names, so a page needn't guess it.
|
|
1208
|
+
*/
|
|
1209
|
+
constructor(root) {
|
|
1210
|
+
this.root = root;
|
|
1211
|
+
}
|
|
869
1212
|
/** Hear every event in this process too (ADR 0119: a reader that keeps files in memory). */
|
|
870
1213
|
listen(fn) {
|
|
871
1214
|
this.listeners.add(fn);
|
|
@@ -880,7 +1223,16 @@ var EventHub = class {
|
|
|
880
1223
|
get size() {
|
|
881
1224
|
return this.sockets.size;
|
|
882
1225
|
}
|
|
883
|
-
publish(
|
|
1226
|
+
publish(given) {
|
|
1227
|
+
let e = given;
|
|
1228
|
+
if (this.root !== void 0 && e.type === "file.changed" && typeof e.path === "string" && typeof e.catalog !== "boolean") {
|
|
1229
|
+
let catalog = true;
|
|
1230
|
+
try {
|
|
1231
|
+
catalog = catalogMayHaveChangedAt(this.root, e.path);
|
|
1232
|
+
} catch {
|
|
1233
|
+
}
|
|
1234
|
+
e = { ...e, catalog };
|
|
1235
|
+
}
|
|
884
1236
|
for (const fn of this.listeners)
|
|
885
1237
|
fn(e);
|
|
886
1238
|
const text = JSON.stringify(e);
|
|
@@ -892,12 +1244,24 @@ var EventHub = class {
|
|
|
892
1244
|
s.close();
|
|
893
1245
|
}
|
|
894
1246
|
};
|
|
1247
|
+
var Signal = class {
|
|
1248
|
+
fs = /* @__PURE__ */ new Set();
|
|
1249
|
+
subscribe(f) {
|
|
1250
|
+
this.fs.add(f);
|
|
1251
|
+
return () => this.fs.delete(f);
|
|
1252
|
+
}
|
|
1253
|
+
emit() {
|
|
1254
|
+
for (const f of this.fs) {
|
|
1255
|
+
try {
|
|
1256
|
+
f();
|
|
1257
|
+
} catch {
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
895
1262
|
var MAX_BODY = 4 * 1024 * 1024;
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
const y = Buffer.from(b);
|
|
899
|
-
return x.length === y.length && timingSafeEqual(x, y);
|
|
900
|
-
}
|
|
1263
|
+
var sameToken = sameSecret;
|
|
1264
|
+
var STRONG = /^[A-Za-z0-9_-]{32,}$/;
|
|
901
1265
|
async function readBody(req, max = MAX_BODY) {
|
|
902
1266
|
const chunks = [];
|
|
903
1267
|
let size = 0;
|
|
@@ -939,10 +1303,15 @@ async function startServer(o) {
|
|
|
939
1303
|
const host = o.host ?? "127.0.0.1";
|
|
940
1304
|
if (host !== "127.0.0.1")
|
|
941
1305
|
throw new Error(`Atticus only listens on 127.0.0.1 (asked for ${host}).`);
|
|
942
|
-
const token = o.token &&
|
|
943
|
-
const
|
|
1306
|
+
const token = o.token && STRONG.test(o.token) ? o.token : randomBytes2(32).toString("base64url");
|
|
1307
|
+
const pageKey = o.pageKey && STRONG.test(o.pageKey) && o.pageKey !== token ? o.pageKey : randomBytes2(32).toString("base64url");
|
|
1308
|
+
const events = new EventHub(o.root);
|
|
1309
|
+
let writing = 0;
|
|
944
1310
|
const jobs = new JobManager((e) => events.publish(e));
|
|
1311
|
+
const confirmations = new Confirmations();
|
|
945
1312
|
const person = o.user ? { handle: o.user, source: "given" } : await gitUser(o.root);
|
|
1313
|
+
const runLogs = new Signal();
|
|
1314
|
+
const onClose = /* @__PURE__ */ new Set();
|
|
946
1315
|
const ctx = {
|
|
947
1316
|
root: o.root,
|
|
948
1317
|
user: person.handle,
|
|
@@ -950,9 +1319,19 @@ async function startServer(o) {
|
|
|
950
1319
|
version: o.version ?? "0.0.0",
|
|
951
1320
|
full: o.full === true,
|
|
952
1321
|
events,
|
|
953
|
-
jobs
|
|
1322
|
+
jobs,
|
|
1323
|
+
confirmations,
|
|
1324
|
+
runLogs,
|
|
1325
|
+
onClose
|
|
954
1326
|
};
|
|
955
|
-
const router = apiRoutes(new Router(), ctx).add("
|
|
1327
|
+
const router = apiRoutes(new Router(), ctx).add("POST", "/api/confirmations", ({ body }) => {
|
|
1328
|
+
const b = api_exports.ConfirmationRequest.safeParse(body ?? {});
|
|
1329
|
+
if (!b.success)
|
|
1330
|
+
throw badRequest(`Say which write and what for: { write: ${api_exports.CONFIRMED_WRITES.join(" | ")}, target }.`);
|
|
1331
|
+
if (!b.data.pageKey || !sameSecret(b.data.pageKey, pageKey))
|
|
1332
|
+
throw new HttpError(403, "Only the Atticus app asks for a confirmation", "A write to a shared system is a person's: they click it in the Atticus app, or run its command with --approve in a terminal. The session token alone (atticus ui --show-token) can't confirm one (ADR 0186).");
|
|
1333
|
+
return { status: 201, body: confirmations.issue(b.data.write, b.data.target) };
|
|
1334
|
+
}).add("GET", "/api/jobs/{jobId}", ({ params }) => {
|
|
956
1335
|
const j = jobs.get(params.jobId);
|
|
957
1336
|
if (!j)
|
|
958
1337
|
throw notFound(`There is no job ${params.jobId}.`);
|
|
@@ -980,7 +1359,15 @@ async function startServer(o) {
|
|
|
980
1359
|
};
|
|
981
1360
|
const server = createServer(async (req, res) => {
|
|
982
1361
|
const t0 = Date.now();
|
|
1362
|
+
let writes = req.method !== "GET" && req.method !== "HEAD";
|
|
1363
|
+
if (writes)
|
|
1364
|
+
writing++;
|
|
983
1365
|
const done = (status, error) => {
|
|
1366
|
+
if (writes) {
|
|
1367
|
+
writes = false;
|
|
1368
|
+
writing--;
|
|
1369
|
+
indexFilesChanged(o.root);
|
|
1370
|
+
}
|
|
984
1371
|
const path = (req.url ?? "/").split("?")[0];
|
|
985
1372
|
if (path.startsWith("/api/"))
|
|
986
1373
|
o.onRequest?.({
|
|
@@ -998,7 +1385,7 @@ async function startServer(o) {
|
|
|
998
1385
|
throw new HttpError(403, "Requests must be addressed to this server");
|
|
999
1386
|
if (!o.staticDir || req.method !== "GET" && req.method !== "HEAD")
|
|
1000
1387
|
throw new HttpError(404, "Not found", `Nothing is served at ${url.pathname}.`);
|
|
1001
|
-
const f = await staticFile(o.staticDir, url.pathname, token);
|
|
1388
|
+
const f = await staticFile(o.staticDir, url.pathname, token, pageKey);
|
|
1002
1389
|
const { "X-Frame-Options": deny, ...rest } = HARDENING;
|
|
1003
1390
|
res.writeHead(f.status, {
|
|
1004
1391
|
...o.embed ? rest : { ...rest, "X-Frame-Options": deny },
|
|
@@ -1059,19 +1446,43 @@ Connection: close\r
|
|
|
1059
1446
|
server.listen(o.port ?? DEFAULT_PORT, host, () => resolve2());
|
|
1060
1447
|
});
|
|
1061
1448
|
port = server.address().port;
|
|
1062
|
-
const watcher = o.watch === false ? void 0 : watchMetarepo({
|
|
1449
|
+
const watcher = o.watch === false ? void 0 : watchMetarepo({
|
|
1450
|
+
root: o.root,
|
|
1451
|
+
publish: (e) => events.publish(e),
|
|
1452
|
+
onRunLog: () => runLogs.emit()
|
|
1453
|
+
});
|
|
1454
|
+
const stopHearing = events.listen((e) => {
|
|
1455
|
+
if (e.type === "file.changed" || e.type === "index.rebuilt" || e.type === "job.done")
|
|
1456
|
+
indexFilesChanged(o.root);
|
|
1457
|
+
});
|
|
1458
|
+
if (watcher)
|
|
1459
|
+
trustIndexBetweenChanges(o.root, true);
|
|
1063
1460
|
return {
|
|
1064
1461
|
url: `http://127.0.0.1:${port}`,
|
|
1065
1462
|
port,
|
|
1066
1463
|
token,
|
|
1464
|
+
pageKey,
|
|
1465
|
+
confirmations,
|
|
1067
1466
|
events,
|
|
1068
1467
|
jobs,
|
|
1069
1468
|
person,
|
|
1070
1469
|
get following() {
|
|
1071
1470
|
return watcher?.following ?? [];
|
|
1072
1471
|
},
|
|
1472
|
+
get quiet() {
|
|
1473
|
+
return writing === 0 && !Object.keys(JOB_KINDS).some((k) => jobs.runningOf(k));
|
|
1474
|
+
},
|
|
1073
1475
|
close: () => new Promise((resolve2) => {
|
|
1074
1476
|
watcher?.close();
|
|
1477
|
+
for (const f of onClose) {
|
|
1478
|
+
try {
|
|
1479
|
+
f();
|
|
1480
|
+
} catch {
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
stopHearing();
|
|
1484
|
+
trustIndexBetweenChanges(o.root, false);
|
|
1485
|
+
stopEmbedding(o.root);
|
|
1075
1486
|
events.closeAll();
|
|
1076
1487
|
server.closeAllConnections?.();
|
|
1077
1488
|
server.close(() => resolve2());
|
|
@@ -1084,6 +1495,33 @@ export {
|
|
|
1084
1495
|
badRequest,
|
|
1085
1496
|
notFound,
|
|
1086
1497
|
conflict,
|
|
1498
|
+
Router,
|
|
1499
|
+
problem,
|
|
1500
|
+
intParam,
|
|
1087
1501
|
strParam,
|
|
1502
|
+
trustIndexBetweenChanges,
|
|
1503
|
+
indexFilesChanged,
|
|
1504
|
+
stopEmbedding,
|
|
1505
|
+
apiRoutes,
|
|
1506
|
+
JOB_LINES,
|
|
1507
|
+
JOBS_KEPT,
|
|
1508
|
+
jobLine,
|
|
1509
|
+
JobManager,
|
|
1510
|
+
appCsp,
|
|
1511
|
+
staticFile,
|
|
1512
|
+
CONFIRM_TTL_MS,
|
|
1513
|
+
Confirmations,
|
|
1514
|
+
sameSecret,
|
|
1515
|
+
needsConfirmation,
|
|
1516
|
+
requireConfirmation,
|
|
1517
|
+
onlyRead,
|
|
1518
|
+
watchMetarepo,
|
|
1519
|
+
acceptKey,
|
|
1520
|
+
frame,
|
|
1521
|
+
Socket,
|
|
1522
|
+
upgrade,
|
|
1523
|
+
EventHub,
|
|
1524
|
+
Signal,
|
|
1525
|
+
HARDENING,
|
|
1088
1526
|
startServer
|
|
1089
1527
|
};
|