@maycombhq/atticus 2.0.0-beta.18 → 2.0.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +8 -4
- package/dist/{chunk-MUSJJ6CQ.js → chunk-265LWMOA.js} +16 -16
- package/dist/chunk-26WBY34Y.js +37 -0
- package/dist/{chunk-6H5JG5GL.js → chunk-26Z7OGQW.js} +63 -30
- package/dist/{chunk-4REDBQOZ.js → chunk-2D7PWSOK.js} +20 -20
- package/dist/{chunk-YPH6ZJ6R.js → chunk-2HH3UCZM.js} +4 -4
- package/dist/{chunk-RTUUX7PX.js → chunk-2HTEMYTB.js} +12 -26
- package/dist/{chunk-EHQUY26D.js → chunk-2UCRFXFZ.js} +11 -11
- package/dist/{chunk-ILDGIXNH.js → chunk-2V2ZPQQU.js} +81 -13
- package/dist/{chunk-YSEZQ6D3.js → chunk-36RY7ZXM.js} +107 -64
- package/dist/{chunk-QXFDM2FZ.js → chunk-37WE3LS2.js} +3 -3
- package/dist/{chunk-BAXM3JFQ.js → chunk-3AQ2R5NL.js} +1212 -754
- package/dist/chunk-3G6S7LAA.js +43 -0
- package/dist/{chunk-7TOAS7KI.js → chunk-3J5I7ZOU.js} +4 -4
- package/dist/{chunk-TAKAEJRD.js → chunk-3LZ6P5EP.js} +1 -1
- package/dist/chunk-3SSTNB4E.js +191 -0
- package/dist/chunk-3TD6S4TC.js +49 -0
- package/dist/{chunk-UUL6ZGMU.js → chunk-3UTYPHN3.js} +1 -1
- package/dist/{chunk-6AP2ZUUM.js → chunk-3WON4G3M.js} +2 -2
- package/dist/{chunk-AXY6LBW4.js → chunk-42EPP7OB.js} +12 -12
- package/dist/{chunk-QKMDT7VU.js → chunk-455SYIIE.js} +2 -2
- package/dist/{chunk-MFUFB3LN.js → chunk-4B6BT75O.js} +110 -20
- package/dist/{chunk-75MYLZSB.js → chunk-4CLK2RJO.js} +7 -7
- package/dist/chunk-4CYTJ5TZ.js +38 -0
- package/dist/{chunk-IH7RANGB.js → chunk-4D62IZII.js} +5 -5
- package/dist/{chunk-2QMZOCWN.js → chunk-4FOAYLI4.js} +14 -7
- package/dist/{chunk-V3UEPUHT.js → chunk-4KNOJC6J.js} +294 -215
- package/dist/{chunk-O6ILVBYB.js → chunk-4PYC2UGC.js} +1 -1
- package/dist/{chunk-EZBAS5BL.js → chunk-4SLBCEPD.js} +82 -50
- package/dist/{chunk-VIRTPODJ.js → chunk-4TKVU2I2.js} +6 -14
- package/dist/{chunk-IVCDU443.js → chunk-4WXRPQDE.js} +281 -51
- package/dist/{chunk-RMEEHH24.js → chunk-5CMPVC3N.js} +24 -24
- package/dist/chunk-5G7ILBUG.js +66 -0
- package/dist/{chunk-Z75XDWQR.js → chunk-5PV7S2ZP.js} +3 -3
- package/dist/{chunk-WWPC2AZ2.js → chunk-5QUOPNLN.js} +4 -4
- package/dist/{chunk-7OVH2L7L.js → chunk-5TDRBOAV.js} +5 -5
- package/dist/{chunk-YXUIUOQZ.js → chunk-5WERBKLE.js} +199 -63
- package/dist/{chunk-6WNNXEG6.js → chunk-62DLJSLV.js} +8 -8
- package/dist/{chunk-KCQS52TH.js → chunk-64AADMTW.js} +99 -25
- package/dist/{chunk-KLRUXRPN.js → chunk-67BP7HXL.js} +17 -17
- package/dist/chunk-6DQYZU2W.js +379 -0
- package/dist/{chunk-RONDYDMQ.js → chunk-6EXDI5GI.js} +51 -34
- package/dist/chunk-6FNAKCET.js +38 -0
- package/dist/{chunk-6SNEA73E.js → chunk-75ASLHBT.js} +21 -15
- package/dist/{chunk-EFT4KM6K.js → chunk-75ZOZFGH.js} +18 -18
- package/dist/{chunk-B3KW7EQW.js → chunk-77O633L5.js} +12 -12
- package/dist/{chunk-TLDL2ZZI.js → chunk-7AB6OWTV.js} +3 -3
- package/dist/{chunk-R5YXY6NT.js → chunk-7CZHUZBL.js} +25 -25
- package/dist/{chunk-F4D4G2A6.js → chunk-7FHNFCHK.js} +306 -125
- package/dist/{chunk-CC5RNYZF.js → chunk-7FUIVIBG.js} +19 -9
- package/dist/{chunk-UBTOSSNK.js → chunk-7QPCGTPS.js} +21 -21
- package/dist/{chunk-CDLTRJ4N.js → chunk-A2G72UI4.js} +7 -7
- package/dist/{chunk-YGSOQ5LX.js → chunk-AE4P57KK.js} +23 -17
- package/dist/{chunk-PGQL5YGH.js → chunk-AHW3RY3X.js} +7 -7
- package/dist/chunk-AM6FP6JW.js +43 -0
- package/dist/{chunk-DYNC6BAQ.js → chunk-AOCWFA7T.js} +93 -10
- package/dist/{chunk-CYX36GKZ.js → chunk-API5TOUB.js} +1 -1
- package/dist/{chunk-BJ5T3KDF.js → chunk-AZDITBCT.js} +3 -3
- package/dist/{chunk-U6GZSUMC.js → chunk-BA2HUMDN.js} +25 -3
- package/dist/chunk-BA3U7ALS.js +99 -0
- package/dist/{chunk-63565QTF.js → chunk-BC6KKZ67.js} +5 -5
- package/dist/{chunk-XO5RQKNM.js → chunk-BEPCKDCP.js} +1843 -577
- package/dist/{chunk-KUH62AQ3.js → chunk-BPPU3PW7.js} +4 -4
- package/dist/{chunk-52ULYRV4.js → chunk-BVWWPBKD.js} +18 -18
- package/dist/{chunk-R2FGEBIU.js → chunk-BXZ4PKIT.js} +13 -11
- package/dist/{chunk-4BU26GFB.js → chunk-C7CEK3KW.js} +4 -4
- package/dist/chunk-CFH3QH26.js +29 -0
- package/dist/chunk-CG6CULP6.js +170 -0
- package/dist/chunk-CLD4RVTA.js +45 -0
- package/dist/{chunk-BU543ZEC.js → chunk-CNPY4NTZ.js} +13 -13
- package/dist/{chunk-PLBIWEPV.js → chunk-CNU5Q2D5.js} +32 -31
- package/dist/{chunk-JTYYEYRR.js → chunk-COYN3UAN.js} +124 -21
- package/dist/{chunk-TNCROWPQ.js → chunk-CPK7QSBG.js} +10 -10
- package/dist/{chunk-43E6XX67.js → chunk-D2WSW4GU.js} +1 -1
- package/dist/{chunk-SHEUEHKC.js → chunk-D57MFJPP.js} +3 -3
- package/dist/chunk-D5KV5PSK.js +45 -0
- package/dist/chunk-D5MASS4I.js +48 -0
- package/dist/{chunk-TQYBXDVH.js → chunk-DCWN3HFV.js} +1 -1
- package/dist/{chunk-FF4IGX4Z.js → chunk-DDJPM5YX.js} +2 -2
- package/dist/chunk-DN4A2Q2O.js +57 -0
- package/dist/{chunk-4ZCFCIEL.js → chunk-DUPZPDCJ.js} +52 -16
- package/dist/{chunk-CUJ5TIEB.js → chunk-E2VXBSIR.js} +4 -4
- package/dist/{chunk-BX47X5DJ.js → chunk-E57AOFYN.js} +13 -13
- package/dist/{chunk-SSTI7GAV.js → chunk-ECLXZWAG.js} +12 -12
- package/dist/{chunk-KYK3TA4Q.js → chunk-EDZ45WIR.js} +14 -14
- package/dist/chunk-EFCQSMXB.js +37 -0
- package/dist/{chunk-YC2K3FJG.js → chunk-EZIN5E5B.js} +8 -8
- package/dist/{chunk-MIZNACDI.js → chunk-F6H2RJ3N.js} +1 -1
- package/dist/{chunk-EMZVHDJP.js → chunk-FAJDKNSD.js} +7 -3
- package/dist/chunk-FGAGWYZB.js +47 -0
- package/dist/{chunk-KBGQ3IAM.js → chunk-FLVZFTLQ.js} +18 -18
- package/dist/{chunk-2NNXLH53.js → chunk-FQ6WH6PB.js} +22 -7
- package/dist/{chunk-QWSLMVHI.js → chunk-FRHD22WM.js} +61 -23
- package/dist/{chunk-5MEN4SM5.js → chunk-FVMPFCDS.js} +4 -4
- package/dist/{chunk-KLRZKW7Y.js → chunk-FY3QIRTL.js} +3 -3
- package/dist/{chunk-B3SWPNJF.js → chunk-FYBF5MB2.js} +13 -11
- package/dist/{chunk-CVZCW3NI.js → chunk-G5YJBNDZ.js} +14 -5
- package/dist/{chunk-U6EPS5PF.js → chunk-G6IQYM25.js} +5 -5
- package/dist/chunk-G6X4YL4D.js +161 -0
- package/dist/{chunk-DOSX3MRW.js → chunk-GC2VK3JT.js} +25 -25
- package/dist/{chunk-EEWBTFRP.js → chunk-GCS3FZOB.js} +27 -3
- package/dist/{chunk-6H6OPNEP.js → chunk-GDZB57IU.js} +5 -5
- package/dist/chunk-GIFMBCTW.js +221 -0
- package/dist/{chunk-X5WYPIH3.js → chunk-GK4PYVEC.js} +18 -8
- package/dist/{chunk-VBSJ5NRB.js → chunk-GNWAOVFQ.js} +5 -5
- package/dist/{chunk-TXFDQRBL.js → chunk-GS76RXQE.js} +11 -11
- package/dist/{chunk-U3YC4RGC.js → chunk-GSGIZ2OO.js} +23 -23
- package/dist/chunk-GUYL7RMK.js +60 -0
- package/dist/{chunk-AZYBHPV4.js → chunk-GX74YWR7.js} +14 -13
- package/dist/{chunk-YY7VP7KW.js → chunk-HE3HRDNZ.js} +2 -2
- package/dist/{chunk-Z7HYYDZM.js → chunk-HGHRSF3E.js} +14 -13
- package/dist/{chunk-Q2X4IREC.js → chunk-HK3VOHIE.js} +106 -36
- package/dist/{chunk-P5JYMO7Y.js → chunk-HS4BGB4G.js} +22 -22
- package/dist/{chunk-IOW6BF3U.js → chunk-HSZMPH5T.js} +798 -141
- package/dist/{chunk-L3T33FA7.js → chunk-HWD4JPU7.js} +4 -2
- package/dist/{chunk-7NYCH5HY.js → chunk-HXXP2NTE.js} +6 -6
- package/dist/{chunk-7S7OFVIU.js → chunk-I2A3Z5AK.js} +4 -4
- package/dist/{chunk-WQSDKX7M.js → chunk-ICHDSWEY.js} +7 -7
- package/dist/chunk-IFFRGC3N.js +31 -0
- package/dist/{chunk-HMZQAIR5.js → chunk-IFHDV6KQ.js} +24 -17
- package/dist/chunk-J2O4LFVI.js +80 -0
- package/dist/chunk-J5AAZ6OJ.js +161 -0
- package/dist/{chunk-CVRWAG76.js → chunk-JAABT3DA.js} +3 -3
- package/dist/chunk-JITJP64K.js +34 -0
- package/dist/chunk-JKIGL3XQ.js +162 -0
- package/dist/chunk-JRVNXLZP.js +615 -0
- package/dist/chunk-JRXHON4E.js +41 -0
- package/dist/{chunk-XFCK5B27.js → chunk-JS6WMC3J.js} +8 -8
- package/dist/chunk-JU4QNJSR.js +62 -0
- package/dist/{chunk-IPSFMTK2.js → chunk-JYMIB5XY.js} +152 -42
- package/dist/{chunk-L336AJCZ.js → chunk-JYTIHTIK.js} +8 -6
- package/dist/{chunk-VEJYZEPC.js → chunk-K332XW7K.js} +135 -16
- package/dist/{chunk-KCF7TFOE.js → chunk-K6JB6XTX.js} +11 -11
- package/dist/{chunk-LFIIX4OV.js → chunk-KDAHXQIE.js} +46 -34
- package/dist/chunk-KYZMRSPS.js +93 -0
- package/dist/chunk-L4CESDPB.js +22 -0
- package/dist/{chunk-3LR4522O.js → chunk-LEBR5NHW.js} +14 -14
- package/dist/{chunk-US3QZU23.js → chunk-LIJJCBQI.js} +67 -7
- package/dist/{chunk-XLHL6WTI.js → chunk-LIRVU3HW.js} +16 -16
- package/dist/{chunk-BAT4CBB7.js → chunk-LN77DXBM.js} +19 -10
- package/dist/{chunk-E5FM44EJ.js → chunk-LNWEWYCM.js} +2474 -315
- package/dist/{chunk-TX4OGZKU.js → chunk-LO3BLMVG.js} +3 -3
- package/dist/{chunk-RUOGHYSK.js → chunk-LPV6T362.js} +5 -5
- package/dist/{chunk-2T5CQH4R.js → chunk-LQH4P45K.js} +1 -1
- package/dist/chunk-LU4MQVAL.js +41 -0
- package/dist/{chunk-HW4RRIJA.js → chunk-LWDNKE4X.js} +12 -10
- package/dist/chunk-M4H2UG4R.js +218 -0
- package/dist/{chunk-CANMOOE6.js → chunk-M6D2U3YM.js} +3 -3
- package/dist/{chunk-AB5E5HCN.js → chunk-MD7KUEJ3.js} +14 -272
- package/dist/{chunk-ENTAAEDK.js → chunk-MMZUN7ZO.js} +20 -20
- package/dist/{chunk-L4MHJG3I.js → chunk-MZGRDONP.js} +46 -36
- package/dist/{chunk-IYI2S6BB.js → chunk-N3RUGTGV.js} +18 -18
- package/dist/{chunk-WZRCGGXG.js → chunk-NCB6656Z.js} +7 -7
- package/dist/{chunk-SBE773JU.js → chunk-NRQ65LTQ.js} +5 -5
- package/dist/{chunk-NRPMPZWJ.js → chunk-NTAVOWYD.js} +117 -18
- package/dist/{chunk-UJBZS5I7.js → chunk-NYOABJNK.js} +36 -27
- package/dist/{chunk-LXAPJ3BL.js → chunk-O4IKAIZ2.js} +24 -20
- package/dist/{chunk-MMB2OHUY.js → chunk-ODMBPDDV.js} +48 -13
- package/dist/chunk-OKUB6RJA.js +533 -0
- package/dist/{chunk-MKFYQQ5Q.js → chunk-OMPENNWY.js} +4 -1
- package/dist/chunk-OPQZISG3.js +25 -0
- package/dist/{chunk-ROJMXG4E.js → chunk-OV57AHCG.js} +24 -24
- package/dist/{chunk-7KGXDIWV.js → chunk-OZJ3JLYI.js} +9 -8
- package/dist/{chunk-G5BYKJIM.js → chunk-P2VBXX7N.js} +11 -10
- package/dist/{chunk-YK6CSODO.js → chunk-PAINMSID.js} +4353 -1106
- package/dist/chunk-PKJAV25S.js +43 -0
- package/dist/{chunk-R5MNPIMD.js → chunk-PNQLCRSS.js} +4 -4
- package/dist/{chunk-3SMMFQED.js → chunk-PQH56YF6.js} +37 -5
- package/dist/chunk-PRTBPXYA.js +50 -0
- package/dist/{chunk-FF4ZMLSL.js → chunk-PRW3HXM3.js} +2 -2
- package/dist/chunk-PRZ7KMWL.js +42 -0
- package/dist/{chunk-IFV6MKYV.js → chunk-PTQ3ZALZ.js} +42 -4
- package/dist/{chunk-ELQSLAP6.js → chunk-PUEWDYGP.js} +2 -2
- package/dist/{chunk-F2ZCZYIK.js → chunk-Q26LDIUV.js} +12 -11
- package/dist/chunk-Q46QDDMF.js +277 -0
- package/dist/chunk-QBNWF5ZU.js +19 -0
- package/dist/{chunk-ANETFNTV.js → chunk-QE527XRY.js} +24 -21
- package/dist/{chunk-QNMLLYTN.js → chunk-QHJJMZLX.js} +397 -32
- package/dist/chunk-QJCJOMW3.js +425 -0
- package/dist/{chunk-3HOONZUE.js → chunk-QKMRFNMA.js} +15 -15
- package/dist/{chunk-7S6VJ643.js → chunk-QOOEYDNJ.js} +101 -13
- package/dist/{chunk-4YNKN4DF.js → chunk-QSIDVFB7.js} +20 -18
- package/dist/{chunk-2IT7SIJY.js → chunk-RA33EYS4.js} +19 -18
- package/dist/{chunk-P7NV3FEJ.js → chunk-RALY3E5U.js} +4 -4
- package/dist/{chunk-6NESNLVU.js → chunk-S2RY3BOD.js} +35 -21
- package/dist/chunk-SB5GRUFM.js +54 -0
- package/dist/{chunk-EUQHM2CH.js → chunk-SH27FYPF.js} +18 -18
- package/dist/chunk-T74WQQGS.js +40 -0
- package/dist/{chunk-LGDW4G73.js → chunk-TGVVUKTG.js} +2 -2
- package/dist/chunk-THN26IEF.js +48 -0
- package/dist/{chunk-ZV2VCBMQ.js → chunk-TJH2EUAZ.js} +18 -12
- package/dist/{chunk-NGT5LLSE.js → chunk-TQ4TG57V.js} +6 -6
- package/dist/{chunk-WEDXFJPG.js → chunk-TQTRWENN.js} +12 -12
- package/dist/{chunk-ZRWS54RI.js → chunk-TSM6T6GQ.js} +23 -23
- package/dist/{chunk-KET7KOVE.js → chunk-TW3KOSQK.js} +15 -7
- package/dist/{chunk-RBXDHCN7.js → chunk-TWQRPM76.js} +2 -2
- package/dist/{chunk-IO6DQCZX.js → chunk-TYD6I4CZ.js} +4 -4
- package/dist/{chunk-5NLJH6R4.js → chunk-U3NBK4EU.js} +56 -17
- package/dist/{chunk-U542BJME.js → chunk-UDXWIPCB.js} +7 -7
- package/dist/{chunk-OSB6AKF2.js → chunk-UEVZZZU2.js} +4 -4
- package/dist/{chunk-5ZV7BK22.js → chunk-UF4UHCIG.js} +2 -2
- package/dist/{chunk-PHJOOL6U.js → chunk-UFE36WJH.js} +4 -4
- package/dist/{chunk-IHRP4OYV.js → chunk-URIKUID7.js} +12 -12
- package/dist/chunk-UYLBRRFK.js +1106 -0
- package/dist/chunk-UZACEG2C.js +515 -0
- package/dist/{chunk-LR4XBH4L.js → chunk-VAMHOHUU.js} +12 -12
- package/dist/{chunk-S5PSGAQ2.js → chunk-VUVGX5L2.js} +1 -1
- package/dist/{chunk-2TG2QGKW.js → chunk-VYOCPTUB.js} +18 -16
- package/dist/{chunk-VTEDQ6GY.js → chunk-WAZEXEJH.js} +175 -3
- package/dist/{chunk-UTSFKZ72.js → chunk-WCEF7H6L.js} +3 -3
- package/dist/{chunk-DXPUYG5L.js → chunk-WEOMJHPV.js} +12 -12
- package/dist/{chunk-NFKBU2UH.js → chunk-WFU77T3A.js} +5 -5
- package/dist/chunk-WIWTJMMR.js +292 -0
- package/dist/{chunk-MRFSUAJH.js → chunk-WNTIOBOG.js} +18 -18
- package/dist/{chunk-UROTYIGJ.js → chunk-X2CUXTWU.js} +6 -6
- package/dist/chunk-X7EMBM5X.js +34 -0
- package/dist/{chunk-OO5TKEAG.js → chunk-XEQCQO66.js} +8 -8
- package/dist/{chunk-NBQO75XT.js → chunk-XG4WJHLQ.js} +17 -1
- package/dist/{chunk-ZQC7MNQB.js → chunk-XOL3GFW2.js} +101 -30
- package/dist/{chunk-GXDATVSY.js → chunk-XQ3YZ4QW.js} +22 -22
- package/dist/{chunk-GTW54D3D.js → chunk-Y6K3CJBU.js} +726 -88
- package/dist/{chunk-CQCAJI6G.js → chunk-YAH5IQAL.js} +5 -5
- package/dist/{chunk-U6TD7UOH.js → chunk-YBOVNMHC.js} +51 -14
- package/dist/{chunk-OJICVOZH.js → chunk-YF5DZCPN.js} +79 -39
- package/dist/chunk-YIGBJNH4.js +37 -0
- package/dist/{chunk-7C7OZARH.js → chunk-YJ3TBOTK.js} +25 -25
- package/dist/{chunk-HXFSM4LG.js → chunk-YKTE2RU3.js} +2 -2
- package/dist/{chunk-7IM4BVVH.js → chunk-YO2PKTXT.js} +268 -36
- package/dist/{chunk-Z3UU7XV6.js → chunk-YTTNTQOX.js} +15 -15
- package/dist/{chunk-2ZICHO3V.js → chunk-YWAKDNMH.js} +183 -33
- package/dist/{chunk-OXOSJXOI.js → chunk-YZDZOEV4.js} +4 -4
- package/dist/{chunk-MRCETHW5.js → chunk-Z3QFH7YG.js} +4 -4
- package/dist/{chunk-5KZTRD4V.js → chunk-Z6VLC5X4.js} +17 -17
- package/dist/{chunk-EDURU5DF.js → chunk-ZFQMMU5Y.js} +2 -2
- package/dist/{chunk-3GLDB4IT.js → chunk-ZKYRDV7A.js} +12 -12
- package/dist/{chunk-GBGJ6WSO.js → chunk-ZLS6PU2O.js} +3 -3
- package/dist/{chunk-JZOOX3PQ.js → chunk-ZOSD4FXV.js} +3 -3
- package/dist/chunk-ZPDDEVQX.js +47 -0
- package/dist/{chunk-2TTSX7NB.js → chunk-ZQLRCA2V.js} +7 -7
- package/dist/{chunk-ESP3RUUR.js → chunk-ZX7235KR.js} +128 -54
- package/dist/{chunk-MH4XG5XS.js → chunk-ZZFHLRQW.js} +18 -16
- package/dist/files.json +559 -439
- package/dist/packages/sdk/npm/index.js +4679 -2672
- package/dist/packages/ui/dist/assets/{elk-api-BuFBvNyV.js → elk-api-CowTnhEJ.js} +2 -2
- package/dist/packages/ui/dist/assets/index-Dw20IRhQ.css +1 -0
- package/dist/packages/ui/dist/assets/index-z2wv0d5d.js +47 -0
- package/dist/packages/ui/dist/index.html +2 -2
- package/package.json +3 -3
- package/dist/chunk-25TJC2CL.js +0 -48
- package/dist/chunk-3Q5RHGCA.js +0 -47
- package/dist/chunk-4W7FOGAB.js +0 -41
- package/dist/chunk-6AF3CVJT.js +0 -48
- package/dist/chunk-A3KEXFQS.js +0 -34
- package/dist/chunk-BAUINGGJ.js +0 -41
- package/dist/chunk-BOFUCRJX.js +0 -47
- package/dist/chunk-GGKGILIP.js +0 -54
- package/dist/chunk-IKN6C67W.js +0 -53
- package/dist/chunk-K7MYVIFK.js +0 -54
- package/dist/chunk-KHA5LVPE.js +0 -34
- package/dist/chunk-LSXGM6MB.js +0 -37
- package/dist/chunk-M54TDRM3.js +0 -29
- package/dist/chunk-M5GF4NAB.js +0 -45
- package/dist/chunk-UTZGBCXE.js +0 -38
- package/dist/chunk-UVTSMBM4.js +0 -43
- package/dist/chunk-XXE3S3OG.js +0 -44
- package/dist/chunk-YJRQCUVJ.js +0 -43
- package/dist/chunk-ZFTK4BDN.js +0 -41
- package/dist/chunk-ZMARAW37.js +0 -38
- package/dist/packages/ui/dist/assets/index-C5QnK82A.css +0 -1
- package/dist/packages/ui/dist/assets/index-CQ0a1cBg.js +0 -29
|
@@ -3,17 +3,14 @@ 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
|
-
listRuns,
|
|
8
|
-
runTranscript
|
|
9
|
-
} from "./chunk-U6GZSUMC.js";
|
|
10
6
|
import {
|
|
11
7
|
historyEntry,
|
|
12
8
|
listHistory
|
|
13
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3WON4G3M.js";
|
|
10
|
+
import "./chunk-JYTIHTIK.js";
|
|
14
11
|
import {
|
|
15
|
-
|
|
16
|
-
} from "./chunk-
|
|
12
|
+
uiComponentTypeRoutes
|
|
13
|
+
} from "./chunk-CG6CULP6.js";
|
|
17
14
|
import {
|
|
18
15
|
answerAudit,
|
|
19
16
|
auditLines,
|
|
@@ -21,38 +18,52 @@ import {
|
|
|
21
18
|
precisionOf,
|
|
22
19
|
prepareAudit,
|
|
23
20
|
writeAudit
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
} from "./chunk-7FUIVIBG.js";
|
|
22
|
+
import {
|
|
23
|
+
listRuns,
|
|
24
|
+
partStates,
|
|
25
|
+
runTranscript
|
|
26
|
+
} from "./chunk-BA2HUMDN.js";
|
|
27
|
+
import {
|
|
28
|
+
uiCiteRoutes
|
|
29
|
+
} from "./chunk-WCEF7H6L.js";
|
|
30
|
+
import {
|
|
31
|
+
isHandoffStep
|
|
32
|
+
} from "./chunk-4Q3NN7VF.js";
|
|
29
33
|
import {
|
|
30
34
|
estimateOf
|
|
31
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-WFU77T3A.js";
|
|
36
|
+
import {
|
|
37
|
+
changeMapBody,
|
|
38
|
+
changeMapOf,
|
|
39
|
+
targetFlowsOf
|
|
40
|
+
} from "./chunk-GNWAOVFQ.js";
|
|
32
41
|
import {
|
|
33
42
|
changeArchive,
|
|
34
43
|
changeHandoff,
|
|
35
44
|
changeNew,
|
|
45
|
+
changeReleasePrs,
|
|
36
46
|
changeSync
|
|
37
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-COYN3UAN.js";
|
|
38
48
|
import {
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
isSandbox,
|
|
50
|
+
learnCheck,
|
|
51
|
+
learnStart,
|
|
52
|
+
lessonsFor,
|
|
53
|
+
readProgress,
|
|
54
|
+
sandboxCreate
|
|
55
|
+
} from "./chunk-ZQLRCA2V.js";
|
|
41
56
|
import {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
notFound,
|
|
46
|
-
startServer,
|
|
47
|
-
strParam
|
|
48
|
-
} from "./chunk-Q2X4IREC.js";
|
|
49
|
-
import "./chunk-L336AJCZ.js";
|
|
57
|
+
defencesScan,
|
|
58
|
+
evalRun
|
|
59
|
+
} from "./chunk-FVMPFCDS.js";
|
|
50
60
|
import {
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
listReports,
|
|
62
|
+
readQuality
|
|
63
|
+
} from "./chunk-FYBF5MB2.js";
|
|
53
64
|
import {
|
|
54
65
|
conformanceCommand
|
|
55
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-G5YJBNDZ.js";
|
|
56
67
|
import {
|
|
57
68
|
outcomeList,
|
|
58
69
|
outcomeRecord,
|
|
@@ -61,162 +72,232 @@ import {
|
|
|
61
72
|
releaseNotesCommand,
|
|
62
73
|
releasePlanCommand,
|
|
63
74
|
releaseSecurityCommand
|
|
64
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-AZDITBCT.js";
|
|
65
76
|
import {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
readServiceRequests
|
|
78
|
+
} from "./chunk-36RY7ZXM.js";
|
|
79
|
+
import {
|
|
80
|
+
runDone,
|
|
81
|
+
taskRun,
|
|
82
|
+
taskRunNotWaiting
|
|
83
|
+
} from "./chunk-AOCWFA7T.js";
|
|
69
84
|
import {
|
|
70
85
|
executorsCheck,
|
|
71
86
|
todoDone,
|
|
72
87
|
todoRun,
|
|
73
88
|
todoShow
|
|
74
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-ZFQMMU5Y.js";
|
|
75
90
|
import {
|
|
76
91
|
inputsSha256,
|
|
77
92
|
loadExecutors
|
|
78
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-DDJPM5YX.js";
|
|
79
94
|
import {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
lessonsFor,
|
|
84
|
-
readProgress,
|
|
85
|
-
sandboxCreate
|
|
86
|
-
} from "./chunk-2TTSX7NB.js";
|
|
95
|
+
initiativeStatus,
|
|
96
|
+
readView
|
|
97
|
+
} from "./chunk-2V2ZPQQU.js";
|
|
87
98
|
import {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
DecideError,
|
|
100
|
+
correctDecision,
|
|
101
|
+
decisionsView,
|
|
102
|
+
undoBatch
|
|
103
|
+
} from "./chunk-UYLBRRFK.js";
|
|
91
104
|
import {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
boxesOf,
|
|
106
|
+
candidatesOf,
|
|
107
|
+
uiLinkRoutes
|
|
108
|
+
} from "./chunk-6DQYZU2W.js";
|
|
95
109
|
import {
|
|
96
|
-
|
|
97
|
-
|
|
110
|
+
matchDone,
|
|
111
|
+
quotesOf,
|
|
112
|
+
readMatch,
|
|
113
|
+
runMatch
|
|
114
|
+
} from "./chunk-QJCJOMW3.js";
|
|
115
|
+
import "./chunk-3SSTNB4E.js";
|
|
116
|
+
import "./chunk-JRVNXLZP.js";
|
|
98
117
|
import {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
118
|
+
copilotAcpAllowed
|
|
119
|
+
} from "./chunk-LIJJCBQI.js";
|
|
120
|
+
import "./chunk-26Z7OGQW.js";
|
|
121
|
+
import "./chunk-OKUB6RJA.js";
|
|
102
122
|
import {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
123
|
+
filesUnder,
|
|
124
|
+
memoByFiles,
|
|
125
|
+
recheckNow,
|
|
126
|
+
uiFactsRoutes
|
|
127
|
+
} from "./chunk-QOOEYDNJ.js";
|
|
106
128
|
import {
|
|
107
|
-
|
|
108
|
-
|
|
129
|
+
HttpError,
|
|
130
|
+
badRequest,
|
|
131
|
+
conflict,
|
|
132
|
+
notFound,
|
|
133
|
+
startServer,
|
|
134
|
+
strParam
|
|
135
|
+
} from "./chunk-HK3VOHIE.js";
|
|
136
|
+
import {
|
|
137
|
+
safeMessage,
|
|
138
|
+
withFileLock
|
|
139
|
+
} from "./chunk-THN26IEF.js";
|
|
140
|
+
import "./chunk-LN77DXBM.js";
|
|
141
|
+
import "./chunk-L4CESDPB.js";
|
|
142
|
+
import "./chunk-U3NBK4EU.js";
|
|
143
|
+
import "./chunk-455SYIIE.js";
|
|
109
144
|
import {
|
|
110
145
|
reconcileCommand
|
|
111
|
-
} from "./chunk-
|
|
146
|
+
} from "./chunk-YZDZOEV4.js";
|
|
112
147
|
import {
|
|
113
148
|
sourcesAdd,
|
|
114
149
|
sourcesSync
|
|
115
|
-
} from "./chunk-
|
|
150
|
+
} from "./chunk-HXXP2NTE.js";
|
|
116
151
|
import {
|
|
117
152
|
INPUTS_SOURCE_ID
|
|
118
|
-
} from "./chunk-
|
|
119
|
-
import "./chunk-
|
|
153
|
+
} from "./chunk-D57MFJPP.js";
|
|
154
|
+
import "./chunk-5QUOPNLN.js";
|
|
155
|
+
import {
|
|
156
|
+
readRepos
|
|
157
|
+
} from "./chunk-4TKVU2I2.js";
|
|
158
|
+
import {
|
|
159
|
+
uiOnboardingRoutes
|
|
160
|
+
} from "./chunk-PNQLCRSS.js";
|
|
161
|
+
import "./chunk-3J5I7ZOU.js";
|
|
162
|
+
import {
|
|
163
|
+
uiTrustRoutes
|
|
164
|
+
} from "./chunk-4FOAYLI4.js";
|
|
165
|
+
import {
|
|
166
|
+
contractCheckOf,
|
|
167
|
+
estateJoinOnFile,
|
|
168
|
+
stampOf
|
|
169
|
+
} from "./chunk-GX74YWR7.js";
|
|
170
|
+
import "./chunk-G6IQYM25.js";
|
|
171
|
+
import "./chunk-LPV6T362.js";
|
|
172
|
+
import {
|
|
173
|
+
digestCommand
|
|
174
|
+
} from "./chunk-X2CUXTWU.js";
|
|
120
175
|
import {
|
|
121
176
|
baselineCommand,
|
|
122
177
|
setupSteps
|
|
123
|
-
} from "./chunk-
|
|
178
|
+
} from "./chunk-GK4PYVEC.js";
|
|
179
|
+
import {
|
|
180
|
+
doctorChecks
|
|
181
|
+
} from "./chunk-HGHRSF3E.js";
|
|
182
|
+
import "./chunk-4B6BT75O.js";
|
|
124
183
|
import {
|
|
125
184
|
readMe,
|
|
126
185
|
writeMe
|
|
127
|
-
} from "./chunk-
|
|
128
|
-
import {
|
|
129
|
-
uiOnboardingRoutes
|
|
130
|
-
} from "./chunk-R5MNPIMD.js";
|
|
186
|
+
} from "./chunk-UF4UHCIG.js";
|
|
131
187
|
import {
|
|
132
|
-
|
|
133
|
-
|
|
188
|
+
cancelTaskRunWait,
|
|
189
|
+
findTaskRunOfRun,
|
|
190
|
+
previewTaskRun,
|
|
191
|
+
raiseTaskPr,
|
|
192
|
+
readTaskRun,
|
|
193
|
+
readyTasksOf,
|
|
194
|
+
runReadyTasks,
|
|
195
|
+
saveTaskRun,
|
|
196
|
+
settleTaskPr,
|
|
197
|
+
stopAllBuilds,
|
|
198
|
+
taskRunOfRun
|
|
199
|
+
} from "./chunk-Y6K3CJBU.js";
|
|
200
|
+
import "./chunk-GIFMBCTW.js";
|
|
201
|
+
import "./chunk-MD7KUEJ3.js";
|
|
134
202
|
import {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
import "./chunk-AB5E5HCN.js";
|
|
139
|
-
import "./chunk-LGDW4G73.js";
|
|
203
|
+
checkoutOf
|
|
204
|
+
} from "./chunk-Q46QDDMF.js";
|
|
205
|
+
import "./chunk-TGVVUKTG.js";
|
|
140
206
|
import {
|
|
141
207
|
intakeContext
|
|
142
|
-
} from "./chunk-
|
|
143
|
-
import
|
|
144
|
-
|
|
208
|
+
} from "./chunk-TQ4TG57V.js";
|
|
209
|
+
import {
|
|
210
|
+
workspaceOpen,
|
|
211
|
+
workspaceSync
|
|
212
|
+
} from "./chunk-IFHDV6KQ.js";
|
|
213
|
+
import "./chunk-LQH4P45K.js";
|
|
214
|
+
import "./chunk-P2VBXX7N.js";
|
|
215
|
+
import {
|
|
216
|
+
archiveGate,
|
|
217
|
+
ciArchiveGate
|
|
218
|
+
} from "./chunk-ZX7235KR.js";
|
|
219
|
+
import {
|
|
220
|
+
traceMatrix
|
|
221
|
+
} from "./chunk-EZIN5E5B.js";
|
|
222
|
+
import "./chunk-3LZ6P5EP.js";
|
|
145
223
|
import {
|
|
146
224
|
scanCommand
|
|
147
|
-
} from "./chunk-
|
|
148
|
-
import "./chunk-
|
|
225
|
+
} from "./chunk-NCB6656Z.js";
|
|
226
|
+
import "./chunk-TYD6I4CZ.js";
|
|
227
|
+
import {
|
|
228
|
+
readChangeTasks,
|
|
229
|
+
readStory,
|
|
230
|
+
setTaskDone
|
|
231
|
+
} from "./chunk-YWAKDNMH.js";
|
|
149
232
|
import {
|
|
150
233
|
catalogRecords,
|
|
151
234
|
openChanges,
|
|
152
235
|
systemGuide
|
|
153
|
-
} from "./chunk-
|
|
154
|
-
import {
|
|
155
|
-
doctorChecks
|
|
156
|
-
} from "./chunk-Z7HYYDZM.js";
|
|
236
|
+
} from "./chunk-FY3QIRTL.js";
|
|
157
237
|
import "./chunk-3G4YI4ZU.js";
|
|
158
|
-
import "./chunk-
|
|
159
|
-
import "./chunk-RTUUX7PX.js";
|
|
160
|
-
import {
|
|
161
|
-
handoffDone,
|
|
162
|
-
workspaceOpen,
|
|
163
|
-
workspaceSync
|
|
164
|
-
} from "./chunk-HMZQAIR5.js";
|
|
165
|
-
import "./chunk-2T5CQH4R.js";
|
|
166
|
-
import "./chunk-G5BYKJIM.js";
|
|
167
|
-
import {
|
|
168
|
-
readChangeTasks,
|
|
169
|
-
readStory
|
|
170
|
-
} from "./chunk-2ZICHO3V.js";
|
|
238
|
+
import "./chunk-2HTEMYTB.js";
|
|
171
239
|
import {
|
|
172
240
|
ASSISTANT_FORMATS,
|
|
173
241
|
readProbes,
|
|
174
242
|
whatRunsWhere
|
|
175
|
-
} from "./chunk-
|
|
243
|
+
} from "./chunk-3AQ2R5NL.js";
|
|
176
244
|
import {
|
|
177
245
|
critic,
|
|
178
246
|
criticStats,
|
|
179
247
|
findingAction
|
|
180
|
-
} from "./chunk-
|
|
181
|
-
import "./chunk-
|
|
248
|
+
} from "./chunk-PTQ3ZALZ.js";
|
|
249
|
+
import "./chunk-A2G72UI4.js";
|
|
182
250
|
import {
|
|
183
251
|
planStories,
|
|
184
252
|
snowDraft,
|
|
185
253
|
snowSubmit
|
|
186
|
-
} from "./chunk-
|
|
187
|
-
import "./chunk-
|
|
188
|
-
import {
|
|
189
|
-
archiveGate,
|
|
190
|
-
ciArchiveGate
|
|
191
|
-
} from "./chunk-ESP3RUUR.js";
|
|
192
|
-
import {
|
|
193
|
-
traceMatrix
|
|
194
|
-
} from "./chunk-YC2K3FJG.js";
|
|
195
|
-
import "./chunk-TAKAEJRD.js";
|
|
254
|
+
} from "./chunk-I2A3Z5AK.js";
|
|
255
|
+
import "./chunk-F6H2RJ3N.js";
|
|
196
256
|
import {
|
|
257
|
+
CORRECTIONS_FILE,
|
|
258
|
+
FEATURE_FILE,
|
|
197
259
|
NEEDS_FILE,
|
|
198
260
|
PlannerError,
|
|
199
261
|
SYNC_FILE,
|
|
262
|
+
SnowFillError,
|
|
263
|
+
Stroke,
|
|
200
264
|
TARGET_DIR,
|
|
265
|
+
addCorrection,
|
|
266
|
+
applyStroke,
|
|
201
267
|
codeFactRecords,
|
|
202
268
|
commentOnFinding,
|
|
203
269
|
conflictTouches,
|
|
270
|
+
draftItems,
|
|
271
|
+
draftProvenance,
|
|
272
|
+
drawnStrokes,
|
|
273
|
+
fillSnowFields,
|
|
274
|
+
loadEstate,
|
|
204
275
|
markNeed,
|
|
205
276
|
mergeDelta,
|
|
206
277
|
plainWhy,
|
|
278
|
+
planSketchWrite,
|
|
279
|
+
readCorrections,
|
|
207
280
|
readDeltas,
|
|
208
281
|
readKnowledgeApplies,
|
|
209
282
|
readNeeds,
|
|
210
283
|
readStageLoop,
|
|
284
|
+
recordPersonSave,
|
|
285
|
+
removeCorrection,
|
|
286
|
+
renderFeature,
|
|
211
287
|
setKnowledgeStatus,
|
|
288
|
+
sketchFingerprint,
|
|
212
289
|
stageComments,
|
|
213
|
-
stageGate
|
|
214
|
-
|
|
290
|
+
stageGate,
|
|
291
|
+
writeSketch
|
|
292
|
+
} from "./chunk-BEPCKDCP.js";
|
|
215
293
|
import {
|
|
294
|
+
FeaturePlacement,
|
|
295
|
+
STAGES,
|
|
216
296
|
STAGE_PHASE,
|
|
217
297
|
fieldNames,
|
|
218
298
|
rerunOf
|
|
219
|
-
} from "./chunk-
|
|
299
|
+
} from "./chunk-HWD4JPU7.js";
|
|
300
|
+
import "./chunk-5WERBKLE.js";
|
|
220
301
|
import "./chunk-VOGCSYOI.js";
|
|
221
302
|
import {
|
|
222
303
|
layerRules,
|
|
@@ -230,8 +311,9 @@ import {
|
|
|
230
311
|
readStoryIndex,
|
|
231
312
|
reviewedGates,
|
|
232
313
|
roundsOf
|
|
233
|
-
} from "./chunk-
|
|
314
|
+
} from "./chunk-K332XW7K.js";
|
|
234
315
|
import {
|
|
316
|
+
ChangeOwnersError,
|
|
235
317
|
artifactFiles,
|
|
236
318
|
artifactPhase,
|
|
237
319
|
changeFolder,
|
|
@@ -241,24 +323,27 @@ import {
|
|
|
241
323
|
detectConflicts,
|
|
242
324
|
liveHandoff,
|
|
243
325
|
loadChangeContext,
|
|
244
|
-
requiredArtifacts
|
|
245
|
-
|
|
246
|
-
|
|
326
|
+
requiredArtifacts,
|
|
327
|
+
setChangeOwners
|
|
328
|
+
} from "./chunk-HSZMPH5T.js";
|
|
329
|
+
import "./chunk-D2WSW4GU.js";
|
|
247
330
|
import {
|
|
248
331
|
fileStepStore,
|
|
249
332
|
manualAdapter,
|
|
250
333
|
stepOfProvisional
|
|
251
|
-
} from "./chunk-
|
|
334
|
+
} from "./chunk-4KNOJC6J.js";
|
|
252
335
|
import {
|
|
253
336
|
componentRenames,
|
|
254
337
|
estateFacts,
|
|
338
|
+
estateRepos,
|
|
255
339
|
forgetCatalogs,
|
|
256
340
|
hostAliases,
|
|
257
341
|
joinReposOf,
|
|
258
342
|
keepCatalogsInMemory,
|
|
259
343
|
outsideProfileSystems,
|
|
260
|
-
readCatalog
|
|
261
|
-
|
|
344
|
+
readCatalog,
|
|
345
|
+
targetPicker
|
|
346
|
+
} from "./chunk-4SLBCEPD.js";
|
|
262
347
|
import {
|
|
263
348
|
OrgPackProposal,
|
|
264
349
|
SNAPSHOT_FILE,
|
|
@@ -282,67 +367,86 @@ import {
|
|
|
282
367
|
snapshotDates,
|
|
283
368
|
snapshotSources,
|
|
284
369
|
writeReview
|
|
285
|
-
} from "./chunk-
|
|
370
|
+
} from "./chunk-64AADMTW.js";
|
|
286
371
|
import {
|
|
287
372
|
NoSuchNode,
|
|
288
373
|
buildEstate,
|
|
289
374
|
focusView,
|
|
290
375
|
nodeView,
|
|
291
376
|
viewKey
|
|
292
|
-
} from "./chunk-
|
|
377
|
+
} from "./chunk-JYMIB5XY.js";
|
|
293
378
|
import {
|
|
294
379
|
readServiceRequestExports,
|
|
295
380
|
readVendorSpec,
|
|
296
381
|
readWorkItemExports
|
|
297
|
-
} from "./chunk-
|
|
298
|
-
import "./chunk-
|
|
299
|
-
import "./chunk-
|
|
300
|
-
import "./chunk-
|
|
301
|
-
import "./chunk-
|
|
302
|
-
import "./chunk-CYX36GKZ.js";
|
|
382
|
+
} from "./chunk-CPK7QSBG.js";
|
|
383
|
+
import "./chunk-YO2PKTXT.js";
|
|
384
|
+
import "./chunk-TWQRPM76.js";
|
|
385
|
+
import "./chunk-VUVGX5L2.js";
|
|
386
|
+
import "./chunk-API5TOUB.js";
|
|
303
387
|
import {
|
|
388
|
+
baseClonePath,
|
|
389
|
+
loadRepos,
|
|
304
390
|
readChangeRepos
|
|
305
|
-
} from "./chunk-
|
|
306
|
-
import "./chunk-TLDL2ZZI.js";
|
|
391
|
+
} from "./chunk-XOL3GFW2.js";
|
|
307
392
|
import {
|
|
308
393
|
COMMON_SETTINGS,
|
|
309
394
|
PROVIDER_SETTINGS,
|
|
310
395
|
defaultKeyStore,
|
|
311
396
|
looksLikeKey
|
|
312
|
-
} from "./chunk-
|
|
397
|
+
} from "./chunk-PRW3HXM3.js";
|
|
313
398
|
import {
|
|
314
399
|
providerFactoryFor
|
|
315
|
-
} from "./chunk-
|
|
400
|
+
} from "./chunk-QHJJMZLX.js";
|
|
401
|
+
import "./chunk-7AB6OWTV.js";
|
|
316
402
|
import {
|
|
317
403
|
ASSISTANTS,
|
|
318
404
|
ChangeArtifact,
|
|
319
405
|
DEFAULT_PORT,
|
|
320
406
|
DEFAULT_RUNTIME,
|
|
407
|
+
DeclareError,
|
|
321
408
|
DiagramLayout,
|
|
322
409
|
KNOWLEDGE_KINDS,
|
|
323
410
|
KNOWLEDGE_RECORD_KIND,
|
|
324
411
|
LAYOUT_SCHEMA_VERSION,
|
|
325
412
|
MANUAL_SYSTEMS,
|
|
413
|
+
ManifestEditError,
|
|
326
414
|
QuestionError,
|
|
415
|
+
QuestionRole,
|
|
327
416
|
QuestionState,
|
|
328
417
|
RUN_SCHEMA_VERSION,
|
|
329
418
|
RecordId,
|
|
330
419
|
Runtime,
|
|
331
420
|
SOURCE_KIND_SUGGESTIONS,
|
|
421
|
+
SPEC_HEADER_FILE,
|
|
332
422
|
TARGETS_STEP_ID,
|
|
333
423
|
TOPICS_STEP_ID,
|
|
334
424
|
ViewKey,
|
|
335
425
|
acceptProposal,
|
|
426
|
+
addProfileSystem,
|
|
427
|
+
addRolesTeam,
|
|
428
|
+
answerByWords,
|
|
336
429
|
answerQuestion,
|
|
337
430
|
api_exports,
|
|
338
431
|
catalogDirOf,
|
|
432
|
+
changedLines,
|
|
339
433
|
changesDirOf,
|
|
340
434
|
changesRelOf,
|
|
435
|
+
copilotAcpOf,
|
|
436
|
+
currentSignal,
|
|
437
|
+
decideOf,
|
|
438
|
+
declareLink,
|
|
439
|
+
declaredOf,
|
|
440
|
+
diagramsRelOf,
|
|
441
|
+
eolOf,
|
|
341
442
|
external_exports,
|
|
342
443
|
factIdPart,
|
|
444
|
+
factsDirOf,
|
|
343
445
|
factsRelOf,
|
|
344
446
|
gateRoundLimit,
|
|
447
|
+
inEol,
|
|
345
448
|
inputsDirOf,
|
|
449
|
+
isAdopted,
|
|
346
450
|
joinConventions,
|
|
347
451
|
joinSharedMaps,
|
|
348
452
|
joinVendorOperations,
|
|
@@ -350,10 +454,13 @@ import {
|
|
|
350
454
|
knowledgeKindOf,
|
|
351
455
|
knowledgeRelOf,
|
|
352
456
|
layoutPath,
|
|
457
|
+
lfOnly,
|
|
353
458
|
listQuestions,
|
|
354
459
|
loadOrgPack,
|
|
460
|
+
manifestFiles,
|
|
355
461
|
orgPackDirOf,
|
|
356
462
|
pageStanding,
|
|
463
|
+
parseCorrections,
|
|
357
464
|
proposalsDirOf,
|
|
358
465
|
proposalsRelOf,
|
|
359
466
|
readEstateJoins,
|
|
@@ -363,20 +470,25 @@ import {
|
|
|
363
470
|
require_dist,
|
|
364
471
|
runsDirOf,
|
|
365
472
|
runsRelOf,
|
|
473
|
+
setManifestField,
|
|
474
|
+
specDirOf,
|
|
366
475
|
specRelOf,
|
|
367
|
-
specRepos
|
|
368
|
-
|
|
476
|
+
specRepos,
|
|
477
|
+
undeclareLink
|
|
478
|
+
} from "./chunk-PAINMSID.js";
|
|
369
479
|
import {
|
|
480
|
+
FileChangedError,
|
|
370
481
|
createLog,
|
|
371
|
-
writeFileAtomic
|
|
372
|
-
|
|
482
|
+
writeFileAtomic,
|
|
483
|
+
writeFileIfUnchanged
|
|
484
|
+
} from "./chunk-ODMBPDDV.js";
|
|
373
485
|
import {
|
|
374
486
|
__toESM
|
|
375
487
|
} from "./chunk-TV45EUGM.js";
|
|
376
488
|
|
|
377
489
|
// packages/cli/dist/ui-commands.js
|
|
378
490
|
import { spawn } from "node:child_process";
|
|
379
|
-
import { isAbsolute, join as
|
|
491
|
+
import { isAbsolute, join as join14, relative as relative2, sep as sep2 } from "node:path";
|
|
380
492
|
|
|
381
493
|
// packages/ui/dist-lib/index.js
|
|
382
494
|
import { dirname, join } from "node:path";
|
|
@@ -388,8 +500,45 @@ function uiDistDir() {
|
|
|
388
500
|
|
|
389
501
|
// packages/cli/dist/ui-api.js
|
|
390
502
|
import { createHash } from "node:crypto";
|
|
391
|
-
import {
|
|
392
|
-
import {
|
|
503
|
+
import { existsSync } from "node:fs";
|
|
504
|
+
import { mkdir, readdir, readFile, stat } from "node:fs/promises";
|
|
505
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
506
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
507
|
+
var FACTS_REPO = /^[a-z0-9][a-z0-9._-]{0,99}$/i;
|
|
508
|
+
async function openTaskWorktree(root, change, task, gitHost) {
|
|
509
|
+
const p = await previewTaskRun(root, change, task, {
|
|
510
|
+
skipGitHost: true,
|
|
511
|
+
...gitHost ? { gitHost } : {}
|
|
512
|
+
}).catch(() => void 0);
|
|
513
|
+
if (!p)
|
|
514
|
+
return void 0;
|
|
515
|
+
const text = await readFile(join2(changesDirOf(root), change, "repos.yaml"), "utf8").catch(() => "");
|
|
516
|
+
let has = false;
|
|
517
|
+
try {
|
|
518
|
+
const d = (0, import_yaml.parse)(text);
|
|
519
|
+
has = !!d?.repos?.some((r) => r.id === p.repo && r.worktree);
|
|
520
|
+
} catch {
|
|
521
|
+
}
|
|
522
|
+
if (has)
|
|
523
|
+
return void 0;
|
|
524
|
+
if (!existsSync(baseClonePath(root, p.repo))) {
|
|
525
|
+
const synced = await run((io) => workspaceSync(root, [p.repo], io));
|
|
526
|
+
if (synced.code !== 0)
|
|
527
|
+
return synced;
|
|
528
|
+
const opened = await run((io) => workspaceOpen(root, change, [p.repo], io));
|
|
529
|
+
return { ...opened, out: [...synced.out, ...opened.out] };
|
|
530
|
+
}
|
|
531
|
+
return run((io) => workspaceOpen(root, change, [p.repo], io));
|
|
532
|
+
}
|
|
533
|
+
var TASK_ERRORS = /* @__PURE__ */ new Set([
|
|
534
|
+
"SpecKitError",
|
|
535
|
+
"ChangeError",
|
|
536
|
+
"ChangeFileError",
|
|
537
|
+
"AdapterError",
|
|
538
|
+
"RuntimeConfigError",
|
|
539
|
+
"GitError",
|
|
540
|
+
"RuntimeError"
|
|
541
|
+
]);
|
|
393
542
|
async function run(f) {
|
|
394
543
|
const out = [];
|
|
395
544
|
const err = [];
|
|
@@ -440,6 +589,7 @@ async function changeDetail(root, id) {
|
|
|
440
589
|
const current = report.phase ? phases.indexOf(report.phase) : phases.length;
|
|
441
590
|
const artifacts = [];
|
|
442
591
|
const blockedArtifacts = new Set(report.blockers.map((b) => b.artifact).filter(Boolean));
|
|
592
|
+
const templateOnly = new Set(report.blockers.filter((b) => b.code === "unfilled-artifact").map((b) => b.artifact));
|
|
443
593
|
const cctx = await loadChangeContext(root);
|
|
444
594
|
const onStages = (await Promise.all(cctx.policy.stages.map((s) => readFile(join2(dir, ...s.loop.split("/"))).then(() => true, () => false)))).some(Boolean);
|
|
445
595
|
const type = report.type.artifacts;
|
|
@@ -459,6 +609,8 @@ async function changeDetail(root, id) {
|
|
|
459
609
|
artifact: a,
|
|
460
610
|
path: `${changesRelOf(root)}/${id}/${files[0] ?? `${a}.md`}`,
|
|
461
611
|
status: done ? "done" : at <= current ? "ready" : "blocked",
|
|
612
|
+
// Seventh UX walk (2.70.0): ready or blocked says what the phase allows, not that it is there.
|
|
613
|
+
written: files.length > 0 && !templateOnly.has(a),
|
|
462
614
|
openFindings: findings.filter((f) => f.state === "open" && f.artifact.startsWith(a)).length
|
|
463
615
|
});
|
|
464
616
|
}
|
|
@@ -473,6 +625,8 @@ async function changeDetail(root, id) {
|
|
|
473
625
|
openFindings: open,
|
|
474
626
|
updatedAt: c.history.at(-1)?.at ?? c.createdAt,
|
|
475
627
|
...fast ? { fastPath: true } : {},
|
|
628
|
+
// Ninth UX walk (2.83.0): who owns each role, so the change page can name them.
|
|
629
|
+
owners: c.owners,
|
|
476
630
|
artifacts,
|
|
477
631
|
...h ? {
|
|
478
632
|
handoff: {
|
|
@@ -483,6 +637,74 @@ async function changeDetail(root, id) {
|
|
|
483
637
|
} : {}
|
|
484
638
|
};
|
|
485
639
|
}
|
|
640
|
+
async function applyFirstOf(root, files) {
|
|
641
|
+
const mtime = (p) => stat(p).then((s) => s.mtimeMs, () => void 0);
|
|
642
|
+
const out = [];
|
|
643
|
+
for (const f of files) {
|
|
644
|
+
const repo = /(?:^|\/)facts\/([^/]+)\.corrections\.jsonl$/.exec(f.path)?.[1] ?? await answeredMapQuestionRepo(root, f.path);
|
|
645
|
+
if (!repo || out.includes(repo))
|
|
646
|
+
continue;
|
|
647
|
+
const saved = await mtime(join2(root, ...f.path.split("/")));
|
|
648
|
+
if (saved === void 0)
|
|
649
|
+
continue;
|
|
650
|
+
const applied = await mtime(join2(specDirOf(root, repo), SPEC_HEADER_FILE)) ?? await mtime(join2(factsDirOf(root), `${repo}.verify.yaml`));
|
|
651
|
+
if (applied === void 0 || saved > applied)
|
|
652
|
+
out.push(repo);
|
|
653
|
+
}
|
|
654
|
+
return out;
|
|
655
|
+
}
|
|
656
|
+
async function answeredMapQuestionRepo(root, path) {
|
|
657
|
+
if (!/(?:^|\/)questions\/q-[^/]+\.yaml$/.test(path))
|
|
658
|
+
return void 0;
|
|
659
|
+
const q = await readFile(join2(root, ...path.split("/")), "utf8").then((t) => (0, import_yaml.parse)(t), () => void 0);
|
|
660
|
+
if (!q || q.state !== "answered" || typeof q.repo !== "string")
|
|
661
|
+
return void 0;
|
|
662
|
+
const of = /^atticus verify ([a-z0-9][a-z0-9._-]*) --write$/.exec(String(q.rerun ?? "").trim());
|
|
663
|
+
return of?.[1] === q.repo ? q.repo : void 0;
|
|
664
|
+
}
|
|
665
|
+
async function taskViews(root, change, prs) {
|
|
666
|
+
const dir = join2(changesDirOf(root), change);
|
|
667
|
+
let tasks = readChangeTasks(await readChangeFiles(dir));
|
|
668
|
+
const states = prs ? await Promise.all(tasks.map((t) => settleTaskPr(root, change, t.id, {
|
|
669
|
+
...prs.gitHost ? { gitHost: prs.gitHost } : {},
|
|
670
|
+
...prs.now ? { now: () => new Date(prs.now) } : {}
|
|
671
|
+
}).catch(() => ({})))) : [];
|
|
672
|
+
if (states.some((s) => s.ticked)) {
|
|
673
|
+
tasks = readChangeTasks(await readChangeFiles(dir));
|
|
674
|
+
prs?.onTick?.();
|
|
675
|
+
}
|
|
676
|
+
const waits = new Map((await readyTasksOf(root, change).catch(() => ({ tasks: [] }))).tasks.map((x) => [x.id, x]));
|
|
677
|
+
const out = [];
|
|
678
|
+
for (const [i, t] of tasks.entries()) {
|
|
679
|
+
const w = t.done ? void 0 : waits.get(t.id);
|
|
680
|
+
const tr = await readTaskRun(root, change, t.id).catch(() => void 0);
|
|
681
|
+
const run4 = tr ? tr.waiting ?? tr.runs[0] : void 0;
|
|
682
|
+
const prState = tr?.state === "pr-open" ? states[i]?.state : void 0;
|
|
683
|
+
out.push({
|
|
684
|
+
id: t.id,
|
|
685
|
+
repo: t.repo,
|
|
686
|
+
description: t.title,
|
|
687
|
+
done: t.done,
|
|
688
|
+
...t.stories[0] ? { story: t.stories[0] } : {},
|
|
689
|
+
branch: `task/${change}/${t.id}`,
|
|
690
|
+
...run4 ? { run: run4 } : {},
|
|
691
|
+
...tr ? {
|
|
692
|
+
taskRun: {
|
|
693
|
+
state: tr.state,
|
|
694
|
+
level: tr.level,
|
|
695
|
+
branch: tr.branch,
|
|
696
|
+
...tr.commit ? { commit: tr.commit } : {},
|
|
697
|
+
...tr.pr ? { pr: { ...tr.pr, ...prState ? { state: prState } : {} } } : {},
|
|
698
|
+
...tr.ticked ? { ticked: tr.ticked } : {},
|
|
699
|
+
...tr.marked ? { marked: tr.marked } : {},
|
|
700
|
+
notes: tr.notes
|
|
701
|
+
}
|
|
702
|
+
} : {},
|
|
703
|
+
...w?.waitsFor.length ? { waits: { tasks: w.waitsFor, sameRepo: w.sameRepo ?? [] } } : {}
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
return out;
|
|
707
|
+
}
|
|
486
708
|
async function runView(root, change, runId) {
|
|
487
709
|
const dir = join2(runsDirOf(root), change, runId);
|
|
488
710
|
const text = await readFile(join2(dir, "run.json"), "utf8").catch(() => void 0);
|
|
@@ -490,6 +712,7 @@ async function runView(root, change, runId) {
|
|
|
490
712
|
return void 0;
|
|
491
713
|
const r = JSON.parse(text);
|
|
492
714
|
const manifest = await readFile(join2(dir, "context-manifest.json"), "utf8").catch(() => "");
|
|
715
|
+
const tr = await taskRunOfRun(root, change, runId).catch(() => void 0);
|
|
493
716
|
return {
|
|
494
717
|
schemaVersion: RUN_SCHEMA_VERSION,
|
|
495
718
|
runId: r.runId,
|
|
@@ -506,7 +729,22 @@ async function runView(root, change, runId) {
|
|
|
506
729
|
attempt: r.attempt ?? 1,
|
|
507
730
|
...r.stepClass ? { stepClass: r.stepClass } : {},
|
|
508
731
|
...r.model ? { model: r.model } : {},
|
|
509
|
-
|
|
732
|
+
...r.batch ? { batch: r.batch } : {},
|
|
733
|
+
...r.parts?.length ? { parts: await partStates(root, change, r.parts) } : {},
|
|
734
|
+
promptPath: `${runsRelOf(root)}/${change}/${runId}/prompt.md`,
|
|
735
|
+
...tr ? {
|
|
736
|
+
taskRun: {
|
|
737
|
+
task: tr.task,
|
|
738
|
+
repo: tr.repo,
|
|
739
|
+
level: tr.level,
|
|
740
|
+
state: tr.state,
|
|
741
|
+
branch: tr.branch,
|
|
742
|
+
worktree: tr.worktree,
|
|
743
|
+
notes: tr.notes,
|
|
744
|
+
...tr.commit ? { commit: tr.commit } : {},
|
|
745
|
+
...tr.attempts.at(-1) ? { log: tr.attempts.at(-1).log } : {}
|
|
746
|
+
}
|
|
747
|
+
} : {}
|
|
510
748
|
};
|
|
511
749
|
}
|
|
512
750
|
async function findRun(root, runId) {
|
|
@@ -519,23 +757,137 @@ async function findRun(root, runId) {
|
|
|
519
757
|
}
|
|
520
758
|
throw notFound(`There is no run ${runId}.`);
|
|
521
759
|
}
|
|
522
|
-
async function artifactPath(root, id, artifact) {
|
|
760
|
+
async function artifactPath(root, id, artifact, o = {}) {
|
|
523
761
|
const a = ChangeArtifact.safeParse(artifact);
|
|
524
762
|
if (!a.success)
|
|
525
763
|
throw badRequest(`${artifact} is not an artifact. Use one of ${ChangeArtifact.options.join(", ")}.`);
|
|
526
764
|
const dir = join2(changesDirOf(root), id);
|
|
527
765
|
const files = await artifactFiles(dir, a.data);
|
|
766
|
+
if (o.file) {
|
|
767
|
+
if (!files.includes(o.file))
|
|
768
|
+
throw notFound(`${o.file} isn't one of change ${id}'s ${artifact} files.`);
|
|
769
|
+
return o.file;
|
|
770
|
+
}
|
|
771
|
+
if (files.length === 0 && o.orNew && a.data !== "specs")
|
|
772
|
+
return a.data === "stories" ? "stories.md" : `${a.data}.md`;
|
|
528
773
|
if (files.length === 0)
|
|
529
774
|
throw notFound(`Change ${id} has no ${artifact} yet.`);
|
|
530
775
|
return files[0];
|
|
531
776
|
}
|
|
532
777
|
function uiRoutes(r, ctx, deps = {}) {
|
|
533
778
|
const { root, user, jobs } = ctx;
|
|
779
|
+
const readyView = async (change) => {
|
|
780
|
+
const { deployOrderOf } = await import("./chunk-JKIGL3XQ.js");
|
|
781
|
+
const repoOrder = await deployOrderOf(root, change);
|
|
782
|
+
const prStates = /* @__PURE__ */ new Map();
|
|
783
|
+
for (const t of await taskViews(root, change, {
|
|
784
|
+
...deps.gitHost ? { gitHost: deps.gitHost } : {},
|
|
785
|
+
...deps.now ? { now: deps.now } : {}
|
|
786
|
+
}))
|
|
787
|
+
if (t.taskRun?.pr?.state)
|
|
788
|
+
prStates.set(t.id, t.taskRun.pr.state);
|
|
789
|
+
const plan = await readyTasksOf(root, change, {
|
|
790
|
+
...repoOrder ? { repoOrder } : {},
|
|
791
|
+
prStates
|
|
792
|
+
});
|
|
793
|
+
return api_exports.ReadyTasks.parse({ change, ...plan, ...repoOrder ? { repoOrder } : {} });
|
|
794
|
+
};
|
|
795
|
+
const doneBusy = /* @__PURE__ */ new Set();
|
|
534
796
|
const changeDeps = {
|
|
535
797
|
...deps.gitHost ? { gitHost: deps.gitHost } : {},
|
|
536
798
|
...deps.now ? { now: deps.now } : {}
|
|
537
799
|
};
|
|
538
|
-
|
|
800
|
+
const localWhat = /* @__PURE__ */ new Map();
|
|
801
|
+
const asJob = (what, work) => {
|
|
802
|
+
const busy = ctx.jobs.runningOf("local");
|
|
803
|
+
if (busy)
|
|
804
|
+
throw conflict(`${localWhat.get(busy.id) ?? busy.progress.message} is running on this server (${busy.id}): wait for it to finish, then try again.`);
|
|
805
|
+
const job = ctx.jobs.start("local", async (c) => {
|
|
806
|
+
c.progress(0, 1, what);
|
|
807
|
+
const res = await work();
|
|
808
|
+
c.progress(1, 1, res.code === 0 ? "Done" : "Stopped");
|
|
809
|
+
ctx.events.publish({ type: "file.changed", path: "." });
|
|
810
|
+
const lines = [...res.out, ...res.err];
|
|
811
|
+
return { result: { code: res.code, lines }, errors: res.code === 0 ? [] : lines };
|
|
812
|
+
});
|
|
813
|
+
localWhat.set(job.id, what);
|
|
814
|
+
return { status: 202, body: { jobId: job.id } };
|
|
815
|
+
};
|
|
816
|
+
return r.add("POST", "/api/facts/{repo}/apply", async ({ params }) => {
|
|
817
|
+
const { verifyCommand } = await import("./chunk-T74WQQGS.js");
|
|
818
|
+
const repo = params.repo;
|
|
819
|
+
if (!FACTS_REPO.test(repo))
|
|
820
|
+
throw badRequest(`${JSON.stringify(repo)} isn't a repo name.`);
|
|
821
|
+
if (!(await loadRepos(root)).some((x) => x.id === repo))
|
|
822
|
+
throw notFound(`There is no repo ${repo} in this workspace.`);
|
|
823
|
+
return asJob(`Applying to ${repo}`, () => run((io) => verifyCommand(root, repo, { write: true, verbose: false, json: false }, io)));
|
|
824
|
+
}).add("GET", "/api/upgrade", async () => {
|
|
825
|
+
const { upgradeCheck } = await import("./chunk-AM6FP6JW.js");
|
|
826
|
+
const c = await upgradeCheck(root);
|
|
827
|
+
const body = {
|
|
828
|
+
atticus: c.atticus,
|
|
829
|
+
newer: c.newer,
|
|
830
|
+
...c.stamp ? { stamp: c.stamp.atticus } : {},
|
|
831
|
+
pending: c.pending
|
|
832
|
+
};
|
|
833
|
+
return { status: 200, body };
|
|
834
|
+
}).add("POST", "/api/upgrade", async () => {
|
|
835
|
+
const { upgradeCheck, upgradeCommand } = await import("./chunk-AM6FP6JW.js");
|
|
836
|
+
const c = await upgradeCheck(root);
|
|
837
|
+
if (c.newer)
|
|
838
|
+
throw conflict(`This metarepo was upgraded by Atticus ${c.stamp.atticus}; this is ${c.atticus}. Install ${c.stamp.atticus} or later first.`);
|
|
839
|
+
if (!c.pending.length)
|
|
840
|
+
throw conflict(`Nothing to upgrade: up to date for Atticus ${c.atticus}.`);
|
|
841
|
+
return asJob("Upgrading the metarepo", () => run((io) => upgradeCommand(root, { by: user }, io)));
|
|
842
|
+
}).add("GET", "/api/propose", async ({ query }) => {
|
|
843
|
+
const { proposePlan, PROPOSE_SCOPES } = await import("./chunk-UZACEG2C.js");
|
|
844
|
+
const scope = query.get("scope") ?? "";
|
|
845
|
+
if (!PROPOSE_SCOPES.includes(scope))
|
|
846
|
+
throw refused({
|
|
847
|
+
code: 2,
|
|
848
|
+
out: [],
|
|
849
|
+
err: [`scope is one of ${PROPOSE_SCOPES.join(", ")}.`]
|
|
850
|
+
});
|
|
851
|
+
const plan = await proposePlan(root, scope, {
|
|
852
|
+
by: user
|
|
853
|
+
}).catch((e) => {
|
|
854
|
+
throw refused({
|
|
855
|
+
code: 1,
|
|
856
|
+
out: [],
|
|
857
|
+
err: [
|
|
858
|
+
`Atticus can't list what changed here: ${e.message.split("\n")[0]}. Propose for review needs the metarepo to be a Git repository with a remote.`
|
|
859
|
+
]
|
|
860
|
+
});
|
|
861
|
+
});
|
|
862
|
+
return { status: 200, body: { ...plan, applyFirst: await applyFirstOf(root, plan.files) } };
|
|
863
|
+
}).add("POST", "/api/propose", async ({ body }) => {
|
|
864
|
+
const b = parseBody(api_exports.ProposeRequest, body);
|
|
865
|
+
const { proposeForReview } = await import("./chunk-UZACEG2C.js");
|
|
866
|
+
return asJob("Proposing for review", () => run((io) => proposeForReview(root, {
|
|
867
|
+
scope: b.scope,
|
|
868
|
+
by: user,
|
|
869
|
+
files: b.files,
|
|
870
|
+
...b.title ? { title: b.title } : {},
|
|
871
|
+
...b.branch ? { branch: b.branch } : {}
|
|
872
|
+
}, io)));
|
|
873
|
+
}).add("POST", "/api/propose/bring-in", async () => {
|
|
874
|
+
const { bringInMerged } = await import("./chunk-UZACEG2C.js");
|
|
875
|
+
return asJob("Bringing in what merged", () => run((io) => bringInMerged(root, io)));
|
|
876
|
+
}).add("POST", "/api/changes/{changeId}/conformance", async ({ params }) => {
|
|
877
|
+
await readChange(root, params.changeId);
|
|
878
|
+
const { changeConformCommand } = await import("./chunk-5CMPVC3N.js");
|
|
879
|
+
return asJob(`Checking ${params.changeId}'s code against its design`, () => run((io) => changeConformCommand(root, params.changeId, { findingsAnswer: true }, io)));
|
|
880
|
+
}).add("GET", "/api/change-types", async () => {
|
|
881
|
+
const op = await loadOrgPack(orgPackDirOf(root));
|
|
882
|
+
return {
|
|
883
|
+
status: 200,
|
|
884
|
+
body: op.changeTypes.types.map((t) => ({
|
|
885
|
+
id: t.id,
|
|
886
|
+
name: t.name,
|
|
887
|
+
...t.description ? { description: t.description } : {}
|
|
888
|
+
}))
|
|
889
|
+
};
|
|
890
|
+
}).add("POST", "/api/changes", async ({ body }) => {
|
|
539
891
|
const b = parseBody(NewChange, body);
|
|
540
892
|
const owners = Object.entries(b.owners ?? {}).map(([role, who]) => `${role}=${who.join(",")}`);
|
|
541
893
|
const res = await run((io) => changeNew(root, {
|
|
@@ -557,7 +909,22 @@ function uiRoutes(r, ctx, deps = {}) {
|
|
|
557
909
|
}).add("GET", "/api/changes/{changeId}", async ({ params }) => ({
|
|
558
910
|
status: 200,
|
|
559
911
|
body: await changeDetail(root, params.changeId)
|
|
560
|
-
})).add("
|
|
912
|
+
})).add("PUT", "/api/changes/{changeId}/owners", async ({ params, body }) => {
|
|
913
|
+
await readChange(root, params.changeId);
|
|
914
|
+
const b = parseBody(api_exports.ChangeOwnersRequest, body);
|
|
915
|
+
try {
|
|
916
|
+
await setChangeOwners(root, params.changeId, b.owners);
|
|
917
|
+
} catch (e) {
|
|
918
|
+
if (e instanceof ChangeOwnersError)
|
|
919
|
+
throw badRequest(e.message);
|
|
920
|
+
throw e;
|
|
921
|
+
}
|
|
922
|
+
ctx.events.publish({
|
|
923
|
+
type: "file.changed",
|
|
924
|
+
path: `${changesRelOf(root)}/${params.changeId}/change.yaml`
|
|
925
|
+
});
|
|
926
|
+
return { status: 200, body: await changeDetail(root, params.changeId) };
|
|
927
|
+
}).add("GET", "/api/changes/{changeId}/status", async ({ params }) => {
|
|
561
928
|
await readChange(root, params.changeId);
|
|
562
929
|
const rep = await changeReport(root, params.changeId);
|
|
563
930
|
return {
|
|
@@ -581,10 +948,13 @@ function uiRoutes(r, ctx, deps = {}) {
|
|
|
581
948
|
reasons: rep.reasons
|
|
582
949
|
}
|
|
583
950
|
};
|
|
584
|
-
}).add("GET", "/api/changes/{changeId}/artifacts/{artifact}", async ({ params }) => {
|
|
951
|
+
}).add("GET", "/api/changes/{changeId}/artifacts/{artifact}", async ({ params, query }) => {
|
|
585
952
|
await readChange(root, params.changeId);
|
|
586
|
-
const rel = await artifactPath(root, params.changeId, params.artifact
|
|
587
|
-
|
|
953
|
+
const rel = await artifactPath(root, params.changeId, params.artifact, {
|
|
954
|
+
orNew: true,
|
|
955
|
+
file: query.get("file")
|
|
956
|
+
});
|
|
957
|
+
const content = await readFile(join2(changesDirOf(root), params.changeId, rel), "utf8").catch(() => "");
|
|
588
958
|
return {
|
|
589
959
|
status: 200,
|
|
590
960
|
body: {
|
|
@@ -594,15 +964,27 @@ function uiRoutes(r, ctx, deps = {}) {
|
|
|
594
964
|
sha256: sha(content)
|
|
595
965
|
}
|
|
596
966
|
};
|
|
597
|
-
}).add("PUT", "/api/changes/{changeId}/artifacts/{artifact}", async ({ params, body }) => {
|
|
967
|
+
}).add("PUT", "/api/changes/{changeId}/artifacts/{artifact}", async ({ params, body, query }) => {
|
|
598
968
|
await readChange(root, params.changeId);
|
|
599
969
|
const b = parseBody(api_exports.SaveArtifactRequest, body);
|
|
600
|
-
const rel = await artifactPath(root, params.changeId, params.artifact
|
|
970
|
+
const rel = await artifactPath(root, params.changeId, params.artifact, {
|
|
971
|
+
orNew: true,
|
|
972
|
+
file: query.get("file")
|
|
973
|
+
});
|
|
601
974
|
const file = join2(changesDirOf(root), params.changeId, rel);
|
|
602
|
-
const
|
|
975
|
+
const was = await readFile(file, "utf8").catch(() => void 0);
|
|
976
|
+
const now = was ?? "";
|
|
603
977
|
if (sha(now) !== b.baseSha256)
|
|
604
978
|
throw conflict(`${rel} changed since you opened it. Reload it, then make your edit again.`);
|
|
605
|
-
await
|
|
979
|
+
await mkdir(dirname2(file), { recursive: true });
|
|
980
|
+
await writeFileIfUnchanged(file, was, b.content);
|
|
981
|
+
const { recordPersonSave: recordPersonSave2 } = await import("./chunk-NTAVOWYD.js");
|
|
982
|
+
await recordPersonSave2(join2(changesDirOf(root), params.changeId), params.changeId, {
|
|
983
|
+
file: rel,
|
|
984
|
+
who: user,
|
|
985
|
+
at: (deps.now ? new Date(deps.now) : /* @__PURE__ */ new Date()).toISOString(),
|
|
986
|
+
content: b.content
|
|
987
|
+
}).catch(() => void 0);
|
|
606
988
|
ctx.events.publish({
|
|
607
989
|
type: "file.changed",
|
|
608
990
|
path: `${changesRelOf(root)}/${params.changeId}/${rel}`
|
|
@@ -618,17 +1000,142 @@ function uiRoutes(r, ctx, deps = {}) {
|
|
|
618
1000
|
};
|
|
619
1001
|
}).add("GET", "/api/changes/{changeId}/tasks", async ({ params }) => {
|
|
620
1002
|
await readChange(root, params.changeId);
|
|
621
|
-
const
|
|
1003
|
+
const change = params.changeId;
|
|
622
1004
|
return {
|
|
623
1005
|
status: 200,
|
|
624
|
-
body:
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
1006
|
+
body: await taskViews(root, change, {
|
|
1007
|
+
...deps.gitHost ? { gitHost: deps.gitHost } : {},
|
|
1008
|
+
...deps.now ? { now: deps.now } : {},
|
|
1009
|
+
// Seventh UX walk: a task ticked because its PR merged changed tasks.md.
|
|
1010
|
+
onTick: () => ctx.events.publish({
|
|
1011
|
+
type: "file.changed",
|
|
1012
|
+
path: `${changesRelOf(root)}/${change}/tasks.md`
|
|
1013
|
+
})
|
|
1014
|
+
})
|
|
1015
|
+
};
|
|
1016
|
+
}).add("POST", "/api/changes/{changeId}/tasks/{taskId}/done", async ({ params, body }) => {
|
|
1017
|
+
await readChange(root, params.changeId);
|
|
1018
|
+
const change = params.changeId;
|
|
1019
|
+
const task = params.taskId;
|
|
1020
|
+
const b = parseBody(api_exports.TaskDoneRequest, body);
|
|
1021
|
+
if (!(await taskViews(root, change)).some((t) => t.id === task))
|
|
1022
|
+
throw notFound(`Change ${change} has no task ${task}.`);
|
|
1023
|
+
if (await setTaskDone(root, change, task, b.done))
|
|
1024
|
+
ctx.events.publish({
|
|
1025
|
+
type: "file.changed",
|
|
1026
|
+
path: `${changesRelOf(root)}/${change}/tasks.md`
|
|
1027
|
+
});
|
|
1028
|
+
const tr = await readTaskRun(root, change, task).catch(() => void 0);
|
|
1029
|
+
if (tr) {
|
|
1030
|
+
tr.marked = {
|
|
1031
|
+
done: b.done,
|
|
1032
|
+
by: user,
|
|
1033
|
+
at: (deps.now ? new Date(deps.now) : /* @__PURE__ */ new Date()).toISOString().replace(/\.000Z$/, "Z")
|
|
1034
|
+
};
|
|
1035
|
+
await saveTaskRun(root, tr);
|
|
1036
|
+
}
|
|
1037
|
+
return {
|
|
1038
|
+
status: 200,
|
|
1039
|
+
body: (await taskViews(root, change)).find((t) => t.id === task)
|
|
1040
|
+
};
|
|
1041
|
+
}).add("GET", "/api/changes/{changeId}/tasks/ready", async ({ params }) => {
|
|
1042
|
+
await readChange(root, params.changeId);
|
|
1043
|
+
return { status: 200, body: await readyView(params.changeId) };
|
|
1044
|
+
}).add("POST", "/api/changes/{changeId}/tasks/run-ready", async ({ params, body }) => {
|
|
1045
|
+
const change = params.changeId;
|
|
1046
|
+
await readChange(root, change);
|
|
1047
|
+
const b = parseBody(api_exports.RunReadyRequest, body);
|
|
1048
|
+
const view3 = await readyView(change);
|
|
1049
|
+
const tasks = b.tasks ? view3.ready.filter((t) => b.tasks.includes(t)) : view3.ready;
|
|
1050
|
+
if (!tasks.length)
|
|
1051
|
+
throw refused({
|
|
1052
|
+
code: 1,
|
|
1053
|
+
out: [],
|
|
1054
|
+
err: [
|
|
1055
|
+
b.tasks ? `None of ${b.tasks.join(", ")} is ready to run now: the Task board says why.` : `No task of ${change} is ready to run: each waits for the tasks before it, its PR, the assistant or a person.`
|
|
1056
|
+
]
|
|
1057
|
+
});
|
|
1058
|
+
const repoOf2 = new Map(view3.tasks.map((t) => [t.id, t.repo]));
|
|
1059
|
+
const busy = ctx.jobs.runningOf("step");
|
|
1060
|
+
if (busy)
|
|
1061
|
+
throw conflict(`An AI step is running on this server (${busy.id}): wait for it to finish, or cancel it.`);
|
|
1062
|
+
const job = ctx.jobs.start("step", async (c) => {
|
|
1063
|
+
const r2 = await runReadyTasks(root, change, {
|
|
1064
|
+
by: user,
|
|
1065
|
+
only: tasks,
|
|
1066
|
+
...view3.repoOrder ? { repoOrder: view3.repoOrder } : {},
|
|
1067
|
+
...b.level ? { level: b.level } : {},
|
|
1068
|
+
...b.runtime ? { mode: b.runtime } : {},
|
|
1069
|
+
// As Run with AI: runtime.yaml's level, lowered to the repo's cap, and at most draft.
|
|
1070
|
+
levelFor: async (task) => {
|
|
1071
|
+
const p = await previewTaskRun(root, change, task, {
|
|
1072
|
+
skipGitHost: true,
|
|
1073
|
+
...deps.gitHost ? { gitHost: deps.gitHost } : {}
|
|
1074
|
+
});
|
|
1075
|
+
return p.level === "pr" ? "draft" : p.level;
|
|
1076
|
+
},
|
|
1077
|
+
// The task's repo gets its worktree when it has none yet, as Run with AI does.
|
|
1078
|
+
before: async (task) => {
|
|
1079
|
+
const opened = await openTaskWorktree(root, change, task, deps.gitHost);
|
|
1080
|
+
return opened && opened.code !== 0 ? opened.err.join(" ") || opened.out.join(" ") || "Its worktree couldn't be opened." : void 0;
|
|
1081
|
+
},
|
|
1082
|
+
progress: (done, total, message) => c.progress(done, total, message),
|
|
1083
|
+
cancelled: () => c.cancelled,
|
|
1084
|
+
...deps.gitHost ? { gitHost: deps.gitHost } : {},
|
|
1085
|
+
...deps.taskRun?.git ? { git: deps.taskRun.git } : {},
|
|
1086
|
+
...deps.taskRun?.commands ? { commands: deps.taskRun.commands } : {}
|
|
1087
|
+
});
|
|
1088
|
+
for (const x of r2.ran)
|
|
1089
|
+
ctx.events.publish({
|
|
1090
|
+
type: "file.changed",
|
|
1091
|
+
path: `${changesRelOf(root)}/${change}/tasks/${x.task}/task-run.yaml`
|
|
1092
|
+
});
|
|
1093
|
+
const ran = r2.ran.map((x) => "record" in x ? { task: x.task, repo: x.repo, state: x.record.state, branch: x.record.branch } : { task: x.task, repo: x.repo || (repoOf2.get(x.task) ?? ""), refused: x.refused });
|
|
1094
|
+
const left = r2.stopped ? r2.planned.slice(r2.planned.indexOf(r2.stopped.task) + 1) : [];
|
|
1095
|
+
return {
|
|
1096
|
+
result: api_exports.RunReadyResult.parse({
|
|
1097
|
+
ran,
|
|
1098
|
+
...r2.stopped ? { stopped: r2.stopped } : {},
|
|
1099
|
+
left
|
|
1100
|
+
})
|
|
1101
|
+
};
|
|
1102
|
+
});
|
|
1103
|
+
return { status: 202, body: api_exports.RunReadyAccepted.parse({ jobId: job.id, tasks }) };
|
|
1104
|
+
}).add("POST", "/api/changes/{changeId}/tasks/{taskId}/pr", async ({ params }) => {
|
|
1105
|
+
await readChange(root, params.changeId);
|
|
1106
|
+
const change = params.changeId;
|
|
1107
|
+
const task = params.taskId;
|
|
1108
|
+
if (!(await taskViews(root, change)).some((t) => t.id === task))
|
|
1109
|
+
throw notFound(`Change ${change} has no task ${task}.`);
|
|
1110
|
+
let raised;
|
|
1111
|
+
try {
|
|
1112
|
+
raised = await raiseTaskPr(root, change, task, {
|
|
1113
|
+
approval: {
|
|
1114
|
+
by: user,
|
|
1115
|
+
at: (deps.now ? new Date(deps.now) : /* @__PURE__ */ new Date()).toISOString(),
|
|
1116
|
+
ref: `task ${task} of ${change}: push and PR (the app's Raise the task's PR)`
|
|
1117
|
+
},
|
|
1118
|
+
...deps.taskRun?.git ? { git: deps.taskRun.git } : {},
|
|
1119
|
+
...deps.gitHost ? { gitHost: deps.gitHost } : {}
|
|
1120
|
+
});
|
|
1121
|
+
} catch (e) {
|
|
1122
|
+
if (e instanceof Error && (e.name === "TaskRunError" || TASK_ERRORS.has(e.name)))
|
|
1123
|
+
throw refused({ code: 1, out: [], err: [e.message] });
|
|
1124
|
+
throw e;
|
|
1125
|
+
}
|
|
1126
|
+
ctx.events.publish({
|
|
1127
|
+
type: "file.changed",
|
|
1128
|
+
path: `${changesRelOf(root)}/${change}/tasks/${task}/task-run.yaml`
|
|
1129
|
+
});
|
|
1130
|
+
if (raised.state !== "pr-open")
|
|
1131
|
+
throw refused({
|
|
1132
|
+
code: 1,
|
|
1133
|
+
out: [],
|
|
1134
|
+
err: [raised.notes.at(-1) ?? "The PR wasn't raised."]
|
|
1135
|
+
});
|
|
1136
|
+
return {
|
|
1137
|
+
status: 201,
|
|
1138
|
+
body: (await taskViews(root, change, { ...deps.gitHost ? { gitHost: deps.gitHost } : {} })).find((t) => t.id === task)
|
|
632
1139
|
};
|
|
633
1140
|
}).add("POST", "/api/changes/{changeId}/workspace", async ({ params, body }) => {
|
|
634
1141
|
await readChange(root, params.changeId);
|
|
@@ -644,41 +1151,69 @@ function uiRoutes(r, ctx, deps = {}) {
|
|
|
644
1151
|
const res = await run((io) => changeHandoff(root, params.changeId, { by: user, approve: true, ...b.repo ? { repo: b.repo } : {} }, io, changeDeps));
|
|
645
1152
|
if (res.code !== 0)
|
|
646
1153
|
throw refused(res);
|
|
647
|
-
return {
|
|
1154
|
+
return {
|
|
1155
|
+
status: 201,
|
|
1156
|
+
body: { ...await changeDetail(root, params.changeId), notes: res.out }
|
|
1157
|
+
};
|
|
1158
|
+
}).add("POST", "/api/changes/{changeId}/release-prs", async ({ params, body }) => {
|
|
1159
|
+
const id = params.changeId;
|
|
1160
|
+
await readChange(root, id);
|
|
1161
|
+
parseBody(api_exports.ReleasePrsRequest, body);
|
|
1162
|
+
const res = await run((io) => changeReleasePrs(root, id, { by: user, approve: true }, io, changeDeps));
|
|
1163
|
+
ctx.events.publish({ type: "file.changed", path: `${id}/repos.yaml` });
|
|
1164
|
+
if (res.code !== 0)
|
|
1165
|
+
throw refused(res);
|
|
1166
|
+
return { status: 201, body: api_exports.LinesView.parse({ lines: res.out }) };
|
|
648
1167
|
}).add("POST", "/api/changes/{changeId}/sync", async ({ params, body }) => {
|
|
649
1168
|
await readChange(root, params.changeId);
|
|
650
1169
|
const b = parseBody(api_exports.SyncRequest, body);
|
|
651
1170
|
const res = await run((io) => changeSync(root, params.changeId, { by: user, approve: true, ...b.repo ? { repo: b.repo } : {} }, io, changeDeps));
|
|
652
1171
|
if (res.code === 2)
|
|
653
1172
|
throw refused(res);
|
|
1173
|
+
const { appLines } = await import("./chunk-J2O4LFVI.js");
|
|
654
1174
|
return {
|
|
655
1175
|
status: 200,
|
|
656
1176
|
body: {
|
|
657
1177
|
...await changeDetail(root, params.changeId),
|
|
658
|
-
lines: [...res.out, ...res.err]
|
|
1178
|
+
lines: appLines([...res.out, ...res.err])
|
|
659
1179
|
}
|
|
660
1180
|
};
|
|
661
1181
|
}).add("GET", "/api/changes/{changeId}/inputs", async ({ params }) => {
|
|
662
1182
|
const c = await readChange(root, params.changeId);
|
|
663
|
-
const { readChangeInputs } = await import("./chunk-
|
|
1183
|
+
const { readChangeInputs } = await import("./chunk-UDXWIPCB.js");
|
|
664
1184
|
return {
|
|
665
1185
|
status: 200,
|
|
666
1186
|
body: api_exports.ChangeInputList.parse(await readChangeInputs(join2(changesDirOf(root), c.id)))
|
|
667
1187
|
};
|
|
668
1188
|
}).add("GET", "/api/changes/{changeId}/prototypes", async ({ params }) => {
|
|
669
1189
|
const c = await readChange(root, params.changeId);
|
|
670
|
-
const { changePrototypes } = await import("./chunk-
|
|
1190
|
+
const { changePrototypes } = await import("./chunk-VYOCPTUB.js");
|
|
671
1191
|
return {
|
|
672
1192
|
status: 200,
|
|
673
1193
|
body: api_exports.ChangePrototypeList.parse(await changePrototypes(root, c.id))
|
|
674
1194
|
};
|
|
1195
|
+
}).add("POST", "/api/changes/{changeId}/prototypes", async ({ params, body }) => {
|
|
1196
|
+
const c = await readChange(root, params.changeId);
|
|
1197
|
+
const b = parseBody(api_exports.ComparePrototypeRequest, body);
|
|
1198
|
+
const { attachPrototype, changePrototypes } = await import("./chunk-VYOCPTUB.js");
|
|
1199
|
+
const res = await run((io) => attachPrototype(root, c.id, b.repo, { by: user, ...deps.now ? { now: new Date(deps.now) } : {} }, io));
|
|
1200
|
+
if (res.code !== 0)
|
|
1201
|
+
throw refused(res);
|
|
1202
|
+
ctx.events.publish({ type: "file.changed", path: `${changesRelOf(root)}/${c.id}/inputs` });
|
|
1203
|
+
return {
|
|
1204
|
+
status: 201,
|
|
1205
|
+
body: api_exports.ComparePrototypeView.parse({
|
|
1206
|
+
...await changePrototypes(root, c.id),
|
|
1207
|
+
lines: res.out
|
|
1208
|
+
})
|
|
1209
|
+
};
|
|
675
1210
|
}).add("POST", "/api/changes/{changeId}/inputs", async ({ params, body }) => {
|
|
676
1211
|
const c = await readChange(root, params.changeId);
|
|
677
1212
|
const b = parseBody(api_exports.AttachFileRequest, body);
|
|
678
1213
|
const bytes = new Uint8Array(Buffer.from(b.content, "base64"));
|
|
679
1214
|
if (bytes.length > MAX_ATTACH)
|
|
680
1215
|
throw new HttpError(413, "The file is too large", "Attach a file of 15 MB or less.");
|
|
681
|
-
const { attachFiles } = await import("./chunk-
|
|
1216
|
+
const { attachFiles } = await import("./chunk-XQ3YZ4QW.js");
|
|
682
1217
|
const r2 = await attachFiles(root, c.id, [{ name: b.name, bytes }], user);
|
|
683
1218
|
if (!r2.added.length)
|
|
684
1219
|
throw new HttpError(422, "Atticus can't attach that", r2.refused[0]?.why ?? "", {
|
|
@@ -700,15 +1235,42 @@ function uiRoutes(r, ctx, deps = {}) {
|
|
|
700
1235
|
const b = parseBody(api_exports.StartRunRequest, body);
|
|
701
1236
|
const before = new Set(await readdir(join2(runsDirOf(root), params.changeId)).catch(() => []));
|
|
702
1237
|
let res;
|
|
703
|
-
if (b.task)
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
1238
|
+
if (b.task) {
|
|
1239
|
+
let level = b.autonomy ? b.autonomy === "draft-and-pr" ? "pr" : b.autonomy === "plan-only" ? "plan" : "draft" : void 0;
|
|
1240
|
+
if (level === "pr")
|
|
1241
|
+
throw refused({
|
|
1242
|
+
code: 1,
|
|
1243
|
+
out: [],
|
|
1244
|
+
err: [
|
|
1245
|
+
"The pr level pushes the task branch and opens a PR, which needs the person's yes: start it from VS Code, IntelliJ or the command line (atticus task run <change> <task> --level pr --approve)."
|
|
1246
|
+
]
|
|
1247
|
+
});
|
|
1248
|
+
if (!level) {
|
|
1249
|
+
try {
|
|
1250
|
+
const p = await previewTaskRun(root, params.changeId, b.task, {
|
|
1251
|
+
skipGitHost: true,
|
|
1252
|
+
...deps.gitHost ? { gitHost: deps.gitHost } : {}
|
|
1253
|
+
});
|
|
1254
|
+
level = p.level === "pr" ? "draft" : p.level;
|
|
1255
|
+
} catch (e) {
|
|
1256
|
+
if (e instanceof Error && e.name === "TaskRunError")
|
|
1257
|
+
throw conflict(e.message);
|
|
1258
|
+
if (e instanceof Error && TASK_ERRORS.has(e.name))
|
|
1259
|
+
throw refused({ code: 1, out: [], err: [e.message] });
|
|
1260
|
+
throw e;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
const lv = level;
|
|
1264
|
+
const opened = await openTaskWorktree(root, params.changeId, b.task, deps.gitHost);
|
|
1265
|
+
if (opened && opened.code !== 0)
|
|
1266
|
+
throw refused(opened);
|
|
1267
|
+
res = await run((io) => taskRun(root, params.changeId, b.task, { mode: b.runtime, by: user, level: lv }, io, {
|
|
1268
|
+
...deps.gitHost ? { gitHost: deps.gitHost } : {},
|
|
1269
|
+
...deps.taskRun?.git ? { git: deps.taskRun.git } : {}
|
|
1270
|
+
}));
|
|
1271
|
+
if (opened)
|
|
1272
|
+
res = { ...res, out: [...opened.out, ...res.out] };
|
|
1273
|
+
} else if (b.agent === "story-writer")
|
|
712
1274
|
res = await run((io) => planStories(root, params.changeId, { mode: b.runtime }, io));
|
|
713
1275
|
else if (b.agent.endsWith("-critic"))
|
|
714
1276
|
res = await run((io) => critic(root, params.changeId, { mode: b.runtime }, io));
|
|
@@ -759,32 +1321,110 @@ function uiRoutes(r, ctx, deps = {}) {
|
|
|
759
1321
|
const before = await findRun(root, params.runId);
|
|
760
1322
|
if (before.state === "validated" || before.state === "cancelled")
|
|
761
1323
|
throw conflict(`Run ${params.runId} is already ${before.state}.`);
|
|
762
|
-
|
|
1324
|
+
if (doneBusy.has(params.runId))
|
|
1325
|
+
throw conflict(`Done for ${params.runId} is already running; wait for it to finish.`);
|
|
1326
|
+
doneBusy.add(params.runId);
|
|
1327
|
+
let res;
|
|
1328
|
+
try {
|
|
1329
|
+
res = await run((io) => runDone(root, params.runId, { by: user }, io, deps.taskRun));
|
|
1330
|
+
} finally {
|
|
1331
|
+
doneBusy.delete(params.runId);
|
|
1332
|
+
}
|
|
763
1333
|
const after = await findRun(root, params.runId);
|
|
764
1334
|
ctx.events.publish({ type: "run.changed", runId: after.runId, state: after.state });
|
|
765
|
-
|
|
1335
|
+
const { resumeAfterDone, appLines } = await import("./chunk-J2O4LFVI.js");
|
|
1336
|
+
if (res.code !== 0)
|
|
1337
|
+
throw refused({ ...res, out: appLines(res.out), err: appLines(res.err) });
|
|
1338
|
+
const stepRunner = deps.runStep ?? (async (args) => {
|
|
1339
|
+
const { main } = await import("./chunk-7FHNFCHK.js");
|
|
1340
|
+
const out = [];
|
|
1341
|
+
const err = [];
|
|
1342
|
+
const code = await main([...args, "--root", root], { out: (l) => out.push(l), err: (l) => err.push(l) }, { quiet: true });
|
|
1343
|
+
return { code, out, err };
|
|
1344
|
+
});
|
|
1345
|
+
const resumed = await resumeAfterDone(root, stepRunner, after.change, after.runId).catch((e) => ({ lines: [e.message] }));
|
|
1346
|
+
if (resumed)
|
|
1347
|
+
ctx.events.publish({ type: "file.changed", path: changesRelOf(root) });
|
|
1348
|
+
return {
|
|
1349
|
+
status: 200,
|
|
1350
|
+
body: {
|
|
1351
|
+
...after,
|
|
1352
|
+
// When the app resumed the step, runDone's "run the step again with --resume" is done;
|
|
1353
|
+
// sixth UX walk: what is left to do is said in the app's words.
|
|
1354
|
+
lines: [
|
|
1355
|
+
...resumed ? appLines([...res.out, ...res.err].filter((l) => !/--resume run-/.test(l))) : [...res.out, ...res.err],
|
|
1356
|
+
...resumed?.lines ?? []
|
|
1357
|
+
],
|
|
1358
|
+
...resumed?.next ? { next: resumed.next } : {}
|
|
1359
|
+
}
|
|
1360
|
+
};
|
|
766
1361
|
}).add("POST", "/api/runs/{runId}/retry", async ({ params }) => {
|
|
767
1362
|
const v = await findRun(root, params.runId);
|
|
768
1363
|
if (v.state !== "failed")
|
|
769
1364
|
throw conflict(`Only a failed run can be retried; ${v.runId} is ${v.state}.`);
|
|
1365
|
+
const owner = await findTaskRunOfRun(root, v.runId);
|
|
1366
|
+
if (owner && owner.waiting !== v.runId)
|
|
1367
|
+
throw conflict(taskRunNotWaiting(v.runId, owner));
|
|
770
1368
|
const file = join2(runsDirOf(root), v.change, v.runId, "run.json");
|
|
771
|
-
const
|
|
1369
|
+
const was = await readFile(file, "utf8");
|
|
1370
|
+
const rec = JSON.parse(was);
|
|
772
1371
|
rec.state = "prepared";
|
|
773
1372
|
rec.attempt = (rec.attempt ?? 1) + 1;
|
|
774
1373
|
rec.errors = [];
|
|
775
|
-
await
|
|
1374
|
+
await writeFileIfUnchanged(file, was, JSON.stringify(rec, null, 2) + "\n");
|
|
776
1375
|
const after = await findRun(root, params.runId);
|
|
777
1376
|
ctx.events.publish({ type: "run.changed", runId: after.runId, state: after.state });
|
|
778
1377
|
return { status: 200, body: after };
|
|
779
1378
|
}).add("POST", "/api/runs/{runId}/cancel", async ({ params }) => {
|
|
1379
|
+
const here = await findRun(root, params.runId).catch(() => void 0);
|
|
1380
|
+
if (!here) {
|
|
1381
|
+
let ended;
|
|
1382
|
+
try {
|
|
1383
|
+
ended = await cancelTaskRunWait(root, params.runId, { by: user });
|
|
1384
|
+
} catch (e) {
|
|
1385
|
+
if (e instanceof Error && e.name === "TaskRunError")
|
|
1386
|
+
throw conflict(e.message);
|
|
1387
|
+
throw e;
|
|
1388
|
+
}
|
|
1389
|
+
if (!ended)
|
|
1390
|
+
throw notFound(`There is no run ${params.runId}.`);
|
|
1391
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1392
|
+
const body = {
|
|
1393
|
+
schemaVersion: RUN_SCHEMA_VERSION,
|
|
1394
|
+
runId: params.runId,
|
|
1395
|
+
change: ended.change,
|
|
1396
|
+
agent: "task-runner",
|
|
1397
|
+
runtime: "hand-off",
|
|
1398
|
+
state: "cancelled",
|
|
1399
|
+
startedAt: ended.startedAt,
|
|
1400
|
+
finishedAt: at,
|
|
1401
|
+
contextManifestSha256: sha(""),
|
|
1402
|
+
errors: [],
|
|
1403
|
+
attempt: 1
|
|
1404
|
+
};
|
|
1405
|
+
ctx.events.publish({ type: "run.changed", runId: params.runId, state: "cancelled" });
|
|
1406
|
+
return { status: 200, body };
|
|
1407
|
+
}
|
|
780
1408
|
const v = await findRun(root, params.runId);
|
|
781
1409
|
if (["validated", "cancelled"].includes(v.state))
|
|
782
1410
|
throw conflict(`Run ${v.runId} is already ${v.state}.`);
|
|
1411
|
+
if (doneBusy.has(v.runId))
|
|
1412
|
+
throw conflict(`Done for ${v.runId} is running; wait for it to finish.`);
|
|
783
1413
|
const file = join2(runsDirOf(root), v.change, v.runId, "run.json");
|
|
784
|
-
const
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
1414
|
+
const cancelRun = async () => {
|
|
1415
|
+
const was = await readFile(file, "utf8");
|
|
1416
|
+
const rec = JSON.parse(was);
|
|
1417
|
+
rec.state = "cancelled";
|
|
1418
|
+
rec.finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1419
|
+
await writeFileIfUnchanged(file, was, JSON.stringify(rec, null, 2) + "\n");
|
|
1420
|
+
};
|
|
1421
|
+
try {
|
|
1422
|
+
await cancelTaskRunWait(root, v.runId, { by: user, cancelRun });
|
|
1423
|
+
} catch (e) {
|
|
1424
|
+
if (e instanceof Error && e.name === "TaskRunError")
|
|
1425
|
+
throw conflict(e.message);
|
|
1426
|
+
throw e;
|
|
1427
|
+
}
|
|
788
1428
|
const after = await findRun(root, params.runId);
|
|
789
1429
|
ctx.events.publish({ type: "run.changed", runId: after.runId, state: after.state });
|
|
790
1430
|
return { status: 200, body: after };
|
|
@@ -867,8 +1507,10 @@ function uiRoutes(r, ctx, deps = {}) {
|
|
|
867
1507
|
}
|
|
868
1508
|
|
|
869
1509
|
// packages/cli/dist/ui-api-run.js
|
|
870
|
-
var
|
|
871
|
-
import {
|
|
1510
|
+
var import_yaml2 = __toESM(require_dist(), 1);
|
|
1511
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
1512
|
+
import { readdir as readdir2, readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
1513
|
+
import { homedir } from "node:os";
|
|
872
1514
|
import { join as join3, resolve } from "node:path";
|
|
873
1515
|
async function run2(f) {
|
|
874
1516
|
const out = [];
|
|
@@ -925,7 +1567,7 @@ async function latestFindings2(root, change) {
|
|
|
925
1567
|
}
|
|
926
1568
|
return out;
|
|
927
1569
|
}
|
|
928
|
-
async function
|
|
1570
|
+
async function filesUnder2(dir, prefix = "") {
|
|
929
1571
|
const out = [];
|
|
930
1572
|
let entries;
|
|
931
1573
|
try {
|
|
@@ -936,9 +1578,9 @@ async function filesUnder(dir, prefix = "") {
|
|
|
936
1578
|
for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
937
1579
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
938
1580
|
if (e.isDirectory())
|
|
939
|
-
out.push(...await
|
|
1581
|
+
out.push(...await filesUnder2(join3(dir, e.name), rel));
|
|
940
1582
|
else
|
|
941
|
-
out.push({ path: rel, bytes: (await
|
|
1583
|
+
out.push({ path: rel, bytes: (await stat2(join3(dir, e.name))).size });
|
|
942
1584
|
}
|
|
943
1585
|
return out;
|
|
944
1586
|
}
|
|
@@ -998,6 +1640,8 @@ async function findStep(root, id, change) {
|
|
|
998
1640
|
throw notFound(`There is no step ${stepRef(id, change)}.`);
|
|
999
1641
|
return s;
|
|
1000
1642
|
}
|
|
1643
|
+
var sha2 = (s) => createHash2("sha256").update(s).digest("hex");
|
|
1644
|
+
var snowText = (dir) => readFile2(join3(dir, "snow.md"), "utf8").catch(() => "");
|
|
1001
1645
|
var SyncEntries = external_exports.object({
|
|
1002
1646
|
requests: external_exports.array(external_exports.object({ key: external_exports.string(), id: external_exports.string() })).default([])
|
|
1003
1647
|
});
|
|
@@ -1006,9 +1650,13 @@ async function changeRequests(root, change, templates, steps) {
|
|
|
1006
1650
|
const drafts = readSnowDrafts(await readChangeFiles(dir));
|
|
1007
1651
|
if (drafts.length === 0)
|
|
1008
1652
|
return [];
|
|
1653
|
+
const snow = {
|
|
1654
|
+
file: `${changesRelOf(root)}/${change}/snow.md`,
|
|
1655
|
+
sha256: sha2(await snowText(dir))
|
|
1656
|
+
};
|
|
1009
1657
|
let synced = [];
|
|
1010
1658
|
try {
|
|
1011
|
-
synced = SyncEntries.parse((0,
|
|
1659
|
+
synced = SyncEntries.parse((0, import_yaml2.parse)(await readFile2(join3(dir, SYNC_FILE), "utf8"))).requests;
|
|
1012
1660
|
} catch {
|
|
1013
1661
|
}
|
|
1014
1662
|
return drafts.map((d) => {
|
|
@@ -1028,7 +1676,8 @@ async function changeRequests(root, change, templates, steps) {
|
|
|
1028
1676
|
record,
|
|
1029
1677
|
approvers: t?.approvers ?? [],
|
|
1030
1678
|
fields,
|
|
1031
|
-
missing: fields.filter((f) => f.required && !f.value.trim()).map((f) => f.name)
|
|
1679
|
+
missing: fields.filter((f) => f.required && !f.value.trim()).map((f) => f.name),
|
|
1680
|
+
...snow
|
|
1032
1681
|
};
|
|
1033
1682
|
const entry = t ? synced.find((e) => e.key === `${t.id}|${record}`) : void 0;
|
|
1034
1683
|
if (!entry)
|
|
@@ -1079,6 +1728,23 @@ function uiRunRoutes(r, ctx, deps = {}) {
|
|
|
1079
1728
|
const nowDate = deps.now ? () => new Date(deps.now) : void 0;
|
|
1080
1729
|
const pack = () => loadOrgPack(orgPackDirOf(root));
|
|
1081
1730
|
const rel = deps.now ? { now: () => new Date(deps.now) } : {};
|
|
1731
|
+
const syncAfterStep = async (s) => {
|
|
1732
|
+
if (s.system !== "git-host" || !s.change || s.state === "open")
|
|
1733
|
+
return void 0;
|
|
1734
|
+
const c = await changeStore(root).tryRead(s.change).catch(() => void 0);
|
|
1735
|
+
const live = c && c.state !== "returned" ? liveHandoff(c) : void 0;
|
|
1736
|
+
const steps = await fileStepStore(root).list({ change: s.change, system: "git-host" });
|
|
1737
|
+
const open = s.action === "open-pull-request" ? s : steps.find((x) => x.action === "open-pull-request" && s.dependsOn.includes(x.id));
|
|
1738
|
+
if (!live || !open || open.inputs.head !== live.branch)
|
|
1739
|
+
return void 0;
|
|
1740
|
+
const repo = typeof open.inputs.repo === "string" ? open.inputs.repo : void 0;
|
|
1741
|
+
const res = await run2((io) => changeSync(root, s.change, { by: user, ...repo ? { repo } : {} }, io, {
|
|
1742
|
+
...deps.gitHost ? { gitHost: deps.gitHost } : {},
|
|
1743
|
+
...deps.now ? { now: deps.now } : {}
|
|
1744
|
+
}));
|
|
1745
|
+
ctx.events.publish({ type: "file.changed", path: `${changesRelOf(root)}/${s.change}` });
|
|
1746
|
+
return [...res.out, ...res.err];
|
|
1747
|
+
};
|
|
1082
1748
|
return r.add("GET", "/api/todo", async ({ query }) => {
|
|
1083
1749
|
const change = strParam(query, "change");
|
|
1084
1750
|
const op = await pack();
|
|
@@ -1153,7 +1819,8 @@ function uiRunRoutes(r, ctx, deps = {}) {
|
|
|
1153
1819
|
}
|
|
1154
1820
|
ctx.events.publish({ type: "file.changed", path: `steps/${params.stepId}` });
|
|
1155
1821
|
const s = await findStep(root, params.stepId, b.change);
|
|
1156
|
-
|
|
1822
|
+
const synced = await syncAfterStep(s);
|
|
1823
|
+
return { status: 200, body: { ...s, lines: res.out, ...synced ? { synced } : {} } };
|
|
1157
1824
|
}).add("GET", "/api/todo/{stepId}/run", async ({ params, query }) => {
|
|
1158
1825
|
const s = await findStep(root, params.stepId, strParam(query, "change"));
|
|
1159
1826
|
const op = await pack();
|
|
@@ -1226,6 +1893,38 @@ function uiRunRoutes(r, ctx, deps = {}) {
|
|
|
1226
1893
|
throw refused2(res);
|
|
1227
1894
|
ctx.events.publish({ type: "file.changed", path: `${params.changeId}/snow.md` });
|
|
1228
1895
|
return { status: 200, body: { lines: res.out, toFill: res.code === 1 } };
|
|
1896
|
+
}).add("PUT", "/api/service-desk/{changeId}/fields", async ({ params, body }) => {
|
|
1897
|
+
const c = await readChange2(root, params.changeId);
|
|
1898
|
+
const b = parseBody2(api_exports.FillRequestFieldsRequest, body);
|
|
1899
|
+
const dir = changeFolder(root, c.id);
|
|
1900
|
+
const rel2 = `${changesRelOf(root)}/${c.id}/snow.md`;
|
|
1901
|
+
const was = await readFile2(join3(dir, "snow.md"), "utf8").catch(() => void 0);
|
|
1902
|
+
if (was === void 0)
|
|
1903
|
+
throw notFound(`${c.id} has no snow.md: draft its requests first.`);
|
|
1904
|
+
if (sha2(was) !== b.baseSha256)
|
|
1905
|
+
throw conflict(`${rel2} changed since you opened it (another edit, or a person's): reload the page and fill the fields again.`);
|
|
1906
|
+
let next;
|
|
1907
|
+
try {
|
|
1908
|
+
next = fillSnowFields(was, b.heading, b.values);
|
|
1909
|
+
} catch (e) {
|
|
1910
|
+
if (e instanceof SnowFillError)
|
|
1911
|
+
throw new HttpError(422, "Atticus can't fill that", e.message);
|
|
1912
|
+
throw e;
|
|
1913
|
+
}
|
|
1914
|
+
await writeFileIfUnchanged(join3(dir, "snow.md"), was, next);
|
|
1915
|
+
ctx.events.publish({ type: "file.changed", path: rel2 });
|
|
1916
|
+
const op = await pack();
|
|
1917
|
+
const now = (await changeRequests(root, c.id, op.serviceRequests, [])).find((r2) => r2.heading === b.heading);
|
|
1918
|
+
const names = Object.keys(b.values).join(", ");
|
|
1919
|
+
return {
|
|
1920
|
+
status: 200,
|
|
1921
|
+
body: {
|
|
1922
|
+
path: rel2,
|
|
1923
|
+
sha256: sha2(next),
|
|
1924
|
+
missing: now?.missing ?? [],
|
|
1925
|
+
lines: [`Filled ${names} in ${rel2}.`]
|
|
1926
|
+
}
|
|
1927
|
+
};
|
|
1229
1928
|
}).add("POST", "/api/service-desk/{changeId}/submit", async ({ params }) => {
|
|
1230
1929
|
await readChange2(root, params.changeId);
|
|
1231
1930
|
const op = await pack();
|
|
@@ -1320,7 +2019,7 @@ function uiRunRoutes(r, ctx, deps = {}) {
|
|
|
1320
2019
|
} : {},
|
|
1321
2020
|
conflicts,
|
|
1322
2021
|
archive: { pass: archive.pass, blockers: archive.blockers, notes: archive.notes },
|
|
1323
|
-
evidence: await
|
|
2022
|
+
evidence: await filesUnder2(changeFolder(root, id))
|
|
1324
2023
|
}
|
|
1325
2024
|
};
|
|
1326
2025
|
}).add("POST", "/api/release/{changeId}/archive", async ({ params, body }) => {
|
|
@@ -1497,7 +2196,7 @@ function uiRunRoutes(r, ctx, deps = {}) {
|
|
|
1497
2196
|
const { lessons, problems } = await lessonsFor(root);
|
|
1498
2197
|
const sandbox = await isSandbox(root);
|
|
1499
2198
|
const progress = sandbox ? await readProgress(root) : void 0;
|
|
1500
|
-
const
|
|
2199
|
+
const view3 = lessons.map((l) => {
|
|
1501
2200
|
const p = progress?.lessons[l.id];
|
|
1502
2201
|
const done = p ? l.steps.filter((s) => p.steps[s.id]).length : 0;
|
|
1503
2202
|
return {
|
|
@@ -1513,8 +2212,8 @@ function uiRunRoutes(r, ctx, deps = {}) {
|
|
|
1513
2212
|
});
|
|
1514
2213
|
const roles = [...new Set(lessons.map((l) => l.role))].map((role) => ({
|
|
1515
2214
|
role,
|
|
1516
|
-
lessons:
|
|
1517
|
-
done:
|
|
2215
|
+
lessons: view3.filter((v) => v.role === role).length,
|
|
2216
|
+
done: view3.filter((v) => v.role === role && v.state === "done").length
|
|
1518
2217
|
}));
|
|
1519
2218
|
const cur = progress?.current ? lessons.find((l) => l.id === progress.current) : void 0;
|
|
1520
2219
|
const lp = cur ? progress.lessons[cur.id] : void 0;
|
|
@@ -1524,7 +2223,7 @@ function uiRunRoutes(r, ctx, deps = {}) {
|
|
|
1524
2223
|
body: {
|
|
1525
2224
|
sandbox,
|
|
1526
2225
|
roles,
|
|
1527
|
-
lessons:
|
|
2226
|
+
lessons: view3,
|
|
1528
2227
|
...cur ? {
|
|
1529
2228
|
current: {
|
|
1530
2229
|
lesson: cur.id,
|
|
@@ -1564,7 +2263,8 @@ function uiRunRoutes(r, ctx, deps = {}) {
|
|
|
1564
2263
|
return { status: 200, body: { ...out, ...hint ? { hint } : {} } };
|
|
1565
2264
|
}).add("POST", "/api/learning/sandbox", async ({ body }) => {
|
|
1566
2265
|
const b = parseBody2(api_exports.SandboxRequest, body);
|
|
1567
|
-
const
|
|
2266
|
+
const dir = b.dir.replace(/^~(?=$|[\\/])/, homedir());
|
|
2267
|
+
const res = await run2((io) => sandboxCreate(resolve(root, dir), { json: true }, io, nowDate ? { now: nowDate() } : {}));
|
|
1568
2268
|
const out = jsonOf(res);
|
|
1569
2269
|
if (res.code !== 0 || !out)
|
|
1570
2270
|
throw refused2(res);
|
|
@@ -1736,10 +2436,10 @@ function uiKnowRoutes(r, ctx, o = {}) {
|
|
|
1736
2436
|
let checked;
|
|
1737
2437
|
const machine = (fresh = false) => {
|
|
1738
2438
|
if (fresh || !checked || Date.now() - checked.at > 3e5) {
|
|
1739
|
-
const
|
|
1740
|
-
checked =
|
|
1741
|
-
|
|
1742
|
-
if (checked ===
|
|
2439
|
+
const run4 = { at: Date.now(), checks: doctor(ctx.root) };
|
|
2440
|
+
checked = run4;
|
|
2441
|
+
run4.checks.catch(() => {
|
|
2442
|
+
if (checked === run4)
|
|
1743
2443
|
checked = void 0;
|
|
1744
2444
|
});
|
|
1745
2445
|
}
|
|
@@ -1747,7 +2447,7 @@ function uiKnowRoutes(r, ctx, o = {}) {
|
|
|
1747
2447
|
};
|
|
1748
2448
|
if (o.warm)
|
|
1749
2449
|
void machine().catch(() => void 0);
|
|
1750
|
-
const
|
|
2450
|
+
const view3 = async (name, arg) => {
|
|
1751
2451
|
const build = VIEWS[name];
|
|
1752
2452
|
if (!build)
|
|
1753
2453
|
throw notFound(`There is no view ${name}.`);
|
|
@@ -1756,7 +2456,7 @@ function uiKnowRoutes(r, ctx, o = {}) {
|
|
|
1756
2456
|
const args = build(arg);
|
|
1757
2457
|
if (!args)
|
|
1758
2458
|
throw badRequest(`The ${name} view needs an id: /api/view/${name}/<id>.`);
|
|
1759
|
-
const { main } = await import("./chunk-
|
|
2459
|
+
const { main } = await import("./chunk-7FHNFCHK.js");
|
|
1760
2460
|
const out = [];
|
|
1761
2461
|
const err = [];
|
|
1762
2462
|
const code = await main([...args, "--json", "--root", ctx.root], { out: (l) => out.push(l), err: (l) => err.push(l) }, { quiet: true });
|
|
@@ -1773,6 +2473,12 @@ function uiKnowRoutes(r, ctx, o = {}) {
|
|
|
1773
2473
|
} catch {
|
|
1774
2474
|
body = void 0;
|
|
1775
2475
|
}
|
|
2476
|
+
if (body === null && code !== 0) {
|
|
2477
|
+
const words = err.join("\n").trim() || "The command gave no answer.";
|
|
2478
|
+
if (/^(There is no|No .+ (is|named) )/i.test(words))
|
|
2479
|
+
throw notFound(words);
|
|
2480
|
+
throw new HttpError(422, "Atticus can't show that yet", words, scanFirst(words) ? { notYet: true } : void 0);
|
|
2481
|
+
}
|
|
1776
2482
|
if (body === void 0) {
|
|
1777
2483
|
const words = [...err, ...out].join("\n") || "No output.";
|
|
1778
2484
|
throw new HttpError(422, "Atticus can't show that yet", words, scanFirst(words) ? { notYet: true } : void 0);
|
|
@@ -1780,7 +2486,7 @@ function uiKnowRoutes(r, ctx, o = {}) {
|
|
|
1780
2486
|
return { status: 200, body: { code, data: body, problems: err } };
|
|
1781
2487
|
};
|
|
1782
2488
|
const text = async (args) => {
|
|
1783
|
-
const { main } = await import("./chunk-
|
|
2489
|
+
const { main } = await import("./chunk-7FHNFCHK.js");
|
|
1784
2490
|
const out = [];
|
|
1785
2491
|
const err = [];
|
|
1786
2492
|
const code = await main([...args, "--root", ctx.root], { out: (l) => out.push(l), err: (l) => err.push(l) }, { quiet: true });
|
|
@@ -1798,7 +2504,7 @@ function uiKnowRoutes(r, ctx, o = {}) {
|
|
|
1798
2504
|
throw badRequest("Some fields aren't right.", {
|
|
1799
2505
|
errors: b.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }))
|
|
1800
2506
|
});
|
|
1801
|
-
const { triageDecide } = await import("./chunk-
|
|
2507
|
+
const { triageDecide } = await import("./chunk-ZKYRDV7A.js");
|
|
1802
2508
|
const out = [];
|
|
1803
2509
|
const err = [];
|
|
1804
2510
|
const code = await triageDecide(ctx.root, params.itemId, b.data.option, { by: ctx.user, ...b.data.reason ? { reason: b.data.reason } : {} }, { out: (l) => out.push(l), err: (l) => err.push(l) });
|
|
@@ -1882,7 +2588,96 @@ function uiKnowRoutes(r, ctx, o = {}) {
|
|
|
1882
2588
|
throw new HttpError(422, "Atticus can't show that yet", words, scanFirst(words) ? { notYet: true } : void 0);
|
|
1883
2589
|
}
|
|
1884
2590
|
return { status: 200, body: { view: JSON.parse(out) } };
|
|
1885
|
-
}).add("GET", "/api/
|
|
2591
|
+
}).add("GET", "/api/coverage", async () => {
|
|
2592
|
+
const r2 = await view3("coverage");
|
|
2593
|
+
const data = r2.body.data;
|
|
2594
|
+
return { status: 200, body: data?.api ?? { areas: [], systems: [] } };
|
|
2595
|
+
}).add("GET", "/api/view/{name}", ({ params }) => view3(params.name)).add("GET", "/api/view/{name}/{id}", ({ params }) => view3(params.name, params.id));
|
|
2596
|
+
}
|
|
2597
|
+
|
|
2598
|
+
// packages/cli/dist/ui-api-initiatives.js
|
|
2599
|
+
var ID2 = /^[a-z0-9][a-z0-9._-]*$/;
|
|
2600
|
+
async function run3(f) {
|
|
2601
|
+
const out = [];
|
|
2602
|
+
const err = [];
|
|
2603
|
+
const code = await f({ out: (l) => out.push(l), err: (l) => err.push(l) });
|
|
2604
|
+
return { code, out, err };
|
|
2605
|
+
}
|
|
2606
|
+
function parseBody3(schema, body) {
|
|
2607
|
+
const r = schema.safeParse(body ?? {});
|
|
2608
|
+
if (!r.success)
|
|
2609
|
+
throw badRequest("Some fields aren't right.", {
|
|
2610
|
+
errors: r.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }))
|
|
2611
|
+
});
|
|
2612
|
+
return r.data;
|
|
2613
|
+
}
|
|
2614
|
+
function refused3(r) {
|
|
2615
|
+
const detail = [...r.err, ...r.out].join("\n") || "Atticus refused.";
|
|
2616
|
+
if (/^There is no (initiative|commitment) /m.test(detail))
|
|
2617
|
+
return notFound(detail);
|
|
2618
|
+
if (/already exists/.test(detail))
|
|
2619
|
+
return conflict(detail);
|
|
2620
|
+
return r.code === 2 ? badRequest(detail) : new HttpError(422, "Atticus refused", detail);
|
|
2621
|
+
}
|
|
2622
|
+
function uiInitiativeRoutes(r, ctx) {
|
|
2623
|
+
const commands = () => import("./chunk-AE4P57KK.js");
|
|
2624
|
+
const changed = () => ctx.events.publish({ type: "file.changed", path: "catalog/curated" });
|
|
2625
|
+
return r.add("POST", "/api/initiatives", async ({ body }) => {
|
|
2626
|
+
const b = parseBody3(api_exports.NewInitiativeRequest, body);
|
|
2627
|
+
const { initiativeNew } = await commands();
|
|
2628
|
+
const res = await run3((io) => initiativeNew(ctx.root, {
|
|
2629
|
+
title: b.title,
|
|
2630
|
+
journey: b.journey,
|
|
2631
|
+
by: ctx.user,
|
|
2632
|
+
...b.id ? { id: b.id } : {},
|
|
2633
|
+
...b.release ? { release: b.release } : {},
|
|
2634
|
+
...b.epic ? { epic: b.epic } : {},
|
|
2635
|
+
json: true
|
|
2636
|
+
}, io));
|
|
2637
|
+
if (res.code !== 0)
|
|
2638
|
+
throw refused3(res);
|
|
2639
|
+
const made = JSON.parse(res.out.join("\n"));
|
|
2640
|
+
changed();
|
|
2641
|
+
return {
|
|
2642
|
+
status: 201,
|
|
2643
|
+
body: {
|
|
2644
|
+
initiative: made.initiative.id,
|
|
2645
|
+
lines: [
|
|
2646
|
+
`Started ${made.initiative.id} (${made.initiative.journey}). Wrote ${made.written}.`
|
|
2647
|
+
]
|
|
2648
|
+
}
|
|
2649
|
+
};
|
|
2650
|
+
}).add("POST", "/api/initiatives/{initiativeId}/plan", async ({ params, body }) => {
|
|
2651
|
+
const id = params.initiativeId;
|
|
2652
|
+
if (!ID2.test(id))
|
|
2653
|
+
throw badRequest(`${id} isn't an id.`);
|
|
2654
|
+
const b = parseBody3(api_exports.InitiativePlanRequest, body);
|
|
2655
|
+
const { initiativePlan } = await commands();
|
|
2656
|
+
const res = await run3((io) => initiativePlan(ctx.root, id, {
|
|
2657
|
+
by: ctx.user,
|
|
2658
|
+
...b.target ? { target: b.target } : {},
|
|
2659
|
+
...b.release ? { release: b.release } : {},
|
|
2660
|
+
...b.systems?.length ? { systems: b.systems } : {}
|
|
2661
|
+
}, io));
|
|
2662
|
+
if (res.code !== 0)
|
|
2663
|
+
throw refused3(res);
|
|
2664
|
+
changed();
|
|
2665
|
+
return { status: 200, body: { initiative: id, lines: res.out } };
|
|
2666
|
+
}).add("POST", "/api/commitments/{commitmentId}/status", async ({ params, body }) => {
|
|
2667
|
+
const id = params.commitmentId;
|
|
2668
|
+
if (!ID2.test(id))
|
|
2669
|
+
throw badRequest(`${id} isn't an id.`);
|
|
2670
|
+
const b = parseBody3(api_exports.CommitmentStatusRequest, body);
|
|
2671
|
+
const c = (await readView(ctx.root)).get("Commitment", id);
|
|
2672
|
+
if (!c)
|
|
2673
|
+
throw notFound(`There is no commitment ${id}.`);
|
|
2674
|
+
const { initiativeCommitment } = await commands();
|
|
2675
|
+
const res = await run3((io) => initiativeCommitment(ctx.root, id, b.status, { by: ctx.user, ...b.note ? { note: b.note } : {} }, io));
|
|
2676
|
+
if (res.code !== 0)
|
|
2677
|
+
throw refused3(res);
|
|
2678
|
+
changed();
|
|
2679
|
+
return { status: 200, body: { initiative: c.initiative, lines: res.out } };
|
|
2680
|
+
});
|
|
1886
2681
|
}
|
|
1887
2682
|
|
|
1888
2683
|
// packages/cli/dist/ui-api-questions.js
|
|
@@ -1895,16 +2690,79 @@ function uiQuestionRoutes(r, ctx, deps = {}) {
|
|
|
1895
2690
|
const mine = strParam(query, "mine");
|
|
1896
2691
|
if (mine !== void 0 && mine !== "true")
|
|
1897
2692
|
throw badRequest("mine is true, or left out.");
|
|
1898
|
-
const
|
|
1899
|
-
|
|
1900
|
-
|
|
2693
|
+
const change = strParam(query, "change");
|
|
2694
|
+
if (change !== void 0 && !RecordId.safeParse(change).success)
|
|
2695
|
+
throw badRequest("change is a change's id, or left out.");
|
|
2696
|
+
const role = strParam(query, "role");
|
|
2697
|
+
if (role !== void 0 && !QuestionRole.safeParse(role).success)
|
|
2698
|
+
throw badRequest("role is product, architecture, analysis or delivery, or left out.");
|
|
2699
|
+
const onFile = await listQuestions(ctx.root);
|
|
2700
|
+
const every = { ...onFile, questions: onFile.questions.filter((q) => !q.finding) };
|
|
2701
|
+
const { routeQuestions } = await import("./chunk-Z3QFH7YG.js");
|
|
2702
|
+
const routedAll = await routeQuestions(ctx.root, every.questions, mine ? { mine: ctx.user } : {});
|
|
2703
|
+
const { stageQuestions, roleWithStage, isChangeQuestion, countByRole, personsRoles } = await import("./chunk-KYZMRSPS.js");
|
|
2704
|
+
const stages = await stageQuestions(ctx.root);
|
|
2705
|
+
const roleOf = (q) => roleWithStage(q, stages);
|
|
2706
|
+
for (const q of every.questions) {
|
|
2707
|
+
const r2 = roleOf(q);
|
|
2708
|
+
const a = routedAll.about[q.id];
|
|
2709
|
+
if (r2 && a)
|
|
2710
|
+
a.role = r2;
|
|
2711
|
+
}
|
|
2712
|
+
const base = change ? routedAll.questions.filter((q) => isChangeQuestion(q, change, { stages, restsOn: routedAll.about[q.id]?.restsOn })) : routedAll.questions;
|
|
2713
|
+
const routed = {
|
|
2714
|
+
...routedAll,
|
|
2715
|
+
questions: base.filter((q) => (!state || q.state === state) && (!role || roleOf(q) === role))
|
|
2716
|
+
};
|
|
2717
|
+
const listed = { problems: every.problems };
|
|
2718
|
+
const n = (s) => base.filter((q) => q.state === s).length;
|
|
1901
2719
|
const body = {
|
|
2720
|
+
counts: {
|
|
2721
|
+
open: n("open"),
|
|
2722
|
+
answered: n("answered"),
|
|
2723
|
+
retired: n("retired"),
|
|
2724
|
+
total: base.length,
|
|
2725
|
+
byRepo: Object.fromEntries([...new Set(base.map((q) => q.repo))].sort().map((r2) => {
|
|
2726
|
+
const of = base.filter((q) => q.repo === r2);
|
|
2727
|
+
const k = (s) => of.filter((q) => q.state === s).length;
|
|
2728
|
+
return [
|
|
2729
|
+
r2,
|
|
2730
|
+
{
|
|
2731
|
+
open: k("open"),
|
|
2732
|
+
answered: k("answered"),
|
|
2733
|
+
retired: k("retired"),
|
|
2734
|
+
total: of.length
|
|
2735
|
+
}
|
|
2736
|
+
];
|
|
2737
|
+
})),
|
|
2738
|
+
byRole: countByRole(base, roleOf)
|
|
2739
|
+
},
|
|
1902
2740
|
questions: routed.questions,
|
|
1903
2741
|
problems: [...listed.problems, ...routed.problems],
|
|
1904
2742
|
about: routed.about,
|
|
1905
|
-
...routed.me ? { me: routed.me } : {}
|
|
2743
|
+
...routed.me ? { me: routed.me } : {},
|
|
2744
|
+
...change ? { yourRoles: await personsRoles(ctx.root, change, ctx.user) } : {}
|
|
1906
2745
|
};
|
|
1907
2746
|
return { status: 200, body };
|
|
2747
|
+
}).add("GET", "/api/owner-questions", async () => {
|
|
2748
|
+
const { ownerQuestions } = await import("./chunk-M4H2UG4R.js");
|
|
2749
|
+
return { status: 200, body: await ownerQuestions(ctx.root, { now: now() }) };
|
|
2750
|
+
}).add("POST", "/api/owner-questions/{id}/answer", async ({ params, body }) => {
|
|
2751
|
+
const b = api_exports.OwnerAnswerRequest.safeParse(body ?? {});
|
|
2752
|
+
if (!b.success || !b.data.answer.trim())
|
|
2753
|
+
throw badRequest('Answer with { answer: "what the owner said" }.');
|
|
2754
|
+
const { answerOwnerQuestion, OwnerQuestionError } = await import("./chunk-M4H2UG4R.js");
|
|
2755
|
+
try {
|
|
2756
|
+
const r2 = await answerOwnerQuestion(ctx.root, params.id, b.data.answer, {
|
|
2757
|
+
by: ctx.user,
|
|
2758
|
+
now: now()
|
|
2759
|
+
});
|
|
2760
|
+
return { status: 200, body: r2 };
|
|
2761
|
+
} catch (e) {
|
|
2762
|
+
if (e instanceof OwnerQuestionError)
|
|
2763
|
+
throw e.code === "not-found" ? notFound(e.message) : badRequest(e.message);
|
|
2764
|
+
throw e;
|
|
2765
|
+
}
|
|
1908
2766
|
}).add("GET", "/api/questions/{id}", async ({ params }) => {
|
|
1909
2767
|
const q = await readQuestion(ctx.root, params.id).catch(() => {
|
|
1910
2768
|
throw new HttpError(422, "Atticus can't read that question", `questions/${params.id}.yaml isn't a valid question.`);
|
|
@@ -1918,13 +2776,13 @@ function uiQuestionRoutes(r, ctx, deps = {}) {
|
|
|
1918
2776
|
throw notFound(`There is no question ${params.id}.`);
|
|
1919
2777
|
if (q.askedBy.step !== TARGETS_STEP_ID && q.askedBy.step !== TOPICS_STEP_ID)
|
|
1920
2778
|
throw new HttpError(422, "That question doesn't ask where a call goes or who owns a topic", `${q.id} isn't a targets or topics question, so it has no picker.`);
|
|
1921
|
-
const { pickerOf } = await import("./chunk-
|
|
2779
|
+
const { pickerOf } = await import("./chunk-IFFRGC3N.js");
|
|
1922
2780
|
return { status: 200, body: { picks: await pickerOf(ctx.root) } };
|
|
1923
2781
|
}).add("GET", "/api/questions/{id}/evidence", async ({ params }) => {
|
|
1924
2782
|
const q = await readQuestion(ctx.root, params.id).catch(() => void 0);
|
|
1925
2783
|
if (!q)
|
|
1926
2784
|
throw notFound(`There is no question ${params.id}.`);
|
|
1927
|
-
const { evidenceExcerpts } = await import("./chunk-
|
|
2785
|
+
const { evidenceExcerpts } = await import("./chunk-UFE36WJH.js");
|
|
1928
2786
|
return {
|
|
1929
2787
|
status: 200,
|
|
1930
2788
|
body: {
|
|
@@ -1947,7 +2805,7 @@ function uiQuestionRoutes(r, ctx, deps = {}) {
|
|
|
1947
2805
|
const q0 = await readQuestion(ctx.root, params.id).catch(() => void 0);
|
|
1948
2806
|
if (!q0)
|
|
1949
2807
|
throw notFound(`There is no question ${params.id}.`);
|
|
1950
|
-
const { targetAnswerOf, offerLine } = await import("./chunk-
|
|
2808
|
+
const { targetAnswerOf, offerLine } = await import("./chunk-IFFRGC3N.js");
|
|
1951
2809
|
const t = await targetAnswerOf(ctx.root, q0, target, {
|
|
1952
2810
|
...addSystem ? { addSystem } : {},
|
|
1953
2811
|
...name ? { name } : {}
|
|
@@ -2018,15 +2876,15 @@ async function latestFindings3(root, change) {
|
|
|
2018
2876
|
}
|
|
2019
2877
|
var SEVERITY_ORDER = ["blocking", "gap", "risk", "idea"];
|
|
2020
2878
|
var AT_RELEASE = /* @__PURE__ */ new Set(["release-ready", "released", "post-release-review"]);
|
|
2021
|
-
async function acrossRows(root,
|
|
2879
|
+
async function acrossRows(root, view3) {
|
|
2022
2880
|
const changes = await openChanges3(root);
|
|
2023
2881
|
const rows = [];
|
|
2024
|
-
const op =
|
|
2025
|
-
const steps =
|
|
2882
|
+
const op = view3 === "requests" ? await loadOrgPack(orgPackDirOf(root)) : void 0;
|
|
2883
|
+
const steps = view3 === "requests" ? await fileStepStore(root).list({ system: "service-desk" }).catch(() => []) : [];
|
|
2026
2884
|
for (const c of changes) {
|
|
2027
2885
|
const base = { change: c.id, changeTitle: c.title, changeState: c.state };
|
|
2028
2886
|
const dir = changeFolder(root, c.id);
|
|
2029
|
-
switch (
|
|
2887
|
+
switch (view3) {
|
|
2030
2888
|
case "findings":
|
|
2031
2889
|
for (const f of await latestFindings3(root, c.id))
|
|
2032
2890
|
rows.push({
|
|
@@ -2113,9 +2971,9 @@ async function acrossRows(root, view2) {
|
|
|
2113
2971
|
}
|
|
2114
2972
|
}
|
|
2115
2973
|
}
|
|
2116
|
-
if (
|
|
2974
|
+
if (view3 === "findings")
|
|
2117
2975
|
rows.sort((a, b) => Number(a.state !== "open") - Number(b.state !== "open") || SEVERITY_ORDER.indexOf(String(a.severity)) - SEVERITY_ORDER.indexOf(String(b.severity)) || a.change.localeCompare(b.change));
|
|
2118
|
-
if (
|
|
2976
|
+
if (view3 === "releases")
|
|
2119
2977
|
rows.sort((a, b) => Number(b.atRelease) - Number(a.atRelease));
|
|
2120
2978
|
return rows;
|
|
2121
2979
|
}
|
|
@@ -2205,13 +3063,13 @@ async function hopsFromTargetFlows(dir, mappings, interfaces) {
|
|
|
2205
3063
|
function uiAcrossRoutes(r, ctx) {
|
|
2206
3064
|
const { root } = ctx;
|
|
2207
3065
|
return r.add("GET", "/api/across", async ({ query }) => {
|
|
2208
|
-
const
|
|
2209
|
-
if (!ACROSS_VIEWS.includes(
|
|
3066
|
+
const view3 = strParam(query, "view") ?? "";
|
|
3067
|
+
if (!ACROSS_VIEWS.includes(view3))
|
|
2210
3068
|
throw badRequest(`Say which view: ?view= one of ${ACROSS_VIEWS.join(", ")}.`);
|
|
2211
|
-
const rows = await acrossRows(root,
|
|
3069
|
+
const rows = await acrossRows(root, view3);
|
|
2212
3070
|
return {
|
|
2213
3071
|
status: 200,
|
|
2214
|
-
body: { view:
|
|
3072
|
+
body: { view: view3, changes: (await openChanges3(root)).length, rows }
|
|
2215
3073
|
};
|
|
2216
3074
|
}).add("GET", "/api/changes/{changeId}/mappings", async ({ params }) => {
|
|
2217
3075
|
try {
|
|
@@ -2224,8 +3082,9 @@ function uiAcrossRoutes(r, ctx) {
|
|
|
2224
3082
|
}
|
|
2225
3083
|
|
|
2226
3084
|
// packages/cli/dist/ui-api-graph.js
|
|
2227
|
-
var
|
|
2228
|
-
import { readFile as readFile3 } from "node:fs/promises";
|
|
3085
|
+
var import_yaml3 = __toESM(require_dist(), 1);
|
|
3086
|
+
import { readdir as readdir3, readFile as readFile3 } from "node:fs/promises";
|
|
3087
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
2229
3088
|
import { join as join4 } from "node:path";
|
|
2230
3089
|
var lensOf = (v, fallback) => {
|
|
2231
3090
|
if (v === null)
|
|
@@ -2245,13 +3104,27 @@ var keyOf = (k) => {
|
|
|
2245
3104
|
throw badRequest(`${k} isn't a view key. Use <lens>.<node>, e.g. architecture.estate.`);
|
|
2246
3105
|
return k;
|
|
2247
3106
|
};
|
|
3107
|
+
function vscodeFileLink(path, line) {
|
|
3108
|
+
const posix = path.replace(/\\/g, "/");
|
|
3109
|
+
const segs = (posix.startsWith("/") ? posix.slice(1) : posix).split("/").map((x) => /^[A-Za-z]:$/.test(x) ? x : encodeURIComponent(x));
|
|
3110
|
+
return `vscode://file/${segs.join("/")}:${line}`;
|
|
3111
|
+
}
|
|
2248
3112
|
function uiGraphRoutes(r, ctx) {
|
|
2249
|
-
const
|
|
3113
|
+
const memoKey = `estate:${ctx.root}`;
|
|
3114
|
+
ctx.events.listen((e) => {
|
|
3115
|
+
if (e.type === "file.changed" && typeof e.path === "string" && /^(\.atticus[\\/])?catalog[\\/]/.test(e.path))
|
|
3116
|
+
recheckNow(memoKey);
|
|
3117
|
+
});
|
|
3118
|
+
const estate = async () => memoByFiles(memoKey, () => filesUnder(catalogDirOf(ctx.root)), buildFromCatalog, {
|
|
3119
|
+
recheckAfterMs: 1e3
|
|
3120
|
+
});
|
|
3121
|
+
const buildFromCatalog = async () => {
|
|
2250
3122
|
const records = await catalogRecords(ctx.root);
|
|
2251
3123
|
if (!records.length)
|
|
2252
3124
|
throw new HttpError(422, "Atticus can't show that yet", "The catalog is empty: read the repos first (atticus map <repo>, then atticus verify <repo> --write).", { notYet: true });
|
|
2253
3125
|
return buildEstate(records);
|
|
2254
3126
|
};
|
|
3127
|
+
setTimeout(() => void estate().catch(() => void 0), 0).unref?.();
|
|
2255
3128
|
const guard = (f) => {
|
|
2256
3129
|
try {
|
|
2257
3130
|
return f();
|
|
@@ -2261,11 +3134,13 @@ function uiGraphRoutes(r, ctx) {
|
|
|
2261
3134
|
throw e;
|
|
2262
3135
|
}
|
|
2263
3136
|
};
|
|
2264
|
-
const
|
|
3137
|
+
const layoutRel = (view3) => isAdopted(ctx.root) ? `.atticus/${layoutPath(view3)}` : layoutPath(view3);
|
|
3138
|
+
const viewsRel = diagramsRelOf(ctx.root) + "/views";
|
|
3139
|
+
const readLayout = async (view3) => {
|
|
2265
3140
|
try {
|
|
2266
|
-
const f = DiagramLayout.safeParse((0,
|
|
3141
|
+
const f = DiagramLayout.safeParse((0, import_yaml3.parse)(await readFile3(join4(ctx.root, layoutRel(view3)), "utf8")));
|
|
2267
3142
|
if (!f.success)
|
|
2268
|
-
throw new HttpError(422, "Atticus refused", `${
|
|
3143
|
+
throw new HttpError(422, "Atticus refused", `${layoutRel(view3)} isn't a layout file.`);
|
|
2269
3144
|
return f.data;
|
|
2270
3145
|
} catch (e) {
|
|
2271
3146
|
if (e.code === "ENOENT")
|
|
@@ -2289,46 +3164,100 @@ function uiGraphRoutes(r, ctx) {
|
|
|
2289
3164
|
const lens = lensOf(query.get("lens"), "data");
|
|
2290
3165
|
const est = await estate();
|
|
2291
3166
|
return { status: 200, body: guard(() => focusView(est, id, { lens })) };
|
|
3167
|
+
}).add("GET", "/api/graph/views", async () => {
|
|
3168
|
+
const dir = join4(ctx.root, ...viewsRel.split("/"));
|
|
3169
|
+
const names = (await readdir3(dir).catch(() => [])).filter((n) => n.endsWith(".yaml")).sort();
|
|
3170
|
+
const views = [];
|
|
3171
|
+
for (const n of names) {
|
|
3172
|
+
const v = api_exports.SavedCanvasView.safeParse((0, import_yaml3.parse)(await readFile3(join4(dir, n), "utf8").catch(() => "")));
|
|
3173
|
+
if (v.success)
|
|
3174
|
+
views.push(v.data);
|
|
3175
|
+
}
|
|
3176
|
+
return {
|
|
3177
|
+
status: 200,
|
|
3178
|
+
body: { views, dir: viewsRel }
|
|
3179
|
+
};
|
|
3180
|
+
}).add("PUT", "/api/graph/views/{name}", async ({ params, body, query }) => {
|
|
3181
|
+
const b = api_exports.SavedCanvasView.safeParse({ ...body, name: params.name });
|
|
3182
|
+
if (!b.success)
|
|
3183
|
+
throw badRequest("Name the view (lower case, digits and dashes) and give its lens and node.", {
|
|
3184
|
+
errors: b.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }))
|
|
3185
|
+
});
|
|
3186
|
+
const v = { ...b.data, by: ctx.user, at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
3187
|
+
const rel = `${viewsRel}/${v.name}.yaml`;
|
|
3188
|
+
if (existsSync2(join4(ctx.root, rel)) && query.get("replace") !== "1")
|
|
3189
|
+
throw conflict(`There is a view ${v.name} already (${rel}): pick another name, or replace it.`);
|
|
3190
|
+
await writeFileAtomic(join4(ctx.root, rel), (0, import_yaml3.stringify)(v));
|
|
3191
|
+
ctx.events.publish({ type: "file.changed", path: rel });
|
|
3192
|
+
return { status: 200, body: v };
|
|
3193
|
+
}).add("GET", "/api/code-link", async ({ query }) => {
|
|
3194
|
+
const repo = query.get("repo") ?? "";
|
|
3195
|
+
const at = query.get("at") ?? "";
|
|
3196
|
+
const m = /^(.+):(\d+)$/.exec(at);
|
|
3197
|
+
if (!/^[A-Za-z0-9._-]{1,200}$/.test(repo) || !m || m[1].includes(".."))
|
|
3198
|
+
throw badRequest("Say repo=<repo> and at=<file>:<line>.");
|
|
3199
|
+
const line = Number(m[2]);
|
|
3200
|
+
if (line < 1)
|
|
3201
|
+
throw badRequest("A line is 1 or more.");
|
|
3202
|
+
const dir = await checkoutOf(ctx.root, repo).catch(() => void 0);
|
|
3203
|
+
if (!dir || !existsSync2(dir))
|
|
3204
|
+
return {
|
|
3205
|
+
status: 200,
|
|
3206
|
+
body: {
|
|
3207
|
+
line,
|
|
3208
|
+
missing: `There is no checkout of ${repo} here (atticus sync clones it into the workspace).`
|
|
3209
|
+
}
|
|
3210
|
+
};
|
|
3211
|
+
const path = join4(dir, ...m[1].split("/"));
|
|
3212
|
+
return {
|
|
3213
|
+
status: 200,
|
|
3214
|
+
body: {
|
|
3215
|
+
path,
|
|
3216
|
+
line,
|
|
3217
|
+
vscode: vscodeFileLink(path, line),
|
|
3218
|
+
idea: `idea://open?file=${encodeURIComponent(path)}&line=${line}`
|
|
3219
|
+
}
|
|
3220
|
+
};
|
|
2292
3221
|
}).add("GET", "/api/graph/layout/{viewKey}", async ({ params }) => {
|
|
2293
|
-
const
|
|
2294
|
-
const f = await readLayout(
|
|
3222
|
+
const view3 = keyOf(params.viewKey);
|
|
3223
|
+
const f = await readLayout(view3);
|
|
2295
3224
|
return {
|
|
2296
3225
|
status: 200,
|
|
2297
|
-
body: { view:
|
|
3226
|
+
body: { view: view3, saved: !!f, path: layoutRel(view3), positions: f?.positions ?? {} }
|
|
2298
3227
|
};
|
|
2299
3228
|
}).add("PUT", "/api/graph/layout/{viewKey}", async ({ params, body }) => {
|
|
2300
|
-
const
|
|
3229
|
+
const view3 = keyOf(params.viewKey);
|
|
2301
3230
|
const b = api_exports.PutLayoutRequest.safeParse(body ?? {});
|
|
2302
3231
|
if (!b.success)
|
|
2303
3232
|
throw badRequest("Some fields aren't right.", {
|
|
2304
3233
|
errors: b.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }))
|
|
2305
3234
|
});
|
|
2306
3235
|
const { lens, node, positions } = b.data;
|
|
2307
|
-
if (
|
|
2308
|
-
throw badRequest(`${
|
|
3236
|
+
if (view3 !== viewKey(lens, node) && view3 !== viewKey(lens, node, "focus"))
|
|
3237
|
+
throw badRequest(`${view3} isn't the view key of ${node} in the ${lens} lens.`);
|
|
2309
3238
|
if (Object.keys(positions).length > 5e3)
|
|
2310
3239
|
throw badRequest("At most 5000 boxes per view.");
|
|
2311
3240
|
const sorted = Object.fromEntries(Object.entries(positions).sort(([a], [b2]) => a < b2 ? -1 : 1).map(([k, p]) => [k, { x: Math.round(p.x), y: Math.round(p.y) }]));
|
|
2312
3241
|
const file = DiagramLayout.parse({
|
|
2313
3242
|
schemaVersion: LAYOUT_SCHEMA_VERSION,
|
|
2314
|
-
view:
|
|
3243
|
+
view: view3,
|
|
2315
3244
|
lens,
|
|
2316
3245
|
node,
|
|
2317
3246
|
by: ctx.user,
|
|
2318
3247
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2319
3248
|
positions: sorted
|
|
2320
3249
|
});
|
|
2321
|
-
await writeFileAtomic(join4(ctx.root,
|
|
2322
|
-
ctx.events.publish({ type: "file.changed", path:
|
|
3250
|
+
await writeFileAtomic(join4(ctx.root, layoutRel(view3)), (0, import_yaml3.stringify)(file));
|
|
3251
|
+
ctx.events.publish({ type: "file.changed", path: layoutRel(view3) });
|
|
2323
3252
|
return {
|
|
2324
3253
|
status: 200,
|
|
2325
|
-
body: { view:
|
|
3254
|
+
body: { view: view3, saved: true, path: layoutRel(view3), positions: file.positions }
|
|
2326
3255
|
};
|
|
2327
3256
|
});
|
|
2328
3257
|
}
|
|
2329
3258
|
|
|
2330
3259
|
// packages/cli/dist/ui-api-specs.js
|
|
2331
|
-
import { stat as
|
|
3260
|
+
import { stat as stat3 } from "node:fs/promises";
|
|
2332
3261
|
import { join as join5 } from "node:path";
|
|
2333
3262
|
var idOf2 = (v, what) => {
|
|
2334
3263
|
if (!RecordId.safeParse(v).success)
|
|
@@ -2435,7 +3364,7 @@ function uiSpecRoutes(r, ctx) {
|
|
|
2435
3364
|
});
|
|
2436
3365
|
const deltasOf = async (change) => {
|
|
2437
3366
|
const dir = join5(changesDirOf(root), change);
|
|
2438
|
-
if (!await
|
|
3367
|
+
if (!await stat3(join5(dir, "change.yaml")).catch(() => void 0))
|
|
2439
3368
|
throw notFound(`There is no change ${change}.`);
|
|
2440
3369
|
return readDeltas(dir);
|
|
2441
3370
|
};
|
|
@@ -2459,7 +3388,7 @@ function uiSpecRoutes(r, ctx) {
|
|
|
2459
3388
|
});
|
|
2460
3389
|
r.add("GET", "/api/changes/{changeId}/conformance", async ({ params }) => {
|
|
2461
3390
|
const change = idOf2(params.changeId, "change");
|
|
2462
|
-
const { conformanceOf } = await import("./chunk-
|
|
3391
|
+
const { conformanceOf } = await import("./chunk-FRHD22WM.js");
|
|
2463
3392
|
const c = await conformanceOf(root, change);
|
|
2464
3393
|
if (!c)
|
|
2465
3394
|
throw notFound(`There is no change ${change}.`);
|
|
@@ -2474,7 +3403,7 @@ function uiSpecRoutes(r, ctx) {
|
|
|
2474
3403
|
});
|
|
2475
3404
|
r.add("GET", "/api/changes/{changeId}/impact", async ({ params }) => {
|
|
2476
3405
|
const change = idOf2(params.changeId, "change");
|
|
2477
|
-
const { changeImpactOf } = await import("./chunk-
|
|
3406
|
+
const { changeImpactOf } = await import("./chunk-2D7PWSOK.js");
|
|
2478
3407
|
const i = await changeImpactOf(root, change);
|
|
2479
3408
|
if (!i)
|
|
2480
3409
|
throw notFound(`There is no change ${change}.`);
|
|
@@ -2508,8 +3437,8 @@ function uiSpecRoutes(r, ctx) {
|
|
|
2508
3437
|
}
|
|
2509
3438
|
|
|
2510
3439
|
// packages/cli/dist/ui-api-knowledge.js
|
|
2511
|
-
var
|
|
2512
|
-
import { readFile as readFile4, stat as
|
|
3440
|
+
var import_yaml4 = __toESM(require_dist(), 1);
|
|
3441
|
+
import { readFile as readFile4, stat as stat4 } from "node:fs/promises";
|
|
2513
3442
|
import { join as join6 } from "node:path";
|
|
2514
3443
|
var STALE_DAYS = 14;
|
|
2515
3444
|
var SLUG = /^[a-z0-9][a-z0-9-]*$/;
|
|
@@ -2579,7 +3508,7 @@ function candidateView(c) {
|
|
|
2579
3508
|
keepAs: keepAs(r.kind)
|
|
2580
3509
|
};
|
|
2581
3510
|
}
|
|
2582
|
-
var exists = (p) =>
|
|
3511
|
+
var exists = (p) => stat4(p).then(() => true, () => false);
|
|
2583
3512
|
function capture() {
|
|
2584
3513
|
const lines = [];
|
|
2585
3514
|
const problems = [];
|
|
@@ -2670,7 +3599,7 @@ function uiKnowledgeRoutes(r, ctx, deps = {}) {
|
|
|
2670
3599
|
const platforms = [];
|
|
2671
3600
|
for (const { platform } of op.profiles) {
|
|
2672
3601
|
const text = await readFile4(join6(proposalsDirOf(root), "orgpack", `${platform}.yaml`), "utf8").catch(() => void 0);
|
|
2673
|
-
const data = text === void 0 ? void 0 : (0,
|
|
3602
|
+
const data = text === void 0 ? void 0 : (0, import_yaml4.parse)(text);
|
|
2674
3603
|
const proposals = Array.isArray(data?.proposals) ? data.proposals.flatMap((p) => {
|
|
2675
3604
|
const x = OrgPackProposal.safeParse(p);
|
|
2676
3605
|
return x.success ? [x.data] : [];
|
|
@@ -2702,7 +3631,7 @@ function uiKnowledgeRoutes(r, ctx, deps = {}) {
|
|
|
2702
3631
|
if (date) {
|
|
2703
3632
|
const file = join6(knowledgeDirOf(root), "snapshots", w.id, date, SNAPSHOT_FILE);
|
|
2704
3633
|
const text = await readFile4(file, "utf8").catch(() => void 0);
|
|
2705
|
-
const m = text === void 0 ? void 0 : SnapshotManifest.safeParse((0,
|
|
3634
|
+
const m = text === void 0 ? void 0 : SnapshotManifest.safeParse((0, import_yaml4.parse)(text));
|
|
2706
3635
|
if (m?.success)
|
|
2707
3636
|
snapshot = {
|
|
2708
3637
|
date,
|
|
@@ -2942,7 +3871,7 @@ function uiKnowledgeRoutes(r, ctx, deps = {}) {
|
|
|
2942
3871
|
if (fileExists && !f)
|
|
2943
3872
|
throw new HttpError(422, "Atticus can't read that file", `${changesRelOf(root)}/${change}/${NEEDS_FILE} isn't a valid needs file.`);
|
|
2944
3873
|
const k = f ? await readKnowledge(root, { cacheRoot: root }) : void 0;
|
|
2945
|
-
const
|
|
3874
|
+
const view3 = (n) => ({
|
|
2946
3875
|
...n,
|
|
2947
3876
|
...k?.reviews[n.item] ? { review: k.reviews[n.item] } : {}
|
|
2948
3877
|
});
|
|
@@ -2951,7 +3880,7 @@ function uiKnowledgeRoutes(r, ctx, deps = {}) {
|
|
|
2951
3880
|
file: `${changesRelOf(root)}/${change}/${NEEDS_FILE}`,
|
|
2952
3881
|
present: !!f,
|
|
2953
3882
|
...f ? { updatedAt: f.updatedAt } : {},
|
|
2954
|
-
needs: (f?.needs ?? []).map(
|
|
3883
|
+
needs: (f?.needs ?? []).map(view3),
|
|
2955
3884
|
considered: f?.considered ?? [],
|
|
2956
3885
|
command: `atticus change needs ${change}`,
|
|
2957
3886
|
slash: `/atticus-needs ${change}`
|
|
@@ -3016,7 +3945,8 @@ function uiKnowledgeRoutes(r, ctx, deps = {}) {
|
|
|
3016
3945
|
const result = {
|
|
3017
3946
|
knowledge: await appliesView(change),
|
|
3018
3947
|
file: before.file,
|
|
3019
|
-
commit: `git add ${before.file}
|
|
3948
|
+
commit: `git add ${before.file}
|
|
3949
|
+
git commit -m "${change}: the knowledge that applies"`
|
|
3020
3950
|
};
|
|
3021
3951
|
return { status: 200, body: result };
|
|
3022
3952
|
}).add("GET", "/api/orgpack/draft", async () => ({ status: 200, body: await draftView() })).add("POST", "/api/orgpack/draft", async ({ body }) => {
|
|
@@ -3054,7 +3984,7 @@ function uiKnowledgeRoutes(r, ctx, deps = {}) {
|
|
|
3054
3984
|
// packages/cli/dist/ui-api-runs.js
|
|
3055
3985
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
3056
3986
|
import { join as join7 } from "node:path";
|
|
3057
|
-
var
|
|
3987
|
+
var import_yaml5 = __toESM(require_dist(), 1);
|
|
3058
3988
|
async function serverModel(root) {
|
|
3059
3989
|
return (await configuredModel(root))?.type ?? null;
|
|
3060
3990
|
}
|
|
@@ -3064,7 +3994,7 @@ async function configuredModel(root) {
|
|
|
3064
3994
|
return null;
|
|
3065
3995
|
let y;
|
|
3066
3996
|
try {
|
|
3067
|
-
y = (0,
|
|
3997
|
+
y = (0, import_yaml5.parse)(text);
|
|
3068
3998
|
} catch {
|
|
3069
3999
|
return null;
|
|
3070
4000
|
}
|
|
@@ -3080,26 +4010,29 @@ async function configuredModel(root) {
|
|
|
3080
4010
|
function uiModelRunRoutes(r, ctx, deps = {}) {
|
|
3081
4011
|
const root = ctx.root;
|
|
3082
4012
|
const runStep = deps.runStep ?? (async (args) => {
|
|
3083
|
-
const { main } = await import("./chunk-
|
|
4013
|
+
const { main } = await import("./chunk-7FHNFCHK.js");
|
|
3084
4014
|
const out = [];
|
|
3085
4015
|
const err = [];
|
|
3086
4016
|
const code = await main([...args, "--root", root], { out: (l) => out.push(l), err: (l) => err.push(l) }, { quiet: true });
|
|
3087
4017
|
return { code, out, err };
|
|
3088
4018
|
});
|
|
3089
|
-
return r.add("POST", "/api/runs", async ({ body }) => {
|
|
3090
|
-
const
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
if (!
|
|
3095
|
-
throw
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
4019
|
+
return r.add("POST", "/api/runs/handoff", async ({ body }) => {
|
|
4020
|
+
const words = stepWords(body);
|
|
4021
|
+
const { prepareStep } = await import("./chunk-J2O4LFVI.js");
|
|
4022
|
+
const { code, prepared } = await prepareStep(root, runStep, words);
|
|
4023
|
+
ctx.events.publish({ type: "file.changed", path: runsRelOf(root) });
|
|
4024
|
+
if (!prepared.runId && code !== 0)
|
|
4025
|
+
throw new HttpError(422, "The step wasn't prepared", prepared.lines.join("\n") || "The step prepared no run.");
|
|
4026
|
+
return { status: 201, body: prepared };
|
|
4027
|
+
}).add("POST", "/api/runs", async ({ body }) => {
|
|
4028
|
+
const words = stepWords(body);
|
|
3099
4029
|
const configured = await configuredModel(root);
|
|
3100
4030
|
const model = configured?.type;
|
|
3101
4031
|
if (!model)
|
|
3102
4032
|
throw conflict("This server's runtime.yaml configures no model, so it can't run an AI step. Run it in your assistant (its slash command), or from VS Code with Copilot.");
|
|
4033
|
+
const busy = ctx.jobs.runningOf("step");
|
|
4034
|
+
if (busy)
|
|
4035
|
+
throw conflict(`An AI step is running on this server (${busy.id}): wait for it to finish, or cancel it.`);
|
|
3103
4036
|
const job = ctx.jobs.start("step", async (c) => {
|
|
3104
4037
|
c.progress(0, 1, `Running atticus ${words.join(" ")} with ${model}`);
|
|
3105
4038
|
const before = new Set((await listRuns(root, { limit: 1e5 })).map((x) => x.runId));
|
|
@@ -3140,6 +4073,900 @@ function uiModelRunRoutes(r, ctx, deps = {}) {
|
|
|
3140
4073
|
return { status: 200, body: t };
|
|
3141
4074
|
});
|
|
3142
4075
|
}
|
|
4076
|
+
function stepWords(body) {
|
|
4077
|
+
const args = body?.args;
|
|
4078
|
+
if (!Array.isArray(args) || args.length < 2 || !args.every((a) => typeof a === "string" && a.trim() !== ""))
|
|
4079
|
+
throw badRequest(`args is the step's command words and arguments, for example ["scan", "survey", "forge-ledger"].`);
|
|
4080
|
+
const words = args;
|
|
4081
|
+
if (!isHandoffStep(words[0], words[1]))
|
|
4082
|
+
throw badRequest(`atticus ${words.slice(0, 2).join(" ")} isn't an AI step; the app starts only those.`);
|
|
4083
|
+
const option = withoutSource(words).find((a) => a.startsWith("-"));
|
|
4084
|
+
if (option)
|
|
4085
|
+
throw badRequest(`${option} would be read as an option; give the step's arguments only.`);
|
|
4086
|
+
return words;
|
|
4087
|
+
}
|
|
4088
|
+
var SOURCE_STEPS = /* @__PURE__ */ new Set(["knowledge scan", "knowledge find"]);
|
|
4089
|
+
function withoutSource(words) {
|
|
4090
|
+
if (!SOURCE_STEPS.has(`${words[0]} ${words[1]}`))
|
|
4091
|
+
return words;
|
|
4092
|
+
const at = words.indexOf("--source");
|
|
4093
|
+
const value = words[at + 1];
|
|
4094
|
+
if (at < 0 || !value || value.startsWith("-"))
|
|
4095
|
+
return words;
|
|
4096
|
+
return [...words.slice(0, at), ...words.slice(at + 2)];
|
|
4097
|
+
}
|
|
4098
|
+
|
|
4099
|
+
// packages/cli/dist/ui-api-copilot-runs.js
|
|
4100
|
+
import { randomBytes } from "node:crypto";
|
|
4101
|
+
|
|
4102
|
+
// packages/cli/dist/copilot-run.js
|
|
4103
|
+
var TAB_LINES = 5e3;
|
|
4104
|
+
var CopilotRun = class {
|
|
4105
|
+
view;
|
|
4106
|
+
current = "run";
|
|
4107
|
+
constructor(o) {
|
|
4108
|
+
this.view = {
|
|
4109
|
+
runId: o.runId,
|
|
4110
|
+
jobId: o.jobId,
|
|
4111
|
+
kind: o.kind,
|
|
4112
|
+
...o.repos?.length ? { repos: o.repos } : {},
|
|
4113
|
+
...o.force ? { force: true } : {},
|
|
4114
|
+
state: "running",
|
|
4115
|
+
...o.by ? { by: o.by } : {},
|
|
4116
|
+
...o.model ? { model: o.model } : {},
|
|
4117
|
+
startedAt: o.startedAt,
|
|
4118
|
+
progress: { repos: 0, repoIndex: 0, sessions: 0 },
|
|
4119
|
+
totals: { kept: 0, rejected: 0, tokens: 0 },
|
|
4120
|
+
tabs: [{ id: "run", title: "Run", state: "running", from: 0, lines: [] }]
|
|
4121
|
+
};
|
|
4122
|
+
}
|
|
4123
|
+
tab(id) {
|
|
4124
|
+
return this.view.tabs.find((t) => t.id === id) ?? this.view.tabs[0];
|
|
4125
|
+
}
|
|
4126
|
+
push(id, lines) {
|
|
4127
|
+
const t = this.tab(id);
|
|
4128
|
+
const at = t.from + t.lines.length;
|
|
4129
|
+
t.lines.push(...lines);
|
|
4130
|
+
if (t.lines.length > TAB_LINES) {
|
|
4131
|
+
const drop = t.lines.length - TAB_LINES;
|
|
4132
|
+
t.lines.splice(0, drop);
|
|
4133
|
+
t.from += drop;
|
|
4134
|
+
}
|
|
4135
|
+
return { tab: t.id, title: t.title, at, lines };
|
|
4136
|
+
}
|
|
4137
|
+
/** A line the run printed: into the session under way (or just ended, until the next repo). */
|
|
4138
|
+
line(text) {
|
|
4139
|
+
return this.push(this.current, [text]);
|
|
4140
|
+
}
|
|
4141
|
+
/** A step of the run: progress, and the tabs it opens or closes. Returns the lines it adds. */
|
|
4142
|
+
event(e) {
|
|
4143
|
+
const v = this.view;
|
|
4144
|
+
const out = [];
|
|
4145
|
+
switch (e.type) {
|
|
4146
|
+
case "plan":
|
|
4147
|
+
v.progress.repos = e.repos.length;
|
|
4148
|
+
break;
|
|
4149
|
+
case "repo":
|
|
4150
|
+
v.progress.repoIndex = e.index;
|
|
4151
|
+
v.progress.repos = e.total;
|
|
4152
|
+
v.progress.repo = e.repo;
|
|
4153
|
+
delete v.progress.session;
|
|
4154
|
+
this.current = "run";
|
|
4155
|
+
break;
|
|
4156
|
+
case "session": {
|
|
4157
|
+
const id = `s${v.progress.sessions + 1}`;
|
|
4158
|
+
v.progress.sessions++;
|
|
4159
|
+
const title = `${e.repo}, ${e.label}${e.attempt ? " (again)" : ""}`;
|
|
4160
|
+
v.progress.session = title;
|
|
4161
|
+
v.tabs.push({ id, title, repo: e.repo, state: "running", from: 0, lines: [] });
|
|
4162
|
+
out.push(this.push("run", [`Session ${v.progress.sessions}: ${title}`]));
|
|
4163
|
+
this.current = id;
|
|
4164
|
+
break;
|
|
4165
|
+
}
|
|
4166
|
+
case "session.end": {
|
|
4167
|
+
const t = v.tabs.findLast((x) => x.repo === e.repo && x.state === "running");
|
|
4168
|
+
if (t) {
|
|
4169
|
+
t.state = e.failed ? "failed" : "ended";
|
|
4170
|
+
t.ended = e.failed ?? e.ended;
|
|
4171
|
+
out.push(this.push("run", [`${t.title}: ended (${t.ended})`]));
|
|
4172
|
+
}
|
|
4173
|
+
if (e.tokens)
|
|
4174
|
+
v.totals.tokens += e.tokens;
|
|
4175
|
+
delete v.progress.session;
|
|
4176
|
+
break;
|
|
4177
|
+
}
|
|
4178
|
+
case "verify":
|
|
4179
|
+
v.totals.kept += e.kept;
|
|
4180
|
+
v.totals.rejected += e.rejected;
|
|
4181
|
+
if (this.current !== "run")
|
|
4182
|
+
out.push(this.push("run", [
|
|
4183
|
+
`${e.repo}: ${e.kept} kept, ${e.rejected} rejected, coverage ${Math.round(e.coverage * 100)}%, ${e.open} open`
|
|
4184
|
+
]));
|
|
4185
|
+
break;
|
|
4186
|
+
}
|
|
4187
|
+
return out;
|
|
4188
|
+
}
|
|
4189
|
+
/** How it ended: done, stopped by a person, or failed with the error said. */
|
|
4190
|
+
finish(state, at, message) {
|
|
4191
|
+
const v = this.view;
|
|
4192
|
+
v.state = state;
|
|
4193
|
+
v.finishedAt = at;
|
|
4194
|
+
if (message)
|
|
4195
|
+
v.message = message;
|
|
4196
|
+
for (const t of v.tabs)
|
|
4197
|
+
if (t.state === "running") {
|
|
4198
|
+
t.state = state === "failed" ? "failed" : "ended";
|
|
4199
|
+
if (t.id !== "run")
|
|
4200
|
+
t.ended ??= state;
|
|
4201
|
+
}
|
|
4202
|
+
this.current = "run";
|
|
4203
|
+
return this.push("run", [
|
|
4204
|
+
state === "done" ? "The run finished." : state === "stopped" ? "Stopped. The next run carries on from here." : `The run stopped: ${message ?? "an error"}`
|
|
4205
|
+
]);
|
|
4206
|
+
}
|
|
4207
|
+
/** The state without the lines, for the live event. */
|
|
4208
|
+
summary() {
|
|
4209
|
+
const { tabs: _tabs, ...rest } = this.view;
|
|
4210
|
+
return structuredClone(rest);
|
|
4211
|
+
}
|
|
4212
|
+
};
|
|
4213
|
+
|
|
4214
|
+
// packages/cli/dist/ui-api-copilot-runs.js
|
|
4215
|
+
var defaultStarter = (root) => async (o, io, deps) => {
|
|
4216
|
+
const { mapAllCommand } = await import("./chunk-YF5DZCPN.js");
|
|
4217
|
+
return mapAllCommand(root, o, io, {
|
|
4218
|
+
...deps,
|
|
4219
|
+
makeAcp: async () => (await import("./chunk-ZPDDEVQX.js")).acpStepRunner(root)
|
|
4220
|
+
});
|
|
4221
|
+
};
|
|
4222
|
+
var TAIL = 200;
|
|
4223
|
+
var NOT_ALLOWED = "runtime.yaml doesn't allow copilot-acp here (schemaVersion 3, copilot-acp in modes.allowed and copilot in assistants.allowed), so the app can't start Copilot itself. Read through Copilot Chat instead: atticus map --all in a terminal gives each part to paste.";
|
|
4224
|
+
async function allowedHere(root) {
|
|
4225
|
+
try {
|
|
4226
|
+
const op = await loadOrgPack(orgPackDirOf(root));
|
|
4227
|
+
const c = copilotAcpOf(op.runtime);
|
|
4228
|
+
return { allowed: copilotAcpAllowed(op), ...c.model ? { model: c.model } : {} };
|
|
4229
|
+
} catch {
|
|
4230
|
+
return { allowed: false };
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
var optionsOf = (b) => ({
|
|
4234
|
+
mode: "copilot-acp",
|
|
4235
|
+
...b.kind === "stale" ? { stale: true } : {},
|
|
4236
|
+
...b.kind === "gaps" ? { gaps: true } : {},
|
|
4237
|
+
...b.repos?.length ? { repos: b.repos } : {},
|
|
4238
|
+
...b.force ? { force: true } : {},
|
|
4239
|
+
resumeAs: "the next run (Map from the app, or atticus map --all)"
|
|
4240
|
+
});
|
|
4241
|
+
function uiCopilotRunRoutes(r, ctx, deps = {}) {
|
|
4242
|
+
const start = deps.start ?? defaultStarter(ctx.root);
|
|
4243
|
+
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
4244
|
+
const flushMs = deps.flushMs ?? 100;
|
|
4245
|
+
let run4;
|
|
4246
|
+
let allowed;
|
|
4247
|
+
let seq = 0;
|
|
4248
|
+
let starting = false;
|
|
4249
|
+
const pending = /* @__PURE__ */ new Map();
|
|
4250
|
+
let timer;
|
|
4251
|
+
const flush = () => {
|
|
4252
|
+
timer = void 0;
|
|
4253
|
+
const r0 = run4;
|
|
4254
|
+
if (!r0)
|
|
4255
|
+
return;
|
|
4256
|
+
for (const n of pending.values())
|
|
4257
|
+
ctx.events.publish({ type: "copilot-run.lines", runId: r0.view.runId, ...n });
|
|
4258
|
+
pending.clear();
|
|
4259
|
+
};
|
|
4260
|
+
const queue = (n) => {
|
|
4261
|
+
const p = pending.get(n.tab);
|
|
4262
|
+
if (p)
|
|
4263
|
+
p.lines.push(...n.lines);
|
|
4264
|
+
else
|
|
4265
|
+
pending.set(n.tab, { ...n, lines: [...n.lines] });
|
|
4266
|
+
timer ??= setTimeout(flush, flushMs);
|
|
4267
|
+
};
|
|
4268
|
+
const state = () => {
|
|
4269
|
+
if (run4)
|
|
4270
|
+
ctx.events.publish({ type: "copilot-run.state", run: run4.summary() });
|
|
4271
|
+
};
|
|
4272
|
+
return r.add("GET", "/api/copilot-runs/current", async ({ query }) => {
|
|
4273
|
+
if (!allowed || Date.now() - allowed.at > 1e4)
|
|
4274
|
+
allowed = { at: Date.now(), v: await allowedHere(ctx.root) };
|
|
4275
|
+
const a = allowed.v;
|
|
4276
|
+
const tail = Math.min(Math.max(Number(query.get("tail") ?? TAIL) || TAIL, 0), TAB_LINES);
|
|
4277
|
+
const view3 = run4 ? {
|
|
4278
|
+
...run4.summary(),
|
|
4279
|
+
tabs: run4.view.tabs.map((t) => {
|
|
4280
|
+
const keep = tail ? t.lines.slice(-tail) : t.lines;
|
|
4281
|
+
return { ...t, from: t.from + t.lines.length - keep.length, lines: [...keep] };
|
|
4282
|
+
})
|
|
4283
|
+
} : null;
|
|
4284
|
+
return {
|
|
4285
|
+
status: 200,
|
|
4286
|
+
body: {
|
|
4287
|
+
run: view3,
|
|
4288
|
+
allowed: a.allowed,
|
|
4289
|
+
...a.allowed ? {} : { why: NOT_ALLOWED },
|
|
4290
|
+
...a.model ? { model: a.model } : {}
|
|
4291
|
+
}
|
|
4292
|
+
};
|
|
4293
|
+
}).add("POST", "/api/copilot-runs", async ({ body }) => {
|
|
4294
|
+
const b = api_exports.StartCopilotRunRequest.safeParse(body ?? {});
|
|
4295
|
+
if (!b.success)
|
|
4296
|
+
throw badRequest("Some fields aren't right.", {
|
|
4297
|
+
errors: b.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }))
|
|
4298
|
+
});
|
|
4299
|
+
if (b.data.kind === "repos" && !b.data.repos?.length)
|
|
4300
|
+
throw badRequest("Name the repos to read (repos), or pick stale, gaps or all.");
|
|
4301
|
+
if (run4?.view.state === "running")
|
|
4302
|
+
throw conflict(`A Copilot run is under way (${run4.view.runId}, started ${run4.view.startedAt}): stop it, or wait for it to finish.`);
|
|
4303
|
+
if (starting)
|
|
4304
|
+
throw conflict("A Copilot run is starting: wait for it, then stop it if need be.");
|
|
4305
|
+
const busy = ctx.jobs.runningOf("step");
|
|
4306
|
+
if (busy?.state === "running")
|
|
4307
|
+
throw conflict(`An AI step is running on this server (${busy.id}): wait for it to finish.`);
|
|
4308
|
+
starting = true;
|
|
4309
|
+
let a;
|
|
4310
|
+
try {
|
|
4311
|
+
a = await allowedHere(ctx.root);
|
|
4312
|
+
} finally {
|
|
4313
|
+
starting = false;
|
|
4314
|
+
}
|
|
4315
|
+
if (!a.allowed)
|
|
4316
|
+
throw conflict(NOT_ALLOWED);
|
|
4317
|
+
if (ctx.jobs.runningOf("step")?.state === "running")
|
|
4318
|
+
throw conflict("An AI step started on this server meanwhile: wait for it to finish.");
|
|
4319
|
+
const runId = `copilot-run-${now().getTime().toString(36)}-${randomBytes(3).toString("hex")}-${++seq}`;
|
|
4320
|
+
const me = new CopilotRun({
|
|
4321
|
+
runId,
|
|
4322
|
+
jobId: "",
|
|
4323
|
+
kind: b.data.kind,
|
|
4324
|
+
...b.data.repos ? { repos: b.data.repos } : {},
|
|
4325
|
+
...b.data.force ? { force: true } : {},
|
|
4326
|
+
...ctx.user ? { by: ctx.user } : {},
|
|
4327
|
+
...a.model ? { model: a.model } : {},
|
|
4328
|
+
startedAt: now().toISOString()
|
|
4329
|
+
});
|
|
4330
|
+
run4 = me;
|
|
4331
|
+
let lastErr;
|
|
4332
|
+
const job = ctx.jobs.start("step", async (c) => {
|
|
4333
|
+
const io = {
|
|
4334
|
+
out: (l) => queue(me.line(l)),
|
|
4335
|
+
err: (l) => {
|
|
4336
|
+
lastErr = l;
|
|
4337
|
+
queue(me.line(l));
|
|
4338
|
+
}
|
|
4339
|
+
};
|
|
4340
|
+
const onEvent = (e) => {
|
|
4341
|
+
for (const n of me.event(e))
|
|
4342
|
+
queue(n);
|
|
4343
|
+
const p = me.view.progress;
|
|
4344
|
+
c.progress(p.repoIndex, p.repos, p.session ?? p.repo ?? "Planning");
|
|
4345
|
+
state();
|
|
4346
|
+
};
|
|
4347
|
+
const signal = currentSignal();
|
|
4348
|
+
let code;
|
|
4349
|
+
try {
|
|
4350
|
+
code = await start(optionsOf(b.data), io, {
|
|
4351
|
+
...signal ? { signal } : {},
|
|
4352
|
+
onEvent
|
|
4353
|
+
});
|
|
4354
|
+
} catch (e) {
|
|
4355
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
4356
|
+
queue(me.finish(signal?.aborted ? "stopped" : "failed", now().toISOString(), msg));
|
|
4357
|
+
flush();
|
|
4358
|
+
state();
|
|
4359
|
+
ctx.events.publish({ type: "file.changed", path: "facts" });
|
|
4360
|
+
return { errors: [msg] };
|
|
4361
|
+
}
|
|
4362
|
+
const stopped = signal?.aborted === true;
|
|
4363
|
+
queue(me.finish(stopped ? "stopped" : code === 0 ? "done" : "failed", now().toISOString(), stopped || code === 0 ? void 0 : lastErr ?? `atticus map --all ended with ${code}`));
|
|
4364
|
+
flush();
|
|
4365
|
+
state();
|
|
4366
|
+
ctx.events.publish({ type: "file.changed", path: "facts" });
|
|
4367
|
+
return { result: { code, runId } };
|
|
4368
|
+
});
|
|
4369
|
+
me.view.jobId = job.id;
|
|
4370
|
+
state();
|
|
4371
|
+
return { status: 202, body: structuredClone(me.view) };
|
|
4372
|
+
}).add("GET", "/api/copilot-runs/{runId}/tabs/{tab}", async ({ params, query }) => {
|
|
4373
|
+
if (!run4 || run4.view.runId !== params.runId)
|
|
4374
|
+
throw notFound(`There is no run ${params.runId}.`);
|
|
4375
|
+
const t = run4.view.tabs.find((x) => x.id === params.tab);
|
|
4376
|
+
if (!t)
|
|
4377
|
+
throw notFound(`${params.runId} has no tab ${params.tab}.`);
|
|
4378
|
+
const from = Math.max(Number(query.get("from") ?? 0) || 0, t.from);
|
|
4379
|
+
return {
|
|
4380
|
+
status: 200,
|
|
4381
|
+
body: { id: t.id, title: t.title, from, lines: t.lines.slice(from - t.from) }
|
|
4382
|
+
};
|
|
4383
|
+
}).add("POST", "/api/copilot-runs/{runId}/stop", async ({ params }) => {
|
|
4384
|
+
if (!run4 || run4.view.runId !== params.runId)
|
|
4385
|
+
throw notFound(`There is no run ${params.runId}.`);
|
|
4386
|
+
if (run4.view.state !== "running")
|
|
4387
|
+
throw conflict(`${params.runId} has already ${run4.view.state === "done" ? "finished" : run4.view.state}.`);
|
|
4388
|
+
ctx.jobs.cancel(run4.view.jobId);
|
|
4389
|
+
queue(run4.line("Stopping: the session under way is cancelled..."));
|
|
4390
|
+
return { status: 200, body: structuredClone(run4.view) };
|
|
4391
|
+
});
|
|
4392
|
+
}
|
|
4393
|
+
|
|
4394
|
+
// packages/cli/dist/ui-api-link-match.js
|
|
4395
|
+
var keyOf2 = (from, to) => `${from}\0${to.repo ?? ""}\0${to.system ?? ""}`;
|
|
4396
|
+
function uiLinkMatchRoutes(r, ctx, deps = {}) {
|
|
4397
|
+
const running = /* @__PURE__ */ new Map();
|
|
4398
|
+
return r.add("GET", "/api/links/match", async ({ query }) => {
|
|
4399
|
+
const { from, to } = boxesOf(query);
|
|
4400
|
+
const { view: view3 } = await candidatesOf(ctx.root, from, to);
|
|
4401
|
+
const run4 = running.get(keyOf2(from, to));
|
|
4402
|
+
const job = run4 ? ctx.jobs.get(run4.jobId) : void 0;
|
|
4403
|
+
if (run4 && job?.state === "running") {
|
|
4404
|
+
const files = await readMatch(ctx.root, view3);
|
|
4405
|
+
return {
|
|
4406
|
+
status: 200,
|
|
4407
|
+
body: {
|
|
4408
|
+
...files,
|
|
4409
|
+
state: "running",
|
|
4410
|
+
jobId: run4.jobId,
|
|
4411
|
+
proposals: [],
|
|
4412
|
+
none: [],
|
|
4413
|
+
rejected: []
|
|
4414
|
+
}
|
|
4415
|
+
};
|
|
4416
|
+
}
|
|
4417
|
+
const m = await readMatch(ctx.root, view3);
|
|
4418
|
+
if (run4?.error && m.state === "handoff") {
|
|
4419
|
+
m.state = "failed";
|
|
4420
|
+
m.error = run4.error;
|
|
4421
|
+
}
|
|
4422
|
+
return { status: 200, body: m };
|
|
4423
|
+
}).add("POST", "/api/links/match/done", async ({ body }) => {
|
|
4424
|
+
const b = api_exports.MatchLinksRequest.safeParse(body ?? {});
|
|
4425
|
+
if (!b.success)
|
|
4426
|
+
throw badRequest("Say both boxes: { from: <repo>, to: { repo } | { system } }.");
|
|
4427
|
+
const { from, to } = b.data;
|
|
4428
|
+
const { view: view3, facts } = await candidatesOf(ctx.root, from, to);
|
|
4429
|
+
const run4 = running.get(keyOf2(from, to));
|
|
4430
|
+
if (run4 && ctx.jobs.get(run4.jobId)?.state === "running")
|
|
4431
|
+
throw conflict(`A match of ${from} with ${view3.toName} is under way: wait for it.`);
|
|
4432
|
+
const m = await matchDone(ctx.root, { view: view3, facts });
|
|
4433
|
+
if (m.state === "handoff" || m.state === "idle")
|
|
4434
|
+
throw conflict(m.error ?? `No answer is written yet for ${from} and ${view3.toName}.`);
|
|
4435
|
+
if (m.decided?.batch) {
|
|
4436
|
+
ctx.events.publish({ type: "file.changed", path: `facts/${from}.corrections.jsonl` });
|
|
4437
|
+
ctx.events.publish({ type: "file.changed", path: "decisions/" });
|
|
4438
|
+
}
|
|
4439
|
+
return { status: 200, body: m };
|
|
4440
|
+
}).add("POST", "/api/links/match", async ({ body }) => {
|
|
4441
|
+
const b = api_exports.MatchLinksRequest.safeParse(body ?? {});
|
|
4442
|
+
if (!b.success)
|
|
4443
|
+
throw badRequest("Say both boxes: { from: <repo>, to: { repo } | { system } }.");
|
|
4444
|
+
const { from, to } = b.data;
|
|
4445
|
+
const { view: view3, facts } = await candidatesOf(ctx.root, from, to);
|
|
4446
|
+
if (!view3.calls.some((c) => c.status !== "paired"))
|
|
4447
|
+
throw conflict(`${from} has no loose call to match with ${view3.toName}.`);
|
|
4448
|
+
if (!view3.apis.length)
|
|
4449
|
+
throw conflict(`${view3.toName} has no API on record${view3.noApis ? `: ${view3.noApis.command}` : ""}.`);
|
|
4450
|
+
const key = keyOf2(from, to);
|
|
4451
|
+
const op = await loadOrgPack(orgPackDirOf(ctx.root));
|
|
4452
|
+
const had = running.get(key);
|
|
4453
|
+
if (had && ctx.jobs.get(had.jobId)?.state === "running")
|
|
4454
|
+
throw conflict(`A match of ${from} with ${view3.toName} is under way: wait for it.`);
|
|
4455
|
+
const busy = ctx.jobs.runningOf("step");
|
|
4456
|
+
if (busy?.state === "running")
|
|
4457
|
+
throw conflict(`An AI step is running on this server (${busy.id}): wait for it to finish.`);
|
|
4458
|
+
if (!copilotAcpAllowed(op) && !deps.runner) {
|
|
4459
|
+
const m = await runMatch(ctx.root, { view: view3, quotes: quotesOf(facts), mode: "hand-off" });
|
|
4460
|
+
return { status: 202, body: m };
|
|
4461
|
+
}
|
|
4462
|
+
let done;
|
|
4463
|
+
const job = ctx.jobs.start("step", async (c) => {
|
|
4464
|
+
c.progress(0, 1, `Matching ${from} with ${view3.toName}`);
|
|
4465
|
+
const signal = currentSignal();
|
|
4466
|
+
try {
|
|
4467
|
+
done = await runMatch(ctx.root, {
|
|
4468
|
+
view: view3,
|
|
4469
|
+
quotes: quotesOf(facts),
|
|
4470
|
+
facts,
|
|
4471
|
+
mode: "copilot-acp",
|
|
4472
|
+
...deps.runner ? { runner: deps.runner } : {},
|
|
4473
|
+
...signal ? { signal } : {},
|
|
4474
|
+
onProgress: (line) => c.progress(0, 1, line.slice(0, 200))
|
|
4475
|
+
});
|
|
4476
|
+
} catch (e) {
|
|
4477
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
4478
|
+
const me2 = running.get(key);
|
|
4479
|
+
if (me2)
|
|
4480
|
+
me2.error = msg;
|
|
4481
|
+
return { errors: [msg] };
|
|
4482
|
+
}
|
|
4483
|
+
const me = running.get(key);
|
|
4484
|
+
if (me && done.error)
|
|
4485
|
+
me.error = done.error;
|
|
4486
|
+
return done.state === "failed" ? { errors: [done.error ?? "The session ended without an answer."] } : { result: { state: done.state } };
|
|
4487
|
+
});
|
|
4488
|
+
running.set(key, { jobId: job.id });
|
|
4489
|
+
const files = await readMatch(ctx.root, view3);
|
|
4490
|
+
return {
|
|
4491
|
+
status: 202,
|
|
4492
|
+
body: {
|
|
4493
|
+
...files,
|
|
4494
|
+
state: "running",
|
|
4495
|
+
jobId: job.id,
|
|
4496
|
+
proposals: [],
|
|
4497
|
+
none: [],
|
|
4498
|
+
rejected: []
|
|
4499
|
+
}
|
|
4500
|
+
};
|
|
4501
|
+
});
|
|
4502
|
+
}
|
|
4503
|
+
|
|
4504
|
+
// packages/cli/dist/ui-api-decisions.js
|
|
4505
|
+
var BATCH = /^b-\d{8}-\d{6}-[0-9a-f]{6}$/;
|
|
4506
|
+
function fail(e) {
|
|
4507
|
+
if (e instanceof DecideError) {
|
|
4508
|
+
if (e.code === "not-found")
|
|
4509
|
+
throw notFound(e.message);
|
|
4510
|
+
if (e.code === "conflict")
|
|
4511
|
+
throw conflict(e.message);
|
|
4512
|
+
if (e.code === "refused")
|
|
4513
|
+
throw new HttpError(422, "Atticus can't do that", e.message);
|
|
4514
|
+
throw badRequest(e.message);
|
|
4515
|
+
}
|
|
4516
|
+
throw e;
|
|
4517
|
+
}
|
|
4518
|
+
function uiDecisionRoutes(r, ctx, deps = {}) {
|
|
4519
|
+
const now = () => deps.now?.() ?? /* @__PURE__ */ new Date();
|
|
4520
|
+
return r.add("GET", "/api/decisions", async () => ({
|
|
4521
|
+
status: 200,
|
|
4522
|
+
body: await decisionsView(ctx.root)
|
|
4523
|
+
})).add("POST", "/api/decisions/correct", async ({ body }) => {
|
|
4524
|
+
const b = api_exports.CorrectDecisionRequest.safeParse(body ?? {});
|
|
4525
|
+
if (!b.success)
|
|
4526
|
+
throw badRequest("Say the item and the right answer: { item, option } for a question, { item, api, repo } or { item, none: true } for a pairing.", {
|
|
4527
|
+
errors: b.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }))
|
|
4528
|
+
});
|
|
4529
|
+
let out;
|
|
4530
|
+
try {
|
|
4531
|
+
out = await correctDecision(ctx.root, b.data, { by: ctx.user, now: now() });
|
|
4532
|
+
} catch (e) {
|
|
4533
|
+
fail(e);
|
|
4534
|
+
}
|
|
4535
|
+
if (out.written)
|
|
4536
|
+
for (const path of out.files)
|
|
4537
|
+
ctx.events.publish({ type: "file.changed", path });
|
|
4538
|
+
return { status: 200, body: out };
|
|
4539
|
+
}).add("GET", "/api/propose-answers", async () => {
|
|
4540
|
+
const { openDecideRun, PROPOSE_CHANGE } = await import("./chunk-EFCQSMXB.js");
|
|
4541
|
+
const run4 = await openDecideRun(ctx.root, PROPOSE_CHANGE);
|
|
4542
|
+
const body = run4 ? {
|
|
4543
|
+
state: "waiting",
|
|
4544
|
+
run: run4.runId,
|
|
4545
|
+
line: "/atticus-propose",
|
|
4546
|
+
prompt: `${runsRelOf(ctx.root)}/${PROPOSE_CHANGE}/${run4.runId}/prompt.md`,
|
|
4547
|
+
done: `atticus handoff done ${run4.runId}`
|
|
4548
|
+
} : { state: "none", line: "/atticus-propose" };
|
|
4549
|
+
return { status: 200, body };
|
|
4550
|
+
}).add("POST", "/api/propose-answers", async () => {
|
|
4551
|
+
const op = await loadOrgPack(orgPackDirOf(ctx.root));
|
|
4552
|
+
if (op.runtime.ai === "off")
|
|
4553
|
+
throw conflict("runtime.yaml turns AI off here (ai: off): answer the questions yourself.");
|
|
4554
|
+
const { startProposeHandoff } = await import("./chunk-ZPDDEVQX.js");
|
|
4555
|
+
const h = await startProposeHandoff(ctx.root, { now: now() });
|
|
4556
|
+
const body = {
|
|
4557
|
+
state: "waiting",
|
|
4558
|
+
run: h.runId,
|
|
4559
|
+
line: h.line,
|
|
4560
|
+
prompt: h.promptRel,
|
|
4561
|
+
done: h.done
|
|
4562
|
+
};
|
|
4563
|
+
return { status: 201, body };
|
|
4564
|
+
}).add("POST", "/api/decisions/batches/{batchId}/undo", async ({ params }) => {
|
|
4565
|
+
const id = params.batchId ?? "";
|
|
4566
|
+
if (!BATCH.test(id))
|
|
4567
|
+
throw notFound(`There is no batch ${JSON.stringify(id)}.`);
|
|
4568
|
+
let out;
|
|
4569
|
+
try {
|
|
4570
|
+
out = await undoBatch(ctx.root, id, { by: ctx.user, now: now() });
|
|
4571
|
+
} catch (e) {
|
|
4572
|
+
fail(e);
|
|
4573
|
+
}
|
|
4574
|
+
for (const path of out.files)
|
|
4575
|
+
ctx.events.publish({ type: "file.changed", path });
|
|
4576
|
+
return { status: 200, body: out };
|
|
4577
|
+
});
|
|
4578
|
+
}
|
|
4579
|
+
|
|
4580
|
+
// packages/cli/dist/ui-api-sketch.js
|
|
4581
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
4582
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
4583
|
+
import { join as join8 } from "node:path";
|
|
4584
|
+
var CHANGE = /^[a-z0-9][a-z0-9._-]{0,199}$/;
|
|
4585
|
+
var drawnOf = (deltas) => drawnStrokes(deltas);
|
|
4586
|
+
function uiSketchRoutes(r, ctx) {
|
|
4587
|
+
const root = ctx.root;
|
|
4588
|
+
const changeOf = (v) => {
|
|
4589
|
+
if (!CHANGE.test(v))
|
|
4590
|
+
throw badRequest(`${v} isn't a change id.`);
|
|
4591
|
+
return v;
|
|
4592
|
+
};
|
|
4593
|
+
const commitOf = (change) => `git add ${changesRelOf(root)}/${change}
|
|
4594
|
+
git commit -m "${safeMessage(`${change}: drawn on the canvas`)}"`;
|
|
4595
|
+
return r.add("GET", "/api/changes/{changeId}/sketch", async ({ params }) => {
|
|
4596
|
+
const change = changeOf(params.changeId);
|
|
4597
|
+
const m = await changeMapOf(root, change);
|
|
4598
|
+
if (!m)
|
|
4599
|
+
throw notFound(`There is no change ${change}.`);
|
|
4600
|
+
const dir = join8(changesDirOf(root), change);
|
|
4601
|
+
const { deltas } = await readDeltas(dir);
|
|
4602
|
+
return {
|
|
4603
|
+
status: 200,
|
|
4604
|
+
body: {
|
|
4605
|
+
written: false,
|
|
4606
|
+
files: [],
|
|
4607
|
+
map: changeMapBody(change, m),
|
|
4608
|
+
drawn: drawnOf(deltas),
|
|
4609
|
+
commit: commitOf(change),
|
|
4610
|
+
fingerprint: await sketchFingerprint(dir)
|
|
4611
|
+
}
|
|
4612
|
+
};
|
|
4613
|
+
}).add("POST", "/api/changes/{changeId}/sketch", async ({ params, body }) => {
|
|
4614
|
+
const change = changeOf(params.changeId);
|
|
4615
|
+
const b = api_exports.SketchStrokeRequest.safeParse(body ?? {});
|
|
4616
|
+
if (!b.success)
|
|
4617
|
+
throw badRequest("Say the stroke: { stroke: { kind, ... }, preview? }.");
|
|
4618
|
+
const s = Stroke.safeParse(b.data.stroke);
|
|
4619
|
+
if (!s.success)
|
|
4620
|
+
throw badRequest("The stroke isn't one Atticus draws.", {
|
|
4621
|
+
errors: s.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }))
|
|
4622
|
+
});
|
|
4623
|
+
const c = await changeStore(root).read(change).catch(() => void 0);
|
|
4624
|
+
if (!c)
|
|
4625
|
+
throw notFound(`There is no change ${change}.`);
|
|
4626
|
+
const dir = changeFolder(root, change);
|
|
4627
|
+
const t = await targetFlowsOf(root, change);
|
|
4628
|
+
if (!t)
|
|
4629
|
+
throw notFound(`There is no change ${change}.`);
|
|
4630
|
+
const estate = await loadEstate(root, t.records);
|
|
4631
|
+
const by = ctx.user ?? "a person";
|
|
4632
|
+
return withFileLock(join8(dir, TARGET_DIR), async () => {
|
|
4633
|
+
const fingerprint = await sketchFingerprint(dir);
|
|
4634
|
+
const { deltas, problems } = await readDeltas(dir);
|
|
4635
|
+
const answer = (extra) => ({
|
|
4636
|
+
written: false,
|
|
4637
|
+
files: [],
|
|
4638
|
+
drawn: drawnOf(deltas),
|
|
4639
|
+
commit: commitOf(change),
|
|
4640
|
+
fingerprint,
|
|
4641
|
+
...extra
|
|
4642
|
+
});
|
|
4643
|
+
if (problems.length)
|
|
4644
|
+
return {
|
|
4645
|
+
status: 200,
|
|
4646
|
+
body: answer({
|
|
4647
|
+
problem: `A target flow of ${change} doesn't read, so nothing is drawn until it is fixed: ${problems[0]}`
|
|
4648
|
+
})
|
|
4649
|
+
};
|
|
4650
|
+
const strokeId = createHash3("sha256").update(fingerprint).update(JSON.stringify(s.data)).digest("hex").slice(0, 8);
|
|
4651
|
+
const res = applyStroke(deltas, s.data, estate, by, strokeId);
|
|
4652
|
+
if (res.problem)
|
|
4653
|
+
return {
|
|
4654
|
+
status: 200,
|
|
4655
|
+
body: answer({ problem: res.problem, ...res.pick ? { pick: res.pick } : {} })
|
|
4656
|
+
};
|
|
4657
|
+
const plan = await planSketchWrite(dir, res.deltas, res.changed, estate, by);
|
|
4658
|
+
const files = (await Promise.all(plan.map(async (f) => ({
|
|
4659
|
+
file: `${changesRelOf(root)}/${change}/${f.file}`,
|
|
4660
|
+
changes: changedLines(lfOnly(await readFile6(join8(dir, ...f.file.split("/")), "utf8").catch(() => "")), lfOnly(f.now ?? ""))
|
|
4661
|
+
})))).filter((f) => f.changes.length);
|
|
4662
|
+
if (b.data.preview)
|
|
4663
|
+
return { status: 200, body: answer({ files, drawn: drawnOf(res.deltas) }) };
|
|
4664
|
+
if (b.data.expect !== void 0 && b.data.expect !== fingerprint)
|
|
4665
|
+
throw conflict(`${change}'s target flows changed since the preview: look again, then draw the stroke again.`);
|
|
4666
|
+
await writeSketch(dir, plan);
|
|
4667
|
+
for (const f of files)
|
|
4668
|
+
ctx.events.publish({ type: "file.changed", path: f.file });
|
|
4669
|
+
const m = await changeMapOf(root, change);
|
|
4670
|
+
return {
|
|
4671
|
+
status: 200,
|
|
4672
|
+
body: answer({
|
|
4673
|
+
written: true,
|
|
4674
|
+
files,
|
|
4675
|
+
...m ? { map: changeMapBody(change, m) } : {},
|
|
4676
|
+
drawn: drawnOf(res.deltas),
|
|
4677
|
+
fingerprint: await sketchFingerprint(dir)
|
|
4678
|
+
})
|
|
4679
|
+
};
|
|
4680
|
+
});
|
|
4681
|
+
});
|
|
4682
|
+
}
|
|
4683
|
+
|
|
4684
|
+
// packages/cli/dist/ui-api-owner.js
|
|
4685
|
+
var REPO = /^[A-Za-z0-9._-]{1,200}$/;
|
|
4686
|
+
var TEAM = /^[a-z0-9][a-z0-9-]{0,62}$/;
|
|
4687
|
+
function uiOwnerRoutes(r, ctx) {
|
|
4688
|
+
const options = async (repo) => {
|
|
4689
|
+
if (!REPO.test(repo))
|
|
4690
|
+
throw badRequest(`${JSON.stringify(repo)} isn't a repo name.`);
|
|
4691
|
+
const op = await loadOrgPack(orgPackDirOf(ctx.root));
|
|
4692
|
+
const entry = estateRepos(op).find((x) => x.id === repo);
|
|
4693
|
+
if (!entry)
|
|
4694
|
+
throw notFound(`No repo of the manifest is ${repo}.`);
|
|
4695
|
+
const teams = (op.roles?.teams ?? []).map((t) => ({ id: t.id, name: t.name ?? t.id }));
|
|
4696
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4697
|
+
const systems = op.profiles.flatMap((p) => p.profile?.systems ?? []).filter((s) => !seen.has(s.id) && !!seen.add(s.id)).map((s) => ({ id: s.id, name: s.name || s.id })).sort((a, b) => a.id < b.id ? -1 : 1);
|
|
4698
|
+
return { entry, teams, systems };
|
|
4699
|
+
};
|
|
4700
|
+
return r.add("GET", "/api/repos/{repo}/owner", async ({ params }) => {
|
|
4701
|
+
const repo = params.repo;
|
|
4702
|
+
const o = await options(repo);
|
|
4703
|
+
const file = (await manifestFiles(ctx.root)).find((f) => f.platform === o.entry.platform);
|
|
4704
|
+
return {
|
|
4705
|
+
status: 200,
|
|
4706
|
+
body: {
|
|
4707
|
+
repo,
|
|
4708
|
+
owner: o.entry.owner,
|
|
4709
|
+
...o.entry.system ? { system: o.entry.system } : {},
|
|
4710
|
+
file: file?.rel ?? "org-pack/profiles",
|
|
4711
|
+
teams: o.teams,
|
|
4712
|
+
systems: o.systems
|
|
4713
|
+
}
|
|
4714
|
+
};
|
|
4715
|
+
}).add("PUT", "/api/repos/{repo}/owner", async ({ params, body }) => {
|
|
4716
|
+
const repo = params.repo;
|
|
4717
|
+
const b = api_exports.SetRepoOwnerRequest.safeParse(body ?? {});
|
|
4718
|
+
if (!b.success)
|
|
4719
|
+
throw badRequest("Say the owner, the system, or a team to add: { owner, system, addTeam }.", {
|
|
4720
|
+
errors: b.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }))
|
|
4721
|
+
});
|
|
4722
|
+
const o = await options(repo);
|
|
4723
|
+
const { addTeam, preview, system } = b.data;
|
|
4724
|
+
let owner = b.data.owner;
|
|
4725
|
+
if (addTeam) {
|
|
4726
|
+
if (!TEAM.test(addTeam.id))
|
|
4727
|
+
throw badRequest(`${addTeam.id} isn't a team id: lower case, digits and dashes, e.g. team-ledger.`);
|
|
4728
|
+
if (o.teams.some((t) => t.id === addTeam.id))
|
|
4729
|
+
throw badRequest(`${addTeam.id} is a team already: pick it as the owner.`);
|
|
4730
|
+
owner = addTeam.id;
|
|
4731
|
+
} else if (owner && !o.teams.some((t) => t.id === owner) && (o.teams.length || !TEAM.test(owner)))
|
|
4732
|
+
throw badRequest(`No team in roles.yaml is ${owner}: pick one, or add it as a new team.`);
|
|
4733
|
+
if (system && !o.systems.some((s) => s.id === system))
|
|
4734
|
+
throw badRequest(`No system of the profiles is ${system}.`);
|
|
4735
|
+
const files = [];
|
|
4736
|
+
const writtenSoFar = [];
|
|
4737
|
+
try {
|
|
4738
|
+
if (addTeam) {
|
|
4739
|
+
const t = await addRolesTeam(ctx.root, addTeam, { preview: true });
|
|
4740
|
+
files.push({ file: t.rel, changes: t.changes });
|
|
4741
|
+
}
|
|
4742
|
+
if (owner) {
|
|
4743
|
+
const m = await setManifestField(ctx.root, repo, "owner", owner, { preview: true });
|
|
4744
|
+
files.push({ file: m.file.rel, changes: m.changes });
|
|
4745
|
+
}
|
|
4746
|
+
if (system) {
|
|
4747
|
+
const m = await setManifestField(ctx.root, repo, "system", system, { preview: true });
|
|
4748
|
+
const f = files.find((x) => x.file === m.file.rel);
|
|
4749
|
+
if (f)
|
|
4750
|
+
f.changes.push(...m.changes);
|
|
4751
|
+
else
|
|
4752
|
+
files.push({ file: m.file.rel, changes: m.changes });
|
|
4753
|
+
}
|
|
4754
|
+
if (!preview) {
|
|
4755
|
+
if (owner)
|
|
4756
|
+
writtenSoFar.push((await setManifestField(ctx.root, repo, "owner", owner)).file.rel);
|
|
4757
|
+
if (system)
|
|
4758
|
+
writtenSoFar.push((await setManifestField(ctx.root, repo, "system", system)).file.rel);
|
|
4759
|
+
if (addTeam)
|
|
4760
|
+
await addRolesTeam(ctx.root, addTeam);
|
|
4761
|
+
for (const f of files)
|
|
4762
|
+
ctx.events.publish({ type: "file.changed", path: f.file });
|
|
4763
|
+
}
|
|
4764
|
+
} catch (e) {
|
|
4765
|
+
if (e instanceof FileChangedError)
|
|
4766
|
+
throw conflict(writtenSoFar.length ? `${e.message} (${[...new Set(writtenSoFar)].join(", ")} was written already; do the rest again.)` : e.message);
|
|
4767
|
+
if (e instanceof ManifestEditError)
|
|
4768
|
+
throw e.code === "not-found" ? notFound(e.message) : new HttpError(422, "Atticus can't write that", e.message);
|
|
4769
|
+
throw e;
|
|
4770
|
+
}
|
|
4771
|
+
return {
|
|
4772
|
+
status: 200,
|
|
4773
|
+
body: {
|
|
4774
|
+
written: !preview,
|
|
4775
|
+
files,
|
|
4776
|
+
verify: "atticus verify --all --write",
|
|
4777
|
+
commit: `git add ${files.map((f) => f.file).join(" ")}
|
|
4778
|
+
git commit -m "${safeMessage(`${repo}: ${[owner ? `owner ${owner}` : "", system ? `system ${system}` : ""].filter(Boolean).join(", ")}`)}"`
|
|
4779
|
+
}
|
|
4780
|
+
};
|
|
4781
|
+
});
|
|
4782
|
+
}
|
|
4783
|
+
|
|
4784
|
+
// packages/cli/dist/ui-api-declared.js
|
|
4785
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
4786
|
+
import { join as join9 } from "node:path";
|
|
4787
|
+
var REPO2 = /^[A-Za-z0-9._-]{1,200}$/;
|
|
4788
|
+
var says = (c) => {
|
|
4789
|
+
const what = `${c.target.kind} ${c.target.value} (${c.target.file}:${c.target.line})`;
|
|
4790
|
+
if (c.action === "wrong")
|
|
4791
|
+
return `${what} is wrong: ${c.reason ?? ""}`.trim();
|
|
4792
|
+
if (c.action === "link")
|
|
4793
|
+
return `${what} goes to ${[c.link?.method, c.link?.path].filter(Boolean).join(" ")} on ${c.link?.repo ?? c.link?.system}${c.ai ? ` (detected by AI, run ${c.ai.run})` : ""}`;
|
|
4794
|
+
if (c.action === "unlink")
|
|
4795
|
+
return `${what} reaches none of these`;
|
|
4796
|
+
const set = Object.entries(c.set ?? {}).map(([k, v]) => `${k} ${v}`).join(", ");
|
|
4797
|
+
return `${what}: ${[set, c.line ? `line ${c.line}` : ""].filter(Boolean).join(", ")}`;
|
|
4798
|
+
};
|
|
4799
|
+
function uiDeclaredRoutes(r, ctx, deps = {}) {
|
|
4800
|
+
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
4801
|
+
const fail2 = (e) => {
|
|
4802
|
+
if (e instanceof FileChangedError)
|
|
4803
|
+
throw conflict(e.message);
|
|
4804
|
+
if (e instanceof DeclareError) {
|
|
4805
|
+
if (e.code === "not-found")
|
|
4806
|
+
throw notFound(e.message);
|
|
4807
|
+
if (e.code === "exists")
|
|
4808
|
+
throw conflict(e.message);
|
|
4809
|
+
throw new HttpError(422, "Atticus can't write that", e.message);
|
|
4810
|
+
}
|
|
4811
|
+
throw e;
|
|
4812
|
+
};
|
|
4813
|
+
return r.add("GET", "/api/boxes/addable", async () => {
|
|
4814
|
+
const op = await loadOrgPack(orgPackDirOf(ctx.root));
|
|
4815
|
+
const picks = targetPicker(op, await readRepos(ctx.root));
|
|
4816
|
+
return {
|
|
4817
|
+
status: 200,
|
|
4818
|
+
body: {
|
|
4819
|
+
repos: picks.filter((p) => p.kind === "repo").map((p) => ({ id: p.id, name: p.name, read: p.read === true })),
|
|
4820
|
+
systems: picks.filter((p) => p.kind === "system").map((p) => ({
|
|
4821
|
+
id: p.id,
|
|
4822
|
+
name: p.name,
|
|
4823
|
+
...p.boundary ? { boundary: p.boundary } : {}
|
|
4824
|
+
})),
|
|
4825
|
+
teams: picks.filter((p) => p.kind === "team").map((p) => ({ id: p.id, name: p.name }))
|
|
4826
|
+
}
|
|
4827
|
+
};
|
|
4828
|
+
}).add("POST", "/api/boxes", async ({ body }) => {
|
|
4829
|
+
const b = api_exports.AddSystemRequest.safeParse(body ?? {});
|
|
4830
|
+
if (!b.success)
|
|
4831
|
+
throw badRequest("Say the system's id, name and whether it is a vendor or another team's.", {
|
|
4832
|
+
errors: b.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }))
|
|
4833
|
+
});
|
|
4834
|
+
const op = await loadOrgPack(orgPackDirOf(ctx.root));
|
|
4835
|
+
if (op.profiles.some((p) => (p.profile?.systems ?? []).some((s) => s.id === b.data.id)))
|
|
4836
|
+
throw conflict(`A system of the profiles is ${b.data.id} already: it is on the picture.`);
|
|
4837
|
+
const anyRepo = estateRepos(op)[0];
|
|
4838
|
+
if (!anyRepo)
|
|
4839
|
+
throw conflict("No repo is in a manifest yet, so there is no profile to add it to.");
|
|
4840
|
+
const sys = {
|
|
4841
|
+
id: b.data.id,
|
|
4842
|
+
name: b.data.name,
|
|
4843
|
+
boundary: b.data.boundary,
|
|
4844
|
+
...b.data.owner ? { owner: b.data.owner } : {}
|
|
4845
|
+
};
|
|
4846
|
+
if (b.data.preview) {
|
|
4847
|
+
const res = await addProfileSystem(ctx.root, anyRepo.id, sys, { preview: true }).catch((e) => {
|
|
4848
|
+
throw new HttpError(422, "Atticus can't write that", e instanceof Error ? e.message : String(e));
|
|
4849
|
+
});
|
|
4850
|
+
return {
|
|
4851
|
+
status: 200,
|
|
4852
|
+
body: {
|
|
4853
|
+
written: false,
|
|
4854
|
+
files: [{ file: res.profile, changes: res.changes ?? [] }],
|
|
4855
|
+
verify: "atticus verify --all --write",
|
|
4856
|
+
commit: ""
|
|
4857
|
+
}
|
|
4858
|
+
};
|
|
4859
|
+
}
|
|
4860
|
+
try {
|
|
4861
|
+
const res = await addProfileSystem(ctx.root, anyRepo.id, sys);
|
|
4862
|
+
ctx.events.publish({ type: "file.changed", path: res.profile });
|
|
4863
|
+
return {
|
|
4864
|
+
status: 200,
|
|
4865
|
+
body: {
|
|
4866
|
+
written: true,
|
|
4867
|
+
files: [{ file: res.profile, changes: res.changes ?? [] }],
|
|
4868
|
+
verify: "atticus verify --all --write",
|
|
4869
|
+
commit: `git add ${res.profile}
|
|
4870
|
+
git commit -m "${safeMessage(`profile: ${b.data.id} added from the canvas`)}"`
|
|
4871
|
+
}
|
|
4872
|
+
};
|
|
4873
|
+
} catch (e) {
|
|
4874
|
+
if (e instanceof FileChangedError)
|
|
4875
|
+
throw conflict(e.message);
|
|
4876
|
+
throw new HttpError(422, "Atticus can't write that", e instanceof Error ? e.message : String(e));
|
|
4877
|
+
}
|
|
4878
|
+
}).add("POST", "/api/declared-links", async ({ body }) => {
|
|
4879
|
+
const b = api_exports.DeclareLinkRequest.safeParse(body ?? {});
|
|
4880
|
+
if (!b.success)
|
|
4881
|
+
throw badRequest("Say the system and the topic with its side (publishes or listens), or the route it calls.", { errors: b.error.issues.map((i) => ({ path: i.path.join("."), message: i.message })) });
|
|
4882
|
+
const op = await loadOrgPack(orgPackDirOf(ctx.root));
|
|
4883
|
+
const own = estateRepos(op).some((x) => x.system === b.data.system);
|
|
4884
|
+
if (own && b.data.kind === "topic")
|
|
4885
|
+
throw conflict(`${b.data.system}'s repos are in the manifest: their code says what it publishes and listens on. Read them (atticus map) rather than declaring it.`);
|
|
4886
|
+
try {
|
|
4887
|
+
const { preview, ...d } = b.data;
|
|
4888
|
+
const res = await declareLink(ctx.root, d, {
|
|
4889
|
+
by: ctx.user,
|
|
4890
|
+
at: now().toISOString(),
|
|
4891
|
+
...preview ? { preview } : {}
|
|
4892
|
+
});
|
|
4893
|
+
if (res.written)
|
|
4894
|
+
ctx.events.publish({ type: "file.changed", path: res.rel });
|
|
4895
|
+
const what = d.kind === "topic" ? `${d.side} ${d.topic}` : `calls ${d.route}`;
|
|
4896
|
+
return {
|
|
4897
|
+
status: 200,
|
|
4898
|
+
body: {
|
|
4899
|
+
written: res.written,
|
|
4900
|
+
files: [{ file: res.rel, changes: res.changes }],
|
|
4901
|
+
verify: "atticus verify --all --write",
|
|
4902
|
+
commit: `git add ${res.rel}
|
|
4903
|
+
git commit -m "${safeMessage(`profile: ${d.system} ${what}, declared on the canvas`)}"`
|
|
4904
|
+
}
|
|
4905
|
+
};
|
|
4906
|
+
} catch (e) {
|
|
4907
|
+
return fail2(e);
|
|
4908
|
+
}
|
|
4909
|
+
}).add("POST", "/api/declared-links/undo", async ({ body }) => {
|
|
4910
|
+
const b = api_exports.UndeclareLinkRequest.safeParse(body ?? {});
|
|
4911
|
+
if (!b.success)
|
|
4912
|
+
throw badRequest("Say which declaration: { kind, system, value }.");
|
|
4913
|
+
try {
|
|
4914
|
+
const res = await undeclareLink(ctx.root, b.data);
|
|
4915
|
+
ctx.events.publish({ type: "file.changed", path: res.rel });
|
|
4916
|
+
return {
|
|
4917
|
+
status: 200,
|
|
4918
|
+
body: {
|
|
4919
|
+
written: true,
|
|
4920
|
+
files: [{ file: res.rel, changes: res.changes }],
|
|
4921
|
+
verify: "atticus verify --all --write",
|
|
4922
|
+
commit: `git add ${res.rel}
|
|
4923
|
+
git commit -m "${safeMessage(`profile: ${b.data.system}: a declaration undone`)}"`
|
|
4924
|
+
}
|
|
4925
|
+
};
|
|
4926
|
+
} catch (e) {
|
|
4927
|
+
return fail2(e);
|
|
4928
|
+
}
|
|
4929
|
+
}).add("GET", "/api/boxes/corrections", async ({ query }) => {
|
|
4930
|
+
const repo = query.get("repo");
|
|
4931
|
+
const system = query.get("system");
|
|
4932
|
+
if (!repo === !system)
|
|
4933
|
+
throw badRequest("Say repo=<repo> or system=<id>.");
|
|
4934
|
+
const items = [];
|
|
4935
|
+
if (repo) {
|
|
4936
|
+
if (!REPO2.test(repo))
|
|
4937
|
+
throw badRequest(`${JSON.stringify(repo)} isn't a repo name.`);
|
|
4938
|
+
const rel = `${factsRelOf(ctx.root)}/${repo}.corrections.jsonl`;
|
|
4939
|
+
const text = await readFile7(join9(factsDirOf(ctx.root), `${repo}.corrections.jsonl`), "utf8").catch(() => "");
|
|
4940
|
+
for (const line of text.split(/\r?\n/).filter((l) => l.trim())) {
|
|
4941
|
+
const c = parseCorrections(line).corrections[0];
|
|
4942
|
+
if (!c)
|
|
4943
|
+
continue;
|
|
4944
|
+
items.push({
|
|
4945
|
+
kind: c.action,
|
|
4946
|
+
says: says(c),
|
|
4947
|
+
by: c.by,
|
|
4948
|
+
at: c.at,
|
|
4949
|
+
...c.ai ? { ai: { runtime: c.ai.runtime, run: c.ai.run } } : {},
|
|
4950
|
+
...c.batch ? { batch: c.batch } : {},
|
|
4951
|
+
file: rel,
|
|
4952
|
+
undo: { repo, line }
|
|
4953
|
+
});
|
|
4954
|
+
}
|
|
4955
|
+
} else {
|
|
4956
|
+
const d = await declaredOf(ctx.root, system);
|
|
4957
|
+
for (const x of d.list.filter((y) => y.by))
|
|
4958
|
+
items.push({
|
|
4959
|
+
kind: x.kind,
|
|
4960
|
+
says: x.kind === "topic" ? `${x.side ? `${x.side} ` : ""}${x.value}` : `calls ${x.value}`,
|
|
4961
|
+
...x.by ? { by: x.by } : {},
|
|
4962
|
+
...x.at ? { at: x.at } : {},
|
|
4963
|
+
file: d.rel,
|
|
4964
|
+
undo: { kind: x.kind, system: x.system, value: x.value }
|
|
4965
|
+
});
|
|
4966
|
+
}
|
|
4967
|
+
return { status: 200, body: { items } };
|
|
4968
|
+
});
|
|
4969
|
+
}
|
|
3143
4970
|
|
|
3144
4971
|
// packages/cli/dist/ui-api-history.js
|
|
3145
4972
|
function uiHistoryRoutes(r, ctx) {
|
|
@@ -3172,18 +4999,18 @@ function uiHistoryRoutes(r, ctx) {
|
|
|
3172
4999
|
}
|
|
3173
5000
|
|
|
3174
5001
|
// packages/cli/dist/ui-api-ai.js
|
|
3175
|
-
var
|
|
3176
|
-
import { existsSync } from "node:fs";
|
|
3177
|
-
import { readFile as
|
|
3178
|
-
import { join as
|
|
5002
|
+
var import_yaml6 = __toESM(require_dist(), 1);
|
|
5003
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
5004
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
5005
|
+
import { join as join10, relative, sep } from "node:path";
|
|
3179
5006
|
var unprocessable = (detail) => new HttpError(422, "The settings aren't valid", detail);
|
|
3180
5007
|
var ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
3181
|
-
var FIELDS = ["ai", "modes", "assistants", "models", "budgets"];
|
|
5008
|
+
var FIELDS = ["ai", "modes", "assistants", "models", "budgets", "decide"];
|
|
3182
5009
|
function uiAiRoutes(r, ctx, deps = {}) {
|
|
3183
5010
|
const root = ctx.root;
|
|
3184
5011
|
const env = deps.env ?? process.env;
|
|
3185
5012
|
const keys = () => deps.keys ?? defaultKeyStore();
|
|
3186
|
-
const file = () =>
|
|
5013
|
+
const file = () => join10(orgPackDirOf(root), "runtime.yaml");
|
|
3187
5014
|
const rel = () => relative(root, file()).split(sep).join("/");
|
|
3188
5015
|
const build = async (op, type, settings) => {
|
|
3189
5016
|
if (deps.provider)
|
|
@@ -3231,13 +5058,16 @@ function uiAiRoutes(r, ctx, deps = {}) {
|
|
|
3231
5058
|
keySet: keyEnv ? !!env[keyEnv]?.trim() || !!keys().get(keyEnv) : false,
|
|
3232
5059
|
models: rt.models,
|
|
3233
5060
|
budgets: rt.budgets,
|
|
5061
|
+
// Ninth UX walk (ADR 0181): whether the AI decides first, and the bar that pauses it.
|
|
5062
|
+
decide: decideOf(rt),
|
|
5063
|
+
schemaVersion: rt.schemaVersion,
|
|
3234
5064
|
path: rel()
|
|
3235
5065
|
}
|
|
3236
5066
|
};
|
|
3237
5067
|
}).add("PUT", "/api/settings/ai", async ({ body }) => {
|
|
3238
5068
|
const b = body ?? {};
|
|
3239
|
-
const text =
|
|
3240
|
-
const raw = text !== void 0 ? (0,
|
|
5069
|
+
const text = existsSync3(file()) ? await readFile8(file(), "utf8") : void 0;
|
|
5070
|
+
const raw = text !== void 0 ? (0, import_yaml6.parse)(text) ?? {} : structuredClone(DEFAULT_RUNTIME);
|
|
3241
5071
|
for (const f of FIELDS)
|
|
3242
5072
|
if (b[f] !== void 0)
|
|
3243
5073
|
raw[f] = b[f];
|
|
@@ -3258,18 +5088,39 @@ function uiAiRoutes(r, ctx, deps = {}) {
|
|
|
3258
5088
|
}
|
|
3259
5089
|
raw.adapters = adapters;
|
|
3260
5090
|
}
|
|
5091
|
+
const names = (m) => {
|
|
5092
|
+
const x = m;
|
|
5093
|
+
return [...x?.allowed ?? [], x?.default].includes("copilot-acp");
|
|
5094
|
+
};
|
|
5095
|
+
const lifted = names(b.modes) && raw.schemaVersion === 2;
|
|
5096
|
+
if (lifted)
|
|
5097
|
+
raw.schemaVersion = 3;
|
|
5098
|
+
const liftedDecide = b.decide !== void 0 && raw.schemaVersion === 3;
|
|
5099
|
+
if (liftedDecide)
|
|
5100
|
+
raw.schemaVersion = 4;
|
|
3261
5101
|
const checked = Runtime.safeParse(raw);
|
|
3262
5102
|
if (!checked.success)
|
|
3263
5103
|
throw unprocessable(checked.error.issues.map((i) => `${i.path.join(".") || "runtime.yaml"}: ${i.message}`).join("; "));
|
|
3264
|
-
const
|
|
3265
|
-
|
|
3266
|
-
|
|
5104
|
+
const out = (() => {
|
|
5105
|
+
if (text === void 0)
|
|
5106
|
+
return (0, import_yaml6.stringify)(raw, { lineWidth: 0 });
|
|
5107
|
+
const doc = (0, import_yaml6.parseDocument)(text);
|
|
5108
|
+
for (const f of FIELDS)
|
|
5109
|
+
if (b[f] !== void 0)
|
|
5110
|
+
doc.set(f, raw[f]);
|
|
5111
|
+
if (b.model !== void 0)
|
|
5112
|
+
doc.set("adapters", raw.adapters);
|
|
5113
|
+
if (lifted || liftedDecide)
|
|
5114
|
+
doc.set("schemaVersion", raw.schemaVersion);
|
|
5115
|
+
return doc.toString({ lineWidth: 0 });
|
|
5116
|
+
})();
|
|
5117
|
+
await writeFileIfUnchanged(file(), text, inEol(out, eolOf(text ?? "")));
|
|
3267
5118
|
return {
|
|
3268
5119
|
status: 200,
|
|
3269
5120
|
body: {
|
|
3270
5121
|
ok: true,
|
|
3271
5122
|
path: rel(),
|
|
3272
|
-
note: `Saved ${rel()}.
|
|
5123
|
+
note: `Saved ${rel()}. Propose it for review: the org pack is reviewed like code.`
|
|
3273
5124
|
}
|
|
3274
5125
|
};
|
|
3275
5126
|
}).add("POST", "/api/settings/ai/key", async ({ body }) => {
|
|
@@ -3316,7 +5167,7 @@ function uiDocumentRoutes(r, ctx) {
|
|
|
3316
5167
|
const root = ctx.root;
|
|
3317
5168
|
const changed = (path) => ctx.events.publish({ type: "file.changed", path });
|
|
3318
5169
|
return r.add("GET", "/api/knowledge/documents", async () => {
|
|
3319
|
-
const { listDocuments } = await import("./chunk-
|
|
5170
|
+
const { listDocuments } = await import("./chunk-URIKUID7.js");
|
|
3320
5171
|
return { status: 200, body: api_exports.DocumentList.parse(await listDocuments(root)) };
|
|
3321
5172
|
}).add("POST", "/api/knowledge/documents", async ({ body }) => {
|
|
3322
5173
|
const b = api_exports.AttachFileRequest.safeParse(body ?? {});
|
|
@@ -3325,7 +5176,7 @@ function uiDocumentRoutes(r, ctx) {
|
|
|
3325
5176
|
const bytes = new Uint8Array(Buffer.from(b.data.content, "base64"));
|
|
3326
5177
|
if (bytes.length > MAX_FILE)
|
|
3327
5178
|
throw new HttpError(413, "The file is too large", "Add a file of 15 MB or less.");
|
|
3328
|
-
const { addToInbox } = await import("./chunk-
|
|
5179
|
+
const { addToInbox } = await import("./chunk-ZKYRDV7A.js");
|
|
3329
5180
|
const res = await addToInbox(root, [{ name: b.data.name, bytes }]);
|
|
3330
5181
|
if (!res.added.length)
|
|
3331
5182
|
throw new HttpError(422, "Atticus can't add that", res.refused[0]?.why ?? "", {
|
|
@@ -3335,7 +5186,7 @@ function uiDocumentRoutes(r, ctx) {
|
|
|
3335
5186
|
changed(a.path);
|
|
3336
5187
|
return { status: 201, body: api_exports.AddDocumentResult.parse(res) };
|
|
3337
5188
|
}, { maxBody: Math.ceil(MAX_FILE * 4 / 3) + 64 * 1024 }).add("POST", "/api/changes/{changeId}/inputs/{name}/promote", async ({ params }) => {
|
|
3338
|
-
const { AttachError, promoteChangeInput } = await import("./chunk-
|
|
5189
|
+
const { AttachError, promoteChangeInput } = await import("./chunk-XQ3YZ4QW.js");
|
|
3339
5190
|
try {
|
|
3340
5191
|
const res = await promoteChangeInput(root, params.changeId, params.name);
|
|
3341
5192
|
changed(res.path);
|
|
@@ -3352,13 +5203,13 @@ function uiDocumentRoutes(r, ctx) {
|
|
|
3352
5203
|
function uiRepoRoutes(r, ctx) {
|
|
3353
5204
|
const root = ctx.root;
|
|
3354
5205
|
return r.add("GET", "/api/repos/branches", async () => {
|
|
3355
|
-
const { repoBranches } = await import("./chunk-
|
|
5206
|
+
const { repoBranches } = await import("./chunk-YBOVNMHC.js");
|
|
3356
5207
|
return { status: 200, body: api_exports.RepoBranchesList.parse(await repoBranches(root)) };
|
|
3357
5208
|
}).add("GET", "/api/repos/compare", async ({ query }) => {
|
|
3358
5209
|
const branch = query.get("branch")?.trim() ?? "";
|
|
3359
5210
|
if (!branch)
|
|
3360
5211
|
throw badRequest("Say which branch: ?branch=<name>.");
|
|
3361
|
-
const { compareBranch } = await import("./chunk-
|
|
5212
|
+
const { compareBranch } = await import("./chunk-YBOVNMHC.js");
|
|
3362
5213
|
const c = await compareBranch(root, branch);
|
|
3363
5214
|
if (!c)
|
|
3364
5215
|
throw notFound(`${branch} hasn't been scanned beside the baseline yet.`);
|
|
@@ -3367,7 +5218,7 @@ function uiRepoRoutes(r, ctx) {
|
|
|
3367
5218
|
const b = api_exports.EditRepoBranchesRequest.safeParse(body ?? {});
|
|
3368
5219
|
if (!b.success)
|
|
3369
5220
|
throw badRequest("Send defaultBranch and branches as branch names.");
|
|
3370
|
-
const { editRepoBranches, RepoEditError } = await import("./chunk-
|
|
5221
|
+
const { editRepoBranches, RepoEditError } = await import("./chunk-YBOVNMHC.js");
|
|
3371
5222
|
try {
|
|
3372
5223
|
const file = await editRepoBranches(root, params.repoId, b.data);
|
|
3373
5224
|
ctx.events.publish({ type: "file.changed", path: file });
|
|
@@ -3380,14 +5231,56 @@ function uiRepoRoutes(r, ctx) {
|
|
|
3380
5231
|
};
|
|
3381
5232
|
} catch (e) {
|
|
3382
5233
|
if (e instanceof RepoEditError)
|
|
3383
|
-
throw e.code === "not-found" ? notFound(e.message) : badRequest(e.message);
|
|
5234
|
+
throw e.code === "not-found" ? notFound(e.message) : e.code === "conflict" ? conflict(e.message) : badRequest(e.message);
|
|
5235
|
+
throw e;
|
|
5236
|
+
}
|
|
5237
|
+
}).add("PUT", "/api/repos/{repoId}/build", async ({ params, body }) => {
|
|
5238
|
+
const b = api_exports.EditRepoBuildRequest.safeParse(body ?? {});
|
|
5239
|
+
if (!b.success)
|
|
5240
|
+
throw badRequest('Send the build command as build ("" clears it), up to 500 characters.');
|
|
5241
|
+
const { editRepoBuild, RepoEditError } = await import("./chunk-YBOVNMHC.js");
|
|
5242
|
+
try {
|
|
5243
|
+
const r2 = await editRepoBuild(root, params.repoId, b.data);
|
|
5244
|
+
ctx.events.publish({ type: "file.changed", path: r2.file });
|
|
5245
|
+
return {
|
|
5246
|
+
status: 200,
|
|
5247
|
+
body: {
|
|
5248
|
+
file: r2.file,
|
|
5249
|
+
...r2.build ? { build: r2.build } : {},
|
|
5250
|
+
note: r2.build ? `${r2.file} changed: propose it for review. A task in ${params.repoId} is now built and tested with it before its PR is raised; run the task again.` : `${r2.file} changed: propose it for review. ${params.repoId} has no build command now, so its tasks aren't built or tested.`
|
|
5251
|
+
}
|
|
5252
|
+
};
|
|
5253
|
+
} catch (e) {
|
|
5254
|
+
if (e instanceof RepoEditError)
|
|
5255
|
+
throw e.code === "not-found" ? notFound(e.message) : e.code === "conflict" ? conflict(e.message) : badRequest(e.message);
|
|
5256
|
+
throw e;
|
|
5257
|
+
}
|
|
5258
|
+
}).add("PUT", "/api/orgpack/owner", async ({ body }) => {
|
|
5259
|
+
const b = api_exports.SetOrgPackOwnerRequest.safeParse(body ?? {});
|
|
5260
|
+
if (!b.success)
|
|
5261
|
+
throw badRequest("Send the owner as one handle: { owner }.");
|
|
5262
|
+
const { setOrgPackOwner, OwnerEditError } = await import("./chunk-PQH56YF6.js");
|
|
5263
|
+
try {
|
|
5264
|
+
const r2 = await setOrgPackOwner(root, b.data.owner, b.data.was);
|
|
5265
|
+
ctx.events.publish({ type: "file.changed", path: r2.file });
|
|
5266
|
+
return {
|
|
5267
|
+
status: 200,
|
|
5268
|
+
body: {
|
|
5269
|
+
file: r2.file,
|
|
5270
|
+
owner: r2.owner,
|
|
5271
|
+
note: `${r2.owner} now looks after the org pack. ${r2.file} changed: propose it for review; its owner approves changes to the org pack.`
|
|
5272
|
+
}
|
|
5273
|
+
};
|
|
5274
|
+
} catch (e) {
|
|
5275
|
+
if (e instanceof OwnerEditError)
|
|
5276
|
+
throw e.code === "not-found" ? notFound(e.message) : e.code === "conflict" ? conflict(e.message) : badRequest(e.message);
|
|
3384
5277
|
throw e;
|
|
3385
5278
|
}
|
|
3386
5279
|
}).add("PUT", "/api/repos/{repoId}/description", async ({ params, body }) => {
|
|
3387
5280
|
const b = api_exports.EditRepoDescriptionRequest.safeParse(body ?? {});
|
|
3388
5281
|
if (!b.success)
|
|
3389
5282
|
throw badRequest("Send what the repo is as text, or accept: true to confirm the draft, or reject: true to drop it.");
|
|
3390
|
-
const { editRepoDescription, RepoEditError } = await import("./chunk-
|
|
5283
|
+
const { editRepoDescription, RepoEditError } = await import("./chunk-YBOVNMHC.js");
|
|
3391
5284
|
try {
|
|
3392
5285
|
const r2 = await editRepoDescription(root, params.repoId, b.data);
|
|
3393
5286
|
ctx.events.publish({ type: "file.changed", path: r2.file });
|
|
@@ -3401,7 +5294,7 @@ function uiRepoRoutes(r, ctx) {
|
|
|
3401
5294
|
};
|
|
3402
5295
|
} catch (e) {
|
|
3403
5296
|
if (e instanceof RepoEditError)
|
|
3404
|
-
throw e.code === "not-found" ? notFound(e.message) : badRequest(e.message);
|
|
5297
|
+
throw e.code === "not-found" ? notFound(e.message) : e.code === "conflict" ? conflict(e.message) : badRequest(e.message);
|
|
3405
5298
|
throw e;
|
|
3406
5299
|
}
|
|
3407
5300
|
});
|
|
@@ -3410,11 +5303,11 @@ function uiRepoRoutes(r, ctx) {
|
|
|
3410
5303
|
// packages/cli/dist/ui-api-cockpit.js
|
|
3411
5304
|
function uiCockpitRoutes(r, ctx) {
|
|
3412
5305
|
return r.add("GET", "/api/changes/{changeId}/cockpit", async ({ params }) => {
|
|
3413
|
-
const { cockpit } = await import("./chunk-
|
|
5306
|
+
const { cockpit } = await import("./chunk-6EXDI5GI.js");
|
|
3414
5307
|
try {
|
|
3415
5308
|
return {
|
|
3416
5309
|
status: 200,
|
|
3417
|
-
body: api_exports.ChangeCockpit.parse(await cockpit(ctx.root, params.changeId))
|
|
5310
|
+
body: api_exports.ChangeCockpit.parse(await cockpit(ctx.root, params.changeId, { user: ctx.user }))
|
|
3418
5311
|
};
|
|
3419
5312
|
} catch (e) {
|
|
3420
5313
|
if (e instanceof Error && e.name === "ChangeFileError")
|
|
@@ -3422,7 +5315,7 @@ function uiCockpitRoutes(r, ctx) {
|
|
|
3422
5315
|
throw e;
|
|
3423
5316
|
}
|
|
3424
5317
|
}).add("GET", "/api/past-changes", async ({ query }) => {
|
|
3425
|
-
const { changeAboutText, similarChanges } = await import("./chunk-
|
|
5318
|
+
const { changeAboutText, similarChanges } = await import("./chunk-BC6KKZ67.js");
|
|
3426
5319
|
const change = query.get("change");
|
|
3427
5320
|
const text = change ? await changeAboutText(ctx.root, change) : query.get("text")?.trim();
|
|
3428
5321
|
if (change && !text)
|
|
@@ -3440,11 +5333,11 @@ function uiCockpitRoutes(r, ctx) {
|
|
|
3440
5333
|
const b = api_exports.AttachPastChangeRequest.safeParse(body ?? {});
|
|
3441
5334
|
if (!b.success)
|
|
3442
5335
|
throw badRequest("Say which archived change: { like: <its folder or id> }.");
|
|
3443
|
-
const { attachPastChange, findPastChange } = await import("./chunk-
|
|
5336
|
+
const { attachPastChange, findPastChange } = await import("./chunk-BC6KKZ67.js");
|
|
3444
5337
|
const folder = await findPastChange(ctx.root, b.data.like);
|
|
3445
5338
|
if (!folder)
|
|
3446
5339
|
throw notFound(`There is no archived change ${b.data.like}.`);
|
|
3447
|
-
const { AttachError } = await import("./chunk-
|
|
5340
|
+
const { AttachError } = await import("./chunk-XQ3YZ4QW.js");
|
|
3448
5341
|
try {
|
|
3449
5342
|
const name = await attachPastChange(ctx.root, params.changeId, folder, ctx.user);
|
|
3450
5343
|
ctx.events.publish({ type: "file.changed", path: `inputs/${name}` });
|
|
@@ -3461,9 +5354,9 @@ function uiCockpitRoutes(r, ctx) {
|
|
|
3461
5354
|
}
|
|
3462
5355
|
|
|
3463
5356
|
// packages/cli/dist/ui-api-audit.js
|
|
3464
|
-
var
|
|
5357
|
+
var REPO3 = /^[a-z0-9][a-z0-9._-]{0,99}$/i;
|
|
3465
5358
|
var repoOf = (v) => {
|
|
3466
|
-
if (!
|
|
5359
|
+
if (!REPO3.test(v))
|
|
3467
5360
|
throw badRequest(`${JSON.stringify(v)} isn't a repo name.`);
|
|
3468
5361
|
return v;
|
|
3469
5362
|
};
|
|
@@ -3557,15 +5450,16 @@ function uiAuditRoutes(r, ctx, deps = {}) {
|
|
|
3557
5450
|
open: p.audit.items.filter((i) => !i.answer).length,
|
|
3558
5451
|
items: await itemsWithLines(ctx.root, repo, ofDraw(p.audit, p.drawn)),
|
|
3559
5452
|
precision: { facts: precision.facts, links: precision.links },
|
|
3560
|
-
commit: `git add ${p.fileRel}
|
|
5453
|
+
commit: `git add ${p.fileRel}
|
|
5454
|
+
git commit -m "${repo}: a person's sample audit answers"`
|
|
3561
5455
|
};
|
|
3562
5456
|
return { status: 200, body: result };
|
|
3563
5457
|
});
|
|
3564
5458
|
}
|
|
3565
5459
|
|
|
3566
5460
|
// packages/cli/dist/ui-api-outside.js
|
|
3567
|
-
import { readFile as
|
|
3568
|
-
import { join as
|
|
5461
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
5462
|
+
import { join as join11 } from "node:path";
|
|
3569
5463
|
var SPECS = /* @__PURE__ */ new Set(["openapi", "swagger"]);
|
|
3570
5464
|
var cmp = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
3571
5465
|
var OUTSIDE_ADD_SPEC = (id) => [
|
|
@@ -3577,12 +5471,13 @@ async function outsideView(root) {
|
|
|
3577
5471
|
const quiet = { out: () => void 0, err: () => void 0 };
|
|
3578
5472
|
const { op, records, inputs } = await intakeContext(root, quiet);
|
|
3579
5473
|
const systems = outsideProfileSystems(op);
|
|
5474
|
+
const stamp2 = await stampOf(root);
|
|
3580
5475
|
const estate = await estateFacts(root, op, "");
|
|
3581
5476
|
const facts = /* @__PURE__ */ new Map();
|
|
3582
5477
|
for (const r of estate.repos)
|
|
3583
5478
|
for (const f of r.facts)
|
|
3584
5479
|
facts.set(`${r.repo}\0${f.id}`, f);
|
|
3585
|
-
const joined = await estateJoinOnFile(root, op, estate);
|
|
5480
|
+
const joined = await estateJoinOnFile(root, op, estate, stamp2);
|
|
3586
5481
|
const repos = joinReposOf(op, estate.repos, componentRenames(estate.repos, op));
|
|
3587
5482
|
const { maps: sharedMaps } = await readSharedMaps(root);
|
|
3588
5483
|
const sharedJoin = sharedMaps.length ? joinSharedMaps({ outside: joined.outside ?? [], repos, maps: sharedMaps, systems }) : { matches: [], gaps: [], asks: [] };
|
|
@@ -3593,7 +5488,7 @@ async function outsideView(root) {
|
|
|
3593
5488
|
const system = systems.find((s) => s.id === d.systems[0]);
|
|
3594
5489
|
if (!system || specs.has(system.id))
|
|
3595
5490
|
continue;
|
|
3596
|
-
const body = await
|
|
5491
|
+
const body = await readFile9(join11(inputsDirOf(root), ...d.path.split("/").slice(1)), "utf8");
|
|
3597
5492
|
const spec = readVendorSpec(d.path, body, system.id);
|
|
3598
5493
|
if (spec)
|
|
3599
5494
|
specs.set(system.id, spec);
|
|
@@ -3625,7 +5520,7 @@ async function outsideView(root) {
|
|
|
3625
5520
|
...joinConventions(op)
|
|
3626
5521
|
}) : { matches: [], gaps: [], asks: [] };
|
|
3627
5522
|
const contracts = await contractCheckOf(root).catch(() => void 0);
|
|
3628
|
-
const catalog = records.length ? records : (await readCatalog(
|
|
5523
|
+
const catalog = records.length ? records : (await readCatalog(join11(catalogDirOf(root), "generated"), { cacheRoot: root })).records;
|
|
3629
5524
|
const ifaces = catalog.filter((r) => r.kind === "Interface");
|
|
3630
5525
|
const componentsOf = (id) => /* @__PURE__ */ new Set([
|
|
3631
5526
|
id,
|
|
@@ -3783,9 +5678,196 @@ function uiContractsRoutes(r, ctx, o = {}) {
|
|
|
3783
5678
|
}
|
|
3784
5679
|
|
|
3785
5680
|
// packages/cli/dist/ui-api-stages.js
|
|
3786
|
-
|
|
3787
|
-
import {
|
|
3788
|
-
|
|
5681
|
+
var import_yaml7 = __toESM(require_dist(), 1);
|
|
5682
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
5683
|
+
import { readFile as readFile11, stat as stat6 } from "node:fs/promises";
|
|
5684
|
+
import { join as join13 } from "node:path";
|
|
5685
|
+
|
|
5686
|
+
// packages/cli/dist/ui-api-drafts.js
|
|
5687
|
+
import { readdir as readdir4, readFile as readFile10, stat as stat5 } from "node:fs/promises";
|
|
5688
|
+
import { join as join12 } from "node:path";
|
|
5689
|
+
var ID3 = /^[a-z0-9][a-z0-9._-]{0,99}$/;
|
|
5690
|
+
var CORRECTION_ID = /^c-[0-9a-f]{10}$/;
|
|
5691
|
+
var exists2 = (p) => stat5(p).then(() => true, () => false);
|
|
5692
|
+
var PAGE_STAGE = {
|
|
5693
|
+
feature: "feature",
|
|
5694
|
+
architecture: "architecture",
|
|
5695
|
+
stories: "stories",
|
|
5696
|
+
tasks: "stories"
|
|
5697
|
+
};
|
|
5698
|
+
var ON_PAGE = {
|
|
5699
|
+
feature: (f) => f === "feature.md" || f === "proposal.md",
|
|
5700
|
+
architecture: (f) => /^target-flows\/[^/]+\.ya?ml$/.test(f) || f === "design.md" || f === "data.md",
|
|
5701
|
+
stories: (f) => f === "stories.md" || /^stories\/[^/]+\.md$/.test(f) || /^specs\/.+\/spec\.md$/.test(f),
|
|
5702
|
+
tasks: (f) => f === "tasks.md"
|
|
5703
|
+
};
|
|
5704
|
+
var pageOfFile = (f) => Object.keys(ON_PAGE).find((p) => ON_PAGE[p](f));
|
|
5705
|
+
async function walk(dir, sub = "") {
|
|
5706
|
+
const out = [];
|
|
5707
|
+
for (const e of await readdir4(join12(dir, sub), { withFileTypes: true }).catch(() => [])) {
|
|
5708
|
+
if (e.name.startsWith("."))
|
|
5709
|
+
continue;
|
|
5710
|
+
const rel = sub ? `${sub}/${e.name}` : e.name;
|
|
5711
|
+
if (e.isDirectory()) {
|
|
5712
|
+
if (["stage", "review", "tasks", "inputs"].includes(rel))
|
|
5713
|
+
continue;
|
|
5714
|
+
out.push(...await walk(dir, rel));
|
|
5715
|
+
} else
|
|
5716
|
+
out.push(rel);
|
|
5717
|
+
}
|
|
5718
|
+
return out;
|
|
5719
|
+
}
|
|
5720
|
+
var slashOf = (stage, change) => `/atticus-${stage === "small" ? "small" : stage} ${change}`;
|
|
5721
|
+
var nextOf = (stage, change) => ({
|
|
5722
|
+
stage,
|
|
5723
|
+
command: rerunOf(stage, change),
|
|
5724
|
+
slash: slashOf(stage, change)
|
|
5725
|
+
});
|
|
5726
|
+
var view = (c) => ({ ...c });
|
|
5727
|
+
async function writtenByStage(dir, change) {
|
|
5728
|
+
const out = [];
|
|
5729
|
+
for (const s of STAGES) {
|
|
5730
|
+
const l = await readStageLoop(dir, change, s).catch(() => void 0);
|
|
5731
|
+
if (l?.present && l.loop.written)
|
|
5732
|
+
out.push({ stage: s, hashes: l.loop.written });
|
|
5733
|
+
}
|
|
5734
|
+
return out;
|
|
5735
|
+
}
|
|
5736
|
+
var provenanceView = (p) => ({ ...p });
|
|
5737
|
+
async function stageDraftsView(root, change, page) {
|
|
5738
|
+
const dir = changeFolder(root, change);
|
|
5739
|
+
const rel = `${changesRelOf(root)}/${change}`;
|
|
5740
|
+
const problems = [];
|
|
5741
|
+
const candidates = (await walk(dir)).filter(ON_PAGE[page]).sort();
|
|
5742
|
+
const prov = await draftProvenance(dir, change, candidates, await writtenByStage(dir, change)).catch((e) => {
|
|
5743
|
+
problems.push({ file: `${rel}/stage/drafted.yaml`, message: String(e.message) });
|
|
5744
|
+
return {};
|
|
5745
|
+
});
|
|
5746
|
+
const files = [];
|
|
5747
|
+
for (const f of candidates) {
|
|
5748
|
+
const p = prov[f];
|
|
5749
|
+
if (!p)
|
|
5750
|
+
continue;
|
|
5751
|
+
const text = await readFile10(join12(dir, ...f.split("/")), "utf8").catch(() => "") ?? "";
|
|
5752
|
+
files.push({
|
|
5753
|
+
file: f,
|
|
5754
|
+
path: `${rel}/${f}`,
|
|
5755
|
+
stage: p.by === "ai" ? p.stage : PAGE_STAGE[page],
|
|
5756
|
+
drafted: provenanceView(p),
|
|
5757
|
+
items: draftItems(f, text)
|
|
5758
|
+
});
|
|
5759
|
+
}
|
|
5760
|
+
let corrections = [];
|
|
5761
|
+
try {
|
|
5762
|
+
corrections = await readCorrections(dir, change);
|
|
5763
|
+
} catch (e) {
|
|
5764
|
+
problems.push({ file: `${rel}/${CORRECTIONS_FILE}`, message: String(e.message) });
|
|
5765
|
+
}
|
|
5766
|
+
const mine = corrections.filter((c) => ON_PAGE[page](c.file)).sort((a, b) => a.at < b.at ? -1 : a.at > b.at ? 1 : 0);
|
|
5767
|
+
const waiting = mine.find((c) => c.state === "waiting");
|
|
5768
|
+
return {
|
|
5769
|
+
change,
|
|
5770
|
+
page,
|
|
5771
|
+
files,
|
|
5772
|
+
corrections: mine.map(view),
|
|
5773
|
+
next: nextOf(waiting?.stage ?? PAGE_STAGE[page], change),
|
|
5774
|
+
problems
|
|
5775
|
+
};
|
|
5776
|
+
}
|
|
5777
|
+
function pageOf(v) {
|
|
5778
|
+
const r = api_exports.DraftPage.safeParse(v);
|
|
5779
|
+
if (!r.success)
|
|
5780
|
+
throw badRequest(`${JSON.stringify(v)} isn't a page of drafts: feature, architecture, stories or tasks.`);
|
|
5781
|
+
return r.data;
|
|
5782
|
+
}
|
|
5783
|
+
var refusal = (e) => {
|
|
5784
|
+
if (e instanceof PlannerError && e.code === "refused")
|
|
5785
|
+
throw conflict(e.message);
|
|
5786
|
+
if (e instanceof PlannerError)
|
|
5787
|
+
throw new HttpError(422, "Atticus refused", e.message);
|
|
5788
|
+
throw e;
|
|
5789
|
+
};
|
|
5790
|
+
function uiDraftRoutes(r, ctx, deps = {}) {
|
|
5791
|
+
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
5792
|
+
const changeOf = async (v) => {
|
|
5793
|
+
if (!ID3.test(v))
|
|
5794
|
+
throw badRequest(`${JSON.stringify(v)} isn't a change id.`);
|
|
5795
|
+
if (!await exists2(join12(changeFolder(ctx.root, v), "change.yaml")))
|
|
5796
|
+
throw notFound(`There is no change ${v}.`);
|
|
5797
|
+
return v;
|
|
5798
|
+
};
|
|
5799
|
+
const list = async (change) => ({
|
|
5800
|
+
change,
|
|
5801
|
+
corrections: (await readCorrections(changeFolder(ctx.root, change), change).catch(refusal)).map(view)
|
|
5802
|
+
});
|
|
5803
|
+
return r.add("GET", "/api/changes/{changeId}/drafts/{page}", async ({ params }) => {
|
|
5804
|
+
const page = pageOf(params.page);
|
|
5805
|
+
const change = await changeOf(params.changeId);
|
|
5806
|
+
return { status: 200, body: await stageDraftsView(ctx.root, change, page) };
|
|
5807
|
+
}).add("GET", "/api/changes/{changeId}/corrections", async ({ params }) => {
|
|
5808
|
+
const change = await changeOf(params.changeId);
|
|
5809
|
+
return { status: 200, body: await list(change) };
|
|
5810
|
+
}).add("POST", "/api/changes/{changeId}/corrections", async ({ params, body }) => {
|
|
5811
|
+
const change = await changeOf(params.changeId);
|
|
5812
|
+
const b = api_exports.AddCorrectionRequest.safeParse(body ?? {});
|
|
5813
|
+
if (!b.success)
|
|
5814
|
+
throw badRequest("Say which draft (file, and item) and write the correction: { file, item, text }.", {
|
|
5815
|
+
errors: b.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }))
|
|
5816
|
+
});
|
|
5817
|
+
const page = pageOfFile(b.data.file);
|
|
5818
|
+
if (!page)
|
|
5819
|
+
throw notFound(`${b.data.file} isn't a stage draft of ${change}.`);
|
|
5820
|
+
const v = await stageDraftsView(ctx.root, change, page);
|
|
5821
|
+
const f = v.files.find((x) => x.file === b.data.file);
|
|
5822
|
+
if (!f)
|
|
5823
|
+
throw notFound(`${b.data.file} isn't a stage draft of ${change}.`);
|
|
5824
|
+
const item = b.data.item ? f.items.find((i) => i.id === b.data.item) : void 0;
|
|
5825
|
+
if (b.data.item && !item)
|
|
5826
|
+
throw notFound(`${b.data.file} has no item ${b.data.item} now: reload the page, then correct it again.`);
|
|
5827
|
+
const stage = f.stage;
|
|
5828
|
+
const dir = changeFolder(ctx.root, change);
|
|
5829
|
+
const { present } = await readStageLoop(dir, change, stage);
|
|
5830
|
+
if (!present)
|
|
5831
|
+
throw conflict(`The ${stage} stage of ${change} hasn't run here yet, so nothing would read a correction: run ${rerunOf(stage, change)} first.`);
|
|
5832
|
+
const c = await addCorrection(dir, change, {
|
|
5833
|
+
stage,
|
|
5834
|
+
file: f.file,
|
|
5835
|
+
...item ? { item: item.id } : {},
|
|
5836
|
+
label: item?.label ?? f.file,
|
|
5837
|
+
text: b.data.text,
|
|
5838
|
+
similar: b.data.similar,
|
|
5839
|
+
...b.data.like ? { like: b.data.like } : item?.like?.[0] ? { like: item.like[0] } : {},
|
|
5840
|
+
by: ctx.user,
|
|
5841
|
+
at: now().toISOString()
|
|
5842
|
+
}).catch(refusal);
|
|
5843
|
+
const written = `${changesRelOf(ctx.root)}/${change}/${CORRECTIONS_FILE}`;
|
|
5844
|
+
ctx.events.publish({ type: "file.changed", path: written });
|
|
5845
|
+
const result = {
|
|
5846
|
+
correction: view(c),
|
|
5847
|
+
files: [written],
|
|
5848
|
+
commit: `git add ${written}
|
|
5849
|
+
git commit -m "${change}: a correction of ${f.file}"`,
|
|
5850
|
+
next: nextOf(stage, change)
|
|
5851
|
+
};
|
|
5852
|
+
return { status: 200, body: result };
|
|
5853
|
+
}).add("POST", "/api/changes/{changeId}/corrections/{correctionId}/remove", async ({ params }) => {
|
|
5854
|
+
const change = await changeOf(params.changeId);
|
|
5855
|
+
const id = params.correctionId;
|
|
5856
|
+
if (!CORRECTION_ID.test(id))
|
|
5857
|
+
throw badRequest(`${JSON.stringify(id)} isn't a correction id.`);
|
|
5858
|
+
const gone = await removeCorrection(changeFolder(ctx.root, change), change, id).catch(refusal);
|
|
5859
|
+
if (!gone)
|
|
5860
|
+
throw notFound(`Change ${change} has no correction ${id}.`);
|
|
5861
|
+
ctx.events.publish({
|
|
5862
|
+
type: "file.changed",
|
|
5863
|
+
path: `${changesRelOf(ctx.root)}/${change}/${CORRECTIONS_FILE}`
|
|
5864
|
+
});
|
|
5865
|
+
return { status: 200, body: await list(change) };
|
|
5866
|
+
});
|
|
5867
|
+
}
|
|
5868
|
+
|
|
5869
|
+
// packages/cli/dist/ui-api-stages.js
|
|
5870
|
+
var ID4 = /^[a-z0-9][a-z0-9._-]{0,99}$/;
|
|
3789
5871
|
function findingOptions(f) {
|
|
3790
5872
|
const open = f.state === "open";
|
|
3791
5873
|
const issue = f.kind === "issue";
|
|
@@ -3797,8 +5879,8 @@ function findingOptions(f) {
|
|
|
3797
5879
|
...open && f.question ? { ask: { text: f.question.text, owner: f.question.owner } } : {}
|
|
3798
5880
|
};
|
|
3799
5881
|
}
|
|
3800
|
-
var
|
|
3801
|
-
var
|
|
5882
|
+
var exists3 = (p) => stat6(p).then(() => true, () => false);
|
|
5883
|
+
var slashOf2 = (stage, change) => `/atticus-${stage} ${change}`;
|
|
3802
5884
|
async function gateOf(root, change, stage) {
|
|
3803
5885
|
const problems = [];
|
|
3804
5886
|
let gate;
|
|
@@ -3824,7 +5906,7 @@ async function latest(root, change, gate) {
|
|
|
3824
5906
|
const r = await readRound(root, change, gate, round);
|
|
3825
5907
|
return { round, findings: r.findings, bad: r.bad };
|
|
3826
5908
|
}
|
|
3827
|
-
var
|
|
5909
|
+
var view2 = (c) => ({
|
|
3828
5910
|
question: c.question,
|
|
3829
5911
|
text: c.text,
|
|
3830
5912
|
by: c.by,
|
|
@@ -3848,7 +5930,7 @@ async function stageReviewView(root, change, stage) {
|
|
|
3848
5930
|
finding: s.finding,
|
|
3849
5931
|
file: fileRel,
|
|
3850
5932
|
options: findingOptions(s.finding),
|
|
3851
|
-
comments: comments.comments.filter((c) => c.about === fileRel).map(
|
|
5933
|
+
comments: comments.comments.filter((c) => c.about === fileRel).map(view2),
|
|
3852
5934
|
...p ? {
|
|
3853
5935
|
proposal: {
|
|
3854
5936
|
claim: p.claim,
|
|
@@ -3881,10 +5963,37 @@ async function stageReviewView(root, change, stage) {
|
|
|
3881
5963
|
},
|
|
3882
5964
|
findings,
|
|
3883
5965
|
questions,
|
|
3884
|
-
next: { command: rerunOf(stage, change), slash:
|
|
5966
|
+
next: { command: rerunOf(stage, change), slash: slashOf2(stage, change) },
|
|
3885
5967
|
problems
|
|
3886
5968
|
};
|
|
3887
5969
|
}
|
|
5970
|
+
var PLACED_HEAD = "# The feature placed against the estate (ADR 0087).";
|
|
5971
|
+
var EDITED = /^# The feature placed against the estate \(ADR 0087\)\. Edited by (.+) on (\S+); /;
|
|
5972
|
+
var sha3 = (s) => createHash4("sha256").update(s).digest("hex");
|
|
5973
|
+
function draftedOf(text) {
|
|
5974
|
+
const head = text.split("\n", 1)[0] ?? "";
|
|
5975
|
+
if (head.startsWith(PLACED_HEAD) && / Drafted by /.test(head))
|
|
5976
|
+
return { by: "ai" };
|
|
5977
|
+
const m = EDITED.exec(head);
|
|
5978
|
+
return m ? { by: "person", who: m[1], at: m[2] } : { by: "person" };
|
|
5979
|
+
}
|
|
5980
|
+
async function placementView(root, change) {
|
|
5981
|
+
const rel = `${changesRelOf(root)}/${change}`;
|
|
5982
|
+
const dir = changeFolder(root, change);
|
|
5983
|
+
const read = (f) => readFile11(join13(dir, f), "utf8").catch(() => void 0);
|
|
5984
|
+
const source = await read(FEATURE_FILE);
|
|
5985
|
+
const content = await read("feature.md") ?? "";
|
|
5986
|
+
return {
|
|
5987
|
+
change,
|
|
5988
|
+
present: source !== void 0,
|
|
5989
|
+
file: `${rel}/feature.md`,
|
|
5990
|
+
content,
|
|
5991
|
+
source: `${rel}/${FEATURE_FILE}`,
|
|
5992
|
+
sourceContent: source ?? "",
|
|
5993
|
+
sha256: sha3(source ?? ""),
|
|
5994
|
+
...source !== void 0 ? { drafted: draftedOf(source) } : {}
|
|
5995
|
+
};
|
|
5996
|
+
}
|
|
3888
5997
|
function tabOf(v) {
|
|
3889
5998
|
const r = api_exports.StageTab.safeParse(v);
|
|
3890
5999
|
if (!r.success)
|
|
@@ -3894,13 +6003,57 @@ function tabOf(v) {
|
|
|
3894
6003
|
function uiStageRoutes(r, ctx, deps = {}) {
|
|
3895
6004
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
3896
6005
|
const changeOf = async (v) => {
|
|
3897
|
-
if (!
|
|
6006
|
+
if (!ID4.test(v))
|
|
3898
6007
|
throw badRequest(`${JSON.stringify(v)} isn't a change id.`);
|
|
3899
|
-
if (!await
|
|
6008
|
+
if (!await exists3(join13(changeFolder(ctx.root, v), "change.yaml")))
|
|
3900
6009
|
throw notFound(`There is no change ${v}.`);
|
|
3901
6010
|
return v;
|
|
3902
6011
|
};
|
|
3903
|
-
return r.add("GET", "/api/changes/{changeId}/
|
|
6012
|
+
return uiDraftRoutes(r, ctx, deps).add("GET", "/api/changes/{changeId}/placement", async ({ params }) => {
|
|
6013
|
+
const change = await changeOf(params.changeId);
|
|
6014
|
+
return { status: 200, body: await placementView(ctx.root, change) };
|
|
6015
|
+
}).add("PUT", "/api/changes/{changeId}/placement", async ({ params, body }) => {
|
|
6016
|
+
const change = await changeOf(params.changeId);
|
|
6017
|
+
const b = api_exports.SavePlacementRequest.safeParse(body ?? {});
|
|
6018
|
+
if (!b.success)
|
|
6019
|
+
throw badRequest("Send feature.yaml's text and the sha256 it started from.", {
|
|
6020
|
+
errors: b.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }))
|
|
6021
|
+
});
|
|
6022
|
+
const dir = changeFolder(ctx.root, change);
|
|
6023
|
+
const file = join13(dir, FEATURE_FILE);
|
|
6024
|
+
const was = await readFile11(file, "utf8").catch(() => void 0);
|
|
6025
|
+
if (sha3(was ?? "") !== b.data.baseSha256)
|
|
6026
|
+
throw conflict(`${FEATURE_FILE} changed since you opened it. Reload it, then edit again.`);
|
|
6027
|
+
const lines = b.data.content.replace(/\r\n/g, "\n").split("\n");
|
|
6028
|
+
const own = lines[0]?.startsWith(PLACED_HEAD) ? lines.slice(1) : lines;
|
|
6029
|
+
let parsed;
|
|
6030
|
+
try {
|
|
6031
|
+
parsed = (0, import_yaml7.parse)(own.join("\n"));
|
|
6032
|
+
} catch (e) {
|
|
6033
|
+
throw new HttpError(422, "Not a placement", `${FEATURE_FILE} doesn't read as YAML: ${String(e.message ?? e).split("\n")[0]}`);
|
|
6034
|
+
}
|
|
6035
|
+
const p = FeaturePlacement.safeParse(parsed);
|
|
6036
|
+
if (!p.success)
|
|
6037
|
+
throw new HttpError(422, "Not a placement", `${FEATURE_FILE} doesn't read as a placement: ${p.error.issues.map((i) => `${i.path.join(".") || "(top)"}: ${i.message}`).join("; ")}`);
|
|
6038
|
+
if (p.data.change !== change)
|
|
6039
|
+
throw new HttpError(422, "Not a placement", `${FEATURE_FILE} names change ${p.data.change}, not ${change}.`);
|
|
6040
|
+
const at = now().toISOString();
|
|
6041
|
+
const head = `${PLACED_HEAD} Edited by ${ctx.user} on ${at}; review it in the feature PR.`;
|
|
6042
|
+
const saved = `${head}
|
|
6043
|
+
${own.join("\n")}`;
|
|
6044
|
+
await writeFileIfUnchanged(file, was, saved);
|
|
6045
|
+
const md = renderFeature(p.data);
|
|
6046
|
+
await writeFileAtomic(join13(dir, "feature.md"), md);
|
|
6047
|
+
for (const [f, content] of [
|
|
6048
|
+
[FEATURE_FILE, saved],
|
|
6049
|
+
["feature.md", md]
|
|
6050
|
+
])
|
|
6051
|
+
await recordPersonSave(dir, change, { file: f, who: ctx.user, at, content }).catch(() => void 0);
|
|
6052
|
+
const rel = `${changesRelOf(ctx.root)}/${change}`;
|
|
6053
|
+
for (const f of [FEATURE_FILE, "feature.md"])
|
|
6054
|
+
ctx.events.publish({ type: "file.changed", path: `${rel}/${f}` });
|
|
6055
|
+
return { status: 200, body: await placementView(ctx.root, change) };
|
|
6056
|
+
}).add("GET", "/api/changes/{changeId}/stages/{stage}", async ({ params }) => {
|
|
3904
6057
|
const stage = tabOf(params.stage);
|
|
3905
6058
|
const change = await changeOf(params.changeId);
|
|
3906
6059
|
return { status: 200, body: await stageReviewView(ctx.root, change, stage) };
|
|
@@ -3948,12 +6101,13 @@ function uiStageRoutes(r, ctx, deps = {}) {
|
|
|
3948
6101
|
comment: {
|
|
3949
6102
|
question: q.id,
|
|
3950
6103
|
text: q.answer.text,
|
|
3951
|
-
by: q.answer.by,
|
|
6104
|
+
by: answerByWords(q.answer.by),
|
|
3952
6105
|
at: q.answer.at,
|
|
3953
6106
|
read: false
|
|
3954
6107
|
},
|
|
3955
6108
|
files: written.files,
|
|
3956
|
-
commit: `git add ${written.files.join(" ")}
|
|
6109
|
+
commit: `git add ${written.files.join(" ")}
|
|
6110
|
+
git commit -m "${change}: a comment on ${f.finding.id}"`,
|
|
3957
6111
|
next: v.next
|
|
3958
6112
|
};
|
|
3959
6113
|
return { status: 200, body: result };
|
|
@@ -3971,6 +6125,16 @@ function catalogMayHaveChanged(root, path) {
|
|
|
3971
6125
|
};
|
|
3972
6126
|
return near(catalogDirOf(root)) || near(orgPackDirOf(root));
|
|
3973
6127
|
}
|
|
6128
|
+
function extendUiRoutes(r, ctx, deps = {}, o = {}) {
|
|
6129
|
+
const known = uiKnowRoutes(uiRunRoutes(uiRoutes(r, ctx, deps), ctx, deps), ctx, {
|
|
6130
|
+
warm: o.warm === true
|
|
6131
|
+
});
|
|
6132
|
+
const base = uiInitiativeRoutes(known, ctx);
|
|
6133
|
+
const views = uiGraphRoutes(uiAcrossRoutes(uiMeRoutes(base, ctx), ctx), ctx);
|
|
6134
|
+
const specs = uiSpecRoutes(uiOnboardingRoutes(uiQuestionRoutes(views, ctx), ctx), ctx);
|
|
6135
|
+
const all = uiComponentTypeRoutes(uiLinkMatchRoutes(uiSketchRoutes(uiDeclaredRoutes(uiOwnerRoutes(uiLinkRoutes(uiCopilotRunRoutes(uiStageRoutes(uiContractsRoutes(uiOutsideRoutes(uiAuditRoutes(uiFactsRoutes(uiTrustRoutes(uiCockpitRoutes(uiRepoRoutes(uiDocumentRoutes(uiAiRoutes(uiHistoryRoutes(uiModelRunRoutes(uiKnowledgeRoutes(uiCiteRoutes(specs, ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx);
|
|
6136
|
+
return uiDecisionRoutes(all, ctx);
|
|
6137
|
+
}
|
|
3974
6138
|
async function startUi(root, o = {}, deps = {}) {
|
|
3975
6139
|
const srv = await startServer({
|
|
3976
6140
|
root,
|
|
@@ -3993,17 +6157,10 @@ async function startUi(root, o = {}, deps = {}) {
|
|
|
3993
6157
|
log.debug("request", fields);
|
|
3994
6158
|
};
|
|
3995
6159
|
})(),
|
|
3996
|
-
extend: (r, ctx) => {
|
|
3997
|
-
const base = uiKnowRoutes(uiRunRoutes(uiRoutes(r, ctx, deps), ctx, deps), ctx, {
|
|
3998
|
-
warm: o.warm === true
|
|
3999
|
-
});
|
|
4000
|
-
const views = uiGraphRoutes(uiAcrossRoutes(uiMeRoutes(base, ctx), ctx), ctx);
|
|
4001
|
-
const specs = uiSpecRoutes(uiOnboardingRoutes(uiQuestionRoutes(views, ctx), ctx), ctx);
|
|
4002
|
-
return uiStageRoutes(uiContractsRoutes(uiOutsideRoutes(uiAuditRoutes(uiFactsRoutes(uiTrustRoutes(uiCockpitRoutes(uiRepoRoutes(uiDocumentRoutes(uiAiRoutes(uiHistoryRoutes(uiModelRunRoutes(uiKnowledgeRoutes(uiCiteRoutes(specs, ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx), ctx);
|
|
4003
|
-
}
|
|
6160
|
+
extend: (r, ctx) => extendUiRoutes(r, ctx, deps, { warm: o.warm === true })
|
|
4004
6161
|
});
|
|
4005
6162
|
keepCatalogsInMemory(true);
|
|
4006
|
-
void readCatalog(
|
|
6163
|
+
void readCatalog(join14(catalogDirOf(root), "generated"), { cacheRoot: root }).catch(() => void 0);
|
|
4007
6164
|
const stop = srv.events.listen((e) => {
|
|
4008
6165
|
const changed = e.type === "file.changed" && (typeof e.path !== "string" || catalogMayHaveChanged(root, e.path));
|
|
4009
6166
|
if (changed || e.type === "index.rebuilt")
|
|
@@ -4096,12 +6253,14 @@ async function uiCommand(root, o, io) {
|
|
|
4096
6253
|
if (o.open)
|
|
4097
6254
|
openBrowser(srv.url);
|
|
4098
6255
|
await untilStopped(o.embed === "vscode", process.stdin, o.parent !== void 0 ? { parent: o.parent } : {});
|
|
6256
|
+
stopAllBuilds();
|
|
4099
6257
|
await srv.close();
|
|
4100
6258
|
io.out("Stopped.");
|
|
4101
6259
|
return 0;
|
|
4102
6260
|
}
|
|
4103
6261
|
export {
|
|
4104
6262
|
catalogMayHaveChanged,
|
|
6263
|
+
extendUiRoutes,
|
|
4105
6264
|
startUi,
|
|
4106
6265
|
startedLines,
|
|
4107
6266
|
uiCommand,
|