@ebrindley/build 0.0.0-stage → 1.42.1-rc28
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/.build-project/providers/catalog.json +13951 -0
- package/.build-project/providers/pricing.json +1978 -0
- package/.build-project/providers/registry.json +4103 -0
- package/.github/SECURITY.md +75 -0
- package/.nvmrc +1 -0
- package/CHANGELOG.md +661 -0
- package/CODE_OF_CONDUCT.md +44 -0
- package/CONTRIBUTING.md +24 -0
- package/INSTALL.md +623 -0
- package/LICENSE +21 -0
- package/README.md +118 -2
- package/THIRD_PARTY_NOTICES.txt +26 -0
- package/dist/ai-judge-UE5UOYOO.js +191 -0
- package/dist/allowlist-grounding-KPLN6NC5.js +16 -0
- package/dist/allowlist-utils-MZZKKXRD.js +31 -0
- package/dist/apply-completion-mode-EM37UZHB.js +110 -0
- package/dist/artifact-migrator-WPACNSEP.js +276 -0
- package/dist/ask-2OZ4JFQR.js +176 -0
- package/dist/auth-6UKBTJUQ.js +185 -0
- package/dist/auth-H5KJL6HL.js +165 -0
- package/dist/auth-LVJRJDMU.js +12 -0
- package/dist/auth-NHZOCNRR.js +94 -0
- package/dist/auth-PBXHWXGW.js +95 -0
- package/dist/auth-T7Y5DCAH.js +91 -0
- package/dist/auth-TVVKCHQW.js +13 -0
- package/dist/auth-UHB2UCSS.js +97 -0
- package/dist/auth-VACA3VUL.js +98 -0
- package/dist/auth-VVLC77S3.js +44 -0
- package/dist/auth-liveness-XO4AGDDD.js +53 -0
- package/dist/autoloop-cleanup-SI3VGAAR.js +106 -0
- package/dist/autoloop-evidence-gates-J5GG5YQB.js +39 -0
- package/dist/autoloop-gate-policy-SUNAEP6Q.js +169 -0
- package/dist/autoloop-helpers-VQGQNTT6.js +52 -0
- package/dist/autoloop-ledger-P6TIDP7C.js +96 -0
- package/dist/autoloop-ledger-subscriber-HFAGOZXH.js +161 -0
- package/dist/autoloop-run-defaults-GWGZBNT7.js +27 -0
- package/dist/autoloop-run-lock-GBWRM5A2.js +197 -0
- package/dist/autoloop-success-C32QVWOP.js +93 -0
- package/dist/autoloop-termination-summary-GI6IBQWD.js +58 -0
- package/dist/autoloop-trajectory-AMKSQISD.js +70 -0
- package/dist/autoloop-wall-clock-T7ZVIQOC.js +12 -0
- package/dist/automatic-branch-cleanup-R62X2C5O.js +49 -0
- package/dist/autonomous-loop-controller-2WL363LW.js +4386 -0
- package/dist/backend-YUTFDZXZ.js +30 -0
- package/dist/background-executor-Z3ODTMD7.js +260 -0
- package/dist/backlog-75QPEAMW.js +403 -0
- package/dist/backlog-execution-intent-GWUV5TUK.js +19 -0
- package/dist/backup-active-store-XHWLN34M.js +16 -0
- package/dist/backup-machine-stores-UI4LTJOY.js +251 -0
- package/dist/backup-telemetry-db-Z4ICYCNW.js +26 -0
- package/dist/branch-archive-manager-FMSQ7YJF.js +18 -0
- package/dist/branch-cleanup-manager-ST6FJGND.js +35 -0
- package/dist/build-gate-7NKWPY62.js +68 -0
- package/dist/build-root-S7DINODY.js +18 -0
- package/dist/change-summary-R6CB6VXJ.js +50 -0
- package/dist/chunk-24MNKKOM.js +173 -0
- package/dist/chunk-2H6VZFIO.js +235 -0
- package/dist/chunk-2JIX3EKV.js +39 -0
- package/dist/chunk-2KO7HVZM.js +106 -0
- package/dist/chunk-2L36U25O.js +100 -0
- package/dist/chunk-2NMNFUQA.js +475 -0
- package/dist/chunk-2OUAEH67.js +83 -0
- package/dist/chunk-2VLJUXJU.js +115 -0
- package/dist/chunk-2VUEDIUM.js +77 -0
- package/dist/chunk-2Y2IIHPI.js +430 -0
- package/dist/chunk-2YRG3LHZ.js +220 -0
- package/dist/chunk-2Z5Q3SUY.js +65 -0
- package/dist/chunk-32IYXIE5.js +873 -0
- package/dist/chunk-33IGPPUI.js +292 -0
- package/dist/chunk-352PCJLK.js +283 -0
- package/dist/chunk-35J4NE6S.js +226 -0
- package/dist/chunk-3C7WBIVK.js +1016 -0
- package/dist/chunk-3H3EY6U7.js +1225 -0
- package/dist/chunk-3H4MWYIC.js +198 -0
- package/dist/chunk-3HHWQR3N.js +2479 -0
- package/dist/chunk-3JKNRYEE.js +14 -0
- package/dist/chunk-3LECCYZY.js +128 -0
- package/dist/chunk-3LOY6YZI.js +852 -0
- package/dist/chunk-3M57DADF.js +44 -0
- package/dist/chunk-3NOTLVLG.js +3803 -0
- package/dist/chunk-3OPP2OZB.js +1480 -0
- package/dist/chunk-3P5IN5E7.js +9 -0
- package/dist/chunk-3PL22IYZ.js +20 -0
- package/dist/chunk-3REDAJUJ.js +14 -0
- package/dist/chunk-3S2R4XJI.js +203 -0
- package/dist/chunk-3UBZI5DW.js +61 -0
- package/dist/chunk-3VV5OBGG.js +308 -0
- package/dist/chunk-3WY5TU2O.js +823 -0
- package/dist/chunk-43OKHTW4.js +82 -0
- package/dist/chunk-45KUJBDI.js +112 -0
- package/dist/chunk-47X5LM7B.js +224 -0
- package/dist/chunk-4B6FQJ77.js +268 -0
- package/dist/chunk-4BTDUT2S.js +42 -0
- package/dist/chunk-4DJL2VXA.js +24 -0
- package/dist/chunk-4EBSXZ73.js +48 -0
- package/dist/chunk-4QKP6I4C.js +294 -0
- package/dist/chunk-4U6XK2DG.js +300 -0
- package/dist/chunk-4UMRUFBD.js +132 -0
- package/dist/chunk-4US4SYJ4.js +569 -0
- package/dist/chunk-4ZPLWEZO.js +154 -0
- package/dist/chunk-56WPYDJH.js +624 -0
- package/dist/chunk-57WRCJJW.js +50 -0
- package/dist/chunk-5AW4RMNG.js +24 -0
- package/dist/chunk-5EQN56OZ.js +155 -0
- package/dist/chunk-5F43TUIN.js +38 -0
- package/dist/chunk-5FKHIKTS.js +115 -0
- package/dist/chunk-5HDP7XZG.js +91 -0
- package/dist/chunk-5KQETTNS.js +152 -0
- package/dist/chunk-5PDVN2KO.js +498 -0
- package/dist/chunk-5UBIFVRD.js +509 -0
- package/dist/chunk-5YDE3Q62.js +46 -0
- package/dist/chunk-626AJVMU.js +302 -0
- package/dist/chunk-633XZ7UF.js +3583 -0
- package/dist/chunk-63DHNHGA.js +236 -0
- package/dist/chunk-666656AR.js +568 -0
- package/dist/chunk-67YRJPJO.js +19 -0
- package/dist/chunk-6CAU7VBA.js +20 -0
- package/dist/chunk-6CB3KJRY.js +21 -0
- package/dist/chunk-6DBMALXL.js +29 -0
- package/dist/chunk-6E25C4IA.js +269 -0
- package/dist/chunk-6FIBNIQU.js +73 -0
- package/dist/chunk-6G57FYBV.js +189 -0
- package/dist/chunk-6KZKRTG3.js +4885 -0
- package/dist/chunk-6LAH2UV2.js +525 -0
- package/dist/chunk-6PZY2TTU.js +921 -0
- package/dist/chunk-6T6NHXK4.js +230 -0
- package/dist/chunk-6TBEX4R4.js +432 -0
- package/dist/chunk-6TRD7TEE.js +911 -0
- package/dist/chunk-6XCP2RAI.js +47 -0
- package/dist/chunk-726G6WDL.js +351 -0
- package/dist/chunk-75EMT7BF.js +616 -0
- package/dist/chunk-762ACDZJ.js +4696 -0
- package/dist/chunk-77I6G4CO.js +1 -0
- package/dist/chunk-7DJ6SQH3.js +510 -0
- package/dist/chunk-7HPCIOMA.js +1383 -0
- package/dist/chunk-7HYBSRPZ.js +17503 -0
- package/dist/chunk-7KBEOPVB.js +73 -0
- package/dist/chunk-7LHJDJB3.js +2222 -0
- package/dist/chunk-7NVJMH52.js +306 -0
- package/dist/chunk-7RMARDVH.js +33 -0
- package/dist/chunk-7SEWU4QG.js +36 -0
- package/dist/chunk-7TUTZTI2.js +911 -0
- package/dist/chunk-7VBDFPUM.js +340 -0
- package/dist/chunk-7VRJHTGZ.js +6406 -0
- package/dist/chunk-7YAOUUKK.js +493 -0
- package/dist/chunk-AAAODV76.js +860 -0
- package/dist/chunk-AB4HUJVQ.js +339 -0
- package/dist/chunk-AEQWV746.js +611 -0
- package/dist/chunk-AHU3FKPA.js +11639 -0
- package/dist/chunk-AISTV5XU.js +226 -0
- package/dist/chunk-AJBTKGJZ.js +48 -0
- package/dist/chunk-AJJNW7XT.js +248 -0
- package/dist/chunk-AJN5Y5YZ.js +160 -0
- package/dist/chunk-ALDTFNZ3.js +150 -0
- package/dist/chunk-ARARVIZK.js +281 -0
- package/dist/chunk-ATBM6AW5.js +53 -0
- package/dist/chunk-ATKEKM3E.js +206 -0
- package/dist/chunk-AUJLW6JZ.js +92 -0
- package/dist/chunk-AY3MHEFM.js +24 -0
- package/dist/chunk-B7PYTV72.js +236 -0
- package/dist/chunk-B7YRSULE.js +1423 -0
- package/dist/chunk-BAWJNMWF.js +339 -0
- package/dist/chunk-BBPIILO2.js +88 -0
- package/dist/chunk-BD3PGW6A.js +957 -0
- package/dist/chunk-BDPYFAB4.js +44 -0
- package/dist/chunk-BIUV23HH.js +729 -0
- package/dist/chunk-BQ3VAGXH.js +243 -0
- package/dist/chunk-BQJOGAWT.js +31 -0
- package/dist/chunk-BT7EG7CO.js +68 -0
- package/dist/chunk-BV3XQQLU.js +27 -0
- package/dist/chunk-BY6ODHNZ.js +78 -0
- package/dist/chunk-BZRLSZNV.js +79 -0
- package/dist/chunk-C3DH3NCY.js +2773 -0
- package/dist/chunk-C3KCMAJP.js +756 -0
- package/dist/chunk-C7AGUJ5K.js +267 -0
- package/dist/chunk-CBSWKQCX.js +342 -0
- package/dist/chunk-CE5OZBYY.js +21 -0
- package/dist/chunk-CFCVYHSW.js +373 -0
- package/dist/chunk-CHA2HDE5.js +126 -0
- package/dist/chunk-CIHWPGS5.js +146 -0
- package/dist/chunk-CJBSZX3F.js +127 -0
- package/dist/chunk-CLA6QIJM.js +43 -0
- package/dist/chunk-CPSVQR2I.js +365 -0
- package/dist/chunk-CRPRVNQ4.js +254 -0
- package/dist/chunk-CSIE4Y7C.js +1093 -0
- package/dist/chunk-CSOPSYDY.js +142 -0
- package/dist/chunk-CSXLLEGB.js +205 -0
- package/dist/chunk-CTDLERWU.js +293 -0
- package/dist/chunk-CULBXMSK.js +110 -0
- package/dist/chunk-D2M2Y5ID.js +21 -0
- package/dist/chunk-D37WY7SH.js +1060 -0
- package/dist/chunk-D4VJFCGZ.js +89 -0
- package/dist/chunk-D6WTZMZB.js +48 -0
- package/dist/chunk-DBHOWDUH.js +976 -0
- package/dist/chunk-DCACX7BV.js +19364 -0
- package/dist/chunk-DFHX4XYA.js +128 -0
- package/dist/chunk-DIKBRRKE.js +176 -0
- package/dist/chunk-DJG5RIOR.js +9 -0
- package/dist/chunk-DNIOIISW.js +616 -0
- package/dist/chunk-DOA5G7IA.js +315 -0
- package/dist/chunk-DP7FKP6W.js +855 -0
- package/dist/chunk-DS2JZ677.js +79 -0
- package/dist/chunk-DSRLVYBS.js +82 -0
- package/dist/chunk-EAEVKNJA.js +209 -0
- package/dist/chunk-EEUESN3T.js +575 -0
- package/dist/chunk-EJ4LUU5Y.js +73 -0
- package/dist/chunk-EJIWTPSZ.js +1063 -0
- package/dist/chunk-EJVCDTAN.js +116 -0
- package/dist/chunk-EKLUBDBQ.js +627 -0
- package/dist/chunk-EN62WLFD.js +849 -0
- package/dist/chunk-ENYRCL43.js +26 -0
- package/dist/chunk-EP22ZMFO.js +273 -0
- package/dist/chunk-EP4SVAVI.js +87 -0
- package/dist/chunk-EPAMVGI3.js +1562 -0
- package/dist/chunk-EPRMH6HO.js +24 -0
- package/dist/chunk-ES6NWJ36.js +4057 -0
- package/dist/chunk-ETA2K4KI.js +30 -0
- package/dist/chunk-ETAD4NKD.js +31 -0
- package/dist/chunk-EUWIIDQ7.js +93 -0
- package/dist/chunk-EVE3OD2W.js +141 -0
- package/dist/chunk-EXA26FFC.js +459 -0
- package/dist/chunk-EXSPAA35.js +244 -0
- package/dist/chunk-F55YABKV.js +258 -0
- package/dist/chunk-F5DNGU5W.js +27 -0
- package/dist/chunk-F622MJYV.js +103 -0
- package/dist/chunk-F6NIQD74.js +5111 -0
- package/dist/chunk-FAWJTC34.js +43 -0
- package/dist/chunk-FAZBRHGG.js +47 -0
- package/dist/chunk-FIEUSGNJ.js +39 -0
- package/dist/chunk-FKCG7K6H.js +1146 -0
- package/dist/chunk-FOVVXV45.js +229 -0
- package/dist/chunk-FRBPKBFE.js +30 -0
- package/dist/chunk-FSA5BPFI.js +268 -0
- package/dist/chunk-FSJ5TTZ3.js +29 -0
- package/dist/chunk-FT7SGLXT.js +193 -0
- package/dist/chunk-FUUVZZUB.js +62 -0
- package/dist/chunk-FYMRVUNZ.js +1697 -0
- package/dist/chunk-FYTAA5FG.js +162 -0
- package/dist/chunk-G3VB2UCZ.js +3892 -0
- package/dist/chunk-G6OIMVXH.js +405 -0
- package/dist/chunk-G7PQCXVH.js +228 -0
- package/dist/chunk-GAB6UW52.js +1087 -0
- package/dist/chunk-GAFJEYLK.js +29 -0
- package/dist/chunk-GC4CRMTS.js +642 -0
- package/dist/chunk-GFHSIWHL.js +5297 -0
- package/dist/chunk-GI5M67YA.js +735 -0
- package/dist/chunk-GIJWHUWF.js +191 -0
- package/dist/chunk-GO6DRECI.js +1 -0
- package/dist/chunk-GOFVBTMN.js +314 -0
- package/dist/chunk-GQIP72ZJ.js +13 -0
- package/dist/chunk-GQXLXRFA.js +28 -0
- package/dist/chunk-GT6HFKJB.js +48 -0
- package/dist/chunk-GVJGSSKM.js +174 -0
- package/dist/chunk-GWHGTG37.js +36 -0
- package/dist/chunk-GZAJHLKO.js +18 -0
- package/dist/chunk-GZK62I3N.js +314 -0
- package/dist/chunk-H3HGMISG.js +483 -0
- package/dist/chunk-H3ISZJMJ.js +403 -0
- package/dist/chunk-H4HXVWEC.js +9 -0
- package/dist/chunk-H6MJGKAW.js +120 -0
- package/dist/chunk-HBTTGVR5.js +353 -0
- package/dist/chunk-HBZ322WZ.js +35 -0
- package/dist/chunk-HEP3ILP4.js +34 -0
- package/dist/chunk-HGFXODKO.js +106 -0
- package/dist/chunk-HHWDTB6S.js +59 -0
- package/dist/chunk-HKO45NLZ.js +286 -0
- package/dist/chunk-HLVTEA6A.js +89 -0
- package/dist/chunk-HS3SY6HN.js +160 -0
- package/dist/chunk-HT5OCGKN.js +899 -0
- package/dist/chunk-HXIIEMGF.js +78 -0
- package/dist/chunk-I56TH7VM.js +46 -0
- package/dist/chunk-I6FN3R5D.js +352 -0
- package/dist/chunk-I7SCBHJN.js +655 -0
- package/dist/chunk-IJM4GKAT.js +529 -0
- package/dist/chunk-IMEYU36R.js +344 -0
- package/dist/chunk-INJ3SS6A.js +936 -0
- package/dist/chunk-IUKOPCCE.js +441 -0
- package/dist/chunk-IVEPZQJO.js +33 -0
- package/dist/chunk-IVZEONFC.js +43 -0
- package/dist/chunk-IWBHRSG7.js +936 -0
- package/dist/chunk-IYY3HQAD.js +484 -0
- package/dist/chunk-J2ICMYDA.js +48 -0
- package/dist/chunk-J2QCFLUN.js +505 -0
- package/dist/chunk-J5HM6V5P.js +1039 -0
- package/dist/chunk-J6NZX6QH.js +398 -0
- package/dist/chunk-JBBB2Y47.js +432 -0
- package/dist/chunk-JDCZQZU7.js +42 -0
- package/dist/chunk-JEDNXGSS.js +169 -0
- package/dist/chunk-JHP7OT6K.js +89 -0
- package/dist/chunk-JLS65NUQ.js +14 -0
- package/dist/chunk-JNMWYMC6.js +38 -0
- package/dist/chunk-JNSTWNNW.js +25 -0
- package/dist/chunk-JOSK6GEU.js +9564 -0
- package/dist/chunk-JQUMSIGC.js +100 -0
- package/dist/chunk-JVHGMURQ.js +1106 -0
- package/dist/chunk-JYXS47FQ.js +951 -0
- package/dist/chunk-K2ZMW2Z5.js +2147 -0
- package/dist/chunk-K7FAFORM.js +14 -0
- package/dist/chunk-KBJXX3ON.js +333 -0
- package/dist/chunk-KHFKVQWY.js +486 -0
- package/dist/chunk-KHMEI3DQ.js +173 -0
- package/dist/chunk-KHW3UD7B.js +69 -0
- package/dist/chunk-KKQKWAMF.js +365 -0
- package/dist/chunk-KOKXJV2U.js +455 -0
- package/dist/chunk-KQ4NGOJI.js +14 -0
- package/dist/chunk-KQYQOXMS.js +342 -0
- package/dist/chunk-KTMW65UX.js +14 -0
- package/dist/chunk-KUEWV2JH.js +593 -0
- package/dist/chunk-KXYDV3HP.js +1523 -0
- package/dist/chunk-KZ4JMGZ5.js +96 -0
- package/dist/chunk-KZWGBUIO.js +2659 -0
- package/dist/chunk-L2CBG5IX.js +1892 -0
- package/dist/chunk-L2S235CU.js +314 -0
- package/dist/chunk-L32WD57F.js +98 -0
- package/dist/chunk-LDJCKAJP.js +123 -0
- package/dist/chunk-LDWNBEN7.js +541 -0
- package/dist/chunk-LJVH57G2.js +241 -0
- package/dist/chunk-LPQ7NZEN.js +209 -0
- package/dist/chunk-LRGH3CCV.js +148 -0
- package/dist/chunk-LULOGMMM.js +1133 -0
- package/dist/chunk-LWGKN2GY.js +8284 -0
- package/dist/chunk-LX4F24ZH.js +157 -0
- package/dist/chunk-M4BUEXXF.js +839 -0
- package/dist/chunk-M6UHOC4I.js +553 -0
- package/dist/chunk-MCBNWZNO.js +657 -0
- package/dist/chunk-MEMSY6VY.js +223 -0
- package/dist/chunk-MHLEZQQI.js +145 -0
- package/dist/chunk-MJ6WNSIX.js +192 -0
- package/dist/chunk-MKASIKWZ.js +442 -0
- package/dist/chunk-MNOVBYFU.js +60 -0
- package/dist/chunk-MO2BYAAF.js +2896 -0
- package/dist/chunk-MP6P7Y2A.js +180 -0
- package/dist/chunk-MQ4TFJAG.js +3365 -0
- package/dist/chunk-MT2WAIR3.js +131 -0
- package/dist/chunk-MTU7VTNN.js +1122 -0
- package/dist/chunk-MULMXX4V.js +150 -0
- package/dist/chunk-MW2DWWVA.js +147 -0
- package/dist/chunk-MY3ZPUN4.js +151 -0
- package/dist/chunk-MYLH2S4G.js +64 -0
- package/dist/chunk-MZ5WYKNA.js +28 -0
- package/dist/chunk-N3Q2JNPV.js +249 -0
- package/dist/chunk-N5DX4JAK.js +12 -0
- package/dist/chunk-NAINGKHF.js +35 -0
- package/dist/chunk-NEQUQHOX.js +223 -0
- package/dist/chunk-NHNPEZS4.js +1408 -0
- package/dist/chunk-NHTIXJCR.js +17 -0
- package/dist/chunk-NKLPMBNV.js +1154 -0
- package/dist/chunk-NMVZ5YES.js +199 -0
- package/dist/chunk-NRFRY3GE.js +256 -0
- package/dist/chunk-NTD6CSI6.js +1266 -0
- package/dist/chunk-NUO7B3SH.js +318 -0
- package/dist/chunk-NVOHIJKG.js +1319 -0
- package/dist/chunk-NXH3RX7O.js +523 -0
- package/dist/chunk-NXZ3DURF.js +257 -0
- package/dist/chunk-O26L6F7F.js +209 -0
- package/dist/chunk-O5RRIUEP.js +124 -0
- package/dist/chunk-O5X6BKAO.js +10 -0
- package/dist/chunk-O6ZQUVTR.js +31 -0
- package/dist/chunk-O7FE75QZ.js +306 -0
- package/dist/chunk-OC7Z6AJQ.js +81 -0
- package/dist/chunk-OH7IEZ63.js +307 -0
- package/dist/chunk-OI734GRS.js +115 -0
- package/dist/chunk-OJBH62DK.js +684 -0
- package/dist/chunk-OKJLVSTJ.js +247 -0
- package/dist/chunk-OMX5VL43.js +79 -0
- package/dist/chunk-ONHAMBN6.js +12 -0
- package/dist/chunk-ONYPLIVE.js +753 -0
- package/dist/chunk-OSK7QWPD.js +637 -0
- package/dist/chunk-OTXLMJKP.js +438 -0
- package/dist/chunk-OV5PKQMA.js +213 -0
- package/dist/chunk-OXK5HA4B.js +31 -0
- package/dist/chunk-OYDWFQA4.js +272 -0
- package/dist/chunk-OZAUKWHB.js +22 -0
- package/dist/chunk-P5P2EKGH.js +94 -0
- package/dist/chunk-P6SSWAKY.js +29 -0
- package/dist/chunk-P7CQGPLS.js +30 -0
- package/dist/chunk-P7RVCHQV.js +197 -0
- package/dist/chunk-PEBWDYIW.js +726 -0
- package/dist/chunk-PFCXFO7A.js +9193 -0
- package/dist/chunk-PFLDWMX6.js +168 -0
- package/dist/chunk-PHZGLQSK.js +15883 -0
- package/dist/chunk-PNFTPNSR.js +20 -0
- package/dist/chunk-PPHXX4W7.js +175 -0
- package/dist/chunk-PPZESPJT.js +262 -0
- package/dist/chunk-PRDHI2L5.js +296 -0
- package/dist/chunk-PSTKWHHN.js +32 -0
- package/dist/chunk-PV53ODOT.js +555 -0
- package/dist/chunk-PVJBTI7P.js +24 -0
- package/dist/chunk-PXKERBKX.js +100 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-Q3DHEZA5.js +85 -0
- package/dist/chunk-Q5RZDVQK.js +204 -0
- package/dist/chunk-Q64IR2Z2.js +4933 -0
- package/dist/chunk-Q6Z5UGPL.js +398 -0
- package/dist/chunk-QAMAV4DT.js +627 -0
- package/dist/chunk-QBWF4444.js +112 -0
- package/dist/chunk-QDKYT4CI.js +22805 -0
- package/dist/chunk-QFLBRWCJ.js +126 -0
- package/dist/chunk-QILAQACE.js +107 -0
- package/dist/chunk-QJ6OEH4K.js +3683 -0
- package/dist/chunk-QK3NLYTV.js +320 -0
- package/dist/chunk-QOFLUS24.js +535 -0
- package/dist/chunk-QOIASNEJ.js +98 -0
- package/dist/chunk-QP4UTSOV.js +3587 -0
- package/dist/chunk-QP5ST7RI.js +904 -0
- package/dist/chunk-QS5AGRZN.js +167 -0
- package/dist/chunk-QTAOU53N.js +107 -0
- package/dist/chunk-QTCLJHLZ.js +351 -0
- package/dist/chunk-QTOLTG4L.js +119 -0
- package/dist/chunk-QWDV4OSL.js +142 -0
- package/dist/chunk-QWMQ74KD.js +508 -0
- package/dist/chunk-QX6LOMMH.js +158 -0
- package/dist/chunk-QXBKIHY7.js +238 -0
- package/dist/chunk-QXBKTJT6.js +270 -0
- package/dist/chunk-QYQOVOLR.js +196 -0
- package/dist/chunk-R2CKS6WT.js +73 -0
- package/dist/chunk-R2TIYG7U.js +68 -0
- package/dist/chunk-R2W3LESH.js +465 -0
- package/dist/chunk-R5EXHMUN.js +100 -0
- package/dist/chunk-RBBTBCHX.js +289 -0
- package/dist/chunk-RBKLOUXA.js +121 -0
- package/dist/chunk-RCP2Y6DQ.js +86 -0
- package/dist/chunk-RCYEJSD5.js +260 -0
- package/dist/chunk-RFDVSI4N.js +134 -0
- package/dist/chunk-RGJU63FV.js +1717 -0
- package/dist/chunk-RI4EX2QE.js +18 -0
- package/dist/chunk-RIMARPCF.js +152 -0
- package/dist/chunk-RJ6RSNT6.js +42 -0
- package/dist/chunk-RNI2GUIF.js +131 -0
- package/dist/chunk-RPHUWJ3K.js +264 -0
- package/dist/chunk-RPIMAMV7.js +361 -0
- package/dist/chunk-RQFX6YRN.js +49 -0
- package/dist/chunk-RRC5BL7B.js +285 -0
- package/dist/chunk-RSYTSBOO.js +79 -0
- package/dist/chunk-RWQQIKIC.js +35 -0
- package/dist/chunk-RZUBOZH2.js +373 -0
- package/dist/chunk-S2E632FQ.js +380 -0
- package/dist/chunk-S2VQCZO4.js +22 -0
- package/dist/chunk-S2XIMQJQ.js +681 -0
- package/dist/chunk-S47ISY27.js +183 -0
- package/dist/chunk-S6I4KISU.js +142 -0
- package/dist/chunk-S6TAFQI5.js +2403 -0
- package/dist/chunk-SBBNT5ZJ.js +27 -0
- package/dist/chunk-SDJV2DTQ.js +491 -0
- package/dist/chunk-SDPIFNLD.js +33 -0
- package/dist/chunk-SF6YK3JI.js +835 -0
- package/dist/chunk-SK3ZFONO.js +976 -0
- package/dist/chunk-SKTFRFQ7.js +1775 -0
- package/dist/chunk-SNGM452K.js +2002 -0
- package/dist/chunk-STW7OFOA.js +581 -0
- package/dist/chunk-SU6UFUQY.js +1351 -0
- package/dist/chunk-SVJM3LJA.js +27 -0
- package/dist/chunk-SVUNZOPG.js +129 -0
- package/dist/chunk-T5XLUYV3.js +34 -0
- package/dist/chunk-T7E5JS6N.js +57 -0
- package/dist/chunk-TA3N5MMO.js +450 -0
- package/dist/chunk-TAJPCXSB.js +13 -0
- package/dist/chunk-TDEMDRN2.js +1639 -0
- package/dist/chunk-TDSEX5CF.js +24 -0
- package/dist/chunk-TGCVL74Y.js +28 -0
- package/dist/chunk-TGXXYDL4.js +1012 -0
- package/dist/chunk-TIKTYUJO.js +296 -0
- package/dist/chunk-TIZAJD4M.js +6029 -0
- package/dist/chunk-TLSEZZCG.js +5549 -0
- package/dist/chunk-TMBDRHAX.js +19 -0
- package/dist/chunk-TRURQUBP.js +1217 -0
- package/dist/chunk-TSQ256N5.js +152 -0
- package/dist/chunk-TUQMMFEQ.js +2244 -0
- package/dist/chunk-U424MJLC.js +81 -0
- package/dist/chunk-U4DRS6ZW.js +11 -0
- package/dist/chunk-U5KS22IN.js +204 -0
- package/dist/chunk-UAPHFJPN.js +673 -0
- package/dist/chunk-UB7LQITD.js +1040 -0
- package/dist/chunk-UBVRHGAZ.js +237 -0
- package/dist/chunk-UDNNAQN5.js +98 -0
- package/dist/chunk-UJP3XM54.js +342 -0
- package/dist/chunk-UJYDH2MW.js +305 -0
- package/dist/chunk-UKMPASIC.js +399 -0
- package/dist/chunk-UKUL3EHK.js +763 -0
- package/dist/chunk-UPHU64NB.js +1327 -0
- package/dist/chunk-URMSZXAD.js +43 -0
- package/dist/chunk-US3RT6CY.js +525 -0
- package/dist/chunk-UTDEOPKV.js +30 -0
- package/dist/chunk-UUUDKV7N.js +13 -0
- package/dist/chunk-UVKWU3SM.js +39 -0
- package/dist/chunk-V2TVPO3X.js +521 -0
- package/dist/chunk-V3KLVK7B.js +398 -0
- package/dist/chunk-V3YFFHDR.js +17 -0
- package/dist/chunk-VAG6GUBR.js +1162 -0
- package/dist/chunk-VBENAHDA.js +1814 -0
- package/dist/chunk-VBNCKCCI.js +16 -0
- package/dist/chunk-VCGSWN5M.js +1300 -0
- package/dist/chunk-VE2O2I7M.js +115 -0
- package/dist/chunk-VIFHYTI5.js +31 -0
- package/dist/chunk-VJER3FUS.js +5080 -0
- package/dist/chunk-VLMDM56Q.js +268 -0
- package/dist/chunk-VMFZEVVX.js +99 -0
- package/dist/chunk-VNDPQVUZ.js +1853 -0
- package/dist/chunk-VSPJRLGA.js +4783 -0
- package/dist/chunk-VSWC5ZXI.js +103 -0
- package/dist/chunk-VYI4DSZP.js +2017 -0
- package/dist/chunk-W4BAIQ6L.js +1212 -0
- package/dist/chunk-W7VQAL2K.js +2203 -0
- package/dist/chunk-WEI3ZDZH.js +33 -0
- package/dist/chunk-WEIUS5NT.js +26 -0
- package/dist/chunk-WEW7UFWE.js +546 -0
- package/dist/chunk-WGQAXLNA.js +384 -0
- package/dist/chunk-WJAL4JL3.js +206 -0
- package/dist/chunk-WKFOJ5ZG.js +141 -0
- package/dist/chunk-WMWQEFLN.js +2177 -0
- package/dist/chunk-WNECKKO2.js +154 -0
- package/dist/chunk-WPKLYOAM.js +195 -0
- package/dist/chunk-WSH37YQN.js +243 -0
- package/dist/chunk-WV3KQDPE.js +84 -0
- package/dist/chunk-WZFC4V4U.js +389 -0
- package/dist/chunk-XCOIBNET.js +13 -0
- package/dist/chunk-XDM65LBX.js +53 -0
- package/dist/chunk-XGU6PBO5.js +645 -0
- package/dist/chunk-XHOI4V62.js +43 -0
- package/dist/chunk-XIBVFMLQ.js +6858 -0
- package/dist/chunk-XJ2E7YEJ.js +117 -0
- package/dist/chunk-XON4ZCYX.js +69 -0
- package/dist/chunk-XQPEWJPI.js +127 -0
- package/dist/chunk-XSJTIFUY.js +31 -0
- package/dist/chunk-XT7OVWM3.js +64 -0
- package/dist/chunk-XTXYIISX.js +1104 -0
- package/dist/chunk-XV7NZL4B.js +57 -0
- package/dist/chunk-XWIZ6B5S.js +109 -0
- package/dist/chunk-XWLIKOBX.js +240 -0
- package/dist/chunk-XZOXEIN4.js +156 -0
- package/dist/chunk-XZRS7I7W.js +3673 -0
- package/dist/chunk-Y4ZDDHB6.js +44 -0
- package/dist/chunk-Y733RB7T.js +194 -0
- package/dist/chunk-YBHUB4XR.js +14931 -0
- package/dist/chunk-YKC75XK4.js +147 -0
- package/dist/chunk-YKMXFVK7.js +27 -0
- package/dist/chunk-YO5BAJ55.js +225 -0
- package/dist/chunk-YPDCLXNZ.js +568 -0
- package/dist/chunk-YSQPGVFK.js +116 -0
- package/dist/chunk-YTVVTIWJ.js +716 -0
- package/dist/chunk-YVCMDVBB.js +698 -0
- package/dist/chunk-YYTOA6DP.js +114 -0
- package/dist/chunk-Z5WGNULV.js +88 -0
- package/dist/chunk-Z6NGVVXG.js +66 -0
- package/dist/chunk-Z7CDQNH3.js +20 -0
- package/dist/chunk-ZH4G3FU5.js +187 -0
- package/dist/chunk-ZJB6SQPA.js +257 -0
- package/dist/chunk-ZL6E4HMY.js +42 -0
- package/dist/chunk-ZMLOC3DW.js +62 -0
- package/dist/chunk-ZORW64QH.js +101 -0
- package/dist/chunk-ZVVD2XGV.js +1369 -0
- package/dist/cli-utils-ER33ODC5.js +31 -0
- package/dist/cli-validation-6CHPTANV.js +146 -0
- package/dist/commit-utils-3STAY7C7.js +49 -0
- package/dist/compatibility-notice-IHNXR2JR.js +21 -0
- package/dist/compete-config-resolver-V3GDNJMM.js +125 -0
- package/dist/compete-results-XUM3PJHS.js +318 -0
- package/dist/competition-outcome-tracker-NWSMVUPG.js +62 -0
- package/dist/config-4HHE4OIK.js +238 -0
- package/dist/config-D6YAZASH.js +10 -0
- package/dist/config-MIPRDYYV.js +46 -0
- package/dist/config-audit-GA5DCUAI.js +371 -0
- package/dist/config-explain-4LMO556H.js +71 -0
- package/dist/config-loader-RGP634PC.js +51 -0
- package/dist/config-manager-J2UTO635.js +114 -0
- package/dist/config-merger-TVUJBZTS.js +14 -0
- package/dist/config-validator-H4ZVIE56.js +122 -0
- package/dist/cost-HSIV5U2Y.js +85 -0
- package/dist/data-migration-state-OAUL2WPQ.js +35 -0
- package/dist/db-migrator-NUOW5NKR.js +34 -0
- package/dist/default-paths-UILB62BN.js +49 -0
- package/dist/discovery-V6GYUJUC.js +53 -0
- package/dist/doctor-BBSMCDWE.js +271 -0
- package/dist/doctor-context-blocks-LPY75VZA.js +231 -0
- package/dist/doctor-instructions-import-JXHDDOE5.js +70 -0
- package/dist/doctor-purpose-6YJOXPBE.js +30 -0
- package/dist/domain-analyzer-S35ABUNA.js +48 -0
- package/dist/ensure-initialized-Q6PEU55O.js +78 -0
- package/dist/entry.js +922 -0
- package/dist/error-parser-core-MZFMFANN.js +70 -0
- package/dist/evaluation-context-GQBYDAEV.js +63 -0
- package/dist/evidence-plan-resolver-5FUAP3SA.js +111 -0
- package/dist/execution-data-writer-YCG5UH37.js +72 -0
- package/dist/execution-policy-applier-PWZM5LNA.js +63 -0
- package/dist/execution-preflight-DASJWWQF.js +223 -0
- package/dist/execution-roles-KNSNNB2D.js +112 -0
- package/dist/exit-code-error-QIY5DOKF.js +18 -0
- package/dist/external-temp-cleanup-CAW7LQ6R.js +360 -0
- package/dist/factory-YCYCB7AE.js +209 -0
- package/dist/file-utils-ZQYNBQBW.js +45 -0
- package/dist/flywheel-allowlist-revert-H22HA6JE.js +21 -0
- package/dist/flywheel-autoloop-executor-PDOASJEZ.js +316 -0
- package/dist/flywheel-autoloop-unverified-TOKYFCDC.js +36 -0
- package/dist/flywheel-competition-executor-YJUMMEJO.js +320 -0
- package/dist/flywheel-executor-JWU43KAY.js +437 -0
- package/dist/flywheel-git-isolation-FQ2TRWMB.js +56 -0
- package/dist/flywheel-manifest-HDPNMWWF.js +114 -0
- package/dist/flywheel-model-defaults-UHAKTZT3.js +110 -0
- package/dist/flywheel-preflight-III2C7TH.js +163 -0
- package/dist/flywheel-resume-2O45MS7Y.js +31 -0
- package/dist/flywheel-resume-execution-lease-P2BK257J.js +59 -0
- package/dist/flywheel-safety-AVAVFXIJ.js +19 -0
- package/dist/flywheel-scope-decision-ALJUUNGG.js +14 -0
- package/dist/get-telemetry-logger-MPDVO2JA.js +155 -0
- package/dist/git-message-style-KCXGMTDT.js +104 -0
- package/dist/guidance-profile-config-G3K5YQOO.js +113 -0
- package/dist/guidance-profile-renderer-TX4TNDFL.js +23 -0
- package/dist/identity-XLQJ4YJF.js +25 -0
- package/dist/index-query-6NUY4FKX.js +37 -0
- package/dist/index.js +85588 -0
- package/dist/indexer-DL54CM3K.js +44 -0
- package/dist/init-OUZ72344.js +245 -0
- package/dist/instructions-import-offer-NSYXSITC.js +363 -0
- package/dist/instructions-run-NBII7W36.js +114 -0
- package/dist/interrupted-work-E4TLKJLE.js +43 -0
- package/dist/invoke-provider-auth-NEWEIHCI.js +38 -0
- package/dist/judge-scoring.json +64 -0
- package/dist/lab-mode-YXQ2Y3NG.js +44 -0
- package/dist/lab-utils-5QAMDJR5.js +29 -0
- package/dist/linux-host-class-YDWQX65O.js +31 -0
- package/dist/llm-judge-executor-OJSNCTFJ.js +179 -0
- package/dist/local-ci-config-VZ4WWDT5.js +48 -0
- package/dist/local-executor-DCMDDRX2.js +280 -0
- package/dist/logger-5KNKS3O4.js +154 -0
- package/dist/matrix-prompt-builder-4ZBOGZSB.js +527 -0
- package/dist/matrix-result-parser-EZJM4YXP.js +14 -0
- package/dist/merge-batch-RTEEMVDB.js +313 -0
- package/dist/merge-batch-members-VIWGVRHP.js +24 -0
- package/dist/merge-queue-TIIUSOY6.js +126 -0
- package/dist/merge-queue-trust-DUNZ4J65.js +21 -0
- package/dist/metadata-UKSMWM6J.js +29 -0
- package/dist/model-catalog-readiness-R5KJBP5M.js +202 -0
- package/dist/model-invocations-db-XTUPPQ34.js +70 -0
- package/dist/model-resolver-JFZ2MHOJ.js +39 -0
- package/dist/model-resolver-SCQ57KAQ.js +217 -0
- package/dist/model-roles-D3OR4NAH.js +110 -0
- package/dist/monitor-F4SIU5G2.js +96 -0
- package/dist/nested-worktrees-2WUWQ75N.js +23 -0
- package/dist/next-S3IRLVER.js +96 -0
- package/dist/next-UKPFRXOO.js +148 -0
- package/dist/opportunistic-TL4S26VX.js +86 -0
- package/dist/optimization-config-resolver-NAEIYU6A.js +148 -0
- package/dist/package-HJR4QJT4.js +10 -0
- package/dist/parse-git-status-7PIYFPS2.js +21 -0
- package/dist/path-security-5WJSY56G.js +41 -0
- package/dist/paths-JUI7C4KU.js +45 -0
- package/dist/plan-backlog-list-fast-SSTQL5XP.js +89 -0
- package/dist/plan-backlog-show-fast-PFRAQ3JB.js +114 -0
- package/dist/plan-sprint-list-fast-HD2KBZSY.js +110 -0
- package/dist/plan-sprint-status-fast-YFYH7WQF.js +116 -0
- package/dist/plan-task-status-fast-JU5PNLUU.js +114 -0
- package/dist/plan-to-flywheel-PY5MSY2H.js +529 -0
- package/dist/preflight-PJHGTJNZ.js +12 -0
- package/dist/process-registry-B4ZUCN7T.js +28 -0
- package/dist/process-scanner-TU3QHWVB.js +23 -0
- package/dist/processes-6FHVGT72.js +28 -0
- package/dist/processes-json-fast-YWTMUWXB.js +72 -0
- package/dist/profile-HWTC56SG.js +209 -0
- package/dist/project-runtime-paths-2UQNG5Y4.js +41 -0
- package/dist/protected-branches-N36LDBFY.js +71 -0
- package/dist/provider-aware-resource-manager-YTFAHNGJ.js +40 -0
- package/dist/provider-matrix-2KO2V5OM.js +214 -0
- package/dist/provider-matrix-renderer-MEC3PER7.js +139 -0
- package/dist/provider-output-forwarding-2AHL7YMA.js +26 -0
- package/dist/provider-registry-WCZ65QHC.js +136 -0
- package/dist/provider-temp-cleanup-IUNPJCZF.js +14 -0
- package/dist/prune-engine-EOQVWEP6.js +448 -0
- package/dist/publication-turn-S42RZTQF.js +44 -0
- package/dist/quality-gate-JQMVCKOO.js +72 -0
- package/dist/quickstart-3O6FRCFB.js +105 -0
- package/dist/readiness-GW6ABRHB.js +139 -0
- package/dist/readiness-KFZCXDTT.js +215 -0
- package/dist/registry-7XG376SY.js +217 -0
- package/dist/repair-helpers-TTV5FEF4.js +117 -0
- package/dist/repo-root-YG6MQZDW.js +28 -0
- package/dist/resolution-engine-FFEK7HQ2.js +187 -0
- package/dist/resolve-provider-cli-ZEXVZKET.js +44 -0
- package/dist/restore-telemetry-db-E7BR5PO7.js +459 -0
- package/dist/routing-events-AW6SRZ6G.js +13 -0
- package/dist/routing-history-store-FMDDQL6W.js +39 -0
- package/dist/routing-planner-C6OHO3EY.js +221 -0
- package/dist/runner-KHDNQ5KU.js +1194 -0
- package/dist/runner-PIS2BW7Y.js +1801 -0
- package/dist/safety-E3JJVSFL.js +67 -0
- package/dist/safety-stanza-HE6GXP4G.js +49 -0
- package/dist/sandbox-7LBZC5PE.js +72 -0
- package/dist/sandbox-ASWCDYZL.js +80 -0
- package/dist/schema-extensions.sql +234 -0
- package/dist/security-JI22TBEB.js +17 -0
- package/dist/setup-bb-plugin-FQXLA76Y.js +531 -0
- package/dist/setup-claude-code-NF4ZSHVE.js +197 -0
- package/dist/setup-temp-cleanup-2APZ4HMA.js +29 -0
- package/dist/shared-utils-34HJZ6JX.js +40 -0
- package/dist/simple-artifact-goal-MQLDDMMX.js +29 -0
- package/dist/sprint-N7JFTEGL.js +403 -0
- package/dist/sprint-bridge-KJXIBNRJ.js +117 -0
- package/dist/sprint-completion-dependents-34SR7JVL.js +43 -0
- package/dist/sprint-execution-service-A6JPUBWY.js +376 -0
- package/dist/sprint-manager-MU2ZUWN2.js +140 -0
- package/dist/sqlite-timeout-config-U2CT4LKU.js +13 -0
- package/dist/sqlite-wrapper-FSGJ2QEW.js +19 -0
- package/dist/stale-cleanup-orchestrator-4X6324VF.js +71 -0
- package/dist/storage-access-I3V5LER7.js +31 -0
- package/dist/store-XVG64ZR2.js +25 -0
- package/dist/task-classifier-MN2DYE5R.js +558 -0
- package/dist/task-list-fast-7AT6LTTA.js +112 -0
- package/dist/task-manager-LHPBBRRE.js +136 -0
- package/dist/task-report-OLPAWBTK.js +64 -0
- package/dist/task-type-detector-6RG3YNZF.js +27 -0
- package/dist/task-type-resolver-EQHOUIHT.js +64 -0
- package/dist/telemetry-5VYSK772.js +212 -0
- package/dist/telemetry-health-tracker-4GFW2EMP.js +12 -0
- package/dist/telemetry-path-resolver-H3NFHHQY.js +34 -0
- package/dist/telemetry-reliability-URJDTNPZ.js +76 -0
- package/dist/transports-NREZQTJK.js +106 -0
- package/dist/unified-cost-tracker-5MTBJ2CL.js +59 -0
- package/dist/unified-state-cleanup-GGAXLHXF.js +292 -0
- package/dist/universal-cost-calculator-JTFEJVWK.js +70 -0
- package/dist/user-agents-QLIGPLP2.js +30 -0
- package/dist/variant-execution-I4ZZUAWY.js +319 -0
- package/dist/variant-opt-parser-JHCXKY2K.js +251 -0
- package/dist/variant-request-input-PL37N3AN.js +11 -0
- package/dist/variant-state-cleanup-KHMXRBZN.js +287 -0
- package/dist/variant-worker-COB5YTJX.js +4517 -0
- package/dist/variant-worker.js +26 -0
- package/dist/variants-XGDSXYG3.js +267 -0
- package/dist/verification-command-YSPU4VBH.js +66 -0
- package/dist/verify-command-timeout-DQUYH33Z.js +11 -0
- package/dist/verify-commands-LOHMOFKC.js +65 -0
- package/dist/warning-JSKSFKBT.js +13 -0
- package/dist/work-edge-K65NHVWY.js +50 -0
- package/dist/work-item-writer-KY5ZWZWW.js +30 -0
- package/dist/worker-JNXXEIT6.js +1504 -0
- package/dist/worker.js +21 -0
- package/dist/workspace-tree-identity-JO5PSKTW.js +52 -0
- package/dist/worktree-environment-WTVABAQW.js +64 -0
- package/dist/worktree-metrics-VZRQI26T.js +66 -0
- package/dist/writeback-TQFQBJNU.js +50 -0
- package/docs/CLI_REFERENCE.md +8287 -0
- package/docs/PROVIDER_SETUP.md +1737 -0
- package/docs/README.md +96 -0
- package/docs/TROUBLESHOOTING.md +2209 -0
- package/docs/getting-started/QUICK_START.md +260 -0
- package/docs/getting-started/README.md +198 -0
- package/docs/getting-started/SETUP.md +25 -0
- package/docs/reference/AGENT_CONTEXT.md +84 -0
- package/docs/reference/DELIVERY_ONBOARDING.md +198 -0
- package/docs/reference/PROVIDER_RELEASE_TIERS.md +34 -0
- package/docs/reference/SECURITY.md +291 -0
- package/docs/reference/TELEMETRY_PRIVACY.md +259 -0
- package/integrations/bb-plugin-build/README.md +391 -0
- package/integrations/bb-plugin-build/app.css +431 -0
- package/integrations/bb-plugin-build/app.tsx +6210 -0
- package/integrations/bb-plugin-build/package.json +45 -0
- package/integrations/bb-plugin-build/server.ts +488 -0
- package/integrations/bb-plugin-build/src/adapter.ts +3672 -0
- package/integrations/bb-plugin-build/src/backlog-authoring-model.ts +150 -0
- package/integrations/bb-plugin-build/src/backlog-authoring-schema.ts +458 -0
- package/integrations/bb-plugin-build/src/backlog-authoring-service.ts +467 -0
- package/integrations/bb-plugin-build/src/backlog-authoring-view.ts +1025 -0
- package/integrations/bb-plugin-build/src/command-evidence-schema.ts +13 -0
- package/integrations/bb-plugin-build/src/competition-defaults-schema.ts +122 -0
- package/integrations/bb-plugin-build/src/competition-defaults-service.ts +105 -0
- package/integrations/bb-plugin-build/src/competition-defaults-view.ts +138 -0
- package/integrations/bb-plugin-build/src/contract.ts +718 -0
- package/integrations/bb-plugin-build/src/execution-activity-view.ts +98 -0
- package/integrations/bb-plugin-build/src/finalize-model.ts +205 -0
- package/integrations/bb-plugin-build/src/finalize-schema.ts +150 -0
- package/integrations/bb-plugin-build/src/finalize-service.ts +330 -0
- package/integrations/bb-plugin-build/src/finalize-view.ts +159 -0
- package/integrations/bb-plugin-build/src/judge-operations-readback.ts +303 -0
- package/integrations/bb-plugin-build/src/judge-operations-schema.ts +33 -0
- package/integrations/bb-plugin-build/src/judge-operations-view.ts +459 -0
- package/integrations/bb-plugin-build/src/model.ts +1318 -0
- package/integrations/bb-plugin-build/src/monitor-service.ts +233 -0
- package/integrations/bb-plugin-build/src/panel-read-ux.ts +97 -0
- package/integrations/bb-plugin-build/src/patch-preview-schema.ts +166 -0
- package/integrations/bb-plugin-build/src/patch-preview-service.ts +480 -0
- package/integrations/bb-plugin-build/src/patch-preview-view.ts +109 -0
- package/integrations/bb-plugin-build/src/planning-readback.ts +228 -0
- package/integrations/bb-plugin-build/src/planning-service.ts +647 -0
- package/integrations/bb-plugin-build/src/planning-sync-evidence.ts +37 -0
- package/integrations/bb-plugin-build/src/planning-workspace-readback.ts +33 -0
- package/integrations/bb-plugin-build/src/planning-workspace-schema.ts +131 -0
- package/integrations/bb-plugin-build/src/planning-workspace.ts +333 -0
- package/integrations/bb-plugin-build/src/poll-handoff.ts +136 -0
- package/integrations/bb-plugin-build/src/project-target-server.ts +21 -0
- package/integrations/bb-plugin-build/src/project-target.ts +45 -0
- package/integrations/bb-plugin-build/src/reference-index.ts +218 -0
- package/integrations/bb-plugin-build/src/repository-identity.ts +17 -0
- package/integrations/bb-plugin-build/src/repository-schema.ts +30 -0
- package/integrations/bb-plugin-build/src/result-explorer-view.ts +597 -0
- package/integrations/bb-plugin-build/src/result-readback-model.ts +163 -0
- package/integrations/bb-plugin-build/src/result-readback-schema.ts +319 -0
- package/integrations/bb-plugin-build/src/result-readback-service.ts +333 -0
- package/integrations/bb-plugin-build/src/run-page-view.ts +332 -0
- package/integrations/bb-plugin-build/src/setup-config-schema.ts +293 -0
- package/integrations/bb-plugin-build/src/setup-config-service.ts +620 -0
- package/integrations/bb-plugin-build/src/setup-config-view.ts +388 -0
- package/integrations/bb-plugin-build/src/sprint-close-model.ts +150 -0
- package/integrations/bb-plugin-build/src/sprint-close-schema.ts +128 -0
- package/integrations/bb-plugin-build/src/sprint-close-service.ts +293 -0
- package/integrations/bb-plugin-build/src/sprint-close-view.ts +116 -0
- package/integrations/bb-plugin-build/src/sprint-composition-model.ts +709 -0
- package/integrations/bb-plugin-build/src/sprint-composition-readback.ts +231 -0
- package/integrations/bb-plugin-build/src/sprint-composition-schema.ts +597 -0
- package/integrations/bb-plugin-build/src/sprint-composition-service.ts +773 -0
- package/integrations/bb-plugin-build/src/sprint-composition-view.ts +1221 -0
- package/integrations/bb-plugin-build/src/sprint-execution-schema.ts +188 -0
- package/integrations/bb-plugin-build/src/sprint-execution-service.ts +289 -0
- package/integrations/bb-plugin-build/src/sprint-execution-view.ts +54 -0
- package/integrations/bb-plugin-build/src/task-authoring-model.ts +563 -0
- package/integrations/bb-plugin-build/src/task-authoring-schema.ts +629 -0
- package/integrations/bb-plugin-build/src/task-authoring-service.ts +842 -0
- package/integrations/bb-plugin-build/src/task-authoring-view.ts +1227 -0
- package/integrations/bb-plugin-build/src/task-catalog-schema.ts +46 -0
- package/integrations/bb-plugin-build/src/task-catalog-service.ts +44 -0
- package/integrations/bb-plugin-build/src/task-detail-readback.ts +56 -0
- package/integrations/bb-plugin-build/src/task-detail-schema.ts +171 -0
- package/integrations/bb-plugin-build/src/task-navigation.ts +446 -0
- package/integrations/bb-plugin-build/src/workbench-route.ts +74 -0
- package/package.json +306 -4
- package/schemas/README.md +80 -0
- package/schemas/build.config.schema.json +2110 -0
- package/schemas/config-v1.schema.json +136 -0
- package/schemas/execution-config.schema.json +47 -0
- package/schemas/judge-scoring.schema.json +257 -0
- package/schemas/provider-config.schema.json +179 -0
- package/schemas/telemetry-config.schema.json +79 -0
- package/schemas/user-preferences.schema.json +141 -0
- package/scripts/assert-node-runtime.mjs +146 -0
- package/scripts/preflight-native.mjs +49 -0
- package/scripts/setup-git-hooks.mjs +39 -0
- package/scripts/sync.sh +2871 -0
- package/scripts/write-node-launcher.sh +138 -0
- package/src/resources/gemini/slash-packs/default/plan.toml +15 -0
- package/src/resources/gemini/slash-packs/default/summary.toml +16 -0
- package/src/resources/gemini/slash-packs/default/tests.toml +16 -0
- package/templates/.build-project/README.md +41 -0
- package/templates/.build-project/agents/README.md +50 -0
- package/templates/.build-project/agents/architect.md +10 -0
- package/templates/.build-project/agents/code-reviewer.md +10 -0
- package/templates/.build-project/agents/debugger.md +10 -0
- package/templates/.build-project/agents/documenter.md +10 -0
- package/templates/.build-project/agents/test-automator.md +10 -0
- package/templates/.build-project/config/build.config.jsonc +64 -0
- package/templates/.build-project/config/project-context.template.json +6 -0
- package/templates/.build-project/config/task-type-aliases.presets/kanban.yaml +14 -0
- package/templates/.build-project/config/task-type-aliases.presets/scrum.yaml +17 -0
- package/templates/.build-project/config/task-type-aliases.presets/xp.yaml +12 -0
- package/templates/.build-project/config/task-type-aliases.yaml +29 -0
- package/templates/.build-project/gitignore.template +70 -0
- package/templates/.build-project/task-types/analysis.yaml +38 -0
- package/templates/.build-project/task-types/architecture.yaml +35 -0
- package/templates/.build-project/task-types/doc.yaml +34 -0
- package/templates/.build-project/task-types/feature.yaml +22 -0
- package/templates/.build-project/task-types/general.yaml +4 -0
- package/templates/.build-project/task-types/security.yaml +38 -0
- package/templates/AGENTS.template.md +85 -0
- package/templates/CLAUDE.template.md +1 -0
- package/templates/GEMINI.template.md +1 -0
- package/templates/builtin-workflows/code-review.yaml +73 -0
- package/templates/builtin-workflows/skills/code-review/SKILL.md +61 -0
- package/templates/builtin-workflows/skills/execution-contract-analysis/SKILL.md +24 -0
- package/templates/builtin-workflows/skills/execution-contract-code/SKILL.md +19 -0
- package/templates/builtin-workflows/skills/execution-contract-structured/SKILL.md +17 -0
- package/templates/ci/incident-intake.mjs +787 -0
- package/templates/ci/incidents.yml.template +103 -0
- package/templates/ci/node.yml.template +17 -0
- package/templates/ci/python.yml.template +17 -0
- package/templates/guard-kit/GUARD_SETUP.md.template +258 -0
- package/templates/guard-kit/build-guard.yml.template +189 -0
- package/templates/guard-kit/check.mjs.template +932 -0
- package/templates/guard-kit/config.json.template +7 -0
- package/templates/guard-kit/policy.json.template +1 -0
- package/templates/profiles/README.md +57 -0
- package/templates/profiles/frontier-claude.json +23 -0
- package/templates/profiles/frontier-codex.json +23 -0
|
@@ -0,0 +1,1369 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getWorkflowLastActivityMs
|
|
3
|
+
} from "./chunk-6TRD7TEE.js";
|
|
4
|
+
import {
|
|
5
|
+
getBranchCleanupQueuePath,
|
|
6
|
+
readBranchCleanupQueue,
|
|
7
|
+
removeBranchCleanupEntries
|
|
8
|
+
} from "./chunk-MULMXX4V.js";
|
|
9
|
+
import {
|
|
10
|
+
parseGitWorktreeBranches
|
|
11
|
+
} from "./chunk-UTDEOPKV.js";
|
|
12
|
+
import {
|
|
13
|
+
parseJsonWithContext
|
|
14
|
+
} from "./chunk-P6SSWAKY.js";
|
|
15
|
+
import {
|
|
16
|
+
isEphemeralBuildBranchDeletionCandidate,
|
|
17
|
+
isProtectedPipelineBranch,
|
|
18
|
+
parseCurrentBranchRef,
|
|
19
|
+
resolveDefaultBranch
|
|
20
|
+
} from "./chunk-XGU6PBO5.js";
|
|
21
|
+
import {
|
|
22
|
+
buildRemovedBranchName,
|
|
23
|
+
buildVariantBranchPrefixes,
|
|
24
|
+
findBuildBranchShape,
|
|
25
|
+
isBuildOwnedBranch,
|
|
26
|
+
isValidationBranch,
|
|
27
|
+
runBranchNameCandidates,
|
|
28
|
+
runChildBranchTargets
|
|
29
|
+
} from "./chunk-F55YABKV.js";
|
|
30
|
+
import {
|
|
31
|
+
resolveRunStateDir,
|
|
32
|
+
resolveRunStateReadDirs
|
|
33
|
+
} from "./chunk-AJN5Y5YZ.js";
|
|
34
|
+
import {
|
|
35
|
+
execGit
|
|
36
|
+
} from "./chunk-MHLEZQQI.js";
|
|
37
|
+
import {
|
|
38
|
+
resolveBuildDirFromContext
|
|
39
|
+
} from "./chunk-7VRJHTGZ.js";
|
|
40
|
+
|
|
41
|
+
// src/core/cleanup/branch-cleanup-manager.ts
|
|
42
|
+
import { existsSync as existsSync2 } from "fs";
|
|
43
|
+
import { resolve as resolve4 } from "path";
|
|
44
|
+
import { execa as execa2 } from "execa";
|
|
45
|
+
|
|
46
|
+
// src/core/git/cleanup-current-branch.ts
|
|
47
|
+
import { execa } from "execa";
|
|
48
|
+
var CLEANUP_UNBORN_REPOSITORY_INFO = "Info: repository has no commits yet";
|
|
49
|
+
var CLEANUP_HEAD_INSPECTION_ERROR = "Error: could not inspect repository HEAD";
|
|
50
|
+
var AMBIGUOUS_HEAD_SIGNATURE = /ambiguous argument ['"]HEAD['"]/i;
|
|
51
|
+
var UNKNOWN_REVISION_SIGNATURE = /unknown revision|bad object/i;
|
|
52
|
+
function isAmbiguousHeadFailure(stderr, stdout) {
|
|
53
|
+
const combined = `${stderr}
|
|
54
|
+
${stdout}`;
|
|
55
|
+
return AMBIGUOUS_HEAD_SIGNATURE.test(combined);
|
|
56
|
+
}
|
|
57
|
+
function isUnknownRevisionFailure(stderr, stdout) {
|
|
58
|
+
const combined = `${stderr}
|
|
59
|
+
${stdout}`;
|
|
60
|
+
return UNKNOWN_REVISION_SIGNATURE.test(combined);
|
|
61
|
+
}
|
|
62
|
+
async function headCommitIsMissing(cwd) {
|
|
63
|
+
const verify = await execa("git", ["rev-parse", "--verify", "-q", "HEAD^{commit}"], {
|
|
64
|
+
cwd,
|
|
65
|
+
reject: false,
|
|
66
|
+
stdio: "pipe"
|
|
67
|
+
});
|
|
68
|
+
const exitCode = verify.exitCode ?? 0;
|
|
69
|
+
if (exitCode === 0) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return isUnknownRevisionFailure(verify.stderr ?? "", verify.stdout ?? "");
|
|
73
|
+
}
|
|
74
|
+
async function resolveCleanupCurrentBranch(cwd) {
|
|
75
|
+
const revParse = await execa("git", ["rev-parse", "--symbolic-full-name", "HEAD"], {
|
|
76
|
+
cwd,
|
|
77
|
+
reject: false,
|
|
78
|
+
stdio: "pipe"
|
|
79
|
+
});
|
|
80
|
+
const revParseExitCode = revParse.exitCode ?? 0;
|
|
81
|
+
if (revParseExitCode === 0) {
|
|
82
|
+
const branch = revParse.stdout.trim() ? parseCurrentBranchRef(revParse.stdout) : "";
|
|
83
|
+
if (branch === "HEAD") {
|
|
84
|
+
return { state: "detached" };
|
|
85
|
+
}
|
|
86
|
+
if (branch) {
|
|
87
|
+
return { state: "attached", branch };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const revParseAmbiguous = revParseExitCode !== 0 && isAmbiguousHeadFailure(revParse.stderr ?? "", revParse.stdout ?? "");
|
|
91
|
+
const symbolic = await execa("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], {
|
|
92
|
+
cwd,
|
|
93
|
+
reject: false,
|
|
94
|
+
stdio: "pipe"
|
|
95
|
+
});
|
|
96
|
+
const symbolicExitCode = symbolic.exitCode ?? 0;
|
|
97
|
+
if (symbolicExitCode === 0) {
|
|
98
|
+
const symbolicBranch = symbolic.stdout.trim();
|
|
99
|
+
if (symbolicBranch) {
|
|
100
|
+
if (revParseAmbiguous) {
|
|
101
|
+
return { state: "unborn", symbolicBranch };
|
|
102
|
+
}
|
|
103
|
+
if (revParseExitCode !== 0 && await headCommitIsMissing(cwd)) {
|
|
104
|
+
return { state: "unborn", symbolicBranch };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (revParseAmbiguous) {
|
|
109
|
+
const fallbackSymbolic = await execa("git", ["symbolic-ref", "--short", "HEAD"], {
|
|
110
|
+
cwd,
|
|
111
|
+
reject: false,
|
|
112
|
+
stdio: "pipe"
|
|
113
|
+
});
|
|
114
|
+
const branch = fallbackSymbolic.stdout.trim();
|
|
115
|
+
if ((fallbackSymbolic.exitCode ?? 0) === 0 && branch) {
|
|
116
|
+
return { state: "unborn", symbolicBranch: branch };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (revParseExitCode !== 0) {
|
|
120
|
+
return { state: "unknown", reason: "HEAD branch inspection failed" };
|
|
121
|
+
}
|
|
122
|
+
return { state: "detached" };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/core/cleanup/tool-branch-cleanup.ts
|
|
126
|
+
import { existsSync } from "fs";
|
|
127
|
+
import { readdir, readFile as readFile2, realpath, stat as stat2 } from "fs/promises";
|
|
128
|
+
import { join, resolve as resolve3 } from "path";
|
|
129
|
+
|
|
130
|
+
// src/core/cleanup/competition-state-cleanup.ts
|
|
131
|
+
import { opendir, readFile, rm, stat } from "fs/promises";
|
|
132
|
+
import { resolve as resolve2 } from "path";
|
|
133
|
+
|
|
134
|
+
// src/core/cleanup/state-dir.ts
|
|
135
|
+
import { resolve } from "path";
|
|
136
|
+
function resolveCleanupBuildDir(cwd) {
|
|
137
|
+
return cwd ? resolve(cwd, ".build-project") : resolveBuildDirFromContext();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/core/cleanup/competition-state-cleanup.ts
|
|
141
|
+
function parseIsoDateMs(value) {
|
|
142
|
+
if (!value) return null;
|
|
143
|
+
const ms = new Date(value).getTime();
|
|
144
|
+
if (!Number.isFinite(ms)) return null;
|
|
145
|
+
return ms;
|
|
146
|
+
}
|
|
147
|
+
function isTerminalCandidate(candidate) {
|
|
148
|
+
if (candidate.submittedOnly === true) return false;
|
|
149
|
+
if (typeof candidate.success === "boolean") return true;
|
|
150
|
+
if (candidate.timedOut === true) return true;
|
|
151
|
+
if (typeof candidate.errorMessage === "string" && candidate.errorMessage.trim().length > 0) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
function getHandleCandidates(handle) {
|
|
157
|
+
if (Array.isArray(handle.candidates)) return handle.candidates;
|
|
158
|
+
if (Array.isArray(handle.variants)) return handle.variants;
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
function isTerminalHandle(handle) {
|
|
162
|
+
const candidates = getHandleCandidates(handle);
|
|
163
|
+
if (candidates.length === 0) return false;
|
|
164
|
+
return candidates.every(isTerminalCandidate);
|
|
165
|
+
}
|
|
166
|
+
function describeNonTerminalMetadata(handle) {
|
|
167
|
+
const candidates = getHandleCandidates(handle);
|
|
168
|
+
const hasSubmittedOnly = candidates.length > 0 && candidates.every((candidate) => candidate.submittedOnly === true);
|
|
169
|
+
const hasStatusFields = candidates.some((candidate) => {
|
|
170
|
+
if (typeof candidate.success === "boolean") return true;
|
|
171
|
+
if (candidate.timedOut === true) return true;
|
|
172
|
+
if (typeof candidate.errorMessage === "string" && candidate.errorMessage.trim().length > 0) {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
return false;
|
|
176
|
+
});
|
|
177
|
+
return {
|
|
178
|
+
hasSubmittedOnly,
|
|
179
|
+
hasStatusFields
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function evaluateNonTerminalState(ageMs, metadata, policy) {
|
|
183
|
+
if (policy === "strict") {
|
|
184
|
+
return { keep: true, reason: "non_terminal" };
|
|
185
|
+
}
|
|
186
|
+
const hours = ageMs / (60 * 60 * 1e3);
|
|
187
|
+
const days = ageMs / (24 * 60 * 60 * 1e3);
|
|
188
|
+
if (days >= 30) {
|
|
189
|
+
return { keep: false, reason: "non_terminal_stale" };
|
|
190
|
+
}
|
|
191
|
+
if (metadata.hasSubmittedOnly && days >= 7) {
|
|
192
|
+
return { keep: false, reason: "non_terminal_submitted_expired" };
|
|
193
|
+
}
|
|
194
|
+
if (metadata.hasSubmittedOnly && hours >= 48) {
|
|
195
|
+
return { keep: true, reason: "non_terminal_submitted_grace" };
|
|
196
|
+
}
|
|
197
|
+
if (!metadata.hasStatusFields && hours >= 48) {
|
|
198
|
+
return { keep: false, reason: "non_terminal_missing_status" };
|
|
199
|
+
}
|
|
200
|
+
return { keep: true, reason: "non_terminal" };
|
|
201
|
+
}
|
|
202
|
+
async function cleanupCompetitionStateFiles(options) {
|
|
203
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
204
|
+
const rootDir = resolve2(resolveRunStateDir(resolveCleanupBuildDir(options.cwd)), "competitions");
|
|
205
|
+
const maxAgeMs = options.maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
206
|
+
const report = {
|
|
207
|
+
mode: options.dryRun ? "dry-run" : "executed",
|
|
208
|
+
rootDir,
|
|
209
|
+
scanned: 0,
|
|
210
|
+
eligible: 0,
|
|
211
|
+
deleted: 0,
|
|
212
|
+
kept: 0,
|
|
213
|
+
freedBytes: 0,
|
|
214
|
+
keptBecause: {},
|
|
215
|
+
deletedBecause: {},
|
|
216
|
+
items: [],
|
|
217
|
+
errors: []
|
|
218
|
+
};
|
|
219
|
+
const bump = (map, key) => {
|
|
220
|
+
map[key] = (map[key] ?? 0) + 1;
|
|
221
|
+
};
|
|
222
|
+
const entries = [];
|
|
223
|
+
try {
|
|
224
|
+
const dir = await opendir(rootDir);
|
|
225
|
+
try {
|
|
226
|
+
for await (const d of dir) {
|
|
227
|
+
if (!d.isFile()) continue;
|
|
228
|
+
if (!d.name.endsWith(".json")) continue;
|
|
229
|
+
const fullPath = resolve2(rootDir, d.name);
|
|
230
|
+
report.scanned++;
|
|
231
|
+
try {
|
|
232
|
+
const st = await stat(fullPath);
|
|
233
|
+
const sizeBytes = st.size;
|
|
234
|
+
const tsMsFromStat = st.mtimeMs;
|
|
235
|
+
const raw = await readFile(fullPath, "utf8");
|
|
236
|
+
let parsed;
|
|
237
|
+
try {
|
|
238
|
+
parsed = parseJsonWithContext(raw, `Competition state (${d.name})`);
|
|
239
|
+
} catch {
|
|
240
|
+
const ageDays = Math.floor((now.getTime() - tsMsFromStat) / (24 * 60 * 60 * 1e3));
|
|
241
|
+
bump(report.keptBecause, "invalid_json");
|
|
242
|
+
report.kept++;
|
|
243
|
+
report.items.push({
|
|
244
|
+
path: fullPath,
|
|
245
|
+
sizeBytes,
|
|
246
|
+
ageDays,
|
|
247
|
+
terminal: false,
|
|
248
|
+
decision: "keep",
|
|
249
|
+
reason: "invalid_json"
|
|
250
|
+
});
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
const updatedMs = parseIsoDateMs(parsed.updatedAt) ?? parseIsoDateMs(parsed.createdAt);
|
|
254
|
+
const terminal = isTerminalHandle(parsed);
|
|
255
|
+
const metadata = describeNonTerminalMetadata(parsed);
|
|
256
|
+
entries.push({
|
|
257
|
+
name: d.name,
|
|
258
|
+
fullPath,
|
|
259
|
+
sizeBytes,
|
|
260
|
+
tsMs: updatedMs ?? tsMsFromStat,
|
|
261
|
+
terminal,
|
|
262
|
+
metadata
|
|
263
|
+
});
|
|
264
|
+
} catch (error) {
|
|
265
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
266
|
+
report.errors.push(`${d.name}: stat/read failed: ${msg}`);
|
|
267
|
+
bump(report.keptBecause, "read_error");
|
|
268
|
+
report.kept++;
|
|
269
|
+
report.items.push({
|
|
270
|
+
path: fullPath,
|
|
271
|
+
sizeBytes: 0,
|
|
272
|
+
ageDays: 0,
|
|
273
|
+
terminal: false,
|
|
274
|
+
decision: "keep",
|
|
275
|
+
reason: "read_error"
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
} finally {
|
|
280
|
+
await dir.close().catch(() => {
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
} catch (error) {
|
|
284
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
285
|
+
report.errors.push(`Failed to read ${rootDir}: ${msg}`);
|
|
286
|
+
return report;
|
|
287
|
+
}
|
|
288
|
+
const keepLast = Math.max(0, options.keepLast);
|
|
289
|
+
const keepLastSet = /* @__PURE__ */ new Set();
|
|
290
|
+
if (keepLast > 0) {
|
|
291
|
+
const sorted = [...entries].sort((a, b) => b.tsMs - a.tsMs);
|
|
292
|
+
for (const e of sorted.slice(0, keepLast)) {
|
|
293
|
+
keepLastSet.add(e.fullPath);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
for (const entry of entries) {
|
|
297
|
+
const ageMs = now.getTime() - entry.tsMs;
|
|
298
|
+
const ageDays = Math.floor(ageMs / (24 * 60 * 60 * 1e3));
|
|
299
|
+
const terminal = entry.terminal;
|
|
300
|
+
const metadata = entry.metadata;
|
|
301
|
+
const policy = options.nonTerminalPolicy ?? (options.keepNonTerminal ? "strict" : "smart");
|
|
302
|
+
const isTooOld = ageMs > maxAgeMs;
|
|
303
|
+
let decision = "keep";
|
|
304
|
+
let reason = "too_recent";
|
|
305
|
+
if (keepLastSet.has(entry.fullPath)) {
|
|
306
|
+
decision = "keep";
|
|
307
|
+
reason = "keep_last";
|
|
308
|
+
bump(report.keptBecause, reason);
|
|
309
|
+
} else if (!isTooOld) {
|
|
310
|
+
decision = "keep";
|
|
311
|
+
reason = "too_recent";
|
|
312
|
+
bump(report.keptBecause, reason);
|
|
313
|
+
} else if (!terminal) {
|
|
314
|
+
const disposition = evaluateNonTerminalState(ageMs, metadata, policy);
|
|
315
|
+
if (disposition.keep) {
|
|
316
|
+
decision = "keep";
|
|
317
|
+
reason = disposition.reason;
|
|
318
|
+
bump(report.keptBecause, reason);
|
|
319
|
+
} else {
|
|
320
|
+
decision = "delete";
|
|
321
|
+
reason = disposition.reason;
|
|
322
|
+
bump(report.deletedBecause, reason);
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
decision = "delete";
|
|
326
|
+
reason = "stale_terminal";
|
|
327
|
+
bump(report.deletedBecause, reason);
|
|
328
|
+
}
|
|
329
|
+
if (decision === "delete") {
|
|
330
|
+
report.eligible++;
|
|
331
|
+
if (options.dryRun) {
|
|
332
|
+
report.freedBytes += entry.sizeBytes;
|
|
333
|
+
} else {
|
|
334
|
+
try {
|
|
335
|
+
await rm(entry.fullPath, { force: true });
|
|
336
|
+
const eventsPath = entry.fullPath.replace(/\.json$/, ".events.jsonl");
|
|
337
|
+
await rm(eventsPath, { force: true }).catch(() => {
|
|
338
|
+
});
|
|
339
|
+
report.deleted++;
|
|
340
|
+
report.freedBytes += entry.sizeBytes;
|
|
341
|
+
} catch (error) {
|
|
342
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
343
|
+
report.errors.push(`${entry.name}: delete failed: ${msg}`);
|
|
344
|
+
decision = "keep";
|
|
345
|
+
reason = "read_error";
|
|
346
|
+
bump(report.keptBecause, reason);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (decision === "keep") report.kept++;
|
|
351
|
+
report.items.push({
|
|
352
|
+
path: entry.fullPath,
|
|
353
|
+
sizeBytes: entry.sizeBytes,
|
|
354
|
+
ageDays,
|
|
355
|
+
terminal,
|
|
356
|
+
decision,
|
|
357
|
+
reason
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
if (options.dryRun) {
|
|
361
|
+
report.deleted = report.eligible;
|
|
362
|
+
}
|
|
363
|
+
if (!options.verbose) {
|
|
364
|
+
report.items = report.items.slice(0, 200);
|
|
365
|
+
}
|
|
366
|
+
return report;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/core/cleanup/tool-branch-cleanup.ts
|
|
370
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
371
|
+
var UNFINISHED_RUN_PROTECTION_DAYS = 30;
|
|
372
|
+
var NON_RUN_FLYWHEEL_ENTRIES = /* @__PURE__ */ new Set(["legacy-archive", "detached", "cache"]);
|
|
373
|
+
async function listEntries(dir) {
|
|
374
|
+
try {
|
|
375
|
+
return await readdir(dir, { withFileTypes: true });
|
|
376
|
+
} catch {
|
|
377
|
+
return [];
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
async function listCheckoutRoots(repoRoot) {
|
|
381
|
+
const paths = [repoRoot];
|
|
382
|
+
try {
|
|
383
|
+
const result = await execGit(["worktree", "list", "--porcelain"], { cwd: repoRoot });
|
|
384
|
+
if (result.exitCode === 0) {
|
|
385
|
+
paths.push(...parseGitWorktreeBranches(result.stdout).map((entry) => entry.path));
|
|
386
|
+
}
|
|
387
|
+
} catch {
|
|
388
|
+
}
|
|
389
|
+
const roots = /* @__PURE__ */ new Map();
|
|
390
|
+
for (const p of paths) {
|
|
391
|
+
const key = await realpath(p).catch(() => resolve3(p));
|
|
392
|
+
if (!roots.has(key)) roots.set(key, p);
|
|
393
|
+
}
|
|
394
|
+
return [...roots.values()];
|
|
395
|
+
}
|
|
396
|
+
async function loadRunBranchGuard(repoRoot, now = Date.now()) {
|
|
397
|
+
const exact = /* @__PURE__ */ new Map();
|
|
398
|
+
const prefixes = [];
|
|
399
|
+
const isRecent = async (recordedMs, file) => {
|
|
400
|
+
const activityMs = Number.isFinite(recordedMs) ? recordedMs : await stat2(file).then(
|
|
401
|
+
(st) => st.mtimeMs,
|
|
402
|
+
() => Number.NaN
|
|
403
|
+
);
|
|
404
|
+
return !(now - activityMs > UNFINISHED_RUN_PROTECTION_DAYS * DAY_MS);
|
|
405
|
+
};
|
|
406
|
+
for (const checkoutRoot of await listCheckoutRoots(repoRoot)) {
|
|
407
|
+
const flywheelDir = join(checkoutRoot, ".build-project", "tmp", "flywheel");
|
|
408
|
+
for (const entry of await listEntries(flywheelDir)) {
|
|
409
|
+
if (!entry.isDirectory() || NON_RUN_FLYWHEEL_ENTRIES.has(entry.name)) continue;
|
|
410
|
+
const manifestPath = join(flywheelDir, entry.name, "manifest.json");
|
|
411
|
+
if (!existsSync(manifestPath)) continue;
|
|
412
|
+
let manifest;
|
|
413
|
+
try {
|
|
414
|
+
manifest = JSON.parse(await readFile2(manifestPath, "utf8"));
|
|
415
|
+
} catch {
|
|
416
|
+
}
|
|
417
|
+
if (manifest?.appliedAt) continue;
|
|
418
|
+
const recordedMs = manifest ? getWorkflowLastActivityMs(manifest) : void 0;
|
|
419
|
+
if (!await isRecent(recordedMs, manifestPath)) continue;
|
|
420
|
+
const reason = `unfinished run ${entry.name}`;
|
|
421
|
+
const gathering = new Set(runBranchNameCandidates(entry.name));
|
|
422
|
+
if (typeof manifest?.integrationBranch === "string" && manifest.integrationBranch) {
|
|
423
|
+
gathering.add(manifest.integrationBranch);
|
|
424
|
+
}
|
|
425
|
+
for (const name of gathering) {
|
|
426
|
+
exact.set(name, reason);
|
|
427
|
+
const children = runChildBranchTargets(name);
|
|
428
|
+
for (const child of children.exact) exact.set(child, reason);
|
|
429
|
+
for (const prefix of children.prefixes) prefixes.push([prefix, reason]);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
let stateDirs = [];
|
|
434
|
+
try {
|
|
435
|
+
stateDirs = resolveRunStateReadDirs(join(repoRoot, ".build-project"));
|
|
436
|
+
} catch {
|
|
437
|
+
}
|
|
438
|
+
for (const stateDir of stateDirs) {
|
|
439
|
+
const dir = join(stateDir, "competitions");
|
|
440
|
+
for (const entry of await listEntries(dir)) {
|
|
441
|
+
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
442
|
+
try {
|
|
443
|
+
const handlePath = join(dir, entry.name);
|
|
444
|
+
const handle = JSON.parse(await readFile2(handlePath, "utf8"));
|
|
445
|
+
if (typeof handle?.taskId !== "string" || isTerminalHandle(handle)) continue;
|
|
446
|
+
if (!await isRecent(Date.parse(handle.updatedAt ?? ""), handlePath)) continue;
|
|
447
|
+
for (const prefix of buildVariantBranchPrefixes(handle.taskId)) {
|
|
448
|
+
prefixes.push([prefix, `unfinished competition ${handle.taskId}`]);
|
|
449
|
+
}
|
|
450
|
+
} catch {
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return (branch) => exact.get(branch) ?? prefixes.find(([prefix]) => branch.startsWith(prefix))?.[1];
|
|
455
|
+
}
|
|
456
|
+
async function analyzeToolBranch(manager, branch, queuedEntry, opts, runGuard) {
|
|
457
|
+
const unfinished = runGuard(branch);
|
|
458
|
+
if (unfinished) {
|
|
459
|
+
return { name: branch, action: "skip", reason: unfinished };
|
|
460
|
+
}
|
|
461
|
+
const currentHeadSha = await manager.getBranchHeadSha(branch) ?? void 0;
|
|
462
|
+
if (!currentHeadSha) {
|
|
463
|
+
return { name: branch, action: "skip", reason: "branch head unavailable" };
|
|
464
|
+
}
|
|
465
|
+
const expectedHeadSha = queuedEntry?.expectedHeadSha;
|
|
466
|
+
if (expectedHeadSha && expectedHeadSha === currentHeadSha) {
|
|
467
|
+
return {
|
|
468
|
+
name: branch,
|
|
469
|
+
action: "archive",
|
|
470
|
+
reason: "queued worktree cleanup",
|
|
471
|
+
details: { queuedForCleanup: true, expectedHeadSha, currentHeadSha }
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
const now = opts.now ?? Date.now();
|
|
475
|
+
const thresholdMs = opts.minAgeDays * DAY_MS;
|
|
476
|
+
const lastActivity = await manager.getLastActivityTime(branch, thresholdMs, now);
|
|
477
|
+
const idleMs = now - lastActivity.getTime();
|
|
478
|
+
const ageDays = Math.floor(idleMs / DAY_MS);
|
|
479
|
+
const details = {
|
|
480
|
+
ageDays,
|
|
481
|
+
lastActivity,
|
|
482
|
+
queuedForCleanup: Boolean(queuedEntry),
|
|
483
|
+
expectedHeadSha,
|
|
484
|
+
currentHeadSha
|
|
485
|
+
};
|
|
486
|
+
if (idleMs < thresholdMs) {
|
|
487
|
+
const queuedNote = expectedHeadSha ? "; queued branch head changed" : "";
|
|
488
|
+
return {
|
|
489
|
+
name: branch,
|
|
490
|
+
action: "skip",
|
|
491
|
+
reason: `active ${ageDays}d ago (threshold: ${opts.minAgeDays}d)${queuedNote}`,
|
|
492
|
+
details
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
return { name: branch, action: "archive", reason: "idle", details };
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// src/core/cleanup/branch-cleanup-manager.ts
|
|
499
|
+
var DEFAULT_BRANCH_CLEANUP_AGE_DAYS = 7;
|
|
500
|
+
var STRICT_BUILD_PATTERNS = [
|
|
501
|
+
// Legacy lab mode worktree branches (before build/wt-*, now build/lab/*)
|
|
502
|
+
/^lab-[a-f0-9]{8,}-\d{14,}-.*-[a-f0-9]{8}$/,
|
|
503
|
+
// Backup branches (numeric timestamp)
|
|
504
|
+
/^backup\/pre-sync-\d{10,}$/,
|
|
505
|
+
// Legacy Build competition branches (feature/<uuid>-...-<8hex>)
|
|
506
|
+
/^feature\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}-.*-[a-f0-9]{8}$/i
|
|
507
|
+
];
|
|
508
|
+
var EXTENDED_TEST_PATTERNS = [
|
|
509
|
+
// Test harness branches (require 8-char hex suffix)
|
|
510
|
+
/^feature\/task-\d+-.*-[a-f0-9]{8}$/,
|
|
511
|
+
/^feature\/test-\d+-variant-.*-[a-f0-9]{8}$/
|
|
512
|
+
];
|
|
513
|
+
var BranchCleanupManager = class {
|
|
514
|
+
constructor(cwd = process.cwd()) {
|
|
515
|
+
this.cwd = cwd;
|
|
516
|
+
}
|
|
517
|
+
cwd;
|
|
518
|
+
defaultBranch = null;
|
|
519
|
+
remoteDefaultBranches = /* @__PURE__ */ new Map();
|
|
520
|
+
queuedBranches = /* @__PURE__ */ new Map();
|
|
521
|
+
runGuard;
|
|
522
|
+
async refreshQueuedBranches() {
|
|
523
|
+
try {
|
|
524
|
+
const entries = await readBranchCleanupQueue(getBranchCleanupQueuePath(this.cwd));
|
|
525
|
+
this.queuedBranches = new Map(entries.map((entry) => [entry.branch, entry]));
|
|
526
|
+
} catch {
|
|
527
|
+
this.queuedBranches = /* @__PURE__ */ new Map();
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Auto-detect the default branch from origin/HEAD or fallback.
|
|
532
|
+
* Delegates to resolveDefaultBranch; caches the result on this instance.
|
|
533
|
+
*/
|
|
534
|
+
async getDefaultBranch() {
|
|
535
|
+
if (this.defaultBranch) {
|
|
536
|
+
return this.defaultBranch;
|
|
537
|
+
}
|
|
538
|
+
this.defaultBranch = await resolveDefaultBranch(this.cwd);
|
|
539
|
+
return this.defaultBranch;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Auto-detect the default branch for a specific remote (e.g. origin/HEAD, upstream/HEAD).
|
|
543
|
+
* Falls back to getDefaultBranch() if the remote HEAD cannot be resolved.
|
|
544
|
+
*/
|
|
545
|
+
async getDefaultBranchForRemote(remote) {
|
|
546
|
+
const cached = this.remoteDefaultBranches.get(remote);
|
|
547
|
+
if (cached) return cached;
|
|
548
|
+
try {
|
|
549
|
+
const { stdout } = await execa2("git", ["symbolic-ref", `refs/remotes/${remote}/HEAD`], {
|
|
550
|
+
cwd: this.cwd,
|
|
551
|
+
stdio: "pipe"
|
|
552
|
+
});
|
|
553
|
+
const prefix = `refs/remotes/${remote}/`;
|
|
554
|
+
const trimmed = stdout.trim();
|
|
555
|
+
if (trimmed.startsWith(prefix)) {
|
|
556
|
+
const branch = trimmed.slice(prefix.length);
|
|
557
|
+
if (branch.length > 0) {
|
|
558
|
+
this.remoteDefaultBranches.set(remote, branch);
|
|
559
|
+
return branch;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
} catch {
|
|
563
|
+
}
|
|
564
|
+
return await this.getDefaultBranch();
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Get current HEAD branch name for cleanup analysis.
|
|
568
|
+
*
|
|
569
|
+
* Returns "HEAD" when detached. Never throws for unborn repositories.
|
|
570
|
+
*/
|
|
571
|
+
async getCurrentBranch() {
|
|
572
|
+
const resolution = await resolveCleanupCurrentBranch(this.cwd);
|
|
573
|
+
if (resolution.state === "attached") {
|
|
574
|
+
return resolution.branch;
|
|
575
|
+
}
|
|
576
|
+
if (resolution.state === "unborn") {
|
|
577
|
+
return resolution.symbolicBranch;
|
|
578
|
+
}
|
|
579
|
+
return "HEAD";
|
|
580
|
+
}
|
|
581
|
+
/** Get all worktree-attached branches */
|
|
582
|
+
async getWorktreeBranches() {
|
|
583
|
+
const branches = /* @__PURE__ */ new Map();
|
|
584
|
+
const { stdout } = await execa2("git", ["worktree", "list", "--porcelain"], {
|
|
585
|
+
cwd: this.cwd,
|
|
586
|
+
stdio: "pipe"
|
|
587
|
+
});
|
|
588
|
+
const lines = stdout.split("\n");
|
|
589
|
+
let currentPath = null;
|
|
590
|
+
for (const line of lines) {
|
|
591
|
+
if (line.startsWith("worktree ")) {
|
|
592
|
+
currentPath = resolve4(line.substring("worktree ".length).trim());
|
|
593
|
+
} else if (line.startsWith("branch ") && currentPath) {
|
|
594
|
+
const branchRef = line.substring("branch ".length).trim();
|
|
595
|
+
const branchName = branchRef.replace(/^refs\/heads\//, "");
|
|
596
|
+
branches.set(branchName, currentPath);
|
|
597
|
+
currentPath = null;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return branches;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Check if a remote ref exists for this branch (local remote-tracking refs)
|
|
604
|
+
*/
|
|
605
|
+
async hasRemoteRef(branch) {
|
|
606
|
+
try {
|
|
607
|
+
const { stdout } = await execa2(
|
|
608
|
+
"git",
|
|
609
|
+
["for-each-ref", "--format=%(refname:short)", `refs/remotes/*/${branch}`],
|
|
610
|
+
{ cwd: this.cwd, stdio: "pipe" }
|
|
611
|
+
);
|
|
612
|
+
const refs = stdout.trim().split("\n").filter(Boolean);
|
|
613
|
+
return refs[0] || null;
|
|
614
|
+
} catch {
|
|
615
|
+
return null;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
/** Check if branch has upstream tracking configured */
|
|
619
|
+
async hasUpstreamTracking(branch) {
|
|
620
|
+
try {
|
|
621
|
+
const { stdout } = await execa2("git", ["config", "--get", `branch.${branch}.remote`], {
|
|
622
|
+
cwd: this.cwd,
|
|
623
|
+
stdio: "pipe"
|
|
624
|
+
});
|
|
625
|
+
const remote = stdout.trim();
|
|
626
|
+
if (remote) {
|
|
627
|
+
const { stdout: merge } = await execa2(
|
|
628
|
+
"git",
|
|
629
|
+
["config", "--get", `branch.${branch}.merge`],
|
|
630
|
+
{ cwd: this.cwd, stdio: "pipe" }
|
|
631
|
+
);
|
|
632
|
+
return `${remote}/${merge.replace("refs/heads/", "")}`;
|
|
633
|
+
}
|
|
634
|
+
return null;
|
|
635
|
+
} catch {
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Check if branch is merged into default branch using merge-base --is-ancestor
|
|
641
|
+
* This is more reliable than git branch -d behavior
|
|
642
|
+
*/
|
|
643
|
+
async isMergedInto(branch, target) {
|
|
644
|
+
try {
|
|
645
|
+
await execa2("git", ["merge-base", "--is-ancestor", branch, target], {
|
|
646
|
+
cwd: this.cwd,
|
|
647
|
+
stdio: "pipe"
|
|
648
|
+
});
|
|
649
|
+
return true;
|
|
650
|
+
} catch {
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Get count of commits ahead of default branch (unique commits)
|
|
656
|
+
*/
|
|
657
|
+
async getAheadCount(branch, target) {
|
|
658
|
+
try {
|
|
659
|
+
const { stdout } = await execa2("git", ["rev-list", "--count", `${target}..${branch}`], {
|
|
660
|
+
cwd: this.cwd,
|
|
661
|
+
stdio: "pipe"
|
|
662
|
+
});
|
|
663
|
+
return parseInt(stdout.trim(), 10) || 0;
|
|
664
|
+
} catch {
|
|
665
|
+
return 0;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
async getBranchHeadSha(branch) {
|
|
669
|
+
try {
|
|
670
|
+
const { stdout } = await execa2(
|
|
671
|
+
"git",
|
|
672
|
+
["rev-parse", "--verify", `refs/heads/${branch}^{commit}`],
|
|
673
|
+
{
|
|
674
|
+
cwd: this.cwd,
|
|
675
|
+
stdio: "pipe"
|
|
676
|
+
}
|
|
677
|
+
);
|
|
678
|
+
return stdout.trim() || null;
|
|
679
|
+
} catch {
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Get last activity time for a branch
|
|
685
|
+
* Uses max of: tip commit time, reflog latest entry
|
|
686
|
+
* Conservative: if reflog missing and near threshold, treat as recent
|
|
687
|
+
*/
|
|
688
|
+
async getLastActivityTime(branch, thresholdMs, now = Date.now()) {
|
|
689
|
+
let tipTime = null;
|
|
690
|
+
let reflogTime = null;
|
|
691
|
+
try {
|
|
692
|
+
const { stdout } = await execa2("git", ["show", "-s", "--format=%ct", branch], {
|
|
693
|
+
cwd: this.cwd,
|
|
694
|
+
stdio: "pipe"
|
|
695
|
+
});
|
|
696
|
+
tipTime = parseInt(stdout.trim(), 10) * 1e3;
|
|
697
|
+
} catch {
|
|
698
|
+
}
|
|
699
|
+
try {
|
|
700
|
+
const { stdout } = await execa2(
|
|
701
|
+
"git",
|
|
702
|
+
["reflog", "show", "--date=unix", "--format=%gd", "-1", branch],
|
|
703
|
+
{
|
|
704
|
+
cwd: this.cwd,
|
|
705
|
+
stdio: "pipe"
|
|
706
|
+
}
|
|
707
|
+
);
|
|
708
|
+
const selector = stdout.trim().split("\n")[0] ?? "";
|
|
709
|
+
const timestampMatch = selector.match(/@\{(?<timestamp>\d+)\}$/);
|
|
710
|
+
const timestamp = parseInt(timestampMatch?.groups?.timestamp ?? "", 10);
|
|
711
|
+
reflogTime = Number.isFinite(timestamp) && timestamp > 0 ? timestamp * 1e3 : null;
|
|
712
|
+
} catch {
|
|
713
|
+
}
|
|
714
|
+
const lastActivity = Math.max(tipTime || 0, reflogTime || 0);
|
|
715
|
+
if (!reflogTime && tipTime) {
|
|
716
|
+
const age = now - tipTime;
|
|
717
|
+
if (age < thresholdMs * 2) {
|
|
718
|
+
return new Date(now);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
return new Date(lastActivity || now);
|
|
722
|
+
}
|
|
723
|
+
/** Check if branch name matches any protected pattern */
|
|
724
|
+
isProtectedBranch(branch) {
|
|
725
|
+
return isProtectedPipelineBranch(branch, void 0, this.cwd);
|
|
726
|
+
}
|
|
727
|
+
/** Check if branch matches cleanup patterns */
|
|
728
|
+
matchesCleanupPattern(branch, includeTestBranches) {
|
|
729
|
+
if (isBuildOwnedBranch(branch)) {
|
|
730
|
+
return true;
|
|
731
|
+
}
|
|
732
|
+
for (const pattern of STRICT_BUILD_PATTERNS) {
|
|
733
|
+
if (pattern.test(branch)) {
|
|
734
|
+
return true;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
if (includeTestBranches) {
|
|
738
|
+
for (const pattern of EXTENDED_TEST_PATTERNS) {
|
|
739
|
+
if (pattern.test(branch)) {
|
|
740
|
+
return true;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return false;
|
|
745
|
+
}
|
|
746
|
+
/** Get all local branches */
|
|
747
|
+
async getAllBranches(toolBranchesOnly = false) {
|
|
748
|
+
const { stdout } = await execa2(
|
|
749
|
+
"git",
|
|
750
|
+
[
|
|
751
|
+
"for-each-ref",
|
|
752
|
+
"--format=%(refname:short)",
|
|
753
|
+
toolBranchesOnly ? "refs/heads/build/" : "refs/heads/"
|
|
754
|
+
],
|
|
755
|
+
{ cwd: this.cwd, stdio: "pipe" }
|
|
756
|
+
);
|
|
757
|
+
const branches = stdout.trim().split("\n").filter(Boolean);
|
|
758
|
+
return toolBranchesOnly ? branches.filter(isBuildOwnedBranch) : branches;
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Analyze branches for cleanup
|
|
762
|
+
* This is a read-only operation that returns what would be archived
|
|
763
|
+
*/
|
|
764
|
+
async analyze(options = {}) {
|
|
765
|
+
const opts = {
|
|
766
|
+
includeBranches: options.includeBranches ?? false,
|
|
767
|
+
includeTestBranches: options.includeTestBranches ?? false,
|
|
768
|
+
dryRun: options.dryRun ?? true,
|
|
769
|
+
allowUnmerged: options.allowUnmerged ?? false,
|
|
770
|
+
confirm: options.confirm,
|
|
771
|
+
minAgeDays: options.minAgeDays ?? DEFAULT_BRANCH_CLEANUP_AGE_DAYS,
|
|
772
|
+
maxArchiveCount: options.maxArchiveCount ?? 100,
|
|
773
|
+
verbose: options.verbose ?? false,
|
|
774
|
+
toolBranchesOnly: options.toolBranchesOnly ?? false,
|
|
775
|
+
now: options.now ?? Date.now()
|
|
776
|
+
};
|
|
777
|
+
const result = {
|
|
778
|
+
mode: "dry-run",
|
|
779
|
+
// Analysis is always dry-run
|
|
780
|
+
defaultBranch: await this.getDefaultBranch(),
|
|
781
|
+
patternsUsed: opts.includeTestBranches ? "extended" : "strict",
|
|
782
|
+
scanned: 0,
|
|
783
|
+
archived: 0,
|
|
784
|
+
skipped: 0,
|
|
785
|
+
branches: [],
|
|
786
|
+
errors: [],
|
|
787
|
+
circuitBreakerTriggered: false
|
|
788
|
+
};
|
|
789
|
+
if (!opts.includeBranches) {
|
|
790
|
+
return result;
|
|
791
|
+
}
|
|
792
|
+
await this.refreshQueuedBranches();
|
|
793
|
+
this.runGuard = void 0;
|
|
794
|
+
const headResolution = await resolveCleanupCurrentBranch(this.cwd);
|
|
795
|
+
if (headResolution.state === "unknown") {
|
|
796
|
+
result.headInspectionError = true;
|
|
797
|
+
result.errors.push(CLEANUP_HEAD_INSPECTION_ERROR);
|
|
798
|
+
result.scanned = 0;
|
|
799
|
+
result.skipped = 0;
|
|
800
|
+
return result;
|
|
801
|
+
}
|
|
802
|
+
if (headResolution.state === "unborn") {
|
|
803
|
+
result.unbornRepository = true;
|
|
804
|
+
result.scanned = 0;
|
|
805
|
+
result.skipped = 0;
|
|
806
|
+
return result;
|
|
807
|
+
}
|
|
808
|
+
const branches = await this.getAllBranches(opts.toolBranchesOnly);
|
|
809
|
+
const currentBranch = headResolution.state === "attached" ? headResolution.branch : "HEAD";
|
|
810
|
+
let worktreeBranches;
|
|
811
|
+
try {
|
|
812
|
+
worktreeBranches = await this.getWorktreeBranches();
|
|
813
|
+
} catch (error) {
|
|
814
|
+
result.errors.push(
|
|
815
|
+
`Failed to inspect git worktrees; skipping branch cleanup analysis: ${error instanceof Error ? error.message : String(error)}`
|
|
816
|
+
);
|
|
817
|
+
result.scanned = branches.length;
|
|
818
|
+
result.skipped = branches.length;
|
|
819
|
+
result.branches = branches.map((branch) => ({
|
|
820
|
+
name: branch,
|
|
821
|
+
action: "skip",
|
|
822
|
+
reason: "worktree inspection unavailable"
|
|
823
|
+
}));
|
|
824
|
+
return result;
|
|
825
|
+
}
|
|
826
|
+
const thresholdMs = opts.minAgeDays * 24 * 60 * 60 * 1e3;
|
|
827
|
+
result.scanned = branches.length;
|
|
828
|
+
if (currentBranch === "HEAD") {
|
|
829
|
+
result.errors.push("Detached HEAD detected; skipping branch cleanup analysis for safety.");
|
|
830
|
+
result.skipped = branches.length;
|
|
831
|
+
result.branches = branches.map((branch) => ({
|
|
832
|
+
name: branch,
|
|
833
|
+
action: "skip",
|
|
834
|
+
reason: "detached HEAD"
|
|
835
|
+
}));
|
|
836
|
+
return result;
|
|
837
|
+
}
|
|
838
|
+
for (const branch of branches) {
|
|
839
|
+
if (result.archived >= opts.maxArchiveCount) {
|
|
840
|
+
result.circuitBreakerTriggered = true;
|
|
841
|
+
result.branches.push({
|
|
842
|
+
name: branch,
|
|
843
|
+
action: "skip",
|
|
844
|
+
reason: "circuit breaker triggered"
|
|
845
|
+
});
|
|
846
|
+
result.skipped++;
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
const analysis = await this.analyzeBranch(
|
|
850
|
+
branch,
|
|
851
|
+
currentBranch,
|
|
852
|
+
worktreeBranches,
|
|
853
|
+
result.defaultBranch,
|
|
854
|
+
thresholdMs,
|
|
855
|
+
opts,
|
|
856
|
+
this.queuedBranches
|
|
857
|
+
);
|
|
858
|
+
result.branches.push(analysis);
|
|
859
|
+
if (analysis.action === "archive") {
|
|
860
|
+
result.archived++;
|
|
861
|
+
} else {
|
|
862
|
+
result.skipped++;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
return result;
|
|
866
|
+
}
|
|
867
|
+
/** Analyze a single branch */
|
|
868
|
+
async analyzeBranch(branch, currentBranch, worktreeBranches, defaultBranch, thresholdMs, opts, queuedBranches) {
|
|
869
|
+
if (this.isProtectedBranch(branch)) {
|
|
870
|
+
return { name: branch, action: "skip", reason: "protected branch" };
|
|
871
|
+
}
|
|
872
|
+
if (branch === currentBranch) {
|
|
873
|
+
return { name: branch, action: "skip", reason: "current HEAD" };
|
|
874
|
+
}
|
|
875
|
+
if (isValidationBranch(branch)) {
|
|
876
|
+
return { name: branch, action: "skip", reason: "validation branch" };
|
|
877
|
+
}
|
|
878
|
+
const worktreePath = worktreeBranches.get(branch);
|
|
879
|
+
const queuedEntry = queuedBranches.get(branch);
|
|
880
|
+
const toolBranch = isBuildOwnedBranch(branch);
|
|
881
|
+
if (worktreePath) {
|
|
882
|
+
if (toolBranch || existsSync2(worktreePath)) {
|
|
883
|
+
return {
|
|
884
|
+
name: branch,
|
|
885
|
+
action: "skip",
|
|
886
|
+
reason: `worktree: ${worktreePath}`,
|
|
887
|
+
details: { worktreePath }
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
if (!queuedEntry) {
|
|
891
|
+
return {
|
|
892
|
+
name: branch,
|
|
893
|
+
action: "skip",
|
|
894
|
+
reason: `worktree metadata present but missing on disk: ${worktreePath}`,
|
|
895
|
+
details: { worktreePath }
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
if (!toolBranch && queuedEntry?.expectedHeadSha) {
|
|
900
|
+
const currentHeadSha = await this.getBranchHeadSha(branch);
|
|
901
|
+
if (!currentHeadSha) {
|
|
902
|
+
return {
|
|
903
|
+
name: branch,
|
|
904
|
+
action: "skip",
|
|
905
|
+
reason: "queued branch head unavailable",
|
|
906
|
+
details: { expectedHeadSha: queuedEntry.expectedHeadSha }
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
if (currentHeadSha !== queuedEntry.expectedHeadSha) {
|
|
910
|
+
return {
|
|
911
|
+
name: branch,
|
|
912
|
+
action: "skip",
|
|
913
|
+
reason: "queued branch head changed",
|
|
914
|
+
details: {
|
|
915
|
+
expectedHeadSha: queuedEntry.expectedHeadSha,
|
|
916
|
+
currentHeadSha
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
const remoteRef = await this.hasRemoteRef(branch);
|
|
922
|
+
if (remoteRef) {
|
|
923
|
+
return {
|
|
924
|
+
name: branch,
|
|
925
|
+
action: "skip",
|
|
926
|
+
reason: `has remote ref: ${remoteRef}`,
|
|
927
|
+
details: { remoteBranch: remoteRef }
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
const upstream = await this.hasUpstreamTracking(branch);
|
|
931
|
+
if (upstream) {
|
|
932
|
+
return {
|
|
933
|
+
name: branch,
|
|
934
|
+
action: "skip",
|
|
935
|
+
reason: `tracks upstream: ${upstream}`,
|
|
936
|
+
details: { remoteBranch: upstream }
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
if (toolBranch) {
|
|
940
|
+
this.runGuard ??= loadRunBranchGuard(this.cwd, opts.now);
|
|
941
|
+
return analyzeToolBranch(this, branch, queuedEntry, opts, await this.runGuard);
|
|
942
|
+
}
|
|
943
|
+
if (!this.matchesCleanupPattern(branch, opts.includeTestBranches)) {
|
|
944
|
+
return { name: branch, action: "skip", reason: "no pattern match" };
|
|
945
|
+
}
|
|
946
|
+
const isMerged = await this.isMergedInto(branch, defaultBranch);
|
|
947
|
+
const aheadCount = await this.getAheadCount(branch, defaultBranch);
|
|
948
|
+
if (!isMerged || aheadCount > 0) {
|
|
949
|
+
if (!opts.allowUnmerged) {
|
|
950
|
+
return {
|
|
951
|
+
name: branch,
|
|
952
|
+
action: "skip",
|
|
953
|
+
reason: `${aheadCount} unmerged commits`,
|
|
954
|
+
details: { aheadCount }
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
const lastActivity = await this.getLastActivityTime(branch, thresholdMs, opts.now);
|
|
959
|
+
const ageDays = Math.floor(((opts.now ?? 0) - lastActivity.getTime()) / (24 * 60 * 60 * 1e3));
|
|
960
|
+
const isQueued = Boolean(queuedEntry);
|
|
961
|
+
if (!isQueued && ageDays < opts.minAgeDays) {
|
|
962
|
+
return {
|
|
963
|
+
name: branch,
|
|
964
|
+
action: "skip",
|
|
965
|
+
reason: `active ${ageDays}d ago (threshold: ${opts.minAgeDays}d)`,
|
|
966
|
+
details: { ageDays, lastActivity }
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
return {
|
|
970
|
+
name: branch,
|
|
971
|
+
action: "archive",
|
|
972
|
+
reason: isQueued ? "queued worktree cleanup" : "matches criteria",
|
|
973
|
+
details: {
|
|
974
|
+
ageDays,
|
|
975
|
+
aheadCount,
|
|
976
|
+
lastActivity,
|
|
977
|
+
queuedForCleanup: isQueued,
|
|
978
|
+
expectedHeadSha: queuedEntry?.expectedHeadSha,
|
|
979
|
+
currentHeadSha: await this.getBranchHeadSha(branch) ?? void 0
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
/** Why a move candidate changed since analysis (tip, checkout, push), or null. */
|
|
984
|
+
async changedSinceAnalysis(branch) {
|
|
985
|
+
const headSha = await this.getBranchHeadSha(branch.name);
|
|
986
|
+
if (!headSha || headSha !== branch.details?.currentHeadSha) return "tip changed since analysis";
|
|
987
|
+
if ((await this.getWorktreeBranches()).has(branch.name)) return "checked out since analysis";
|
|
988
|
+
if (await this.hasRemoteRef(branch.name) || await this.hasUpstreamTracking(branch.name)) {
|
|
989
|
+
return "pushed since analysis";
|
|
990
|
+
}
|
|
991
|
+
return null;
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Move branches aside into the build/removed/<date>/ holding area
|
|
995
|
+
* Returns the actual result after execution
|
|
996
|
+
*/
|
|
997
|
+
async archive(options = {}) {
|
|
998
|
+
const analysis = await this.analyze(options);
|
|
999
|
+
if (options.dryRun ?? true) {
|
|
1000
|
+
return analysis;
|
|
1001
|
+
}
|
|
1002
|
+
const archiveCount = analysis.branches.filter((b) => b.action === "archive").length;
|
|
1003
|
+
if (options.confirm !== archiveCount) {
|
|
1004
|
+
analysis.errors.push(
|
|
1005
|
+
`Confirmation mismatch: --confirm ${options.confirm ?? "not provided"} but ${archiveCount} branches to archive. Use --confirm ${archiveCount} to proceed.`
|
|
1006
|
+
);
|
|
1007
|
+
return analysis;
|
|
1008
|
+
}
|
|
1009
|
+
return this.executeMoves(analysis, options.now);
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Move an analysis's candidates into build/removed/<UTC date>/ (no
|
|
1013
|
+
* confirmation gate; callers own that). Each branch is re-checked first; a
|
|
1014
|
+
* failure on one branch is recorded and the rest continue.
|
|
1015
|
+
*/
|
|
1016
|
+
async executeMoves(analysis, now = Date.now()) {
|
|
1017
|
+
analysis.mode = "executed";
|
|
1018
|
+
const timestamp = new Date(now).toISOString().slice(0, 10).replace(/-/g, "");
|
|
1019
|
+
const successfullyArchivedQueuedBranches = [];
|
|
1020
|
+
for (const branch of analysis.branches) {
|
|
1021
|
+
if (branch.action !== "archive") continue;
|
|
1022
|
+
const archiveName = buildRemovedBranchName(timestamp, branch.name);
|
|
1023
|
+
try {
|
|
1024
|
+
const changed = await this.changedSinceAnalysis(branch);
|
|
1025
|
+
if (changed) {
|
|
1026
|
+
branch.action = "skip";
|
|
1027
|
+
branch.reason = changed;
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
await execa2("git", ["branch", "-m", "--", branch.name, archiveName], {
|
|
1031
|
+
cwd: this.cwd,
|
|
1032
|
+
stdio: "pipe"
|
|
1033
|
+
});
|
|
1034
|
+
branch.reason = `moved to ${archiveName}`;
|
|
1035
|
+
if (this.queuedBranches.has(branch.name)) {
|
|
1036
|
+
successfullyArchivedQueuedBranches.push(branch.name);
|
|
1037
|
+
}
|
|
1038
|
+
} catch (error) {
|
|
1039
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1040
|
+
analysis.errors.push(`Failed to archive ${branch.name}: ${msg}`);
|
|
1041
|
+
branch.action = "skip";
|
|
1042
|
+
branch.reason = `archive failed: ${msg}`;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
analysis.archived = analysis.branches.filter((b) => b.action === "archive").length;
|
|
1046
|
+
analysis.skipped = analysis.branches.filter((b) => b.action === "skip").length;
|
|
1047
|
+
if (successfullyArchivedQueuedBranches.length > 0) {
|
|
1048
|
+
try {
|
|
1049
|
+
await removeBranchCleanupEntries(
|
|
1050
|
+
successfullyArchivedQueuedBranches,
|
|
1051
|
+
getBranchCleanupQueuePath(this.cwd)
|
|
1052
|
+
);
|
|
1053
|
+
} catch {
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
this.queuedBranches.clear();
|
|
1057
|
+
return analysis;
|
|
1058
|
+
}
|
|
1059
|
+
// ============================================================================
|
|
1060
|
+
// REMOTE BRANCH CLEANUP (Safety-first, off by default)
|
|
1061
|
+
// ============================================================================
|
|
1062
|
+
/**
|
|
1063
|
+
* Get all remote branches matching build/* pattern
|
|
1064
|
+
* SAFETY: Only returns build/* branches to prevent accidental deletion of human work
|
|
1065
|
+
*/
|
|
1066
|
+
async getRemoteBuildBranches(remote = "origin") {
|
|
1067
|
+
try {
|
|
1068
|
+
const { stdout } = await execa2(
|
|
1069
|
+
"git",
|
|
1070
|
+
// Prefix form (trailing `/`): a `build/*` glob stops at the next `/`
|
|
1071
|
+
// and would miss every build/<kind>/<details> branch.
|
|
1072
|
+
["for-each-ref", "--format=%(refname:short)", `refs/remotes/${remote}/build/`],
|
|
1073
|
+
{ cwd: this.cwd, stdio: "pipe" }
|
|
1074
|
+
);
|
|
1075
|
+
return stdout.trim().split("\n").filter(Boolean).map((ref) => ref.replace(`${remote}/`, ""));
|
|
1076
|
+
} catch {
|
|
1077
|
+
return [];
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Check if a remote branch is merged into the default branch
|
|
1082
|
+
*/
|
|
1083
|
+
async isRemoteBranchMerged(remote, branch, defaultBranch) {
|
|
1084
|
+
try {
|
|
1085
|
+
await execa2(
|
|
1086
|
+
"git",
|
|
1087
|
+
["merge-base", "--is-ancestor", `${remote}/${branch}`, `${remote}/${defaultBranch}`],
|
|
1088
|
+
{ cwd: this.cwd, stdio: "pipe" }
|
|
1089
|
+
);
|
|
1090
|
+
return true;
|
|
1091
|
+
} catch {
|
|
1092
|
+
return false;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Get count of commits on remote branch ahead of default
|
|
1097
|
+
*/
|
|
1098
|
+
async getRemoteAheadCount(remote, branch, defaultBranch) {
|
|
1099
|
+
try {
|
|
1100
|
+
const { stdout } = await execa2(
|
|
1101
|
+
"git",
|
|
1102
|
+
["rev-list", "--count", `${remote}/${defaultBranch}..${remote}/${branch}`],
|
|
1103
|
+
{ cwd: this.cwd, stdio: "pipe" }
|
|
1104
|
+
);
|
|
1105
|
+
return parseInt(stdout.trim(), 10) || 0;
|
|
1106
|
+
} catch {
|
|
1107
|
+
return 0;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* Get the currently analyzed local remote-tracking tip for a remote branch.
|
|
1112
|
+
*/
|
|
1113
|
+
async getRemoteBranchTip(remote, branch) {
|
|
1114
|
+
try {
|
|
1115
|
+
const { stdout } = await execa2(
|
|
1116
|
+
"git",
|
|
1117
|
+
["rev-parse", "--verify", `refs/remotes/${remote}/${branch}`],
|
|
1118
|
+
{ cwd: this.cwd, stdio: "pipe" }
|
|
1119
|
+
);
|
|
1120
|
+
const sha = stdout.trim();
|
|
1121
|
+
return sha || null;
|
|
1122
|
+
} catch {
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Check if branch is the head of any open PR
|
|
1128
|
+
* Returns the PR number if found, null otherwise
|
|
1129
|
+
* SAFETY: Protects branches that are still referenced by open PRs
|
|
1130
|
+
*/
|
|
1131
|
+
async getOpenPRForBranch(branch) {
|
|
1132
|
+
try {
|
|
1133
|
+
const result = await execa2(
|
|
1134
|
+
"gh",
|
|
1135
|
+
["pr", "list", "--head", branch, "--state", "open", "--json", "number", "--limit", "1"],
|
|
1136
|
+
{ cwd: this.cwd, stdio: "pipe" }
|
|
1137
|
+
);
|
|
1138
|
+
const stdout = result.stdout || "";
|
|
1139
|
+
const prs = JSON.parse(stdout.trim() || "[]");
|
|
1140
|
+
return prs.length > 0 && prs[0] ? prs[0].number : null;
|
|
1141
|
+
} catch {
|
|
1142
|
+
return "unknown";
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Analyze remote branches for cleanup
|
|
1147
|
+
* SAFETY: Only analyzes build/* branches on the specified remote
|
|
1148
|
+
*/
|
|
1149
|
+
async analyzeRemote(options = {}) {
|
|
1150
|
+
const opts = {
|
|
1151
|
+
remote: options.remote ?? "origin",
|
|
1152
|
+
dryRun: options.dryRun ?? true,
|
|
1153
|
+
requireMerged: options.requireMerged ?? true,
|
|
1154
|
+
protectOpenPRs: options.protectOpenPRs ?? true,
|
|
1155
|
+
confirm: options.confirm,
|
|
1156
|
+
maxDeleteCount: options.maxDeleteCount ?? 50,
|
|
1157
|
+
verbose: options.verbose ?? false
|
|
1158
|
+
};
|
|
1159
|
+
try {
|
|
1160
|
+
await execa2("git", ["fetch", opts.remote, "--prune"], { cwd: this.cwd, stdio: "pipe" });
|
|
1161
|
+
} catch (error) {
|
|
1162
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1163
|
+
return {
|
|
1164
|
+
mode: "dry-run",
|
|
1165
|
+
remote: opts.remote,
|
|
1166
|
+
defaultBranch: await this.getDefaultBranch(),
|
|
1167
|
+
scanned: 0,
|
|
1168
|
+
deleted: 0,
|
|
1169
|
+
skipped: 0,
|
|
1170
|
+
branches: [],
|
|
1171
|
+
errors: [`Failed to fetch from ${opts.remote}: ${msg}`],
|
|
1172
|
+
circuitBreakerTriggered: false
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
const result = {
|
|
1176
|
+
mode: "dry-run",
|
|
1177
|
+
remote: opts.remote,
|
|
1178
|
+
defaultBranch: await this.getDefaultBranchForRemote(opts.remote),
|
|
1179
|
+
scanned: 0,
|
|
1180
|
+
deleted: 0,
|
|
1181
|
+
skipped: 0,
|
|
1182
|
+
branches: [],
|
|
1183
|
+
errors: [],
|
|
1184
|
+
circuitBreakerTriggered: false,
|
|
1185
|
+
remoteRefsFetchedAndPruned: true
|
|
1186
|
+
};
|
|
1187
|
+
const remoteBranches = await this.getRemoteBuildBranches(opts.remote);
|
|
1188
|
+
result.scanned = remoteBranches.length;
|
|
1189
|
+
for (const branch of remoteBranches) {
|
|
1190
|
+
if (result.deleted >= opts.maxDeleteCount) {
|
|
1191
|
+
result.circuitBreakerTriggered = true;
|
|
1192
|
+
result.branches.push({
|
|
1193
|
+
name: branch,
|
|
1194
|
+
fullRef: `${opts.remote}/${branch}`,
|
|
1195
|
+
action: "skip",
|
|
1196
|
+
reason: "circuit breaker triggered"
|
|
1197
|
+
});
|
|
1198
|
+
result.skipped++;
|
|
1199
|
+
continue;
|
|
1200
|
+
}
|
|
1201
|
+
const analysis = await this.analyzeRemoteBranch(
|
|
1202
|
+
opts.remote,
|
|
1203
|
+
branch,
|
|
1204
|
+
result.defaultBranch,
|
|
1205
|
+
opts
|
|
1206
|
+
);
|
|
1207
|
+
result.branches.push(analysis);
|
|
1208
|
+
if (analysis.action === "delete") {
|
|
1209
|
+
result.deleted++;
|
|
1210
|
+
} else {
|
|
1211
|
+
result.skipped++;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return result;
|
|
1215
|
+
}
|
|
1216
|
+
/**
|
|
1217
|
+
* Analyze a single remote branch
|
|
1218
|
+
*/
|
|
1219
|
+
async analyzeRemoteBranch(remote, branch, defaultBranch, opts) {
|
|
1220
|
+
const fullRef = `${remote}/${branch}`;
|
|
1221
|
+
const kind = findBuildBranchShape(branch)?.kind;
|
|
1222
|
+
if (kind === "removed") {
|
|
1223
|
+
return {
|
|
1224
|
+
name: branch,
|
|
1225
|
+
fullRef,
|
|
1226
|
+
action: "skip",
|
|
1227
|
+
reason: "removed branch (use prune-removed)"
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
if (kind === "preflight") {
|
|
1231
|
+
return {
|
|
1232
|
+
name: branch,
|
|
1233
|
+
fullRef,
|
|
1234
|
+
action: "skip",
|
|
1235
|
+
reason: "preflight branch"
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
if (!isEphemeralBuildBranchDeletionCandidate(branch)) {
|
|
1239
|
+
const reason = kind === "sprint" || kind === "workflow" ? "run branch (not ephemeral)" : "not a recognized ephemeral build branch";
|
|
1240
|
+
return {
|
|
1241
|
+
name: branch,
|
|
1242
|
+
fullRef,
|
|
1243
|
+
action: "skip",
|
|
1244
|
+
reason
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
const isMerged = await this.isRemoteBranchMerged(remote, branch, defaultBranch);
|
|
1248
|
+
const aheadCount = await this.getRemoteAheadCount(remote, branch, defaultBranch);
|
|
1249
|
+
if (opts.requireMerged && !isMerged) {
|
|
1250
|
+
return {
|
|
1251
|
+
name: branch,
|
|
1252
|
+
fullRef,
|
|
1253
|
+
action: "skip",
|
|
1254
|
+
reason: `not merged (${aheadCount} commits ahead)`,
|
|
1255
|
+
details: { isMerged, aheadCount }
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
if (opts.protectOpenPRs) {
|
|
1259
|
+
const openPRNumber = await this.getOpenPRForBranch(branch);
|
|
1260
|
+
if (openPRNumber === "unknown") {
|
|
1261
|
+
return {
|
|
1262
|
+
name: branch,
|
|
1263
|
+
fullRef,
|
|
1264
|
+
action: "skip",
|
|
1265
|
+
reason: "open PR status unknown",
|
|
1266
|
+
details: { isMerged, aheadCount }
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1269
|
+
if (openPRNumber !== null) {
|
|
1270
|
+
return {
|
|
1271
|
+
name: branch,
|
|
1272
|
+
fullRef,
|
|
1273
|
+
action: "skip",
|
|
1274
|
+
reason: `open PR #${openPRNumber}`,
|
|
1275
|
+
details: { isMerged, aheadCount, openPRNumber }
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
const expectedRemoteSha = await this.getRemoteBranchTip(remote, branch);
|
|
1280
|
+
if (!expectedRemoteSha) {
|
|
1281
|
+
return {
|
|
1282
|
+
name: branch,
|
|
1283
|
+
fullRef,
|
|
1284
|
+
action: "skip",
|
|
1285
|
+
reason: "remote tip unknown",
|
|
1286
|
+
details: { isMerged, aheadCount }
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
return {
|
|
1290
|
+
name: branch,
|
|
1291
|
+
fullRef,
|
|
1292
|
+
action: "delete",
|
|
1293
|
+
reason: isMerged ? "merged into default" : "force delete (unmerged)",
|
|
1294
|
+
details: { isMerged, aheadCount, expectedRemoteSha }
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1298
|
+
* Delete remote branches
|
|
1299
|
+
* SAFETY: Only deletes build/* branches that pass all checks
|
|
1300
|
+
*/
|
|
1301
|
+
async deleteRemote(options = {}) {
|
|
1302
|
+
const opts = {
|
|
1303
|
+
remote: options.remote ?? "origin",
|
|
1304
|
+
dryRun: options.dryRun ?? true,
|
|
1305
|
+
requireMerged: options.requireMerged ?? true,
|
|
1306
|
+
protectOpenPRs: options.protectOpenPRs ?? true,
|
|
1307
|
+
confirm: options.confirm,
|
|
1308
|
+
maxDeleteCount: options.maxDeleteCount ?? 50,
|
|
1309
|
+
verbose: options.verbose ?? false
|
|
1310
|
+
};
|
|
1311
|
+
const analysis = await this.analyzeRemote(opts);
|
|
1312
|
+
if (opts.dryRun) {
|
|
1313
|
+
return analysis;
|
|
1314
|
+
}
|
|
1315
|
+
const deleteCount = analysis.branches.filter((b) => b.action === "delete").length;
|
|
1316
|
+
if (opts.confirm !== deleteCount) {
|
|
1317
|
+
analysis.errors.push(
|
|
1318
|
+
`Confirmation mismatch: --confirm ${opts.confirm ?? "not provided"} but ${deleteCount} branches to delete. Use --confirm ${deleteCount} to proceed.`
|
|
1319
|
+
);
|
|
1320
|
+
return analysis;
|
|
1321
|
+
}
|
|
1322
|
+
analysis.mode = "executed";
|
|
1323
|
+
for (const branch of analysis.branches) {
|
|
1324
|
+
if (branch.action !== "delete") continue;
|
|
1325
|
+
try {
|
|
1326
|
+
const expectedRemoteSha = branch.details?.expectedRemoteSha;
|
|
1327
|
+
if (!expectedRemoteSha) {
|
|
1328
|
+
throw new Error("missing expected remote tip");
|
|
1329
|
+
}
|
|
1330
|
+
await execa2(
|
|
1331
|
+
"git",
|
|
1332
|
+
[
|
|
1333
|
+
"push",
|
|
1334
|
+
opts.remote,
|
|
1335
|
+
`--force-with-lease=refs/heads/${branch.name}:${expectedRemoteSha}`,
|
|
1336
|
+
`:refs/heads/${branch.name}`
|
|
1337
|
+
],
|
|
1338
|
+
{
|
|
1339
|
+
cwd: this.cwd,
|
|
1340
|
+
stdio: "pipe"
|
|
1341
|
+
}
|
|
1342
|
+
);
|
|
1343
|
+
branch.reason = `deleted from ${opts.remote}`;
|
|
1344
|
+
} catch (error) {
|
|
1345
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1346
|
+
analysis.errors.push(`Failed to delete ${branch.fullRef}: ${msg}`);
|
|
1347
|
+
branch.action = "skip";
|
|
1348
|
+
branch.reason = `delete failed: ${msg}`;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
analysis.deleted = analysis.branches.filter((b) => b.action === "delete").length;
|
|
1352
|
+
analysis.skipped = analysis.branches.filter((b) => b.action === "skip").length;
|
|
1353
|
+
return analysis;
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
function createBranchCleanupManager(cwd = process.cwd()) {
|
|
1357
|
+
return new BranchCleanupManager(cwd);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
export {
|
|
1361
|
+
CLEANUP_UNBORN_REPOSITORY_INFO,
|
|
1362
|
+
CLEANUP_HEAD_INSPECTION_ERROR,
|
|
1363
|
+
resolveCleanupBuildDir,
|
|
1364
|
+
cleanupCompetitionStateFiles,
|
|
1365
|
+
DEFAULT_BRANCH_CLEANUP_AGE_DAYS,
|
|
1366
|
+
BranchCleanupManager,
|
|
1367
|
+
createBranchCleanupManager
|
|
1368
|
+
};
|
|
1369
|
+
//# sourceMappingURL=chunk-ZVVD2XGV.js.map
|