@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,4386 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveAutoloopElapsedMs
|
|
3
|
+
} from "./chunk-MZ5WYKNA.js";
|
|
4
|
+
import {
|
|
5
|
+
describeMissingGateBaseline,
|
|
6
|
+
failsIdenticallyOnBaseline,
|
|
7
|
+
gateEvidenceOf
|
|
8
|
+
} from "./chunk-CBSWKQCX.js";
|
|
9
|
+
import {
|
|
10
|
+
createDirectAutoloopCancellationFailure,
|
|
11
|
+
deriveDirectAutoloopRecovery,
|
|
12
|
+
getCarriedDirectAutoloopFailureEnvelope,
|
|
13
|
+
getCarriedDirectAutoloopIterationFingerprint,
|
|
14
|
+
globalRecursionTracker,
|
|
15
|
+
rediscoverCandidateGates,
|
|
16
|
+
serializeDirectAutoloopFailureRecovery
|
|
17
|
+
} from "./chunk-6LAH2UV2.js";
|
|
18
|
+
import "./chunk-OV5PKQMA.js";
|
|
19
|
+
import {
|
|
20
|
+
DEFAULT_AUTOLOOP_TIMEBOX_MS,
|
|
21
|
+
resolveAutoloopTimeboxMs,
|
|
22
|
+
resolveAutoloopValidationMode
|
|
23
|
+
} from "./chunk-6FIBNIQU.js";
|
|
24
|
+
import {
|
|
25
|
+
computeMonotonicAutoloopEscalation,
|
|
26
|
+
execWithTimeout,
|
|
27
|
+
validateRequirements
|
|
28
|
+
} from "./chunk-OTXLMJKP.js";
|
|
29
|
+
import {
|
|
30
|
+
autoloopPresetIncludesGateKind
|
|
31
|
+
} from "./chunk-GQIP72ZJ.js";
|
|
32
|
+
import {
|
|
33
|
+
tailUtf8
|
|
34
|
+
} from "./chunk-K7FAFORM.js";
|
|
35
|
+
import "./chunk-J6NZX6QH.js";
|
|
36
|
+
import {
|
|
37
|
+
COMPLETION_BLOCKER_MISSING_SUBSTANTIVE_EVIDENCE,
|
|
38
|
+
COMPLETION_BLOCKER_PROGRESS_VERIFICATION_UNAVAILABLE,
|
|
39
|
+
completionStatusAllowsSuccess,
|
|
40
|
+
customGatesAllowCompletion,
|
|
41
|
+
customGatesHaveBlockingFailure,
|
|
42
|
+
evaluateCompletion,
|
|
43
|
+
hasOnlyStyleVerificationEvidence,
|
|
44
|
+
hasSubstantiveCompletionEvidence,
|
|
45
|
+
isBenignSemanticSkip,
|
|
46
|
+
isBlockingCustomGateForCompletion,
|
|
47
|
+
isBlockingQualityGateForCompletion,
|
|
48
|
+
isNonBlockingQualityGateSkip,
|
|
49
|
+
isSemanticCheckBlocking,
|
|
50
|
+
isSemanticCompletionSatisfied,
|
|
51
|
+
isSemanticErrorSkip,
|
|
52
|
+
isSuccessLikeControllerReason,
|
|
53
|
+
isUnavailableOrSkippedQualityGate,
|
|
54
|
+
qualityGatesAllowCompletion,
|
|
55
|
+
qualityGatesHaveBlockingFailure,
|
|
56
|
+
readReturnedTaskFailure,
|
|
57
|
+
verificationGatesUnavailableOnly
|
|
58
|
+
} from "./chunk-IJM4GKAT.js";
|
|
59
|
+
import {
|
|
60
|
+
countBlockingVulnerabilities,
|
|
61
|
+
isTestEvidenceGate,
|
|
62
|
+
isTestEvidenceGateResult,
|
|
63
|
+
testEvidenceGateId
|
|
64
|
+
} from "./chunk-QOFLUS24.js";
|
|
65
|
+
import {
|
|
66
|
+
isSignificantProgress,
|
|
67
|
+
rateProgress
|
|
68
|
+
} from "./chunk-4ZPLWEZO.js";
|
|
69
|
+
import {
|
|
70
|
+
calculateSatisfactionScore,
|
|
71
|
+
checkAcceptanceCriteria
|
|
72
|
+
} from "./chunk-C7AGUJ5K.js";
|
|
73
|
+
import "./chunk-VLMDM56Q.js";
|
|
74
|
+
import "./chunk-VCGSWN5M.js";
|
|
75
|
+
import "./chunk-6CAU7VBA.js";
|
|
76
|
+
import "./chunk-IYY3HQAD.js";
|
|
77
|
+
import "./chunk-TGCVL74Y.js";
|
|
78
|
+
import "./chunk-MKASIKWZ.js";
|
|
79
|
+
import "./chunk-UDNNAQN5.js";
|
|
80
|
+
import "./chunk-HKO45NLZ.js";
|
|
81
|
+
import {
|
|
82
|
+
classifyFailureEnvelope
|
|
83
|
+
} from "./chunk-PRDHI2L5.js";
|
|
84
|
+
import {
|
|
85
|
+
abortableDelay
|
|
86
|
+
} from "./chunk-4QKP6I4C.js";
|
|
87
|
+
import "./chunk-GWHGTG37.js";
|
|
88
|
+
import "./chunk-XON4ZCYX.js";
|
|
89
|
+
import "./chunk-S6I4KISU.js";
|
|
90
|
+
import "./chunk-3P5IN5E7.js";
|
|
91
|
+
import {
|
|
92
|
+
globalProcessLimiter
|
|
93
|
+
} from "./chunk-SF6YK3JI.js";
|
|
94
|
+
import "./chunk-JBBB2Y47.js";
|
|
95
|
+
import "./chunk-RBKLOUXA.js";
|
|
96
|
+
import "./chunk-VMFZEVVX.js";
|
|
97
|
+
import "./chunk-T7E5JS6N.js";
|
|
98
|
+
import {
|
|
99
|
+
ORCHESTRATOR_FEATURE_FLAGS
|
|
100
|
+
} from "./chunk-ZJB6SQPA.js";
|
|
101
|
+
import {
|
|
102
|
+
signalCoordinator
|
|
103
|
+
} from "./chunk-GC4CRMTS.js";
|
|
104
|
+
import "./chunk-C3DH3NCY.js";
|
|
105
|
+
import "./chunk-IVZEONFC.js";
|
|
106
|
+
import "./chunk-XTXYIISX.js";
|
|
107
|
+
import "./chunk-MEMSY6VY.js";
|
|
108
|
+
import "./chunk-VBNCKCCI.js";
|
|
109
|
+
import "./chunk-33IGPPUI.js";
|
|
110
|
+
import "./chunk-UPHU64NB.js";
|
|
111
|
+
import "./chunk-JLS65NUQ.js";
|
|
112
|
+
import "./chunk-FRBPKBFE.js";
|
|
113
|
+
import "./chunk-BAWJNMWF.js";
|
|
114
|
+
import "./chunk-LX4F24ZH.js";
|
|
115
|
+
import "./chunk-BBPIILO2.js";
|
|
116
|
+
import "./chunk-2NMNFUQA.js";
|
|
117
|
+
import "./chunk-I7SCBHJN.js";
|
|
118
|
+
import "./chunk-TGXXYDL4.js";
|
|
119
|
+
import {
|
|
120
|
+
isSafeGitRef
|
|
121
|
+
} from "./chunk-D2M2Y5ID.js";
|
|
122
|
+
import "./chunk-UJP3XM54.js";
|
|
123
|
+
import "./chunk-MULMXX4V.js";
|
|
124
|
+
import "./chunk-UTDEOPKV.js";
|
|
125
|
+
import "./chunk-RFDVSI4N.js";
|
|
126
|
+
import "./chunk-M4BUEXXF.js";
|
|
127
|
+
import "./chunk-ZH4G3FU5.js";
|
|
128
|
+
import "./chunk-726G6WDL.js";
|
|
129
|
+
import {
|
|
130
|
+
readUntrackedFileDiffEntry,
|
|
131
|
+
renderUntrackedFileDiff
|
|
132
|
+
} from "./chunk-5UBIFVRD.js";
|
|
133
|
+
import "./chunk-7HPCIOMA.js";
|
|
134
|
+
import "./chunk-P6SSWAKY.js";
|
|
135
|
+
import {
|
|
136
|
+
classifyResolverCommand,
|
|
137
|
+
countSecurityVulnerabilities
|
|
138
|
+
} from "./chunk-6TBEX4R4.js";
|
|
139
|
+
import "./chunk-PXKERBKX.js";
|
|
140
|
+
import "./chunk-QYQOVOLR.js";
|
|
141
|
+
import "./chunk-AEQWV746.js";
|
|
142
|
+
import "./chunk-SVUNZOPG.js";
|
|
143
|
+
import "./chunk-KUEWV2JH.js";
|
|
144
|
+
import "./chunk-R2TIYG7U.js";
|
|
145
|
+
import {
|
|
146
|
+
parseDiffGitHeaderPaths
|
|
147
|
+
} from "./chunk-5FKHIKTS.js";
|
|
148
|
+
import {
|
|
149
|
+
runVerificationCommand
|
|
150
|
+
} from "./chunk-S2E632FQ.js";
|
|
151
|
+
import "./chunk-XJ2E7YEJ.js";
|
|
152
|
+
import "./chunk-B7YRSULE.js";
|
|
153
|
+
import "./chunk-4U6XK2DG.js";
|
|
154
|
+
import "./chunk-BY6ODHNZ.js";
|
|
155
|
+
import "./chunk-3H4MWYIC.js";
|
|
156
|
+
import "./chunk-DP7FKP6W.js";
|
|
157
|
+
import "./chunk-VIFHYTI5.js";
|
|
158
|
+
import "./chunk-XGU6PBO5.js";
|
|
159
|
+
import "./chunk-F55YABKV.js";
|
|
160
|
+
import "./chunk-D6WTZMZB.js";
|
|
161
|
+
import "./chunk-5EQN56OZ.js";
|
|
162
|
+
import {
|
|
163
|
+
shouldIgnoreRepoPath
|
|
164
|
+
} from "./chunk-RBBTBCHX.js";
|
|
165
|
+
import "./chunk-4DJL2VXA.js";
|
|
166
|
+
import {
|
|
167
|
+
boundedFailureDiagnostics,
|
|
168
|
+
detectProjectCapabilities,
|
|
169
|
+
parseFailureOutput
|
|
170
|
+
} from "./chunk-AHU3FKPA.js";
|
|
171
|
+
import {
|
|
172
|
+
deriveVerificationDisposition
|
|
173
|
+
} from "./chunk-TUQMMFEQ.js";
|
|
174
|
+
import {
|
|
175
|
+
describeVerificationCommand,
|
|
176
|
+
detectExitZeroVerifyFailure
|
|
177
|
+
} from "./chunk-EPAMVGI3.js";
|
|
178
|
+
import "./chunk-6CB3KJRY.js";
|
|
179
|
+
import "./chunk-L2S235CU.js";
|
|
180
|
+
import "./chunk-D4VJFCGZ.js";
|
|
181
|
+
import "./chunk-RPIMAMV7.js";
|
|
182
|
+
import "./chunk-ALDTFNZ3.js";
|
|
183
|
+
import "./chunk-QOIASNEJ.js";
|
|
184
|
+
import "./chunk-2VUEDIUM.js";
|
|
185
|
+
import "./chunk-MJ6WNSIX.js";
|
|
186
|
+
import "./chunk-5KQETTNS.js";
|
|
187
|
+
import "./chunk-J2ICMYDA.js";
|
|
188
|
+
import "./chunk-2VLJUXJU.js";
|
|
189
|
+
import "./chunk-PPZESPJT.js";
|
|
190
|
+
import "./chunk-XCOIBNET.js";
|
|
191
|
+
import "./chunk-Y733RB7T.js";
|
|
192
|
+
import "./chunk-H3HGMISG.js";
|
|
193
|
+
import "./chunk-FAZBRHGG.js";
|
|
194
|
+
import "./chunk-CJBSZX3F.js";
|
|
195
|
+
import "./chunk-C3KCMAJP.js";
|
|
196
|
+
import "./chunk-FKCG7K6H.js";
|
|
197
|
+
import "./chunk-AJN5Y5YZ.js";
|
|
198
|
+
import {
|
|
199
|
+
execGit
|
|
200
|
+
} from "./chunk-MHLEZQQI.js";
|
|
201
|
+
import "./chunk-HEP3ILP4.js";
|
|
202
|
+
import "./chunk-BQJOGAWT.js";
|
|
203
|
+
import "./chunk-WV3KQDPE.js";
|
|
204
|
+
import "./chunk-VSWC5ZXI.js";
|
|
205
|
+
import "./chunk-XV7NZL4B.js";
|
|
206
|
+
import "./chunk-KKQKWAMF.js";
|
|
207
|
+
import "./chunk-RWQQIKIC.js";
|
|
208
|
+
import "./chunk-GVJGSSKM.js";
|
|
209
|
+
import "./chunk-QJ6OEH4K.js";
|
|
210
|
+
import "./chunk-BD3PGW6A.js";
|
|
211
|
+
import "./chunk-43OKHTW4.js";
|
|
212
|
+
import "./chunk-MNOVBYFU.js";
|
|
213
|
+
import "./chunk-QXBKTJT6.js";
|
|
214
|
+
import "./chunk-4BTDUT2S.js";
|
|
215
|
+
import "./chunk-35J4NE6S.js";
|
|
216
|
+
import "./chunk-RIMARPCF.js";
|
|
217
|
+
import "./chunk-HGFXODKO.js";
|
|
218
|
+
import "./chunk-N5DX4JAK.js";
|
|
219
|
+
import "./chunk-V2TVPO3X.js";
|
|
220
|
+
import "./chunk-RRC5BL7B.js";
|
|
221
|
+
import "./chunk-352PCJLK.js";
|
|
222
|
+
import "./chunk-RCP2Y6DQ.js";
|
|
223
|
+
import "./chunk-M6UHOC4I.js";
|
|
224
|
+
import "./chunk-KTMW65UX.js";
|
|
225
|
+
import "./chunk-3JKNRYEE.js";
|
|
226
|
+
import "./chunk-MT2WAIR3.js";
|
|
227
|
+
import "./chunk-WGQAXLNA.js";
|
|
228
|
+
import "./chunk-ONHAMBN6.js";
|
|
229
|
+
import "./chunk-XSJTIFUY.js";
|
|
230
|
+
import "./chunk-XWIZ6B5S.js";
|
|
231
|
+
import "./chunk-U4DRS6ZW.js";
|
|
232
|
+
import "./chunk-I56TH7VM.js";
|
|
233
|
+
import "./chunk-Z5WGNULV.js";
|
|
234
|
+
import "./chunk-O26L6F7F.js";
|
|
235
|
+
import "./chunk-RJ6RSNT6.js";
|
|
236
|
+
import "./chunk-TAJPCXSB.js";
|
|
237
|
+
import "./chunk-56WPYDJH.js";
|
|
238
|
+
import "./chunk-RSYTSBOO.js";
|
|
239
|
+
import "./chunk-STW7OFOA.js";
|
|
240
|
+
import "./chunk-CHA2HDE5.js";
|
|
241
|
+
import "./chunk-JNMWYMC6.js";
|
|
242
|
+
import {
|
|
243
|
+
BUILD_AUTOLOOP_COMPLETION_SIGNAL,
|
|
244
|
+
BUILD_AUTOLOOP_JUDGE,
|
|
245
|
+
BUILD_AUTOLOOP_MAX_ITERATIONS,
|
|
246
|
+
BUILD_AUTOLOOP_MAX_MEMORY,
|
|
247
|
+
BUILD_AUTOLOOP_MIN_PROGRESS,
|
|
248
|
+
BUILD_AUTOLOOP_QUALITY_GATES_MODE,
|
|
249
|
+
debugLog,
|
|
250
|
+
emitWarning,
|
|
251
|
+
readEnv,
|
|
252
|
+
readRawEnv,
|
|
253
|
+
withExecutionContextEnvOverrides
|
|
254
|
+
} from "./chunk-7VRJHTGZ.js";
|
|
255
|
+
import "./chunk-XDM65LBX.js";
|
|
256
|
+
import "./chunk-CPSVQR2I.js";
|
|
257
|
+
import "./chunk-PZ5AY32C.js";
|
|
258
|
+
|
|
259
|
+
// src/orchestrator/autonomous-loop-controller.ts
|
|
260
|
+
import { createHash } from "crypto";
|
|
261
|
+
import { EventEmitter } from "events";
|
|
262
|
+
import * as os from "os";
|
|
263
|
+
import { performance } from "perf_hooks";
|
|
264
|
+
|
|
265
|
+
// src/core/project/compile-failure-output.ts
|
|
266
|
+
var MAVEN_LEVEL_TAG = String.raw`(?:\[(?:ERROR|INFO|WARNING)\]\s+)?`;
|
|
267
|
+
var COMPILE_DIAGNOSTIC_PATTERNS = [
|
|
268
|
+
// Rust compiler diagnostics: `error[E0382]:` (the bare form is BARE_ERROR_LINE)
|
|
269
|
+
/^\s*error\[[A-Z]\d+\]:/m,
|
|
270
|
+
/\berror:\s+could not compile\b/i,
|
|
271
|
+
// Go compiler diagnostics: `path/file.go:line:col: message`
|
|
272
|
+
/^\s*(?:\.[/\\][^\n]+\.go:\d+:\d+:|[^\s:]+\.go:\d+:\d+:)\s+.+/m,
|
|
273
|
+
// Maven's compiler section header.
|
|
274
|
+
new RegExp(String.raw`^\s*${MAVEN_LEVEL_TAG}COMPILATION ERROR\b`, "im"),
|
|
275
|
+
/\bfailed to compile\b/i,
|
|
276
|
+
/\bcompilation failed\b/i
|
|
277
|
+
];
|
|
278
|
+
var BUILD_FAILURE_BANNER_PATTERNS = [
|
|
279
|
+
/^\s*BUILD FAILED\b/im,
|
|
280
|
+
new RegExp(String.raw`^\s*${MAVEN_LEVEL_TAG}BUILD FAILURE\b`, "im")
|
|
281
|
+
];
|
|
282
|
+
var BARE_ERROR_LINE = /^\s*error:/m;
|
|
283
|
+
function hasCompileDiagnosticOutput(output, scope = "tail") {
|
|
284
|
+
if (scope === "tail" && BARE_ERROR_LINE.test(output)) return true;
|
|
285
|
+
return COMPILE_DIAGNOSTIC_PATTERNS.some((pattern) => pattern.test(output));
|
|
286
|
+
}
|
|
287
|
+
function hasBuildFailureBanner(output) {
|
|
288
|
+
return BUILD_FAILURE_BANNER_PATTERNS.some((pattern) => pattern.test(output));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/core/project/failure-count-availability.ts
|
|
292
|
+
var UNATTRIBUTABLE_COUNT = "unattributable";
|
|
293
|
+
function failureCountUnavailableReason(language, kind) {
|
|
294
|
+
return `No registered ${kind} failure parser for language '${language}'; issue count unavailable.`;
|
|
295
|
+
}
|
|
296
|
+
function unavailableFailureCountForCommand(command, kind) {
|
|
297
|
+
const { language } = describeVerificationCommand(command);
|
|
298
|
+
if (language === "node" || language === "unknown") return null;
|
|
299
|
+
return { language, reason: failureCountUnavailableReason(language, kind) };
|
|
300
|
+
}
|
|
301
|
+
function deriveVerificationFailureCount(command, output, kind) {
|
|
302
|
+
const parsed = parseFailureOutput(command, output, kind);
|
|
303
|
+
if (parsed.parsed && parsed.errorCount !== null) {
|
|
304
|
+
return {
|
|
305
|
+
status: "counted",
|
|
306
|
+
count: parsed.errorCount,
|
|
307
|
+
messages: parsed.messages,
|
|
308
|
+
...parsed.suiteFootprint ? { suiteFootprint: parsed.suiteFootprint } : {}
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const unavailable = unavailableFailureCountForCommand(command, kind);
|
|
312
|
+
if (unavailable) {
|
|
313
|
+
return { status: "unavailable", ...unavailable };
|
|
314
|
+
}
|
|
315
|
+
return { status: "unattributed", language: describeVerificationCommand(command).language };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// src/orchestrator/autoloop-custom-gate-result.ts
|
|
319
|
+
var RESOLVER_BUCKETS = ["lint", "typecheck", "build", "test"];
|
|
320
|
+
function readResolverBucketKinds(cwd) {
|
|
321
|
+
const kinds = /* @__PURE__ */ new Map();
|
|
322
|
+
try {
|
|
323
|
+
const { verification } = detectProjectCapabilities(cwd);
|
|
324
|
+
for (const bucket of RESOLVER_BUCKETS) {
|
|
325
|
+
for (const command of verification[bucket] ?? []) kinds.set(command, bucket);
|
|
326
|
+
}
|
|
327
|
+
for (const command of verification.format ?? []) {
|
|
328
|
+
if (!kinds.has(command)) kinds.set(command, "format");
|
|
329
|
+
}
|
|
330
|
+
} catch {
|
|
331
|
+
}
|
|
332
|
+
return kinds;
|
|
333
|
+
}
|
|
334
|
+
function withCustomGateVerificationKinds(cwd, gates) {
|
|
335
|
+
if (!gates || gates.length === 0) return gates;
|
|
336
|
+
const bucketKinds = readResolverBucketKinds(cwd);
|
|
337
|
+
return gates.map((gate) => ({
|
|
338
|
+
...gate,
|
|
339
|
+
verificationKind: gate.verificationKind ?? describeVerificationCommand(gate.command, { bucket: bucketKinds.get(gate.command) }).kind
|
|
340
|
+
}));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/orchestrator/autoloop-mature-delivery.ts
|
|
344
|
+
function idleStopEnabledChecksFromConfig(config) {
|
|
345
|
+
return {
|
|
346
|
+
qualityGates: config.runQualityGates === true,
|
|
347
|
+
customGates: config.runQualityGates === true && (config.customGateCommands?.length ?? 0) > 0,
|
|
348
|
+
qualityGatePolicy: config.qualityGatePolicy ?? (config.runQualityGates === true ? "enabled" : "not_configured"),
|
|
349
|
+
stopOnUnconfirmableCompletion: config.stopOnUnconfirmableCompletion === true
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function isUnconfirmableGatesOffDelivery(result, enabled) {
|
|
353
|
+
return enabled.stopOnUnconfirmableCompletion === true && enabled.qualityGatePolicy === "explicitly_disabled" && !enabled.qualityGates && !enabled.customGates && result.success && typeof result.iterationFingerprint === "string" && result.iterationFingerprint !== "" && result.requirements?.enabled !== true && result.completionSummary?.completionSignalDetected === true && result.completionSummary.blockingIssues?.includes(
|
|
354
|
+
COMPLETION_BLOCKER_MISSING_SUBSTANTIVE_EVIDENCE
|
|
355
|
+
) === true;
|
|
356
|
+
}
|
|
357
|
+
var EMPTY_DIFF_FAILURE_PATTERN = /no[- ]?changes? detected|empty (?:diff|change set)|git diff (?:is )?empty|baseline unchanged|delivery no[- ]?op/i;
|
|
358
|
+
function enabledRequiredGatesActuallyRanAndPassed(result, enabled) {
|
|
359
|
+
if (!enabled.qualityGates && !enabled.customGates) {
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
let standardGateEvidence = false;
|
|
363
|
+
if (enabled.qualityGates) {
|
|
364
|
+
const gates = result.qualityGates;
|
|
365
|
+
if (gates?.some((gate) => isBlockingQualityGateForCompletion(gate)) === true) {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
if (gates?.some((gate) => gate.unavailable === true)) {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
standardGateEvidence = qualityGatesAllowCompletion(gates);
|
|
372
|
+
}
|
|
373
|
+
let customGateEvidence = false;
|
|
374
|
+
if (enabled.customGates) {
|
|
375
|
+
const customGates = result.customGateResults;
|
|
376
|
+
if (!customGates || customGates.length === 0) {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
for (const gate of customGates) {
|
|
380
|
+
if (gate.skipped === true || gate.unavailable === true || !gate.passed) {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
customGateEvidence = customGates.some(
|
|
385
|
+
(gate) => gate.passed && gate.skipped !== true && gate.unavailable !== true
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
if (!standardGateEvidence && !customGateEvidence) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
if (result.requirements?.enabled && !result.requirements.passed) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
function resolveMatureDeliveryVerification(result, enabled) {
|
|
397
|
+
if (result.completionSummary?.completionSignalDetected !== true) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
if (!enabled.qualityGates && !enabled.customGates) {
|
|
401
|
+
if (enabled.qualityGatePolicy !== "explicitly_disabled") {
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
if (result.completionSummary.hasSubstantiveEvidence !== true) {
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
const expectedUnverifiedBlockers = /* @__PURE__ */ new Set([
|
|
408
|
+
COMPLETION_BLOCKER_PROGRESS_VERIFICATION_UNAVAILABLE
|
|
409
|
+
]);
|
|
410
|
+
const hasSubstantiveEvidence = result.completionSummary.hasSubstantiveEvidence === true;
|
|
411
|
+
const explicitlyDisabledWithOnlyExpectedUnverifiedEvidenceGaps = result.completionSummary.status === "NOT_COMPLETE" && result.completionSummary.providerOk === true && result.completionSummary.gatesOk === true && result.completionSummary.unsafeCompletion === true && hasSubstantiveEvidence && (result.completionSummary.blockingIssues?.length ?? 0) > 0 && result.completionSummary.blockingIssues?.every(
|
|
412
|
+
(issue) => expectedUnverifiedBlockers.has(issue)
|
|
413
|
+
) === true;
|
|
414
|
+
if (!completionStatusAllowsSuccess(result.completionSummary.status) && !explicitlyDisabledWithOnlyExpectedUnverifiedEvidenceGaps) {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
if (result.requirements?.enabled && !result.requirements.passed) {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
if (isSemanticCheckBlocking(result.semanticValidation)) {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
return "unverified";
|
|
424
|
+
}
|
|
425
|
+
if (resolveUnavailableOnlyDelivery(result, enabled)) {
|
|
426
|
+
return "unverified";
|
|
427
|
+
}
|
|
428
|
+
if (!completionStatusAllowsSuccess(result.completionSummary.status)) {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
if (!enabledRequiredGatesActuallyRanAndPassed(result, enabled)) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
return hasOnlyStyleVerificationEvidence(result) ? "unverified" : "verified";
|
|
435
|
+
}
|
|
436
|
+
function resolveUnavailableOnlyDelivery(result, enabled) {
|
|
437
|
+
const summary = result.completionSummary;
|
|
438
|
+
if (!enabled.qualityGates && !enabled.customGates) return null;
|
|
439
|
+
if (summary?.completionSignalDetected !== true || summary.providerOk !== true || summary.hasSubstantiveEvidence !== true) {
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
if (result.requirements?.enabled && !result.requirements.passed) return null;
|
|
443
|
+
if (isSemanticCheckBlocking(result.semanticValidation)) return null;
|
|
444
|
+
if (!verificationGatesUnavailableOnly({
|
|
445
|
+
qualityGates: result.qualityGates,
|
|
446
|
+
customGateResults: result.customGateResults
|
|
447
|
+
})) {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
if (result.customGateResults?.some(
|
|
451
|
+
(gate) => !gate.passed && gate.skipped === true && gate.unavailable !== true
|
|
452
|
+
)) {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
const unavailable = (result.qualityGates?.filter((gate) => gate.unavailable === true && !gate.passed).length ?? 0) + (result.customGateResults?.filter((gate) => gate.unavailable === true && !gate.passed).length ?? 0);
|
|
456
|
+
return deriveVerificationDisposition({
|
|
457
|
+
passed: false,
|
|
458
|
+
unavailable: true,
|
|
459
|
+
scope: "project",
|
|
460
|
+
reason: `required verification was unavailable (${unavailable} gate${unavailable === 1 ? "" : "s"} could not run)`
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
function isRealFirstDeliveryIteration(result, enabled) {
|
|
464
|
+
if (!result.success) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
if (typeof result.iterationFingerprint !== "string" || result.iterationFingerprint === "") {
|
|
468
|
+
return false;
|
|
469
|
+
}
|
|
470
|
+
return resolveMatureDeliveryVerification(result, enabled) !== null;
|
|
471
|
+
}
|
|
472
|
+
function isEmptyDiffIdleFailure(result) {
|
|
473
|
+
if (result.success) {
|
|
474
|
+
return result.iterationFingerprint === "";
|
|
475
|
+
}
|
|
476
|
+
return result.iterationFingerprint === "" && EMPTY_DIFF_FAILURE_PATTERN.test(result.error?.message ?? "");
|
|
477
|
+
}
|
|
478
|
+
function shouldIdleStopAfterRealFirstDelivery(priorIterations, current, enabled) {
|
|
479
|
+
return resolveIdleStopAfterRealFirstDelivery(priorIterations, current, enabled).shouldStop;
|
|
480
|
+
}
|
|
481
|
+
function resolveIdleStopAfterRealFirstDelivery(priorIterations, current, enabled, options = {}) {
|
|
482
|
+
if (options.iterationChangeEvidenceTrusted === false || !isEmptyDiffIdleFailure(current)) {
|
|
483
|
+
return { shouldStop: false };
|
|
484
|
+
}
|
|
485
|
+
const priorIterationIndex = priorIterations.length - 1;
|
|
486
|
+
if (priorIterationIndex < 0) {
|
|
487
|
+
return { shouldStop: false };
|
|
488
|
+
}
|
|
489
|
+
const priorIteration = priorIterations[priorIterationIndex];
|
|
490
|
+
if (!isRealFirstDeliveryIteration(priorIteration, enabled)) {
|
|
491
|
+
return { shouldStop: false };
|
|
492
|
+
}
|
|
493
|
+
const verification = resolveMatureDeliveryVerification(priorIteration, enabled);
|
|
494
|
+
if (verification === null) {
|
|
495
|
+
return { shouldStop: false };
|
|
496
|
+
}
|
|
497
|
+
const disposition = verification === "unverified" ? resolveUnavailableOnlyDelivery(priorIteration, enabled) ?? void 0 : void 0;
|
|
498
|
+
return {
|
|
499
|
+
shouldStop: true,
|
|
500
|
+
priorIterationIndex,
|
|
501
|
+
verification,
|
|
502
|
+
...disposition ? { disposition } : {}
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// src/orchestrator/progress-untracked-diff.ts
|
|
507
|
+
var MAX_UNTRACKED_DIFF_BYTES = 10 * 1024 * 1024;
|
|
508
|
+
var MAX_UNTRACKED_FILE_BYTES = 1024 * 1024;
|
|
509
|
+
async function buildUntrackedFilesDiff(workingDir) {
|
|
510
|
+
let listed;
|
|
511
|
+
try {
|
|
512
|
+
listed = await execGit(["ls-files", "--others", "--exclude-standard", "-z"], {
|
|
513
|
+
cwd: workingDir
|
|
514
|
+
});
|
|
515
|
+
} catch {
|
|
516
|
+
return "";
|
|
517
|
+
}
|
|
518
|
+
if (listed.exitCode !== 0) return "";
|
|
519
|
+
const parts = [];
|
|
520
|
+
let totalBytes = 0;
|
|
521
|
+
for (const relPath of listed.stdout.split("\0").filter(Boolean)) {
|
|
522
|
+
let lines = [`diff --git a/${relPath} b/${relPath}`, "new file mode 100644"];
|
|
523
|
+
try {
|
|
524
|
+
const entry = await readUntrackedFileDiffEntry(workingDir, relPath, MAX_UNTRACKED_FILE_BYTES);
|
|
525
|
+
if (entry) lines = renderUntrackedFileDiff(`a/${relPath}`, `b/${relPath}`, entry);
|
|
526
|
+
} catch {
|
|
527
|
+
}
|
|
528
|
+
const text = lines.join("\n");
|
|
529
|
+
totalBytes += text.length;
|
|
530
|
+
if (totalBytes > MAX_UNTRACKED_DIFF_BYTES) break;
|
|
531
|
+
parts.push(text);
|
|
532
|
+
}
|
|
533
|
+
return parts.join("\n");
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// src/orchestrator/progress-validator.ts
|
|
537
|
+
function isProgressRuntimePath(filePath) {
|
|
538
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
539
|
+
return normalized === ".build-project" || normalized.startsWith(".build-project/");
|
|
540
|
+
}
|
|
541
|
+
function getExecOutput(error) {
|
|
542
|
+
if (!error || typeof error !== "object") return null;
|
|
543
|
+
const stdout = "stdout" in error ? error.stdout : void 0;
|
|
544
|
+
const stderr = "stderr" in error ? error.stderr : void 0;
|
|
545
|
+
const stdoutText = typeof stdout === "string" ? stdout : Buffer.isBuffer(stdout) ? stdout.toString("utf-8") : "";
|
|
546
|
+
const stderrText = typeof stderr === "string" ? stderr : Buffer.isBuffer(stderr) ? stderr.toString("utf-8") : "";
|
|
547
|
+
const combined = `${stdoutText}
|
|
548
|
+
${stderrText}`.trim();
|
|
549
|
+
return combined.length > 0 ? combined : null;
|
|
550
|
+
}
|
|
551
|
+
function countVerificationErrorsFromOutput(command, output, kind) {
|
|
552
|
+
const derived = deriveVerificationFailureCount(command, output, kind);
|
|
553
|
+
if (derived.status === "counted") return { count: derived.count, unavailable: false };
|
|
554
|
+
if (derived.status === "unavailable") return { count: null, unavailable: true };
|
|
555
|
+
return { count: countErrorsFromOutputHeuristics(output), unavailable: false };
|
|
556
|
+
}
|
|
557
|
+
function countErrorsFromOutputHeuristics(output) {
|
|
558
|
+
const normalized = output.trim();
|
|
559
|
+
if (normalized.length === 0) return null;
|
|
560
|
+
const tsErrorMatches = output.match(/error TS\d+:/g);
|
|
561
|
+
if (tsErrorMatches && tsErrorMatches.length > 0) {
|
|
562
|
+
return tsErrorMatches.length;
|
|
563
|
+
}
|
|
564
|
+
const errorMatches = Array.from(output.matchAll(/(?:Found\s+)?(\d+)\s+errors?/gi));
|
|
565
|
+
const lastErrorMatch = errorMatches[errorMatches.length - 1];
|
|
566
|
+
if (lastErrorMatch?.[1]) {
|
|
567
|
+
const parsed = Number.parseInt(lastErrorMatch[1], 10);
|
|
568
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
569
|
+
}
|
|
570
|
+
if (/^\s*FAIL\b/m.test(output) || /\b[1-9]\d*\s+Error\(s\)/i.test(output) || hasBuildFailureBanner(output) || hasCompileDiagnosticOutput(output)) {
|
|
571
|
+
return 1;
|
|
572
|
+
}
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
function detectProjectLanguageSummary(workingDir) {
|
|
576
|
+
try {
|
|
577
|
+
return detectProjectCapabilities(workingDir).languages.join(", ") || "unknown";
|
|
578
|
+
} catch (error) {
|
|
579
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
580
|
+
return `unknown (capability detection failed: ${message})`;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
function selectProjectProgressVerificationCommands(workingDir) {
|
|
584
|
+
const capabilities = detectProjectCapabilities(workingDir);
|
|
585
|
+
if (capabilities.verification.typecheck.length > 0) {
|
|
586
|
+
return { commands: [...new Set(capabilities.verification.typecheck)], kind: "typecheck" };
|
|
587
|
+
}
|
|
588
|
+
if (capabilities.verification.build.length > 0) {
|
|
589
|
+
return { commands: [...new Set(capabilities.verification.build)], kind: "build" };
|
|
590
|
+
}
|
|
591
|
+
return { commands: [...new Set(capabilities.verification.test)], kind: "test" };
|
|
592
|
+
}
|
|
593
|
+
async function countTypeScriptErrors(workingDir) {
|
|
594
|
+
const { commands, kind } = selectProjectProgressVerificationCommands(workingDir);
|
|
595
|
+
if (commands.length === 0) return null;
|
|
596
|
+
let total = 0;
|
|
597
|
+
let counted = false;
|
|
598
|
+
let unattributable = false;
|
|
599
|
+
for (const command of commands) {
|
|
600
|
+
const count = await countErrorsForCommand(workingDir, command, kind);
|
|
601
|
+
if (count === UNATTRIBUTABLE_COUNT) {
|
|
602
|
+
unattributable = true;
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
605
|
+
if (count === null) continue;
|
|
606
|
+
counted = true;
|
|
607
|
+
total += count;
|
|
608
|
+
}
|
|
609
|
+
if (unattributable) return null;
|
|
610
|
+
if (total > 0) return total;
|
|
611
|
+
return counted ? 0 : null;
|
|
612
|
+
}
|
|
613
|
+
async function countErrorsForCommand(workingDir, command, kind) {
|
|
614
|
+
try {
|
|
615
|
+
const envTimeout = Number.parseInt(process.env.BUILD_TSC_TIMEOUT_MS ?? "", 10);
|
|
616
|
+
const timeoutMs = Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : 15e3;
|
|
617
|
+
const result = await runVerificationCommand(command, {
|
|
618
|
+
cwd: workingDir,
|
|
619
|
+
timeoutMs
|
|
620
|
+
});
|
|
621
|
+
const output = String(result.all ?? `${result.stdout ?? ""}
|
|
622
|
+
${result.stderr ?? ""}`).trim();
|
|
623
|
+
const exitCode = result.exitCode;
|
|
624
|
+
if (exitCode == null || exitCode === 126) return null;
|
|
625
|
+
if (exitCode !== 0) {
|
|
626
|
+
if (classifyResolverCommand(command, result, 0).classification === "unavailable") {
|
|
627
|
+
return UNATTRIBUTABLE_COUNT;
|
|
628
|
+
}
|
|
629
|
+
const parsed = countVerificationErrorsFromOutput(command, output, kind);
|
|
630
|
+
if (parsed.unavailable) return UNATTRIBUTABLE_COUNT;
|
|
631
|
+
if (detectExitZeroVerifyFailure(command, output)) {
|
|
632
|
+
return Math.max(parsed.count ?? 0, 1);
|
|
633
|
+
}
|
|
634
|
+
return parsed.count === 0 ? 1 : parsed.count ?? 1;
|
|
635
|
+
}
|
|
636
|
+
const exitZeroFailure = detectExitZeroVerifyFailure(command, output);
|
|
637
|
+
if (exitZeroFailure) return 1;
|
|
638
|
+
return countVerificationErrorsFromOutput(command, output, kind).count ?? 0;
|
|
639
|
+
} catch (error) {
|
|
640
|
+
const output = getExecOutput(error);
|
|
641
|
+
if (!output) return null;
|
|
642
|
+
const parsed = countVerificationErrorsFromOutput(command, output, kind);
|
|
643
|
+
if (parsed.unavailable) return UNATTRIBUTABLE_COUNT;
|
|
644
|
+
if (detectExitZeroVerifyFailure(command, output)) {
|
|
645
|
+
return Math.max(parsed.count ?? 0, 1);
|
|
646
|
+
}
|
|
647
|
+
return parsed.count === 0 ? 1 : parsed.count;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
var ProgressValidator = class {
|
|
651
|
+
constructor(options = {}) {
|
|
652
|
+
this.options = options;
|
|
653
|
+
this.options = {
|
|
654
|
+
enableGitAnalysis: true,
|
|
655
|
+
enableTestDetection: true,
|
|
656
|
+
minProgressThreshold: 0.05,
|
|
657
|
+
trendThreshold: 0.01,
|
|
658
|
+
...options
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
options;
|
|
662
|
+
compilationBaselineErrors = null;
|
|
663
|
+
getPreviousScore(context) {
|
|
664
|
+
const previous = context.previousIterations[context.previousIterations.length - 1];
|
|
665
|
+
return previous?.progress.score ?? 0;
|
|
666
|
+
}
|
|
667
|
+
isProgressSignificant(context, score) {
|
|
668
|
+
const threshold = this.options.minProgressThreshold ?? 0.05;
|
|
669
|
+
if (context.previousIterations.length === 0) {
|
|
670
|
+
return score >= threshold;
|
|
671
|
+
}
|
|
672
|
+
const previousScore = this.getPreviousScore(context);
|
|
673
|
+
const delta = score - previousScore;
|
|
674
|
+
return delta >= threshold;
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Validate progress for an iteration
|
|
678
|
+
*/
|
|
679
|
+
async validateProgress(context) {
|
|
680
|
+
const startTime = Date.now();
|
|
681
|
+
try {
|
|
682
|
+
const compilationCheck = await this.checkCompilation(context);
|
|
683
|
+
const hadToolingFailure = compilationCheck.toolingFailure === true;
|
|
684
|
+
const verificationUnavailable = compilationCheck.status === "unavailable";
|
|
685
|
+
if (verificationUnavailable) {
|
|
686
|
+
debugLog(
|
|
687
|
+
`[ProgressValidator] Compilation verification unavailable: ${compilationCheck.reason}`
|
|
688
|
+
);
|
|
689
|
+
} else if (!compilationCheck.passed) {
|
|
690
|
+
debugLog(
|
|
691
|
+
`[ProgressValidator] Compilation check failed: ${compilationCheck.newErrors} new errors`
|
|
692
|
+
);
|
|
693
|
+
emitWarning(
|
|
694
|
+
"VAL-002",
|
|
695
|
+
{
|
|
696
|
+
taskId: context.workingDir,
|
|
697
|
+
subsystem: "progress-validator",
|
|
698
|
+
executionPhase: "validation"
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
severity: "ERROR" /* ERROR */,
|
|
702
|
+
metadata: {
|
|
703
|
+
newErrors: compilationCheck.newErrors,
|
|
704
|
+
totalErrors: compilationCheck.totalErrors,
|
|
705
|
+
iteration: context.iteration
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
);
|
|
709
|
+
return {
|
|
710
|
+
score: 0,
|
|
711
|
+
isSignificant: false,
|
|
712
|
+
trend: "declining",
|
|
713
|
+
confidence: 1,
|
|
714
|
+
// High confidence - compilation failure is definitive
|
|
715
|
+
metrics: {
|
|
716
|
+
testCoverage: 0,
|
|
717
|
+
completeness: 0
|
|
718
|
+
},
|
|
719
|
+
insights: [
|
|
720
|
+
`Iteration ${context.iteration}: Compilation failed with ${compilationCheck.newErrors} new errors`,
|
|
721
|
+
"Fix compilation errors before proceeding",
|
|
722
|
+
`Total errors: ${compilationCheck.totalErrors}`
|
|
723
|
+
],
|
|
724
|
+
compilationErrors: compilationCheck.errorCount
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
const gitStats = this.options.enableGitAnalysis ? await this.analyzeGitChanges(context.workingDir, context.baseRef) : this.getEmptyGitStats();
|
|
728
|
+
const metrics = this.calculateMetrics(gitStats, context);
|
|
729
|
+
const score = this.calculateProgressScore(metrics, gitStats);
|
|
730
|
+
const isSignificant = this.isProgressSignificant(context, score);
|
|
731
|
+
const trend = this.calculateTrend(context.previousIterations, score);
|
|
732
|
+
const confidence = this.calculateConfidence(gitStats, context);
|
|
733
|
+
const insights = this.generateInsights(context.iteration, score, metrics, gitStats, trend);
|
|
734
|
+
if (verificationUnavailable) {
|
|
735
|
+
insights.push(
|
|
736
|
+
`WARNING: Validation unavailable \u2014 ${compilationCheck.reason ?? "no deterministic compilation check could run"}`
|
|
737
|
+
);
|
|
738
|
+
} else if (hadToolingFailure) {
|
|
739
|
+
insights.push("WARNING: Validation tooling failed \u2014 reported progress may be illusory");
|
|
740
|
+
}
|
|
741
|
+
const validationDuration = Date.now() - startTime;
|
|
742
|
+
debugLog(
|
|
743
|
+
`[ProgressValidator] Iteration ${context.iteration} validated in ${validationDuration}ms`
|
|
744
|
+
);
|
|
745
|
+
return {
|
|
746
|
+
score,
|
|
747
|
+
isSignificant,
|
|
748
|
+
trend,
|
|
749
|
+
// Reduce confidence when tooling failed to reflect lower certainty
|
|
750
|
+
confidence: verificationUnavailable || hadToolingFailure ? Math.min(confidence, 0.4) : confidence,
|
|
751
|
+
metrics,
|
|
752
|
+
insights,
|
|
753
|
+
...compilationCheck.errorCount !== void 0 ? { compilationErrors: compilationCheck.errorCount } : {},
|
|
754
|
+
...hadToolingFailure ? { toolingFailure: true } : {},
|
|
755
|
+
...verificationUnavailable ? {
|
|
756
|
+
verificationUnavailable: true,
|
|
757
|
+
verificationUnavailableReason: compilationCheck.reason ?? "No deterministic compilation check could run."
|
|
758
|
+
} : {}
|
|
759
|
+
};
|
|
760
|
+
} catch (error) {
|
|
761
|
+
emitWarning(
|
|
762
|
+
"VAL-001",
|
|
763
|
+
{
|
|
764
|
+
taskId: context.workingDir,
|
|
765
|
+
subsystem: "progress-validator",
|
|
766
|
+
executionPhase: "validation"
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
severity: "WARN" /* WARN */,
|
|
770
|
+
metadata: {
|
|
771
|
+
error: error instanceof Error ? error.message : String(error),
|
|
772
|
+
iteration: context.iteration,
|
|
773
|
+
operation: "validateProgress"
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
);
|
|
777
|
+
return this.createFallbackValidation(context);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
// ========================================================================
|
|
781
|
+
// COMPILATION CHECK
|
|
782
|
+
// ========================================================================
|
|
783
|
+
/**
|
|
784
|
+
* Check project compilation/typecheck status and compare against baseline.
|
|
785
|
+
*
|
|
786
|
+
* Runs a detected typecheck/build command without inventing target-project tooling.
|
|
787
|
+
* If no compile-specific command exists, falls back to resolver-backed test
|
|
788
|
+
* commands as deterministic verification evidence.
|
|
789
|
+
* Compares the current error count against a baseline to detect if new errors were introduced.
|
|
790
|
+
*
|
|
791
|
+
* Baseline precedence:
|
|
792
|
+
* 1) `context.compilationBaselineErrors` (captured pre-iteration by controller, preferred)
|
|
793
|
+
* 2) Internal baseline captured on first use (fallback)
|
|
794
|
+
*
|
|
795
|
+
* @param context - Progress validation context for this iteration
|
|
796
|
+
* @returns Compilation check result with pass/fail status and error counts
|
|
797
|
+
*/
|
|
798
|
+
async checkCompilation(context) {
|
|
799
|
+
try {
|
|
800
|
+
const compilationCommands = selectProjectProgressVerificationCommands(
|
|
801
|
+
context.workingDir
|
|
802
|
+
).commands;
|
|
803
|
+
if (compilationCommands.length === 0) {
|
|
804
|
+
const reason = `No deterministic typecheck/build/test command found; compilation verification is unavailable for detected languages: ${detectProjectLanguageSummary(context.workingDir)}.`;
|
|
805
|
+
debugLog(`[ProgressValidator] ${reason}`);
|
|
806
|
+
return {
|
|
807
|
+
passed: false,
|
|
808
|
+
newErrors: 0,
|
|
809
|
+
totalErrors: 0,
|
|
810
|
+
toolingFailure: true,
|
|
811
|
+
status: "unavailable",
|
|
812
|
+
reason,
|
|
813
|
+
errorCount: null
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
const totalErrors = await countTypeScriptErrors(context.workingDir);
|
|
817
|
+
if (totalErrors === null) {
|
|
818
|
+
debugLog(
|
|
819
|
+
`[ProgressValidator] Unable to run ${compilationCommands.join(", ")}, marking validation tooling failure`
|
|
820
|
+
);
|
|
821
|
+
return {
|
|
822
|
+
passed: false,
|
|
823
|
+
newErrors: 0,
|
|
824
|
+
totalErrors: 0,
|
|
825
|
+
toolingFailure: true,
|
|
826
|
+
status: "unavailable",
|
|
827
|
+
errorCount: null,
|
|
828
|
+
reason: `Project compilation command was unavailable or produced output no registered parser could attribute: ${compilationCommands.join(", ")} (detected languages: ${detectProjectLanguageSummary(context.workingDir)})`
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
const capturedBaseline = context.compilationBaselineErrors ?? this.compilationBaselineErrors;
|
|
832
|
+
if (context.compilationBaselineErrors === null && capturedBaseline === null && totalErrors > 0) {
|
|
833
|
+
return {
|
|
834
|
+
passed: false,
|
|
835
|
+
newErrors: 0,
|
|
836
|
+
totalErrors,
|
|
837
|
+
errorCount: totalErrors,
|
|
838
|
+
toolingFailure: true,
|
|
839
|
+
status: "unavailable",
|
|
840
|
+
reason: "Pre-iteration compilation baseline is unavailable; new errors cannot be attributed."
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
const baselineErrors = capturedBaseline ?? totalErrors;
|
|
844
|
+
this.compilationBaselineErrors ??= baselineErrors;
|
|
845
|
+
const newErrors = Math.max(0, totalErrors - baselineErrors);
|
|
846
|
+
const passed = newErrors === 0;
|
|
847
|
+
if (!passed) {
|
|
848
|
+
debugLog(
|
|
849
|
+
`[ProgressValidator] Compilation check failed: ${newErrors} new errors (${totalErrors} total)`
|
|
850
|
+
);
|
|
851
|
+
} else {
|
|
852
|
+
debugLog("[ProgressValidator] Compilation check passed");
|
|
853
|
+
}
|
|
854
|
+
return {
|
|
855
|
+
passed,
|
|
856
|
+
newErrors,
|
|
857
|
+
totalErrors,
|
|
858
|
+
errorCount: totalErrors,
|
|
859
|
+
status: passed ? "verified" : "failed"
|
|
860
|
+
};
|
|
861
|
+
} catch (error) {
|
|
862
|
+
console.warn(
|
|
863
|
+
`Error running compilation check: ${error instanceof Error ? error.message : String(error)}`
|
|
864
|
+
);
|
|
865
|
+
debugLog("Full stack:", error);
|
|
866
|
+
emitWarning(
|
|
867
|
+
"VAL-002",
|
|
868
|
+
{
|
|
869
|
+
taskId: context.workingDir,
|
|
870
|
+
subsystem: "progress-validator",
|
|
871
|
+
executionPhase: "validation"
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
severity: "WARN" /* WARN */,
|
|
875
|
+
metadata: {
|
|
876
|
+
error: error instanceof Error ? error.message : String(error),
|
|
877
|
+
operation: "checkCompilation"
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
);
|
|
881
|
+
return {
|
|
882
|
+
passed: false,
|
|
883
|
+
newErrors: 0,
|
|
884
|
+
totalErrors: 0,
|
|
885
|
+
toolingFailure: true,
|
|
886
|
+
status: "unavailable",
|
|
887
|
+
reason: "Compilation validation tooling failed before producing a result."
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
// ========================================================================
|
|
892
|
+
// GIT ANALYSIS
|
|
893
|
+
// ========================================================================
|
|
894
|
+
/**
|
|
895
|
+
* Calculate meaningful code delta excluding comments and whitespace.
|
|
896
|
+
* Used to detect "comment-only" changes that shouldn't count as progress.
|
|
897
|
+
*
|
|
898
|
+
* @param gitDiff - Full git diff output
|
|
899
|
+
* @returns Additions and deletions excluding comments/whitespace
|
|
900
|
+
*/
|
|
901
|
+
calculateMeaningfulDelta(gitDiff) {
|
|
902
|
+
const lines = gitDiff.split("\n");
|
|
903
|
+
let additions = 0;
|
|
904
|
+
let deletions = 0;
|
|
905
|
+
for (const line of lines) {
|
|
906
|
+
if (line.startsWith("@@") || line.startsWith("diff") || line.startsWith("index") || line.startsWith("---") || line.startsWith("+++")) {
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
909
|
+
if (!line.startsWith("+") && !line.startsWith("-")) {
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
const content = line.slice(1).trim();
|
|
913
|
+
if (!content) continue;
|
|
914
|
+
const isDefinitelyComment = content.startsWith("//") || // C-family single-line comment
|
|
915
|
+
content.startsWith("/*") || // C-family multi-line start
|
|
916
|
+
content.startsWith("*/") || // C-family multi-line end
|
|
917
|
+
content.startsWith("*") && content.match(/^\*\s+[^*/]/);
|
|
918
|
+
if (isDefinitelyComment) {
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
if (line.match(/^[+-]\s*$/)) continue;
|
|
922
|
+
if (line.startsWith("+")) additions++;
|
|
923
|
+
if (line.startsWith("-")) deletions++;
|
|
924
|
+
}
|
|
925
|
+
return { additions, deletions };
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Analyze git changes since base ref
|
|
929
|
+
*/
|
|
930
|
+
async analyzeGitChanges(workingDir, baseRef = "HEAD") {
|
|
931
|
+
try {
|
|
932
|
+
if (!this.isGitRepository(workingDir)) {
|
|
933
|
+
return this.getEmptyGitStats();
|
|
934
|
+
}
|
|
935
|
+
const safeBaseRef = baseRef.trim();
|
|
936
|
+
if (!isSafeGitRef(safeBaseRef)) {
|
|
937
|
+
return this.getEmptyGitStats();
|
|
938
|
+
}
|
|
939
|
+
const trackedDiff = execWithTimeout(`git diff ${safeBaseRef} 2>/dev/null || echo ""`, {
|
|
940
|
+
cwd: workingDir,
|
|
941
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
942
|
+
timeout: 3e4,
|
|
943
|
+
returnEmptyOnError: true
|
|
944
|
+
}).trim();
|
|
945
|
+
const fullDiff = [trackedDiff, await buildUntrackedFilesDiff(workingDir)].filter(Boolean).join("\n");
|
|
946
|
+
if (!fullDiff) {
|
|
947
|
+
return this.getEmptyGitStats();
|
|
948
|
+
}
|
|
949
|
+
const modifiedFileSet = /* @__PURE__ */ new Set();
|
|
950
|
+
let insertions = 0;
|
|
951
|
+
let deletions = 0;
|
|
952
|
+
let includeCurrentFile = false;
|
|
953
|
+
const includedDiffLines = [];
|
|
954
|
+
for (const line of fullDiff.split("\n")) {
|
|
955
|
+
const paths = parseDiffGitHeaderPaths(line);
|
|
956
|
+
if (paths) {
|
|
957
|
+
const filePath = paths.bPath;
|
|
958
|
+
includeCurrentFile = !isProgressRuntimePath(filePath);
|
|
959
|
+
if (includeCurrentFile) {
|
|
960
|
+
modifiedFileSet.add(filePath);
|
|
961
|
+
includedDiffLines.push(line);
|
|
962
|
+
}
|
|
963
|
+
continue;
|
|
964
|
+
}
|
|
965
|
+
if (!includeCurrentFile) {
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
includedDiffLines.push(line);
|
|
969
|
+
if (line.startsWith("+++") || line.startsWith("---") || line.startsWith("@@") || line.startsWith("diff --git") || line.startsWith("index ")) {
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
if (line.startsWith("+")) insertions++;
|
|
973
|
+
if (line.startsWith("-")) deletions++;
|
|
974
|
+
}
|
|
975
|
+
const modifiedFiles = Array.from(modifiedFileSet).sort((a, b) => a.localeCompare(b));
|
|
976
|
+
const hasTests = modifiedFiles.some(
|
|
977
|
+
(f) => f.includes("test") || f.includes("spec") || f.endsWith(".test.ts") || f.endsWith(".spec.ts")
|
|
978
|
+
);
|
|
979
|
+
const hasDocs = modifiedFiles.some(
|
|
980
|
+
(f) => f.endsWith(".md") || f.includes("doc") || f.includes("README")
|
|
981
|
+
);
|
|
982
|
+
const meaningfulDelta = this.calculateMeaningfulDelta(includedDiffLines.join("\n"));
|
|
983
|
+
return {
|
|
984
|
+
filesChanged: modifiedFiles.length,
|
|
985
|
+
insertions,
|
|
986
|
+
deletions,
|
|
987
|
+
totalLines: insertions + deletions,
|
|
988
|
+
modifiedFiles,
|
|
989
|
+
hasTests,
|
|
990
|
+
hasDocs,
|
|
991
|
+
meaningfulInsertions: meaningfulDelta.additions,
|
|
992
|
+
meaningfulDeletions: meaningfulDelta.deletions
|
|
993
|
+
};
|
|
994
|
+
} catch (error) {
|
|
995
|
+
console.warn(
|
|
996
|
+
`Error analyzing git changes: ${error instanceof Error ? error.message : String(error)}`
|
|
997
|
+
);
|
|
998
|
+
debugLog("Full stack:", error);
|
|
999
|
+
emitWarning(
|
|
1000
|
+
"VAL-001",
|
|
1001
|
+
{
|
|
1002
|
+
taskId: workingDir,
|
|
1003
|
+
subsystem: "progress-validator",
|
|
1004
|
+
executionPhase: "validation"
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
severity: "WARN" /* WARN */,
|
|
1008
|
+
metadata: {
|
|
1009
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1010
|
+
operation: "analyzeGitChanges"
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
);
|
|
1014
|
+
return this.getEmptyGitStats();
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Check if directory is a git repository
|
|
1019
|
+
*/
|
|
1020
|
+
isGitRepository(dir) {
|
|
1021
|
+
try {
|
|
1022
|
+
execWithTimeout("git rev-parse --git-dir", {
|
|
1023
|
+
cwd: dir,
|
|
1024
|
+
stdio: "pipe",
|
|
1025
|
+
timeout: 3e4
|
|
1026
|
+
});
|
|
1027
|
+
return true;
|
|
1028
|
+
} catch {
|
|
1029
|
+
return false;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
// ========================================================================
|
|
1033
|
+
// METRICS CALCULATION
|
|
1034
|
+
// ========================================================================
|
|
1035
|
+
/**
|
|
1036
|
+
* Calculate all progress metrics from git stats.
|
|
1037
|
+
*
|
|
1038
|
+
* completeness and testCoverage are derived from the diff. They feed telemetry
|
|
1039
|
+
* and the diff-size floor that applies only when no verification gate produced
|
|
1040
|
+
* evidence; passing gates, not this score, decide completion.
|
|
1041
|
+
*/
|
|
1042
|
+
calculateMetrics(gitStats, context) {
|
|
1043
|
+
const hasMeaningfulChanges = gitStats.meaningfulInsertions + gitStats.meaningfulDeletions > 0;
|
|
1044
|
+
const hasAnyChanges = gitStats.insertions + gitStats.deletions > 0;
|
|
1045
|
+
const isCommentOnlyChange = hasAnyChanges && !hasMeaningfulChanges;
|
|
1046
|
+
if (isCommentOnlyChange) {
|
|
1047
|
+
debugLog("[ProgressValidator] Comment/whitespace-only changes detected, no progress credit");
|
|
1048
|
+
}
|
|
1049
|
+
const completeness = isCommentOnlyChange ? 0 : Math.min(
|
|
1050
|
+
1,
|
|
1051
|
+
(gitStats.meaningfulInsertions + gitStats.meaningfulDeletions) / Math.max(100, 1)
|
|
1052
|
+
);
|
|
1053
|
+
const testCoverage = gitStats.hasTests ? Math.min(1, 0.5 + gitStats.filesChanged * 0.1) : context.previousIterations.length > 0 ? context.previousIterations[context.previousIterations.length - 1]?.progress.metrics.testCoverage ?? 0.3 : 0.3;
|
|
1054
|
+
return {
|
|
1055
|
+
completeness: Math.max(0, Math.min(1, completeness)),
|
|
1056
|
+
testCoverage: Math.max(0, Math.min(1, testCoverage))
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
/**
|
|
1060
|
+
* Calculate overall progress score.
|
|
1061
|
+
*
|
|
1062
|
+
* Weights: completeness 70%, testCoverage 30%.
|
|
1063
|
+
* Bonuses: +0.05 for test file changes, +0.02 for doc changes.
|
|
1064
|
+
*/
|
|
1065
|
+
calculateProgressScore(metrics, gitStats) {
|
|
1066
|
+
const hasMeaningfulChanges = gitStats.meaningfulInsertions + gitStats.meaningfulDeletions > 0;
|
|
1067
|
+
if (!hasMeaningfulChanges) {
|
|
1068
|
+
return 0;
|
|
1069
|
+
}
|
|
1070
|
+
const weights = {
|
|
1071
|
+
completeness: 0.7,
|
|
1072
|
+
testCoverage: 0.3
|
|
1073
|
+
};
|
|
1074
|
+
let score = metrics.completeness * weights.completeness + metrics.testCoverage * weights.testCoverage;
|
|
1075
|
+
if (gitStats.hasTests) score += 0.05;
|
|
1076
|
+
if (gitStats.hasDocs) score += 0.02;
|
|
1077
|
+
return Math.max(0, Math.min(1, score));
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Calculate trend from previous iterations
|
|
1081
|
+
*/
|
|
1082
|
+
calculateTrend(previousIterations, currentScore) {
|
|
1083
|
+
if (previousIterations.length === 0) {
|
|
1084
|
+
return "unknown";
|
|
1085
|
+
}
|
|
1086
|
+
if (previousIterations.length === 1) {
|
|
1087
|
+
const prev = previousIterations[0]?.progress.score ?? 0;
|
|
1088
|
+
const diff = currentScore - prev;
|
|
1089
|
+
const threshold2 = this.options.trendThreshold ?? 0.01;
|
|
1090
|
+
if (diff > threshold2) return "improving";
|
|
1091
|
+
if (diff < -threshold2) return "declining";
|
|
1092
|
+
return "stable";
|
|
1093
|
+
}
|
|
1094
|
+
const recentCount = Math.min(3, previousIterations.length);
|
|
1095
|
+
const recent = previousIterations.slice(-recentCount);
|
|
1096
|
+
const scores = [...recent.map((r) => r.progress.score), currentScore];
|
|
1097
|
+
let sumX = 0;
|
|
1098
|
+
let sumY = 0;
|
|
1099
|
+
let sumXY = 0;
|
|
1100
|
+
let sumXX = 0;
|
|
1101
|
+
const n = scores.length;
|
|
1102
|
+
for (let i = 0; i < n; i++) {
|
|
1103
|
+
sumX += i;
|
|
1104
|
+
sumY += scores[i] ?? 0;
|
|
1105
|
+
sumXY += i * (scores[i] ?? 0);
|
|
1106
|
+
sumXX += i * i;
|
|
1107
|
+
}
|
|
1108
|
+
const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
|
|
1109
|
+
const threshold = this.options.trendThreshold ?? 0.01;
|
|
1110
|
+
if (slope > threshold) return "improving";
|
|
1111
|
+
if (slope < -threshold) return "declining";
|
|
1112
|
+
return "stable";
|
|
1113
|
+
}
|
|
1114
|
+
/**
|
|
1115
|
+
* Calculate confidence in assessment
|
|
1116
|
+
*/
|
|
1117
|
+
calculateConfidence(gitStats, context) {
|
|
1118
|
+
let confidence = 0.5;
|
|
1119
|
+
if (gitStats.filesChanged > 0) {
|
|
1120
|
+
confidence += Math.min(0.2, gitStats.filesChanged * 0.05);
|
|
1121
|
+
}
|
|
1122
|
+
if (context.previousIterations.length >= 2) {
|
|
1123
|
+
confidence += 0.3;
|
|
1124
|
+
}
|
|
1125
|
+
return Math.max(0, Math.min(1, confidence));
|
|
1126
|
+
}
|
|
1127
|
+
// ========================================================================
|
|
1128
|
+
// INSIGHTS GENERATION
|
|
1129
|
+
// ========================================================================
|
|
1130
|
+
/**
|
|
1131
|
+
* Generate human-readable insights
|
|
1132
|
+
*/
|
|
1133
|
+
generateInsights(iteration, score, metrics, gitStats, trend) {
|
|
1134
|
+
const insights = [];
|
|
1135
|
+
insights.push(
|
|
1136
|
+
`Iteration ${iteration}: ${(score * 100).toFixed(1)}% overall progress (${trend})`
|
|
1137
|
+
);
|
|
1138
|
+
if (gitStats.filesChanged > 0) {
|
|
1139
|
+
insights.push(
|
|
1140
|
+
`Modified ${gitStats.filesChanged} file(s): +${gitStats.insertions} -${gitStats.deletions} lines`
|
|
1141
|
+
);
|
|
1142
|
+
const hasMeaningfulChanges = gitStats.meaningfulInsertions + gitStats.meaningfulDeletions > 0;
|
|
1143
|
+
if (!hasMeaningfulChanges) {
|
|
1144
|
+
insights.push("Only comment/whitespace changes detected - no meaningful code progress");
|
|
1145
|
+
}
|
|
1146
|
+
} else {
|
|
1147
|
+
insights.push("No file changes detected in this iteration");
|
|
1148
|
+
}
|
|
1149
|
+
if (gitStats.hasTests) {
|
|
1150
|
+
insights.push("Test files updated - good coverage practice");
|
|
1151
|
+
} else if (gitStats.filesChanged > 0) {
|
|
1152
|
+
insights.push("Recommendation: Add tests for code changes");
|
|
1153
|
+
}
|
|
1154
|
+
if (metrics.completeness >= 0.9) {
|
|
1155
|
+
insights.push("Task appears nearly complete");
|
|
1156
|
+
} else if (metrics.completeness >= 0.7) {
|
|
1157
|
+
insights.push("Good progress, some work remaining");
|
|
1158
|
+
} else if (metrics.completeness >= 0.5) {
|
|
1159
|
+
insights.push("Halfway through task completion");
|
|
1160
|
+
} else {
|
|
1161
|
+
insights.push("Significant work still needed");
|
|
1162
|
+
}
|
|
1163
|
+
if (trend === "improving") {
|
|
1164
|
+
insights.push("Progress trend: Improving - keep going!");
|
|
1165
|
+
} else if (trend === "declining") {
|
|
1166
|
+
insights.push("Progress trend: Declining - review approach");
|
|
1167
|
+
} else if (trend === "stable") {
|
|
1168
|
+
insights.push("Progress trend: Stable - consider new strategies");
|
|
1169
|
+
}
|
|
1170
|
+
return insights;
|
|
1171
|
+
}
|
|
1172
|
+
// ========================================================================
|
|
1173
|
+
// FALLBACK & HELPERS
|
|
1174
|
+
// ========================================================================
|
|
1175
|
+
/**
|
|
1176
|
+
* Create fallback validation when analysis fails.
|
|
1177
|
+
*
|
|
1178
|
+
* Returns score=0 with low confidence and an explicit warning rather than
|
|
1179
|
+
* fabricating a positive score from the iteration count. A non-zero score
|
|
1180
|
+
* derived purely from "how many iterations have elapsed" is illusory — it
|
|
1181
|
+
* says nothing about whether actual work was done.
|
|
1182
|
+
*/
|
|
1183
|
+
createFallbackValidation(context) {
|
|
1184
|
+
const score = 0;
|
|
1185
|
+
return {
|
|
1186
|
+
score,
|
|
1187
|
+
isSignificant: false,
|
|
1188
|
+
trend: "unknown",
|
|
1189
|
+
// Low confidence: we could not run any real analysis
|
|
1190
|
+
confidence: 0.1,
|
|
1191
|
+
metrics: {
|
|
1192
|
+
testCoverage: 0,
|
|
1193
|
+
completeness: 0
|
|
1194
|
+
},
|
|
1195
|
+
insights: [
|
|
1196
|
+
`Iteration ${context.iteration}: Using fallback validation`,
|
|
1197
|
+
"Unable to perform detailed analysis - reported progress may be illusory",
|
|
1198
|
+
"Proceeding with caution"
|
|
1199
|
+
],
|
|
1200
|
+
toolingFailure: true,
|
|
1201
|
+
verificationUnavailable: true,
|
|
1202
|
+
verificationUnavailableReason: "Progress validation failed before deterministic checks completed."
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Get empty git stats
|
|
1207
|
+
*/
|
|
1208
|
+
getEmptyGitStats() {
|
|
1209
|
+
return {
|
|
1210
|
+
filesChanged: 0,
|
|
1211
|
+
insertions: 0,
|
|
1212
|
+
deletions: 0,
|
|
1213
|
+
totalLines: 0,
|
|
1214
|
+
modifiedFiles: [],
|
|
1215
|
+
hasTests: false,
|
|
1216
|
+
hasDocs: false,
|
|
1217
|
+
meaningfulInsertions: 0,
|
|
1218
|
+
meaningfulDeletions: 0
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
function createCustomProgressValidator(options) {
|
|
1223
|
+
return new ProgressValidator(options);
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
// src/orchestrator/quality-failed-commands.ts
|
|
1227
|
+
function compareFailedCommands(allCurrent, allBaseline) {
|
|
1228
|
+
const current = allCurrent.filter((entry) => !entry.unavailable && !entry.passed);
|
|
1229
|
+
const baseline = allBaseline.filter((entry) => !entry.unavailable && !entry.passed);
|
|
1230
|
+
if ([...current, ...baseline].some((entry) => entry.timedOut)) return void 0;
|
|
1231
|
+
if (current.some((entry) => !baseline.some((b) => b.command === entry.command))) return true;
|
|
1232
|
+
if (current.length !== 1 || baseline.length !== 1) return void 0;
|
|
1233
|
+
return null;
|
|
1234
|
+
}
|
|
1235
|
+
function compareLintCommands(allCurrent, allBaseline, countOf) {
|
|
1236
|
+
const current = allCurrent.filter((entry) => !entry.passed);
|
|
1237
|
+
const baseline = allBaseline.filter((entry) => !entry.passed);
|
|
1238
|
+
if ([...current, ...baseline].some((entry) => entry.timedOut || entry.unavailable)) {
|
|
1239
|
+
return void 0;
|
|
1240
|
+
}
|
|
1241
|
+
if (current.some((entry) => !baseline.some((b) => b.command === entry.command))) return true;
|
|
1242
|
+
const provenPassing = (command) => allCurrent.some((entry) => entry.passed && entry.command === command);
|
|
1243
|
+
const absent = baseline.filter((b) => !current.some((entry) => entry.command === b.command));
|
|
1244
|
+
if (absent.some((b) => !provenPassing(b.command))) return void 0;
|
|
1245
|
+
if (current.length === 1 && baseline.length === 1) return null;
|
|
1246
|
+
const unique = (list) => new Set(list.map((entry) => entry.command)).size === list.length;
|
|
1247
|
+
if (!unique(current) || !unique(baseline)) return void 0;
|
|
1248
|
+
let unknown = false;
|
|
1249
|
+
for (const entry of current) {
|
|
1250
|
+
const counterpart = baseline.find((b) => b.command === entry.command);
|
|
1251
|
+
if (!counterpart) return void 0;
|
|
1252
|
+
const now = countOf(entry);
|
|
1253
|
+
const before = countOf(counterpart);
|
|
1254
|
+
const guessed = now.method === "fallback_1" || before.method === "fallback_1";
|
|
1255
|
+
if (now.count === null || before.count === null || guessed) {
|
|
1256
|
+
unknown = true;
|
|
1257
|
+
} else if (now.count > before.count) {
|
|
1258
|
+
return true;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
return unknown ? void 0 : false;
|
|
1262
|
+
}
|
|
1263
|
+
function compareAuditCommands(allCurrent, allBaseline, countOf) {
|
|
1264
|
+
const unproven = (counted) => counted.count === null || counted.method === "fallback_1" || counted.method === "unavailable_no_parser";
|
|
1265
|
+
let unknown = false;
|
|
1266
|
+
for (const entry of allCurrent.filter((candidate) => !candidate.passed)) {
|
|
1267
|
+
const now = entry.timedOut || entry.unavailable ? null : countOf(entry);
|
|
1268
|
+
if (now !== null && !unproven(now) && now.count === 0) continue;
|
|
1269
|
+
const counterpart = allBaseline.find((b) => b.command === entry.command);
|
|
1270
|
+
let before = 0;
|
|
1271
|
+
if (counterpart && !counterpart.passed) {
|
|
1272
|
+
const counted = counterpart.timedOut || counterpart.unavailable ? null : countOf(counterpart);
|
|
1273
|
+
before = counted && !unproven(counted) ? counted.count : null;
|
|
1274
|
+
}
|
|
1275
|
+
if (now === null || unproven(now) || before === null) {
|
|
1276
|
+
unknown = true;
|
|
1277
|
+
} else if (now.count !== null && now.count > before) {
|
|
1278
|
+
return true;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
return unknown ? void 0 : false;
|
|
1282
|
+
}
|
|
1283
|
+
function compareBucketCommands(gate, current, baseline, extract) {
|
|
1284
|
+
const countOf = (entry) => extract([{ gate, success: false, ...entry }], gate);
|
|
1285
|
+
if (gate === "lint") return compareLintCommands(current, baseline, countOf);
|
|
1286
|
+
if (gate === "security") return compareAuditCommands(current, baseline, countOf);
|
|
1287
|
+
return compareFailedCommands(current, baseline);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
// src/orchestrator/autonomous-loop-controller.ts
|
|
1291
|
+
var DEFAULT_AUTOLOOP_RESOURCE_LIMITS = {
|
|
1292
|
+
maxMemoryMB: 1048576
|
|
1293
|
+
};
|
|
1294
|
+
var MAX_AUTOLOOP_ENV_ITERATIONS = 100;
|
|
1295
|
+
var COMPLETION_SIGNAL_TAIL_BYTES = 8192;
|
|
1296
|
+
function parseCompletionSignal(spec) {
|
|
1297
|
+
if (spec.startsWith("xml:")) {
|
|
1298
|
+
const tag = spec.slice(4);
|
|
1299
|
+
if (tag.length === 0) return null;
|
|
1300
|
+
return { type: "xml", tag };
|
|
1301
|
+
}
|
|
1302
|
+
if (spec.startsWith("regex:")) {
|
|
1303
|
+
const rawPattern = spec.slice(6);
|
|
1304
|
+
if (rawPattern.length === 0) return null;
|
|
1305
|
+
const slashMatch = rawPattern.match(/^\/(.+)\/([gimsuy]*)$/);
|
|
1306
|
+
const patternSource = slashMatch ? slashMatch[1] : rawPattern;
|
|
1307
|
+
const patternFlags = slashMatch ? slashMatch[2] : "i";
|
|
1308
|
+
if (patternSource.length === 0) return null;
|
|
1309
|
+
try {
|
|
1310
|
+
return {
|
|
1311
|
+
type: "regex",
|
|
1312
|
+
pattern: new RegExp(patternSource, patternFlags)
|
|
1313
|
+
};
|
|
1314
|
+
} catch {
|
|
1315
|
+
return null;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
return null;
|
|
1319
|
+
}
|
|
1320
|
+
function matchesCompletionSignal(output, signal) {
|
|
1321
|
+
if (typeof output !== "string") {
|
|
1322
|
+
return false;
|
|
1323
|
+
}
|
|
1324
|
+
const tail = tailUtf8(output, COMPLETION_SIGNAL_TAIL_BYTES) ?? "";
|
|
1325
|
+
if (signal.type === "xml") {
|
|
1326
|
+
const escapedTag = signal.tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1327
|
+
const atLineStart = new RegExp(`(?:^|[\\r\\n])${escapedTag}(?:\\s|$)`, "i");
|
|
1328
|
+
const asFinalToken = new RegExp(`${escapedTag}\\s*$`, "i");
|
|
1329
|
+
return atLineStart.test(tail) || asFinalToken.test(tail.trimEnd());
|
|
1330
|
+
}
|
|
1331
|
+
const trimmedEnd = tail.trimEnd();
|
|
1332
|
+
const pattern = new RegExp(
|
|
1333
|
+
signal.pattern.source,
|
|
1334
|
+
signal.pattern.flags.includes("g") ? signal.pattern.flags : `${signal.pattern.flags}g`
|
|
1335
|
+
);
|
|
1336
|
+
let lastMatch = null;
|
|
1337
|
+
let match = pattern.exec(trimmedEnd);
|
|
1338
|
+
while (match !== null) {
|
|
1339
|
+
lastMatch = match;
|
|
1340
|
+
if (match[0].length === 0) {
|
|
1341
|
+
pattern.lastIndex += 1;
|
|
1342
|
+
}
|
|
1343
|
+
match = pattern.exec(trimmedEnd);
|
|
1344
|
+
}
|
|
1345
|
+
if (!lastMatch) {
|
|
1346
|
+
return false;
|
|
1347
|
+
}
|
|
1348
|
+
return lastMatch.index + lastMatch[0].length >= trimmedEnd.length;
|
|
1349
|
+
}
|
|
1350
|
+
function selectTaskOutputForChecks(taskResult) {
|
|
1351
|
+
if (typeof taskResult === "object" && taskResult !== null) {
|
|
1352
|
+
if ("completionOutputText" in taskResult && typeof taskResult.completionOutputText === "string") {
|
|
1353
|
+
return taskResult.completionOutputText;
|
|
1354
|
+
}
|
|
1355
|
+
if ("providerOutputText" in taskResult && typeof taskResult.providerOutputText === "string") {
|
|
1356
|
+
return taskResult.providerOutputText;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
return typeof taskResult === "string" ? taskResult : "";
|
|
1360
|
+
}
|
|
1361
|
+
function isRepairOutcome(value) {
|
|
1362
|
+
if (!value || typeof value !== "object") return false;
|
|
1363
|
+
const candidate = value;
|
|
1364
|
+
return typeof candidate.status === "string" && typeof candidate.attempts === "number" && typeof candidate.reason === "string";
|
|
1365
|
+
}
|
|
1366
|
+
function isCompletionEvidence(value) {
|
|
1367
|
+
if (!value || typeof value !== "object") return false;
|
|
1368
|
+
const candidate = value;
|
|
1369
|
+
return candidate.durable === true && (candidate.source === "simple-artifact" || candidate.source === "requirements" || candidate.source === "external") && (candidate.detail === void 0 || typeof candidate.detail === "string");
|
|
1370
|
+
}
|
|
1371
|
+
function isCustomGateResult(value) {
|
|
1372
|
+
if (!value || typeof value !== "object") return false;
|
|
1373
|
+
const candidate = value;
|
|
1374
|
+
if (typeof candidate.id !== "string" || typeof candidate.command !== "string" || typeof candidate.passed !== "boolean" || typeof candidate.durationMs !== "number" || !Number.isFinite(candidate.durationMs) || candidate.durationMs < 0) {
|
|
1375
|
+
return false;
|
|
1376
|
+
}
|
|
1377
|
+
if (candidate.exitCode !== void 0 && typeof candidate.exitCode !== "number") return false;
|
|
1378
|
+
if (candidate.outputTail !== void 0 && typeof candidate.outputTail !== "string") return false;
|
|
1379
|
+
if (candidate.isRegression !== void 0 && typeof candidate.isRegression !== "boolean") {
|
|
1380
|
+
return false;
|
|
1381
|
+
}
|
|
1382
|
+
if (candidate.skipped !== void 0 && typeof candidate.skipped !== "boolean") return false;
|
|
1383
|
+
if (candidate.unavailable !== void 0 && typeof candidate.unavailable !== "boolean") {
|
|
1384
|
+
return false;
|
|
1385
|
+
}
|
|
1386
|
+
if (candidate.misconfigured !== void 0 && typeof candidate.misconfigured !== "boolean") {
|
|
1387
|
+
return false;
|
|
1388
|
+
}
|
|
1389
|
+
return true;
|
|
1390
|
+
}
|
|
1391
|
+
function isCustomGateResultsArray(value) {
|
|
1392
|
+
return Array.isArray(value) && value.every(isCustomGateResult);
|
|
1393
|
+
}
|
|
1394
|
+
function buildCustomGateId(command) {
|
|
1395
|
+
const prefix = command.replace(/\s+/g, "-").slice(0, 40);
|
|
1396
|
+
const hash = createHash("sha256").update(command).digest("hex").slice(0, 8);
|
|
1397
|
+
return `${prefix}-${hash}`;
|
|
1398
|
+
}
|
|
1399
|
+
function filterSemanticValidationDiff(gitDiff, taskText) {
|
|
1400
|
+
if (!gitDiff.trim()) {
|
|
1401
|
+
return gitDiff;
|
|
1402
|
+
}
|
|
1403
|
+
const normalizedTaskText = taskText.replace(/\\/g, "/");
|
|
1404
|
+
const sections = gitDiff.split(/^diff --git /m).map((section, index) => index === 0 ? section : `diff --git ${section}`).filter((section) => section.trim().length > 0);
|
|
1405
|
+
return sections.filter((section) => {
|
|
1406
|
+
const match = section.match(/^diff --git a\/(.+?) b\/(.+)$/m);
|
|
1407
|
+
const changedPath = match?.[2] ?? match?.[1];
|
|
1408
|
+
if (!changedPath) {
|
|
1409
|
+
return true;
|
|
1410
|
+
}
|
|
1411
|
+
if (!shouldIgnoreRepoPath(changedPath)) {
|
|
1412
|
+
return true;
|
|
1413
|
+
}
|
|
1414
|
+
const normalizedPath = changedPath.replace(/\\/g, "/");
|
|
1415
|
+
const parentDir = normalizedPath.includes("/") ? `${normalizedPath.slice(0, normalizedPath.lastIndexOf("/") + 1)}` : "";
|
|
1416
|
+
return normalizedTaskText.includes(normalizedPath) || parentDir.length > 0 && normalizedTaskText.includes(parentDir);
|
|
1417
|
+
}).join("\n");
|
|
1418
|
+
}
|
|
1419
|
+
var TYPECHECK_GATE_IDS = /* @__PURE__ */ new Set(["tsc", "typecheck", "typescript"]);
|
|
1420
|
+
function normalizeGateId(gateId) {
|
|
1421
|
+
return gateId.trim().toLowerCase().replaceAll("_", "-");
|
|
1422
|
+
}
|
|
1423
|
+
function isTypecheckGateId(gateId) {
|
|
1424
|
+
const normalized = normalizeGateId(gateId);
|
|
1425
|
+
if (TYPECHECK_GATE_IDS.has(normalized)) {
|
|
1426
|
+
return true;
|
|
1427
|
+
}
|
|
1428
|
+
return normalized.split("-").some((part) => TYPECHECK_GATE_IDS.has(part));
|
|
1429
|
+
}
|
|
1430
|
+
function hasCompilerErrorOutput(output, scope = "tail") {
|
|
1431
|
+
if (output.trim().length === 0) {
|
|
1432
|
+
return false;
|
|
1433
|
+
}
|
|
1434
|
+
const hasTsError = output.split(/\r?\n/).some(
|
|
1435
|
+
(line) => /^(?:.+(?:\(\d+,\d+\)|:\d+:\d+)\s*(?::|-)\s+)?error\s+TS\d+:/i.test(line.trim())
|
|
1436
|
+
);
|
|
1437
|
+
return hasTsError || hasCompileDiagnosticOutput(output, scope);
|
|
1438
|
+
}
|
|
1439
|
+
function hasCompilationProgressSignal(insights) {
|
|
1440
|
+
return insights?.some(
|
|
1441
|
+
(insight) => /\bcompilation failed with [1-9]\d* new (?:typescript )?errors?\b/i.test(insight)
|
|
1442
|
+
) ?? false;
|
|
1443
|
+
}
|
|
1444
|
+
function classifyQualityGateFailure(gate) {
|
|
1445
|
+
if (gate.passed || gate.isRegression === false) {
|
|
1446
|
+
return "other";
|
|
1447
|
+
}
|
|
1448
|
+
if (isTypecheckGateId(gate.gateId)) {
|
|
1449
|
+
return "compilation";
|
|
1450
|
+
}
|
|
1451
|
+
if (gate.compilationFailure !== void 0) {
|
|
1452
|
+
return gate.compilationFailure ? "compilation" : "other";
|
|
1453
|
+
}
|
|
1454
|
+
const compilerOutput = `${gate.details}
|
|
1455
|
+
${gate.outputTail ?? ""}`;
|
|
1456
|
+
return hasCompilerErrorOutput(compilerOutput) ? "compilation" : "other";
|
|
1457
|
+
}
|
|
1458
|
+
function semanticSkipped(skipped) {
|
|
1459
|
+
return { enabled: true, skipped };
|
|
1460
|
+
}
|
|
1461
|
+
function semanticDisabled() {
|
|
1462
|
+
return { enabled: false };
|
|
1463
|
+
}
|
|
1464
|
+
var MIN_CUSTOM_GATE_BASELINE_MS = 3e3;
|
|
1465
|
+
var MIN_CUSTOM_GATE_RUN_MS = 1e3;
|
|
1466
|
+
var MIN_FIRST_ITERATION_RESERVE_MS = 15e3;
|
|
1467
|
+
var MAX_FIRST_ITERATION_RESERVE_MS = 9e4;
|
|
1468
|
+
function classifyError(error) {
|
|
1469
|
+
const message = error.message.toLowerCase();
|
|
1470
|
+
if (message.includes("timeout") || message.includes("timed out") || message.includes("deadline")) {
|
|
1471
|
+
return {
|
|
1472
|
+
category: "timeout",
|
|
1473
|
+
hint: "Consider reducing iteration complexity or increasing timeout limits"
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
if (message.includes("auth") || message.includes("unauthorized") || message.includes("forbidden") || message.includes("credentials")) {
|
|
1477
|
+
return {
|
|
1478
|
+
category: "auth",
|
|
1479
|
+
hint: "Verify API credentials and authentication configuration"
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
if (message.includes("syntax") || message.includes("parse") || message.includes("unexpected token")) {
|
|
1483
|
+
return {
|
|
1484
|
+
category: "syntax",
|
|
1485
|
+
hint: "Check generated code for syntax errors or malformed output"
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
if (message.includes("memory") || message.includes("cpu") || message.includes("disk") || message.includes("enospc") || message.includes("enomem")) {
|
|
1489
|
+
return {
|
|
1490
|
+
category: "resource",
|
|
1491
|
+
hint: "Reduce memory/CPU usage or increase resource limits"
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
return {
|
|
1495
|
+
category: "unknown",
|
|
1496
|
+
hint: "Review error details and adjust implementation approach"
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
function abortErrorFromSignal(signal) {
|
|
1500
|
+
const reason = signal.reason;
|
|
1501
|
+
if (reason instanceof Error) {
|
|
1502
|
+
return reason;
|
|
1503
|
+
}
|
|
1504
|
+
if (typeof reason === "string" && reason.trim().length > 0) {
|
|
1505
|
+
return new Error(reason);
|
|
1506
|
+
}
|
|
1507
|
+
return new Error("Autoloop iteration aborted");
|
|
1508
|
+
}
|
|
1509
|
+
function isAutoloopTimeboxAbortError(error) {
|
|
1510
|
+
return /remaining timebox|autoloop timebox exceeded/i.test(error.message);
|
|
1511
|
+
}
|
|
1512
|
+
function rejectIterationAbort(signal, reject) {
|
|
1513
|
+
const abortError = abortErrorFromSignal(signal);
|
|
1514
|
+
if (isAutoloopTimeboxAbortError(abortError)) {
|
|
1515
|
+
reject(abortError);
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
reject(createDirectAutoloopCancellationFailure(abortError, "mid-run"));
|
|
1519
|
+
}
|
|
1520
|
+
function resolveQualityGateExecutionFlags(mode = "fast") {
|
|
1521
|
+
return {
|
|
1522
|
+
coverage: autoloopPresetIncludesGateKind(mode, "unit"),
|
|
1523
|
+
lint: autoloopPresetIncludesGateKind(mode, "lint"),
|
|
1524
|
+
security: autoloopPresetIncludesGateKind(mode, "security")
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
async function captureQualityBaseline(workingDir, qualityGates, options) {
|
|
1528
|
+
if (!qualityGates) {
|
|
1529
|
+
return {
|
|
1530
|
+
status: "skipped",
|
|
1531
|
+
reason: "quality_gates_unavailable",
|
|
1532
|
+
capturedAt: /* @__PURE__ */ new Date()
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
try {
|
|
1536
|
+
const gateFlags = resolveQualityGateExecutionFlags(options?.mode ?? "fast");
|
|
1537
|
+
const summary = await qualityGates.run({
|
|
1538
|
+
...gateFlags,
|
|
1539
|
+
cwd: workingDir,
|
|
1540
|
+
abortSignal: options?.abortSignal,
|
|
1541
|
+
...typeof options?.timeoutMs === "number" && options.timeoutMs > 0 ? { timeoutMs: options.timeoutMs } : {}
|
|
1542
|
+
});
|
|
1543
|
+
const testFailuresResult = extractFailureCountWithMethod(
|
|
1544
|
+
summary.results,
|
|
1545
|
+
testEvidenceGateId(summary.results)
|
|
1546
|
+
);
|
|
1547
|
+
const lintErrorsResult = extractFailureCountWithMethod(summary.results, "lint");
|
|
1548
|
+
const securityFailuresResult = extractFailureCountWithMethod(summary.results, "security");
|
|
1549
|
+
const typeErrorsResult = lintErrorsResult;
|
|
1550
|
+
const failedCommandsOf = (gate) => {
|
|
1551
|
+
const gateResult = summary.results.find((entry) => entry.gate === gate);
|
|
1552
|
+
return gateResult?.success ? [] : gateResult?.failedCommands;
|
|
1553
|
+
};
|
|
1554
|
+
return {
|
|
1555
|
+
status: "captured",
|
|
1556
|
+
testFailures: testFailuresResult.count,
|
|
1557
|
+
testFailuresMethod: testFailuresResult.method,
|
|
1558
|
+
...testFailuresResult.suiteFootprint ? { testSuiteFootprint: testFailuresResult.suiteFootprint } : {},
|
|
1559
|
+
...testFailuresResult.messages && testFailuresResult.messages.length > 0 ? { testFailureMessages: testFailuresResult.messages } : {},
|
|
1560
|
+
testEvidenceCommand: summary.results.find(
|
|
1561
|
+
(entry) => entry.gate === testEvidenceGateId(summary.results)
|
|
1562
|
+
)?.command,
|
|
1563
|
+
lintErrors: lintErrorsResult.count,
|
|
1564
|
+
lintErrorsMethod: lintErrorsResult.method,
|
|
1565
|
+
typeErrors: typeErrorsResult.count,
|
|
1566
|
+
typeErrorsMethod: typeErrorsResult.method,
|
|
1567
|
+
securityFailures: securityFailuresResult.count,
|
|
1568
|
+
securityFailuresMethod: securityFailuresResult.method,
|
|
1569
|
+
gateEvidence: Object.fromEntries(
|
|
1570
|
+
summary.results.map((entry) => [entry.gate, gateEvidenceOf(entry, workingDir)])
|
|
1571
|
+
),
|
|
1572
|
+
lintFailedCommands: failedCommandsOf("lint"),
|
|
1573
|
+
testFailedCommands: failedCommandsOf(testEvidenceGateId(summary.results)),
|
|
1574
|
+
securityFailedCommands: failedCommandsOf("security"),
|
|
1575
|
+
gateAvailability: {
|
|
1576
|
+
coverage: summary.results.some(
|
|
1577
|
+
(result) => isTestEvidenceGate(result.gate) && !result.skipped && !result.unavailable
|
|
1578
|
+
),
|
|
1579
|
+
lint: summary.results.some(
|
|
1580
|
+
(result) => result.gate === "lint" && !result.skipped && !result.unavailable
|
|
1581
|
+
),
|
|
1582
|
+
security: summary.results.some(
|
|
1583
|
+
(result) => result.gate === "security" && !result.skipped && !result.unavailable
|
|
1584
|
+
)
|
|
1585
|
+
},
|
|
1586
|
+
capturedAt: /* @__PURE__ */ new Date()
|
|
1587
|
+
};
|
|
1588
|
+
} catch (error) {
|
|
1589
|
+
console.warn(
|
|
1590
|
+
`[AutonomousLoopController] Failed to capture quality baseline: ${error instanceof Error ? error.message : String(error)}`
|
|
1591
|
+
);
|
|
1592
|
+
return {
|
|
1593
|
+
status: "failed",
|
|
1594
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
1595
|
+
capturedAt: /* @__PURE__ */ new Date()
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
function computeErrorSignature(result) {
|
|
1600
|
+
const normalizedMessage = (result.error?.message ?? "").replace(/T\d+/g, "TASK_ID").replace(/\d+/g, "N").trim().toLowerCase();
|
|
1601
|
+
const warningCodes = [...new Set(result.warningCodes ?? [])].sort();
|
|
1602
|
+
const missingFiles = [...new Set(result.metadata?.missingFiles ?? [])].sort();
|
|
1603
|
+
const hash = createHash("sha256").update(JSON.stringify({ normalizedMessage, warningCodes, missingFiles })).digest("hex").slice(0, 16);
|
|
1604
|
+
return {
|
|
1605
|
+
hash,
|
|
1606
|
+
components: {
|
|
1607
|
+
normalizedMessage,
|
|
1608
|
+
warningCodes,
|
|
1609
|
+
missingFiles
|
|
1610
|
+
}
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
function classifyCoverageBaselineComparison(baseline, candidate) {
|
|
1614
|
+
if (baseline.failures === null || candidate.failures === null) {
|
|
1615
|
+
return "unknown";
|
|
1616
|
+
}
|
|
1617
|
+
if (candidate.failures > baseline.failures) {
|
|
1618
|
+
return "regression";
|
|
1619
|
+
}
|
|
1620
|
+
const baseFp = baseline.suiteFootprint;
|
|
1621
|
+
const candFp = candidate.suiteFootprint;
|
|
1622
|
+
if (!baseFp || !candFp) {
|
|
1623
|
+
return "unknown";
|
|
1624
|
+
}
|
|
1625
|
+
if (candFp.executed < baseFp.executed) {
|
|
1626
|
+
return "regression";
|
|
1627
|
+
}
|
|
1628
|
+
if (candFp.skipped > baseFp.skipped) {
|
|
1629
|
+
return "regression";
|
|
1630
|
+
}
|
|
1631
|
+
if (candidate.failures < baseline.failures) {
|
|
1632
|
+
return "improvement";
|
|
1633
|
+
}
|
|
1634
|
+
const baseMsgs = baseline.messages ?? [];
|
|
1635
|
+
const candMsgs = candidate.messages ?? [];
|
|
1636
|
+
if (baseMsgs.length === 0 || candMsgs.length === 0) {
|
|
1637
|
+
return "unknown";
|
|
1638
|
+
}
|
|
1639
|
+
if (!stableMessageSetsMatch(baseMsgs, candMsgs)) {
|
|
1640
|
+
return "unknown";
|
|
1641
|
+
}
|
|
1642
|
+
return "pre_existing";
|
|
1643
|
+
}
|
|
1644
|
+
function stableMessageSetsMatch(a, b) {
|
|
1645
|
+
if (a.length !== b.length) return false;
|
|
1646
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1647
|
+
for (const msg of a) {
|
|
1648
|
+
counts.set(msg, (counts.get(msg) ?? 0) + 1);
|
|
1649
|
+
}
|
|
1650
|
+
for (const msg of b) {
|
|
1651
|
+
const next = (counts.get(msg) ?? 0) - 1;
|
|
1652
|
+
if (next < 0) return false;
|
|
1653
|
+
if (next === 0) counts.delete(msg);
|
|
1654
|
+
else counts.set(msg, next);
|
|
1655
|
+
}
|
|
1656
|
+
return counts.size === 0;
|
|
1657
|
+
}
|
|
1658
|
+
function extractFailureCountWithMethod(results, gateId) {
|
|
1659
|
+
const result = results.find((r) => r.gate === gateId);
|
|
1660
|
+
if (!result) {
|
|
1661
|
+
return { count: 0, method: "passed_or_not_found" };
|
|
1662
|
+
}
|
|
1663
|
+
if (result.unavailable === true || result.skipped === true) {
|
|
1664
|
+
return { count: 0, method: "passed_or_not_found" };
|
|
1665
|
+
}
|
|
1666
|
+
const output = result.stdout + result.stderr;
|
|
1667
|
+
if (isTestEvidenceGate(gateId)) {
|
|
1668
|
+
if (result.command) {
|
|
1669
|
+
const parsed = parseFailureOutput(result.command, output, "test");
|
|
1670
|
+
if (parsed.parsed && parsed.errorCount !== null) {
|
|
1671
|
+
return {
|
|
1672
|
+
count: parsed.errorCount,
|
|
1673
|
+
method: "parsed_failure_output",
|
|
1674
|
+
...parsed.suiteFootprint ? { suiteFootprint: parsed.suiteFootprint } : {},
|
|
1675
|
+
...parsed.messages.length > 0 ? { messages: parsed.messages } : {}
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
if (result.success) {
|
|
1680
|
+
return { count: 0, method: "passed_or_not_found" };
|
|
1681
|
+
}
|
|
1682
|
+
const failMatch = output.match(/(\d+)\s+(?:tests?\s+)?(?:failing|failed)/i);
|
|
1683
|
+
if (failMatch?.[1]) {
|
|
1684
|
+
return { count: parseInt(failMatch[1], 10), method: "fail_pattern" };
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
if (result.success) {
|
|
1688
|
+
return { count: 0, method: "passed_or_not_found" };
|
|
1689
|
+
}
|
|
1690
|
+
if (gateId === "lint") {
|
|
1691
|
+
if (result.command) {
|
|
1692
|
+
const parsed = parseFailureOutput(result.command, output, "lint");
|
|
1693
|
+
if (parsed.parsed && parsed.errorCount !== null) {
|
|
1694
|
+
return { count: parsed.errorCount, method: "parsed_failure_output" };
|
|
1695
|
+
}
|
|
1696
|
+
const unavailable2 = unavailableFailureCountForCommand(result.command, "lint");
|
|
1697
|
+
if (unavailable2) {
|
|
1698
|
+
return { count: null, method: "unavailable_no_parser", language: unavailable2.language };
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
const tsErrorMatches = output.match(/error TS\d+:/g);
|
|
1702
|
+
if (tsErrorMatches && tsErrorMatches.length > 0) {
|
|
1703
|
+
return { count: tsErrorMatches.length, method: "ts_error_lines" };
|
|
1704
|
+
}
|
|
1705
|
+
const eslintMatch = output.match(/(\d+)\s+problems?\s*\(\s*(\d+)\s+errors?/i);
|
|
1706
|
+
if (eslintMatch?.[2]) {
|
|
1707
|
+
return { count: parseInt(eslintMatch[2], 10), method: "eslint_summary" };
|
|
1708
|
+
}
|
|
1709
|
+
const errorMatches = Array.from(output.matchAll(/(?:Found\s+)?(\d+)\s+errors?/gi));
|
|
1710
|
+
const lastErrorMatch = errorMatches[errorMatches.length - 1];
|
|
1711
|
+
if (lastErrorMatch?.[1]) {
|
|
1712
|
+
return { count: parseInt(lastErrorMatch[1], 10), method: "found_errors" };
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
if (gateId === "security") {
|
|
1716
|
+
const blockingCount = countSecurityVulnerabilities(result, countBlockingVulnerabilities);
|
|
1717
|
+
if (blockingCount !== null) {
|
|
1718
|
+
return { count: blockingCount, method: "security_vuln_count" };
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
const unavailable = isTestEvidenceGate(gateId) && result.command ? unavailableFailureCountForCommand(result.command, "test") : null;
|
|
1722
|
+
if (unavailable) {
|
|
1723
|
+
return { count: null, method: "unavailable_no_parser", language: unavailable.language };
|
|
1724
|
+
}
|
|
1725
|
+
return { count: 1, method: "fallback_1" };
|
|
1726
|
+
}
|
|
1727
|
+
function createProgressScore(score) {
|
|
1728
|
+
if (score < 0 || score > 1) {
|
|
1729
|
+
throw new Error(`Progress score must be between 0 and 1, got: ${score}`);
|
|
1730
|
+
}
|
|
1731
|
+
return score;
|
|
1732
|
+
}
|
|
1733
|
+
function createIterationCount(count) {
|
|
1734
|
+
if (count < 0 || !Number.isInteger(count)) {
|
|
1735
|
+
throw new Error(`Iteration count must be a non-negative integer, got: ${count}`);
|
|
1736
|
+
}
|
|
1737
|
+
return count;
|
|
1738
|
+
}
|
|
1739
|
+
function createDurationMs(ms) {
|
|
1740
|
+
if (ms < 0 || !Number.isFinite(ms)) {
|
|
1741
|
+
throw new Error(`Duration must be a non-negative finite number, got: ${ms}`);
|
|
1742
|
+
}
|
|
1743
|
+
return ms;
|
|
1744
|
+
}
|
|
1745
|
+
function calculateBackoffDelay(attempt, config) {
|
|
1746
|
+
const delay = Math.min(config.initialDelayMs * config.multiplier ** attempt, config.maxDelayMs);
|
|
1747
|
+
return createDurationMs(delay);
|
|
1748
|
+
}
|
|
1749
|
+
function getResourceUsage() {
|
|
1750
|
+
const memory = process.memoryUsage();
|
|
1751
|
+
const cpu = process.cpuUsage();
|
|
1752
|
+
const cpuCount = Math.max(1, os.cpus().length);
|
|
1753
|
+
const load1 = os.loadavg?.()[0] ?? 0;
|
|
1754
|
+
const cpuPercent = Math.max(0, load1 / cpuCount * 100);
|
|
1755
|
+
return {
|
|
1756
|
+
memory,
|
|
1757
|
+
cpu: (cpu.user + cpu.system) / 1e6,
|
|
1758
|
+
// Convert to seconds
|
|
1759
|
+
processes: globalProcessLimiter.getActiveCount(),
|
|
1760
|
+
cpuPercent
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
function requiredHostGatesPassed(qualityGates, customGates) {
|
|
1764
|
+
const ran = (qualityGates ?? []).some((gate) => gate.passed && gate.skipped !== true) || (customGates ?? []).some((gate) => gate.passed);
|
|
1765
|
+
const qualityOk = (qualityGates ?? []).every(
|
|
1766
|
+
(gate) => gate.passed || isNonBlockingQualityGateSkip(gate)
|
|
1767
|
+
);
|
|
1768
|
+
return ran && qualityOk && (customGates ?? []).every((gate) => gate.passed);
|
|
1769
|
+
}
|
|
1770
|
+
var AutonomousLoopController = class extends EventEmitter {
|
|
1771
|
+
config;
|
|
1772
|
+
recursionTracker;
|
|
1773
|
+
telemetry;
|
|
1774
|
+
resultStreamer;
|
|
1775
|
+
aiJudge;
|
|
1776
|
+
qualityGates;
|
|
1777
|
+
progressValidator;
|
|
1778
|
+
state = { status: "idle" };
|
|
1779
|
+
iterationHistory = [];
|
|
1780
|
+
startTime = 0;
|
|
1781
|
+
elapsedRuntimeBeforeStartMs = 0;
|
|
1782
|
+
instanceId = `AutonomousLoopController-${createHash("md5").update(String(Date.now() + Math.random())).digest("hex").slice(0, 8)}`;
|
|
1783
|
+
cleanupStarted = false;
|
|
1784
|
+
backoffAttempts = 0;
|
|
1785
|
+
resourceWarnings = /* @__PURE__ */ new Set();
|
|
1786
|
+
lastErrorSignature = null;
|
|
1787
|
+
consecutiveIdenticalCount = 0;
|
|
1788
|
+
/** A normally returned failure is recorded but, as before, does not spend retry budget. */
|
|
1789
|
+
lastIterationReturnedFailure = false;
|
|
1790
|
+
/**
|
|
1791
|
+
* Set when shouldContinue idle-stops after a real first delivery so start()
|
|
1792
|
+
* can mark the run completed even if the completion XML 0.3 gate left the
|
|
1793
|
+
* oracle at NOT_COMPLETE. Does not change totalIterations accounting.
|
|
1794
|
+
*/
|
|
1795
|
+
idleStoppedAfterRealFirstDelivery = false;
|
|
1796
|
+
cleanupHandlers = [];
|
|
1797
|
+
workingDir = process.cwd();
|
|
1798
|
+
/** Whether completion signal matched on last iteration */
|
|
1799
|
+
completionSignalMatched = false;
|
|
1800
|
+
/** Quality baseline captured at loop start (undefined until initialized) */
|
|
1801
|
+
qualityBaseline;
|
|
1802
|
+
/** Custom gate pass/fail captured at loop start (gate id -> passed). */
|
|
1803
|
+
customGateBaseline;
|
|
1804
|
+
/** TypeScript error baseline captured at loop start (null if not applicable) */
|
|
1805
|
+
compilationBaselineErrors = null;
|
|
1806
|
+
/** Monotonic policy level for stability-first escalation */
|
|
1807
|
+
policyLevel = "baseline";
|
|
1808
|
+
/**
|
|
1809
|
+
* Git ref (SHA) captured at loop start for semantic validation diffs.
|
|
1810
|
+
*
|
|
1811
|
+
* Important: semantic validation should evaluate cumulative work across the whole loop,
|
|
1812
|
+
* not just the last iteration’s working-tree or last commit’s diff.
|
|
1813
|
+
*/
|
|
1814
|
+
semanticBaselineRef = null;
|
|
1815
|
+
/** Loop-start HEAD SHA for change-surface gate scaling. */
|
|
1816
|
+
loopStartRef = null;
|
|
1817
|
+
/** Git ref (SHA) captured at loop start for progress validation diffs. */
|
|
1818
|
+
progressBaselineRef = null;
|
|
1819
|
+
/** Current provider for cross-provider pivot (initialized from routing decision or undefined) */
|
|
1820
|
+
currentProvider;
|
|
1821
|
+
/** Current provider setup mode for pivot-aware execution mode selection */
|
|
1822
|
+
currentProviderSetup;
|
|
1823
|
+
/** Available alternate providers for pivot */
|
|
1824
|
+
availableAlternates = [];
|
|
1825
|
+
constructor(config = {}, dependencies = {}) {
|
|
1826
|
+
super();
|
|
1827
|
+
this.config = {
|
|
1828
|
+
maxIterations: createIterationCount(3),
|
|
1829
|
+
timeboxMs: createDurationMs(DEFAULT_AUTOLOOP_TIMEBOX_MS),
|
|
1830
|
+
minProgressThreshold: createProgressScore(0.05),
|
|
1831
|
+
useAIJudge: false,
|
|
1832
|
+
runQualityGates: false,
|
|
1833
|
+
qualityGatesMode: "fast",
|
|
1834
|
+
resourceLimits: DEFAULT_AUTOLOOP_RESOURCE_LIMITS,
|
|
1835
|
+
backoffConfig: {
|
|
1836
|
+
initialDelayMs: createDurationMs(1e3),
|
|
1837
|
+
maxDelayMs: createDurationMs(3e4),
|
|
1838
|
+
multiplier: 2,
|
|
1839
|
+
maxRetries: 3
|
|
1840
|
+
},
|
|
1841
|
+
progressConfig: {
|
|
1842
|
+
windowSize: 3,
|
|
1843
|
+
trendThreshold: 0.01,
|
|
1844
|
+
confidenceThreshold: 0.7
|
|
1845
|
+
},
|
|
1846
|
+
validationMode: "heuristic",
|
|
1847
|
+
requirements: {
|
|
1848
|
+
mode: "auto",
|
|
1849
|
+
minCoverage: 0.9,
|
|
1850
|
+
requireEvidence: true,
|
|
1851
|
+
blockNewRepoRootMarkdown: true
|
|
1852
|
+
},
|
|
1853
|
+
// completionSignal is undefined by default (opt-in)
|
|
1854
|
+
...config
|
|
1855
|
+
};
|
|
1856
|
+
this.recursionTracker = globalRecursionTracker;
|
|
1857
|
+
this.telemetry = dependencies.telemetry;
|
|
1858
|
+
this.resultStreamer = dependencies.resultStreamer;
|
|
1859
|
+
this.aiJudge = dependencies.aiJudge;
|
|
1860
|
+
this.qualityGates = dependencies.qualityGates;
|
|
1861
|
+
this.validateConfig();
|
|
1862
|
+
if (this.config.routingDecision) {
|
|
1863
|
+
this.currentProvider = this.config.routingDecision.primary.provider;
|
|
1864
|
+
this.currentProviderSetup = this.config.routingDecision.primary.setup;
|
|
1865
|
+
this.availableAlternates = [...this.config.routingDecision.alternates];
|
|
1866
|
+
}
|
|
1867
|
+
this.progressValidator = createCustomProgressValidator({
|
|
1868
|
+
minProgressThreshold: this.config.minProgressThreshold,
|
|
1869
|
+
trendThreshold: this.config.progressConfig.trendThreshold
|
|
1870
|
+
});
|
|
1871
|
+
this.setupEventForwarding();
|
|
1872
|
+
}
|
|
1873
|
+
// ========================================================================
|
|
1874
|
+
// PUBLIC API
|
|
1875
|
+
// ========================================================================
|
|
1876
|
+
/**
|
|
1877
|
+
* Start the autonomous loop with the given task function
|
|
1878
|
+
*/
|
|
1879
|
+
async start(taskFunction) {
|
|
1880
|
+
if (this.state.status !== "idle") {
|
|
1881
|
+
throw new Error(`Cannot start loop in state: ${this.state.status}`);
|
|
1882
|
+
}
|
|
1883
|
+
try {
|
|
1884
|
+
this.synchronizeWallClockBudgetAtStart();
|
|
1885
|
+
this.startTime = performance.now();
|
|
1886
|
+
this.state = {
|
|
1887
|
+
status: "running",
|
|
1888
|
+
_iteration: createIterationCount(0),
|
|
1889
|
+
startTime: this.startTime
|
|
1890
|
+
};
|
|
1891
|
+
if (this.getRemainingTimeboxMs() <= 0) {
|
|
1892
|
+
this.terminate("timebox_exceeded");
|
|
1893
|
+
throw new Error("Autoloop timebox exceeded before loop started");
|
|
1894
|
+
}
|
|
1895
|
+
await this.initializeSafetySystems();
|
|
1896
|
+
this.emit("loop_started", { type: "loop_started", config: this.config });
|
|
1897
|
+
let lastResult;
|
|
1898
|
+
for (let i = 1; i <= this.config.maxIterations; i++) {
|
|
1899
|
+
if (this.state.status !== "running") {
|
|
1900
|
+
break;
|
|
1901
|
+
}
|
|
1902
|
+
const iteration = createIterationCount(i);
|
|
1903
|
+
if (this.state.status === "running") {
|
|
1904
|
+
this.state._iteration = iteration;
|
|
1905
|
+
}
|
|
1906
|
+
if (await this.shouldTerminate(iteration)) {
|
|
1907
|
+
break;
|
|
1908
|
+
}
|
|
1909
|
+
if (this.state.status !== "running") {
|
|
1910
|
+
break;
|
|
1911
|
+
}
|
|
1912
|
+
lastResult = await this.executeIteration(iteration, taskFunction);
|
|
1913
|
+
this.iterationHistory.push(lastResult);
|
|
1914
|
+
if (!await this.shouldContinue(lastResult)) {
|
|
1915
|
+
break;
|
|
1916
|
+
}
|
|
1917
|
+
if (!lastResult.success && !this.lastIterationReturnedFailure) {
|
|
1918
|
+
if (this.isRunAborted()) {
|
|
1919
|
+
if (this.state.status === "running") {
|
|
1920
|
+
this.terminate("system_error");
|
|
1921
|
+
}
|
|
1922
|
+
break;
|
|
1923
|
+
}
|
|
1924
|
+
await this.applyBackoff();
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
if (!lastResult) {
|
|
1928
|
+
const terminatedReason2 = this.state.status === "terminated" ? this.state.reason : void 0;
|
|
1929
|
+
if (terminatedReason2 === "timebox_exceeded") {
|
|
1930
|
+
const timeboxMin = (this.config.timeboxMs / 6e4).toFixed(1);
|
|
1931
|
+
throw new Error(
|
|
1932
|
+
`Autoloop timebox (${timeboxMin}m) elapsed before the first iteration completed. Baseline quality-gate capture runs inside the first iteration and can exhaust a small budget; increase --autoloop-timebox (recommend at least 15m) or reduce gate cost with --autoloop-quality-gates-mode fast.`
|
|
1933
|
+
);
|
|
1934
|
+
}
|
|
1935
|
+
throw new Error("No iterations were executed");
|
|
1936
|
+
}
|
|
1937
|
+
const finalResult = lastResult;
|
|
1938
|
+
const totalDuration = createDurationMs(this.getElapsedRuntimeMs());
|
|
1939
|
+
const hasCompilationFailure = this.detectCompilationFailure(finalResult);
|
|
1940
|
+
const currentTerminatedReason = this.state.status === "terminated" ? this.state.reason : null;
|
|
1941
|
+
const isMaxIterationsOnly = currentTerminatedReason === "max_iterations_reached";
|
|
1942
|
+
if (hasCompilationFailure && (this.state.status !== "terminated" || isMaxIterationsOnly)) {
|
|
1943
|
+
this.telemetry?.logEvent({
|
|
1944
|
+
name: "loop_terminated_compilation_errors",
|
|
1945
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
1946
|
+
properties: {
|
|
1947
|
+
iteration: finalResult._iteration,
|
|
1948
|
+
progressScore: finalResult.progress.score,
|
|
1949
|
+
insights: finalResult.progress.insights.slice(0, 3)
|
|
1950
|
+
}
|
|
1951
|
+
});
|
|
1952
|
+
this.upgradeTerminationReason("compilation_errors");
|
|
1953
|
+
return { ...finalResult, success: false };
|
|
1954
|
+
}
|
|
1955
|
+
if (this.iterationHistory.length >= this.config.maxIterations && this.state.status === "running") {
|
|
1956
|
+
this.terminate("max_iterations_reached");
|
|
1957
|
+
}
|
|
1958
|
+
const ranAllIterations = this.iterationHistory.length === this.config.maxIterations;
|
|
1959
|
+
const terminatedReason = this.state.status === "terminated" ? this.state.reason : null;
|
|
1960
|
+
const isBudgetCompletionTermination = terminatedReason === "max_iterations_reached";
|
|
1961
|
+
const isSuccessfulEarlyTermination = terminatedReason !== null && isSuccessLikeControllerReason(terminatedReason);
|
|
1962
|
+
const currentStateStatus = this.state.status;
|
|
1963
|
+
const summaryProvesUnsafeCompletion = finalResult.completionSummary?.unsafeCompletion === true;
|
|
1964
|
+
const summaryAllowsCompletion = completionStatusAllowsSuccess(finalResult.completionSummary?.status) || this.idleStoppedAfterRealFirstDelivery;
|
|
1965
|
+
const shouldMarkCompleted = (currentStateStatus === "running" && finalResult.success !== false || currentStateStatus === "terminated" && (ranAllIterations && isBudgetCompletionTermination || isSuccessfulEarlyTermination) && finalResult.success !== false) && !summaryProvesUnsafeCompletion && summaryAllowsCompletion;
|
|
1966
|
+
if (shouldMarkCompleted) {
|
|
1967
|
+
this.state = {
|
|
1968
|
+
status: "completed",
|
|
1969
|
+
totalIterations: createIterationCount(this.iterationHistory.length),
|
|
1970
|
+
finalScore: finalResult.progress.score,
|
|
1971
|
+
duration: totalDuration,
|
|
1972
|
+
completionReason: terminatedReason ?? void 0
|
|
1973
|
+
};
|
|
1974
|
+
this.emit("loop_completed", {
|
|
1975
|
+
type: "loop_completed",
|
|
1976
|
+
finalResult,
|
|
1977
|
+
totalDuration
|
|
1978
|
+
});
|
|
1979
|
+
} else if (this.state.status === "running" && finalResult.success === false) {
|
|
1980
|
+
const failureError = finalResult.error ?? new Error("Autoloop ended without success");
|
|
1981
|
+
this.state = {
|
|
1982
|
+
status: "failed",
|
|
1983
|
+
_iteration: finalResult._iteration,
|
|
1984
|
+
_error: failureError,
|
|
1985
|
+
duration: totalDuration
|
|
1986
|
+
};
|
|
1987
|
+
this.emit("loop_failed", {
|
|
1988
|
+
type: "loop_failed",
|
|
1989
|
+
error: failureError,
|
|
1990
|
+
_iteration: finalResult._iteration
|
|
1991
|
+
});
|
|
1992
|
+
}
|
|
1993
|
+
return finalResult;
|
|
1994
|
+
} catch (error) {
|
|
1995
|
+
if (this.state.status === "terminated") {
|
|
1996
|
+
throw error;
|
|
1997
|
+
}
|
|
1998
|
+
const currentIteration = this.state.status === "running" ? this.state._iteration : createIterationCount(0);
|
|
1999
|
+
const duration = createDurationMs(this.getElapsedRuntimeMs());
|
|
2000
|
+
this.state = {
|
|
2001
|
+
status: "failed",
|
|
2002
|
+
_iteration: currentIteration,
|
|
2003
|
+
_error: error,
|
|
2004
|
+
duration
|
|
2005
|
+
};
|
|
2006
|
+
this.emit("loop_failed", {
|
|
2007
|
+
type: "loop_failed",
|
|
2008
|
+
error,
|
|
2009
|
+
_iteration: currentIteration
|
|
2010
|
+
});
|
|
2011
|
+
throw error;
|
|
2012
|
+
} finally {
|
|
2013
|
+
await this.cleanup();
|
|
2014
|
+
this.close();
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
/**
|
|
2018
|
+
* Set the initial policy level (e.g., from static pre-run detection).
|
|
2019
|
+
*
|
|
2020
|
+
* Monotonic: only allows moving to a more conservative level.
|
|
2021
|
+
*/
|
|
2022
|
+
setInitialPolicyLevel(level) {
|
|
2023
|
+
if (this.policyLevel === "safe") return;
|
|
2024
|
+
if (this.policyLevel === "guarded" && level === "baseline") return;
|
|
2025
|
+
this.policyLevel = level;
|
|
2026
|
+
}
|
|
2027
|
+
/**
|
|
2028
|
+
* Apply a monotonic escalation in response to a runtime signal.
|
|
2029
|
+
*
|
|
2030
|
+
* Returns true if the policy level advanced (even if no config knobs changed),
|
|
2031
|
+
* false if already at max level.
|
|
2032
|
+
*/
|
|
2033
|
+
escalatePolicy(signal, details) {
|
|
2034
|
+
const escalation = computeMonotonicAutoloopEscalation({
|
|
2035
|
+
currentLevel: this.policyLevel,
|
|
2036
|
+
signal,
|
|
2037
|
+
currentValidationMode: this.config.validationMode,
|
|
2038
|
+
currentUseAIJudge: this.config.useAIJudge,
|
|
2039
|
+
currentQualityGatesMode: this.config.qualityGatesMode,
|
|
2040
|
+
runQualityGates: this.config.runQualityGates
|
|
2041
|
+
});
|
|
2042
|
+
if (!escalation) return false;
|
|
2043
|
+
if (escalation.corePatch.validationMode && this.config.validationMode === "none") {
|
|
2044
|
+
this.config.validationMode = escalation.corePatch.validationMode;
|
|
2045
|
+
}
|
|
2046
|
+
if (escalation.corePatch.useAIJudge === true) {
|
|
2047
|
+
if (this.aiJudge) {
|
|
2048
|
+
this.config.useAIJudge = true;
|
|
2049
|
+
} else {
|
|
2050
|
+
this.telemetry?.logEvent({
|
|
2051
|
+
name: "autoloop_escalation_skipped",
|
|
2052
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2053
|
+
properties: { reason: "ai_judge_dependency_missing", signal }
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
if (escalation.corePatch.qualityGatesMode && this.config.runQualityGates) {
|
|
2058
|
+
if (this.config.qualityGatesMode === "fast" && escalation.corePatch.qualityGatesMode === "safe") {
|
|
2059
|
+
this.config.qualityGatesMode = "safe";
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
const from = this.policyLevel;
|
|
2063
|
+
this.policyLevel = escalation.to;
|
|
2064
|
+
this.telemetry?.logEvent({
|
|
2065
|
+
name: "autoloop_policy_escalated",
|
|
2066
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2067
|
+
properties: {
|
|
2068
|
+
from,
|
|
2069
|
+
to: escalation.to,
|
|
2070
|
+
signal,
|
|
2071
|
+
appliedPatch: escalation.corePatch,
|
|
2072
|
+
...details ? { details } : {}
|
|
2073
|
+
}
|
|
2074
|
+
});
|
|
2075
|
+
this.emit("policy_escalated", {
|
|
2076
|
+
type: "policy_escalated",
|
|
2077
|
+
from,
|
|
2078
|
+
to: escalation.to,
|
|
2079
|
+
signal,
|
|
2080
|
+
appliedPatch: escalation.corePatch,
|
|
2081
|
+
...details ? { details } : {}
|
|
2082
|
+
});
|
|
2083
|
+
return true;
|
|
2084
|
+
}
|
|
2085
|
+
/**
|
|
2086
|
+
* Terminate the loop with a specific reason
|
|
2087
|
+
*/
|
|
2088
|
+
terminate(reason) {
|
|
2089
|
+
if (this.state.status === "terminated") {
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
2092
|
+
if (this.state.status === "idle" || this.state.status === "completed" || this.state.status === "failed") {
|
|
2093
|
+
return;
|
|
2094
|
+
}
|
|
2095
|
+
if (this.state.status !== "running") {
|
|
2096
|
+
return;
|
|
2097
|
+
}
|
|
2098
|
+
const currentIteration = createIterationCount(this.iterationHistory.length);
|
|
2099
|
+
const duration = createDurationMs(this.getElapsedRuntimeMs());
|
|
2100
|
+
this.state = {
|
|
2101
|
+
status: "terminated",
|
|
2102
|
+
_iteration: currentIteration,
|
|
2103
|
+
reason,
|
|
2104
|
+
duration
|
|
2105
|
+
};
|
|
2106
|
+
this.emit("loop_terminated", {
|
|
2107
|
+
type: "loop_terminated",
|
|
2108
|
+
reason,
|
|
2109
|
+
_iteration: currentIteration
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2112
|
+
/**
|
|
2113
|
+
* Internal reason upgrade used by the start() epilogue: replaces the generic
|
|
2114
|
+
* budget termination ('max_iterations_reached') with a more specific reason
|
|
2115
|
+
* such as 'compilation_errors'. Bypasses terminate()'s already-terminated
|
|
2116
|
+
* early return without changing public terminate() semantics. Deliberately
|
|
2117
|
+
* does not re-emit 'loop_terminated' (the original termination event has
|
|
2118
|
+
* already been delivered to ledger/CLI listeners).
|
|
2119
|
+
*/
|
|
2120
|
+
upgradeTerminationReason(reason) {
|
|
2121
|
+
if (this.state.status !== "terminated") {
|
|
2122
|
+
this.terminate(reason);
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
this.state = { ...this.state, reason };
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Get current loop state
|
|
2129
|
+
*/
|
|
2130
|
+
getState() {
|
|
2131
|
+
return { ...this.state };
|
|
2132
|
+
}
|
|
2133
|
+
/** The loop-start gate baseline, or why there is none. */
|
|
2134
|
+
getQualityBaseline() {
|
|
2135
|
+
return this.qualityBaseline;
|
|
2136
|
+
}
|
|
2137
|
+
/**
|
|
2138
|
+
* Get iteration history
|
|
2139
|
+
*/
|
|
2140
|
+
getIterationHistory() {
|
|
2141
|
+
return [...this.iterationHistory];
|
|
2142
|
+
}
|
|
2143
|
+
/**
|
|
2144
|
+
* Get current configuration
|
|
2145
|
+
*/
|
|
2146
|
+
getConfig() {
|
|
2147
|
+
return { ...this.config };
|
|
2148
|
+
}
|
|
2149
|
+
/**
|
|
2150
|
+
* Override the working directory used for git-based progress validation and quality gates.
|
|
2151
|
+
*
|
|
2152
|
+
* Useful when an orchestrator executes iterations inside an isolated worktree.
|
|
2153
|
+
*/
|
|
2154
|
+
setWorkingDir(workingDir) {
|
|
2155
|
+
this.workingDir = workingDir;
|
|
2156
|
+
}
|
|
2157
|
+
/**
|
|
2158
|
+
* Apply outer-run wall-clock handoff immediately before start().
|
|
2159
|
+
*
|
|
2160
|
+
* CLI setup (evidence-plan resolution, worktree creation, etc.) happens before the
|
|
2161
|
+
* controller starts; this keeps custom/evidence gate budgets aligned with runStart.
|
|
2162
|
+
*/
|
|
2163
|
+
applyWallClockHandoff(handoff) {
|
|
2164
|
+
if (typeof handoff.wallClockRunStartMs === "number" && Number.isFinite(handoff.wallClockRunStartMs)) {
|
|
2165
|
+
this.config.wallClockRunStartMs = handoff.wallClockRunStartMs;
|
|
2166
|
+
}
|
|
2167
|
+
if (typeof handoff.preControllerElapsedMs === "number" && Number.isFinite(handoff.preControllerElapsedMs)) {
|
|
2168
|
+
this.config.preControllerElapsedMs = Math.max(0, Math.floor(handoff.preControllerElapsedMs));
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
// ========================================================================
|
|
2172
|
+
// PRIVATE IMPLEMENTATION
|
|
2173
|
+
// ========================================================================
|
|
2174
|
+
/**
|
|
2175
|
+
* Validate configuration values
|
|
2176
|
+
*/
|
|
2177
|
+
validateConfig() {
|
|
2178
|
+
if (this.config.maxIterations <= 0) {
|
|
2179
|
+
throw new Error("Iteration count must be a positive integer");
|
|
2180
|
+
}
|
|
2181
|
+
if (this.config.validationMode === "deterministic" && this.config.completionSignal) {
|
|
2182
|
+
throw new Error(
|
|
2183
|
+
'Cannot combine validation mode "deterministic" with a completion signal. Deterministic mode uses quality gates to determine completion.'
|
|
2184
|
+
);
|
|
2185
|
+
}
|
|
2186
|
+
if (this.config.runQualityGates && !this.qualityGates) {
|
|
2187
|
+
throw new Error(
|
|
2188
|
+
"Quality gates enabled (runQualityGates=true) but no QualityGateRunner injected. Either wire `dependencies.qualityGates` or set `runQualityGates: false` if gates are run elsewhere."
|
|
2189
|
+
);
|
|
2190
|
+
}
|
|
2191
|
+
if (this.config.useAIJudge && !this.aiJudge) {
|
|
2192
|
+
throw new Error(
|
|
2193
|
+
"AI judge enabled (useAIJudge=true) but no Judge injected. Either wire `dependencies.aiJudge` or set `useAIJudge: false`."
|
|
2194
|
+
);
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
synchronizeWallClockBudgetAtStart() {
|
|
2198
|
+
const elapsedMs = resolveAutoloopElapsedMs({
|
|
2199
|
+
wallClockRunStartMs: this.config.wallClockRunStartMs,
|
|
2200
|
+
preControllerElapsedMs: this.config.preControllerElapsedMs
|
|
2201
|
+
});
|
|
2202
|
+
if (elapsedMs > 0) {
|
|
2203
|
+
this.elapsedRuntimeBeforeStartMs = elapsedMs;
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
getElapsedRuntimeMs() {
|
|
2207
|
+
if (typeof this.config.wallClockRunStartMs === "number" && Number.isFinite(this.config.wallClockRunStartMs)) {
|
|
2208
|
+
return Math.max(0, Date.now() - this.config.wallClockRunStartMs);
|
|
2209
|
+
}
|
|
2210
|
+
if (this.state.status === "running") {
|
|
2211
|
+
return this.elapsedRuntimeBeforeStartMs + (performance.now() - this.startTime);
|
|
2212
|
+
}
|
|
2213
|
+
return this.elapsedRuntimeBeforeStartMs;
|
|
2214
|
+
}
|
|
2215
|
+
isRunAborted() {
|
|
2216
|
+
return this.config.abortSignal?.aborted === true;
|
|
2217
|
+
}
|
|
2218
|
+
getRemainingTimeboxMs() {
|
|
2219
|
+
return Math.max(0, Math.floor(this.config.timeboxMs - this.getElapsedRuntimeMs()));
|
|
2220
|
+
}
|
|
2221
|
+
ensureRemainingTimeboxMs(phase) {
|
|
2222
|
+
const remainingMs = this.getRemainingTimeboxMs();
|
|
2223
|
+
if (remainingMs <= 0) {
|
|
2224
|
+
this.terminate("timebox_exceeded");
|
|
2225
|
+
throw new Error(`Autoloop timebox exceeded before ${phase}`);
|
|
2226
|
+
}
|
|
2227
|
+
return remainingMs;
|
|
2228
|
+
}
|
|
2229
|
+
getFirstIterationReserveMs() {
|
|
2230
|
+
const timeboxMs = Number(this.config.timeboxMs);
|
|
2231
|
+
if (!Number.isFinite(timeboxMs) || timeboxMs <= 0) {
|
|
2232
|
+
return 0;
|
|
2233
|
+
}
|
|
2234
|
+
const proportionalReserveMs = Math.floor(timeboxMs * 0.25);
|
|
2235
|
+
const maxReserveForTimeboxMs = Math.max(1, Math.floor(timeboxMs * 0.5));
|
|
2236
|
+
return Math.min(
|
|
2237
|
+
MAX_FIRST_ITERATION_RESERVE_MS,
|
|
2238
|
+
maxReserveForTimeboxMs,
|
|
2239
|
+
Math.max(MIN_FIRST_ITERATION_RESERVE_MS, proportionalReserveMs)
|
|
2240
|
+
);
|
|
2241
|
+
}
|
|
2242
|
+
getPreIterationGateBudgetMs() {
|
|
2243
|
+
const remainingMs = this.getRemainingTimeboxMs();
|
|
2244
|
+
const reserveMs = this.getFirstIterationReserveMs();
|
|
2245
|
+
return {
|
|
2246
|
+
budgetMs: Math.max(0, remainingMs - reserveMs),
|
|
2247
|
+
reserveMs,
|
|
2248
|
+
remainingMs
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
2251
|
+
/**
|
|
2252
|
+
* Initialize safety systems
|
|
2253
|
+
*/
|
|
2254
|
+
async initializeSafetySystems() {
|
|
2255
|
+
await this.recursionTracker.enter();
|
|
2256
|
+
this.checkResourceLimits();
|
|
2257
|
+
this.setupCleanupHandlers();
|
|
2258
|
+
this.compilationBaselineErrors = await countTypeScriptErrors(this.workingDir);
|
|
2259
|
+
if (this.compilationBaselineErrors !== null) {
|
|
2260
|
+
this.telemetry?.logEvent({
|
|
2261
|
+
name: "compilation_baseline_captured",
|
|
2262
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2263
|
+
properties: {
|
|
2264
|
+
totalErrors: this.compilationBaselineErrors
|
|
2265
|
+
}
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
if (this.config.runQualityGates && this.qualityGates) {
|
|
2269
|
+
const {
|
|
2270
|
+
budgetMs: baselineBudgetMs,
|
|
2271
|
+
reserveMs,
|
|
2272
|
+
remainingMs
|
|
2273
|
+
} = this.getPreIterationGateBudgetMs();
|
|
2274
|
+
if (baselineBudgetMs <= 0 || this.isRunAborted()) {
|
|
2275
|
+
const skipReason = this.isRunAborted() ? "aborted" : remainingMs <= 0 ? "insufficient_timebox" : "first_iteration_reserved";
|
|
2276
|
+
this.qualityBaseline = {
|
|
2277
|
+
status: "skipped",
|
|
2278
|
+
reason: skipReason,
|
|
2279
|
+
capturedAt: /* @__PURE__ */ new Date()
|
|
2280
|
+
};
|
|
2281
|
+
this.telemetry?.logEvent({
|
|
2282
|
+
name: "quality_baseline_skipped",
|
|
2283
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2284
|
+
properties: {
|
|
2285
|
+
remainingMs,
|
|
2286
|
+
reserveMs,
|
|
2287
|
+
reason: skipReason
|
|
2288
|
+
}
|
|
2289
|
+
});
|
|
2290
|
+
} else {
|
|
2291
|
+
this.qualityBaseline = await captureQualityBaseline(this.workingDir, this.qualityGates, {
|
|
2292
|
+
mode: this.config.qualityGatesMode,
|
|
2293
|
+
timeoutMs: baselineBudgetMs,
|
|
2294
|
+
abortSignal: this.config.abortSignal
|
|
2295
|
+
});
|
|
2296
|
+
const captured = this.qualityBaseline.status === "captured" ? this.qualityBaseline : void 0;
|
|
2297
|
+
this.telemetry?.logEvent({
|
|
2298
|
+
name: "quality_baseline_captured",
|
|
2299
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2300
|
+
properties: {
|
|
2301
|
+
budgetMs: baselineBudgetMs,
|
|
2302
|
+
reserveMs,
|
|
2303
|
+
status: this.qualityBaseline.status,
|
|
2304
|
+
reason: this.qualityBaseline.status === "captured" ? void 0 : this.qualityBaseline.reason,
|
|
2305
|
+
testFailures: captured?.testFailures,
|
|
2306
|
+
testFailuresMethod: captured?.testFailuresMethod,
|
|
2307
|
+
lintErrors: captured?.lintErrors,
|
|
2308
|
+
lintErrorsMethod: captured?.lintErrorsMethod,
|
|
2309
|
+
typeErrors: captured?.typeErrors,
|
|
2310
|
+
typeErrorsMethod: captured?.typeErrorsMethod,
|
|
2311
|
+
securityFailures: captured?.securityFailures,
|
|
2312
|
+
securityFailuresMethod: captured?.securityFailuresMethod
|
|
2313
|
+
}
|
|
2314
|
+
});
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
if (this.config.runQualityGates && this.config.customGateCommands && this.config.customGateCommands.length > 0) {
|
|
2318
|
+
const {
|
|
2319
|
+
budgetMs: customBaselineBudgetMs,
|
|
2320
|
+
reserveMs,
|
|
2321
|
+
remainingMs
|
|
2322
|
+
} = this.getPreIterationGateBudgetMs();
|
|
2323
|
+
if (customBaselineBudgetMs < MIN_CUSTOM_GATE_BASELINE_MS || remainingMs < MIN_CUSTOM_GATE_BASELINE_MS || this.isRunAborted()) {
|
|
2324
|
+
this.telemetry?.logEvent({
|
|
2325
|
+
name: "custom_gate_baseline_skipped",
|
|
2326
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2327
|
+
properties: {
|
|
2328
|
+
remainingMs,
|
|
2329
|
+
reserveMs,
|
|
2330
|
+
reason: this.isRunAborted() ? "aborted" : remainingMs < MIN_CUSTOM_GATE_BASELINE_MS ? "insufficient_timebox" : "first_iteration_reserved"
|
|
2331
|
+
}
|
|
2332
|
+
});
|
|
2333
|
+
} else {
|
|
2334
|
+
const baselineResults = await this.runCustomGates(
|
|
2335
|
+
createIterationCount(0),
|
|
2336
|
+
this.config.customGateCommands,
|
|
2337
|
+
customBaselineBudgetMs
|
|
2338
|
+
);
|
|
2339
|
+
this.customGateBaseline = new Map(
|
|
2340
|
+
baselineResults.filter((result) => result.skipped !== true && result.misconfigured !== true).map((result) => [result.id, result.passed])
|
|
2341
|
+
);
|
|
2342
|
+
this.telemetry?.logEvent({
|
|
2343
|
+
name: "custom_gate_baseline_captured",
|
|
2344
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2345
|
+
properties: {
|
|
2346
|
+
budgetMs: customBaselineBudgetMs,
|
|
2347
|
+
reserveMs,
|
|
2348
|
+
gateCount: baselineResults.length,
|
|
2349
|
+
failingAtStart: baselineResults.filter((result) => !result.passed).length
|
|
2350
|
+
}
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
if (this.config.semanticCheck?.enabled || this.config.validationMode === "heuristic" || (this.config.requirementsTaskText?.length ?? 0) > 0 || this.config.runQualityGates && (this.config.customGateCommands?.length ?? 0) > 0) {
|
|
2355
|
+
try {
|
|
2356
|
+
const { execa } = await import("execa");
|
|
2357
|
+
const { stdout } = await execa("git", ["rev-parse", "HEAD"], {
|
|
2358
|
+
cwd: this.workingDir,
|
|
2359
|
+
timeout: 5e3,
|
|
2360
|
+
maxBuffer: 1024 * 1024,
|
|
2361
|
+
stderr: "ignore"
|
|
2362
|
+
});
|
|
2363
|
+
const sha = stdout.trim();
|
|
2364
|
+
const resolvedSha = sha || null;
|
|
2365
|
+
this.loopStartRef = resolvedSha;
|
|
2366
|
+
if (this.config.semanticCheck?.enabled) {
|
|
2367
|
+
this.semanticBaselineRef = resolvedSha;
|
|
2368
|
+
}
|
|
2369
|
+
if (this.config.validationMode === "heuristic") {
|
|
2370
|
+
this.progressBaselineRef = resolvedSha;
|
|
2371
|
+
}
|
|
2372
|
+
if (sha) {
|
|
2373
|
+
this.telemetry?.logEvent({
|
|
2374
|
+
name: "semantic_baseline_captured",
|
|
2375
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2376
|
+
properties: { baseRef: sha }
|
|
2377
|
+
});
|
|
2378
|
+
}
|
|
2379
|
+
} catch {
|
|
2380
|
+
this.loopStartRef = null;
|
|
2381
|
+
if (this.config.semanticCheck?.enabled) {
|
|
2382
|
+
this.semanticBaselineRef = null;
|
|
2383
|
+
}
|
|
2384
|
+
if (this.config.validationMode === "heuristic") {
|
|
2385
|
+
this.progressBaselineRef = null;
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
/**
|
|
2391
|
+
* Replace stale progress-insight wording when a completion signal succeeds
|
|
2392
|
+
* because separate durable evidence proved completion.
|
|
2393
|
+
*/
|
|
2394
|
+
reconcileCompletionEvidenceInsights(result) {
|
|
2395
|
+
const summary = result.completionSummary;
|
|
2396
|
+
if (result.completionEvidence?.durable !== true || summary?.completionSignalDetected !== true || !completionStatusAllowsSuccess(summary.status) && summary.status !== "BASELINE_BLOCKED") {
|
|
2397
|
+
return;
|
|
2398
|
+
}
|
|
2399
|
+
const illusoryProgressPattern = /reported progress may be illusory/i;
|
|
2400
|
+
const staleCompletenessPattern = /^(Task appears nearly complete|Good progress, some work remaining|Halfway through task completion|Significant work still needed)$/i;
|
|
2401
|
+
const filteredInsights = [];
|
|
2402
|
+
let removedIllusoryProgress = false;
|
|
2403
|
+
let removedStaleCompleteness = false;
|
|
2404
|
+
for (const insight of result.progress.insights) {
|
|
2405
|
+
if (result.progress.toolingFailure === true && illusoryProgressPattern.test(insight)) {
|
|
2406
|
+
removedIllusoryProgress = true;
|
|
2407
|
+
continue;
|
|
2408
|
+
}
|
|
2409
|
+
if (staleCompletenessPattern.test(insight)) {
|
|
2410
|
+
removedStaleCompleteness = true;
|
|
2411
|
+
continue;
|
|
2412
|
+
}
|
|
2413
|
+
filteredInsights.push(insight);
|
|
2414
|
+
}
|
|
2415
|
+
if (!removedIllusoryProgress && !removedStaleCompleteness) {
|
|
2416
|
+
return;
|
|
2417
|
+
}
|
|
2418
|
+
result.progress.insights = [
|
|
2419
|
+
...filteredInsights,
|
|
2420
|
+
...removedStaleCompleteness ? ["Durable completion evidence satisfied the requested completion criteria."] : [],
|
|
2421
|
+
...removedIllusoryProgress ? [
|
|
2422
|
+
"Progress validation tooling failed; durable completion evidence satisfied the completion signal."
|
|
2423
|
+
] : []
|
|
2424
|
+
];
|
|
2425
|
+
}
|
|
2426
|
+
/**
|
|
2427
|
+
* Execute a single iteration
|
|
2428
|
+
*/
|
|
2429
|
+
async executeIteration(iteration, taskFunction) {
|
|
2430
|
+
const iterationStart = performance.now();
|
|
2431
|
+
this.emit("iteration_start", { type: "iteration_start", iteration });
|
|
2432
|
+
this.lastIterationReturnedFailure = false;
|
|
2433
|
+
try {
|
|
2434
|
+
const lastIteration = this.iterationHistory.length > 0 ? this.iterationHistory[this.iterationHistory.length - 1] : void 0;
|
|
2435
|
+
const blockingCustomGate = lastIteration?.customGateResults?.find(
|
|
2436
|
+
isBlockingCustomGateForCompletion
|
|
2437
|
+
);
|
|
2438
|
+
const boundedCustomGateContext = blockingCustomGate ? `Custom gate '${blockingCustomGate.id}' failed${typeof blockingCustomGate.exitCode === "number" ? ` (exit code ${blockingCustomGate.exitCode})` : ""}${blockingCustomGate.outputTail ? `: ${blockingCustomGate.outputTail.slice(-1e3)}` : ""}` : void 0;
|
|
2439
|
+
const previousError = lastIteration && (!lastIteration.success || boundedCustomGateContext) ? {
|
|
2440
|
+
message: [lastIteration.error?.message, boundedCustomGateContext].filter((part) => Boolean(part)).join("\n"),
|
|
2441
|
+
iteration: lastIteration._iteration,
|
|
2442
|
+
// Convert branded type to plain number
|
|
2443
|
+
...lastIteration.error ? classifyError(lastIteration.error) : { category: "unknown" },
|
|
2444
|
+
...boundedCustomGateContext ? { hint: "Address the blocking custom-gate failure before retrying." } : {}
|
|
2445
|
+
} : void 0;
|
|
2446
|
+
const HISTORY_WINDOW = 10;
|
|
2447
|
+
const context = {
|
|
2448
|
+
_iteration: iteration,
|
|
2449
|
+
history: this.iterationHistory.length <= HISTORY_WINDOW ? [...this.iterationHistory] : this.iterationHistory.slice(-HISTORY_WINDOW),
|
|
2450
|
+
config: this.config,
|
|
2451
|
+
isFirstIteration: iteration === 1,
|
|
2452
|
+
isLastIteration: iteration === this.config.maxIterations,
|
|
2453
|
+
previousError,
|
|
2454
|
+
workingDir: this.workingDir,
|
|
2455
|
+
currentProvider: this.currentProvider,
|
|
2456
|
+
currentProviderSetup: this.currentProviderSetup,
|
|
2457
|
+
availableAlternates: [...this.availableAlternates]
|
|
2458
|
+
};
|
|
2459
|
+
const remainingTimeboxMs = this.config.timeboxMs - this.getElapsedRuntimeMs();
|
|
2460
|
+
if (remainingTimeboxMs <= 0) {
|
|
2461
|
+
this.terminate("timebox_exceeded");
|
|
2462
|
+
throw new Error("Autoloop timebox exceeded before iteration started");
|
|
2463
|
+
}
|
|
2464
|
+
let timeoutId;
|
|
2465
|
+
const iterationAbortController = new AbortController();
|
|
2466
|
+
const iterationAbortSignal = this.config.abortSignal ? AbortSignal.any([this.config.abortSignal, iterationAbortController.signal]) : iterationAbortController.signal;
|
|
2467
|
+
context.abortSignal = iterationAbortSignal;
|
|
2468
|
+
const timeboxError = new Error("Autoloop iteration exceeded remaining timebox");
|
|
2469
|
+
const timeboxRace = new Promise((_, reject) => {
|
|
2470
|
+
timeoutId = setTimeout(() => {
|
|
2471
|
+
reject(timeboxError);
|
|
2472
|
+
iterationAbortController.abort(timeboxError);
|
|
2473
|
+
}, remainingTimeboxMs);
|
|
2474
|
+
});
|
|
2475
|
+
const abortSignal = iterationAbortSignal;
|
|
2476
|
+
let abortListener;
|
|
2477
|
+
const recursionStateFile = this.recursionTracker.getStateFilePath?.();
|
|
2478
|
+
const taskPromise = recursionStateFile ? withExecutionContextEnvOverrides(
|
|
2479
|
+
{ BUILD_RECURSION_STATE_FILE: recursionStateFile },
|
|
2480
|
+
() => taskFunction(iteration, context)
|
|
2481
|
+
) : taskFunction(iteration, context);
|
|
2482
|
+
const raceArms = [taskPromise, timeboxRace];
|
|
2483
|
+
if (abortSignal) {
|
|
2484
|
+
const abortRace = new Promise((_, reject) => {
|
|
2485
|
+
if (abortSignal.aborted) {
|
|
2486
|
+
rejectIterationAbort(abortSignal, reject);
|
|
2487
|
+
return;
|
|
2488
|
+
}
|
|
2489
|
+
abortListener = () => {
|
|
2490
|
+
rejectIterationAbort(abortSignal, reject);
|
|
2491
|
+
};
|
|
2492
|
+
abortSignal.addEventListener("abort", abortListener, { once: true });
|
|
2493
|
+
});
|
|
2494
|
+
raceArms.push(abortRace);
|
|
2495
|
+
}
|
|
2496
|
+
let taskResult;
|
|
2497
|
+
try {
|
|
2498
|
+
taskResult = await Promise.race(raceArms);
|
|
2499
|
+
} catch (error) {
|
|
2500
|
+
if (error instanceof Error && isAutoloopTimeboxAbortError(error)) {
|
|
2501
|
+
this.terminate("timebox_exceeded");
|
|
2502
|
+
}
|
|
2503
|
+
throw error;
|
|
2504
|
+
} finally {
|
|
2505
|
+
if (timeoutId) {
|
|
2506
|
+
clearTimeout(timeoutId);
|
|
2507
|
+
}
|
|
2508
|
+
if (abortSignal && abortListener) {
|
|
2509
|
+
abortSignal.removeEventListener("abort", abortListener);
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
const returnedFailure = readReturnedTaskFailure(taskResult);
|
|
2513
|
+
this.lastIterationReturnedFailure = returnedFailure !== void 0;
|
|
2514
|
+
const repairOutcome = taskResult && typeof taskResult === "object" && "repairOutcome" in taskResult && isRepairOutcome(taskResult.repairOutcome) ? taskResult.repairOutcome : void 0;
|
|
2515
|
+
const completionEvidence = taskResult && typeof taskResult === "object" && "completionEvidence" in taskResult && isCompletionEvidence(taskResult.completionEvidence) ? taskResult.completionEvidence : void 0;
|
|
2516
|
+
const iterationFingerprint = taskResult && typeof taskResult === "object" && "iterationFingerprint" in taskResult && typeof taskResult.iterationFingerprint === "string" ? taskResult.iterationFingerprint : void 0;
|
|
2517
|
+
const callbackCustomGateResults = taskResult && typeof taskResult === "object" && "customGateResults" in taskResult && isCustomGateResultsArray(taskResult.customGateResults) ? taskResult.customGateResults.map(
|
|
2518
|
+
(gate) => ({
|
|
2519
|
+
...gate,
|
|
2520
|
+
durationMs: createDurationMs(gate.durationMs)
|
|
2521
|
+
})
|
|
2522
|
+
) : void 0;
|
|
2523
|
+
const outputForChecks = selectTaskOutputForChecks(taskResult);
|
|
2524
|
+
this.completionSignalMatched = false;
|
|
2525
|
+
if (this.config.completionSignal) {
|
|
2526
|
+
this.completionSignalMatched = matchesCompletionSignal(
|
|
2527
|
+
outputForChecks,
|
|
2528
|
+
this.config.completionSignal
|
|
2529
|
+
);
|
|
2530
|
+
if (this.completionSignalMatched) {
|
|
2531
|
+
this.telemetry?.logEvent({
|
|
2532
|
+
name: "completion_signal_matched",
|
|
2533
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2534
|
+
properties: {
|
|
2535
|
+
iteration,
|
|
2536
|
+
signalType: this.config.completionSignal.type,
|
|
2537
|
+
usedProviderOutputText: outputForChecks !== taskResult
|
|
2538
|
+
}
|
|
2539
|
+
});
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
const progress = await this.validateProgress(iteration, taskResult);
|
|
2543
|
+
const metadata = {};
|
|
2544
|
+
if (this.compilationBaselineErrors !== null) {
|
|
2545
|
+
const currentTypeErrors = progress.compilationErrors !== void 0 ? progress.compilationErrors : await countTypeScriptErrors(this.workingDir);
|
|
2546
|
+
if (currentTypeErrors !== null && currentTypeErrors > this.compilationBaselineErrors) {
|
|
2547
|
+
metadata.compilationErrorDelta = currentTypeErrors - this.compilationBaselineErrors;
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
await rediscoverCandidateGates(this, this.telemetry, this.config, this.workingDir, iteration);
|
|
2551
|
+
const qualityGateBudgetMs = this.config.runQualityGates ? this.ensureRemainingTimeboxMs("quality gates") : void 0;
|
|
2552
|
+
const qualityGates = this.config.runQualityGates && qualityGateBudgetMs !== void 0 ? await this.runQualityGates(iteration, qualityGateBudgetMs) : void 0;
|
|
2553
|
+
const customGateBudgetMs = this.config.runQualityGates && this.config.customGateCommands && this.config.customGateCommands.length > 0 ? this.ensureRemainingTimeboxMs("custom quality gates") : void 0;
|
|
2554
|
+
const customGateResults = withCustomGateVerificationKinds(
|
|
2555
|
+
this.workingDir,
|
|
2556
|
+
customGateBudgetMs !== void 0 && this.config.customGateCommands ? await this.runCustomGates(iteration, this.config.customGateCommands, customGateBudgetMs) : callbackCustomGateResults
|
|
2557
|
+
);
|
|
2558
|
+
const testGateResults = [
|
|
2559
|
+
// A test gate the caller disabled ("skipped by configuration") is not a
|
|
2560
|
+
// missing check; leave it out so passing custom test gates still count.
|
|
2561
|
+
...(qualityGates ?? []).filter((gate) => isTestEvidenceGateResult(gate.gateId, gate.notMeasured)).filter((gate) => !isNonBlockingQualityGateSkip(gate)).map((gate) => ({
|
|
2562
|
+
passed: gate.passed,
|
|
2563
|
+
executed: gate.skipped !== true && gate.unavailable !== true
|
|
2564
|
+
})),
|
|
2565
|
+
...(customGateResults ?? []).filter((gate) => describeVerificationCommand(gate.command).kind === "test").map((gate) => ({
|
|
2566
|
+
passed: gate.passed,
|
|
2567
|
+
executed: gate.skipped !== true && gate.unavailable !== true
|
|
2568
|
+
}))
|
|
2569
|
+
];
|
|
2570
|
+
const executedTestGates = testGateResults.filter((gate) => gate.executed);
|
|
2571
|
+
const testVerification = {
|
|
2572
|
+
status: executedTestGates.some((gate) => !gate.passed) ? "failed" : executedTestGates.length > 0 && testGateResults.every((gate) => gate.executed && gate.passed) ? "passed" : "unavailable",
|
|
2573
|
+
checksRun: executedTestGates.length
|
|
2574
|
+
};
|
|
2575
|
+
const changedFiles = await this.getChangedFilesSinceLoopStart();
|
|
2576
|
+
const requirements = validateRequirements({
|
|
2577
|
+
requirementsTaskText: this.config.requirementsTaskText,
|
|
2578
|
+
providerOutputText: outputForChecks,
|
|
2579
|
+
workingDir: this.workingDir,
|
|
2580
|
+
config: this.config.requirements,
|
|
2581
|
+
changedFiles: changedFiles ?? void 0,
|
|
2582
|
+
testVerification,
|
|
2583
|
+
hostGatesPassed: requiredHostGatesPassed(qualityGates, customGateResults)
|
|
2584
|
+
});
|
|
2585
|
+
const judgeEvaluation = this.config.useAIJudge ? await this.getAIJudgeEvaluation(iteration, taskResult, progress) : void 0;
|
|
2586
|
+
const isCompletionOrBounds = this.completionSignalMatched || iteration >= this.config.maxIterations;
|
|
2587
|
+
const semanticValidation = this.config.semanticCheck?.enabled ? await this.runSemanticValidation(iteration, outputForChecks, isCompletionOrBounds) : void 0;
|
|
2588
|
+
const duration = createDurationMs(performance.now() - iterationStart);
|
|
2589
|
+
const memoryUsage = process.memoryUsage();
|
|
2590
|
+
const result = {
|
|
2591
|
+
_iteration: iteration,
|
|
2592
|
+
progress,
|
|
2593
|
+
requirements,
|
|
2594
|
+
duration,
|
|
2595
|
+
memoryUsage,
|
|
2596
|
+
success: !returnedFailure,
|
|
2597
|
+
error: returnedFailure,
|
|
2598
|
+
iterationFingerprint,
|
|
2599
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
|
|
2600
|
+
qualityGates,
|
|
2601
|
+
customGateResults,
|
|
2602
|
+
repairOutcome,
|
|
2603
|
+
judgeEvaluation,
|
|
2604
|
+
semanticValidation,
|
|
2605
|
+
completionEvidence,
|
|
2606
|
+
usedProvider: this.currentProvider ?? this.config.routingDecision?.primary.provider
|
|
2607
|
+
};
|
|
2608
|
+
result.completionSummary = this.computeCompletionSummary(
|
|
2609
|
+
result,
|
|
2610
|
+
this.completionSignalMatched,
|
|
2611
|
+
isCompletionOrBounds
|
|
2612
|
+
);
|
|
2613
|
+
this.reconcileCompletionEvidenceInsights(result);
|
|
2614
|
+
this.emit("iteration_complete", { type: "iteration_complete", result });
|
|
2615
|
+
return result;
|
|
2616
|
+
} catch (error) {
|
|
2617
|
+
const duration = createDurationMs(performance.now() - iterationStart);
|
|
2618
|
+
const memoryUsage = process.memoryUsage();
|
|
2619
|
+
const failureEnvelope = getCarriedDirectAutoloopFailureEnvelope(error) ?? classifyFailureEnvelope(error, {
|
|
2620
|
+
executionPhase: "post-run",
|
|
2621
|
+
mutationState: "unknown"
|
|
2622
|
+
});
|
|
2623
|
+
const failureRecovery = serializeDirectAutoloopFailureRecovery(
|
|
2624
|
+
failureEnvelope,
|
|
2625
|
+
deriveDirectAutoloopRecovery(failureEnvelope)
|
|
2626
|
+
);
|
|
2627
|
+
const iterationFingerprint = getCarriedDirectAutoloopIterationFingerprint(error) ?? (error && typeof error === "object" && "iterationFingerprint" in error && typeof error.iterationFingerprint === "string" ? error.iterationFingerprint : void 0);
|
|
2628
|
+
const result = {
|
|
2629
|
+
_iteration: iteration,
|
|
2630
|
+
progress: {
|
|
2631
|
+
score: createProgressScore(0),
|
|
2632
|
+
isSignificant: false,
|
|
2633
|
+
trend: "unknown",
|
|
2634
|
+
confidence: 0,
|
|
2635
|
+
metrics: {
|
|
2636
|
+
testCoverage: 0,
|
|
2637
|
+
completeness: 0
|
|
2638
|
+
},
|
|
2639
|
+
insights: [`Iteration failed: ${error.message}`]
|
|
2640
|
+
},
|
|
2641
|
+
completionSummary: {
|
|
2642
|
+
status: "NOT_COMPLETE",
|
|
2643
|
+
gatesOk: false,
|
|
2644
|
+
providerOk: false,
|
|
2645
|
+
convergedOk: false,
|
|
2646
|
+
completionSignalDetected: false,
|
|
2647
|
+
hasSubstantiveEvidence: false,
|
|
2648
|
+
blockingIssues: [`Iteration failed: ${error.message}`],
|
|
2649
|
+
hasBaselineFailures: false,
|
|
2650
|
+
unsafeCompletion: false,
|
|
2651
|
+
// Diagnostic-only: the iteration crashed BEFORE any verification gate
|
|
2652
|
+
// ran, so verification never executed. Per competition semantics
|
|
2653
|
+
// (judge-types-core.ts: skipped/unavailable/no-evidence -> 'not_run'),
|
|
2654
|
+
// a crash with no gate evidence is 'not_run', NOT 'failed' — gatesOk is
|
|
2655
|
+
// false for fail-closed decision reasons, but verification did not fail.
|
|
2656
|
+
verificationDisposition: "not_run"
|
|
2657
|
+
},
|
|
2658
|
+
duration,
|
|
2659
|
+
memoryUsage,
|
|
2660
|
+
success: false,
|
|
2661
|
+
iterationFingerprint,
|
|
2662
|
+
error,
|
|
2663
|
+
failureRecovery,
|
|
2664
|
+
usedProvider: this.currentProvider ?? this.config.routingDecision?.primary.provider
|
|
2665
|
+
};
|
|
2666
|
+
this.emit("iteration_complete", { type: "iteration_complete", result });
|
|
2667
|
+
this.telemetry?.trackError(error, { iteration, duration });
|
|
2668
|
+
return result;
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
/**
|
|
2672
|
+
* Validate progress using heuristic analysis (git diff + file metrics).
|
|
2673
|
+
*
|
|
2674
|
+
* Uses the ProgressValidator to:
|
|
2675
|
+
* - Analyze git diffs to measure meaningful code changes
|
|
2676
|
+
* - Detect test coverage changes
|
|
2677
|
+
* - Evaluate task completeness
|
|
2678
|
+
* - Determine progress trends
|
|
2679
|
+
*
|
|
2680
|
+
* Behavior depends on `validationMode`:
|
|
2681
|
+
* - `heuristic`: Full ProgressValidator analysis
|
|
2682
|
+
* - `none` or `deterministic`: Returns minimal validation (skips heuristics)
|
|
2683
|
+
*
|
|
2684
|
+
* @param iteration - Current iteration number
|
|
2685
|
+
* @param taskResult - Result from task execution
|
|
2686
|
+
* @returns ProgressValidation with scores and metrics
|
|
2687
|
+
*/
|
|
2688
|
+
async validateProgress(iteration, taskResult) {
|
|
2689
|
+
if (this.config.validationMode !== "heuristic") {
|
|
2690
|
+
const skipValidation = {
|
|
2691
|
+
score: createProgressScore(0.5),
|
|
2692
|
+
// Neutral score
|
|
2693
|
+
isSignificant: true,
|
|
2694
|
+
// Don't trigger stagnation in 'none' mode
|
|
2695
|
+
trend: "unknown",
|
|
2696
|
+
confidence: 0,
|
|
2697
|
+
metrics: {
|
|
2698
|
+
testCoverage: 0,
|
|
2699
|
+
completeness: 0
|
|
2700
|
+
},
|
|
2701
|
+
insights: [
|
|
2702
|
+
`Iteration ${iteration}: Heuristic validation skipped (mode: ${this.config.validationMode})`
|
|
2703
|
+
]
|
|
2704
|
+
};
|
|
2705
|
+
this.emit("progress_validated", {
|
|
2706
|
+
type: "progress_validated",
|
|
2707
|
+
validation: skipValidation
|
|
2708
|
+
});
|
|
2709
|
+
this.telemetry?.logEvent({
|
|
2710
|
+
name: "progress_validated",
|
|
2711
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2712
|
+
properties: {
|
|
2713
|
+
iteration,
|
|
2714
|
+
score: skipValidation.score,
|
|
2715
|
+
trend: skipValidation.trend,
|
|
2716
|
+
validationMode: this.config.validationMode,
|
|
2717
|
+
skipped: true
|
|
2718
|
+
}
|
|
2719
|
+
});
|
|
2720
|
+
return skipValidation;
|
|
2721
|
+
}
|
|
2722
|
+
try {
|
|
2723
|
+
const context = {
|
|
2724
|
+
iteration,
|
|
2725
|
+
taskResult,
|
|
2726
|
+
workingDir: this.workingDir,
|
|
2727
|
+
previousIterations: this.iterationHistory.map((r) => ({
|
|
2728
|
+
progress: r.progress,
|
|
2729
|
+
duration: r.duration
|
|
2730
|
+
})),
|
|
2731
|
+
compilationBaselineErrors: this.compilationBaselineErrors,
|
|
2732
|
+
baseRef: this.progressBaselineRef ?? (typeof this.config.progressConfig.baseRef === "string" ? this.config.progressConfig.baseRef : "HEAD")
|
|
2733
|
+
// Compare working tree to baseline commit by default
|
|
2734
|
+
};
|
|
2735
|
+
const validation = await this.progressValidator.validateProgress(context);
|
|
2736
|
+
this.emit("progress_validated", {
|
|
2737
|
+
type: "progress_validated",
|
|
2738
|
+
validation
|
|
2739
|
+
});
|
|
2740
|
+
this.telemetry?.logEvent({
|
|
2741
|
+
name: "progress_validated",
|
|
2742
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2743
|
+
properties: {
|
|
2744
|
+
iteration,
|
|
2745
|
+
score: validation.score,
|
|
2746
|
+
trend: validation.trend,
|
|
2747
|
+
confidence: validation.confidence,
|
|
2748
|
+
metrics: validation.metrics,
|
|
2749
|
+
validationMode: this.config.validationMode
|
|
2750
|
+
}
|
|
2751
|
+
});
|
|
2752
|
+
return validation;
|
|
2753
|
+
} catch (error) {
|
|
2754
|
+
console.warn(
|
|
2755
|
+
`[AutonomousLoopController] Heuristic validation failed: ${error instanceof Error ? error.message : String(error)}`
|
|
2756
|
+
);
|
|
2757
|
+
this.telemetry?.trackError(error, {
|
|
2758
|
+
iteration,
|
|
2759
|
+
context: "progress_validation"
|
|
2760
|
+
});
|
|
2761
|
+
const fallbackScore = createProgressScore(
|
|
2762
|
+
Math.min(0.3, iteration / this.config.maxIterations)
|
|
2763
|
+
);
|
|
2764
|
+
return {
|
|
2765
|
+
score: fallbackScore,
|
|
2766
|
+
isSignificant: false,
|
|
2767
|
+
trend: "unknown",
|
|
2768
|
+
confidence: 0.2,
|
|
2769
|
+
metrics: {
|
|
2770
|
+
testCoverage: 0.3,
|
|
2771
|
+
completeness: 0.3
|
|
2772
|
+
},
|
|
2773
|
+
insights: [
|
|
2774
|
+
`Iteration ${iteration}: Heuristic validation failed, using fallback`,
|
|
2775
|
+
"Unable to analyze progress - recommend manual review"
|
|
2776
|
+
],
|
|
2777
|
+
toolingFailure: true,
|
|
2778
|
+
verificationUnavailable: true,
|
|
2779
|
+
verificationUnavailableReason: error instanceof Error ? error.message : "Heuristic validation failed before producing a result."
|
|
2780
|
+
};
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
/**
|
|
2784
|
+
* Run quality gates if enabled
|
|
2785
|
+
*/
|
|
2786
|
+
async runQualityGates(_iteration, timeoutMs) {
|
|
2787
|
+
if (!this.qualityGates) return [];
|
|
2788
|
+
try {
|
|
2789
|
+
const gateFlags = resolveQualityGateExecutionFlags(this.config.qualityGatesMode);
|
|
2790
|
+
const summary = await this.qualityGates.run({
|
|
2791
|
+
...gateFlags,
|
|
2792
|
+
cwd: this.workingDir,
|
|
2793
|
+
abortSignal: this.config.abortSignal,
|
|
2794
|
+
...typeof timeoutMs === "number" && timeoutMs > 0 ? { timeoutMs } : {}
|
|
2795
|
+
});
|
|
2796
|
+
const mappedResults = summary.results.map((result) => {
|
|
2797
|
+
const duration = createDurationMs(result.durationMs);
|
|
2798
|
+
let isRegression = result.skipped === true ? void 0 : this.isQualityRegression(result);
|
|
2799
|
+
let baselineUnavailableReason;
|
|
2800
|
+
if (!result.success && result.skipped !== true && isRegression === void 0) {
|
|
2801
|
+
const current = gateEvidenceOf(result, this.workingDir);
|
|
2802
|
+
const base = this.qualityBaseline?.status === "captured" ? this.qualityBaseline.gateEvidence?.[result.gate] : void 0;
|
|
2803
|
+
if (failsIdenticallyOnBaseline(current, base)) {
|
|
2804
|
+
isRegression = false;
|
|
2805
|
+
this.telemetry?.logEvent({
|
|
2806
|
+
name: "quality_gate_pre_existing_failure",
|
|
2807
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2808
|
+
properties: { gate: result.gate, classification: "identical_to_baseline" }
|
|
2809
|
+
});
|
|
2810
|
+
} else {
|
|
2811
|
+
baselineUnavailableReason = describeMissingGateBaseline(
|
|
2812
|
+
this.qualityBaseline,
|
|
2813
|
+
result.gate
|
|
2814
|
+
);
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
let effectiveSuccess = result.success;
|
|
2818
|
+
if (isTestEvidenceGate(result.gate) && !result.skipped && result.success && isRegression === true) {
|
|
2819
|
+
effectiveSuccess = false;
|
|
2820
|
+
}
|
|
2821
|
+
const score = result.skipped ? 0 : effectiveSuccess ? 1 : 0;
|
|
2822
|
+
if (effectiveSuccess && !result.skipped) {
|
|
2823
|
+
this.emit("quality_gate_passed", {
|
|
2824
|
+
type: "quality_gate_passed",
|
|
2825
|
+
gateId: result.gate,
|
|
2826
|
+
score
|
|
2827
|
+
});
|
|
2828
|
+
} else if (!result.skipped) {
|
|
2829
|
+
this.emit("quality_gate_failed", {
|
|
2830
|
+
type: "quality_gate_failed",
|
|
2831
|
+
gateId: result.gate,
|
|
2832
|
+
score,
|
|
2833
|
+
reason: result.message
|
|
2834
|
+
});
|
|
2835
|
+
}
|
|
2836
|
+
const buildOutputTail = () => {
|
|
2837
|
+
if (effectiveSuccess) return void 0;
|
|
2838
|
+
const combined = result.stdout + (result.stderr ? `
|
|
2839
|
+
=== stderr ===
|
|
2840
|
+
${result.stderr}` : "");
|
|
2841
|
+
if (combined.length === 0) return void 0;
|
|
2842
|
+
return combined.length > 500 ? `...${combined.slice(-500)}` : combined;
|
|
2843
|
+
};
|
|
2844
|
+
const fullOutput = `${result.message}
|
|
2845
|
+
${result.stdout}
|
|
2846
|
+
${result.stderr ?? ""}`;
|
|
2847
|
+
const compilationFailure = !effectiveSuccess && hasCompilerErrorOutput(fullOutput, "full");
|
|
2848
|
+
const failureDiagnostics = effectiveSuccess ? void 0 : boundedFailureDiagnostics({
|
|
2849
|
+
command: result.command,
|
|
2850
|
+
stdoutTail: result.stdout,
|
|
2851
|
+
stderrTail: result.stderr
|
|
2852
|
+
});
|
|
2853
|
+
const exitCode = effectiveSuccess ? void 0 : result.failedCommands?.find((entry) => entry.command === result.command)?.exitCode;
|
|
2854
|
+
return {
|
|
2855
|
+
gateId: result.gate,
|
|
2856
|
+
passed: result.skipped === true ? false : effectiveSuccess,
|
|
2857
|
+
score,
|
|
2858
|
+
details: result.message,
|
|
2859
|
+
duration,
|
|
2860
|
+
outputTail: buildOutputTail(),
|
|
2861
|
+
...effectiveSuccess || !failureDiagnostics ? {} : { diagnostics: failureDiagnostics },
|
|
2862
|
+
...effectiveSuccess ? {} : { compilationFailure },
|
|
2863
|
+
isRegression,
|
|
2864
|
+
...baselineUnavailableReason ? { baselineUnavailableReason } : {},
|
|
2865
|
+
...effectiveSuccess || !result.command ? {} : { command: result.command },
|
|
2866
|
+
...exitCode === void 0 ? {} : { exitCode },
|
|
2867
|
+
...result.skipped === true ? { skipped: true } : {},
|
|
2868
|
+
...result.unavailable === true ? { unavailable: true } : {},
|
|
2869
|
+
...result.notApplicable === true ? { notApplicable: true } : {},
|
|
2870
|
+
...result.notMeasured === true ? { notMeasured: true } : {},
|
|
2871
|
+
...result.styleOnly === true ? { styleOnly: true } : {}
|
|
2872
|
+
};
|
|
2873
|
+
});
|
|
2874
|
+
return mappedResults;
|
|
2875
|
+
} catch (error) {
|
|
2876
|
+
this.telemetry?.trackError(error, {
|
|
2877
|
+
_iteration,
|
|
2878
|
+
context: "quality_gates"
|
|
2879
|
+
});
|
|
2880
|
+
return [
|
|
2881
|
+
{
|
|
2882
|
+
gateId: "gate-runner-error",
|
|
2883
|
+
passed: false,
|
|
2884
|
+
score: 0,
|
|
2885
|
+
isRegression: true,
|
|
2886
|
+
details: error instanceof Error ? error.message : String(error),
|
|
2887
|
+
duration: createDurationMs(0)
|
|
2888
|
+
}
|
|
2889
|
+
];
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
/**
|
|
2893
|
+
* Run custom gate commands resolved from a Phase A evidence plan.
|
|
2894
|
+
*
|
|
2895
|
+
* Strictly isolated from QualityGateRunner: never widens QualityGateId,
|
|
2896
|
+
* never participates in baseline capture, never feeds isQualityRegression.
|
|
2897
|
+
* Returns results in `customGateResults`, a sibling of `qualityGates`.
|
|
2898
|
+
*/
|
|
2899
|
+
/**
|
|
2900
|
+
* Files changed since loop start: committed/staged/unstaged tracked changes
|
|
2901
|
+
* against the loop-start SHA plus untracked files. Returns null (no scaling)
|
|
2902
|
+
* when the loop-start ref is unknown or git fails, so gate selection falls
|
|
2903
|
+
* back to the configured command list.
|
|
2904
|
+
*/
|
|
2905
|
+
async getChangedFilesSinceLoopStart() {
|
|
2906
|
+
if (!this.loopStartRef || !/^[0-9a-f]{4,40}$/i.test(this.loopStartRef)) return null;
|
|
2907
|
+
try {
|
|
2908
|
+
const { execa } = await import("execa");
|
|
2909
|
+
const execOptions = {
|
|
2910
|
+
cwd: this.workingDir,
|
|
2911
|
+
timeout: 5e3,
|
|
2912
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
2913
|
+
stderr: "ignore"
|
|
2914
|
+
};
|
|
2915
|
+
const [{ stdout: tracked }, { stdout: untracked }] = await Promise.all([
|
|
2916
|
+
execa("git", ["diff", "--name-only", this.loopStartRef], execOptions),
|
|
2917
|
+
execa("git", ["ls-files", "--others", "--exclude-standard"], execOptions)
|
|
2918
|
+
]);
|
|
2919
|
+
const files = new Set(
|
|
2920
|
+
`${tracked}
|
|
2921
|
+
${untracked}`.split("\n").map((line) => line.trim()).filter((line) => line.length > 0)
|
|
2922
|
+
);
|
|
2923
|
+
return Array.from(files);
|
|
2924
|
+
} catch {
|
|
2925
|
+
return null;
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
async runCustomGates(iteration, commands, timeoutBudgetMs) {
|
|
2929
|
+
if (commands.length === 0) return [];
|
|
2930
|
+
const { checkVerifyCommandSafety, runVerifyCommands } = await import("./verify-commands-LOHMOFKC.js");
|
|
2931
|
+
const { resolveVerifyCommandTimeoutMs } = await import("./verify-command-timeout-DQUYH33Z.js");
|
|
2932
|
+
const { detectUnavailableGateCommand } = await import("./flywheel-autoloop-unverified-TOKYFCDC.js");
|
|
2933
|
+
const { canLaunchBroadAutoloopEvidenceGate, selectCustomGateCommands } = await import("./autoloop-evidence-gates-J5GG5YQB.js");
|
|
2934
|
+
if (iteration >= 1) {
|
|
2935
|
+
const changedFiles = await this.getChangedFilesSinceLoopStart();
|
|
2936
|
+
if (changedFiles !== null && changedFiles.length > 0) {
|
|
2937
|
+
const { isProseOrTabularDiffPath } = await import("./simple-artifact-goal-MQLDDMMX.js");
|
|
2938
|
+
if (this.config.customGateCommandsSource !== "prompt" && changedFiles.every((file) => isProseOrTabularDiffPath(file))) {
|
|
2939
|
+
const selection = selectCustomGateCommands(commands, {
|
|
2940
|
+
timeboxMs: this.config.timeboxMs,
|
|
2941
|
+
artifactOnlyChangeSurface: true
|
|
2942
|
+
});
|
|
2943
|
+
if (selection.filtered) {
|
|
2944
|
+
commands = selection.selectedCommands;
|
|
2945
|
+
this.telemetry?.logEvent({
|
|
2946
|
+
name: "custom_gates_scaled_for_change_surface",
|
|
2947
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2948
|
+
properties: {
|
|
2949
|
+
iteration,
|
|
2950
|
+
reason: selection.reason ?? null,
|
|
2951
|
+
changedFileCount: changedFiles.length,
|
|
2952
|
+
keptCommands: selection.selectedCommands.join(", "),
|
|
2953
|
+
droppedCommands: selection.droppedCommands.join(", ")
|
|
2954
|
+
}
|
|
2955
|
+
});
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
const results = [];
|
|
2961
|
+
for (const command of commands) {
|
|
2962
|
+
const start = performance.now();
|
|
2963
|
+
const gateId = buildCustomGateId(command);
|
|
2964
|
+
if (this.isRunAborted()) {
|
|
2965
|
+
results.push({
|
|
2966
|
+
id: gateId,
|
|
2967
|
+
command,
|
|
2968
|
+
passed: false,
|
|
2969
|
+
skipped: true,
|
|
2970
|
+
durationMs: createDurationMs(0),
|
|
2971
|
+
outputTail: "Custom gate skipped: autoloop run aborted."
|
|
2972
|
+
});
|
|
2973
|
+
continue;
|
|
2974
|
+
}
|
|
2975
|
+
const remainingWallMs = this.getRemainingTimeboxMs();
|
|
2976
|
+
const phaseBudgetMs = typeof timeoutBudgetMs === "number" && Number.isFinite(timeoutBudgetMs) ? Math.max(0, Math.floor(timeoutBudgetMs)) : void 0;
|
|
2977
|
+
const effectiveRemainingMs = phaseBudgetMs !== void 0 ? Math.min(remainingWallMs, phaseBudgetMs) : remainingWallMs;
|
|
2978
|
+
if (effectiveRemainingMs < MIN_CUSTOM_GATE_RUN_MS) {
|
|
2979
|
+
results.push({
|
|
2980
|
+
id: gateId,
|
|
2981
|
+
command,
|
|
2982
|
+
passed: false,
|
|
2983
|
+
skipped: true,
|
|
2984
|
+
durationMs: createDurationMs(0),
|
|
2985
|
+
outputTail: "Custom gate skipped: autoloop timebox exhausted."
|
|
2986
|
+
});
|
|
2987
|
+
if (remainingWallMs <= 0) {
|
|
2988
|
+
break;
|
|
2989
|
+
}
|
|
2990
|
+
continue;
|
|
2991
|
+
}
|
|
2992
|
+
if (!canLaunchBroadAutoloopEvidenceGate(command, effectiveRemainingMs, this.config.timeboxMs)) {
|
|
2993
|
+
results.push({
|
|
2994
|
+
id: gateId,
|
|
2995
|
+
command,
|
|
2996
|
+
passed: false,
|
|
2997
|
+
skipped: true,
|
|
2998
|
+
durationMs: createDurationMs(0),
|
|
2999
|
+
outputTail: "Custom gate skipped: broad evidence verifier blocked for remaining autoloop timebox."
|
|
3000
|
+
});
|
|
3001
|
+
continue;
|
|
3002
|
+
}
|
|
3003
|
+
const commandTimeoutMs = Math.max(
|
|
3004
|
+
1,
|
|
3005
|
+
Math.min(effectiveRemainingMs, resolveVerifyCommandTimeoutMs())
|
|
3006
|
+
);
|
|
3007
|
+
try {
|
|
3008
|
+
const safety = checkVerifyCommandSafety(command);
|
|
3009
|
+
let passed = false;
|
|
3010
|
+
let exitCode;
|
|
3011
|
+
let boundedOutputTail;
|
|
3012
|
+
let failureDiagnostics;
|
|
3013
|
+
let durationMs = createDurationMs(0);
|
|
3014
|
+
if (safety.safe) {
|
|
3015
|
+
const verifyOutcome = await runVerifyCommands({
|
|
3016
|
+
cwd: this.workingDir,
|
|
3017
|
+
commands: [command],
|
|
3018
|
+
timeoutMs: commandTimeoutMs,
|
|
3019
|
+
commandProvenance: "workflow-config"
|
|
3020
|
+
});
|
|
3021
|
+
const verifyResult = verifyOutcome.results[0];
|
|
3022
|
+
durationMs = createDurationMs(verifyResult?.durationMs ?? performance.now() - start);
|
|
3023
|
+
const diagnosticOutputTail = [
|
|
3024
|
+
verifyResult?.outputTail,
|
|
3025
|
+
verifyResult?.stderrTail,
|
|
3026
|
+
verifyResult?.stdoutTail
|
|
3027
|
+
].filter((value) => Boolean(value?.trim())).join("\n");
|
|
3028
|
+
const outputTail = [verifyResult?.outputTail, verifyResult?.stderrTail, verifyResult?.stdoutTail].find(
|
|
3029
|
+
(value) => value?.trim() && value.trim() !== "(no output)"
|
|
3030
|
+
) ?? verifyResult?.outputTail;
|
|
3031
|
+
boundedOutputTail = outputTail && outputTail.length > 500 ? `...${outputTail.slice(-500)}` : outputTail;
|
|
3032
|
+
passed = verifyOutcome.passed && (verifyResult?.exitCode ?? 1) === 0;
|
|
3033
|
+
if (!passed) {
|
|
3034
|
+
failureDiagnostics = boundedFailureDiagnostics({
|
|
3035
|
+
command,
|
|
3036
|
+
stderrTail: verifyResult?.stderrTail,
|
|
3037
|
+
stdoutTail: verifyResult?.stdoutTail,
|
|
3038
|
+
outputTail: verifyResult?.outputTail
|
|
3039
|
+
});
|
|
3040
|
+
}
|
|
3041
|
+
exitCode = verifyResult?.exitCode;
|
|
3042
|
+
const unavailableSignal = !passed && diagnosticOutputTail && exitCode !== void 0 ? detectUnavailableGateCommand({
|
|
3043
|
+
command,
|
|
3044
|
+
output: diagnosticOutputTail,
|
|
3045
|
+
exitCode,
|
|
3046
|
+
complete: verifyResult?.unavailable ? void 0 : verifyResult?.complete,
|
|
3047
|
+
// a launch error proves the tool missing
|
|
3048
|
+
unavailableReason: verifyResult?.unavailableReason
|
|
3049
|
+
}) : void 0;
|
|
3050
|
+
if (unavailableSignal) {
|
|
3051
|
+
results.push({
|
|
3052
|
+
id: gateId,
|
|
3053
|
+
command,
|
|
3054
|
+
passed: false,
|
|
3055
|
+
skipped: true,
|
|
3056
|
+
unavailable: true,
|
|
3057
|
+
durationMs,
|
|
3058
|
+
exitCode,
|
|
3059
|
+
outputTail: unavailableSignal.message,
|
|
3060
|
+
...this.customGateBaseline !== void 0 ? {
|
|
3061
|
+
isRegression: false
|
|
3062
|
+
} : {}
|
|
3063
|
+
});
|
|
3064
|
+
continue;
|
|
3065
|
+
}
|
|
3066
|
+
} else {
|
|
3067
|
+
durationMs = createDurationMs(performance.now() - start);
|
|
3068
|
+
results.push({
|
|
3069
|
+
id: gateId,
|
|
3070
|
+
command,
|
|
3071
|
+
passed: false,
|
|
3072
|
+
misconfigured: true,
|
|
3073
|
+
durationMs,
|
|
3074
|
+
outputTail: safety.error.includes("shell") || /[|&;<>()`]/u.test(command) ? "Custom gate misconfiguration: shell metacharacters are not supported. Use a verifier-safe command." : `Custom gate misconfiguration: ${safety.error.slice(-500)}`
|
|
3075
|
+
});
|
|
3076
|
+
continue;
|
|
3077
|
+
}
|
|
3078
|
+
results.push({
|
|
3079
|
+
id: gateId,
|
|
3080
|
+
command,
|
|
3081
|
+
passed,
|
|
3082
|
+
durationMs,
|
|
3083
|
+
exitCode,
|
|
3084
|
+
outputTail: passed ? void 0 : boundedOutputTail,
|
|
3085
|
+
...failureDiagnostics ? { diagnostics: failureDiagnostics } : {},
|
|
3086
|
+
...this.customGateBaseline !== void 0 ? {
|
|
3087
|
+
isRegression: this.isCustomGateRegression(gateId, passed)
|
|
3088
|
+
} : {}
|
|
3089
|
+
});
|
|
3090
|
+
if (!passed && this.isRunAborted()) {
|
|
3091
|
+
break;
|
|
3092
|
+
}
|
|
3093
|
+
} catch (err) {
|
|
3094
|
+
const durationMs = createDurationMs(performance.now() - start);
|
|
3095
|
+
const aborted = this.isRunAborted() || err instanceof Error && (err.name === "AbortError" || /aborted|timebox exceeded/i.test(err.message));
|
|
3096
|
+
results.push({
|
|
3097
|
+
id: gateId,
|
|
3098
|
+
command,
|
|
3099
|
+
passed: false,
|
|
3100
|
+
...aborted ? { skipped: true } : {},
|
|
3101
|
+
durationMs,
|
|
3102
|
+
outputTail: aborted ? "Custom gate aborted: autoloop timebox exceeded." : err instanceof Error ? err.message.slice(-500) : String(err).slice(-500)
|
|
3103
|
+
});
|
|
3104
|
+
if (aborted) {
|
|
3105
|
+
break;
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
return results;
|
|
3110
|
+
}
|
|
3111
|
+
isCustomGateRegression(gateId, passed) {
|
|
3112
|
+
if (passed) {
|
|
3113
|
+
return false;
|
|
3114
|
+
}
|
|
3115
|
+
if (!this.customGateBaseline) {
|
|
3116
|
+
return true;
|
|
3117
|
+
}
|
|
3118
|
+
const baselinePassed = this.customGateBaseline.get(gateId);
|
|
3119
|
+
if (baselinePassed === false) {
|
|
3120
|
+
return false;
|
|
3121
|
+
}
|
|
3122
|
+
return true;
|
|
3123
|
+
}
|
|
3124
|
+
/**
|
|
3125
|
+
* Determine if a quality gate result represents a NEW regression.
|
|
3126
|
+
* Compares current failure count against baseline to distinguish
|
|
3127
|
+
* pre-existing failures from new failures introduced this iteration.
|
|
3128
|
+
*
|
|
3129
|
+
* Coverage/test also enforces suite-footprint integrity: a greener count is
|
|
3130
|
+
* only non-blocking when executed/skipped footprints prove the suite did not
|
|
3131
|
+
* shrink or skip more tests. Lint and security keep count-only comparison.
|
|
3132
|
+
*
|
|
3133
|
+
* @param result - Quality gate check result
|
|
3134
|
+
* @returns true if this is a new regression, false if pre-existing or passed,
|
|
3135
|
+
* undefined when comparison is unknown (fail-closed)
|
|
3136
|
+
*/
|
|
3137
|
+
isQualityRegression(result) {
|
|
3138
|
+
if (!this.qualityBaseline || this.qualityBaseline.status !== "captured") {
|
|
3139
|
+
if (result.success) return false;
|
|
3140
|
+
return void 0;
|
|
3141
|
+
}
|
|
3142
|
+
const baselineGate = isTestEvidenceGate(result.gate) ? "coverage" : result.gate;
|
|
3143
|
+
if ((baselineGate === "lint" || baselineGate === "security" || baselineGate === "coverage") && this.qualityBaseline.gateAvailability[baselineGate] !== true) {
|
|
3144
|
+
if (result.success) return false;
|
|
3145
|
+
return void 0;
|
|
3146
|
+
}
|
|
3147
|
+
const baselineFailed = {
|
|
3148
|
+
lint: this.qualityBaseline.lintFailedCommands,
|
|
3149
|
+
coverage: this.qualityBaseline.testFailedCommands,
|
|
3150
|
+
security: this.qualityBaseline.securityFailedCommands
|
|
3151
|
+
}[baselineGate];
|
|
3152
|
+
if (!result.success && result.failedCommands && baselineFailed) {
|
|
3153
|
+
const perCommand = compareBucketCommands(
|
|
3154
|
+
baselineGate,
|
|
3155
|
+
result.failedCommands,
|
|
3156
|
+
baselineFailed,
|
|
3157
|
+
extractFailureCountWithMethod
|
|
3158
|
+
);
|
|
3159
|
+
if (perCommand !== null) return perCommand;
|
|
3160
|
+
}
|
|
3161
|
+
const currentResult = extractFailureCountWithMethod([result], result.gate);
|
|
3162
|
+
const currentFailures = currentResult.count;
|
|
3163
|
+
if (isTestEvidenceGate(result.gate)) {
|
|
3164
|
+
const baselineCommand = this.qualityBaseline.testEvidenceCommand;
|
|
3165
|
+
if (baselineCommand && result.command && baselineCommand !== result.command) {
|
|
3166
|
+
return void 0;
|
|
3167
|
+
}
|
|
3168
|
+
const classification = classifyCoverageBaselineComparison(
|
|
3169
|
+
{
|
|
3170
|
+
failures: this.qualityBaseline.testFailures,
|
|
3171
|
+
suiteFootprint: this.qualityBaseline.testSuiteFootprint,
|
|
3172
|
+
messages: this.qualityBaseline.testFailureMessages
|
|
3173
|
+
},
|
|
3174
|
+
{
|
|
3175
|
+
failures: currentFailures,
|
|
3176
|
+
suiteFootprint: currentResult.suiteFootprint,
|
|
3177
|
+
messages: currentResult.messages
|
|
3178
|
+
}
|
|
3179
|
+
);
|
|
3180
|
+
if (classification === "regression") {
|
|
3181
|
+
return true;
|
|
3182
|
+
}
|
|
3183
|
+
if (classification === "improvement" || classification === "pre_existing") {
|
|
3184
|
+
if ((currentFailures ?? 0) > 0) {
|
|
3185
|
+
this.telemetry?.logEvent({
|
|
3186
|
+
name: "quality_gate_pre_existing_failure",
|
|
3187
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3188
|
+
properties: {
|
|
3189
|
+
gate: result.gate,
|
|
3190
|
+
currentFailures,
|
|
3191
|
+
currentMethod: currentResult.method,
|
|
3192
|
+
baselineFailures: this.qualityBaseline.testFailures,
|
|
3193
|
+
baselineMethod: this.qualityBaseline.testFailuresMethod,
|
|
3194
|
+
classification
|
|
3195
|
+
}
|
|
3196
|
+
});
|
|
3197
|
+
}
|
|
3198
|
+
return false;
|
|
3199
|
+
}
|
|
3200
|
+
return void 0;
|
|
3201
|
+
}
|
|
3202
|
+
if (result.success) {
|
|
3203
|
+
return false;
|
|
3204
|
+
}
|
|
3205
|
+
let baselineFailures = 0;
|
|
3206
|
+
let baselineMethod;
|
|
3207
|
+
switch (result.gate) {
|
|
3208
|
+
case "lint":
|
|
3209
|
+
baselineFailures = this.qualityBaseline.lintErrors;
|
|
3210
|
+
baselineMethod = this.qualityBaseline.lintErrorsMethod;
|
|
3211
|
+
break;
|
|
3212
|
+
case "security":
|
|
3213
|
+
baselineFailures = this.qualityBaseline.securityFailures;
|
|
3214
|
+
baselineMethod = this.qualityBaseline.securityFailuresMethod;
|
|
3215
|
+
break;
|
|
3216
|
+
default:
|
|
3217
|
+
return true;
|
|
3218
|
+
}
|
|
3219
|
+
const unprovenSecurityCount = (method) => method === "fallback_1" || method === "unavailable_no_parser";
|
|
3220
|
+
if (result.gate === "security" && (unprovenSecurityCount(currentResult.method) || unprovenSecurityCount(baselineMethod))) {
|
|
3221
|
+
return true;
|
|
3222
|
+
}
|
|
3223
|
+
if (currentFailures === null || baselineFailures === null) {
|
|
3224
|
+
return void 0;
|
|
3225
|
+
}
|
|
3226
|
+
const guessed = currentResult.method === "fallback_1" || baselineMethod === "fallback_1";
|
|
3227
|
+
if (result.gate === "lint" && guessed) return void 0;
|
|
3228
|
+
const isRegression = currentFailures > baselineFailures;
|
|
3229
|
+
if (!isRegression && currentFailures > 0) {
|
|
3230
|
+
this.telemetry?.logEvent({
|
|
3231
|
+
name: "quality_gate_pre_existing_failure",
|
|
3232
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3233
|
+
properties: {
|
|
3234
|
+
gate: result.gate,
|
|
3235
|
+
currentFailures,
|
|
3236
|
+
currentMethod: currentResult.method,
|
|
3237
|
+
baselineFailures,
|
|
3238
|
+
baselineMethod
|
|
3239
|
+
}
|
|
3240
|
+
});
|
|
3241
|
+
}
|
|
3242
|
+
return isRegression;
|
|
3243
|
+
}
|
|
3244
|
+
/**
|
|
3245
|
+
* Detect if the iteration failed due to new TypeScript compilation errors.
|
|
3246
|
+
*
|
|
3247
|
+
* Compilation failure is indicated by typed controller metadata, the
|
|
3248
|
+
* ProgressValidator's structured insight, or a classified gate failure. Provider
|
|
3249
|
+
* output text is not used for this decision.
|
|
3250
|
+
*
|
|
3251
|
+
* This is used to block completion when new compilation errors exist.
|
|
3252
|
+
*
|
|
3253
|
+
* @param result - Loop iteration result to check
|
|
3254
|
+
* @returns true if compilation failure detected
|
|
3255
|
+
*/
|
|
3256
|
+
detectCompilationFailure(result) {
|
|
3257
|
+
if ((result.metadata?.compilationErrorDelta ?? 0) > 0) {
|
|
3258
|
+
return true;
|
|
3259
|
+
}
|
|
3260
|
+
if (hasCompilationProgressSignal(result.progress?.insights)) {
|
|
3261
|
+
return true;
|
|
3262
|
+
}
|
|
3263
|
+
return (result.qualityGates ?? []).some(
|
|
3264
|
+
(gate) => classifyQualityGateFailure(gate) === "compilation"
|
|
3265
|
+
);
|
|
3266
|
+
}
|
|
3267
|
+
/**
|
|
3268
|
+
* Compute deterministic completion summary based on hard signals.
|
|
3269
|
+
* Separates "done" (gates, provider, convergence) from heuristics.
|
|
3270
|
+
*
|
|
3271
|
+
* @param result - Current iteration result
|
|
3272
|
+
* @param completionSignalDetected - Whether explicit completion signal was found
|
|
3273
|
+
* @returns CompletionSummary with deterministic status
|
|
3274
|
+
*/
|
|
3275
|
+
computeCompletionSummary(result, completionSignalDetected, isCompletionOrBounds) {
|
|
3276
|
+
const semanticValidation = result.semanticValidation;
|
|
3277
|
+
return evaluateCompletion({
|
|
3278
|
+
result,
|
|
3279
|
+
completionSignalDetected,
|
|
3280
|
+
isCompletionOrBounds,
|
|
3281
|
+
validationMode: this.config.validationMode,
|
|
3282
|
+
runQualityGates: this.config.runQualityGates,
|
|
3283
|
+
priorIterationFingerprints: this.iterationHistory.map((h) => h.iterationFingerprint),
|
|
3284
|
+
priorCompletenessSignals: this.iterationHistory.map((h) => h.progress.metrics.completeness),
|
|
3285
|
+
hasDurableCompletionEvidence: this.hasDurableCompletionEvidence(result),
|
|
3286
|
+
semanticCompletionOk: isSemanticCompletionSatisfied(semanticValidation),
|
|
3287
|
+
semanticIsErrorSkip: isSemanticErrorSkip(semanticValidation?.skipped)
|
|
3288
|
+
});
|
|
3289
|
+
}
|
|
3290
|
+
hasSubstantiveCompletionEvidence(result) {
|
|
3291
|
+
return hasSubstantiveCompletionEvidence(result, this.hasDurableCompletionEvidence(result));
|
|
3292
|
+
}
|
|
3293
|
+
hasDurableCompletionEvidence(result) {
|
|
3294
|
+
return result.completionEvidence?.durable === true;
|
|
3295
|
+
}
|
|
3296
|
+
/**
|
|
3297
|
+
* Get AI Judge evaluation if enabled
|
|
3298
|
+
*/
|
|
3299
|
+
async getAIJudgeEvaluation(_iteration, _taskResult, progress) {
|
|
3300
|
+
if (!this.aiJudge) return void 0;
|
|
3301
|
+
try {
|
|
3302
|
+
const variantResult = {
|
|
3303
|
+
variant: `iteration-${_iteration}`,
|
|
3304
|
+
provider: "autonomous-loop",
|
|
3305
|
+
success: progress.isSignificant,
|
|
3306
|
+
completeness: progress.score * 100,
|
|
3307
|
+
output: typeof _taskResult === "object" ? JSON.stringify(_taskResult) : String(_taskResult),
|
|
3308
|
+
duration: 0,
|
|
3309
|
+
// Will be filled by iteration result
|
|
3310
|
+
costMetrics: void 0
|
|
3311
|
+
};
|
|
3312
|
+
const remainingMs = this.ensureRemainingTimeboxMs("AI judge evaluation");
|
|
3313
|
+
const deadlineMs = Date.now() + remainingMs;
|
|
3314
|
+
const judgeResult = await this.aiJudge.evaluate(
|
|
3315
|
+
[variantResult],
|
|
3316
|
+
`Iteration ${_iteration} progress evaluation`,
|
|
3317
|
+
{
|
|
3318
|
+
taskId: `loop-iteration-${_iteration}`,
|
|
3319
|
+
deadlineMs,
|
|
3320
|
+
abortSignal: this.config.abortSignal
|
|
3321
|
+
}
|
|
3322
|
+
);
|
|
3323
|
+
const evaluation = judgeResult.evaluations[0];
|
|
3324
|
+
const recommendation = this.determineRecommendation(
|
|
3325
|
+
evaluation?.qualityScore ?? progress.score * 100,
|
|
3326
|
+
progress
|
|
3327
|
+
);
|
|
3328
|
+
const result = {
|
|
3329
|
+
overallScore: evaluation?.qualityScore ?? progress.score * 100,
|
|
3330
|
+
criteria: evaluation?.codeQuality ?? {
|
|
3331
|
+
completeness: progress.metrics.completeness * 100
|
|
3332
|
+
},
|
|
3333
|
+
recommendation,
|
|
3334
|
+
reasoning: judgeResult.reasoning || `Progress: ${(progress.score * 100).toFixed(1)}%`,
|
|
3335
|
+
confidence: judgeResult.metadata?.confidence ?? progress.confidence
|
|
3336
|
+
};
|
|
3337
|
+
this.emit("ai_judge_evaluation", {
|
|
3338
|
+
type: "ai_judge_evaluation",
|
|
3339
|
+
evaluation: result
|
|
3340
|
+
});
|
|
3341
|
+
return result;
|
|
3342
|
+
} catch (error) {
|
|
3343
|
+
this.telemetry?.trackError(error, {
|
|
3344
|
+
_iteration,
|
|
3345
|
+
context: "ai_judge"
|
|
3346
|
+
});
|
|
3347
|
+
return void 0;
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
3350
|
+
/**
|
|
3351
|
+
* Count actual change lines in a git diff (lines starting with + or -).
|
|
3352
|
+
* Excludes diff metadata lines (@@, diff, index, ---, +++).
|
|
3353
|
+
*/
|
|
3354
|
+
countActualDiffLines(gitDiff) {
|
|
3355
|
+
let count = 0;
|
|
3356
|
+
for (const line of gitDiff.split("\n")) {
|
|
3357
|
+
if ((line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")) {
|
|
3358
|
+
count++;
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
return count;
|
|
3362
|
+
}
|
|
3363
|
+
/**
|
|
3364
|
+
* Run semantic validation using AI-powered progress checks.
|
|
3365
|
+
*
|
|
3366
|
+
* This validates:
|
|
3367
|
+
* 1. Progress toward goals (via semantic-progress-rater)
|
|
3368
|
+
* 2. Acceptance criteria satisfaction (via acceptance-criteria-checker)
|
|
3369
|
+
*
|
|
3370
|
+
* Graceful degradation: If provider calls fail (auth errors, timeouts, parse errors),
|
|
3371
|
+
* semantic validation is skipped with a warning rather than failing the loop (unless strictMode).
|
|
3372
|
+
* Routing (provider and model) is resolved by the caller; when no override is given, checks run on the
|
|
3373
|
+
* task's own engine/model, and missing provider/auth simply logs a warning and continues without
|
|
3374
|
+
* validation. The CLI gates only at completion boundaries by default; the check itself is opt-in.
|
|
3375
|
+
* Provider/auth warnings become hard failures only when `strictMode` is true (default false).
|
|
3376
|
+
*
|
|
3377
|
+
* Mode behavior:
|
|
3378
|
+
* - `completion-only` (default): Only runs when `isCompletionOrBounds` is true
|
|
3379
|
+
* - `every-iteration`: Runs every N iterations (controlled by runEveryNIterations)
|
|
3380
|
+
*
|
|
3381
|
+
* @param iteration - Current iteration number
|
|
3382
|
+
* @param _outputForChecks - Provider output text for checks
|
|
3383
|
+
* @param isCompletionOrBounds - True if completion signal matched or at bounds (last iteration)
|
|
3384
|
+
* @returns Semantic validation result
|
|
3385
|
+
*/
|
|
3386
|
+
async runSemanticValidation(iteration, _outputForChecks, isCompletionOrBounds) {
|
|
3387
|
+
const config = this.config.semanticCheck;
|
|
3388
|
+
if (!config?.enabled) {
|
|
3389
|
+
return semanticDisabled();
|
|
3390
|
+
}
|
|
3391
|
+
const mode = config.mode ?? "completion-only";
|
|
3392
|
+
if (mode === "completion-only" && !isCompletionOrBounds) {
|
|
3393
|
+
return semanticSkipped("not_completion_bounds");
|
|
3394
|
+
}
|
|
3395
|
+
if (!config.provider) {
|
|
3396
|
+
emitWarning(
|
|
3397
|
+
"SEM-000",
|
|
3398
|
+
{
|
|
3399
|
+
taskId: "semantic-validation",
|
|
3400
|
+
subsystem: "autonomous-loop-controller",
|
|
3401
|
+
executionPhase: "validation"
|
|
3402
|
+
},
|
|
3403
|
+
{
|
|
3404
|
+
severity: "WARN" /* WARN */,
|
|
3405
|
+
metadata: {
|
|
3406
|
+
error: "Semantic validation enabled but no provider configured; skipping",
|
|
3407
|
+
iteration
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
);
|
|
3411
|
+
return semanticSkipped("provider_error");
|
|
3412
|
+
}
|
|
3413
|
+
if (mode === "every-iteration") {
|
|
3414
|
+
const runEveryN = config.runEveryNIterations ?? 1;
|
|
3415
|
+
if (runEveryN > 1 && iteration % runEveryN !== 0) {
|
|
3416
|
+
return semanticSkipped("iteration_skip");
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
const baseRef = this.semanticBaselineRef ?? this.config.progressConfig.baseRef ?? "HEAD~1";
|
|
3420
|
+
let gitDiff;
|
|
3421
|
+
try {
|
|
3422
|
+
if (!isSafeGitRef(baseRef)) {
|
|
3423
|
+
throw new Error(`Invalid git baseRef: "${baseRef}"`);
|
|
3424
|
+
}
|
|
3425
|
+
const { execFileSync } = await import("child_process");
|
|
3426
|
+
gitDiff = execFileSync("git", ["diff", baseRef], {
|
|
3427
|
+
cwd: this.workingDir,
|
|
3428
|
+
timeout: 1e4,
|
|
3429
|
+
maxBuffer: 5 * 1024 * 1024,
|
|
3430
|
+
// 5MB
|
|
3431
|
+
encoding: "utf-8",
|
|
3432
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3433
|
+
}).trim();
|
|
3434
|
+
} catch (error) {
|
|
3435
|
+
this.telemetry?.logEvent({
|
|
3436
|
+
name: "semantic_validation_skipped",
|
|
3437
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3438
|
+
properties: {
|
|
3439
|
+
iteration,
|
|
3440
|
+
reason: "git_diff_failed",
|
|
3441
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3442
|
+
}
|
|
3443
|
+
});
|
|
3444
|
+
return semanticSkipped("provider_error");
|
|
3445
|
+
}
|
|
3446
|
+
const taskText = this.config.requirementsTaskText;
|
|
3447
|
+
if (!taskText) {
|
|
3448
|
+
return semanticSkipped("no_task_spec");
|
|
3449
|
+
}
|
|
3450
|
+
gitDiff = filterSemanticValidationDiff(gitDiff, taskText).trim();
|
|
3451
|
+
const minDiffLines = config.minDiffLines ?? 10;
|
|
3452
|
+
const actualDiffLines = this.countActualDiffLines(gitDiff);
|
|
3453
|
+
if (!isCompletionOrBounds && actualDiffLines < minDiffLines) {
|
|
3454
|
+
return semanticSkipped("trivial_diff");
|
|
3455
|
+
}
|
|
3456
|
+
const remainingMs = this.ensureRemainingTimeboxMs("semantic validation");
|
|
3457
|
+
const deadlineMs = Date.now() + remainingMs;
|
|
3458
|
+
const abortSignal = this.config.abortSignal;
|
|
3459
|
+
const configuredTimeoutMs = config.timeoutMs;
|
|
3460
|
+
const timeoutMs = configuredTimeoutMs != null ? Math.min(configuredTimeoutMs, remainingMs) : remainingMs;
|
|
3461
|
+
let progressResult;
|
|
3462
|
+
try {
|
|
3463
|
+
progressResult = await rateProgress(taskText, gitDiff, {
|
|
3464
|
+
provider: config.provider,
|
|
3465
|
+
workingDir: this.workingDir,
|
|
3466
|
+
profile: config.profile,
|
|
3467
|
+
model: config.model,
|
|
3468
|
+
timeoutMs,
|
|
3469
|
+
deadlineMs,
|
|
3470
|
+
abortSignal,
|
|
3471
|
+
workspaceMode: config.workspaceMode
|
|
3472
|
+
});
|
|
3473
|
+
} catch (error) {
|
|
3474
|
+
if (config.strictMode) throw error;
|
|
3475
|
+
emitWarning(
|
|
3476
|
+
"SEM-001",
|
|
3477
|
+
{
|
|
3478
|
+
taskId: "semantic-validation",
|
|
3479
|
+
subsystem: "autonomous-loop-controller",
|
|
3480
|
+
executionPhase: "validation"
|
|
3481
|
+
},
|
|
3482
|
+
{
|
|
3483
|
+
severity: "WARN" /* WARN */,
|
|
3484
|
+
metadata: {
|
|
3485
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3486
|
+
iteration,
|
|
3487
|
+
operation: "rateProgress"
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
);
|
|
3491
|
+
return semanticSkipped("provider_error");
|
|
3492
|
+
}
|
|
3493
|
+
let acResults = [];
|
|
3494
|
+
let satisfactionScore = 0;
|
|
3495
|
+
try {
|
|
3496
|
+
acResults = await checkAcceptanceCriteria(taskText, gitDiff, {
|
|
3497
|
+
provider: config.provider,
|
|
3498
|
+
workingDir: this.workingDir,
|
|
3499
|
+
profile: config.profile,
|
|
3500
|
+
model: config.model,
|
|
3501
|
+
timeoutMs,
|
|
3502
|
+
deadlineMs,
|
|
3503
|
+
abortSignal,
|
|
3504
|
+
workspaceMode: config.workspaceMode
|
|
3505
|
+
});
|
|
3506
|
+
const hasAnyConfidence = acResults.some((r) => r.confidence > 0);
|
|
3507
|
+
if (acResults.length > 0 && !hasAnyConfidence) {
|
|
3508
|
+
emitWarning(
|
|
3509
|
+
"SEM-002",
|
|
3510
|
+
{
|
|
3511
|
+
taskId: "semantic-validation",
|
|
3512
|
+
subsystem: "autonomous-loop-controller",
|
|
3513
|
+
executionPhase: "validation"
|
|
3514
|
+
},
|
|
3515
|
+
{
|
|
3516
|
+
severity: "WARN" /* WARN */,
|
|
3517
|
+
metadata: {
|
|
3518
|
+
error: "All acceptance criteria checks returned zero confidence; evaluating as unsatisfied",
|
|
3519
|
+
iteration,
|
|
3520
|
+
operation: "checkAcceptanceCriteria"
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
);
|
|
3524
|
+
}
|
|
3525
|
+
if (acResults.length > 0) satisfactionScore = calculateSatisfactionScore(acResults);
|
|
3526
|
+
} catch (error) {
|
|
3527
|
+
if (config.strictMode) throw error;
|
|
3528
|
+
emitWarning(
|
|
3529
|
+
"SEM-002",
|
|
3530
|
+
{
|
|
3531
|
+
taskId: "semantic-validation",
|
|
3532
|
+
subsystem: "autonomous-loop-controller",
|
|
3533
|
+
executionPhase: "validation"
|
|
3534
|
+
},
|
|
3535
|
+
{
|
|
3536
|
+
severity: "WARN" /* WARN */,
|
|
3537
|
+
metadata: {
|
|
3538
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3539
|
+
iteration,
|
|
3540
|
+
operation: "checkAcceptanceCriteria"
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
);
|
|
3544
|
+
return semanticSkipped("provider_error");
|
|
3545
|
+
}
|
|
3546
|
+
let passed;
|
|
3547
|
+
const minProgressConfidence = this.config.progressConfig.confidenceThreshold ?? 0.7;
|
|
3548
|
+
const significantProgress = isSignificantProgress(progressResult, minProgressConfidence);
|
|
3549
|
+
if (acResults.length > 0) {
|
|
3550
|
+
passed = significantProgress || satisfactionScore >= 0.5;
|
|
3551
|
+
} else {
|
|
3552
|
+
passed = significantProgress;
|
|
3553
|
+
}
|
|
3554
|
+
this.telemetry?.logEvent({
|
|
3555
|
+
name: "semantic_validation_complete",
|
|
3556
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3557
|
+
properties: {
|
|
3558
|
+
iteration,
|
|
3559
|
+
movedCloser: progressResult.movedCloser,
|
|
3560
|
+
progressConfidence: progressResult.confidence,
|
|
3561
|
+
satisfactionScore,
|
|
3562
|
+
totalACs: acResults.length,
|
|
3563
|
+
satisfiedACs: acResults.filter((r) => r.satisfied).length,
|
|
3564
|
+
passed,
|
|
3565
|
+
hasACs: acResults.length > 0
|
|
3566
|
+
}
|
|
3567
|
+
});
|
|
3568
|
+
return {
|
|
3569
|
+
enabled: true,
|
|
3570
|
+
passed,
|
|
3571
|
+
progressResult,
|
|
3572
|
+
acResults,
|
|
3573
|
+
satisfactionScore
|
|
3574
|
+
};
|
|
3575
|
+
}
|
|
3576
|
+
/**
|
|
3577
|
+
* Determine recommendation based on score and progress trends
|
|
3578
|
+
*/
|
|
3579
|
+
determineRecommendation(score, progress) {
|
|
3580
|
+
if (score >= 80 && progress.trend === "improving") return "continue";
|
|
3581
|
+
if (score >= 80 && progress.trend === "stable" && !progress.isSignificant) return "terminate";
|
|
3582
|
+
if (score < 40 && progress.trend === "declining") return "terminate";
|
|
3583
|
+
if (progress.isSignificant) return "continue";
|
|
3584
|
+
return score >= 60 ? "continue" : "pivot";
|
|
3585
|
+
}
|
|
3586
|
+
/**
|
|
3587
|
+
* Handle a 'pivot' recommendation from determineRecommendation.
|
|
3588
|
+
*
|
|
3589
|
+
* Behavior depends on the BUILD_CROSS_PROVIDER_PIVOT feature flag:
|
|
3590
|
+
* - 'off': No action taken
|
|
3591
|
+
* - 'shadow': Emits telemetry events but does not switch provider
|
|
3592
|
+
* - 'on': Switches to the next configured alternate provider
|
|
3593
|
+
*/
|
|
3594
|
+
async handlePivotRecommendation(result) {
|
|
3595
|
+
if (!this.config.enableCrossProviderPivot) return;
|
|
3596
|
+
const flagMode = ORCHESTRATOR_FEATURE_FLAGS.CROSS_PROVIDER_PIVOT;
|
|
3597
|
+
if (flagMode === "off") return;
|
|
3598
|
+
const fromProvider = this.currentProvider ?? this.config.routingDecision?.primary.provider ?? "unknown";
|
|
3599
|
+
const nextAlternate = this.availableAlternates.find(
|
|
3600
|
+
(alt) => alt.provider !== this.currentProvider
|
|
3601
|
+
);
|
|
3602
|
+
this.emit("pivot_triggered", {
|
|
3603
|
+
type: "pivot_triggered",
|
|
3604
|
+
iteration: result._iteration,
|
|
3605
|
+
fromProvider,
|
|
3606
|
+
toProvider: nextAlternate?.provider,
|
|
3607
|
+
reason: `Score ${result.judgeEvaluation?.overallScore ?? "N/A"} < 60 with insufficient progress`,
|
|
3608
|
+
mode: flagMode
|
|
3609
|
+
});
|
|
3610
|
+
this.telemetry?.logEvent({
|
|
3611
|
+
name: "cross_provider_pivot_triggered",
|
|
3612
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3613
|
+
properties: {
|
|
3614
|
+
iteration: result._iteration,
|
|
3615
|
+
fromProvider,
|
|
3616
|
+
toProvider: nextAlternate?.provider ?? null,
|
|
3617
|
+
mode: flagMode,
|
|
3618
|
+
score: result.judgeEvaluation?.overallScore,
|
|
3619
|
+
hasAlternates: this.availableAlternates.length > 0
|
|
3620
|
+
}
|
|
3621
|
+
});
|
|
3622
|
+
if (flagMode === "shadow") return;
|
|
3623
|
+
if (nextAlternate) {
|
|
3624
|
+
const previousProvider = this.currentProvider;
|
|
3625
|
+
this.currentProvider = nextAlternate.provider;
|
|
3626
|
+
this.currentProviderSetup = nextAlternate.setup;
|
|
3627
|
+
this.availableAlternates = this.availableAlternates.filter(
|
|
3628
|
+
(alt) => alt.provider !== nextAlternate.provider
|
|
3629
|
+
);
|
|
3630
|
+
this.emit("provider_switched", {
|
|
3631
|
+
type: "provider_switched",
|
|
3632
|
+
iteration: result._iteration,
|
|
3633
|
+
fromProvider: previousProvider ?? "unknown",
|
|
3634
|
+
toProvider: nextAlternate.provider
|
|
3635
|
+
});
|
|
3636
|
+
this.telemetry?.logEvent({
|
|
3637
|
+
name: "cross_provider_switched",
|
|
3638
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3639
|
+
properties: {
|
|
3640
|
+
iteration: result._iteration,
|
|
3641
|
+
fromProvider: previousProvider,
|
|
3642
|
+
toProvider: nextAlternate.provider,
|
|
3643
|
+
remainingAlternates: this.availableAlternates.length
|
|
3644
|
+
}
|
|
3645
|
+
});
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
/**
|
|
3649
|
+
* Check if loop should terminate
|
|
3650
|
+
*/
|
|
3651
|
+
async shouldTerminate(_iteration) {
|
|
3652
|
+
if (this.state.status !== "running") {
|
|
3653
|
+
return true;
|
|
3654
|
+
}
|
|
3655
|
+
const elapsed = this.getElapsedRuntimeMs();
|
|
3656
|
+
if (elapsed >= this.config.timeboxMs) {
|
|
3657
|
+
this.terminate("timebox_exceeded");
|
|
3658
|
+
return true;
|
|
3659
|
+
}
|
|
3660
|
+
const resources = getResourceUsage();
|
|
3661
|
+
if (resources.memory.heapUsed > this.config.resourceLimits.maxMemoryMB * 1024 * 1024) {
|
|
3662
|
+
this.terminate("resource_exhaustion");
|
|
3663
|
+
return true;
|
|
3664
|
+
}
|
|
3665
|
+
if (!this.recursionTracker.canSpawnChildren()) {
|
|
3666
|
+
this.terminate("recursion_limit");
|
|
3667
|
+
return true;
|
|
3668
|
+
}
|
|
3669
|
+
return false;
|
|
3670
|
+
}
|
|
3671
|
+
/**
|
|
3672
|
+
* Check if loop should continue based on progress, completion signal, and validation mode.
|
|
3673
|
+
*
|
|
3674
|
+
* Termination priority (first match wins):
|
|
3675
|
+
* 1. Iteration failure → retry if under limit
|
|
3676
|
+
* 2. Compilation failure (new TS errors) → continue (cannot complete with compilation errors)
|
|
3677
|
+
* 3. Completion signal matched → terminate with 'completion_signal' (unless blocked by gates)
|
|
3678
|
+
* - Gates: quality regressions, requirements, progress (heuristic), semantic validation
|
|
3679
|
+
* - Semantic check gates completion: if enabled and fails, ignore completion signal
|
|
3680
|
+
* - At bounds + semantic fails → terminate with 'semantic_criteria_unsatisfied'
|
|
3681
|
+
* 4. Bounds reached + semantic fails → terminate with 'semantic_criteria_unsatisfied'
|
|
3682
|
+
* 5. Deterministic mode + all quality gates pass (or non-regressions only) → terminate
|
|
3683
|
+
* 6. Heuristic mode: completion threshold / stagnation / AI Judge
|
|
3684
|
+
* 7. None mode: only bounds + completion signal can stop (no stagnation detection)
|
|
3685
|
+
*
|
|
3686
|
+
* Baseline-aware rules:
|
|
3687
|
+
* - Quality gate failures with isRegression === false (pre-existing) do NOT block completion
|
|
3688
|
+
* - Only gates with isRegression === true block completion
|
|
3689
|
+
*
|
|
3690
|
+
* Semantic validation as gate (not parallel termination):
|
|
3691
|
+
* - Semantic check is a gate on "DONE" (completion signal or bounds)
|
|
3692
|
+
* - It does NOT terminate mid-loop on its own; only at completion/bounds checkpoints
|
|
3693
|
+
*/
|
|
3694
|
+
async shouldContinue(result) {
|
|
3695
|
+
if (this.state.status === "terminated") {
|
|
3696
|
+
return false;
|
|
3697
|
+
}
|
|
3698
|
+
if (!result.success) {
|
|
3699
|
+
const initialDisposition = result.failureRecovery?.recovery.disposition;
|
|
3700
|
+
if (initialDisposition === "operator_stop") {
|
|
3701
|
+
this.terminate("system_error");
|
|
3702
|
+
return false;
|
|
3703
|
+
}
|
|
3704
|
+
if (this.tryIdleStopAfterRealFirstDelivery(result)) {
|
|
3705
|
+
if (result.failureRecovery) {
|
|
3706
|
+
result.failureRecovery = serializeDirectAutoloopFailureRecovery(
|
|
3707
|
+
result.failureRecovery.failure,
|
|
3708
|
+
"delivery_rescue"
|
|
3709
|
+
);
|
|
3710
|
+
}
|
|
3711
|
+
return false;
|
|
3712
|
+
}
|
|
3713
|
+
if (initialDisposition === "terminal_stop") {
|
|
3714
|
+
this.telemetry?.logEvent({
|
|
3715
|
+
name: "autoloop_terminal_failure_stop",
|
|
3716
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3717
|
+
properties: {
|
|
3718
|
+
iteration: result._iteration,
|
|
3719
|
+
category: result.failureRecovery?.failure.category,
|
|
3720
|
+
evidenceSource: result.failureRecovery?.failure.evidenceSource
|
|
3721
|
+
}
|
|
3722
|
+
});
|
|
3723
|
+
this.terminate("system_error");
|
|
3724
|
+
return false;
|
|
3725
|
+
}
|
|
3726
|
+
if (this.lastIterationReturnedFailure) return true;
|
|
3727
|
+
if (result.error) {
|
|
3728
|
+
const signature = computeErrorSignature(result);
|
|
3729
|
+
if (signature.hash === this.lastErrorSignature) {
|
|
3730
|
+
this.consecutiveIdenticalCount += 1;
|
|
3731
|
+
} else {
|
|
3732
|
+
this.consecutiveIdenticalCount = 1;
|
|
3733
|
+
}
|
|
3734
|
+
this.lastErrorSignature = signature.hash;
|
|
3735
|
+
if (this.consecutiveIdenticalCount >= 2) {
|
|
3736
|
+
this.telemetry?.logEvent({
|
|
3737
|
+
name: "autoloop_identical_error_exit",
|
|
3738
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3739
|
+
properties: {
|
|
3740
|
+
iteration: result._iteration,
|
|
3741
|
+
signature: signature.hash,
|
|
3742
|
+
components: signature.components,
|
|
3743
|
+
consecutiveCount: this.consecutiveIdenticalCount
|
|
3744
|
+
}
|
|
3745
|
+
});
|
|
3746
|
+
this.terminate("identical_error_pattern");
|
|
3747
|
+
return false;
|
|
3748
|
+
}
|
|
3749
|
+
} else {
|
|
3750
|
+
this.lastErrorSignature = null;
|
|
3751
|
+
this.consecutiveIdenticalCount = 0;
|
|
3752
|
+
}
|
|
3753
|
+
return this.continueAfterFailureOrTerminate();
|
|
3754
|
+
}
|
|
3755
|
+
this.lastErrorSignature = null;
|
|
3756
|
+
this.consecutiveIdenticalCount = 0;
|
|
3757
|
+
const requirementsUnmet = Boolean(result.requirements?.enabled && !result.requirements.passed);
|
|
3758
|
+
const hasCompilationFailure = this.detectCompilationFailure(result);
|
|
3759
|
+
if (hasCompilationFailure) {
|
|
3760
|
+
this.telemetry?.logEvent({
|
|
3761
|
+
name: "completion_blocked_compilation_errors",
|
|
3762
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3763
|
+
properties: {
|
|
3764
|
+
iteration: result._iteration,
|
|
3765
|
+
progressScore: result.progress.score
|
|
3766
|
+
}
|
|
3767
|
+
});
|
|
3768
|
+
return true;
|
|
3769
|
+
}
|
|
3770
|
+
if (result.completionSummary?.status === "BASELINE_BLOCKED") {
|
|
3771
|
+
this.telemetry?.logEvent({
|
|
3772
|
+
name: "loop_terminated_baseline_blocked",
|
|
3773
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3774
|
+
properties: {
|
|
3775
|
+
iteration: result._iteration,
|
|
3776
|
+
baselineGateCount: (result.qualityGates?.filter((gate) => !gate.passed && gate.isRegression === false).length ?? 0) + (result.customGateResults?.filter((gate) => !gate.passed && gate.isRegression === false).length ?? 0)
|
|
3777
|
+
}
|
|
3778
|
+
});
|
|
3779
|
+
this.terminate("baseline_blocked");
|
|
3780
|
+
return false;
|
|
3781
|
+
}
|
|
3782
|
+
if (this.tryIdleStopAfterRealFirstDelivery(result)) {
|
|
3783
|
+
return false;
|
|
3784
|
+
}
|
|
3785
|
+
if (this.completionSignalMatched) {
|
|
3786
|
+
const enabled = idleStopEnabledChecksFromConfig(this.config);
|
|
3787
|
+
if (isUnconfirmableGatesOffDelivery(this.deliverySnapshot(result), enabled)) {
|
|
3788
|
+
this.terminate("completion_unconfirmable");
|
|
3789
|
+
return false;
|
|
3790
|
+
}
|
|
3791
|
+
const customGatesOk = customGatesAllowCompletion(result.customGateResults);
|
|
3792
|
+
const blockingQualityGates = (result.qualityGates ?? []).filter(
|
|
3793
|
+
(gate) => isBlockingQualityGateForCompletion(gate) && !(customGatesOk && isUnavailableOrSkippedQualityGate(gate))
|
|
3794
|
+
);
|
|
3795
|
+
if (blockingQualityGates.length > 0) {
|
|
3796
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3797
|
+
iteration: result._iteration,
|
|
3798
|
+
gate: "quality_regression"
|
|
3799
|
+
});
|
|
3800
|
+
this.telemetry?.logEvent({
|
|
3801
|
+
name: "completion_signal_ignored_failed_gates",
|
|
3802
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3803
|
+
properties: {
|
|
3804
|
+
iteration: result._iteration,
|
|
3805
|
+
signalType: this.config.completionSignal?.type,
|
|
3806
|
+
failingGateIds: blockingQualityGates.map((g) => g.gateId),
|
|
3807
|
+
preExistingFailures: result.qualityGates?.filter((g) => !g.passed && g.isRegression === false).map((g) => g.gateId)
|
|
3808
|
+
}
|
|
3809
|
+
});
|
|
3810
|
+
return true;
|
|
3811
|
+
}
|
|
3812
|
+
const blockingCustomGates = (result.customGateResults ?? []).filter(
|
|
3813
|
+
isBlockingCustomGateForCompletion
|
|
3814
|
+
);
|
|
3815
|
+
if (blockingCustomGates.length > 0) {
|
|
3816
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3817
|
+
iteration: result._iteration,
|
|
3818
|
+
gate: "custom_regression"
|
|
3819
|
+
});
|
|
3820
|
+
this.telemetry?.logEvent({
|
|
3821
|
+
name: "completion_signal_ignored_failed_custom_gates",
|
|
3822
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3823
|
+
properties: {
|
|
3824
|
+
iteration: result._iteration,
|
|
3825
|
+
signalType: this.config.completionSignal?.type,
|
|
3826
|
+
failingGateIds: blockingCustomGates.map((g) => g.id),
|
|
3827
|
+
preExistingFailures: result.customGateResults?.filter((g) => !g.passed && g.isRegression === false).map((g) => g.id)
|
|
3828
|
+
}
|
|
3829
|
+
});
|
|
3830
|
+
return true;
|
|
3831
|
+
}
|
|
3832
|
+
const verificationEvidenceSatisfied = qualityGatesAllowCompletion(result.qualityGates) || customGatesOk;
|
|
3833
|
+
if (this.config.runQualityGates && !verificationEvidenceSatisfied) {
|
|
3834
|
+
if (verificationGatesUnavailableOnly({
|
|
3835
|
+
qualityGates: result.qualityGates,
|
|
3836
|
+
customGateResults: result.customGateResults
|
|
3837
|
+
})) {
|
|
3838
|
+
if (this.tryCompleteUnavailableOnlyDelivery(result)) {
|
|
3839
|
+
return false;
|
|
3840
|
+
}
|
|
3841
|
+
this.telemetry?.logEvent({
|
|
3842
|
+
name: "loop_terminated_verification_unavailable",
|
|
3843
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3844
|
+
properties: {
|
|
3845
|
+
iteration: result._iteration,
|
|
3846
|
+
signalType: this.config.completionSignal?.type,
|
|
3847
|
+
gateCount: result.qualityGates?.length ?? 0,
|
|
3848
|
+
customGateCount: result.customGateResults?.length ?? 0
|
|
3849
|
+
}
|
|
3850
|
+
});
|
|
3851
|
+
this.terminate("verification_unavailable");
|
|
3852
|
+
return false;
|
|
3853
|
+
}
|
|
3854
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3855
|
+
iteration: result._iteration,
|
|
3856
|
+
gate: "quality_unverified"
|
|
3857
|
+
});
|
|
3858
|
+
this.telemetry?.logEvent({
|
|
3859
|
+
name: "completion_signal_ignored_unverified_gates",
|
|
3860
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3861
|
+
properties: {
|
|
3862
|
+
iteration: result._iteration,
|
|
3863
|
+
signalType: this.config.completionSignal?.type,
|
|
3864
|
+
gateCount: result.qualityGates?.length ?? 0,
|
|
3865
|
+
skippedGateIds: result.qualityGates?.filter((g) => g.skipped === true).map((g) => g.gateId),
|
|
3866
|
+
customGateCount: result.customGateResults?.length ?? 0,
|
|
3867
|
+
skippedCustomGateIds: result.customGateResults?.filter((g) => g.skipped === true).map((g) => g.id)
|
|
3868
|
+
}
|
|
3869
|
+
});
|
|
3870
|
+
return true;
|
|
3871
|
+
}
|
|
3872
|
+
if (requirementsUnmet) {
|
|
3873
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3874
|
+
iteration: result._iteration,
|
|
3875
|
+
gate: "requirements",
|
|
3876
|
+
coverage: result.requirements?.coverage
|
|
3877
|
+
});
|
|
3878
|
+
this.telemetry?.logEvent({
|
|
3879
|
+
name: "completion_signal_ignored_requirements_unmet",
|
|
3880
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3881
|
+
properties: {
|
|
3882
|
+
iteration: result._iteration,
|
|
3883
|
+
coverage: result.requirements?.coverage,
|
|
3884
|
+
blockingIssues: result.requirements?.blockingIssues?.slice(0, 5)
|
|
3885
|
+
}
|
|
3886
|
+
});
|
|
3887
|
+
return true;
|
|
3888
|
+
}
|
|
3889
|
+
const hasPositiveVerificationEvidence = qualityGatesAllowCompletion(result.qualityGates) || customGatesOk;
|
|
3890
|
+
if (this.config.validationMode === "heuristic" && result.progress.verificationUnavailable === true && !hasPositiveVerificationEvidence && this.config.qualityGatePolicy !== "explicitly_disabled") {
|
|
3891
|
+
this.telemetry?.logEvent({
|
|
3892
|
+
name: "loop_terminated_verification_unavailable",
|
|
3893
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3894
|
+
properties: {
|
|
3895
|
+
iteration: result._iteration,
|
|
3896
|
+
signalType: this.config.completionSignal?.type,
|
|
3897
|
+
reason: result.progress.verificationUnavailableReason
|
|
3898
|
+
}
|
|
3899
|
+
});
|
|
3900
|
+
this.terminate("verification_unavailable");
|
|
3901
|
+
return false;
|
|
3902
|
+
}
|
|
3903
|
+
const styleOnlyEvidence = hasPositiveVerificationEvidence && hasOnlyStyleVerificationEvidence(result);
|
|
3904
|
+
if (this.config.validationMode === "heuristic" && (!hasPositiveVerificationEvidence || styleOnlyEvidence)) {
|
|
3905
|
+
const COMPLETION_SIGNAL_MIN_SCORE = 0.3;
|
|
3906
|
+
const validationUnavailable = !styleOnlyEvidence && (result.progress.toolingFailure === true || result.progress.verificationUnavailable === true);
|
|
3907
|
+
const durableEvidenceCanSubstituteForTooling = validationUnavailable && this.hasDurableCompletionEvidence(result);
|
|
3908
|
+
const isProgressSufficient = durableEvidenceCanSubstituteForTooling || !validationUnavailable && result.progress.trend !== "declining" && (result.progress.isSignificant || result.progress.score >= COMPLETION_SIGNAL_MIN_SCORE);
|
|
3909
|
+
if (!isProgressSufficient) {
|
|
3910
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3911
|
+
iteration: result._iteration,
|
|
3912
|
+
gate: "progress",
|
|
3913
|
+
trend: result.progress.trend
|
|
3914
|
+
});
|
|
3915
|
+
this.telemetry?.logEvent({
|
|
3916
|
+
name: "completion_signal_ignored_progress_insufficient",
|
|
3917
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3918
|
+
properties: {
|
|
3919
|
+
iteration: result._iteration,
|
|
3920
|
+
signalType: this.config.completionSignal?.type,
|
|
3921
|
+
score: result.progress.score,
|
|
3922
|
+
trend: result.progress.trend,
|
|
3923
|
+
isSignificant: result.progress.isSignificant,
|
|
3924
|
+
minScore: COMPLETION_SIGNAL_MIN_SCORE
|
|
3925
|
+
}
|
|
3926
|
+
});
|
|
3927
|
+
return true;
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
const hostVerifiedCompletionEvidence = result.success === true && this.hasDurableCompletionEvidence(result) && customGatesOk;
|
|
3931
|
+
if (isSemanticCheckBlocking(result.semanticValidation) && !hostVerifiedCompletionEvidence) {
|
|
3932
|
+
const atBounds2 = result._iteration >= this.config.maxIterations;
|
|
3933
|
+
if (atBounds2) {
|
|
3934
|
+
this.telemetry?.logEvent({
|
|
3935
|
+
name: "loop_terminated_semantic_criteria_unsatisfied",
|
|
3936
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3937
|
+
properties: {
|
|
3938
|
+
iteration: result._iteration,
|
|
3939
|
+
context: "completion_signal_gated_at_bounds",
|
|
3940
|
+
movedCloser: result.semanticValidation?.progressResult?.movedCloser,
|
|
3941
|
+
satisfactionScore: result.semanticValidation?.satisfactionScore,
|
|
3942
|
+
totalACs: result.semanticValidation?.acResults?.length ?? 0,
|
|
3943
|
+
satisfiedACs: result.semanticValidation?.acResults?.filter((r) => r.satisfied).length ?? 0
|
|
3944
|
+
}
|
|
3945
|
+
});
|
|
3946
|
+
this.terminate("semantic_criteria_unsatisfied");
|
|
3947
|
+
return false;
|
|
3948
|
+
}
|
|
3949
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3950
|
+
iteration: result._iteration,
|
|
3951
|
+
gate: "semantic",
|
|
3952
|
+
satisfactionScore: result.semanticValidation?.satisfactionScore
|
|
3953
|
+
});
|
|
3954
|
+
this.telemetry?.logEvent({
|
|
3955
|
+
name: "completion_signal_ignored_semantic_failed",
|
|
3956
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3957
|
+
properties: {
|
|
3958
|
+
iteration: result._iteration,
|
|
3959
|
+
signalType: this.config.completionSignal?.type,
|
|
3960
|
+
movedCloser: result.semanticValidation?.progressResult?.movedCloser,
|
|
3961
|
+
satisfactionScore: result.semanticValidation?.satisfactionScore,
|
|
3962
|
+
totalACs: result.semanticValidation?.acResults?.length ?? 0,
|
|
3963
|
+
satisfiedACs: result.semanticValidation?.acResults?.filter((r) => r.satisfied).length ?? 0
|
|
3964
|
+
}
|
|
3965
|
+
});
|
|
3966
|
+
return true;
|
|
3967
|
+
}
|
|
3968
|
+
if (!completionStatusAllowsSuccess(result.completionSummary?.status)) {
|
|
3969
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3970
|
+
iteration: result._iteration,
|
|
3971
|
+
gate: "completion_summary",
|
|
3972
|
+
status: result.completionSummary?.status
|
|
3973
|
+
});
|
|
3974
|
+
this.telemetry?.logEvent({
|
|
3975
|
+
name: "completion_signal_ignored_incomplete_summary",
|
|
3976
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3977
|
+
properties: {
|
|
3978
|
+
iteration: result._iteration,
|
|
3979
|
+
signalType: this.config.completionSignal?.type,
|
|
3980
|
+
status: result.completionSummary?.status,
|
|
3981
|
+
blockingIssues: result.completionSummary?.blockingIssues.slice(0, 5)
|
|
3982
|
+
}
|
|
3983
|
+
});
|
|
3984
|
+
return true;
|
|
3985
|
+
}
|
|
3986
|
+
this.telemetry?.logEvent({
|
|
3987
|
+
name: "loop_terminated_completion_signal",
|
|
3988
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3989
|
+
properties: {
|
|
3990
|
+
iteration: result._iteration,
|
|
3991
|
+
signalType: this.config.completionSignal?.type
|
|
3992
|
+
}
|
|
3993
|
+
});
|
|
3994
|
+
this.terminate("completion_signal");
|
|
3995
|
+
return false;
|
|
3996
|
+
}
|
|
3997
|
+
const atBounds = result._iteration >= this.config.maxIterations;
|
|
3998
|
+
if (atBounds && isSemanticCheckBlocking(result.semanticValidation)) {
|
|
3999
|
+
this.telemetry?.logEvent({
|
|
4000
|
+
name: "loop_terminated_semantic_criteria_unsatisfied",
|
|
4001
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4002
|
+
properties: {
|
|
4003
|
+
iteration: result._iteration,
|
|
4004
|
+
context: "bounds_reached",
|
|
4005
|
+
movedCloser: result.semanticValidation?.progressResult?.movedCloser,
|
|
4006
|
+
satisfactionScore: result.semanticValidation?.satisfactionScore,
|
|
4007
|
+
totalACs: result.semanticValidation?.acResults?.length ?? 0,
|
|
4008
|
+
satisfiedACs: result.semanticValidation?.acResults?.filter((r) => r.satisfied).length ?? 0
|
|
4009
|
+
}
|
|
4010
|
+
});
|
|
4011
|
+
this.terminate("semantic_criteria_unsatisfied");
|
|
4012
|
+
return false;
|
|
4013
|
+
}
|
|
4014
|
+
const customGatesAtBoundsEvidence = customGatesAllowCompletion(result.customGateResults);
|
|
4015
|
+
const qualityGatesAtBoundsBlocking = qualityGatesHaveBlockingFailure(result.qualityGates, {
|
|
4016
|
+
customGatesProvideEvidence: customGatesAtBoundsEvidence
|
|
4017
|
+
});
|
|
4018
|
+
const qualityGatesAtBoundsOk = !this.config.runQualityGates || (qualityGatesAllowCompletion(result.qualityGates) || customGatesAtBoundsEvidence) && !qualityGatesAtBoundsBlocking;
|
|
4019
|
+
const customGatesAtBoundsOk = !customGatesHaveBlockingFailure(result.customGateResults);
|
|
4020
|
+
if (atBounds && this.config.validationMode !== "deterministic" && result.success === true && isSemanticCompletionSatisfied(result.semanticValidation) && this.hasSubstantiveCompletionEvidence(result) && qualityGatesAtBoundsOk && customGatesAtBoundsOk && !requirementsUnmet) {
|
|
4021
|
+
this.telemetry?.logEvent({
|
|
4022
|
+
name: "loop_terminated_semantic_complete",
|
|
4023
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4024
|
+
properties: {
|
|
4025
|
+
iteration: result._iteration,
|
|
4026
|
+
movedCloser: result.semanticValidation?.progressResult?.movedCloser,
|
|
4027
|
+
satisfactionScore: result.semanticValidation?.satisfactionScore,
|
|
4028
|
+
totalACs: result.semanticValidation?.acResults?.length ?? 0,
|
|
4029
|
+
satisfiedACs: result.semanticValidation?.acResults?.filter((r) => r.satisfied).length ?? 0
|
|
4030
|
+
}
|
|
4031
|
+
});
|
|
4032
|
+
this.terminate("semantic_complete");
|
|
4033
|
+
return false;
|
|
4034
|
+
}
|
|
4035
|
+
if (this.config.validationMode === "deterministic") {
|
|
4036
|
+
const allGatesPassed = result.qualityGates && result.qualityGates.length > 0 && result.qualityGates.every((g) => g.passed);
|
|
4037
|
+
const qualityGatesOk = qualityGatesAllowCompletion(result.qualityGates);
|
|
4038
|
+
const customGatesOk = customGatesAllowCompletion(result.customGateResults);
|
|
4039
|
+
const qualityGatesBlocking = qualityGatesHaveBlockingFailure(result.qualityGates, {
|
|
4040
|
+
customGatesProvideEvidence: customGatesOk
|
|
4041
|
+
});
|
|
4042
|
+
const customGatesBlocking = customGatesHaveBlockingFailure(result.customGateResults);
|
|
4043
|
+
if ((allGatesPassed || qualityGatesOk || customGatesOk) && !qualityGatesBlocking && !customGatesBlocking && !requirementsUnmet && completionStatusAllowsSuccess(result.completionSummary?.status)) {
|
|
4044
|
+
this.telemetry?.logEvent({
|
|
4045
|
+
name: "loop_terminated_deterministic_complete",
|
|
4046
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4047
|
+
properties: {
|
|
4048
|
+
iteration: result._iteration,
|
|
4049
|
+
gateCount: result.qualityGates?.length,
|
|
4050
|
+
customGateCount: result.customGateResults?.length,
|
|
4051
|
+
allPassed: allGatesPassed,
|
|
4052
|
+
preExistingFailuresOnly: !allGatesPassed && qualityGatesOk,
|
|
4053
|
+
preExistingFailures: result.qualityGates?.filter((g) => !g.passed && g.isRegression === false).map((g) => g.gateId)
|
|
4054
|
+
}
|
|
4055
|
+
});
|
|
4056
|
+
this.terminate("deterministic_complete");
|
|
4057
|
+
return false;
|
|
4058
|
+
}
|
|
4059
|
+
return true;
|
|
4060
|
+
}
|
|
4061
|
+
if (this.config.validationMode === "none") {
|
|
4062
|
+
if (result.judgeEvaluation?.recommendation === "terminate" && !requirementsUnmet) {
|
|
4063
|
+
this.terminate("ai_judge_recommendation");
|
|
4064
|
+
return false;
|
|
4065
|
+
}
|
|
4066
|
+
if (result.judgeEvaluation?.recommendation === "pivot") {
|
|
4067
|
+
await this.handlePivotRecommendation(result);
|
|
4068
|
+
}
|
|
4069
|
+
return true;
|
|
4070
|
+
}
|
|
4071
|
+
const completionThreshold = 0.8;
|
|
4072
|
+
const stableHighScore = result.progress.trend === "stable" && !result.progress.isSignificant && result.progress.score >= completionThreshold && result.progress.verificationUnavailable !== true && result.progress.toolingFailure !== true && !requirementsUnmet;
|
|
4073
|
+
const completionSummary = result.completionSummary;
|
|
4074
|
+
if (stableHighScore && completionSummary !== void 0 && completionStatusAllowsSuccess(completionSummary.status) && completionSummary.hasSubstantiveEvidence && completionSummary.blockingIssues.length === 0) {
|
|
4075
|
+
this.telemetry?.logEvent({
|
|
4076
|
+
name: "loop_terminated_heuristic_complete",
|
|
4077
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4078
|
+
properties: {
|
|
4079
|
+
iteration: result._iteration,
|
|
4080
|
+
progressScore: result.progress.score,
|
|
4081
|
+
trend: result.progress.trend
|
|
4082
|
+
}
|
|
4083
|
+
});
|
|
4084
|
+
this.terminate("heuristic_complete");
|
|
4085
|
+
return false;
|
|
4086
|
+
}
|
|
4087
|
+
if (!result.progress.isSignificant) {
|
|
4088
|
+
const recentResults = this.iterationHistory.slice(-this.config.progressConfig.windowSize);
|
|
4089
|
+
const stagnantCount = recentResults.filter((r) => !r.progress.isSignificant).length;
|
|
4090
|
+
if (stagnantCount >= this.config.progressConfig.windowSize) {
|
|
4091
|
+
if (result._iteration < this.config.maxIterations) {
|
|
4092
|
+
this.terminate("progress_stagnation");
|
|
4093
|
+
return false;
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4096
|
+
}
|
|
4097
|
+
if (result.judgeEvaluation?.recommendation === "terminate") {
|
|
4098
|
+
this.terminate("ai_judge_recommendation");
|
|
4099
|
+
return false;
|
|
4100
|
+
}
|
|
4101
|
+
if (result.judgeEvaluation?.recommendation === "pivot") {
|
|
4102
|
+
await this.handlePivotRecommendation(result);
|
|
4103
|
+
}
|
|
4104
|
+
return true;
|
|
4105
|
+
}
|
|
4106
|
+
/**
|
|
4107
|
+
* After a mature delivery, stop on the next empty-diff iteration instead
|
|
4108
|
+
* of burning retries. Do not stop on the successful delivery itself — that
|
|
4109
|
+
* would bypass the completion-signal progress floor and semantic oracle.
|
|
4110
|
+
* Baseline-only green does not qualify.
|
|
4111
|
+
*/
|
|
4112
|
+
deliverySnapshot(result) {
|
|
4113
|
+
return {
|
|
4114
|
+
success: result.success,
|
|
4115
|
+
iterationFingerprint: result.iterationFingerprint,
|
|
4116
|
+
error: result.error,
|
|
4117
|
+
qualityGates: result.qualityGates,
|
|
4118
|
+
customGateResults: result.customGateResults,
|
|
4119
|
+
requirements: result.requirements,
|
|
4120
|
+
completionSummary: result.completionSummary,
|
|
4121
|
+
semanticValidation: result.semanticValidation
|
|
4122
|
+
};
|
|
4123
|
+
}
|
|
4124
|
+
/**
|
|
4125
|
+
* A completion signal over a sound delivery whose only blocker is
|
|
4126
|
+
* proven-unavailable required verification completes as delivered-unverified
|
|
4127
|
+
* instead of terminating as `verification_unavailable`. Real gate failures,
|
|
4128
|
+
* budget skips and unmet requirements keep their existing handling.
|
|
4129
|
+
*/
|
|
4130
|
+
tryCompleteUnavailableOnlyDelivery(result) {
|
|
4131
|
+
const disposition = resolveUnavailableOnlyDelivery(
|
|
4132
|
+
this.deliverySnapshot(result),
|
|
4133
|
+
idleStopEnabledChecksFromConfig(this.config)
|
|
4134
|
+
);
|
|
4135
|
+
if (!result.success || !disposition) {
|
|
4136
|
+
return false;
|
|
4137
|
+
}
|
|
4138
|
+
result.earlyFinalization = {
|
|
4139
|
+
reason: "delivered_unverified_verification_unavailable",
|
|
4140
|
+
priorIteration: Number(result._iteration),
|
|
4141
|
+
verification: "unverified",
|
|
4142
|
+
disposition
|
|
4143
|
+
};
|
|
4144
|
+
this.telemetry?.logEvent({
|
|
4145
|
+
name: "loop_completed_delivered_unverified",
|
|
4146
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4147
|
+
properties: {
|
|
4148
|
+
iteration: result._iteration,
|
|
4149
|
+
signalType: this.config.completionSignal?.type,
|
|
4150
|
+
scope: disposition.scope,
|
|
4151
|
+
reason: disposition.reason
|
|
4152
|
+
}
|
|
4153
|
+
});
|
|
4154
|
+
this.terminate("deterministic_complete");
|
|
4155
|
+
return true;
|
|
4156
|
+
}
|
|
4157
|
+
tryIdleStopAfterRealFirstDelivery(result) {
|
|
4158
|
+
const enabled = idleStopEnabledChecksFromConfig(this.config);
|
|
4159
|
+
const snapshot = this.deliverySnapshot(result);
|
|
4160
|
+
const prior = this.iterationHistory.filter((iteration) => iteration !== result);
|
|
4161
|
+
const resolution = resolveIdleStopAfterRealFirstDelivery(prior, snapshot, enabled, {
|
|
4162
|
+
iterationChangeEvidenceTrusted: this.config.iterationChangeEvidenceTrusted !== false
|
|
4163
|
+
});
|
|
4164
|
+
if (!resolution.shouldStop) {
|
|
4165
|
+
return false;
|
|
4166
|
+
}
|
|
4167
|
+
this.idleStoppedAfterRealFirstDelivery = true;
|
|
4168
|
+
const priorResult = prior[resolution.priorIterationIndex];
|
|
4169
|
+
result.earlyFinalization = {
|
|
4170
|
+
reason: "mature_delivery_followed_by_no_op",
|
|
4171
|
+
priorIteration: Number(priorResult?._iteration ?? resolution.priorIterationIndex + 1),
|
|
4172
|
+
verification: resolution.verification,
|
|
4173
|
+
...resolution.disposition ? { disposition: resolution.disposition } : {}
|
|
4174
|
+
};
|
|
4175
|
+
this.telemetry?.logEvent({
|
|
4176
|
+
name: "loop_terminated_idle_after_first_delivery",
|
|
4177
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4178
|
+
properties: {
|
|
4179
|
+
iteration: result._iteration,
|
|
4180
|
+
emptyDiffAfterDelivery: true,
|
|
4181
|
+
gateCount: result.qualityGates?.length ?? 0,
|
|
4182
|
+
verification: resolution.verification
|
|
4183
|
+
}
|
|
4184
|
+
});
|
|
4185
|
+
this.terminate("deterministic_complete");
|
|
4186
|
+
return true;
|
|
4187
|
+
}
|
|
4188
|
+
/**
|
|
4189
|
+
* Decide whether a failed iteration may retry. Terminates the loop with
|
|
4190
|
+
* 'max_retries_exceeded' once the backoff/retry budget is exhausted so retry
|
|
4191
|
+
* exhaustion surfaces as a specific termination reason rather than a generic
|
|
4192
|
+
* failure. backoffAttempts is incremented by applyBackoff() after each
|
|
4193
|
+
* retry-granting failure, so this check gates the NEXT retry.
|
|
4194
|
+
*/
|
|
4195
|
+
continueAfterFailureOrTerminate() {
|
|
4196
|
+
if (this.backoffAttempts >= this.config.backoffConfig.maxRetries) {
|
|
4197
|
+
this.terminate("max_retries_exceeded");
|
|
4198
|
+
return false;
|
|
4199
|
+
}
|
|
4200
|
+
return true;
|
|
4201
|
+
}
|
|
4202
|
+
/**
|
|
4203
|
+
* Apply exponential backoff for failed iterations
|
|
4204
|
+
*/
|
|
4205
|
+
async applyBackoff() {
|
|
4206
|
+
if (this.isRunAborted()) {
|
|
4207
|
+
this.terminate("system_error");
|
|
4208
|
+
return;
|
|
4209
|
+
}
|
|
4210
|
+
if (this.backoffAttempts >= this.config.backoffConfig.maxRetries) {
|
|
4211
|
+
this.terminate("max_retries_exceeded");
|
|
4212
|
+
return;
|
|
4213
|
+
}
|
|
4214
|
+
const delay = calculateBackoffDelay(this.backoffAttempts, this.config.backoffConfig);
|
|
4215
|
+
this.backoffAttempts++;
|
|
4216
|
+
this.emit("backoff_triggered", {
|
|
4217
|
+
type: "backoff_triggered",
|
|
4218
|
+
delay,
|
|
4219
|
+
reason: "iteration_failed"
|
|
4220
|
+
});
|
|
4221
|
+
await abortableDelay(delay, this.config.abortSignal);
|
|
4222
|
+
}
|
|
4223
|
+
/**
|
|
4224
|
+
* Check resource limits and emit warnings.
|
|
4225
|
+
* Near-limit warnings are memory-only; CPU/process stay diagnostic-only.
|
|
4226
|
+
*/
|
|
4227
|
+
checkResourceLimits() {
|
|
4228
|
+
const resources = getResourceUsage();
|
|
4229
|
+
const memoryMB = resources.memory.heapUsed / (1024 * 1024);
|
|
4230
|
+
if (memoryMB > this.config.resourceLimits.maxMemoryMB * 0.8) {
|
|
4231
|
+
if (!this.resourceWarnings.has("memory")) {
|
|
4232
|
+
this.resourceWarnings.add("memory");
|
|
4233
|
+
this.emit("resource_warning", {
|
|
4234
|
+
type: "resource_warning",
|
|
4235
|
+
resource: "memory",
|
|
4236
|
+
usage: memoryMB,
|
|
4237
|
+
limit: this.config.resourceLimits.maxMemoryMB
|
|
4238
|
+
});
|
|
4239
|
+
}
|
|
4240
|
+
}
|
|
4241
|
+
}
|
|
4242
|
+
/**
|
|
4243
|
+
* Set up event forwarding to dependencies
|
|
4244
|
+
*/
|
|
4245
|
+
setupEventForwarding() {
|
|
4246
|
+
if (this.resultStreamer) {
|
|
4247
|
+
this.on("iteration_complete", (data) => {
|
|
4248
|
+
this.resultStreamer?.emit("iterationComplete", data);
|
|
4249
|
+
});
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
/**
|
|
4253
|
+
* Set up cleanup handlers
|
|
4254
|
+
*/
|
|
4255
|
+
setupCleanupHandlers() {
|
|
4256
|
+
signalCoordinator.register(this.instanceId, async () => {
|
|
4257
|
+
await this.cleanup();
|
|
4258
|
+
});
|
|
4259
|
+
this.cleanupHandlers = [() => signalCoordinator.unregister(this.instanceId)];
|
|
4260
|
+
}
|
|
4261
|
+
/**
|
|
4262
|
+
* Clean up resources and remove event listeners
|
|
4263
|
+
*/
|
|
4264
|
+
close() {
|
|
4265
|
+
this.cleanupHandlers.forEach((cleanup) => {
|
|
4266
|
+
try {
|
|
4267
|
+
cleanup();
|
|
4268
|
+
} catch (_error) {
|
|
4269
|
+
}
|
|
4270
|
+
});
|
|
4271
|
+
this.cleanupHandlers = [];
|
|
4272
|
+
this.removeAllListeners();
|
|
4273
|
+
}
|
|
4274
|
+
/**
|
|
4275
|
+
* Clean up resources
|
|
4276
|
+
*/
|
|
4277
|
+
async cleanup() {
|
|
4278
|
+
if (this.cleanupStarted) return;
|
|
4279
|
+
this.cleanupStarted = true;
|
|
4280
|
+
try {
|
|
4281
|
+
await this.recursionTracker.exit();
|
|
4282
|
+
if (this.telemetry) {
|
|
4283
|
+
await this.telemetry.flush();
|
|
4284
|
+
}
|
|
4285
|
+
this.emit("loop_cleanup", { type: "loop_cleanup", state: this.state });
|
|
4286
|
+
} catch (error) {
|
|
4287
|
+
console.error("Error during cleanup:", error);
|
|
4288
|
+
}
|
|
4289
|
+
}
|
|
4290
|
+
};
|
|
4291
|
+
function createAutonomousLoopController(config = {}, dependencies = {}) {
|
|
4292
|
+
return new AutonomousLoopController(config, dependencies);
|
|
4293
|
+
}
|
|
4294
|
+
var DEFAULT_COMPLETION_SIGNALS = [
|
|
4295
|
+
"xml:<task_complete/>",
|
|
4296
|
+
"xml:<TASK_COMPLETE/>",
|
|
4297
|
+
"regex:task\\s+complete|task\\s+finished|all\\s+done"
|
|
4298
|
+
];
|
|
4299
|
+
function createConfigFromEnv(cliFlags = {}) {
|
|
4300
|
+
const readPositiveNumber = (envName, fallback, max) => {
|
|
4301
|
+
const raw = readRawEnv(envName);
|
|
4302
|
+
if (raw === void 0 || raw === "") return fallback;
|
|
4303
|
+
const value = Number(raw);
|
|
4304
|
+
if (!Number.isFinite(value) || value <= 0) return fallback;
|
|
4305
|
+
return max === void 0 ? value : Math.min(value, max);
|
|
4306
|
+
};
|
|
4307
|
+
const readUnitInterval = (envName, fallback) => {
|
|
4308
|
+
const raw = readRawEnv(envName);
|
|
4309
|
+
if (raw === void 0 || raw === "") return fallback;
|
|
4310
|
+
const value = Number(raw);
|
|
4311
|
+
return Number.isFinite(value) && value >= 0 && value <= 1 ? value : fallback;
|
|
4312
|
+
};
|
|
4313
|
+
const maxIterations = readPositiveNumber(
|
|
4314
|
+
BUILD_AUTOLOOP_MAX_ITERATIONS,
|
|
4315
|
+
3,
|
|
4316
|
+
MAX_AUTOLOOP_ENV_ITERATIONS
|
|
4317
|
+
);
|
|
4318
|
+
const timeboxMs = resolveAutoloopTimeboxMs();
|
|
4319
|
+
const minProgress = readUnitInterval(BUILD_AUTOLOOP_MIN_PROGRESS, 0.05);
|
|
4320
|
+
const maxMemoryRaw = readRawEnv(BUILD_AUTOLOOP_MAX_MEMORY);
|
|
4321
|
+
const maxMemoryMB = maxMemoryRaw === void 0 ? DEFAULT_AUTOLOOP_RESOURCE_LIMITS.maxMemoryMB : readPositiveNumber(BUILD_AUTOLOOP_MAX_MEMORY, DEFAULT_AUTOLOOP_RESOURCE_LIMITS.maxMemoryMB);
|
|
4322
|
+
const cliValidation = cliFlags["--autoloop-validation"];
|
|
4323
|
+
const validationMode = resolveAutoloopValidationMode(cliValidation);
|
|
4324
|
+
const completionSignalRaw = validationMode === "deterministic" ? void 0 : cliFlags["--autoloop-completion-signal"] || readEnv(BUILD_AUTOLOOP_COMPLETION_SIGNAL).value;
|
|
4325
|
+
let completionSignal;
|
|
4326
|
+
if (completionSignalRaw) {
|
|
4327
|
+
completionSignal = parseCompletionSignal(completionSignalRaw) ?? void 0;
|
|
4328
|
+
} else if (validationMode !== "deterministic" && validationMode !== "none") {
|
|
4329
|
+
for (const defaultSignal of DEFAULT_COMPLETION_SIGNALS) {
|
|
4330
|
+
const parsed = parseCompletionSignal(defaultSignal);
|
|
4331
|
+
if (parsed) {
|
|
4332
|
+
completionSignal = parsed;
|
|
4333
|
+
break;
|
|
4334
|
+
}
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
4337
|
+
const qualityGatesModeRaw = cliFlags["--autoloop-quality-gates-mode"] || readRawEnv(BUILD_AUTOLOOP_QUALITY_GATES_MODE);
|
|
4338
|
+
const qualityGatesMode = qualityGatesModeRaw === "full" || qualityGatesModeRaw === "safe" || qualityGatesModeRaw === "fast" ? qualityGatesModeRaw : "fast";
|
|
4339
|
+
return {
|
|
4340
|
+
maxIterations: createIterationCount(maxIterations),
|
|
4341
|
+
timeboxMs: createDurationMs(timeboxMs),
|
|
4342
|
+
minProgressThreshold: createProgressScore(minProgress),
|
|
4343
|
+
useAIJudge: readEnv(BUILD_AUTOLOOP_JUDGE).value === "1" || cliFlags["--autoloop-judge"] === true,
|
|
4344
|
+
runQualityGates: cliFlags["--autoloop-quality-gates"] === true,
|
|
4345
|
+
qualityGatesMode,
|
|
4346
|
+
resourceLimits: {
|
|
4347
|
+
maxMemoryMB
|
|
4348
|
+
},
|
|
4349
|
+
...completionSignal ? { completionSignal } : {},
|
|
4350
|
+
validationMode
|
|
4351
|
+
};
|
|
4352
|
+
}
|
|
4353
|
+
var autonomous_loop_controller_default = AutonomousLoopController;
|
|
4354
|
+
export {
|
|
4355
|
+
AutonomousLoopController,
|
|
4356
|
+
COMPLETION_SIGNAL_TAIL_BYTES,
|
|
4357
|
+
DEFAULT_AUTOLOOP_RESOURCE_LIMITS,
|
|
4358
|
+
DEFAULT_COMPLETION_SIGNALS,
|
|
4359
|
+
MAX_FIRST_ITERATION_RESERVE_MS,
|
|
4360
|
+
MIN_FIRST_ITERATION_RESERVE_MS,
|
|
4361
|
+
buildCustomGateId,
|
|
4362
|
+
classifyCoverageBaselineComparison,
|
|
4363
|
+
classifyError,
|
|
4364
|
+
classifyQualityGateFailure,
|
|
4365
|
+
createAutonomousLoopController,
|
|
4366
|
+
createConfigFromEnv,
|
|
4367
|
+
createDurationMs,
|
|
4368
|
+
createIterationCount,
|
|
4369
|
+
createProgressScore,
|
|
4370
|
+
autonomous_loop_controller_default as default,
|
|
4371
|
+
extractFailureCountWithMethod,
|
|
4372
|
+
hasCompilationProgressSignal,
|
|
4373
|
+
isBenignSemanticSkip,
|
|
4374
|
+
isEmptyDiffIdleFailure,
|
|
4375
|
+
isRealFirstDeliveryIteration,
|
|
4376
|
+
isSemanticCompletionSatisfied,
|
|
4377
|
+
isSemanticErrorSkip,
|
|
4378
|
+
matchesCompletionSignal,
|
|
4379
|
+
parseCompletionSignal,
|
|
4380
|
+
resolveIdleStopAfterRealFirstDelivery,
|
|
4381
|
+
selectTaskOutputForChecks,
|
|
4382
|
+
semanticDisabled,
|
|
4383
|
+
semanticSkipped,
|
|
4384
|
+
shouldIdleStopAfterRealFirstDelivery
|
|
4385
|
+
};
|
|
4386
|
+
//# sourceMappingURL=autonomous-loop-controller-2WL363LW.js.map
|