@poetic-ai/poetic 1.42.0
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/.github/SECURITY.md +47 -0
- package/.nvmrc +1 -0
- package/.poetic/README.md +37 -0
- package/.poetic/providers/catalog.json +12051 -0
- package/.poetic/providers/pricing.json +1272 -0
- package/.poetic/providers/registry.json +3369 -0
- package/CHANGELOG.md +552 -0
- package/CODE_OF_CONDUCT.md +40 -0
- package/CONTRIBUTING.md +23 -0
- package/INSTALL.md +454 -0
- package/LICENSE +21 -0
- package/README.md +474 -0
- package/dist/BasicOptimizationCompetitionRunner-5H5TBYO4.js +153 -0
- package/dist/ExecutionTracker-UVONC4C6.js +16 -0
- package/dist/OptimizationConfig-7DFY2TST.js +17 -0
- package/dist/OptimizationEngine-JIMGP3LY.js +1597 -0
- package/dist/PromptStore-U6ZD3ZMQ.js +18 -0
- package/dist/actions-LUJPINLJ.js +322 -0
- package/dist/agent-ingest-3DJUJ7FU.js +53 -0
- package/dist/aggregator-DNCBINFO.js +12 -0
- package/dist/ai-judge-5QT5QJVU.js +156 -0
- package/dist/allowlist-grounding-RO6HKUFI.js +16 -0
- package/dist/allowlist-utils-23V7TJ3G.js +28 -0
- package/dist/anchored-turn-service-JULUCUIK.js +489 -0
- package/dist/api-transport-4TYTNLTJ.js +1087 -0
- package/dist/apply-completion-mode-AW2MOS3R.js +89 -0
- package/dist/artifact-migrator-23L45ISD.js +267 -0
- package/dist/ask-HWVV6QFR.js +135 -0
- package/dist/auth-5KEDKAPP.js +67 -0
- package/dist/auth-7TT3JINV.js +78 -0
- package/dist/auth-E6XUNZ5M.js +68 -0
- package/dist/auth-H3XDZE22.js +134 -0
- package/dist/auth-OC4E6633.js +71 -0
- package/dist/auth-S4CTX4GQ.js +44 -0
- package/dist/auth-YLH3S7EY.js +69 -0
- package/dist/auth-liveness-TDDEZY3T.js +46 -0
- package/dist/auto-optimizer-VPRWOWGU.js +80 -0
- package/dist/autoloop-cleanup-JOGKTLWA.js +109 -0
- package/dist/autoloop-evidence-gates-PCDALGVJ.js +38 -0
- package/dist/autoloop-gate-policy-Z7FVJVXV.js +175 -0
- package/dist/autoloop-helpers-2KTK43GL.js +22 -0
- package/dist/autoloop-ledger-W7QO62PX.js +96 -0
- package/dist/autoloop-ledger-subscriber-Z5RW5EIE.js +162 -0
- package/dist/autoloop-run-defaults-FERGRZGP.js +19 -0
- package/dist/autoloop-run-lock-CT2NWSV3.js +197 -0
- package/dist/autoloop-success-J2VKKBXQ.js +85 -0
- package/dist/autoloop-termination-summary-RN75F422.js +58 -0
- package/dist/autoloop-trajectory-XFIEXP5Z.js +282 -0
- package/dist/autoloop-wall-clock-T7ZVIQOC.js +12 -0
- package/dist/autonomous-loop-controller-PW4XVFGQ.js +4120 -0
- package/dist/backend-P3DAYRP7.js +29 -0
- package/dist/background-executor-CBN552V4.js +257 -0
- package/dist/backlog-execution-intent-U4XYPTV6.js +15 -0
- package/dist/backup-active-store-5WXG6SXT.js +17 -0
- package/dist/backup-telemetry-db-XGLXAA3N.js +254 -0
- package/dist/basic-competition-master-VCSBJVRN.js +344 -0
- package/dist/branch-archive-manager-RP6FP3ZC.js +254 -0
- package/dist/branch-cleanup-manager-RSHAI7YR.js +20 -0
- package/dist/build-gate-YHGRB4QB.js +71 -0
- package/dist/change-summary-WY7J5TOX.js +33 -0
- package/dist/chunk-23A26CSN.js +123 -0
- package/dist/chunk-27UTJD3M.js +265 -0
- package/dist/chunk-2A5CILN3.js +310 -0
- package/dist/chunk-2AQUWJPW.js +225 -0
- package/dist/chunk-2BZ53J6J.js +2344 -0
- package/dist/chunk-2DY5KNVM.js +276 -0
- package/dist/chunk-2EIA4RBE.js +659 -0
- package/dist/chunk-2IUXIGQD.js +1064 -0
- package/dist/chunk-2N42MS2Z.js +2193 -0
- package/dist/chunk-2QJ3H3L7.js +42 -0
- package/dist/chunk-2QLYTVYX.js +791 -0
- package/dist/chunk-2VSQMRCB.js +18 -0
- package/dist/chunk-2XQXYBM2.js +130 -0
- package/dist/chunk-2YFUIER7.js +426 -0
- package/dist/chunk-34CNP2HB.js +148 -0
- package/dist/chunk-35P3W3JX.js +456 -0
- package/dist/chunk-36PEBZAF.js +18 -0
- package/dist/chunk-3AOKYKA7.js +22 -0
- package/dist/chunk-3BCUNHKF.js +475 -0
- package/dist/chunk-3FLXLLB7.js +26 -0
- package/dist/chunk-3FOZ2VHV.js +100 -0
- package/dist/chunk-3G6FZCRF.js +106 -0
- package/dist/chunk-3M57DADF.js +44 -0
- package/dist/chunk-3S62LLWJ.js +543 -0
- package/dist/chunk-3ZPQLGV7.js +2904 -0
- package/dist/chunk-44N5WZZH.js +45 -0
- package/dist/chunk-45FPSA3B.js +125 -0
- package/dist/chunk-4BJ3O4RQ.js +929 -0
- package/dist/chunk-4BOP7T6L.js +2321 -0
- package/dist/chunk-4BTDUT2S.js +42 -0
- package/dist/chunk-4CSS7WVI.js +143 -0
- package/dist/chunk-4CUY7AFY.js +247 -0
- package/dist/chunk-4GSN5O5J.js +62 -0
- package/dist/chunk-4HN6DF7V.js +1027 -0
- package/dist/chunk-4IAPOG5V.js +415 -0
- package/dist/chunk-4IYIZQWV.js +48 -0
- package/dist/chunk-4NXPXE62.js +84 -0
- package/dist/chunk-4RCCF5BR.js +712 -0
- package/dist/chunk-4V7NAQ4R.js +19527 -0
- package/dist/chunk-4VJITV4P.js +445 -0
- package/dist/chunk-4YX7J6QL.js +1859 -0
- package/dist/chunk-527OBWQB.js +338 -0
- package/dist/chunk-5D4A7E3D.js +448 -0
- package/dist/chunk-5DLKYTQX.js +4003 -0
- package/dist/chunk-5EERLVZB.js +139 -0
- package/dist/chunk-5H72XE4H.js +256 -0
- package/dist/chunk-5HDP7XZG.js +91 -0
- package/dist/chunk-5LAMRH4X.js +969 -0
- package/dist/chunk-5LTN43AS.js +1972 -0
- package/dist/chunk-5RBHQYDB.js +2206 -0
- package/dist/chunk-5WCQRDRB.js +588 -0
- package/dist/chunk-5WRLK5KW.js +700 -0
- package/dist/chunk-5ZCXC23G.js +595 -0
- package/dist/chunk-6BM72ZMG.js +31 -0
- package/dist/chunk-6EDAJH2I.js +68 -0
- package/dist/chunk-6EQKFDBH.js +457 -0
- package/dist/chunk-6MFRHTRI.js +115 -0
- package/dist/chunk-6TZJRKNW.js +321 -0
- package/dist/chunk-6V7HGQFZ.js +20 -0
- package/dist/chunk-6VWVO2TU.js +3746 -0
- package/dist/chunk-6Y5TWI7H.js +146 -0
- package/dist/chunk-6Y5U7UFY.js +91 -0
- package/dist/chunk-6ZLAK3XG.js +14 -0
- package/dist/chunk-72XCRQED.js +34 -0
- package/dist/chunk-72YTZMAM.js +589 -0
- package/dist/chunk-73BBJOKA.js +263 -0
- package/dist/chunk-73NCTWKL.js +188 -0
- package/dist/chunk-77I6G4CO.js +1 -0
- package/dist/chunk-7DHRDWFS.js +3104 -0
- package/dist/chunk-7DNSNKJV.js +78 -0
- package/dist/chunk-7FMJVYBS.js +307 -0
- package/dist/chunk-7GDRQBQC.js +419 -0
- package/dist/chunk-7GPCEFUV.js +270 -0
- package/dist/chunk-7IL4A2PP.js +948 -0
- package/dist/chunk-7MMLMXO6.js +3679 -0
- package/dist/chunk-7QCZSLBH.js +1 -0
- package/dist/chunk-7R2WLDOS.js +62 -0
- package/dist/chunk-7T7RUJI7.js +949 -0
- package/dist/chunk-A2WKSVX7.js +43 -0
- package/dist/chunk-A3YGID55.js +133 -0
- package/dist/chunk-A722DEVA.js +14 -0
- package/dist/chunk-ACDIT7OP.js +1376 -0
- package/dist/chunk-ACKIPAOJ.js +302 -0
- package/dist/chunk-APPNGGN7.js +365 -0
- package/dist/chunk-APV6MK5E.js +137 -0
- package/dist/chunk-ASEP3M2W.js +968 -0
- package/dist/chunk-AT4TNPWW.js +2931 -0
- package/dist/chunk-ATVKCSGT.js +250 -0
- package/dist/chunk-AURFMVCD.js +899 -0
- package/dist/chunk-AX6GWE7V.js +47 -0
- package/dist/chunk-AY5EWJPF.js +385 -0
- package/dist/chunk-BAV2HJXS.js +194 -0
- package/dist/chunk-BBHRN366.js +89 -0
- package/dist/chunk-BBPSTTPA.js +1004 -0
- package/dist/chunk-BDATUDDJ.js +992 -0
- package/dist/chunk-BKE5PG5L.js +20414 -0
- package/dist/chunk-BLPHWMDK.js +797 -0
- package/dist/chunk-BSE4R6XD.js +322 -0
- package/dist/chunk-BXGMAU4A.js +396 -0
- package/dist/chunk-BXI4NXL3.js +507 -0
- package/dist/chunk-BZU2O43F.js +1125 -0
- package/dist/chunk-C3L6YQ7P.js +147 -0
- package/dist/chunk-C57KJOUQ.js +121 -0
- package/dist/chunk-CCV7BPSY.js +118 -0
- package/dist/chunk-CD7ISXA4.js +826 -0
- package/dist/chunk-CE5OZBYY.js +21 -0
- package/dist/chunk-CFBIG37O.js +154 -0
- package/dist/chunk-CJC6GZ46.js +457 -0
- package/dist/chunk-CKCDGXIV.js +408 -0
- package/dist/chunk-CKNX3TTP.js +10338 -0
- package/dist/chunk-CLKSETWE.js +10 -0
- package/dist/chunk-CP7H3HSP.js +1552 -0
- package/dist/chunk-CPLEWXNZ.js +66 -0
- package/dist/chunk-CQM3A35X.js +844 -0
- package/dist/chunk-CS6P76D3.js +103 -0
- package/dist/chunk-CTLUBNCW.js +622 -0
- package/dist/chunk-CUSRN6RJ.js +632 -0
- package/dist/chunk-D5EP5D2W.js +26 -0
- package/dist/chunk-D5RYINO7.js +412 -0
- package/dist/chunk-DBFS4HMH.js +751 -0
- package/dist/chunk-DC4ZYMXJ.js +115 -0
- package/dist/chunk-DCBZP442.js +9243 -0
- package/dist/chunk-DCYF7EKG.js +26 -0
- package/dist/chunk-DDMAFNUK.js +5351 -0
- package/dist/chunk-DF5SLDE4.js +966 -0
- package/dist/chunk-DJFW7SMX.js +348 -0
- package/dist/chunk-DQFLLBJW.js +121 -0
- package/dist/chunk-DSFM56OA.js +1203 -0
- package/dist/chunk-DTY4APYV.js +218 -0
- package/dist/chunk-DXH5JBRS.js +437 -0
- package/dist/chunk-E3NTPHEO.js +194 -0
- package/dist/chunk-E74LUIID.js +302 -0
- package/dist/chunk-EI57M5BI.js +194 -0
- package/dist/chunk-EJ4ZAWLV.js +305 -0
- package/dist/chunk-EJGCZGUF.js +1483 -0
- package/dist/chunk-EK2U3YEG.js +486 -0
- package/dist/chunk-ELMFYNV7.js +109 -0
- package/dist/chunk-ENRGKNR5.js +25 -0
- package/dist/chunk-ETYDXCK7.js +679 -0
- package/dist/chunk-EYRH3W74.js +239 -0
- package/dist/chunk-F23DIWNN.js +1024 -0
- package/dist/chunk-F5JO7HAS.js +94 -0
- package/dist/chunk-F7ER6ANO.js +174 -0
- package/dist/chunk-FATUVIIN.js +374 -0
- package/dist/chunk-FC23CTXV.js +322 -0
- package/dist/chunk-FD4ERYEG.js +22 -0
- package/dist/chunk-FH7WOJAE.js +79 -0
- package/dist/chunk-FHOWVDF5.js +1342 -0
- package/dist/chunk-FKAUPHMR.js +96 -0
- package/dist/chunk-FONNFJXA.js +137 -0
- package/dist/chunk-FQ7FSZRW.js +75 -0
- package/dist/chunk-FRG57FPM.js +240 -0
- package/dist/chunk-FUVP64ER.js +31 -0
- package/dist/chunk-FYOILAN5.js +6818 -0
- package/dist/chunk-G35UYQ6Z.js +69 -0
- package/dist/chunk-G36W2T2S.js +1143 -0
- package/dist/chunk-G3L2L5XZ.js +49 -0
- package/dist/chunk-G4THLFV3.js +148 -0
- package/dist/chunk-GAFJEYLK.js +29 -0
- package/dist/chunk-GFGYB2ZU.js +1689 -0
- package/dist/chunk-GG6KJYW6.js +85 -0
- package/dist/chunk-GHHFDU2U.js +55 -0
- package/dist/chunk-GHTZSQB7.js +57 -0
- package/dist/chunk-GK37ILCX.js +1231 -0
- package/dist/chunk-GKN3HMN4.js +2809 -0
- package/dist/chunk-GNVDBVJP.js +156 -0
- package/dist/chunk-GPEL3FBM.js +924 -0
- package/dist/chunk-GPSNGPZS.js +1604 -0
- package/dist/chunk-GSGD5E4C.js +30 -0
- package/dist/chunk-GSUQJJXQ.js +331 -0
- package/dist/chunk-GSV226X6.js +110 -0
- package/dist/chunk-H2AYQIHW.js +224 -0
- package/dist/chunk-H66DXFS5.js +1374 -0
- package/dist/chunk-H6G7QRMQ.js +35 -0
- package/dist/chunk-H7JAGHZT.js +59 -0
- package/dist/chunk-H7ZEFECA.js +316 -0
- package/dist/chunk-HAC6EHZZ.js +79 -0
- package/dist/chunk-HIO33P3G.js +19 -0
- package/dist/chunk-HMVQIPH3.js +547 -0
- package/dist/chunk-HOYBYAOA.js +257 -0
- package/dist/chunk-HX5P3CSP.js +1784 -0
- package/dist/chunk-I46EG2XQ.js +65 -0
- package/dist/chunk-I4NPDSCB.js +279 -0
- package/dist/chunk-I5WRT7ZR.js +514 -0
- package/dist/chunk-IC7I6YIJ.js +301 -0
- package/dist/chunk-IDCSOZVN.js +78 -0
- package/dist/chunk-IFCBYECK.js +112 -0
- package/dist/chunk-IFZCPEY2.js +66 -0
- package/dist/chunk-IKFP2KUR.js +48 -0
- package/dist/chunk-IRFBN336.js +878 -0
- package/dist/chunk-IUXNGKA6.js +152 -0
- package/dist/chunk-IV2RVAN7.js +1356 -0
- package/dist/chunk-IZYIQQ7X.js +53 -0
- package/dist/chunk-J3UUR7DE.js +210 -0
- package/dist/chunk-J54VUAY2.js +566 -0
- package/dist/chunk-J62KPGII.js +464 -0
- package/dist/chunk-J6P3FWWW.js +130 -0
- package/dist/chunk-JKBHJQMT.js +434 -0
- package/dist/chunk-JLS65NUQ.js +14 -0
- package/dist/chunk-JOSYEJKY.js +141 -0
- package/dist/chunk-JPKSXKNB.js +94 -0
- package/dist/chunk-JQNJB2BB.js +2440 -0
- package/dist/chunk-JRVNSWSQ.js +2626 -0
- package/dist/chunk-JSWMRQYG.js +28 -0
- package/dist/chunk-JZKNBBIB.js +152 -0
- package/dist/chunk-K54Y7MLK.js +160 -0
- package/dist/chunk-K65546RE.js +183 -0
- package/dist/chunk-KM3F7SYE.js +702 -0
- package/dist/chunk-KNDYMVWN.js +102 -0
- package/dist/chunk-KNT72VR6.js +132 -0
- package/dist/chunk-KP6YILMU.js +482 -0
- package/dist/chunk-KQEBSK3T.js +274 -0
- package/dist/chunk-KT6VHSPF.js +84 -0
- package/dist/chunk-KTMW65UX.js +14 -0
- package/dist/chunk-KZ5CJVBP.js +1813 -0
- package/dist/chunk-L4427KOE.js +26 -0
- package/dist/chunk-L6OM4A22.js +189 -0
- package/dist/chunk-L7E6XCRA.js +1042 -0
- package/dist/chunk-L7JZLXQL.js +173 -0
- package/dist/chunk-LAMKBTXX.js +40 -0
- package/dist/chunk-LDCF2MKN.js +132 -0
- package/dist/chunk-LEIIWPWQ.js +78 -0
- package/dist/chunk-LFTQVYBB.js +31 -0
- package/dist/chunk-LG3PDRTR.js +2872 -0
- package/dist/chunk-LGHII5ET.js +23 -0
- package/dist/chunk-LH5QY22X.js +1205 -0
- package/dist/chunk-LIVJ6266.js +438 -0
- package/dist/chunk-LKRAR3IH.js +276 -0
- package/dist/chunk-LO23NABI.js +3063 -0
- package/dist/chunk-LO3X5NLS.js +326 -0
- package/dist/chunk-LPITVM7M.js +339 -0
- package/dist/chunk-LR5IJIGV.js +810 -0
- package/dist/chunk-LRGMHROI.js +79 -0
- package/dist/chunk-LUVKFFWR.js +315 -0
- package/dist/chunk-LWCBNGH6.js +35 -0
- package/dist/chunk-LWTN3WRV.js +260 -0
- package/dist/chunk-M3HQYKQX.js +308 -0
- package/dist/chunk-M6GVSPEH.js +1016 -0
- package/dist/chunk-MF5HP6XV.js +221 -0
- package/dist/chunk-MHLCBZJB.js +328 -0
- package/dist/chunk-MN6PL4AN.js +120 -0
- package/dist/chunk-MOEY65Z6.js +5678 -0
- package/dist/chunk-MQ4WA34C.js +206 -0
- package/dist/chunk-MWHF5V7U.js +223 -0
- package/dist/chunk-MWHLBPNU.js +211 -0
- package/dist/chunk-MWK5UZQ3.js +1068 -0
- package/dist/chunk-MYLH2S4G.js +64 -0
- package/dist/chunk-MZ5WYKNA.js +28 -0
- package/dist/chunk-N4VTRA7K.js +131 -0
- package/dist/chunk-N5DX4JAK.js +12 -0
- package/dist/chunk-N65O4XTH.js +5011 -0
- package/dist/chunk-NEQUQHOX.js +223 -0
- package/dist/chunk-NGK6PEOG.js +25 -0
- package/dist/chunk-NJVD4PWE.js +1033 -0
- package/dist/chunk-NM6PMYY4.js +768 -0
- package/dist/chunk-NN4PJDHP.js +708 -0
- package/dist/chunk-NP2V3L7K.js +226 -0
- package/dist/chunk-NRLY536M.js +260 -0
- package/dist/chunk-NRNE225N.js +1270 -0
- package/dist/chunk-NS2K2GTP.js +605 -0
- package/dist/chunk-NS33V3IM.js +51 -0
- package/dist/chunk-NSHASMZZ.js +71 -0
- package/dist/chunk-NWOYOA6H.js +378 -0
- package/dist/chunk-NWRUSEXG.js +322 -0
- package/dist/chunk-NZGDAWIP.js +1905 -0
- package/dist/chunk-O47UOKU3.js +395 -0
- package/dist/chunk-O4G2W3ST.js +9831 -0
- package/dist/chunk-O6V4PNLO.js +63 -0
- package/dist/chunk-OA4GPILI.js +624 -0
- package/dist/chunk-OGMSYL6J.js +227 -0
- package/dist/chunk-OIS7J26S.js +319 -0
- package/dist/chunk-OMX5VL43.js +79 -0
- package/dist/chunk-ON3G73BU.js +264 -0
- package/dist/chunk-OPYFYTWQ.js +220 -0
- package/dist/chunk-OQ6K46CK.js +1734 -0
- package/dist/chunk-OYZYO7TV.js +47 -0
- package/dist/chunk-OZ4REHIN.js +4386 -0
- package/dist/chunk-P47VN5F4.js +282 -0
- package/dist/chunk-P5I4X7A7.js +353 -0
- package/dist/chunk-P6VQROCO.js +594 -0
- package/dist/chunk-P7CQGPLS.js +30 -0
- package/dist/chunk-PCAGC5MR.js +1763 -0
- package/dist/chunk-PFTQBXS6.js +5181 -0
- package/dist/chunk-PGSPX4SU.js +15 -0
- package/dist/chunk-PIKLF7BM.js +432 -0
- package/dist/chunk-PJWJ3SAV.js +22 -0
- package/dist/chunk-PKIFMV72.js +100 -0
- package/dist/chunk-PL37JDNA.js +189 -0
- package/dist/chunk-PTH5E5XO.js +195 -0
- package/dist/chunk-PW6AXLQC.js +4128 -0
- package/dist/chunk-PYITM4N2.js +79 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-Q3RO7N35.js +45 -0
- package/dist/chunk-Q3WIC6GQ.js +2670 -0
- package/dist/chunk-Q5XIXSHX.js +271 -0
- package/dist/chunk-QGJDMEOV.js +34 -0
- package/dist/chunk-QNOB37UH.js +58 -0
- package/dist/chunk-QOCOVLUH.js +462 -0
- package/dist/chunk-QTCJ5CC5.js +172 -0
- package/dist/chunk-QVFV5IP2.js +232 -0
- package/dist/chunk-QVZMFDYG.js +29 -0
- package/dist/chunk-R35PEUKH.js +511 -0
- package/dist/chunk-R4UWBC35.js +200 -0
- package/dist/chunk-R6MLCREW.js +44 -0
- package/dist/chunk-R6W23LKN.js +254 -0
- package/dist/chunk-R7XDDX2A.js +4007 -0
- package/dist/chunk-RDFRCT64.js +168 -0
- package/dist/chunk-RE5VZDFQ.js +58 -0
- package/dist/chunk-RGROYC2G.js +638 -0
- package/dist/chunk-RGWHUI5E.js +68 -0
- package/dist/chunk-RHVG6UNL.js +205 -0
- package/dist/chunk-RI4EX2QE.js +18 -0
- package/dist/chunk-RJAAKDRX.js +17 -0
- package/dist/chunk-ROMHOSMQ.js +185 -0
- package/dist/chunk-RWREC3KJ.js +517 -0
- package/dist/chunk-RYNETRDJ.js +118 -0
- package/dist/chunk-RZY7RKM5.js +500 -0
- package/dist/chunk-S2MNWFAG.js +52 -0
- package/dist/chunk-S2VQCZO4.js +22 -0
- package/dist/chunk-S54MKU6V.js +117 -0
- package/dist/chunk-S5OIDFRM.js +302 -0
- package/dist/chunk-SCW4ZF6R.js +150 -0
- package/dist/chunk-SLS2N4PH.js +2213 -0
- package/dist/chunk-SNLBO4BF.js +247 -0
- package/dist/chunk-SP3LFU6B.js +60 -0
- package/dist/chunk-SQQTDDQA.js +537 -0
- package/dist/chunk-STV6LYYE.js +45 -0
- package/dist/chunk-SURZ2WFE.js +326 -0
- package/dist/chunk-SZ7DL357.js +1047 -0
- package/dist/chunk-T5E4NQCM.js +5742 -0
- package/dist/chunk-TAJPCXSB.js +13 -0
- package/dist/chunk-TAOOYK3P.js +358 -0
- package/dist/chunk-TDSEX5CF.js +24 -0
- package/dist/chunk-TFTGP7Z7.js +174 -0
- package/dist/chunk-TGON4N4O.js +197 -0
- package/dist/chunk-TGQZHDY2.js +2373 -0
- package/dist/chunk-TJJZ2OKV.js +6783 -0
- package/dist/chunk-TRSVUPCX.js +25 -0
- package/dist/chunk-TSXGRLPR.js +107 -0
- package/dist/chunk-U2S3YEX3.js +224 -0
- package/dist/chunk-U45RTRGY.js +818 -0
- package/dist/chunk-U6C3VVWS.js +13 -0
- package/dist/chunk-UDMS5AD3.js +307 -0
- package/dist/chunk-UGX7GI37.js +94 -0
- package/dist/chunk-UH3JJSHK.js +1 -0
- package/dist/chunk-UHRBTZYY.js +208 -0
- package/dist/chunk-UHT2KRG5.js +193 -0
- package/dist/chunk-UI2F6DJ5.js +118 -0
- package/dist/chunk-UMAKSB4Z.js +284 -0
- package/dist/chunk-UR2IBGIM.js +521 -0
- package/dist/chunk-UUH2RVKS.js +585 -0
- package/dist/chunk-UVJ4PJDK.js +4533 -0
- package/dist/chunk-V53UG2OT.js +9924 -0
- package/dist/chunk-V72RMBM4.js +48 -0
- package/dist/chunk-VBNCKCCI.js +16 -0
- package/dist/chunk-VNSYKC25.js +24 -0
- package/dist/chunk-VPHVFK4A.js +1984 -0
- package/dist/chunk-VTLNJQ44.js +133 -0
- package/dist/chunk-VTW7HP3R.js +100 -0
- package/dist/chunk-VVGEPBPS.js +218 -0
- package/dist/chunk-VVLLL7I4.js +166 -0
- package/dist/chunk-VX3UMWB7.js +483 -0
- package/dist/chunk-VXF4Q3FW.js +20 -0
- package/dist/chunk-W3JMT2YY.js +712 -0
- package/dist/chunk-WDUORIHF.js +877 -0
- package/dist/chunk-WDVTY4U6.js +148 -0
- package/dist/chunk-WIFZCHEG.js +12566 -0
- package/dist/chunk-WIRN3F75.js +736 -0
- package/dist/chunk-WMPU2UOV.js +82 -0
- package/dist/chunk-WTOKKE2V.js +784 -0
- package/dist/chunk-WX5IRLF6.js +740 -0
- package/dist/chunk-WZ6U3O7I.js +1581 -0
- package/dist/chunk-XAONGNST.js +57 -0
- package/dist/chunk-XB5YLCLB.js +13 -0
- package/dist/chunk-XEP5NQ5Y.js +688 -0
- package/dist/chunk-XGYF2QMZ.js +351 -0
- package/dist/chunk-XHEKQENB.js +255 -0
- package/dist/chunk-XNO4FM6X.js +1124 -0
- package/dist/chunk-XPHKYHO4.js +878 -0
- package/dist/chunk-XPK2I4NC.js +405 -0
- package/dist/chunk-XPU2XADL.js +2175 -0
- package/dist/chunk-XQD2B6BB.js +507 -0
- package/dist/chunk-XT2ZQVTC.js +558 -0
- package/dist/chunk-XTXJGGUV.js +351 -0
- package/dist/chunk-XUXVDPSZ.js +50 -0
- package/dist/chunk-XV7NZL4B.js +57 -0
- package/dist/chunk-XZE4XARH.js +563 -0
- package/dist/chunk-XZYR5EDO.js +152 -0
- package/dist/chunk-Y3J4JMTU.js +61 -0
- package/dist/chunk-Y55LZN5U.js +52 -0
- package/dist/chunk-Y5VN7DMP.js +112 -0
- package/dist/chunk-Y67VAHN4.js +459 -0
- package/dist/chunk-YAXSKEUH.js +3544 -0
- package/dist/chunk-YB3JD4E6.js +975 -0
- package/dist/chunk-YESZJFK6.js +220 -0
- package/dist/chunk-YGXKOBQQ.js +292 -0
- package/dist/chunk-YMX76IOS.js +31 -0
- package/dist/chunk-YOTXESEH.js +257 -0
- package/dist/chunk-YTYIEZQY.js +119 -0
- package/dist/chunk-YVORHQ2S.js +579 -0
- package/dist/chunk-Z2CUQDAR.js +3429 -0
- package/dist/chunk-Z2KYOFHS.js +7000 -0
- package/dist/chunk-Z6PC7QX6.js +161 -0
- package/dist/chunk-ZDTGECTN.js +235 -0
- package/dist/chunk-ZIPWI2LY.js +151 -0
- package/dist/chunk-ZSKKMTQJ.js +554 -0
- package/dist/chunk-ZTT5IVPY.js +1160 -0
- package/dist/chunk-ZX65UI5W.js +78 -0
- package/dist/chunk-ZYG7GGKO.js +218 -0
- package/dist/chunk-ZZZUL4OF.js +38 -0
- package/dist/cli-utils-IXL26KJT.js +40 -0
- package/dist/cli-validation-WLXWLUJL.js +111 -0
- package/dist/commit-utils-P7CRJF5N.js +202 -0
- package/dist/compete-config-resolver-R5ULXMYH.js +76 -0
- package/dist/compete-request-62JESVET.js +364 -0
- package/dist/compete-results-QEPG6FZX.js +208 -0
- package/dist/competition-outcome-tracker-R32OOZ43.js +38 -0
- package/dist/config-JCOKXOQT.js +166 -0
- package/dist/config-audit-EL3GHXS7.js +360 -0
- package/dist/config-explain-TNILDEVJ.js +12 -0
- package/dist/config-loader-VPFPFO4B.js +38 -0
- package/dist/config-manager-7T4E2BQO.js +67 -0
- package/dist/config-validator-KKOHOW7O.js +72 -0
- package/dist/cost-YC42XUF3.js +53 -0
- package/dist/coverage-orchestrator-CISNKJC2.js +772 -0
- package/dist/coverage-scanner-YVD62MLH.js +12 -0
- package/dist/createCompetitionRunner-LJG6ZQSO.js +46 -0
- package/dist/data-migration-state-VJK64DLT.js +31 -0
- package/dist/db-migrator-XSEIOGWY.js +34 -0
- package/dist/discovery-JGYGDD25.js +25 -0
- package/dist/doctor-GJOYE7AE.js +186 -0
- package/dist/domain-analyzer-AWF3RP6E.js +29 -0
- package/dist/ensure-initialized-744DIZEZ.js +52 -0
- package/dist/entry.js +940 -0
- package/dist/environment-YS45U5ZI.js +81 -0
- package/dist/error-parser-core-PPZ36A4S.js +50 -0
- package/dist/escalation-ladder-MKTCEGSA.js +130 -0
- package/dist/evaluation-context-KV4GZNN7.js +35 -0
- package/dist/evidence-plan-resolver-GBSYSAPX.js +85 -0
- package/dist/execution-data-writer-3ODTBDLH.js +53 -0
- package/dist/execution-policy-applier-ZHD3DCF3.js +31 -0
- package/dist/execution-preflight-Z4Y64V3I.js +209 -0
- package/dist/execution-roles-R3DPPMD3.js +66 -0
- package/dist/exit-code-error-Z4SW2DVK.js +14 -0
- package/dist/external-temp-cleanup-N2RZH4QP.js +311 -0
- package/dist/factory-XBN7DFIM.js +149 -0
- package/dist/file-utils-XIVR2ZMA.js +47 -0
- package/dist/flywheel-autoloop-executor-UILGOFFK.js +249 -0
- package/dist/flywheel-competition-executor-JOBEXTRB.js +259 -0
- package/dist/flywheel-executor-6JFLA6J5.js +369 -0
- package/dist/flywheel-git-isolation-UC5NIEVU.js +48 -0
- package/dist/flywheel-manifest-5UC4VBMA.js +108 -0
- package/dist/flywheel-model-defaults-7CVKP53V.js +27 -0
- package/dist/flywheel-preflight-XEY5SHM6.js +104 -0
- package/dist/flywheel-resume-7HELH7QS.js +23 -0
- package/dist/flywheel-safety-7U7DPOAP.js +28 -0
- package/dist/flywheel-scope-decision-ZHKF6ZIN.js +11 -0
- package/dist/get-telemetry-logger-DPVWWIYY.js +73 -0
- package/dist/git-worktree-IY6V6DUO.js +18 -0
- package/dist/github-pr-manager-4LXEKJTA.js +211 -0
- package/dist/guidance-profile-config-E7XJL2VP.js +117 -0
- package/dist/guidance-profile-renderer-QK2YMAAP.js +21 -0
- package/dist/index-query-4JEUKA44.js +31 -0
- package/dist/index.js +108661 -0
- package/dist/instructions-6BURLQJC.js +64 -0
- package/dist/invoke-provider-auth-GRUYP44M.js +223 -0
- package/dist/judge-scoring.json +80 -0
- package/dist/judge-test.js +555 -0
- package/dist/lab-mode-OTWVHN63.js +39 -0
- package/dist/lab-utils-BJRFLGK4.js +23 -0
- package/dist/linux-host-class-UY4KVLFD.js +29 -0
- package/dist/llm-judge-executor-F7Z3HO77.js +133 -0
- package/dist/local-executor-CEHWE2PL.js +223 -0
- package/dist/logger-33TR6EE5.js +72 -0
- package/dist/loop-spec-XTLQAVZ7.js +191 -0
- package/dist/manager-2HJG5CLT.js +25 -0
- package/dist/matrix-prompt-builder-6UDN5X3F.js +497 -0
- package/dist/matrix-result-parser-7W35EUOV.js +15 -0
- package/dist/metadata-HQ43NDEK.js +22 -0
- package/dist/model-invocations-db-QBO4Y7WZ.js +38 -0
- package/dist/monitor-XGYBG2DW.js +72 -0
- package/dist/next-PB5ZXZKB.js +90 -0
- package/dist/next-ZBDK725T.js +69 -0
- package/dist/optimization-config-resolver-O6WKR47U.js +75 -0
- package/dist/package-3YCWIQQ5.js +10 -0
- package/dist/parallel-orchestrator-NL7YJJU2.js +297 -0
- package/dist/parallel-worker.js +279 -0
- package/dist/parse-git-status-PIAF3OTP.js +10 -0
- package/dist/path-security-ETTH6TZL.js +39 -0
- package/dist/pattern-bank-UNJR5ADV.js +15 -0
- package/dist/plan-backlog-list-fast-VAGYBV3J.js +270 -0
- package/dist/plan-backlog-show-fast-SG2CZPW3.js +406 -0
- package/dist/plan-sprint-list-fast-LURAX47V.js +162 -0
- package/dist/plan-sprint-status-fast-FJAODCHD.js +208 -0
- package/dist/plan-task-status-fast-HNYBMQI4.js +349 -0
- package/dist/plan-to-flywheel-Z4U3GWPN.js +456 -0
- package/dist/planning-backlog-3CQ5QQBQ.js +319 -0
- package/dist/poetic-root-V5DNXEAE.js +17 -0
- package/dist/preflight-OPANWMME.js +12 -0
- package/dist/process-registry-PDZJPTAS.js +27 -0
- package/dist/process-scanner-C22SYXYD.js +22 -0
- package/dist/processes-KMQUD7HY.js +29 -0
- package/dist/processes-json-fast-IBDXZ6WW.js +135 -0
- package/dist/profile-SE5EVXAP.js +149 -0
- package/dist/prompts-WZZPGWBX.js +168 -0
- package/dist/protected-branches-RNTEX7ET.js +57 -0
- package/dist/provider-aware-resource-manager-QBTZJMNP.js +18 -0
- package/dist/provider-matrix-N5X57V3Y.js +154 -0
- package/dist/provider-matrix-renderer-MZDWKKID.js +139 -0
- package/dist/provider-output-forwarding-DERID3TP.js +30 -0
- package/dist/provider-registry-J5NRBJKI.js +128 -0
- package/dist/provider-temp-cleanup-KYGLF6YU.js +14 -0
- package/dist/prune-engine-Q6E2DXBN.js +451 -0
- package/dist/quality-gate-YRHMQAEI.js +70 -0
- package/dist/quickstart-FIRLKGJI.js +62 -0
- package/dist/readiness-VZTMSG6J.js +96 -0
- package/dist/registry-YODFY77A.js +153 -0
- package/dist/repair-helpers-TTV5FEF4.js +117 -0
- package/dist/repo-root-2IGD4H7X.js +22 -0
- package/dist/resolution-engine-D6TX6FRG.js +127 -0
- package/dist/resolve-provider-cli-O2P6XZBZ.js +35 -0
- package/dist/restore-telemetry-db-BQL6DTQF.js +360 -0
- package/dist/result-streamer-WEHW476R.js +19 -0
- package/dist/routing-events-DHPUZDDF.js +27 -0
- package/dist/routing-history-store-UWCEXAP3.js +46 -0
- package/dist/routing-planner-F5WQEUOM.js +160 -0
- package/dist/run-poetic-tui-J6LWRJUP.js +13517 -0
- package/dist/run-simulation.js +376 -0
- package/dist/runner-CS2TNGHA.js +1092 -0
- package/dist/runner-HHH7ZN2Z.js +1571 -0
- package/dist/safety-OCC4KJJR.js +64 -0
- package/dist/safety-stanza-7SV3HGG3.js +60 -0
- package/dist/sandbox-32QXJEMV.js +81 -0
- package/dist/sandbox-RSO7VP6V.js +94 -0
- package/dist/schema-extensions.sql +234 -0
- package/dist/security-2KI5XNDG.js +17 -0
- package/dist/setup-bb-plugin-QAQWZCV5.js +738 -0
- package/dist/setup-claude-code-P7BTTSPO.js +317 -0
- package/dist/setup-temp-cleanup-GASCWZ2I.js +20 -0
- package/dist/shared-utils-D6U6UREP.js +37 -0
- package/dist/simple-artifact-goal-OTXNGZY6.js +25 -0
- package/dist/sprint-UIXPYOXQ.js +338 -0
- package/dist/sprint-bridge-4BHMSC3M.js +68 -0
- package/dist/sprint-execution-service-2B7WHL5L.js +311 -0
- package/dist/sprint-manager-IDQUDNQI.js +91 -0
- package/dist/sqlite-wrapper-UDWCTNLJ.js +17 -0
- package/dist/stale-cleanup-orchestrator-XWXV7KCZ.js +62 -0
- package/dist/storage-access-F6ALDN4S.js +22 -0
- package/dist/synthesis-XD6EDVHF.js +185 -0
- package/dist/task-classifier-LNLXSHOM.js +494 -0
- package/dist/task-list-fast-PTMA4LUC.js +147 -0
- package/dist/task-manager-XAT7GOWB.js +93 -0
- package/dist/task-splitter-U7DJ7W6A.js +79 -0
- package/dist/task-type-detector-OLVOMXZO.js +21 -0
- package/dist/task-type-resolver-KKNQYSB4.js +42 -0
- package/dist/telemetry-5HWBBXLX.js +131 -0
- package/dist/telemetry-health-tracker-DMSSGBZ2.js +11 -0
- package/dist/telemetry-path-resolver-7ICSG276.js +28 -0
- package/dist/telemetry-reliability-XUOZNZZ6.js +125 -0
- package/dist/token-estimator-MEQUL3EJ.js +37 -0
- package/dist/transports-KNSSV2V4.js +255 -0
- package/dist/unified-cost-tracker-4TFRBVPR.js +35 -0
- package/dist/unified-state-cleanup-LJPF2BOW.js +276 -0
- package/dist/universal-cost-calculator-BAJV35GA.js +42 -0
- package/dist/user-agents-GHUGCSKN.js +22 -0
- package/dist/variant-delivery-state-KLRNG6XA.js +33 -0
- package/dist/variant-state-cleanup-MZGGLQAJ.js +280 -0
- package/dist/variant-success-PJXWE3ZV.js +12 -0
- package/dist/variant-worker-KUWKBLAH.js +4196 -0
- package/dist/variant-worker.js +24 -0
- package/dist/variants-JE2FSAQS.js +233 -0
- package/dist/verification-toolchains-V24UHW6Q.js +28 -0
- package/dist/verify-commands-H3DTCSGI.js +37 -0
- package/dist/warning-EGQGUUIO.js +12 -0
- package/dist/work-edge-RWEDWJZF.js +49 -0
- package/dist/work-item-writer-WHAVZXAY.js +19 -0
- package/dist/worker-7SA2VS2Y.js +1435 -0
- package/dist/worker.js +19 -0
- package/dist/worktree-metrics-3DFUYVYE.js +26 -0
- package/dist/writeback-VZKHYHSN.js +44 -0
- package/docs/CLI_REFERENCE.md +7042 -0
- package/docs/PROVIDER_SETUP.md +1570 -0
- package/docs/README.md +96 -0
- package/docs/TROUBLESHOOTING.md +2232 -0
- package/docs/getting-started/QUICK_START.md +294 -0
- package/docs/getting-started/README.md +188 -0
- package/docs/getting-started/SETUP.md +52 -0
- package/docs/reference/AGENT_CONTEXT.md +38 -0
- package/docs/reference/PROVIDER_RELEASE_TIERS.md +34 -0
- package/docs/reference/README.md +381 -0
- package/docs/reference/SECURITY.md +262 -0
- package/integrations/bb-plugin-poetic/README.md +362 -0
- package/integrations/bb-plugin-poetic/app.css +341 -0
- package/integrations/bb-plugin-poetic/app.tsx +5059 -0
- package/integrations/bb-plugin-poetic/package.json +45 -0
- package/integrations/bb-plugin-poetic/server.ts +444 -0
- package/integrations/bb-plugin-poetic/src/adapter.ts +3312 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-model.ts +150 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-schema.ts +355 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-service.ts +419 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-view.ts +1026 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-schema.ts +122 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-service.ts +105 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-view.ts +138 -0
- package/integrations/bb-plugin-poetic/src/contract.ts +615 -0
- package/integrations/bb-plugin-poetic/src/finalize-model.ts +205 -0
- package/integrations/bb-plugin-poetic/src/finalize-schema.ts +158 -0
- package/integrations/bb-plugin-poetic/src/finalize-service.ts +382 -0
- package/integrations/bb-plugin-poetic/src/finalize-view.ts +159 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-readback.ts +303 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-schema.ts +33 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-view.ts +459 -0
- package/integrations/bb-plugin-poetic/src/model.ts +1302 -0
- package/integrations/bb-plugin-poetic/src/monitor-service.ts +233 -0
- package/integrations/bb-plugin-poetic/src/panel-read-ux.ts +97 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-schema.ts +166 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-service.ts +480 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-view.ts +109 -0
- package/integrations/bb-plugin-poetic/src/planning-readback.ts +204 -0
- package/integrations/bb-plugin-poetic/src/planning-service.ts +594 -0
- package/integrations/bb-plugin-poetic/src/planning-workspace-schema.ts +95 -0
- package/integrations/bb-plugin-poetic/src/planning-workspace.ts +323 -0
- package/integrations/bb-plugin-poetic/src/poll-handoff.ts +136 -0
- package/integrations/bb-plugin-poetic/src/project-target-server.ts +21 -0
- package/integrations/bb-plugin-poetic/src/project-target.ts +45 -0
- package/integrations/bb-plugin-poetic/src/reference-index.ts +192 -0
- package/integrations/bb-plugin-poetic/src/repository-schema.ts +30 -0
- package/integrations/bb-plugin-poetic/src/result-explorer-view.ts +597 -0
- package/integrations/bb-plugin-poetic/src/result-readback-model.ts +163 -0
- package/integrations/bb-plugin-poetic/src/result-readback-schema.ts +319 -0
- package/integrations/bb-plugin-poetic/src/result-readback-service.ts +333 -0
- package/integrations/bb-plugin-poetic/src/run-page-view.ts +177 -0
- package/integrations/bb-plugin-poetic/src/setup-config-schema.ts +291 -0
- package/integrations/bb-plugin-poetic/src/setup-config-service.ts +590 -0
- package/integrations/bb-plugin-poetic/src/setup-config-view.ts +413 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-model.ts +150 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-schema.ts +136 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-service.ts +341 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-view.ts +116 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-model.ts +714 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-readback.ts +231 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-schema.ts +601 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-service.ts +775 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-view.ts +1221 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-model.ts +567 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-schema.ts +635 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-service.ts +842 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-view.ts +1227 -0
- package/integrations/bb-plugin-poetic/src/task-detail-readback.ts +56 -0
- package/integrations/bb-plugin-poetic/src/task-detail-schema.ts +144 -0
- package/integrations/bb-plugin-poetic/src/task-navigation.ts +446 -0
- package/integrations/bb-plugin-poetic/src/workbench-route.ts +74 -0
- package/integrations/bb-plugin-poetic/tests/host-contract.test.ts +773 -0
- package/integrations/bb-plugin-poetic/tsconfig.json +18 -0
- package/integrations/bb-plugin-poetic/types/PROVENANCE.json +52 -0
- package/integrations/bb-plugin-poetic/types/bb-plugin-sdk-app.d.ts +1444 -0
- package/integrations/bb-plugin-poetic/types/bb-plugin-sdk.d.ts +13030 -0
- package/integrations/bb-plugin-poetic/vitest.host.config.ts +71 -0
- package/npm-shrinkwrap.json +4950 -0
- package/package.json +331 -0
- package/schemas/README.md +80 -0
- package/schemas/config-v1.schema.json +136 -0
- package/schemas/execution-config.schema.json +47 -0
- package/schemas/judge-scoring.schema.json +370 -0
- package/schemas/poetic.config.schema.json +2214 -0
- package/schemas/provider-config.schema.json +203 -0
- package/schemas/telemetry-config.schema.json +79 -0
- package/schemas/user-preferences.schema.json +141 -0
- package/scripts/assert-node-runtime.mjs +140 -0
- package/scripts/preflight-native.mjs +49 -0
- package/scripts/preinstall-node-check.mjs +78 -0
- package/scripts/setup-git-hooks.mjs +24 -0
- package/scripts/sync.sh +2722 -0
- package/scripts/write-node-launcher.sh +108 -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/.poetic/README.md +37 -0
- package/templates/.poetic/agents/README.md +296 -0
- package/templates/.poetic/agents/api-documenter.md +147 -0
- package/templates/.poetic/agents/backend-architect.md +31 -0
- package/templates/.poetic/agents/code-reviewer.md +157 -0
- package/templates/.poetic/agents/data-scientist.md +179 -0
- package/templates/.poetic/agents/database-optimizer.md +145 -0
- package/templates/.poetic/agents/debugger.md +31 -0
- package/templates/.poetic/agents/deployment-engineer.md +164 -0
- package/templates/.poetic/agents/devops-troubleshooter.md +139 -0
- package/templates/.poetic/agents/frontend-developer.md +150 -0
- package/templates/.poetic/agents/javascript-pro.md +36 -0
- package/templates/.poetic/agents/performance-engineer.md +151 -0
- package/templates/.poetic/agents/python-pro.md +137 -0
- package/templates/.poetic/agents/test-automator.md +147 -0
- package/templates/.poetic/agents/typescript-pro.md +34 -0
- package/templates/.poetic/config/poetic.config.jsonc +69 -0
- package/templates/.poetic/config/project-context.template.json +6 -0
- package/templates/.poetic/config/task-type-aliases.presets/kanban.yaml +14 -0
- package/templates/.poetic/config/task-type-aliases.presets/scrum.yaml +17 -0
- package/templates/.poetic/config/task-type-aliases.presets/xp.yaml +12 -0
- package/templates/.poetic/config/task-type-aliases.yaml +28 -0
- package/templates/.poetic/gitignore.template +55 -0
- package/templates/.poetic/task-types/analysis.yaml +40 -0
- package/templates/.poetic/task-types/architecture.yaml +38 -0
- package/templates/.poetic/task-types/doc.yaml +35 -0
- package/templates/.poetic/task-types/feature.yaml +23 -0
- package/templates/.poetic/task-types/general.yaml +6 -0
- package/templates/.poetic/task-types/security.yaml +39 -0
- package/templates/AGENTS.template.md +99 -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/compete-streak.yaml +78 -0
- package/templates/builtin-workflows/hello-verify.yaml +10 -0
- package/templates/builtin-workflows/judge-regression.yaml +114 -0
- package/templates/builtin-workflows/skills/code-review/SKILL.md +60 -0
- package/templates/builtin-workflows/skills/hello-verify/SKILL.md +6 -0
- package/templates/guard-kit/GUARD_SETUP.md.template +255 -0
- package/templates/guard-kit/check.mjs.template +777 -0
- package/templates/guard-kit/config.json.template +6 -0
- package/templates/guard-kit/poetic-guard.yml.template +189 -0
- package/templates/profiles/README.md +56 -0
- package/templates/profiles/frontier-claude.json +27 -0
- package/templates/profiles/frontier-codex.json +26 -0
|
@@ -0,0 +1,4120 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveAutoloopElapsedMs
|
|
3
|
+
} from "./chunk-MZ5WYKNA.js";
|
|
4
|
+
import {
|
|
5
|
+
deriveDirectAutoloopRecovery,
|
|
6
|
+
getCarriedDirectAutoloopFailureEnvelope,
|
|
7
|
+
globalRecursionTracker,
|
|
8
|
+
isSignificantProgress,
|
|
9
|
+
rateProgress,
|
|
10
|
+
serializeDirectAutoloopFailureRecovery
|
|
11
|
+
} from "./chunk-J54VUAY2.js";
|
|
12
|
+
import {
|
|
13
|
+
classifyFailureEnvelope
|
|
14
|
+
} from "./chunk-NWRUSEXG.js";
|
|
15
|
+
import {
|
|
16
|
+
parseFailureOutput
|
|
17
|
+
} from "./chunk-ACKIPAOJ.js";
|
|
18
|
+
import {
|
|
19
|
+
computeMonotonicAutoloopEscalation,
|
|
20
|
+
execWithTimeout,
|
|
21
|
+
validateRequirements
|
|
22
|
+
} from "./chunk-35P3W3JX.js";
|
|
23
|
+
import {
|
|
24
|
+
calculateSatisfactionScore,
|
|
25
|
+
checkAcceptanceCriteria
|
|
26
|
+
} from "./chunk-UMAKSB4Z.js";
|
|
27
|
+
import {
|
|
28
|
+
COMPLETION_BLOCKER_PROGRESS_VERIFICATION_UNAVAILABLE,
|
|
29
|
+
completionStatusAllowsSuccess,
|
|
30
|
+
customGatesAllowCompletion,
|
|
31
|
+
customGatesHaveBlockingFailure,
|
|
32
|
+
evaluateCompletion,
|
|
33
|
+
hasSubstantiveCompletionEvidence,
|
|
34
|
+
isBlockingCustomGateForCompletion,
|
|
35
|
+
isBlockingQualityGateForCompletion,
|
|
36
|
+
isSuccessLikeControllerReason,
|
|
37
|
+
isUnavailableOrSkippedQualityGate,
|
|
38
|
+
qualityGatesAllowCompletion,
|
|
39
|
+
qualityGatesHaveBlockingFailure,
|
|
40
|
+
verificationGatesUnavailableOnly
|
|
41
|
+
} from "./chunk-4IAPOG5V.js";
|
|
42
|
+
import {
|
|
43
|
+
DEFAULT_AUTOLOOP_TIMEBOX_MS,
|
|
44
|
+
resolveAutoloopTimeboxMs,
|
|
45
|
+
resolveAutoloopValidationMode
|
|
46
|
+
} from "./chunk-H7JAGHZT.js";
|
|
47
|
+
import {
|
|
48
|
+
countBlockingVulnerabilities
|
|
49
|
+
} from "./chunk-SQQTDDQA.js";
|
|
50
|
+
import "./chunk-R6MLCREW.js";
|
|
51
|
+
import "./chunk-Z2KYOFHS.js";
|
|
52
|
+
import "./chunk-K54Y7MLK.js";
|
|
53
|
+
import "./chunk-FONNFJXA.js";
|
|
54
|
+
import "./chunk-XZYR5EDO.js";
|
|
55
|
+
import "./chunk-4RCCF5BR.js";
|
|
56
|
+
import "./chunk-PL37JDNA.js";
|
|
57
|
+
import "./chunk-WIRN3F75.js";
|
|
58
|
+
import "./chunk-Y5VN7DMP.js";
|
|
59
|
+
import "./chunk-6EDAJH2I.js";
|
|
60
|
+
import "./chunk-3FLXLLB7.js";
|
|
61
|
+
import "./chunk-5H72XE4H.js";
|
|
62
|
+
import "./chunk-DXH5JBRS.js";
|
|
63
|
+
import "./chunk-APPNGGN7.js";
|
|
64
|
+
import "./chunk-5HDP7XZG.js";
|
|
65
|
+
import "./chunk-EK2U3YEG.js";
|
|
66
|
+
import "./chunk-IV2RVAN7.js";
|
|
67
|
+
import "./chunk-MYLH2S4G.js";
|
|
68
|
+
import "./chunk-73BBJOKA.js";
|
|
69
|
+
import "./chunk-IC7I6YIJ.js";
|
|
70
|
+
import "./chunk-CLKSETWE.js";
|
|
71
|
+
import "./chunk-V53UG2OT.js";
|
|
72
|
+
import "./chunk-LKRAR3IH.js";
|
|
73
|
+
import "./chunk-QTCJ5CC5.js";
|
|
74
|
+
import "./chunk-MWHF5V7U.js";
|
|
75
|
+
import "./chunk-3FOZ2VHV.js";
|
|
76
|
+
import "./chunk-WZ6U3O7I.js";
|
|
77
|
+
import "./chunk-VTW7HP3R.js";
|
|
78
|
+
import "./chunk-4CUY7AFY.js";
|
|
79
|
+
import "./chunk-MWK5UZQ3.js";
|
|
80
|
+
import "./chunk-MN6PL4AN.js";
|
|
81
|
+
import "./chunk-NS33V3IM.js";
|
|
82
|
+
import "./chunk-UHRBTZYY.js";
|
|
83
|
+
import "./chunk-KP6YILMU.js";
|
|
84
|
+
import {
|
|
85
|
+
shouldIgnoreRepoPath
|
|
86
|
+
} from "./chunk-H2AYQIHW.js";
|
|
87
|
+
import "./chunk-FATUVIIN.js";
|
|
88
|
+
import "./chunk-XPU2XADL.js";
|
|
89
|
+
import "./chunk-AURFMVCD.js";
|
|
90
|
+
import "./chunk-VBNCKCCI.js";
|
|
91
|
+
import "./chunk-SZ7DL357.js";
|
|
92
|
+
import "./chunk-LGHII5ET.js";
|
|
93
|
+
import "./chunk-PJWJ3SAV.js";
|
|
94
|
+
import "./chunk-NRLY536M.js";
|
|
95
|
+
import "./chunk-7DNSNKJV.js";
|
|
96
|
+
import "./chunk-HIO33P3G.js";
|
|
97
|
+
import "./chunk-APV6MK5E.js";
|
|
98
|
+
import "./chunk-ZYG7GGKO.js";
|
|
99
|
+
import {
|
|
100
|
+
globalProcessLimiter
|
|
101
|
+
} from "./chunk-PFTQBXS6.js";
|
|
102
|
+
import "./chunk-E3NTPHEO.js";
|
|
103
|
+
import "./chunk-4NXPXE62.js";
|
|
104
|
+
import "./chunk-4VJITV4P.js";
|
|
105
|
+
import "./chunk-GHHFDU2U.js";
|
|
106
|
+
import "./chunk-R6W23LKN.js";
|
|
107
|
+
import "./chunk-UH3JJSHK.js";
|
|
108
|
+
import "./chunk-FC23CTXV.js";
|
|
109
|
+
import "./chunk-36PEBZAF.js";
|
|
110
|
+
import "./chunk-SURZ2WFE.js";
|
|
111
|
+
import "./chunk-SP3LFU6B.js";
|
|
112
|
+
import "./chunk-R4UWBC35.js";
|
|
113
|
+
import "./chunk-2YFUIER7.js";
|
|
114
|
+
import {
|
|
115
|
+
abortableDelay
|
|
116
|
+
} from "./chunk-CKNX3TTP.js";
|
|
117
|
+
import "./chunk-FYOILAN5.js";
|
|
118
|
+
import "./chunk-J62KPGII.js";
|
|
119
|
+
import "./chunk-XAONGNST.js";
|
|
120
|
+
import "./chunk-GAFJEYLK.js";
|
|
121
|
+
import "./chunk-H6G7QRMQ.js";
|
|
122
|
+
import "./chunk-J6P3FWWW.js";
|
|
123
|
+
import "./chunk-CP7H3HSP.js";
|
|
124
|
+
import "./chunk-ETYDXCK7.js";
|
|
125
|
+
import {
|
|
126
|
+
ORCHESTRATOR_FEATURE_FLAGS
|
|
127
|
+
} from "./chunk-BSE4R6XD.js";
|
|
128
|
+
import "./chunk-UR2IBGIM.js";
|
|
129
|
+
import "./chunk-JSWMRQYG.js";
|
|
130
|
+
import "./chunk-XGYF2QMZ.js";
|
|
131
|
+
import {
|
|
132
|
+
signalCoordinator
|
|
133
|
+
} from "./chunk-72YTZMAM.js";
|
|
134
|
+
import "./chunk-S2VQCZO4.js";
|
|
135
|
+
import "./chunk-WMPU2UOV.js";
|
|
136
|
+
import "./chunk-VX3UMWB7.js";
|
|
137
|
+
import "./chunk-XT2ZQVTC.js";
|
|
138
|
+
import "./chunk-YGXKOBQQ.js";
|
|
139
|
+
import "./chunk-V72RMBM4.js";
|
|
140
|
+
import "./chunk-ZDTGECTN.js";
|
|
141
|
+
import "./chunk-G36W2T2S.js";
|
|
142
|
+
import "./chunk-GKN3HMN4.js";
|
|
143
|
+
import "./chunk-QVZMFDYG.js";
|
|
144
|
+
import "./chunk-S54MKU6V.js";
|
|
145
|
+
import "./chunk-3S62LLWJ.js";
|
|
146
|
+
import "./chunk-45FPSA3B.js";
|
|
147
|
+
import "./chunk-YMX76IOS.js";
|
|
148
|
+
import "./chunk-6Y5U7UFY.js";
|
|
149
|
+
import "./chunk-XV7NZL4B.js";
|
|
150
|
+
import "./chunk-CD7ISXA4.js";
|
|
151
|
+
import "./chunk-QGJDMEOV.js";
|
|
152
|
+
import {
|
|
153
|
+
runVerificationCommand
|
|
154
|
+
} from "./chunk-D5RYINO7.js";
|
|
155
|
+
import "./chunk-6TZJRKNW.js";
|
|
156
|
+
import "./chunk-PCAGC5MR.js";
|
|
157
|
+
import "./chunk-5WCQRDRB.js";
|
|
158
|
+
import "./chunk-5WRLK5KW.js";
|
|
159
|
+
import "./chunk-C57KJOUQ.js";
|
|
160
|
+
import "./chunk-DF5SLDE4.js";
|
|
161
|
+
import "./chunk-TGON4N4O.js";
|
|
162
|
+
import "./chunk-I5WRT7ZR.js";
|
|
163
|
+
import "./chunk-A3YGID55.js";
|
|
164
|
+
import "./chunk-5EERLVZB.js";
|
|
165
|
+
import "./chunk-XQD2B6BB.js";
|
|
166
|
+
import "./chunk-34CNP2HB.js";
|
|
167
|
+
import "./chunk-KNDYMVWN.js";
|
|
168
|
+
import "./chunk-RWREC3KJ.js";
|
|
169
|
+
import "./chunk-LO23NABI.js";
|
|
170
|
+
import "./chunk-7R2WLDOS.js";
|
|
171
|
+
import "./chunk-LAMKBTXX.js";
|
|
172
|
+
import "./chunk-FD4ERYEG.js";
|
|
173
|
+
import "./chunk-KTMW65UX.js";
|
|
174
|
+
import {
|
|
175
|
+
detectProjectCapabilities
|
|
176
|
+
} from "./chunk-FHOWVDF5.js";
|
|
177
|
+
import "./chunk-UDMS5AD3.js";
|
|
178
|
+
import "./chunk-MWHLBPNU.js";
|
|
179
|
+
import "./chunk-JLS65NUQ.js";
|
|
180
|
+
import "./chunk-TRSVUPCX.js";
|
|
181
|
+
import "./chunk-FKAUPHMR.js";
|
|
182
|
+
import "./chunk-TSXGRLPR.js";
|
|
183
|
+
import "./chunk-LUVKFFWR.js";
|
|
184
|
+
import "./chunk-ENRGKNR5.js";
|
|
185
|
+
import "./chunk-XB5YLCLB.js";
|
|
186
|
+
import "./chunk-QOCOVLUH.js";
|
|
187
|
+
import "./chunk-2VSQMRCB.js";
|
|
188
|
+
import "./chunk-ON3G73BU.js";
|
|
189
|
+
import "./chunk-3G6FZCRF.js";
|
|
190
|
+
import "./chunk-N5DX4JAK.js";
|
|
191
|
+
import {
|
|
192
|
+
describeVerificationCommand,
|
|
193
|
+
detectExitZeroVerifyFailure
|
|
194
|
+
} from "./chunk-2QLYTVYX.js";
|
|
195
|
+
import "./chunk-7GDRQBQC.js";
|
|
196
|
+
import "./chunk-PGSPX4SU.js";
|
|
197
|
+
import "./chunk-AT4TNPWW.js";
|
|
198
|
+
import "./chunk-GSGD5E4C.js";
|
|
199
|
+
import {
|
|
200
|
+
withExecutionContextEnvOverrides
|
|
201
|
+
} from "./chunk-UI2F6DJ5.js";
|
|
202
|
+
import "./chunk-4BTDUT2S.js";
|
|
203
|
+
import "./chunk-L6OM4A22.js";
|
|
204
|
+
import "./chunk-G4THLFV3.js";
|
|
205
|
+
import "./chunk-RGWHUI5E.js";
|
|
206
|
+
import "./chunk-UUH2RVKS.js";
|
|
207
|
+
import "./chunk-LEIIWPWQ.js";
|
|
208
|
+
import "./chunk-L7JZLXQL.js";
|
|
209
|
+
import "./chunk-IZYIQQ7X.js";
|
|
210
|
+
import "./chunk-JPKSXKNB.js";
|
|
211
|
+
import "./chunk-TAJPCXSB.js";
|
|
212
|
+
import "./chunk-XZE4XARH.js";
|
|
213
|
+
import {
|
|
214
|
+
debugLog,
|
|
215
|
+
emitWarning
|
|
216
|
+
} from "./chunk-EJGCZGUF.js";
|
|
217
|
+
import "./chunk-LPITVM7M.js";
|
|
218
|
+
import {
|
|
219
|
+
POETIC_AUTOLOOP_COMPLETION_SIGNAL,
|
|
220
|
+
POETIC_AUTOLOOP_JUDGE,
|
|
221
|
+
POETIC_AUTOLOOP_MAX_CPU,
|
|
222
|
+
POETIC_AUTOLOOP_MAX_ITERATIONS,
|
|
223
|
+
POETIC_AUTOLOOP_MAX_MEMORY,
|
|
224
|
+
POETIC_AUTOLOOP_MAX_PROCESSES,
|
|
225
|
+
POETIC_AUTOLOOP_MIN_PROGRESS,
|
|
226
|
+
POETIC_AUTOLOOP_QUALITY_GATES_MODE,
|
|
227
|
+
readEnv,
|
|
228
|
+
readRawEnv
|
|
229
|
+
} from "./chunk-5DLKYTQX.js";
|
|
230
|
+
import "./chunk-PZ5AY32C.js";
|
|
231
|
+
|
|
232
|
+
// src/orchestrator/autonomous-loop-controller.ts
|
|
233
|
+
import { createHash } from "crypto";
|
|
234
|
+
import { EventEmitter } from "events";
|
|
235
|
+
import * as os from "os";
|
|
236
|
+
import { performance } from "perf_hooks";
|
|
237
|
+
|
|
238
|
+
// src/orchestrator/progress-validator.ts
|
|
239
|
+
var SAFE_GIT_REF_PATTERN = /^[A-Za-z0-9_.~^/@{}-]+$/u;
|
|
240
|
+
function isSafeGitRef(ref) {
|
|
241
|
+
const trimmed = ref.trim();
|
|
242
|
+
return trimmed.length > 0 && !trimmed.startsWith("-") && SAFE_GIT_REF_PATTERN.test(trimmed);
|
|
243
|
+
}
|
|
244
|
+
function isProgressRuntimePath(filePath) {
|
|
245
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
246
|
+
return normalized === ".poetic" || normalized.startsWith(".poetic/");
|
|
247
|
+
}
|
|
248
|
+
function getExecOutput(error) {
|
|
249
|
+
if (!error || typeof error !== "object") return null;
|
|
250
|
+
const stdout = "stdout" in error ? error.stdout : void 0;
|
|
251
|
+
const stderr = "stderr" in error ? error.stderr : void 0;
|
|
252
|
+
const stdoutText = typeof stdout === "string" ? stdout : Buffer.isBuffer(stdout) ? stdout.toString("utf-8") : "";
|
|
253
|
+
const stderrText = typeof stderr === "string" ? stderr : Buffer.isBuffer(stderr) ? stderr.toString("utf-8") : "";
|
|
254
|
+
const combined = `${stdoutText}
|
|
255
|
+
${stderrText}`.trim();
|
|
256
|
+
return combined.length > 0 ? combined : null;
|
|
257
|
+
}
|
|
258
|
+
function countVerificationErrorsFromOutput(command, output, kind) {
|
|
259
|
+
const parsed = parseFailureOutput(command, output, kind);
|
|
260
|
+
if (parsed.parsed && parsed.errorCount !== null) {
|
|
261
|
+
return parsed.errorCount;
|
|
262
|
+
}
|
|
263
|
+
const language = describeVerificationCommand(command).language;
|
|
264
|
+
if (language !== "node" && language !== "unknown") {
|
|
265
|
+
return 1;
|
|
266
|
+
}
|
|
267
|
+
return countErrorsFromOutputHeuristics(output);
|
|
268
|
+
}
|
|
269
|
+
function countErrorsFromOutputHeuristics(output) {
|
|
270
|
+
const normalized = output.trim();
|
|
271
|
+
if (normalized.length === 0) return null;
|
|
272
|
+
const tsErrorMatches = output.match(/error TS\d+:/g);
|
|
273
|
+
if (tsErrorMatches && tsErrorMatches.length > 0) {
|
|
274
|
+
return tsErrorMatches.length;
|
|
275
|
+
}
|
|
276
|
+
const errorMatches = Array.from(output.matchAll(/(?:Found\s+)?(\d+)\s+errors?/gi));
|
|
277
|
+
const lastErrorMatch = errorMatches[errorMatches.length - 1];
|
|
278
|
+
if (lastErrorMatch?.[1]) {
|
|
279
|
+
const parsed = Number.parseInt(lastErrorMatch[1], 10);
|
|
280
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
281
|
+
}
|
|
282
|
+
if (/^\s*FAIL\b/m.test(output) || /^\s*BUILD FAILED\b/im.test(output) || /^\s*BUILD FAILURE\b/im.test(output) || /^\s*COMPILATION ERROR\b/im.test(output) || /\b[1-9]\d*\s+Error\(s\)/i.test(output) || /^\s*(?:\.[/\\][^\n]+\.go:\d+:\d+:|[^\s:]+\.go:\d+:\d+:)\s+.+/m.test(output) || /^\s*error(?:\[[A-Z]\d+\])?:/m.test(output) || /\berror:\s+could not compile\b/i.test(output) || /\bfailed to compile\b/i.test(output) || /\bcompilation failed\b/i.test(output)) {
|
|
283
|
+
return 1;
|
|
284
|
+
}
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
function detectProjectLanguageSummary(workingDir) {
|
|
288
|
+
try {
|
|
289
|
+
return detectProjectCapabilities(workingDir).languages.join(", ") || "unknown";
|
|
290
|
+
} catch (error) {
|
|
291
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
292
|
+
return `unknown (capability detection failed: ${message})`;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function selectProjectProgressVerificationCommands(workingDir) {
|
|
296
|
+
const capabilities = detectProjectCapabilities(workingDir);
|
|
297
|
+
if (capabilities.verification.typecheck.length > 0) {
|
|
298
|
+
return { commands: [...new Set(capabilities.verification.typecheck)], kind: "typecheck" };
|
|
299
|
+
}
|
|
300
|
+
if (capabilities.verification.build.length > 0) {
|
|
301
|
+
return { commands: [...new Set(capabilities.verification.build)], kind: "build" };
|
|
302
|
+
}
|
|
303
|
+
return { commands: [...new Set(capabilities.verification.test)], kind: "test" };
|
|
304
|
+
}
|
|
305
|
+
async function countTypeScriptErrors(workingDir) {
|
|
306
|
+
const { commands, kind } = selectProjectProgressVerificationCommands(workingDir);
|
|
307
|
+
if (commands.length === 0) return null;
|
|
308
|
+
let total = 0;
|
|
309
|
+
let counted = false;
|
|
310
|
+
for (const command of commands) {
|
|
311
|
+
const count = await countErrorsForCommand(workingDir, command, kind);
|
|
312
|
+
if (count === null) continue;
|
|
313
|
+
counted = true;
|
|
314
|
+
total += count;
|
|
315
|
+
}
|
|
316
|
+
if (total > 0) return total;
|
|
317
|
+
return counted ? 0 : null;
|
|
318
|
+
}
|
|
319
|
+
async function countErrorsForCommand(workingDir, command, kind) {
|
|
320
|
+
try {
|
|
321
|
+
const envTimeout = Number.parseInt(process.env.POETIC_TSC_TIMEOUT_MS ?? "", 10);
|
|
322
|
+
const timeoutMs = Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : 15e3;
|
|
323
|
+
const result = await runVerificationCommand(command, {
|
|
324
|
+
cwd: workingDir,
|
|
325
|
+
timeoutMs
|
|
326
|
+
});
|
|
327
|
+
const output = String(result.all ?? `${result.stdout ?? ""}
|
|
328
|
+
${result.stderr ?? ""}`).trim();
|
|
329
|
+
const exitCode = result.exitCode;
|
|
330
|
+
if (exitCode == null || exitCode === 126) return null;
|
|
331
|
+
if (exitCode !== 0) {
|
|
332
|
+
const parsedCount = countVerificationErrorsFromOutput(command, output, kind);
|
|
333
|
+
if (detectExitZeroVerifyFailure(command, output)) {
|
|
334
|
+
return Math.max(parsedCount ?? 0, 1);
|
|
335
|
+
}
|
|
336
|
+
return parsedCount === 0 ? 1 : parsedCount ?? 1;
|
|
337
|
+
}
|
|
338
|
+
const exitZeroFailure = detectExitZeroVerifyFailure(command, output);
|
|
339
|
+
if (exitZeroFailure) return 1;
|
|
340
|
+
return countVerificationErrorsFromOutput(command, output, kind) ?? 0;
|
|
341
|
+
} catch (error) {
|
|
342
|
+
const output = getExecOutput(error);
|
|
343
|
+
if (!output) return null;
|
|
344
|
+
const parsedCount = countVerificationErrorsFromOutput(command, output, kind);
|
|
345
|
+
if (detectExitZeroVerifyFailure(command, output)) {
|
|
346
|
+
return Math.max(parsedCount ?? 0, 1);
|
|
347
|
+
}
|
|
348
|
+
return parsedCount === 0 ? 1 : parsedCount;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
var ProgressValidator = class {
|
|
352
|
+
constructor(options = {}) {
|
|
353
|
+
this.options = options;
|
|
354
|
+
this.options = {
|
|
355
|
+
enableGitAnalysis: true,
|
|
356
|
+
enableTestDetection: true,
|
|
357
|
+
minProgressThreshold: 0.05,
|
|
358
|
+
trendThreshold: 0.01,
|
|
359
|
+
...options
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
options;
|
|
363
|
+
compilationBaselineErrors = null;
|
|
364
|
+
getPreviousScore(context) {
|
|
365
|
+
const previous = context.previousIterations[context.previousIterations.length - 1];
|
|
366
|
+
return previous?.progress.score ?? 0;
|
|
367
|
+
}
|
|
368
|
+
isProgressSignificant(context, score) {
|
|
369
|
+
const threshold = this.options.minProgressThreshold ?? 0.05;
|
|
370
|
+
if (context.previousIterations.length === 0) {
|
|
371
|
+
return score >= threshold;
|
|
372
|
+
}
|
|
373
|
+
const previousScore = this.getPreviousScore(context);
|
|
374
|
+
const delta = score - previousScore;
|
|
375
|
+
return delta >= threshold;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Validate progress for an iteration
|
|
379
|
+
*/
|
|
380
|
+
async validateProgress(context) {
|
|
381
|
+
const startTime = Date.now();
|
|
382
|
+
try {
|
|
383
|
+
const compilationCheck = await this.checkCompilation(context);
|
|
384
|
+
const hadToolingFailure = compilationCheck.toolingFailure === true;
|
|
385
|
+
const verificationUnavailable = compilationCheck.status === "unavailable";
|
|
386
|
+
if (verificationUnavailable) {
|
|
387
|
+
debugLog(
|
|
388
|
+
`[ProgressValidator] Compilation verification unavailable: ${compilationCheck.reason}`
|
|
389
|
+
);
|
|
390
|
+
} else if (!compilationCheck.passed) {
|
|
391
|
+
debugLog(
|
|
392
|
+
`[ProgressValidator] Compilation check failed: ${compilationCheck.newErrors} new errors`
|
|
393
|
+
);
|
|
394
|
+
emitWarning(
|
|
395
|
+
"VAL-002",
|
|
396
|
+
{
|
|
397
|
+
taskId: context.workingDir,
|
|
398
|
+
subsystem: "progress-validator",
|
|
399
|
+
executionPhase: "validation"
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
severity: "ERROR" /* ERROR */,
|
|
403
|
+
metadata: {
|
|
404
|
+
newErrors: compilationCheck.newErrors,
|
|
405
|
+
totalErrors: compilationCheck.totalErrors,
|
|
406
|
+
iteration: context.iteration
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
);
|
|
410
|
+
return {
|
|
411
|
+
score: 0,
|
|
412
|
+
isSignificant: false,
|
|
413
|
+
trend: "declining",
|
|
414
|
+
confidence: 1,
|
|
415
|
+
// High confidence - compilation failure is definitive
|
|
416
|
+
metrics: {
|
|
417
|
+
codeQuality: 0,
|
|
418
|
+
testCoverage: 0,
|
|
419
|
+
performance: 0,
|
|
420
|
+
completeness: 0,
|
|
421
|
+
maintainability: 0
|
|
422
|
+
},
|
|
423
|
+
insights: [
|
|
424
|
+
`Iteration ${context.iteration}: Compilation failed with ${compilationCheck.newErrors} new errors`,
|
|
425
|
+
"Fix compilation errors before proceeding",
|
|
426
|
+
`Total errors: ${compilationCheck.totalErrors}`
|
|
427
|
+
]
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
const gitStats = this.options.enableGitAnalysis ? await this.analyzeGitChanges(context.workingDir, context.baseRef) : this.getEmptyGitStats();
|
|
431
|
+
const metrics = this.calculateMetrics(gitStats, context);
|
|
432
|
+
const score = this.calculateProgressScore(metrics, gitStats);
|
|
433
|
+
const isSignificant = this.isProgressSignificant(context, score);
|
|
434
|
+
const trend = this.calculateTrend(context.previousIterations, score);
|
|
435
|
+
const confidence = this.calculateConfidence(gitStats, context);
|
|
436
|
+
const insights = this.generateInsights(context.iteration, score, metrics, gitStats, trend);
|
|
437
|
+
if (verificationUnavailable) {
|
|
438
|
+
insights.push(
|
|
439
|
+
`WARNING: Validation unavailable \u2014 ${compilationCheck.reason ?? "no deterministic compilation check could run"}`
|
|
440
|
+
);
|
|
441
|
+
} else if (hadToolingFailure) {
|
|
442
|
+
insights.push("WARNING: Validation tooling failed \u2014 reported progress may be illusory");
|
|
443
|
+
}
|
|
444
|
+
const validationDuration = Date.now() - startTime;
|
|
445
|
+
debugLog(
|
|
446
|
+
`[ProgressValidator] Iteration ${context.iteration} validated in ${validationDuration}ms`
|
|
447
|
+
);
|
|
448
|
+
return {
|
|
449
|
+
score,
|
|
450
|
+
isSignificant,
|
|
451
|
+
trend,
|
|
452
|
+
// Reduce confidence when tooling failed to reflect lower certainty
|
|
453
|
+
confidence: verificationUnavailable || hadToolingFailure ? Math.min(confidence, 0.4) : confidence,
|
|
454
|
+
metrics,
|
|
455
|
+
insights,
|
|
456
|
+
...hadToolingFailure ? { toolingFailure: true } : {},
|
|
457
|
+
...verificationUnavailable ? {
|
|
458
|
+
verificationUnavailable: true,
|
|
459
|
+
verificationUnavailableReason: compilationCheck.reason ?? "No deterministic compilation check could run."
|
|
460
|
+
} : {}
|
|
461
|
+
};
|
|
462
|
+
} catch (error) {
|
|
463
|
+
emitWarning(
|
|
464
|
+
"VAL-001",
|
|
465
|
+
{
|
|
466
|
+
taskId: context.workingDir,
|
|
467
|
+
subsystem: "progress-validator",
|
|
468
|
+
executionPhase: "validation"
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
severity: "WARN" /* WARN */,
|
|
472
|
+
metadata: {
|
|
473
|
+
error: error instanceof Error ? error.message : String(error),
|
|
474
|
+
iteration: context.iteration,
|
|
475
|
+
operation: "validateProgress"
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
);
|
|
479
|
+
return this.createFallbackValidation(context);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
// ========================================================================
|
|
483
|
+
// COMPILATION CHECK
|
|
484
|
+
// ========================================================================
|
|
485
|
+
/**
|
|
486
|
+
* Check project compilation/typecheck status and compare against baseline.
|
|
487
|
+
*
|
|
488
|
+
* Runs a detected typecheck/build command without inventing target-project tooling.
|
|
489
|
+
* If no compile-specific command exists, falls back to resolver-backed test
|
|
490
|
+
* commands as deterministic verification evidence.
|
|
491
|
+
* Compares the current error count against a baseline to detect if new errors were introduced.
|
|
492
|
+
*
|
|
493
|
+
* Baseline precedence:
|
|
494
|
+
* 1) `context.compilationBaselineErrors` (captured pre-iteration by controller, preferred)
|
|
495
|
+
* 2) Internal baseline captured on first use (fallback)
|
|
496
|
+
*
|
|
497
|
+
* @param context - Progress validation context for this iteration
|
|
498
|
+
* @returns Compilation check result with pass/fail status and error counts
|
|
499
|
+
*/
|
|
500
|
+
async checkCompilation(context) {
|
|
501
|
+
try {
|
|
502
|
+
const compilationCommands = selectProjectProgressVerificationCommands(
|
|
503
|
+
context.workingDir
|
|
504
|
+
).commands;
|
|
505
|
+
if (compilationCommands.length === 0) {
|
|
506
|
+
const reason = `No deterministic typecheck/build/test command found; compilation verification is unavailable for detected languages: ${detectProjectLanguageSummary(context.workingDir)}.`;
|
|
507
|
+
debugLog(`[ProgressValidator] ${reason}`);
|
|
508
|
+
return {
|
|
509
|
+
passed: false,
|
|
510
|
+
newErrors: 0,
|
|
511
|
+
totalErrors: 0,
|
|
512
|
+
toolingFailure: true,
|
|
513
|
+
status: "unavailable",
|
|
514
|
+
reason
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
const totalErrors = await countTypeScriptErrors(context.workingDir);
|
|
518
|
+
if (totalErrors === null) {
|
|
519
|
+
debugLog(
|
|
520
|
+
`[ProgressValidator] Unable to run ${compilationCommands.join(", ")}, marking validation tooling failure`
|
|
521
|
+
);
|
|
522
|
+
return {
|
|
523
|
+
passed: false,
|
|
524
|
+
newErrors: 0,
|
|
525
|
+
totalErrors: 0,
|
|
526
|
+
toolingFailure: true,
|
|
527
|
+
status: "unavailable",
|
|
528
|
+
reason: `Project compilation command was unavailable or produced no parseable output: ${compilationCommands.join(", ")}`
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
const baselineErrors = context.compilationBaselineErrors ?? this.compilationBaselineErrors ?? totalErrors;
|
|
532
|
+
if (this.compilationBaselineErrors === null) {
|
|
533
|
+
this.compilationBaselineErrors = baselineErrors;
|
|
534
|
+
}
|
|
535
|
+
const newErrors = Math.max(0, totalErrors - baselineErrors);
|
|
536
|
+
const passed = newErrors === 0;
|
|
537
|
+
if (!passed) {
|
|
538
|
+
debugLog(
|
|
539
|
+
`[ProgressValidator] Compilation check failed: ${newErrors} new errors (${totalErrors} total)`
|
|
540
|
+
);
|
|
541
|
+
} else {
|
|
542
|
+
debugLog("[ProgressValidator] Compilation check passed");
|
|
543
|
+
}
|
|
544
|
+
return {
|
|
545
|
+
passed,
|
|
546
|
+
newErrors,
|
|
547
|
+
totalErrors,
|
|
548
|
+
status: passed ? "verified" : "failed"
|
|
549
|
+
};
|
|
550
|
+
} catch (error) {
|
|
551
|
+
console.warn(
|
|
552
|
+
`Error running compilation check: ${error instanceof Error ? error.message : String(error)}`
|
|
553
|
+
);
|
|
554
|
+
debugLog("Full stack:", error);
|
|
555
|
+
emitWarning(
|
|
556
|
+
"VAL-002",
|
|
557
|
+
{
|
|
558
|
+
taskId: context.workingDir,
|
|
559
|
+
subsystem: "progress-validator",
|
|
560
|
+
executionPhase: "validation"
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
severity: "WARN" /* WARN */,
|
|
564
|
+
metadata: {
|
|
565
|
+
error: error instanceof Error ? error.message : String(error),
|
|
566
|
+
operation: "checkCompilation"
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
);
|
|
570
|
+
return {
|
|
571
|
+
passed: false,
|
|
572
|
+
newErrors: 0,
|
|
573
|
+
totalErrors: 0,
|
|
574
|
+
toolingFailure: true,
|
|
575
|
+
status: "unavailable",
|
|
576
|
+
reason: "Compilation validation tooling failed before producing a result."
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
// ========================================================================
|
|
581
|
+
// GIT ANALYSIS
|
|
582
|
+
// ========================================================================
|
|
583
|
+
/**
|
|
584
|
+
* Calculate meaningful code delta excluding comments and whitespace.
|
|
585
|
+
* Used to detect "comment-only" changes that shouldn't count as progress.
|
|
586
|
+
*
|
|
587
|
+
* @param gitDiff - Full git diff output
|
|
588
|
+
* @returns Additions and deletions excluding comments/whitespace
|
|
589
|
+
*/
|
|
590
|
+
calculateMeaningfulDelta(gitDiff) {
|
|
591
|
+
const lines = gitDiff.split("\n");
|
|
592
|
+
let additions = 0;
|
|
593
|
+
let deletions = 0;
|
|
594
|
+
for (const line of lines) {
|
|
595
|
+
if (line.startsWith("@@") || line.startsWith("diff") || line.startsWith("index") || line.startsWith("---") || line.startsWith("+++")) {
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
if (!line.startsWith("+") && !line.startsWith("-")) {
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
const content = line.slice(1).trim();
|
|
602
|
+
if (!content) continue;
|
|
603
|
+
const isDefinitelyComment = content.startsWith("//") || // C-family single-line comment
|
|
604
|
+
content.startsWith("/*") || // C-family multi-line start
|
|
605
|
+
content.startsWith("*/") || // C-family multi-line end
|
|
606
|
+
content.startsWith("*") && content.match(/^\*\s+[^*/]/);
|
|
607
|
+
if (isDefinitelyComment) {
|
|
608
|
+
continue;
|
|
609
|
+
}
|
|
610
|
+
if (line.match(/^[+-]\s*$/)) continue;
|
|
611
|
+
if (line.startsWith("+")) additions++;
|
|
612
|
+
if (line.startsWith("-")) deletions++;
|
|
613
|
+
}
|
|
614
|
+
return { additions, deletions };
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Analyze git changes since base ref
|
|
618
|
+
*/
|
|
619
|
+
async analyzeGitChanges(workingDir, baseRef = "HEAD") {
|
|
620
|
+
try {
|
|
621
|
+
if (!this.isGitRepository(workingDir)) {
|
|
622
|
+
return this.getEmptyGitStats();
|
|
623
|
+
}
|
|
624
|
+
const safeBaseRef = baseRef.trim();
|
|
625
|
+
if (!isSafeGitRef(safeBaseRef)) {
|
|
626
|
+
return this.getEmptyGitStats();
|
|
627
|
+
}
|
|
628
|
+
const fullDiff = execWithTimeout(`git diff ${safeBaseRef} 2>/dev/null || echo ""`, {
|
|
629
|
+
cwd: workingDir,
|
|
630
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
631
|
+
// 10MB
|
|
632
|
+
timeout: 3e4,
|
|
633
|
+
returnEmptyOnError: true
|
|
634
|
+
}).trim();
|
|
635
|
+
if (!fullDiff) {
|
|
636
|
+
return this.getEmptyGitStats();
|
|
637
|
+
}
|
|
638
|
+
const modifiedFileSet = /* @__PURE__ */ new Set();
|
|
639
|
+
let insertions = 0;
|
|
640
|
+
let deletions = 0;
|
|
641
|
+
let includeCurrentFile = false;
|
|
642
|
+
const includedDiffLines = [];
|
|
643
|
+
for (const line of fullDiff.split("\n")) {
|
|
644
|
+
const diffMatch = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
|
|
645
|
+
if (diffMatch?.[2]) {
|
|
646
|
+
const filePath = diffMatch[2].trim();
|
|
647
|
+
includeCurrentFile = !isProgressRuntimePath(filePath);
|
|
648
|
+
if (includeCurrentFile) {
|
|
649
|
+
modifiedFileSet.add(filePath);
|
|
650
|
+
includedDiffLines.push(line);
|
|
651
|
+
}
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
if (!includeCurrentFile) {
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
includedDiffLines.push(line);
|
|
658
|
+
if (line.startsWith("+++") || line.startsWith("---") || line.startsWith("@@") || line.startsWith("diff --git") || line.startsWith("index ")) {
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
if (line.startsWith("+")) insertions++;
|
|
662
|
+
if (line.startsWith("-")) deletions++;
|
|
663
|
+
}
|
|
664
|
+
const modifiedFiles = Array.from(modifiedFileSet).sort((a, b) => a.localeCompare(b));
|
|
665
|
+
const hasTests = modifiedFiles.some(
|
|
666
|
+
(f) => f.includes("test") || f.includes("spec") || f.endsWith(".test.ts") || f.endsWith(".spec.ts")
|
|
667
|
+
);
|
|
668
|
+
const hasDocs = modifiedFiles.some(
|
|
669
|
+
(f) => f.endsWith(".md") || f.includes("doc") || f.includes("README")
|
|
670
|
+
);
|
|
671
|
+
const meaningfulDelta = this.calculateMeaningfulDelta(includedDiffLines.join("\n"));
|
|
672
|
+
return {
|
|
673
|
+
filesChanged: modifiedFiles.length,
|
|
674
|
+
insertions,
|
|
675
|
+
deletions,
|
|
676
|
+
totalLines: insertions + deletions,
|
|
677
|
+
modifiedFiles,
|
|
678
|
+
hasTests,
|
|
679
|
+
hasDocs,
|
|
680
|
+
meaningfulInsertions: meaningfulDelta.additions,
|
|
681
|
+
meaningfulDeletions: meaningfulDelta.deletions
|
|
682
|
+
};
|
|
683
|
+
} catch (error) {
|
|
684
|
+
console.warn(
|
|
685
|
+
`Error analyzing git changes: ${error instanceof Error ? error.message : String(error)}`
|
|
686
|
+
);
|
|
687
|
+
debugLog("Full stack:", error);
|
|
688
|
+
emitWarning(
|
|
689
|
+
"VAL-001",
|
|
690
|
+
{
|
|
691
|
+
taskId: workingDir,
|
|
692
|
+
subsystem: "progress-validator",
|
|
693
|
+
executionPhase: "validation"
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
severity: "WARN" /* WARN */,
|
|
697
|
+
metadata: {
|
|
698
|
+
error: error instanceof Error ? error.message : String(error),
|
|
699
|
+
operation: "analyzeGitChanges"
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
);
|
|
703
|
+
return this.getEmptyGitStats();
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Check if directory is a git repository
|
|
708
|
+
*/
|
|
709
|
+
isGitRepository(dir) {
|
|
710
|
+
try {
|
|
711
|
+
execWithTimeout("git rev-parse --git-dir", {
|
|
712
|
+
cwd: dir,
|
|
713
|
+
stdio: "pipe",
|
|
714
|
+
timeout: 3e4
|
|
715
|
+
});
|
|
716
|
+
return true;
|
|
717
|
+
} catch {
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
// ========================================================================
|
|
722
|
+
// METRICS CALCULATION
|
|
723
|
+
// ========================================================================
|
|
724
|
+
/**
|
|
725
|
+
* Calculate all progress metrics from git stats.
|
|
726
|
+
*
|
|
727
|
+
* codeQuality, performance, and maintainability are held at neutral defaults
|
|
728
|
+
* (0.5) since the low-signal heuristics that produced them have been removed.
|
|
729
|
+
* completeness and testCoverage are the high-signal signals derived from the diff.
|
|
730
|
+
*/
|
|
731
|
+
calculateMetrics(gitStats, context) {
|
|
732
|
+
const hasMeaningfulChanges = gitStats.meaningfulInsertions + gitStats.meaningfulDeletions > 0;
|
|
733
|
+
const hasAnyChanges = gitStats.insertions + gitStats.deletions > 0;
|
|
734
|
+
const isCommentOnlyChange = hasAnyChanges && !hasMeaningfulChanges;
|
|
735
|
+
if (isCommentOnlyChange) {
|
|
736
|
+
debugLog("[ProgressValidator] Comment/whitespace-only changes detected, no progress credit");
|
|
737
|
+
}
|
|
738
|
+
const completeness = isCommentOnlyChange ? 0 : Math.min(
|
|
739
|
+
1,
|
|
740
|
+
(gitStats.meaningfulInsertions + gitStats.meaningfulDeletions) / Math.max(100, 1)
|
|
741
|
+
);
|
|
742
|
+
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;
|
|
743
|
+
return {
|
|
744
|
+
// Neutral defaults — low-signal heuristics removed
|
|
745
|
+
codeQuality: 0.5,
|
|
746
|
+
performance: 0.5,
|
|
747
|
+
maintainability: 0.5,
|
|
748
|
+
completeness: Math.max(0, Math.min(1, completeness)),
|
|
749
|
+
testCoverage: Math.max(0, Math.min(1, testCoverage))
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Calculate overall progress score.
|
|
754
|
+
*
|
|
755
|
+
* Weights: completeness 70%, testCoverage 30%.
|
|
756
|
+
* Bonuses: +0.05 for test file changes, +0.02 for doc changes.
|
|
757
|
+
*/
|
|
758
|
+
calculateProgressScore(metrics, gitStats) {
|
|
759
|
+
const hasMeaningfulChanges = gitStats.meaningfulInsertions + gitStats.meaningfulDeletions > 0;
|
|
760
|
+
if (!hasMeaningfulChanges) {
|
|
761
|
+
return 0;
|
|
762
|
+
}
|
|
763
|
+
const weights = {
|
|
764
|
+
completeness: 0.7,
|
|
765
|
+
testCoverage: 0.3
|
|
766
|
+
};
|
|
767
|
+
let score = metrics.completeness * weights.completeness + metrics.testCoverage * weights.testCoverage;
|
|
768
|
+
if (gitStats.hasTests) score += 0.05;
|
|
769
|
+
if (gitStats.hasDocs) score += 0.02;
|
|
770
|
+
return Math.max(0, Math.min(1, score));
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Calculate trend from previous iterations
|
|
774
|
+
*/
|
|
775
|
+
calculateTrend(previousIterations, currentScore) {
|
|
776
|
+
if (previousIterations.length === 0) {
|
|
777
|
+
return "unknown";
|
|
778
|
+
}
|
|
779
|
+
if (previousIterations.length === 1) {
|
|
780
|
+
const prev = previousIterations[0]?.progress.score ?? 0;
|
|
781
|
+
const diff = currentScore - prev;
|
|
782
|
+
const threshold2 = this.options.trendThreshold ?? 0.01;
|
|
783
|
+
if (diff > threshold2) return "improving";
|
|
784
|
+
if (diff < -threshold2) return "declining";
|
|
785
|
+
return "stable";
|
|
786
|
+
}
|
|
787
|
+
const recentCount = Math.min(3, previousIterations.length);
|
|
788
|
+
const recent = previousIterations.slice(-recentCount);
|
|
789
|
+
const scores = [...recent.map((r) => r.progress.score), currentScore];
|
|
790
|
+
let sumX = 0;
|
|
791
|
+
let sumY = 0;
|
|
792
|
+
let sumXY = 0;
|
|
793
|
+
let sumXX = 0;
|
|
794
|
+
const n = scores.length;
|
|
795
|
+
for (let i = 0; i < n; i++) {
|
|
796
|
+
sumX += i;
|
|
797
|
+
sumY += scores[i] ?? 0;
|
|
798
|
+
sumXY += i * (scores[i] ?? 0);
|
|
799
|
+
sumXX += i * i;
|
|
800
|
+
}
|
|
801
|
+
const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
|
|
802
|
+
const threshold = this.options.trendThreshold ?? 0.01;
|
|
803
|
+
if (slope > threshold) return "improving";
|
|
804
|
+
if (slope < -threshold) return "declining";
|
|
805
|
+
return "stable";
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Calculate confidence in assessment
|
|
809
|
+
*/
|
|
810
|
+
calculateConfidence(gitStats, context) {
|
|
811
|
+
let confidence = 0.5;
|
|
812
|
+
if (gitStats.filesChanged > 0) {
|
|
813
|
+
confidence += Math.min(0.2, gitStats.filesChanged * 0.05);
|
|
814
|
+
}
|
|
815
|
+
if (context.previousIterations.length >= 2) {
|
|
816
|
+
confidence += 0.3;
|
|
817
|
+
}
|
|
818
|
+
return Math.max(0, Math.min(1, confidence));
|
|
819
|
+
}
|
|
820
|
+
// ========================================================================
|
|
821
|
+
// INSIGHTS GENERATION
|
|
822
|
+
// ========================================================================
|
|
823
|
+
/**
|
|
824
|
+
* Generate human-readable insights
|
|
825
|
+
*/
|
|
826
|
+
generateInsights(iteration, score, metrics, gitStats, trend) {
|
|
827
|
+
const insights = [];
|
|
828
|
+
insights.push(
|
|
829
|
+
`Iteration ${iteration}: ${(score * 100).toFixed(1)}% overall progress (${trend})`
|
|
830
|
+
);
|
|
831
|
+
if (gitStats.filesChanged > 0) {
|
|
832
|
+
insights.push(
|
|
833
|
+
`Modified ${gitStats.filesChanged} file(s): +${gitStats.insertions} -${gitStats.deletions} lines`
|
|
834
|
+
);
|
|
835
|
+
const hasMeaningfulChanges = gitStats.meaningfulInsertions + gitStats.meaningfulDeletions > 0;
|
|
836
|
+
if (!hasMeaningfulChanges) {
|
|
837
|
+
insights.push("Only comment/whitespace changes detected - no meaningful code progress");
|
|
838
|
+
}
|
|
839
|
+
} else {
|
|
840
|
+
insights.push("No file changes detected in this iteration");
|
|
841
|
+
}
|
|
842
|
+
if (gitStats.hasTests) {
|
|
843
|
+
insights.push("Test files updated - good coverage practice");
|
|
844
|
+
} else if (gitStats.filesChanged > 0) {
|
|
845
|
+
insights.push("Recommendation: Add tests for code changes");
|
|
846
|
+
}
|
|
847
|
+
if (metrics.completeness >= 0.9) {
|
|
848
|
+
insights.push("Task appears nearly complete");
|
|
849
|
+
} else if (metrics.completeness >= 0.7) {
|
|
850
|
+
insights.push("Good progress, some work remaining");
|
|
851
|
+
} else if (metrics.completeness >= 0.5) {
|
|
852
|
+
insights.push("Halfway through task completion");
|
|
853
|
+
} else {
|
|
854
|
+
insights.push("Significant work still needed");
|
|
855
|
+
}
|
|
856
|
+
if (trend === "improving") {
|
|
857
|
+
insights.push("Progress trend: Improving - keep going!");
|
|
858
|
+
} else if (trend === "declining") {
|
|
859
|
+
insights.push("Progress trend: Declining - review approach");
|
|
860
|
+
} else if (trend === "stable") {
|
|
861
|
+
insights.push("Progress trend: Stable - consider new strategies");
|
|
862
|
+
}
|
|
863
|
+
return insights;
|
|
864
|
+
}
|
|
865
|
+
// ========================================================================
|
|
866
|
+
// FALLBACK & HELPERS
|
|
867
|
+
// ========================================================================
|
|
868
|
+
/**
|
|
869
|
+
* Create fallback validation when analysis fails.
|
|
870
|
+
*
|
|
871
|
+
* Returns score=0 with low confidence and an explicit warning rather than
|
|
872
|
+
* fabricating a positive score from the iteration count. A non-zero score
|
|
873
|
+
* derived purely from "how many iterations have elapsed" is illusory — it
|
|
874
|
+
* says nothing about whether actual work was done.
|
|
875
|
+
*/
|
|
876
|
+
createFallbackValidation(context) {
|
|
877
|
+
const score = 0;
|
|
878
|
+
return {
|
|
879
|
+
score,
|
|
880
|
+
isSignificant: false,
|
|
881
|
+
trend: "unknown",
|
|
882
|
+
// Low confidence: we could not run any real analysis
|
|
883
|
+
confidence: 0.1,
|
|
884
|
+
metrics: {
|
|
885
|
+
codeQuality: 0,
|
|
886
|
+
testCoverage: 0,
|
|
887
|
+
performance: 0,
|
|
888
|
+
completeness: 0,
|
|
889
|
+
maintainability: 0
|
|
890
|
+
},
|
|
891
|
+
insights: [
|
|
892
|
+
`Iteration ${context.iteration}: Using fallback validation`,
|
|
893
|
+
"Unable to perform detailed analysis - reported progress may be illusory",
|
|
894
|
+
"Proceeding with caution"
|
|
895
|
+
],
|
|
896
|
+
toolingFailure: true,
|
|
897
|
+
verificationUnavailable: true,
|
|
898
|
+
verificationUnavailableReason: "Progress validation failed before deterministic checks completed."
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Get empty git stats
|
|
903
|
+
*/
|
|
904
|
+
getEmptyGitStats() {
|
|
905
|
+
return {
|
|
906
|
+
filesChanged: 0,
|
|
907
|
+
insertions: 0,
|
|
908
|
+
deletions: 0,
|
|
909
|
+
totalLines: 0,
|
|
910
|
+
modifiedFiles: [],
|
|
911
|
+
hasTests: false,
|
|
912
|
+
hasDocs: false,
|
|
913
|
+
meaningfulInsertions: 0,
|
|
914
|
+
meaningfulDeletions: 0
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
function createCustomProgressValidator(options) {
|
|
919
|
+
return new ProgressValidator(options);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// src/orchestrator/autonomous-loop-controller.ts
|
|
923
|
+
var DEFAULT_AUTOLOOP_RESOURCE_LIMITS = {
|
|
924
|
+
maxMemoryMB: 1048576,
|
|
925
|
+
maxCpuPercent: 1e3,
|
|
926
|
+
maxProcesses: Number.MAX_SAFE_INTEGER
|
|
927
|
+
};
|
|
928
|
+
var MAX_AUTOLOOP_ENV_ITERATIONS = 100;
|
|
929
|
+
var MAX_AUTOLOOP_ENV_PROCESSES = 1024;
|
|
930
|
+
var COMPLETION_SIGNAL_TAIL_BYTES = 8192;
|
|
931
|
+
function tailUtf8Bytes(text, maxBytes) {
|
|
932
|
+
if (Buffer.byteLength(text, "utf8") <= maxBytes) {
|
|
933
|
+
return text;
|
|
934
|
+
}
|
|
935
|
+
let start = 0;
|
|
936
|
+
while (start < text.length && Buffer.byteLength(text.slice(start), "utf8") > maxBytes) {
|
|
937
|
+
start += 1;
|
|
938
|
+
}
|
|
939
|
+
return text.slice(start);
|
|
940
|
+
}
|
|
941
|
+
function parseCompletionSignal(spec) {
|
|
942
|
+
if (spec.startsWith("xml:")) {
|
|
943
|
+
const tag = spec.slice(4);
|
|
944
|
+
if (tag.length === 0) return null;
|
|
945
|
+
return { type: "xml", tag };
|
|
946
|
+
}
|
|
947
|
+
if (spec.startsWith("regex:")) {
|
|
948
|
+
const rawPattern = spec.slice(6);
|
|
949
|
+
if (rawPattern.length === 0) return null;
|
|
950
|
+
const slashMatch = rawPattern.match(/^\/(.+)\/([gimsuy]*)$/);
|
|
951
|
+
const patternSource = slashMatch ? slashMatch[1] : rawPattern;
|
|
952
|
+
const patternFlags = slashMatch ? slashMatch[2] : "i";
|
|
953
|
+
if (patternSource.length === 0) return null;
|
|
954
|
+
try {
|
|
955
|
+
return {
|
|
956
|
+
type: "regex",
|
|
957
|
+
pattern: new RegExp(patternSource, patternFlags)
|
|
958
|
+
};
|
|
959
|
+
} catch {
|
|
960
|
+
return null;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return null;
|
|
964
|
+
}
|
|
965
|
+
function matchesCompletionSignal(output, signal) {
|
|
966
|
+
if (typeof output !== "string") {
|
|
967
|
+
return false;
|
|
968
|
+
}
|
|
969
|
+
const tail = tailUtf8Bytes(output, COMPLETION_SIGNAL_TAIL_BYTES);
|
|
970
|
+
if (signal.type === "xml") {
|
|
971
|
+
const escapedTag = signal.tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
972
|
+
const atLineStart = new RegExp(`(?:^|[\\r\\n])${escapedTag}(?:\\s|$)`, "i");
|
|
973
|
+
const asFinalToken = new RegExp(`${escapedTag}\\s*$`, "i");
|
|
974
|
+
return atLineStart.test(tail) || asFinalToken.test(tail.trimEnd());
|
|
975
|
+
}
|
|
976
|
+
const trimmedEnd = tail.trimEnd();
|
|
977
|
+
const pattern = new RegExp(
|
|
978
|
+
signal.pattern.source,
|
|
979
|
+
signal.pattern.flags.includes("g") ? signal.pattern.flags : `${signal.pattern.flags}g`
|
|
980
|
+
);
|
|
981
|
+
let lastMatch = null;
|
|
982
|
+
let match = pattern.exec(trimmedEnd);
|
|
983
|
+
while (match !== null) {
|
|
984
|
+
lastMatch = match;
|
|
985
|
+
match = pattern.exec(trimmedEnd);
|
|
986
|
+
}
|
|
987
|
+
if (!lastMatch) {
|
|
988
|
+
return false;
|
|
989
|
+
}
|
|
990
|
+
return lastMatch.index + lastMatch[0].length >= trimmedEnd.length;
|
|
991
|
+
}
|
|
992
|
+
function selectTaskOutputForChecks(taskResult) {
|
|
993
|
+
if (typeof taskResult === "object" && taskResult !== null) {
|
|
994
|
+
if ("completionOutputText" in taskResult && typeof taskResult.completionOutputText === "string") {
|
|
995
|
+
return taskResult.completionOutputText;
|
|
996
|
+
}
|
|
997
|
+
if ("providerOutputText" in taskResult && typeof taskResult.providerOutputText === "string") {
|
|
998
|
+
return taskResult.providerOutputText;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
return typeof taskResult === "string" ? taskResult : "";
|
|
1002
|
+
}
|
|
1003
|
+
var SAFE_GIT_REF_PATTERN2 = /^[A-Za-z0-9_.~^/@{}-]+$/u;
|
|
1004
|
+
function isSafeGitRef2(ref) {
|
|
1005
|
+
const trimmed = ref.trim();
|
|
1006
|
+
return trimmed.length > 0 && !trimmed.startsWith("-") && SAFE_GIT_REF_PATTERN2.test(trimmed);
|
|
1007
|
+
}
|
|
1008
|
+
function isRepairOutcome(value) {
|
|
1009
|
+
if (!value || typeof value !== "object") return false;
|
|
1010
|
+
const candidate = value;
|
|
1011
|
+
return typeof candidate.status === "string" && typeof candidate.attempts === "number" && typeof candidate.reason === "string";
|
|
1012
|
+
}
|
|
1013
|
+
function isCompletionEvidence(value) {
|
|
1014
|
+
if (!value || typeof value !== "object") return false;
|
|
1015
|
+
const candidate = value;
|
|
1016
|
+
return candidate.durable === true && (candidate.source === "simple-artifact" || candidate.source === "requirements" || candidate.source === "external") && (candidate.detail === void 0 || typeof candidate.detail === "string");
|
|
1017
|
+
}
|
|
1018
|
+
function isCustomGateResult(value) {
|
|
1019
|
+
if (!value || typeof value !== "object") return false;
|
|
1020
|
+
const candidate = value;
|
|
1021
|
+
if (typeof candidate.id !== "string" || typeof candidate.command !== "string" || typeof candidate.passed !== "boolean" || typeof candidate.durationMs !== "number" || !Number.isFinite(candidate.durationMs) || candidate.durationMs < 0) {
|
|
1022
|
+
return false;
|
|
1023
|
+
}
|
|
1024
|
+
if (candidate.exitCode !== void 0 && typeof candidate.exitCode !== "number") return false;
|
|
1025
|
+
if (candidate.outputTail !== void 0 && typeof candidate.outputTail !== "string") return false;
|
|
1026
|
+
if (candidate.isRegression !== void 0 && typeof candidate.isRegression !== "boolean") {
|
|
1027
|
+
return false;
|
|
1028
|
+
}
|
|
1029
|
+
if (candidate.skipped !== void 0 && typeof candidate.skipped !== "boolean") return false;
|
|
1030
|
+
if (candidate.unavailable !== void 0 && typeof candidate.unavailable !== "boolean") {
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
1033
|
+
if (candidate.misconfigured !== void 0 && typeof candidate.misconfigured !== "boolean") {
|
|
1034
|
+
return false;
|
|
1035
|
+
}
|
|
1036
|
+
return true;
|
|
1037
|
+
}
|
|
1038
|
+
function isCustomGateResultsArray(value) {
|
|
1039
|
+
return Array.isArray(value) && value.every(isCustomGateResult);
|
|
1040
|
+
}
|
|
1041
|
+
function buildCustomGateId(command) {
|
|
1042
|
+
const prefix = command.replace(/\s+/g, "-").slice(0, 40);
|
|
1043
|
+
const hash = createHash("sha256").update(command).digest("hex").slice(0, 8);
|
|
1044
|
+
return `${prefix}-${hash}`;
|
|
1045
|
+
}
|
|
1046
|
+
function isSemanticCompletionSatisfied(validation) {
|
|
1047
|
+
if (!validation?.enabled || validation.skipped !== void 0) {
|
|
1048
|
+
return false;
|
|
1049
|
+
}
|
|
1050
|
+
return validation.passed === true;
|
|
1051
|
+
}
|
|
1052
|
+
function isSemanticCheckBlocking(validation) {
|
|
1053
|
+
if (!validation?.enabled) {
|
|
1054
|
+
return false;
|
|
1055
|
+
}
|
|
1056
|
+
if (validation.skipped === void 0) {
|
|
1057
|
+
return validation.passed !== true;
|
|
1058
|
+
}
|
|
1059
|
+
return isSemanticErrorSkip(validation.skipped);
|
|
1060
|
+
}
|
|
1061
|
+
function filterSemanticValidationDiff(gitDiff, taskText) {
|
|
1062
|
+
if (!gitDiff.trim()) {
|
|
1063
|
+
return gitDiff;
|
|
1064
|
+
}
|
|
1065
|
+
const normalizedTaskText = taskText.replace(/\\/g, "/");
|
|
1066
|
+
const sections = gitDiff.split(/^diff --git /m).map((section, index) => index === 0 ? section : `diff --git ${section}`).filter((section) => section.trim().length > 0);
|
|
1067
|
+
return sections.filter((section) => {
|
|
1068
|
+
const match = section.match(/^diff --git a\/(.+?) b\/(.+)$/m);
|
|
1069
|
+
const changedPath = match?.[2] ?? match?.[1];
|
|
1070
|
+
if (!changedPath) {
|
|
1071
|
+
return true;
|
|
1072
|
+
}
|
|
1073
|
+
if (!shouldIgnoreRepoPath(changedPath)) {
|
|
1074
|
+
return true;
|
|
1075
|
+
}
|
|
1076
|
+
const normalizedPath = changedPath.replace(/\\/g, "/");
|
|
1077
|
+
const parentDir = normalizedPath.includes("/") ? `${normalizedPath.slice(0, normalizedPath.lastIndexOf("/") + 1)}` : "";
|
|
1078
|
+
return normalizedTaskText.includes(normalizedPath) || parentDir.length > 0 && normalizedTaskText.includes(parentDir);
|
|
1079
|
+
}).join("\n");
|
|
1080
|
+
}
|
|
1081
|
+
var TYPECHECK_GATE_IDS = /* @__PURE__ */ new Set(["tsc", "typecheck", "typescript"]);
|
|
1082
|
+
function normalizeGateId(gateId) {
|
|
1083
|
+
return gateId.trim().toLowerCase().replaceAll("_", "-");
|
|
1084
|
+
}
|
|
1085
|
+
function isTypecheckGateId(gateId) {
|
|
1086
|
+
const normalized = normalizeGateId(gateId);
|
|
1087
|
+
if (TYPECHECK_GATE_IDS.has(normalized)) {
|
|
1088
|
+
return true;
|
|
1089
|
+
}
|
|
1090
|
+
return normalized.split("-").some((part) => TYPECHECK_GATE_IDS.has(part));
|
|
1091
|
+
}
|
|
1092
|
+
function hasCompilerErrorOutput(output) {
|
|
1093
|
+
if (output.trim().length === 0) {
|
|
1094
|
+
return false;
|
|
1095
|
+
}
|
|
1096
|
+
const hasTsError = output.split(/\r?\n/).some(
|
|
1097
|
+
(line) => /^(?:.+(?:\(\d+,\d+\)|:\d+:\d+)\s*(?::|-)\s+)?error\s+TS\d+:/i.test(line.trim())
|
|
1098
|
+
);
|
|
1099
|
+
if (hasTsError) {
|
|
1100
|
+
return true;
|
|
1101
|
+
}
|
|
1102
|
+
return (
|
|
1103
|
+
// Rust compiler diagnostics: `error[E0382]:` / bare `error:`
|
|
1104
|
+
/^\s*error(?:\[[A-Z]\d+\])?:/m.test(output) || /\berror:\s+could not compile\b/i.test(output) || // Go compiler diagnostics: `path/file.go:line:col: message`
|
|
1105
|
+
/^\s*(?:\.[/\\][^\n]+\.go:\d+:\d+:|[^\s:]+\.go:\d+:\d+:)\s+.+/m.test(output) || // Generic build-failure banners across toolchains.
|
|
1106
|
+
/^\s*BUILD FAILED\b/im.test(output) || /^\s*BUILD FAILURE\b/im.test(output) || /^\s*COMPILATION ERROR\b/im.test(output) || /\bfailed to compile\b/i.test(output) || /\bcompilation failed\b/i.test(output)
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
function hasCompilationProgressSignal(insights) {
|
|
1110
|
+
return insights?.some(
|
|
1111
|
+
(insight) => /\bcompilation failed with [1-9]\d* new (?:typescript )?errors?\b/i.test(insight)
|
|
1112
|
+
) ?? false;
|
|
1113
|
+
}
|
|
1114
|
+
function classifyQualityGateFailure(gate) {
|
|
1115
|
+
if (gate.passed || gate.isRegression === false) {
|
|
1116
|
+
return "other";
|
|
1117
|
+
}
|
|
1118
|
+
if (isTypecheckGateId(gate.gateId)) {
|
|
1119
|
+
return "compilation";
|
|
1120
|
+
}
|
|
1121
|
+
const compilerOutput = `${gate.details}
|
|
1122
|
+
${gate.outputTail ?? ""}`;
|
|
1123
|
+
return hasCompilerErrorOutput(compilerOutput) ? "compilation" : "other";
|
|
1124
|
+
}
|
|
1125
|
+
var BENIGN_SEMANTIC_SKIP_REASONS = /* @__PURE__ */ new Set([
|
|
1126
|
+
"not_completion_bounds",
|
|
1127
|
+
"trivial_diff",
|
|
1128
|
+
"iteration_skip"
|
|
1129
|
+
]);
|
|
1130
|
+
var SEMANTIC_ERROR_SKIP_REASONS = /* @__PURE__ */ new Set([
|
|
1131
|
+
"provider_error",
|
|
1132
|
+
"no_task_spec",
|
|
1133
|
+
"parse_error"
|
|
1134
|
+
]);
|
|
1135
|
+
function semanticSkipped(skipped) {
|
|
1136
|
+
return { enabled: true, skipped };
|
|
1137
|
+
}
|
|
1138
|
+
function semanticDisabled() {
|
|
1139
|
+
return { enabled: false };
|
|
1140
|
+
}
|
|
1141
|
+
function isBenignSemanticSkip(skipped) {
|
|
1142
|
+
return skipped !== void 0 && BENIGN_SEMANTIC_SKIP_REASONS.has(skipped);
|
|
1143
|
+
}
|
|
1144
|
+
function isSemanticErrorSkip(skipped) {
|
|
1145
|
+
return skipped !== void 0 && SEMANTIC_ERROR_SKIP_REASONS.has(skipped);
|
|
1146
|
+
}
|
|
1147
|
+
var MIN_CUSTOM_GATE_BASELINE_MS = 3e3;
|
|
1148
|
+
var MIN_CUSTOM_GATE_RUN_MS = 1e3;
|
|
1149
|
+
var MIN_FIRST_ITERATION_RESERVE_MS = 15e3;
|
|
1150
|
+
var MAX_FIRST_ITERATION_RESERVE_MS = 9e4;
|
|
1151
|
+
function classifyError(error) {
|
|
1152
|
+
const message = error.message.toLowerCase();
|
|
1153
|
+
if (message.includes("timeout") || message.includes("timed out") || message.includes("deadline")) {
|
|
1154
|
+
return {
|
|
1155
|
+
category: "timeout",
|
|
1156
|
+
hint: "Consider reducing iteration complexity or increasing timeout limits"
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
if (message.includes("auth") || message.includes("unauthorized") || message.includes("forbidden") || message.includes("credentials")) {
|
|
1160
|
+
return {
|
|
1161
|
+
category: "auth",
|
|
1162
|
+
hint: "Verify API credentials and authentication configuration"
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
if (message.includes("syntax") || message.includes("parse") || message.includes("unexpected token")) {
|
|
1166
|
+
return {
|
|
1167
|
+
category: "syntax",
|
|
1168
|
+
hint: "Check generated code for syntax errors or malformed output"
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
if (message.includes("memory") || message.includes("cpu") || message.includes("disk") || message.includes("enospc") || message.includes("enomem")) {
|
|
1172
|
+
return {
|
|
1173
|
+
category: "resource",
|
|
1174
|
+
hint: "Reduce memory/CPU usage or increase resource limits"
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
return {
|
|
1178
|
+
category: "unknown",
|
|
1179
|
+
hint: "Review error details and adjust implementation approach"
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
function resolveQualityGateExecutionFlags(mode = "fast") {
|
|
1183
|
+
return {
|
|
1184
|
+
coverage: mode === "full",
|
|
1185
|
+
lint: mode === "full" || mode === "safe" || mode === "fast",
|
|
1186
|
+
security: mode === "full" || mode === "safe"
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1189
|
+
async function captureQualityBaseline(workingDir, qualityGates, options) {
|
|
1190
|
+
if (!qualityGates) {
|
|
1191
|
+
return {
|
|
1192
|
+
status: "skipped",
|
|
1193
|
+
reason: "quality_gates_unavailable",
|
|
1194
|
+
capturedAt: /* @__PURE__ */ new Date()
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
try {
|
|
1198
|
+
const gateFlags = resolveQualityGateExecutionFlags(options?.mode ?? "fast");
|
|
1199
|
+
const summary = await qualityGates.run({
|
|
1200
|
+
...gateFlags,
|
|
1201
|
+
securityNotModeled: options?.mode === "safe" ? "not-applicable" : "unavailable",
|
|
1202
|
+
cwd: workingDir,
|
|
1203
|
+
...typeof options?.timeoutMs === "number" && options.timeoutMs > 0 ? { timeoutMs: options.timeoutMs } : {}
|
|
1204
|
+
});
|
|
1205
|
+
try {
|
|
1206
|
+
options?.onShadow?.(summary.shadow);
|
|
1207
|
+
} catch {
|
|
1208
|
+
}
|
|
1209
|
+
const testFailuresResult = extractFailureCountWithMethod(summary.results, "coverage");
|
|
1210
|
+
const lintErrorsResult = extractFailureCountWithMethod(summary.results, "lint");
|
|
1211
|
+
const securityFailuresResult = extractFailureCountWithMethod(summary.results, "security");
|
|
1212
|
+
const typeErrorsResult = lintErrorsResult;
|
|
1213
|
+
return {
|
|
1214
|
+
status: "captured",
|
|
1215
|
+
testFailures: testFailuresResult.count,
|
|
1216
|
+
testFailuresMethod: testFailuresResult.method,
|
|
1217
|
+
...testFailuresResult.suiteFootprint ? { testSuiteFootprint: testFailuresResult.suiteFootprint } : {},
|
|
1218
|
+
...testFailuresResult.messages && testFailuresResult.messages.length > 0 ? { testFailureMessages: testFailuresResult.messages } : {},
|
|
1219
|
+
lintErrors: lintErrorsResult.count,
|
|
1220
|
+
lintErrorsMethod: lintErrorsResult.method,
|
|
1221
|
+
typeErrors: typeErrorsResult.count,
|
|
1222
|
+
typeErrorsMethod: typeErrorsResult.method,
|
|
1223
|
+
securityFailures: securityFailuresResult.count,
|
|
1224
|
+
securityFailuresMethod: securityFailuresResult.method,
|
|
1225
|
+
gateAvailability: {
|
|
1226
|
+
coverage: summary.results.some(
|
|
1227
|
+
(result) => result.gate === "coverage" && !result.skipped && !result.unavailable
|
|
1228
|
+
),
|
|
1229
|
+
lint: summary.results.some(
|
|
1230
|
+
(result) => result.gate === "lint" && !result.skipped && !result.unavailable
|
|
1231
|
+
),
|
|
1232
|
+
security: summary.results.some(
|
|
1233
|
+
(result) => result.gate === "security" && !result.skipped && !result.unavailable
|
|
1234
|
+
)
|
|
1235
|
+
},
|
|
1236
|
+
capturedAt: /* @__PURE__ */ new Date()
|
|
1237
|
+
};
|
|
1238
|
+
} catch (error) {
|
|
1239
|
+
console.warn(
|
|
1240
|
+
`[AutonomousLoopController] Failed to capture quality baseline: ${error instanceof Error ? error.message : String(error)}`
|
|
1241
|
+
);
|
|
1242
|
+
return {
|
|
1243
|
+
status: "failed",
|
|
1244
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
1245
|
+
capturedAt: /* @__PURE__ */ new Date()
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
function computeErrorSignature(result) {
|
|
1250
|
+
const normalizedMessage = (result.error?.message ?? "").replace(/T\d+/g, "TASK_ID").replace(/\d+/g, "N").trim().toLowerCase();
|
|
1251
|
+
const warningCodes = [...new Set(result.warningCodes ?? [])].sort();
|
|
1252
|
+
const missingFiles = [...new Set(result.metadata?.missingFiles ?? [])].sort();
|
|
1253
|
+
const hash = createHash("sha256").update(JSON.stringify({ normalizedMessage, warningCodes, missingFiles })).digest("hex").slice(0, 16);
|
|
1254
|
+
return {
|
|
1255
|
+
hash,
|
|
1256
|
+
components: {
|
|
1257
|
+
normalizedMessage,
|
|
1258
|
+
warningCodes,
|
|
1259
|
+
missingFiles
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
function classifyCoverageBaselineComparison(baseline, candidate) {
|
|
1264
|
+
if (candidate.failures > baseline.failures) {
|
|
1265
|
+
return "regression";
|
|
1266
|
+
}
|
|
1267
|
+
const baseFp = baseline.suiteFootprint;
|
|
1268
|
+
const candFp = candidate.suiteFootprint;
|
|
1269
|
+
if (!baseFp || !candFp) {
|
|
1270
|
+
return "unknown";
|
|
1271
|
+
}
|
|
1272
|
+
if (candFp.executed < baseFp.executed) {
|
|
1273
|
+
return "regression";
|
|
1274
|
+
}
|
|
1275
|
+
if (candFp.skipped > baseFp.skipped) {
|
|
1276
|
+
return "regression";
|
|
1277
|
+
}
|
|
1278
|
+
if (candidate.failures < baseline.failures) {
|
|
1279
|
+
return "improvement";
|
|
1280
|
+
}
|
|
1281
|
+
const baseMsgs = baseline.messages ?? [];
|
|
1282
|
+
const candMsgs = candidate.messages ?? [];
|
|
1283
|
+
if (baseMsgs.length === 0 || candMsgs.length === 0) {
|
|
1284
|
+
return "unknown";
|
|
1285
|
+
}
|
|
1286
|
+
if (!stableMessageSetsMatch(baseMsgs, candMsgs)) {
|
|
1287
|
+
return "unknown";
|
|
1288
|
+
}
|
|
1289
|
+
return "pre_existing";
|
|
1290
|
+
}
|
|
1291
|
+
function stableMessageSetsMatch(a, b) {
|
|
1292
|
+
if (a.length !== b.length) return false;
|
|
1293
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1294
|
+
for (const msg of a) {
|
|
1295
|
+
counts.set(msg, (counts.get(msg) ?? 0) + 1);
|
|
1296
|
+
}
|
|
1297
|
+
for (const msg of b) {
|
|
1298
|
+
const next = (counts.get(msg) ?? 0) - 1;
|
|
1299
|
+
if (next < 0) return false;
|
|
1300
|
+
if (next === 0) counts.delete(msg);
|
|
1301
|
+
else counts.set(msg, next);
|
|
1302
|
+
}
|
|
1303
|
+
return counts.size === 0;
|
|
1304
|
+
}
|
|
1305
|
+
function extractFailureCountWithMethod(results, gateId) {
|
|
1306
|
+
const result = results.find((r) => r.gate === gateId);
|
|
1307
|
+
if (!result) {
|
|
1308
|
+
return { count: 0, method: "passed_or_not_found" };
|
|
1309
|
+
}
|
|
1310
|
+
if (result.unavailable === true || result.skipped === true) {
|
|
1311
|
+
return { count: 0, method: "passed_or_not_found" };
|
|
1312
|
+
}
|
|
1313
|
+
const output = result.stdout + result.stderr;
|
|
1314
|
+
if (gateId === "coverage") {
|
|
1315
|
+
if (result.command) {
|
|
1316
|
+
const parsed = parseFailureOutput(result.command, output, "test");
|
|
1317
|
+
if (parsed.parsed && parsed.errorCount !== null) {
|
|
1318
|
+
return {
|
|
1319
|
+
count: parsed.errorCount,
|
|
1320
|
+
method: "parsed_failure_output",
|
|
1321
|
+
...parsed.suiteFootprint ? { suiteFootprint: parsed.suiteFootprint } : {},
|
|
1322
|
+
...parsed.messages.length > 0 ? { messages: parsed.messages } : {}
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
if (result.success) {
|
|
1327
|
+
return { count: 0, method: "passed_or_not_found" };
|
|
1328
|
+
}
|
|
1329
|
+
const failMatch = output.match(/(\d+)\s+(?:tests?\s+)?(?:failing|failed)/i);
|
|
1330
|
+
if (failMatch?.[1]) {
|
|
1331
|
+
return { count: parseInt(failMatch[1], 10), method: "fail_pattern" };
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
if (result.success) {
|
|
1335
|
+
return { count: 0, method: "passed_or_not_found" };
|
|
1336
|
+
}
|
|
1337
|
+
if (gateId === "lint") {
|
|
1338
|
+
if (result.command) {
|
|
1339
|
+
const parsed = parseFailureOutput(result.command, output, "lint");
|
|
1340
|
+
if (parsed.parsed && parsed.errorCount !== null) {
|
|
1341
|
+
return { count: parsed.errorCount, method: "parsed_failure_output" };
|
|
1342
|
+
}
|
|
1343
|
+
const language = describeVerificationCommand(result.command).language;
|
|
1344
|
+
if (language !== "node" && language !== "unknown") {
|
|
1345
|
+
return { count: 1, method: "fallback_1" };
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
const tsErrorMatches = output.match(/error TS\d+:/g);
|
|
1349
|
+
if (tsErrorMatches && tsErrorMatches.length > 0) {
|
|
1350
|
+
return { count: tsErrorMatches.length, method: "ts_error_lines" };
|
|
1351
|
+
}
|
|
1352
|
+
const eslintMatch = output.match(/(\d+)\s+problems?\s*\(\s*(\d+)\s+errors?/i);
|
|
1353
|
+
if (eslintMatch?.[2]) {
|
|
1354
|
+
return { count: parseInt(eslintMatch[2], 10), method: "eslint_summary" };
|
|
1355
|
+
}
|
|
1356
|
+
const errorMatches = Array.from(output.matchAll(/(?:Found\s+)?(\d+)\s+errors?/gi));
|
|
1357
|
+
const lastErrorMatch = errorMatches[errorMatches.length - 1];
|
|
1358
|
+
if (lastErrorMatch?.[1]) {
|
|
1359
|
+
return { count: parseInt(lastErrorMatch[1], 10), method: "found_errors" };
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
if (gateId === "security") {
|
|
1363
|
+
const blockingCount = countBlockingVulnerabilities(result.stdout);
|
|
1364
|
+
if (blockingCount !== null) {
|
|
1365
|
+
return { count: blockingCount, method: "security_vuln_count" };
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
return { count: 1, method: "fallback_1" };
|
|
1369
|
+
}
|
|
1370
|
+
function createProgressScore(score) {
|
|
1371
|
+
if (score < 0 || score > 1) {
|
|
1372
|
+
throw new Error(`Progress score must be between 0 and 1, got: ${score}`);
|
|
1373
|
+
}
|
|
1374
|
+
return score;
|
|
1375
|
+
}
|
|
1376
|
+
function createIterationCount(count) {
|
|
1377
|
+
if (count < 0 || !Number.isInteger(count)) {
|
|
1378
|
+
throw new Error(`Iteration count must be a non-negative integer, got: ${count}`);
|
|
1379
|
+
}
|
|
1380
|
+
return count;
|
|
1381
|
+
}
|
|
1382
|
+
function createDurationMs(ms) {
|
|
1383
|
+
if (ms < 0 || !Number.isFinite(ms)) {
|
|
1384
|
+
throw new Error(`Duration must be a non-negative finite number, got: ${ms}`);
|
|
1385
|
+
}
|
|
1386
|
+
return ms;
|
|
1387
|
+
}
|
|
1388
|
+
function calculateBackoffDelay(attempt, config) {
|
|
1389
|
+
const delay = Math.min(config.initialDelayMs * config.multiplier ** attempt, config.maxDelayMs);
|
|
1390
|
+
return createDurationMs(delay);
|
|
1391
|
+
}
|
|
1392
|
+
function getResourceUsage() {
|
|
1393
|
+
const memory = process.memoryUsage();
|
|
1394
|
+
const cpu = process.cpuUsage();
|
|
1395
|
+
const cpuCount = Math.max(1, os.cpus().length);
|
|
1396
|
+
const load1 = os.loadavg?.()[0] ?? 0;
|
|
1397
|
+
const cpuPercent = Math.max(0, load1 / cpuCount * 100);
|
|
1398
|
+
return {
|
|
1399
|
+
memory,
|
|
1400
|
+
cpu: (cpu.user + cpu.system) / 1e6,
|
|
1401
|
+
// Convert to seconds
|
|
1402
|
+
processes: globalProcessLimiter.getActiveCount(),
|
|
1403
|
+
cpuPercent
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
var EMPTY_DIFF_FAILURE_PATTERN = /no[- ]?changes? detected|empty (?:diff|change set)|git diff (?:is )?empty|baseline unchanged|delivery no[- ]?op/i;
|
|
1407
|
+
function enabledRequiredGatesActuallyRanAndPassed(result, enabled) {
|
|
1408
|
+
if (!enabled.qualityGates && !enabled.customGates) {
|
|
1409
|
+
return false;
|
|
1410
|
+
}
|
|
1411
|
+
let standardGateEvidence = false;
|
|
1412
|
+
if (enabled.qualityGates) {
|
|
1413
|
+
const gates = result.qualityGates;
|
|
1414
|
+
if (gates?.some((gate) => isBlockingQualityGateForCompletion(gate)) === true) {
|
|
1415
|
+
return false;
|
|
1416
|
+
}
|
|
1417
|
+
if (gates?.some((gate) => gate.unavailable === true)) {
|
|
1418
|
+
return false;
|
|
1419
|
+
}
|
|
1420
|
+
standardGateEvidence = qualityGatesAllowCompletion(gates);
|
|
1421
|
+
}
|
|
1422
|
+
let customGateEvidence = false;
|
|
1423
|
+
if (enabled.customGates) {
|
|
1424
|
+
const customGates = result.customGateResults;
|
|
1425
|
+
if (!customGates || customGates.length === 0) {
|
|
1426
|
+
return false;
|
|
1427
|
+
}
|
|
1428
|
+
for (const gate of customGates) {
|
|
1429
|
+
if (gate.skipped === true || gate.unavailable === true || !gate.passed) {
|
|
1430
|
+
return false;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
customGateEvidence = customGates.some(
|
|
1434
|
+
(gate) => gate.passed && gate.skipped !== true && gate.unavailable !== true
|
|
1435
|
+
);
|
|
1436
|
+
}
|
|
1437
|
+
if (!standardGateEvidence && !customGateEvidence) {
|
|
1438
|
+
return false;
|
|
1439
|
+
}
|
|
1440
|
+
if (result.requirements?.enabled && !result.requirements.passed) {
|
|
1441
|
+
return false;
|
|
1442
|
+
}
|
|
1443
|
+
return true;
|
|
1444
|
+
}
|
|
1445
|
+
function resolveMatureDeliveryVerification(result, enabled) {
|
|
1446
|
+
if (result.completionSummary?.completionSignalDetected !== true) {
|
|
1447
|
+
return null;
|
|
1448
|
+
}
|
|
1449
|
+
if (!enabled.qualityGates && !enabled.customGates) {
|
|
1450
|
+
if (enabled.qualityGatePolicy !== "explicitly_disabled") {
|
|
1451
|
+
return null;
|
|
1452
|
+
}
|
|
1453
|
+
if (result.completionSummary.hasSubstantiveEvidence !== true) {
|
|
1454
|
+
return null;
|
|
1455
|
+
}
|
|
1456
|
+
const expectedUnverifiedBlockers = /* @__PURE__ */ new Set([
|
|
1457
|
+
COMPLETION_BLOCKER_PROGRESS_VERIFICATION_UNAVAILABLE
|
|
1458
|
+
]);
|
|
1459
|
+
const hasSubstantiveEvidence = result.completionSummary.hasSubstantiveEvidence === true;
|
|
1460
|
+
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(
|
|
1461
|
+
(issue) => expectedUnverifiedBlockers.has(issue)
|
|
1462
|
+
) === true;
|
|
1463
|
+
if (!completionStatusAllowsSuccess(result.completionSummary.status) && !explicitlyDisabledWithOnlyExpectedUnverifiedEvidenceGaps) {
|
|
1464
|
+
return null;
|
|
1465
|
+
}
|
|
1466
|
+
if (result.requirements?.enabled && !result.requirements.passed) {
|
|
1467
|
+
return null;
|
|
1468
|
+
}
|
|
1469
|
+
if (isSemanticCheckBlocking(result.semanticValidation)) {
|
|
1470
|
+
return null;
|
|
1471
|
+
}
|
|
1472
|
+
return "unverified";
|
|
1473
|
+
}
|
|
1474
|
+
if (!completionStatusAllowsSuccess(result.completionSummary.status)) {
|
|
1475
|
+
return null;
|
|
1476
|
+
}
|
|
1477
|
+
return enabledRequiredGatesActuallyRanAndPassed(result, enabled) ? "verified" : null;
|
|
1478
|
+
}
|
|
1479
|
+
function isRealFirstDeliveryIteration(result, enabled) {
|
|
1480
|
+
if (!result.success) {
|
|
1481
|
+
return false;
|
|
1482
|
+
}
|
|
1483
|
+
if (typeof result.iterationFingerprint !== "string" || result.iterationFingerprint === "") {
|
|
1484
|
+
return false;
|
|
1485
|
+
}
|
|
1486
|
+
return resolveMatureDeliveryVerification(result, enabled) !== null;
|
|
1487
|
+
}
|
|
1488
|
+
function isEmptyDiffIdleFailure(result) {
|
|
1489
|
+
if (result.success) {
|
|
1490
|
+
return result.iterationFingerprint === "";
|
|
1491
|
+
}
|
|
1492
|
+
return EMPTY_DIFF_FAILURE_PATTERN.test(result.error?.message ?? "");
|
|
1493
|
+
}
|
|
1494
|
+
function shouldIdleStopAfterRealFirstDelivery(priorIterations, current, enabled) {
|
|
1495
|
+
return resolveIdleStopAfterRealFirstDelivery(priorIterations, current, enabled).shouldStop;
|
|
1496
|
+
}
|
|
1497
|
+
function resolveIdleStopAfterRealFirstDelivery(priorIterations, current, enabled, options = {}) {
|
|
1498
|
+
if (options.iterationChangeEvidenceTrusted === false || !isEmptyDiffIdleFailure(current)) {
|
|
1499
|
+
return { shouldStop: false };
|
|
1500
|
+
}
|
|
1501
|
+
const priorIterationIndex = priorIterations.length - 1;
|
|
1502
|
+
if (priorIterationIndex < 0) {
|
|
1503
|
+
return { shouldStop: false };
|
|
1504
|
+
}
|
|
1505
|
+
const priorIteration = priorIterations[priorIterationIndex];
|
|
1506
|
+
if (!isRealFirstDeliveryIteration(priorIteration, enabled)) {
|
|
1507
|
+
return { shouldStop: false };
|
|
1508
|
+
}
|
|
1509
|
+
const verification = resolveMatureDeliveryVerification(priorIteration, enabled);
|
|
1510
|
+
if (verification === null) {
|
|
1511
|
+
return { shouldStop: false };
|
|
1512
|
+
}
|
|
1513
|
+
return { shouldStop: true, priorIterationIndex, verification };
|
|
1514
|
+
}
|
|
1515
|
+
var AutonomousLoopController = class extends EventEmitter {
|
|
1516
|
+
config;
|
|
1517
|
+
recursionTracker;
|
|
1518
|
+
telemetry;
|
|
1519
|
+
resultStreamer;
|
|
1520
|
+
aiJudge;
|
|
1521
|
+
qualityGates;
|
|
1522
|
+
progressValidator;
|
|
1523
|
+
state = { status: "idle" };
|
|
1524
|
+
iterationHistory = [];
|
|
1525
|
+
startTime = 0;
|
|
1526
|
+
originalStartTime = 0;
|
|
1527
|
+
elapsedRuntimeBeforePauseMs = 0;
|
|
1528
|
+
instanceId = `AutonomousLoopController-${createHash("md5").update(String(Date.now() + Math.random())).digest("hex").slice(0, 8)}`;
|
|
1529
|
+
cleanupStarted = false;
|
|
1530
|
+
backoffAttempts = 0;
|
|
1531
|
+
resourceWarnings = /* @__PURE__ */ new Set();
|
|
1532
|
+
lastErrorSignature = null;
|
|
1533
|
+
consecutiveIdenticalCount = 0;
|
|
1534
|
+
/**
|
|
1535
|
+
* Set when shouldContinue idle-stops after a real first delivery so start()
|
|
1536
|
+
* can mark the run completed even if the completion XML 0.3 gate left the
|
|
1537
|
+
* oracle at NOT_COMPLETE. Does not change totalIterations accounting.
|
|
1538
|
+
*/
|
|
1539
|
+
idleStoppedAfterRealFirstDelivery = false;
|
|
1540
|
+
/** Pending pause gate; the iteration loop awaits this while paused. */
|
|
1541
|
+
pauseGatePromise = null;
|
|
1542
|
+
/** Resolves the pause gate; set by pause(), released by resume()/terminate(). */
|
|
1543
|
+
pauseGateRelease = null;
|
|
1544
|
+
cleanupHandlers = [];
|
|
1545
|
+
workingDir = process.cwd();
|
|
1546
|
+
/** Whether completion signal matched on last iteration */
|
|
1547
|
+
completionSignalMatched = false;
|
|
1548
|
+
/** Quality baseline captured at loop start (undefined until initialized) */
|
|
1549
|
+
qualityBaseline;
|
|
1550
|
+
/** Custom gate pass/fail captured at loop start (gate id -> passed). */
|
|
1551
|
+
customGateBaseline;
|
|
1552
|
+
/** TypeScript error baseline captured at loop start (null if not applicable) */
|
|
1553
|
+
compilationBaselineErrors = null;
|
|
1554
|
+
/** Monotonic policy level for stability-first escalation */
|
|
1555
|
+
policyLevel = "baseline";
|
|
1556
|
+
/**
|
|
1557
|
+
* Git ref (SHA) captured at loop start for semantic validation diffs.
|
|
1558
|
+
*
|
|
1559
|
+
* Important: semantic validation should evaluate cumulative work across the whole loop,
|
|
1560
|
+
* not just the last iteration’s working-tree or last commit’s diff.
|
|
1561
|
+
*/
|
|
1562
|
+
semanticBaselineRef = null;
|
|
1563
|
+
/** Loop-start HEAD SHA for change-surface gate scaling. */
|
|
1564
|
+
loopStartRef = null;
|
|
1565
|
+
/** Git ref (SHA) captured at loop start for progress validation diffs. */
|
|
1566
|
+
progressBaselineRef = null;
|
|
1567
|
+
/** Current provider for cross-provider pivot (initialized from routing decision or undefined) */
|
|
1568
|
+
currentProvider;
|
|
1569
|
+
/** Current provider setup mode for pivot-aware execution mode selection */
|
|
1570
|
+
currentProviderSetup;
|
|
1571
|
+
/** Available alternate providers for pivot */
|
|
1572
|
+
availableAlternates = [];
|
|
1573
|
+
constructor(config = {}, dependencies = {}) {
|
|
1574
|
+
super();
|
|
1575
|
+
this.config = {
|
|
1576
|
+
maxIterations: createIterationCount(3),
|
|
1577
|
+
timeboxMs: createDurationMs(DEFAULT_AUTOLOOP_TIMEBOX_MS),
|
|
1578
|
+
minProgressThreshold: createProgressScore(0.05),
|
|
1579
|
+
useAIJudge: false,
|
|
1580
|
+
runQualityGates: false,
|
|
1581
|
+
qualityGatesMode: "fast",
|
|
1582
|
+
resourceLimits: DEFAULT_AUTOLOOP_RESOURCE_LIMITS,
|
|
1583
|
+
backoffConfig: {
|
|
1584
|
+
initialDelayMs: createDurationMs(1e3),
|
|
1585
|
+
maxDelayMs: createDurationMs(3e4),
|
|
1586
|
+
multiplier: 2,
|
|
1587
|
+
maxRetries: 3
|
|
1588
|
+
},
|
|
1589
|
+
progressConfig: {
|
|
1590
|
+
windowSize: 3,
|
|
1591
|
+
trendThreshold: 0.01,
|
|
1592
|
+
confidenceThreshold: 0.7
|
|
1593
|
+
},
|
|
1594
|
+
validationMode: "heuristic",
|
|
1595
|
+
requirements: {
|
|
1596
|
+
mode: "auto",
|
|
1597
|
+
minCoverage: 0.9,
|
|
1598
|
+
requireEvidence: true,
|
|
1599
|
+
blockNewRepoRootMarkdown: true
|
|
1600
|
+
},
|
|
1601
|
+
// completionSignal is undefined by default (opt-in)
|
|
1602
|
+
...config
|
|
1603
|
+
};
|
|
1604
|
+
this.recursionTracker = globalRecursionTracker;
|
|
1605
|
+
this.telemetry = dependencies.telemetry;
|
|
1606
|
+
this.resultStreamer = dependencies.resultStreamer;
|
|
1607
|
+
this.aiJudge = dependencies.aiJudge;
|
|
1608
|
+
this.qualityGates = dependencies.qualityGates;
|
|
1609
|
+
this.validateConfig();
|
|
1610
|
+
if (this.config.routingDecision) {
|
|
1611
|
+
this.currentProvider = this.config.routingDecision.primary.provider;
|
|
1612
|
+
this.currentProviderSetup = this.config.routingDecision.primary.setup;
|
|
1613
|
+
this.availableAlternates = [...this.config.routingDecision.alternates];
|
|
1614
|
+
}
|
|
1615
|
+
this.progressValidator = createCustomProgressValidator({
|
|
1616
|
+
minProgressThreshold: this.config.minProgressThreshold,
|
|
1617
|
+
trendThreshold: this.config.progressConfig.trendThreshold
|
|
1618
|
+
});
|
|
1619
|
+
this.setupEventForwarding();
|
|
1620
|
+
}
|
|
1621
|
+
// ========================================================================
|
|
1622
|
+
// PUBLIC API
|
|
1623
|
+
// ========================================================================
|
|
1624
|
+
/**
|
|
1625
|
+
* Start the autonomous loop with the given task function
|
|
1626
|
+
*/
|
|
1627
|
+
async start(taskFunction) {
|
|
1628
|
+
if (this.state.status !== "idle") {
|
|
1629
|
+
throw new Error(`Cannot start loop in state: ${this.state.status}`);
|
|
1630
|
+
}
|
|
1631
|
+
try {
|
|
1632
|
+
this.synchronizeWallClockBudgetAtStart();
|
|
1633
|
+
this.startTime = performance.now();
|
|
1634
|
+
this.originalStartTime = this.startTime;
|
|
1635
|
+
this.state = {
|
|
1636
|
+
status: "running",
|
|
1637
|
+
_iteration: createIterationCount(0),
|
|
1638
|
+
startTime: this.startTime
|
|
1639
|
+
};
|
|
1640
|
+
if (this.getRemainingTimeboxMs() <= 0) {
|
|
1641
|
+
this.terminate("timebox_exceeded");
|
|
1642
|
+
throw new Error("Autoloop timebox exceeded before loop started");
|
|
1643
|
+
}
|
|
1644
|
+
await this.initializeSafetySystems();
|
|
1645
|
+
this.emit("loop_started", { type: "loop_started", config: this.config });
|
|
1646
|
+
let lastResult;
|
|
1647
|
+
for (let i = 1; i <= this.config.maxIterations; i++) {
|
|
1648
|
+
await this.waitWhilePaused();
|
|
1649
|
+
if (this.state.status !== "running") {
|
|
1650
|
+
break;
|
|
1651
|
+
}
|
|
1652
|
+
const iteration = createIterationCount(i);
|
|
1653
|
+
if (this.state.status === "running") {
|
|
1654
|
+
this.state._iteration = iteration;
|
|
1655
|
+
}
|
|
1656
|
+
if (await this.shouldTerminate(iteration)) {
|
|
1657
|
+
break;
|
|
1658
|
+
}
|
|
1659
|
+
await this.waitWhilePaused();
|
|
1660
|
+
if (this.state.status !== "running") {
|
|
1661
|
+
break;
|
|
1662
|
+
}
|
|
1663
|
+
lastResult = await this.executeIteration(iteration, taskFunction);
|
|
1664
|
+
this.iterationHistory.push(lastResult);
|
|
1665
|
+
if (!await this.shouldContinue(lastResult)) {
|
|
1666
|
+
break;
|
|
1667
|
+
}
|
|
1668
|
+
if (!lastResult.success) {
|
|
1669
|
+
await this.applyBackoff();
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
await this.waitWhilePaused();
|
|
1673
|
+
if (!lastResult) {
|
|
1674
|
+
const terminatedReason2 = this.state.status === "terminated" ? this.state.reason : void 0;
|
|
1675
|
+
if (terminatedReason2 === "timebox_exceeded") {
|
|
1676
|
+
const timeboxMin = (this.config.timeboxMs / 6e4).toFixed(1);
|
|
1677
|
+
throw new Error(
|
|
1678
|
+
`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.`
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
throw new Error("No iterations were executed");
|
|
1682
|
+
}
|
|
1683
|
+
const finalResult = lastResult;
|
|
1684
|
+
const totalDuration = createDurationMs(this.getElapsedRuntimeMs());
|
|
1685
|
+
const hasCompilationFailure = this.detectCompilationFailure(finalResult);
|
|
1686
|
+
const currentTerminatedReason = this.state.status === "terminated" ? this.state.reason : null;
|
|
1687
|
+
const isMaxIterationsOnly = currentTerminatedReason === "max_iterations_reached";
|
|
1688
|
+
if (hasCompilationFailure && (this.state.status !== "terminated" || isMaxIterationsOnly)) {
|
|
1689
|
+
this.telemetry?.logEvent({
|
|
1690
|
+
name: "loop_terminated_compilation_errors",
|
|
1691
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
1692
|
+
properties: {
|
|
1693
|
+
iteration: finalResult._iteration,
|
|
1694
|
+
progressScore: finalResult.progress.score,
|
|
1695
|
+
insights: finalResult.progress.insights.slice(0, 3)
|
|
1696
|
+
}
|
|
1697
|
+
});
|
|
1698
|
+
this.upgradeTerminationReason("compilation_errors");
|
|
1699
|
+
return { ...finalResult, success: false };
|
|
1700
|
+
}
|
|
1701
|
+
if (this.iterationHistory.length >= this.config.maxIterations && this.state.status === "running") {
|
|
1702
|
+
this.terminate("max_iterations_reached");
|
|
1703
|
+
}
|
|
1704
|
+
const ranAllIterations = this.iterationHistory.length === this.config.maxIterations;
|
|
1705
|
+
const terminatedReason = this.state.status === "terminated" ? this.state.reason : null;
|
|
1706
|
+
const isBudgetCompletionTermination = terminatedReason === "max_iterations_reached";
|
|
1707
|
+
const isSuccessfulEarlyTermination = terminatedReason !== null && isSuccessLikeControllerReason(terminatedReason);
|
|
1708
|
+
const currentStateStatus = this.state.status;
|
|
1709
|
+
const summaryProvesUnsafeCompletion = finalResult.completionSummary?.unsafeCompletion === true;
|
|
1710
|
+
const summaryAllowsCompletion = completionStatusAllowsSuccess(finalResult.completionSummary?.status) || this.idleStoppedAfterRealFirstDelivery;
|
|
1711
|
+
const shouldMarkCompleted = (currentStateStatus === "running" && finalResult.success !== false || currentStateStatus === "terminated" && (ranAllIterations && isBudgetCompletionTermination || isSuccessfulEarlyTermination) && finalResult.success !== false) && !summaryProvesUnsafeCompletion && summaryAllowsCompletion;
|
|
1712
|
+
if (shouldMarkCompleted) {
|
|
1713
|
+
this.state = {
|
|
1714
|
+
status: "completed",
|
|
1715
|
+
totalIterations: createIterationCount(this.iterationHistory.length),
|
|
1716
|
+
finalScore: finalResult.progress.score,
|
|
1717
|
+
duration: totalDuration,
|
|
1718
|
+
completionReason: terminatedReason ?? void 0
|
|
1719
|
+
};
|
|
1720
|
+
this.emit("loop_completed", {
|
|
1721
|
+
type: "loop_completed",
|
|
1722
|
+
finalResult,
|
|
1723
|
+
totalDuration
|
|
1724
|
+
});
|
|
1725
|
+
} else if (this.state.status === "running" && finalResult.success === false) {
|
|
1726
|
+
const failureError = finalResult.error ?? new Error("Autoloop ended without success");
|
|
1727
|
+
this.state = {
|
|
1728
|
+
status: "failed",
|
|
1729
|
+
_iteration: finalResult._iteration,
|
|
1730
|
+
_error: failureError,
|
|
1731
|
+
duration: totalDuration
|
|
1732
|
+
};
|
|
1733
|
+
this.emit("loop_failed", {
|
|
1734
|
+
type: "loop_failed",
|
|
1735
|
+
error: failureError,
|
|
1736
|
+
_iteration: finalResult._iteration
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
return finalResult;
|
|
1740
|
+
} catch (error) {
|
|
1741
|
+
if (this.state.status === "terminated") {
|
|
1742
|
+
throw error;
|
|
1743
|
+
}
|
|
1744
|
+
const currentIteration = this.state.status === "running" ? this.state._iteration : createIterationCount(0);
|
|
1745
|
+
const duration = createDurationMs(this.getElapsedRuntimeMs());
|
|
1746
|
+
this.state = {
|
|
1747
|
+
status: "failed",
|
|
1748
|
+
_iteration: currentIteration,
|
|
1749
|
+
_error: error,
|
|
1750
|
+
duration
|
|
1751
|
+
};
|
|
1752
|
+
this.emit("loop_failed", {
|
|
1753
|
+
type: "loop_failed",
|
|
1754
|
+
error,
|
|
1755
|
+
_iteration: currentIteration
|
|
1756
|
+
});
|
|
1757
|
+
throw error;
|
|
1758
|
+
} finally {
|
|
1759
|
+
await this.cleanup();
|
|
1760
|
+
this.close();
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
/**
|
|
1764
|
+
* Pause the loop execution.
|
|
1765
|
+
*
|
|
1766
|
+
* The iteration loop blocks on an internal gate while paused: no new
|
|
1767
|
+
* iteration starts until resume() releases the gate or terminate() ends
|
|
1768
|
+
* the run. An iteration already in flight runs to completion first.
|
|
1769
|
+
*/
|
|
1770
|
+
pause(reason) {
|
|
1771
|
+
if (this.state.status !== "running") {
|
|
1772
|
+
throw new Error(`Cannot pause loop in state: ${this.state.status}`);
|
|
1773
|
+
}
|
|
1774
|
+
this.elapsedRuntimeBeforePauseMs += performance.now() - this.startTime;
|
|
1775
|
+
this.state = {
|
|
1776
|
+
status: "paused",
|
|
1777
|
+
_iteration: this.state._iteration,
|
|
1778
|
+
pauseReason: reason
|
|
1779
|
+
};
|
|
1780
|
+
this.pauseGatePromise = new Promise((resolve) => {
|
|
1781
|
+
this.pauseGateRelease = resolve;
|
|
1782
|
+
});
|
|
1783
|
+
this.emit("loop_paused", { type: "loop_paused", reason });
|
|
1784
|
+
}
|
|
1785
|
+
/**
|
|
1786
|
+
* Set the initial policy level (e.g., from static pre-run detection).
|
|
1787
|
+
*
|
|
1788
|
+
* Monotonic: only allows moving to a more conservative level.
|
|
1789
|
+
*/
|
|
1790
|
+
setInitialPolicyLevel(level) {
|
|
1791
|
+
if (this.policyLevel === "safe") return;
|
|
1792
|
+
if (this.policyLevel === "guarded" && level === "baseline") return;
|
|
1793
|
+
this.policyLevel = level;
|
|
1794
|
+
}
|
|
1795
|
+
/**
|
|
1796
|
+
* Apply a monotonic escalation in response to a runtime signal.
|
|
1797
|
+
*
|
|
1798
|
+
* Returns true if the policy level advanced (even if no config knobs changed),
|
|
1799
|
+
* false if already at max level.
|
|
1800
|
+
*/
|
|
1801
|
+
escalatePolicy(signal, details) {
|
|
1802
|
+
const escalation = computeMonotonicAutoloopEscalation({
|
|
1803
|
+
currentLevel: this.policyLevel,
|
|
1804
|
+
signal,
|
|
1805
|
+
currentValidationMode: this.config.validationMode,
|
|
1806
|
+
currentUseAIJudge: this.config.useAIJudge,
|
|
1807
|
+
currentQualityGatesMode: this.config.qualityGatesMode,
|
|
1808
|
+
runQualityGates: this.config.runQualityGates
|
|
1809
|
+
});
|
|
1810
|
+
if (!escalation) return false;
|
|
1811
|
+
if (escalation.corePatch.validationMode && this.config.validationMode === "none") {
|
|
1812
|
+
this.config.validationMode = escalation.corePatch.validationMode;
|
|
1813
|
+
}
|
|
1814
|
+
if (escalation.corePatch.useAIJudge === true) {
|
|
1815
|
+
if (this.aiJudge) {
|
|
1816
|
+
this.config.useAIJudge = true;
|
|
1817
|
+
} else {
|
|
1818
|
+
this.telemetry?.logEvent({
|
|
1819
|
+
name: "autoloop_escalation_skipped",
|
|
1820
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
1821
|
+
properties: { reason: "ai_judge_dependency_missing", signal }
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
if (escalation.corePatch.qualityGatesMode && this.config.runQualityGates) {
|
|
1826
|
+
if (this.config.qualityGatesMode === "fast" && escalation.corePatch.qualityGatesMode === "safe") {
|
|
1827
|
+
this.config.qualityGatesMode = "safe";
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
const from = this.policyLevel;
|
|
1831
|
+
this.policyLevel = escalation.to;
|
|
1832
|
+
this.telemetry?.logEvent({
|
|
1833
|
+
name: "autoloop_policy_escalated",
|
|
1834
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
1835
|
+
properties: {
|
|
1836
|
+
from,
|
|
1837
|
+
to: escalation.to,
|
|
1838
|
+
signal,
|
|
1839
|
+
appliedPatch: escalation.corePatch,
|
|
1840
|
+
...details ? { details } : {}
|
|
1841
|
+
}
|
|
1842
|
+
});
|
|
1843
|
+
this.emit("policy_escalated", {
|
|
1844
|
+
type: "policy_escalated",
|
|
1845
|
+
from,
|
|
1846
|
+
to: escalation.to,
|
|
1847
|
+
signal,
|
|
1848
|
+
appliedPatch: escalation.corePatch,
|
|
1849
|
+
...details ? { details } : {}
|
|
1850
|
+
});
|
|
1851
|
+
return true;
|
|
1852
|
+
}
|
|
1853
|
+
/**
|
|
1854
|
+
* Resume the loop execution
|
|
1855
|
+
*/
|
|
1856
|
+
resume() {
|
|
1857
|
+
if (this.state.status !== "paused") {
|
|
1858
|
+
throw new Error(`Cannot resume loop in state: ${this.state.status}`);
|
|
1859
|
+
}
|
|
1860
|
+
this.startTime = performance.now();
|
|
1861
|
+
this.state = {
|
|
1862
|
+
status: "running",
|
|
1863
|
+
_iteration: this.state._iteration,
|
|
1864
|
+
startTime: this.originalStartTime
|
|
1865
|
+
};
|
|
1866
|
+
this.releasePauseGate();
|
|
1867
|
+
this.emit("loop_resumed", {
|
|
1868
|
+
type: "loop_resumed",
|
|
1869
|
+
_iteration: this.state._iteration
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Terminate the loop with a specific reason
|
|
1874
|
+
*/
|
|
1875
|
+
terminate(reason) {
|
|
1876
|
+
if (this.state.status === "terminated") {
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
if (this.state.status === "idle" || this.state.status === "completed" || this.state.status === "failed") {
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
if (this.state.status !== "running" && this.state.status !== "paused") {
|
|
1883
|
+
return;
|
|
1884
|
+
}
|
|
1885
|
+
const currentIteration = createIterationCount(this.iterationHistory.length);
|
|
1886
|
+
const duration = createDurationMs(this.getElapsedRuntimeMs());
|
|
1887
|
+
this.state = {
|
|
1888
|
+
status: "terminated",
|
|
1889
|
+
_iteration: currentIteration,
|
|
1890
|
+
reason,
|
|
1891
|
+
duration
|
|
1892
|
+
};
|
|
1893
|
+
this.releasePauseGate();
|
|
1894
|
+
this.emit("loop_terminated", {
|
|
1895
|
+
type: "loop_terminated",
|
|
1896
|
+
reason,
|
|
1897
|
+
_iteration: currentIteration
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
/**
|
|
1901
|
+
* Internal reason upgrade used by the start() epilogue: replaces the generic
|
|
1902
|
+
* budget termination ('max_iterations_reached') with a more specific reason
|
|
1903
|
+
* such as 'compilation_errors'. Bypasses terminate()'s already-terminated
|
|
1904
|
+
* early return without changing public terminate() semantics. Deliberately
|
|
1905
|
+
* does not re-emit 'loop_terminated' (the original termination event has
|
|
1906
|
+
* already been delivered to ledger/CLI listeners).
|
|
1907
|
+
*/
|
|
1908
|
+
upgradeTerminationReason(reason) {
|
|
1909
|
+
if (this.state.status !== "terminated") {
|
|
1910
|
+
this.terminate(reason);
|
|
1911
|
+
return;
|
|
1912
|
+
}
|
|
1913
|
+
this.state = { ...this.state, reason };
|
|
1914
|
+
}
|
|
1915
|
+
/** Release a pending pause gate (resume or terminate). */
|
|
1916
|
+
releasePauseGate() {
|
|
1917
|
+
const release = this.pauseGateRelease;
|
|
1918
|
+
this.pauseGateRelease = null;
|
|
1919
|
+
this.pauseGatePromise = null;
|
|
1920
|
+
release?.();
|
|
1921
|
+
}
|
|
1922
|
+
/**
|
|
1923
|
+
* Block the iteration loop while externally paused. resume() or terminate()
|
|
1924
|
+
* releases the gate; callers must re-check state afterwards.
|
|
1925
|
+
*/
|
|
1926
|
+
async waitWhilePaused() {
|
|
1927
|
+
while (this.state.status === "paused") {
|
|
1928
|
+
const gate = this.pauseGatePromise;
|
|
1929
|
+
if (!gate) {
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
await gate;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
/**
|
|
1936
|
+
* Get current loop state
|
|
1937
|
+
*/
|
|
1938
|
+
getState() {
|
|
1939
|
+
return { ...this.state };
|
|
1940
|
+
}
|
|
1941
|
+
/**
|
|
1942
|
+
* Get iteration history
|
|
1943
|
+
*/
|
|
1944
|
+
getIterationHistory() {
|
|
1945
|
+
return [...this.iterationHistory];
|
|
1946
|
+
}
|
|
1947
|
+
/**
|
|
1948
|
+
* Get current configuration
|
|
1949
|
+
*/
|
|
1950
|
+
getConfig() {
|
|
1951
|
+
return { ...this.config };
|
|
1952
|
+
}
|
|
1953
|
+
/**
|
|
1954
|
+
* Override the working directory used for git-based progress validation and quality gates.
|
|
1955
|
+
*
|
|
1956
|
+
* Useful when an orchestrator executes iterations inside an isolated worktree.
|
|
1957
|
+
*/
|
|
1958
|
+
setWorkingDir(workingDir) {
|
|
1959
|
+
this.workingDir = workingDir;
|
|
1960
|
+
}
|
|
1961
|
+
/**
|
|
1962
|
+
* Apply outer-run wall-clock handoff immediately before start().
|
|
1963
|
+
*
|
|
1964
|
+
* CLI setup (evidence-plan resolution, worktree creation, etc.) happens before the
|
|
1965
|
+
* controller starts; this keeps custom/evidence gate budgets aligned with runStart.
|
|
1966
|
+
*/
|
|
1967
|
+
applyWallClockHandoff(handoff) {
|
|
1968
|
+
if (typeof handoff.wallClockRunStartMs === "number" && Number.isFinite(handoff.wallClockRunStartMs)) {
|
|
1969
|
+
this.config.wallClockRunStartMs = handoff.wallClockRunStartMs;
|
|
1970
|
+
}
|
|
1971
|
+
if (typeof handoff.preControllerElapsedMs === "number" && Number.isFinite(handoff.preControllerElapsedMs)) {
|
|
1972
|
+
this.config.preControllerElapsedMs = Math.max(0, Math.floor(handoff.preControllerElapsedMs));
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
// ========================================================================
|
|
1976
|
+
// PRIVATE IMPLEMENTATION
|
|
1977
|
+
// ========================================================================
|
|
1978
|
+
/**
|
|
1979
|
+
* Validate configuration values
|
|
1980
|
+
*/
|
|
1981
|
+
validateConfig() {
|
|
1982
|
+
if (this.config.maxIterations <= 0) {
|
|
1983
|
+
throw new Error("Iteration count must be a positive integer");
|
|
1984
|
+
}
|
|
1985
|
+
if (this.config.validationMode === "deterministic" && this.config.completionSignal) {
|
|
1986
|
+
throw new Error(
|
|
1987
|
+
'Cannot combine validation mode "deterministic" with a completion signal. Deterministic mode uses quality gates to determine completion.'
|
|
1988
|
+
);
|
|
1989
|
+
}
|
|
1990
|
+
if (this.config.runQualityGates && !this.qualityGates) {
|
|
1991
|
+
throw new Error(
|
|
1992
|
+
"Quality gates enabled (runQualityGates=true) but no QualityGateRunner injected. Either wire `dependencies.qualityGates` or set `runQualityGates: false` if gates are run elsewhere."
|
|
1993
|
+
);
|
|
1994
|
+
}
|
|
1995
|
+
if (this.config.useAIJudge && !this.aiJudge) {
|
|
1996
|
+
throw new Error(
|
|
1997
|
+
"AI judge enabled (useAIJudge=true) but no Judge injected. Either wire `dependencies.aiJudge` or set `useAIJudge: false`."
|
|
1998
|
+
);
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
synchronizeWallClockBudgetAtStart() {
|
|
2002
|
+
const elapsedMs = resolveAutoloopElapsedMs({
|
|
2003
|
+
wallClockRunStartMs: this.config.wallClockRunStartMs,
|
|
2004
|
+
preControllerElapsedMs: this.config.preControllerElapsedMs
|
|
2005
|
+
});
|
|
2006
|
+
if (elapsedMs > 0) {
|
|
2007
|
+
this.elapsedRuntimeBeforePauseMs = elapsedMs;
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
getElapsedRuntimeMs() {
|
|
2011
|
+
if (typeof this.config.wallClockRunStartMs === "number" && Number.isFinite(this.config.wallClockRunStartMs)) {
|
|
2012
|
+
return Math.max(0, Date.now() - this.config.wallClockRunStartMs);
|
|
2013
|
+
}
|
|
2014
|
+
if (this.state.status === "running") {
|
|
2015
|
+
return this.elapsedRuntimeBeforePauseMs + (performance.now() - this.startTime);
|
|
2016
|
+
}
|
|
2017
|
+
return this.elapsedRuntimeBeforePauseMs;
|
|
2018
|
+
}
|
|
2019
|
+
isRunAborted() {
|
|
2020
|
+
return this.config.abortSignal?.aborted === true;
|
|
2021
|
+
}
|
|
2022
|
+
getRemainingTimeboxMs() {
|
|
2023
|
+
return Math.max(0, Math.floor(this.config.timeboxMs - this.getElapsedRuntimeMs()));
|
|
2024
|
+
}
|
|
2025
|
+
ensureRemainingTimeboxMs(phase) {
|
|
2026
|
+
const remainingMs = this.getRemainingTimeboxMs();
|
|
2027
|
+
if (remainingMs <= 0) {
|
|
2028
|
+
this.terminate("timebox_exceeded");
|
|
2029
|
+
throw new Error(`Autoloop timebox exceeded before ${phase}`);
|
|
2030
|
+
}
|
|
2031
|
+
return remainingMs;
|
|
2032
|
+
}
|
|
2033
|
+
getFirstIterationReserveMs() {
|
|
2034
|
+
const timeboxMs = Number(this.config.timeboxMs);
|
|
2035
|
+
if (!Number.isFinite(timeboxMs) || timeboxMs <= 0) {
|
|
2036
|
+
return 0;
|
|
2037
|
+
}
|
|
2038
|
+
const proportionalReserveMs = Math.floor(timeboxMs * 0.25);
|
|
2039
|
+
const maxReserveForTimeboxMs = Math.max(1, Math.floor(timeboxMs * 0.5));
|
|
2040
|
+
return Math.min(
|
|
2041
|
+
MAX_FIRST_ITERATION_RESERVE_MS,
|
|
2042
|
+
maxReserveForTimeboxMs,
|
|
2043
|
+
Math.max(MIN_FIRST_ITERATION_RESERVE_MS, proportionalReserveMs)
|
|
2044
|
+
);
|
|
2045
|
+
}
|
|
2046
|
+
getPreIterationGateBudgetMs() {
|
|
2047
|
+
const remainingMs = this.getRemainingTimeboxMs();
|
|
2048
|
+
const reserveMs = this.getFirstIterationReserveMs();
|
|
2049
|
+
return {
|
|
2050
|
+
budgetMs: Math.max(0, remainingMs - reserveMs),
|
|
2051
|
+
reserveMs,
|
|
2052
|
+
remainingMs
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
/**
|
|
2056
|
+
* Initialize safety systems
|
|
2057
|
+
*/
|
|
2058
|
+
async initializeSafetySystems() {
|
|
2059
|
+
await this.recursionTracker.enter();
|
|
2060
|
+
this.checkResourceLimits();
|
|
2061
|
+
this.setupCleanupHandlers();
|
|
2062
|
+
this.compilationBaselineErrors = await countTypeScriptErrors(this.workingDir);
|
|
2063
|
+
if (this.compilationBaselineErrors !== null) {
|
|
2064
|
+
this.telemetry?.logEvent({
|
|
2065
|
+
name: "compilation_baseline_captured",
|
|
2066
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2067
|
+
properties: {
|
|
2068
|
+
totalErrors: this.compilationBaselineErrors
|
|
2069
|
+
}
|
|
2070
|
+
});
|
|
2071
|
+
}
|
|
2072
|
+
if (this.config.runQualityGates && this.qualityGates) {
|
|
2073
|
+
const {
|
|
2074
|
+
budgetMs: baselineBudgetMs,
|
|
2075
|
+
reserveMs,
|
|
2076
|
+
remainingMs
|
|
2077
|
+
} = this.getPreIterationGateBudgetMs();
|
|
2078
|
+
if (baselineBudgetMs <= 0 || this.isRunAborted()) {
|
|
2079
|
+
const skipReason = this.isRunAborted() ? "aborted" : remainingMs <= 0 ? "insufficient_timebox" : "first_iteration_reserved";
|
|
2080
|
+
this.qualityBaseline = {
|
|
2081
|
+
status: "skipped",
|
|
2082
|
+
reason: skipReason,
|
|
2083
|
+
capturedAt: /* @__PURE__ */ new Date()
|
|
2084
|
+
};
|
|
2085
|
+
this.telemetry?.logEvent({
|
|
2086
|
+
name: "quality_baseline_skipped",
|
|
2087
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2088
|
+
properties: {
|
|
2089
|
+
remainingMs,
|
|
2090
|
+
reserveMs,
|
|
2091
|
+
reason: skipReason
|
|
2092
|
+
}
|
|
2093
|
+
});
|
|
2094
|
+
} else {
|
|
2095
|
+
this.qualityBaseline = await captureQualityBaseline(this.workingDir, this.qualityGates, {
|
|
2096
|
+
mode: this.config.qualityGatesMode,
|
|
2097
|
+
timeoutMs: baselineBudgetMs,
|
|
2098
|
+
// Observation-only: emit the resolver shadow beside the baseline. Never
|
|
2099
|
+
// affects baseline status, completion, or promotion.
|
|
2100
|
+
onShadow: (shadow) => this.emitResolverShadowTelemetry(shadow, "baseline")
|
|
2101
|
+
});
|
|
2102
|
+
this.telemetry?.logEvent({
|
|
2103
|
+
name: "quality_baseline_captured",
|
|
2104
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2105
|
+
properties: {
|
|
2106
|
+
budgetMs: baselineBudgetMs,
|
|
2107
|
+
reserveMs,
|
|
2108
|
+
status: this.qualityBaseline.status,
|
|
2109
|
+
reason: this.qualityBaseline.status === "captured" ? void 0 : this.qualityBaseline.reason,
|
|
2110
|
+
testFailures: this.qualityBaseline.status === "captured" ? this.qualityBaseline.testFailures : void 0,
|
|
2111
|
+
testFailuresMethod: this.qualityBaseline.status === "captured" ? this.qualityBaseline.testFailuresMethod : void 0,
|
|
2112
|
+
lintErrors: this.qualityBaseline.status === "captured" ? this.qualityBaseline.lintErrors : void 0,
|
|
2113
|
+
lintErrorsMethod: this.qualityBaseline.status === "captured" ? this.qualityBaseline.lintErrorsMethod : void 0,
|
|
2114
|
+
typeErrors: this.qualityBaseline.status === "captured" ? this.qualityBaseline.typeErrors : void 0,
|
|
2115
|
+
typeErrorsMethod: this.qualityBaseline.status === "captured" ? this.qualityBaseline.typeErrorsMethod : void 0,
|
|
2116
|
+
securityFailures: this.qualityBaseline.status === "captured" ? this.qualityBaseline.securityFailures : void 0,
|
|
2117
|
+
securityFailuresMethod: this.qualityBaseline.status === "captured" ? this.qualityBaseline.securityFailuresMethod : void 0
|
|
2118
|
+
}
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
if (this.config.runQualityGates && this.config.customGateCommands && this.config.customGateCommands.length > 0) {
|
|
2123
|
+
const {
|
|
2124
|
+
budgetMs: customBaselineBudgetMs,
|
|
2125
|
+
reserveMs,
|
|
2126
|
+
remainingMs
|
|
2127
|
+
} = this.getPreIterationGateBudgetMs();
|
|
2128
|
+
if (customBaselineBudgetMs < MIN_CUSTOM_GATE_BASELINE_MS || remainingMs < MIN_CUSTOM_GATE_BASELINE_MS || this.isRunAborted()) {
|
|
2129
|
+
this.telemetry?.logEvent({
|
|
2130
|
+
name: "custom_gate_baseline_skipped",
|
|
2131
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2132
|
+
properties: {
|
|
2133
|
+
remainingMs,
|
|
2134
|
+
reserveMs,
|
|
2135
|
+
reason: this.isRunAborted() ? "aborted" : remainingMs < MIN_CUSTOM_GATE_BASELINE_MS ? "insufficient_timebox" : "first_iteration_reserved"
|
|
2136
|
+
}
|
|
2137
|
+
});
|
|
2138
|
+
} else {
|
|
2139
|
+
const baselineResults = await this.runCustomGates(
|
|
2140
|
+
createIterationCount(0),
|
|
2141
|
+
this.config.customGateCommands,
|
|
2142
|
+
customBaselineBudgetMs
|
|
2143
|
+
);
|
|
2144
|
+
this.customGateBaseline = new Map(
|
|
2145
|
+
baselineResults.map((result) => [result.id, result.passed])
|
|
2146
|
+
);
|
|
2147
|
+
this.telemetry?.logEvent({
|
|
2148
|
+
name: "custom_gate_baseline_captured",
|
|
2149
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2150
|
+
properties: {
|
|
2151
|
+
budgetMs: customBaselineBudgetMs,
|
|
2152
|
+
reserveMs,
|
|
2153
|
+
gateCount: baselineResults.length,
|
|
2154
|
+
failingAtStart: baselineResults.filter((result) => !result.passed).length
|
|
2155
|
+
}
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
if (this.config.semanticCheck?.enabled || this.config.validationMode === "heuristic" || (this.config.requirementsTaskText?.length ?? 0) > 0 || this.config.runQualityGates && (this.config.customGateCommands?.length ?? 0) > 0) {
|
|
2160
|
+
try {
|
|
2161
|
+
const { execa } = await import("execa");
|
|
2162
|
+
const { stdout } = await execa("git", ["rev-parse", "HEAD"], {
|
|
2163
|
+
cwd: this.workingDir,
|
|
2164
|
+
timeout: 5e3,
|
|
2165
|
+
maxBuffer: 1024 * 1024,
|
|
2166
|
+
stderr: "ignore"
|
|
2167
|
+
});
|
|
2168
|
+
const sha = stdout.trim();
|
|
2169
|
+
const resolvedSha = sha || null;
|
|
2170
|
+
this.loopStartRef = resolvedSha;
|
|
2171
|
+
if (this.config.semanticCheck?.enabled) {
|
|
2172
|
+
this.semanticBaselineRef = resolvedSha;
|
|
2173
|
+
}
|
|
2174
|
+
if (this.config.validationMode === "heuristic") {
|
|
2175
|
+
this.progressBaselineRef = resolvedSha;
|
|
2176
|
+
}
|
|
2177
|
+
if (sha) {
|
|
2178
|
+
this.telemetry?.logEvent({
|
|
2179
|
+
name: "semantic_baseline_captured",
|
|
2180
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2181
|
+
properties: { baseRef: sha }
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
} catch {
|
|
2185
|
+
this.loopStartRef = null;
|
|
2186
|
+
if (this.config.semanticCheck?.enabled) {
|
|
2187
|
+
this.semanticBaselineRef = null;
|
|
2188
|
+
}
|
|
2189
|
+
if (this.config.validationMode === "heuristic") {
|
|
2190
|
+
this.progressBaselineRef = null;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
/**
|
|
2196
|
+
* Replace stale progress-insight wording when a completion signal succeeds
|
|
2197
|
+
* because separate durable evidence proved completion.
|
|
2198
|
+
*/
|
|
2199
|
+
reconcileCompletionEvidenceInsights(result) {
|
|
2200
|
+
const summary = result.completionSummary;
|
|
2201
|
+
if (result.completionEvidence?.durable !== true || summary?.completionSignalDetected !== true || !completionStatusAllowsSuccess(summary.status) && summary.status !== "BASELINE_BLOCKED") {
|
|
2202
|
+
return;
|
|
2203
|
+
}
|
|
2204
|
+
const illusoryProgressPattern = /reported progress may be illusory/i;
|
|
2205
|
+
const staleCompletenessPattern = /^(Task appears nearly complete|Good progress, some work remaining|Halfway through task completion|Significant work still needed)$/i;
|
|
2206
|
+
const filteredInsights = [];
|
|
2207
|
+
let removedIllusoryProgress = false;
|
|
2208
|
+
let removedStaleCompleteness = false;
|
|
2209
|
+
for (const insight of result.progress.insights) {
|
|
2210
|
+
if (result.progress.toolingFailure === true && illusoryProgressPattern.test(insight)) {
|
|
2211
|
+
removedIllusoryProgress = true;
|
|
2212
|
+
continue;
|
|
2213
|
+
}
|
|
2214
|
+
if (staleCompletenessPattern.test(insight)) {
|
|
2215
|
+
removedStaleCompleteness = true;
|
|
2216
|
+
continue;
|
|
2217
|
+
}
|
|
2218
|
+
filteredInsights.push(insight);
|
|
2219
|
+
}
|
|
2220
|
+
if (!removedIllusoryProgress && !removedStaleCompleteness) {
|
|
2221
|
+
return;
|
|
2222
|
+
}
|
|
2223
|
+
result.progress.insights = [
|
|
2224
|
+
...filteredInsights,
|
|
2225
|
+
...removedStaleCompleteness ? ["Durable completion evidence satisfied the requested completion criteria."] : [],
|
|
2226
|
+
...removedIllusoryProgress ? [
|
|
2227
|
+
"Progress validation tooling failed; durable completion evidence satisfied the completion signal."
|
|
2228
|
+
] : []
|
|
2229
|
+
];
|
|
2230
|
+
}
|
|
2231
|
+
/**
|
|
2232
|
+
* Execute a single iteration
|
|
2233
|
+
*/
|
|
2234
|
+
async executeIteration(iteration, taskFunction) {
|
|
2235
|
+
const iterationStart = performance.now();
|
|
2236
|
+
this.emit("iteration_start", { type: "iteration_start", iteration });
|
|
2237
|
+
try {
|
|
2238
|
+
const lastIteration = this.iterationHistory.length > 0 ? this.iterationHistory[this.iterationHistory.length - 1] : void 0;
|
|
2239
|
+
const blockingCustomGate = lastIteration?.customGateResults?.find(
|
|
2240
|
+
isBlockingCustomGateForCompletion
|
|
2241
|
+
);
|
|
2242
|
+
const boundedCustomGateContext = blockingCustomGate ? `Custom gate '${blockingCustomGate.id}' failed${typeof blockingCustomGate.exitCode === "number" ? ` (exit code ${blockingCustomGate.exitCode})` : ""}${blockingCustomGate.outputTail ? `: ${blockingCustomGate.outputTail.slice(-1e3)}` : ""}` : void 0;
|
|
2243
|
+
const previousError = lastIteration && (!lastIteration.success || boundedCustomGateContext) ? {
|
|
2244
|
+
message: [lastIteration.error?.message, boundedCustomGateContext].filter((part) => Boolean(part)).join("\n"),
|
|
2245
|
+
iteration: lastIteration._iteration,
|
|
2246
|
+
// Convert branded type to plain number
|
|
2247
|
+
...lastIteration.error ? classifyError(lastIteration.error) : { category: "unknown" },
|
|
2248
|
+
...boundedCustomGateContext ? { hint: "Address the blocking custom-gate failure before retrying." } : {}
|
|
2249
|
+
} : void 0;
|
|
2250
|
+
const HISTORY_WINDOW = 10;
|
|
2251
|
+
const context = {
|
|
2252
|
+
_iteration: iteration,
|
|
2253
|
+
history: this.iterationHistory.length <= HISTORY_WINDOW ? [...this.iterationHistory] : this.iterationHistory.slice(-HISTORY_WINDOW),
|
|
2254
|
+
config: this.config,
|
|
2255
|
+
isFirstIteration: iteration === 1,
|
|
2256
|
+
isLastIteration: iteration === this.config.maxIterations,
|
|
2257
|
+
previousError,
|
|
2258
|
+
workingDir: this.workingDir,
|
|
2259
|
+
currentProvider: this.currentProvider,
|
|
2260
|
+
currentProviderSetup: this.currentProviderSetup,
|
|
2261
|
+
availableAlternates: [...this.availableAlternates]
|
|
2262
|
+
};
|
|
2263
|
+
const remainingTimeboxMs = this.config.timeboxMs - this.getElapsedRuntimeMs();
|
|
2264
|
+
if (remainingTimeboxMs <= 0) {
|
|
2265
|
+
this.terminate("timebox_exceeded");
|
|
2266
|
+
throw new Error("Autoloop timebox exceeded before iteration started");
|
|
2267
|
+
}
|
|
2268
|
+
let timeoutId;
|
|
2269
|
+
const timeboxRace = new Promise((_, reject) => {
|
|
2270
|
+
timeoutId = setTimeout(() => {
|
|
2271
|
+
reject(new Error("Autoloop iteration exceeded remaining timebox"));
|
|
2272
|
+
}, remainingTimeboxMs);
|
|
2273
|
+
});
|
|
2274
|
+
const abortSignal = this.config.abortSignal;
|
|
2275
|
+
let abortListener;
|
|
2276
|
+
const recursionStateFile = this.recursionTracker.getStateFilePath?.();
|
|
2277
|
+
const taskPromise = recursionStateFile ? withExecutionContextEnvOverrides(
|
|
2278
|
+
{ POETIC_RECURSION_STATE_FILE: recursionStateFile },
|
|
2279
|
+
() => taskFunction(iteration, context)
|
|
2280
|
+
) : taskFunction(iteration, context);
|
|
2281
|
+
const raceArms = [taskPromise, timeboxRace];
|
|
2282
|
+
if (abortSignal) {
|
|
2283
|
+
const abortRace = new Promise((_, reject) => {
|
|
2284
|
+
if (abortSignal.aborted) {
|
|
2285
|
+
reject(new Error("Autoloop iteration aborted"));
|
|
2286
|
+
return;
|
|
2287
|
+
}
|
|
2288
|
+
abortListener = () => {
|
|
2289
|
+
reject(new Error("Autoloop iteration aborted"));
|
|
2290
|
+
};
|
|
2291
|
+
abortSignal.addEventListener("abort", abortListener, { once: true });
|
|
2292
|
+
});
|
|
2293
|
+
raceArms.push(abortRace);
|
|
2294
|
+
}
|
|
2295
|
+
let taskResult;
|
|
2296
|
+
try {
|
|
2297
|
+
taskResult = await Promise.race(raceArms);
|
|
2298
|
+
} catch (error) {
|
|
2299
|
+
if (error instanceof Error && error.message.includes("remaining timebox")) {
|
|
2300
|
+
this.terminate("timebox_exceeded");
|
|
2301
|
+
}
|
|
2302
|
+
throw error;
|
|
2303
|
+
} finally {
|
|
2304
|
+
if (timeoutId) {
|
|
2305
|
+
clearTimeout(timeoutId);
|
|
2306
|
+
}
|
|
2307
|
+
if (abortSignal && abortListener) {
|
|
2308
|
+
abortSignal.removeEventListener("abort", abortListener);
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
const repairOutcome = taskResult && typeof taskResult === "object" && "repairOutcome" in taskResult && isRepairOutcome(taskResult.repairOutcome) ? taskResult.repairOutcome : void 0;
|
|
2312
|
+
const completionEvidence = taskResult && typeof taskResult === "object" && "completionEvidence" in taskResult && isCompletionEvidence(taskResult.completionEvidence) ? taskResult.completionEvidence : void 0;
|
|
2313
|
+
const iterationFingerprint = taskResult && typeof taskResult === "object" && "iterationFingerprint" in taskResult && typeof taskResult.iterationFingerprint === "string" ? taskResult.iterationFingerprint : void 0;
|
|
2314
|
+
const callbackCustomGateResults = taskResult && typeof taskResult === "object" && "customGateResults" in taskResult && isCustomGateResultsArray(taskResult.customGateResults) ? taskResult.customGateResults.map(
|
|
2315
|
+
(gate) => ({
|
|
2316
|
+
...gate,
|
|
2317
|
+
durationMs: createDurationMs(gate.durationMs)
|
|
2318
|
+
})
|
|
2319
|
+
) : void 0;
|
|
2320
|
+
const outputForChecks = selectTaskOutputForChecks(taskResult);
|
|
2321
|
+
this.completionSignalMatched = false;
|
|
2322
|
+
if (this.config.completionSignal) {
|
|
2323
|
+
this.completionSignalMatched = matchesCompletionSignal(
|
|
2324
|
+
outputForChecks,
|
|
2325
|
+
this.config.completionSignal
|
|
2326
|
+
);
|
|
2327
|
+
if (this.completionSignalMatched) {
|
|
2328
|
+
this.telemetry?.logEvent({
|
|
2329
|
+
name: "completion_signal_matched",
|
|
2330
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2331
|
+
properties: {
|
|
2332
|
+
iteration,
|
|
2333
|
+
signalType: this.config.completionSignal.type,
|
|
2334
|
+
usedProviderOutputText: outputForChecks !== taskResult
|
|
2335
|
+
}
|
|
2336
|
+
});
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
const progress = await this.validateProgress(iteration, taskResult);
|
|
2340
|
+
const metadata = {};
|
|
2341
|
+
if (this.compilationBaselineErrors !== null) {
|
|
2342
|
+
const currentTypeErrors = await countTypeScriptErrors(this.workingDir);
|
|
2343
|
+
if (currentTypeErrors !== null && currentTypeErrors > this.compilationBaselineErrors) {
|
|
2344
|
+
metadata.compilationErrorDelta = currentTypeErrors - this.compilationBaselineErrors;
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
const qualityGateBudgetMs = this.config.runQualityGates ? this.ensureRemainingTimeboxMs("quality gates") : void 0;
|
|
2348
|
+
const qualityGates = this.config.runQualityGates && qualityGateBudgetMs !== void 0 ? await this.runQualityGates(iteration, qualityGateBudgetMs) : void 0;
|
|
2349
|
+
const customGateBudgetMs = this.config.runQualityGates && this.config.customGateCommands && this.config.customGateCommands.length > 0 ? this.ensureRemainingTimeboxMs("custom quality gates") : void 0;
|
|
2350
|
+
const customGateResults = customGateBudgetMs !== void 0 && this.config.customGateCommands ? await this.runCustomGates(iteration, this.config.customGateCommands, customGateBudgetMs) : callbackCustomGateResults;
|
|
2351
|
+
const testGateResults = [
|
|
2352
|
+
...(qualityGates ?? []).filter((gate) => gate.gateId === "coverage").map((gate) => ({
|
|
2353
|
+
passed: gate.passed,
|
|
2354
|
+
executed: gate.skipped !== true && gate.unavailable !== true
|
|
2355
|
+
})),
|
|
2356
|
+
...(customGateResults ?? []).filter((gate) => describeVerificationCommand(gate.command).kind === "test").map((gate) => ({
|
|
2357
|
+
passed: gate.passed,
|
|
2358
|
+
executed: gate.skipped !== true && gate.unavailable !== true
|
|
2359
|
+
}))
|
|
2360
|
+
];
|
|
2361
|
+
const executedTestGates = testGateResults.filter((gate) => gate.executed);
|
|
2362
|
+
const testVerification = {
|
|
2363
|
+
status: executedTestGates.some((gate) => !gate.passed) ? "failed" : executedTestGates.length > 0 && testGateResults.every((gate) => gate.executed && gate.passed) ? "passed" : "unavailable",
|
|
2364
|
+
checksRun: executedTestGates.length
|
|
2365
|
+
};
|
|
2366
|
+
const changedFiles = await this.getChangedFilesSinceLoopStart();
|
|
2367
|
+
const requirements = validateRequirements({
|
|
2368
|
+
requirementsTaskText: this.config.requirementsTaskText,
|
|
2369
|
+
providerOutputText: outputForChecks,
|
|
2370
|
+
workingDir: this.workingDir,
|
|
2371
|
+
config: this.config.requirements,
|
|
2372
|
+
changedFiles: changedFiles ?? void 0,
|
|
2373
|
+
testVerification
|
|
2374
|
+
});
|
|
2375
|
+
const judgeEvaluation = this.config.useAIJudge ? await this.getAIJudgeEvaluation(iteration, taskResult, progress) : void 0;
|
|
2376
|
+
const isCompletionOrBounds = this.completionSignalMatched || iteration >= this.config.maxIterations;
|
|
2377
|
+
const semanticValidation = this.config.semanticCheck?.enabled ? await this.runSemanticValidation(iteration, outputForChecks, isCompletionOrBounds) : void 0;
|
|
2378
|
+
const duration = createDurationMs(performance.now() - iterationStart);
|
|
2379
|
+
const memoryUsage = process.memoryUsage();
|
|
2380
|
+
const result = {
|
|
2381
|
+
_iteration: iteration,
|
|
2382
|
+
progress,
|
|
2383
|
+
requirements,
|
|
2384
|
+
duration,
|
|
2385
|
+
memoryUsage,
|
|
2386
|
+
success: true,
|
|
2387
|
+
iterationFingerprint,
|
|
2388
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
|
|
2389
|
+
qualityGates,
|
|
2390
|
+
customGateResults,
|
|
2391
|
+
repairOutcome,
|
|
2392
|
+
judgeEvaluation,
|
|
2393
|
+
semanticValidation,
|
|
2394
|
+
completionEvidence,
|
|
2395
|
+
usedProvider: this.currentProvider ?? this.config.routingDecision?.primary.provider
|
|
2396
|
+
};
|
|
2397
|
+
result.completionSummary = this.computeCompletionSummary(
|
|
2398
|
+
result,
|
|
2399
|
+
this.completionSignalMatched,
|
|
2400
|
+
isCompletionOrBounds
|
|
2401
|
+
);
|
|
2402
|
+
this.reconcileCompletionEvidenceInsights(result);
|
|
2403
|
+
this.emit("iteration_complete", { type: "iteration_complete", result });
|
|
2404
|
+
return result;
|
|
2405
|
+
} catch (error) {
|
|
2406
|
+
const duration = createDurationMs(performance.now() - iterationStart);
|
|
2407
|
+
const memoryUsage = process.memoryUsage();
|
|
2408
|
+
const failureEnvelope = getCarriedDirectAutoloopFailureEnvelope(error) ?? classifyFailureEnvelope(error, {
|
|
2409
|
+
executionPhase: "post-run",
|
|
2410
|
+
mutationState: "unknown"
|
|
2411
|
+
});
|
|
2412
|
+
const failureRecovery = serializeDirectAutoloopFailureRecovery(
|
|
2413
|
+
failureEnvelope,
|
|
2414
|
+
deriveDirectAutoloopRecovery(failureEnvelope)
|
|
2415
|
+
);
|
|
2416
|
+
const result = {
|
|
2417
|
+
_iteration: iteration,
|
|
2418
|
+
progress: {
|
|
2419
|
+
score: createProgressScore(0),
|
|
2420
|
+
isSignificant: false,
|
|
2421
|
+
trend: "unknown",
|
|
2422
|
+
confidence: 0,
|
|
2423
|
+
metrics: {
|
|
2424
|
+
codeQuality: 0,
|
|
2425
|
+
testCoverage: 0,
|
|
2426
|
+
performance: 0,
|
|
2427
|
+
completeness: 0,
|
|
2428
|
+
maintainability: 0
|
|
2429
|
+
},
|
|
2430
|
+
insights: [`Iteration failed: ${error.message}`]
|
|
2431
|
+
},
|
|
2432
|
+
completionSummary: {
|
|
2433
|
+
status: "NOT_COMPLETE",
|
|
2434
|
+
gatesOk: false,
|
|
2435
|
+
providerOk: false,
|
|
2436
|
+
convergedOk: false,
|
|
2437
|
+
completionSignalDetected: false,
|
|
2438
|
+
hasSubstantiveEvidence: false,
|
|
2439
|
+
blockingIssues: [`Iteration failed: ${error.message}`],
|
|
2440
|
+
hasBaselineFailures: false,
|
|
2441
|
+
unsafeCompletion: false,
|
|
2442
|
+
// Diagnostic-only: the iteration crashed BEFORE any verification gate
|
|
2443
|
+
// ran, so verification never executed. Per competition semantics
|
|
2444
|
+
// (judge-types-core.ts: skipped/unavailable/no-evidence -> 'not_run'),
|
|
2445
|
+
// a crash with no gate evidence is 'not_run', NOT 'failed' — gatesOk is
|
|
2446
|
+
// false for fail-closed decision reasons, but verification did not fail.
|
|
2447
|
+
verificationDisposition: "not_run"
|
|
2448
|
+
},
|
|
2449
|
+
duration,
|
|
2450
|
+
memoryUsage,
|
|
2451
|
+
success: false,
|
|
2452
|
+
error,
|
|
2453
|
+
failureRecovery,
|
|
2454
|
+
usedProvider: this.currentProvider ?? this.config.routingDecision?.primary.provider
|
|
2455
|
+
};
|
|
2456
|
+
this.emit("iteration_complete", { type: "iteration_complete", result });
|
|
2457
|
+
this.telemetry?.trackError(error, { iteration, duration });
|
|
2458
|
+
return result;
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
/**
|
|
2462
|
+
* Validate progress using heuristic analysis (git diff + file metrics).
|
|
2463
|
+
*
|
|
2464
|
+
* Uses the ProgressValidator to:
|
|
2465
|
+
* - Analyze git diffs to measure meaningful code changes
|
|
2466
|
+
* - Detect test coverage changes
|
|
2467
|
+
* - Evaluate task completeness
|
|
2468
|
+
* - Determine progress trends
|
|
2469
|
+
*
|
|
2470
|
+
* Behavior depends on `validationMode`:
|
|
2471
|
+
* - `heuristic`: Full ProgressValidator analysis
|
|
2472
|
+
* - `none` or `deterministic`: Returns minimal validation (skips heuristics)
|
|
2473
|
+
*
|
|
2474
|
+
* @param iteration - Current iteration number
|
|
2475
|
+
* @param taskResult - Result from task execution
|
|
2476
|
+
* @returns ProgressValidation with scores and metrics
|
|
2477
|
+
*/
|
|
2478
|
+
async validateProgress(iteration, taskResult) {
|
|
2479
|
+
if (this.config.validationMode !== "heuristic") {
|
|
2480
|
+
const skipValidation = {
|
|
2481
|
+
score: createProgressScore(0.5),
|
|
2482
|
+
// Neutral score
|
|
2483
|
+
isSignificant: true,
|
|
2484
|
+
// Don't trigger stagnation in 'none' mode
|
|
2485
|
+
trend: "unknown",
|
|
2486
|
+
confidence: 0,
|
|
2487
|
+
metrics: {
|
|
2488
|
+
codeQuality: 0,
|
|
2489
|
+
testCoverage: 0,
|
|
2490
|
+
performance: 0,
|
|
2491
|
+
completeness: 0,
|
|
2492
|
+
maintainability: 0
|
|
2493
|
+
},
|
|
2494
|
+
insights: [
|
|
2495
|
+
`Iteration ${iteration}: Heuristic validation skipped (mode: ${this.config.validationMode})`
|
|
2496
|
+
]
|
|
2497
|
+
};
|
|
2498
|
+
this.emit("progress_validated", {
|
|
2499
|
+
type: "progress_validated",
|
|
2500
|
+
validation: skipValidation
|
|
2501
|
+
});
|
|
2502
|
+
this.telemetry?.logEvent({
|
|
2503
|
+
name: "progress_validated",
|
|
2504
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2505
|
+
properties: {
|
|
2506
|
+
iteration,
|
|
2507
|
+
score: skipValidation.score,
|
|
2508
|
+
trend: skipValidation.trend,
|
|
2509
|
+
validationMode: this.config.validationMode,
|
|
2510
|
+
skipped: true
|
|
2511
|
+
}
|
|
2512
|
+
});
|
|
2513
|
+
return skipValidation;
|
|
2514
|
+
}
|
|
2515
|
+
try {
|
|
2516
|
+
const context = {
|
|
2517
|
+
iteration,
|
|
2518
|
+
taskResult,
|
|
2519
|
+
workingDir: this.workingDir,
|
|
2520
|
+
previousIterations: this.iterationHistory.map((r) => ({
|
|
2521
|
+
progress: r.progress,
|
|
2522
|
+
duration: r.duration
|
|
2523
|
+
})),
|
|
2524
|
+
compilationBaselineErrors: this.compilationBaselineErrors,
|
|
2525
|
+
baseRef: this.progressBaselineRef ?? (typeof this.config.progressConfig.baseRef === "string" ? this.config.progressConfig.baseRef : "HEAD")
|
|
2526
|
+
// Compare working tree to baseline commit by default
|
|
2527
|
+
};
|
|
2528
|
+
const validation = await this.progressValidator.validateProgress(context);
|
|
2529
|
+
this.emit("progress_validated", {
|
|
2530
|
+
type: "progress_validated",
|
|
2531
|
+
validation
|
|
2532
|
+
});
|
|
2533
|
+
this.telemetry?.logEvent({
|
|
2534
|
+
name: "progress_validated",
|
|
2535
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2536
|
+
properties: {
|
|
2537
|
+
iteration,
|
|
2538
|
+
score: validation.score,
|
|
2539
|
+
trend: validation.trend,
|
|
2540
|
+
confidence: validation.confidence,
|
|
2541
|
+
metrics: validation.metrics,
|
|
2542
|
+
validationMode: this.config.validationMode
|
|
2543
|
+
}
|
|
2544
|
+
});
|
|
2545
|
+
return validation;
|
|
2546
|
+
} catch (error) {
|
|
2547
|
+
console.warn(
|
|
2548
|
+
`[AutonomousLoopController] Heuristic validation failed: ${error instanceof Error ? error.message : String(error)}`
|
|
2549
|
+
);
|
|
2550
|
+
this.telemetry?.trackError(error, {
|
|
2551
|
+
iteration,
|
|
2552
|
+
context: "progress_validation"
|
|
2553
|
+
});
|
|
2554
|
+
const fallbackScore = createProgressScore(
|
|
2555
|
+
Math.min(0.3, iteration / this.config.maxIterations)
|
|
2556
|
+
);
|
|
2557
|
+
return {
|
|
2558
|
+
score: fallbackScore,
|
|
2559
|
+
isSignificant: false,
|
|
2560
|
+
trend: "unknown",
|
|
2561
|
+
confidence: 0.2,
|
|
2562
|
+
metrics: {
|
|
2563
|
+
codeQuality: 0.5,
|
|
2564
|
+
testCoverage: 0.3,
|
|
2565
|
+
performance: 0.5,
|
|
2566
|
+
completeness: 0.3,
|
|
2567
|
+
maintainability: 0.5
|
|
2568
|
+
},
|
|
2569
|
+
insights: [
|
|
2570
|
+
`Iteration ${iteration}: Heuristic validation failed, using fallback`,
|
|
2571
|
+
"Unable to analyze progress - recommend manual review"
|
|
2572
|
+
],
|
|
2573
|
+
toolingFailure: true,
|
|
2574
|
+
verificationUnavailable: true,
|
|
2575
|
+
verificationUnavailableReason: error instanceof Error ? error.message : "Heuristic validation failed before producing a result."
|
|
2576
|
+
};
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
/**
|
|
2580
|
+
* Emit the observation-only resolver shadow comparison as telemetry.
|
|
2581
|
+
*
|
|
2582
|
+
* STRICTLY ADDITIVE: this never touches gate results, success, completion, or
|
|
2583
|
+
* promotion. The shadow carries an explicit `applied: false` marker; this method
|
|
2584
|
+
* only flattens it into telemetry properties.
|
|
2585
|
+
*
|
|
2586
|
+
* @param shadow - The resolver shadow comparison from the gate summary, if any.
|
|
2587
|
+
* @param phase - Which gate run produced the shadow (`baseline` or `per_iteration`).
|
|
2588
|
+
*/
|
|
2589
|
+
emitResolverShadowTelemetry(shadow, phase) {
|
|
2590
|
+
if (!shadow) return;
|
|
2591
|
+
try {
|
|
2592
|
+
this.telemetry?.logEvent({
|
|
2593
|
+
name: "quality_gate_resolver_shadow",
|
|
2594
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2595
|
+
properties: {
|
|
2596
|
+
phase,
|
|
2597
|
+
applied: shadow.applied,
|
|
2598
|
+
languages: shadow.languages.join(","),
|
|
2599
|
+
resolverWouldVerify: shadow.resolverWouldVerify,
|
|
2600
|
+
coverageDivergence: shadow.gates.coverage.divergence,
|
|
2601
|
+
lintDivergence: shadow.gates.lint.divergence,
|
|
2602
|
+
securityDivergence: shadow.gates.security.divergence,
|
|
2603
|
+
summary: shadow.summary
|
|
2604
|
+
},
|
|
2605
|
+
measurements: {
|
|
2606
|
+
coverageResolverCommandCount: shadow.gates.coverage.resolverEquivalent.length,
|
|
2607
|
+
lintResolverCommandCount: shadow.gates.lint.resolverEquivalent.length,
|
|
2608
|
+
securityResolverCommandCount: shadow.gates.security.resolverEquivalent.length
|
|
2609
|
+
}
|
|
2610
|
+
});
|
|
2611
|
+
} catch {
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
/**
|
|
2615
|
+
* Run quality gates if enabled
|
|
2616
|
+
*/
|
|
2617
|
+
async runQualityGates(_iteration, timeoutMs) {
|
|
2618
|
+
if (!this.qualityGates) return [];
|
|
2619
|
+
try {
|
|
2620
|
+
const gateFlags = resolveQualityGateExecutionFlags(this.config.qualityGatesMode);
|
|
2621
|
+
const summary = await this.qualityGates.run({
|
|
2622
|
+
...gateFlags,
|
|
2623
|
+
securityNotModeled: this.config.qualityGatesMode === "safe" ? "not-applicable" : "unavailable",
|
|
2624
|
+
cwd: this.workingDir,
|
|
2625
|
+
...typeof timeoutMs === "number" && timeoutMs > 0 ? { timeoutMs } : {}
|
|
2626
|
+
});
|
|
2627
|
+
const mappedResults = summary.results.map((result) => {
|
|
2628
|
+
const duration = createDurationMs(result.durationMs);
|
|
2629
|
+
const isRegression = result.skipped === true ? void 0 : this.isQualityRegression(result);
|
|
2630
|
+
let effectiveSuccess = result.success;
|
|
2631
|
+
if (result.gate === "coverage" && !result.skipped && result.success && isRegression === true) {
|
|
2632
|
+
effectiveSuccess = false;
|
|
2633
|
+
}
|
|
2634
|
+
const score = result.skipped ? 0 : effectiveSuccess ? 1 : 0;
|
|
2635
|
+
if (effectiveSuccess && !result.skipped) {
|
|
2636
|
+
this.emit("quality_gate_passed", {
|
|
2637
|
+
type: "quality_gate_passed",
|
|
2638
|
+
gateId: result.gate,
|
|
2639
|
+
score
|
|
2640
|
+
});
|
|
2641
|
+
} else if (!result.skipped) {
|
|
2642
|
+
this.emit("quality_gate_failed", {
|
|
2643
|
+
type: "quality_gate_failed",
|
|
2644
|
+
gateId: result.gate,
|
|
2645
|
+
score,
|
|
2646
|
+
reason: result.message
|
|
2647
|
+
});
|
|
2648
|
+
}
|
|
2649
|
+
const buildOutputTail = () => {
|
|
2650
|
+
if (effectiveSuccess) return void 0;
|
|
2651
|
+
const combined = result.stdout + (result.stderr ? `
|
|
2652
|
+
=== stderr ===
|
|
2653
|
+
${result.stderr}` : "");
|
|
2654
|
+
if (combined.length === 0) return void 0;
|
|
2655
|
+
return combined.length > 500 ? `...${combined.slice(-500)}` : combined;
|
|
2656
|
+
};
|
|
2657
|
+
return {
|
|
2658
|
+
gateId: result.gate,
|
|
2659
|
+
passed: result.skipped === true ? false : effectiveSuccess,
|
|
2660
|
+
score,
|
|
2661
|
+
details: result.message,
|
|
2662
|
+
duration,
|
|
2663
|
+
outputTail: buildOutputTail(),
|
|
2664
|
+
isRegression,
|
|
2665
|
+
...result.skipped === true ? { skipped: true } : {},
|
|
2666
|
+
...result.unavailable === true ? { unavailable: true } : {},
|
|
2667
|
+
...result.notApplicable === true ? { notApplicable: true } : {}
|
|
2668
|
+
};
|
|
2669
|
+
});
|
|
2670
|
+
this.emitResolverShadowTelemetry(summary.shadow, "per_iteration");
|
|
2671
|
+
return mappedResults;
|
|
2672
|
+
} catch (error) {
|
|
2673
|
+
this.telemetry?.trackError(error, {
|
|
2674
|
+
_iteration,
|
|
2675
|
+
context: "quality_gates"
|
|
2676
|
+
});
|
|
2677
|
+
return [
|
|
2678
|
+
{
|
|
2679
|
+
gateId: "gate-runner-error",
|
|
2680
|
+
passed: false,
|
|
2681
|
+
score: 0,
|
|
2682
|
+
isRegression: true,
|
|
2683
|
+
details: error instanceof Error ? error.message : String(error),
|
|
2684
|
+
duration: createDurationMs(0)
|
|
2685
|
+
}
|
|
2686
|
+
];
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
/**
|
|
2690
|
+
* Run custom gate commands resolved from a Phase A evidence plan.
|
|
2691
|
+
*
|
|
2692
|
+
* Strictly isolated from QualityGateRunner: never widens QualityGateId,
|
|
2693
|
+
* never participates in baseline capture, never feeds isQualityRegression.
|
|
2694
|
+
* Returns results in `customGateResults`, a sibling of `qualityGates`.
|
|
2695
|
+
*/
|
|
2696
|
+
/**
|
|
2697
|
+
* Files changed since loop start: committed/staged/unstaged tracked changes
|
|
2698
|
+
* against the loop-start SHA plus untracked files. Returns null (no scaling)
|
|
2699
|
+
* when the loop-start ref is unknown or git fails, so gate selection falls
|
|
2700
|
+
* back to the configured command list.
|
|
2701
|
+
*/
|
|
2702
|
+
async getChangedFilesSinceLoopStart() {
|
|
2703
|
+
if (!this.loopStartRef || !/^[0-9a-f]{4,40}$/i.test(this.loopStartRef)) return null;
|
|
2704
|
+
try {
|
|
2705
|
+
const { execa } = await import("execa");
|
|
2706
|
+
const execOptions = {
|
|
2707
|
+
cwd: this.workingDir,
|
|
2708
|
+
timeout: 5e3,
|
|
2709
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
2710
|
+
stderr: "ignore"
|
|
2711
|
+
};
|
|
2712
|
+
const [{ stdout: tracked }, { stdout: untracked }] = await Promise.all([
|
|
2713
|
+
execa("git", ["diff", "--name-only", this.loopStartRef], execOptions),
|
|
2714
|
+
execa("git", ["ls-files", "--others", "--exclude-standard"], execOptions)
|
|
2715
|
+
]);
|
|
2716
|
+
const files = new Set(
|
|
2717
|
+
`${tracked}
|
|
2718
|
+
${untracked}`.split("\n").map((line) => line.trim()).filter((line) => line.length > 0)
|
|
2719
|
+
);
|
|
2720
|
+
return Array.from(files);
|
|
2721
|
+
} catch {
|
|
2722
|
+
return null;
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
async runCustomGates(iteration, commands, timeoutBudgetMs) {
|
|
2726
|
+
if (commands.length === 0) return [];
|
|
2727
|
+
const { checkVerifyCommandSafety, runVerifyCommands } = await import("./verify-commands-H3DTCSGI.js");
|
|
2728
|
+
const { detectVerificationToolUnavailable } = await import("./verification-toolchains-V24UHW6Q.js");
|
|
2729
|
+
const { canLaunchBroadAutoloopEvidenceGate, selectCustomGateCommands } = await import("./autoloop-evidence-gates-PCDALGVJ.js");
|
|
2730
|
+
if (iteration >= 1) {
|
|
2731
|
+
const changedFiles = await this.getChangedFilesSinceLoopStart();
|
|
2732
|
+
if (changedFiles !== null && changedFiles.length > 0) {
|
|
2733
|
+
const { isNonCodeArtifactDiffPath } = await import("./simple-artifact-goal-OTXNGZY6.js");
|
|
2734
|
+
if (this.config.customGateCommandsSource !== "prompt" && changedFiles.every((file) => isNonCodeArtifactDiffPath(file))) {
|
|
2735
|
+
const selection = selectCustomGateCommands(commands, {
|
|
2736
|
+
timeboxMs: this.config.timeboxMs,
|
|
2737
|
+
artifactOnlyChangeSurface: true
|
|
2738
|
+
});
|
|
2739
|
+
if (selection.filtered) {
|
|
2740
|
+
commands = selection.selectedCommands;
|
|
2741
|
+
this.telemetry?.logEvent({
|
|
2742
|
+
name: "custom_gates_scaled_for_change_surface",
|
|
2743
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2744
|
+
properties: {
|
|
2745
|
+
iteration,
|
|
2746
|
+
reason: selection.reason ?? null,
|
|
2747
|
+
changedFileCount: changedFiles.length,
|
|
2748
|
+
keptCommands: selection.selectedCommands.join(", "),
|
|
2749
|
+
droppedCommands: selection.droppedCommands.join(", ")
|
|
2750
|
+
}
|
|
2751
|
+
});
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
const results = [];
|
|
2757
|
+
for (const command of commands) {
|
|
2758
|
+
const start = performance.now();
|
|
2759
|
+
const gateId = buildCustomGateId(command);
|
|
2760
|
+
if (this.isRunAborted()) {
|
|
2761
|
+
results.push({
|
|
2762
|
+
id: gateId,
|
|
2763
|
+
command,
|
|
2764
|
+
passed: false,
|
|
2765
|
+
skipped: true,
|
|
2766
|
+
durationMs: createDurationMs(0),
|
|
2767
|
+
outputTail: "Custom gate skipped: autoloop run aborted."
|
|
2768
|
+
});
|
|
2769
|
+
continue;
|
|
2770
|
+
}
|
|
2771
|
+
const remainingWallMs = this.getRemainingTimeboxMs();
|
|
2772
|
+
const phaseBudgetMs = typeof timeoutBudgetMs === "number" && Number.isFinite(timeoutBudgetMs) ? Math.max(0, Math.floor(timeoutBudgetMs)) : void 0;
|
|
2773
|
+
const effectiveRemainingMs = phaseBudgetMs !== void 0 ? Math.min(remainingWallMs, phaseBudgetMs) : remainingWallMs;
|
|
2774
|
+
if (effectiveRemainingMs < MIN_CUSTOM_GATE_RUN_MS) {
|
|
2775
|
+
results.push({
|
|
2776
|
+
id: gateId,
|
|
2777
|
+
command,
|
|
2778
|
+
passed: false,
|
|
2779
|
+
skipped: true,
|
|
2780
|
+
durationMs: createDurationMs(0),
|
|
2781
|
+
outputTail: "Custom gate skipped: autoloop timebox exhausted."
|
|
2782
|
+
});
|
|
2783
|
+
if (remainingWallMs <= 0) {
|
|
2784
|
+
break;
|
|
2785
|
+
}
|
|
2786
|
+
continue;
|
|
2787
|
+
}
|
|
2788
|
+
if (!canLaunchBroadAutoloopEvidenceGate(command, effectiveRemainingMs, this.config.timeboxMs)) {
|
|
2789
|
+
results.push({
|
|
2790
|
+
id: gateId,
|
|
2791
|
+
command,
|
|
2792
|
+
passed: false,
|
|
2793
|
+
skipped: true,
|
|
2794
|
+
durationMs: createDurationMs(0),
|
|
2795
|
+
outputTail: "Custom gate skipped: broad evidence verifier blocked for remaining autoloop timebox."
|
|
2796
|
+
});
|
|
2797
|
+
continue;
|
|
2798
|
+
}
|
|
2799
|
+
const commandTimeoutMs = Math.max(1, Math.min(effectiveRemainingMs, 5 * 60 * 1e3));
|
|
2800
|
+
try {
|
|
2801
|
+
const safety = checkVerifyCommandSafety(command);
|
|
2802
|
+
let passed = false;
|
|
2803
|
+
let exitCode;
|
|
2804
|
+
let boundedOutputTail;
|
|
2805
|
+
let durationMs = createDurationMs(0);
|
|
2806
|
+
if (safety.safe) {
|
|
2807
|
+
const verifyOutcome = await runVerifyCommands({
|
|
2808
|
+
cwd: this.workingDir,
|
|
2809
|
+
commands: [command],
|
|
2810
|
+
timeoutMs: commandTimeoutMs,
|
|
2811
|
+
commandProvenance: "workflow-config"
|
|
2812
|
+
});
|
|
2813
|
+
const verifyResult = verifyOutcome.results[0];
|
|
2814
|
+
durationMs = createDurationMs(verifyResult?.durationMs ?? performance.now() - start);
|
|
2815
|
+
const diagnosticOutputTail = [
|
|
2816
|
+
verifyResult?.outputTail,
|
|
2817
|
+
verifyResult?.stderrTail,
|
|
2818
|
+
verifyResult?.stdoutTail
|
|
2819
|
+
].filter((value) => Boolean(value?.trim())).join("\n");
|
|
2820
|
+
const outputTail = [verifyResult?.outputTail, verifyResult?.stderrTail, verifyResult?.stdoutTail].find(
|
|
2821
|
+
(value) => value?.trim() && value.trim() !== "(no output)"
|
|
2822
|
+
) ?? verifyResult?.outputTail;
|
|
2823
|
+
boundedOutputTail = outputTail && outputTail.length > 500 ? `...${outputTail.slice(-500)}` : outputTail;
|
|
2824
|
+
passed = verifyOutcome.passed && (verifyResult?.exitCode ?? 1) === 0;
|
|
2825
|
+
exitCode = verifyResult?.exitCode;
|
|
2826
|
+
const unavailableSignal = !passed && diagnosticOutputTail ? detectVerificationToolUnavailable(command, diagnosticOutputTail) : void 0;
|
|
2827
|
+
if (unavailableSignal) {
|
|
2828
|
+
results.push({
|
|
2829
|
+
id: gateId,
|
|
2830
|
+
command,
|
|
2831
|
+
passed: false,
|
|
2832
|
+
skipped: true,
|
|
2833
|
+
unavailable: true,
|
|
2834
|
+
durationMs,
|
|
2835
|
+
exitCode,
|
|
2836
|
+
outputTail: unavailableSignal.message,
|
|
2837
|
+
...this.customGateBaseline !== void 0 ? {
|
|
2838
|
+
isRegression: false
|
|
2839
|
+
} : {}
|
|
2840
|
+
});
|
|
2841
|
+
continue;
|
|
2842
|
+
}
|
|
2843
|
+
} else {
|
|
2844
|
+
durationMs = createDurationMs(performance.now() - start);
|
|
2845
|
+
results.push({
|
|
2846
|
+
id: gateId,
|
|
2847
|
+
command,
|
|
2848
|
+
passed: false,
|
|
2849
|
+
misconfigured: true,
|
|
2850
|
+
durationMs,
|
|
2851
|
+
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)}`
|
|
2852
|
+
});
|
|
2853
|
+
continue;
|
|
2854
|
+
}
|
|
2855
|
+
results.push({
|
|
2856
|
+
id: gateId,
|
|
2857
|
+
command,
|
|
2858
|
+
passed,
|
|
2859
|
+
durationMs,
|
|
2860
|
+
exitCode,
|
|
2861
|
+
outputTail: passed ? void 0 : boundedOutputTail,
|
|
2862
|
+
...this.customGateBaseline !== void 0 ? {
|
|
2863
|
+
isRegression: this.isCustomGateRegression(gateId, passed)
|
|
2864
|
+
} : {}
|
|
2865
|
+
});
|
|
2866
|
+
if (!passed && this.isRunAborted()) {
|
|
2867
|
+
break;
|
|
2868
|
+
}
|
|
2869
|
+
} catch (err) {
|
|
2870
|
+
const durationMs = createDurationMs(performance.now() - start);
|
|
2871
|
+
const aborted = this.isRunAborted() || err instanceof Error && (err.name === "AbortError" || /aborted|timebox exceeded/i.test(err.message));
|
|
2872
|
+
results.push({
|
|
2873
|
+
id: gateId,
|
|
2874
|
+
command,
|
|
2875
|
+
passed: false,
|
|
2876
|
+
durationMs,
|
|
2877
|
+
outputTail: aborted ? "Custom gate aborted: autoloop timebox exceeded." : err instanceof Error ? err.message.slice(-500) : String(err).slice(-500)
|
|
2878
|
+
});
|
|
2879
|
+
if (aborted) {
|
|
2880
|
+
break;
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
return results;
|
|
2885
|
+
}
|
|
2886
|
+
isCustomGateRegression(gateId, passed) {
|
|
2887
|
+
if (passed) {
|
|
2888
|
+
return false;
|
|
2889
|
+
}
|
|
2890
|
+
if (!this.customGateBaseline) {
|
|
2891
|
+
return true;
|
|
2892
|
+
}
|
|
2893
|
+
const baselinePassed = this.customGateBaseline.get(gateId);
|
|
2894
|
+
if (baselinePassed === false) {
|
|
2895
|
+
return false;
|
|
2896
|
+
}
|
|
2897
|
+
return true;
|
|
2898
|
+
}
|
|
2899
|
+
/**
|
|
2900
|
+
* Determine if a quality gate result represents a NEW regression.
|
|
2901
|
+
* Compares current failure count against baseline to distinguish
|
|
2902
|
+
* pre-existing failures from new failures introduced this iteration.
|
|
2903
|
+
*
|
|
2904
|
+
* Coverage/test also enforces suite-footprint integrity: a greener count is
|
|
2905
|
+
* only non-blocking when executed/skipped footprints prove the suite did not
|
|
2906
|
+
* shrink or skip more tests. Lint and security keep count-only comparison.
|
|
2907
|
+
*
|
|
2908
|
+
* @param result - Quality gate check result
|
|
2909
|
+
* @returns true if this is a new regression, false if pre-existing or passed,
|
|
2910
|
+
* undefined when comparison is unknown (fail-closed)
|
|
2911
|
+
*/
|
|
2912
|
+
isQualityRegression(result) {
|
|
2913
|
+
if (!this.qualityBaseline || this.qualityBaseline.status !== "captured") {
|
|
2914
|
+
if (result.success) return false;
|
|
2915
|
+
return void 0;
|
|
2916
|
+
}
|
|
2917
|
+
if ((result.gate === "coverage" || result.gate === "lint" || result.gate === "security") && this.qualityBaseline.gateAvailability[result.gate] !== true) {
|
|
2918
|
+
if (result.success) return false;
|
|
2919
|
+
return void 0;
|
|
2920
|
+
}
|
|
2921
|
+
const currentResult = extractFailureCountWithMethod([result], result.gate);
|
|
2922
|
+
const currentFailures = currentResult.count;
|
|
2923
|
+
if (result.gate === "coverage") {
|
|
2924
|
+
const classification = classifyCoverageBaselineComparison(
|
|
2925
|
+
{
|
|
2926
|
+
failures: this.qualityBaseline.testFailures,
|
|
2927
|
+
suiteFootprint: this.qualityBaseline.testSuiteFootprint,
|
|
2928
|
+
messages: this.qualityBaseline.testFailureMessages
|
|
2929
|
+
},
|
|
2930
|
+
{
|
|
2931
|
+
failures: currentFailures,
|
|
2932
|
+
suiteFootprint: currentResult.suiteFootprint,
|
|
2933
|
+
messages: currentResult.messages
|
|
2934
|
+
}
|
|
2935
|
+
);
|
|
2936
|
+
if (classification === "regression") {
|
|
2937
|
+
return true;
|
|
2938
|
+
}
|
|
2939
|
+
if (classification === "improvement" || classification === "pre_existing") {
|
|
2940
|
+
if (currentFailures > 0) {
|
|
2941
|
+
this.telemetry?.logEvent({
|
|
2942
|
+
name: "quality_gate_pre_existing_failure",
|
|
2943
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2944
|
+
properties: {
|
|
2945
|
+
gate: result.gate,
|
|
2946
|
+
currentFailures,
|
|
2947
|
+
currentMethod: currentResult.method,
|
|
2948
|
+
baselineFailures: this.qualityBaseline.testFailures,
|
|
2949
|
+
baselineMethod: this.qualityBaseline.testFailuresMethod,
|
|
2950
|
+
classification
|
|
2951
|
+
}
|
|
2952
|
+
});
|
|
2953
|
+
}
|
|
2954
|
+
return false;
|
|
2955
|
+
}
|
|
2956
|
+
return void 0;
|
|
2957
|
+
}
|
|
2958
|
+
if (result.success) {
|
|
2959
|
+
return false;
|
|
2960
|
+
}
|
|
2961
|
+
let baselineFailures = 0;
|
|
2962
|
+
let baselineMethod;
|
|
2963
|
+
switch (result.gate) {
|
|
2964
|
+
case "lint":
|
|
2965
|
+
baselineFailures = this.qualityBaseline.lintErrors;
|
|
2966
|
+
baselineMethod = this.qualityBaseline.lintErrorsMethod;
|
|
2967
|
+
break;
|
|
2968
|
+
case "security":
|
|
2969
|
+
baselineFailures = this.qualityBaseline.securityFailures;
|
|
2970
|
+
baselineMethod = this.qualityBaseline.securityFailuresMethod;
|
|
2971
|
+
break;
|
|
2972
|
+
default:
|
|
2973
|
+
return true;
|
|
2974
|
+
}
|
|
2975
|
+
if (result.gate === "security" && (currentResult.method === "fallback_1" || baselineMethod === "fallback_1")) {
|
|
2976
|
+
return true;
|
|
2977
|
+
}
|
|
2978
|
+
const isRegression = currentFailures > baselineFailures;
|
|
2979
|
+
if (!isRegression && currentFailures > 0) {
|
|
2980
|
+
this.telemetry?.logEvent({
|
|
2981
|
+
name: "quality_gate_pre_existing_failure",
|
|
2982
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2983
|
+
properties: {
|
|
2984
|
+
gate: result.gate,
|
|
2985
|
+
currentFailures,
|
|
2986
|
+
currentMethod: currentResult.method,
|
|
2987
|
+
baselineFailures,
|
|
2988
|
+
baselineMethod
|
|
2989
|
+
}
|
|
2990
|
+
});
|
|
2991
|
+
}
|
|
2992
|
+
return isRegression;
|
|
2993
|
+
}
|
|
2994
|
+
/**
|
|
2995
|
+
* Detect if the iteration failed due to new TypeScript compilation errors.
|
|
2996
|
+
*
|
|
2997
|
+
* Compilation failure is indicated by typed controller metadata, the
|
|
2998
|
+
* ProgressValidator's structured insight, or a classified gate failure. Provider
|
|
2999
|
+
* output text is not used for this decision.
|
|
3000
|
+
*
|
|
3001
|
+
* This is used to block completion when new compilation errors exist.
|
|
3002
|
+
*
|
|
3003
|
+
* @param result - Loop iteration result to check
|
|
3004
|
+
* @returns true if compilation failure detected
|
|
3005
|
+
*/
|
|
3006
|
+
detectCompilationFailure(result) {
|
|
3007
|
+
if ((result.metadata?.compilationErrorDelta ?? 0) > 0) {
|
|
3008
|
+
return true;
|
|
3009
|
+
}
|
|
3010
|
+
if (hasCompilationProgressSignal(result.progress?.insights)) {
|
|
3011
|
+
return true;
|
|
3012
|
+
}
|
|
3013
|
+
return (result.qualityGates ?? []).some(
|
|
3014
|
+
(gate) => classifyQualityGateFailure(gate) === "compilation"
|
|
3015
|
+
);
|
|
3016
|
+
}
|
|
3017
|
+
/**
|
|
3018
|
+
* Compute deterministic completion summary based on hard signals.
|
|
3019
|
+
* Separates "done" (gates, provider, convergence) from heuristics.
|
|
3020
|
+
*
|
|
3021
|
+
* @param result - Current iteration result
|
|
3022
|
+
* @param completionSignalDetected - Whether explicit completion signal was found
|
|
3023
|
+
* @returns CompletionSummary with deterministic status
|
|
3024
|
+
*/
|
|
3025
|
+
computeCompletionSummary(result, completionSignalDetected, isCompletionOrBounds) {
|
|
3026
|
+
const semanticValidation = result.semanticValidation;
|
|
3027
|
+
return evaluateCompletion({
|
|
3028
|
+
result,
|
|
3029
|
+
completionSignalDetected,
|
|
3030
|
+
isCompletionOrBounds,
|
|
3031
|
+
validationMode: this.config.validationMode,
|
|
3032
|
+
runQualityGates: this.config.runQualityGates,
|
|
3033
|
+
priorIterationFingerprints: this.iterationHistory.map((h) => h.iterationFingerprint),
|
|
3034
|
+
priorCompletenessSignals: this.iterationHistory.map((h) => h.progress.metrics.completeness),
|
|
3035
|
+
hasDurableCompletionEvidence: this.hasDurableCompletionEvidence(result),
|
|
3036
|
+
semanticCompletionOk: isSemanticCompletionSatisfied(semanticValidation),
|
|
3037
|
+
semanticIsErrorSkip: isSemanticErrorSkip(semanticValidation?.skipped)
|
|
3038
|
+
});
|
|
3039
|
+
}
|
|
3040
|
+
hasSubstantiveCompletionEvidence(result) {
|
|
3041
|
+
return hasSubstantiveCompletionEvidence(result, this.hasDurableCompletionEvidence(result));
|
|
3042
|
+
}
|
|
3043
|
+
hasDurableCompletionEvidence(result) {
|
|
3044
|
+
return result.completionEvidence?.durable === true;
|
|
3045
|
+
}
|
|
3046
|
+
/**
|
|
3047
|
+
* Get AI Judge evaluation if enabled
|
|
3048
|
+
*/
|
|
3049
|
+
async getAIJudgeEvaluation(_iteration, _taskResult, progress) {
|
|
3050
|
+
if (!this.aiJudge) return void 0;
|
|
3051
|
+
try {
|
|
3052
|
+
const variantResult = {
|
|
3053
|
+
variant: `iteration-${_iteration}`,
|
|
3054
|
+
provider: "autonomous-loop",
|
|
3055
|
+
success: progress.isSignificant,
|
|
3056
|
+
completeness: progress.score * 100,
|
|
3057
|
+
output: typeof _taskResult === "object" ? JSON.stringify(_taskResult) : String(_taskResult),
|
|
3058
|
+
duration: 0,
|
|
3059
|
+
// Will be filled by iteration result
|
|
3060
|
+
costMetrics: void 0
|
|
3061
|
+
};
|
|
3062
|
+
const remainingMs = this.ensureRemainingTimeboxMs("AI judge evaluation");
|
|
3063
|
+
const deadlineMs = Date.now() + remainingMs;
|
|
3064
|
+
const judgeResult = await this.aiJudge.evaluate(
|
|
3065
|
+
[variantResult],
|
|
3066
|
+
`Iteration ${_iteration} progress evaluation`,
|
|
3067
|
+
{
|
|
3068
|
+
taskId: `loop-iteration-${_iteration}`,
|
|
3069
|
+
deadlineMs,
|
|
3070
|
+
abortSignal: this.config.abortSignal
|
|
3071
|
+
}
|
|
3072
|
+
);
|
|
3073
|
+
const evaluation = judgeResult.evaluations[0];
|
|
3074
|
+
const recommendation = this.determineRecommendation(
|
|
3075
|
+
evaluation?.qualityScore ?? progress.score * 100,
|
|
3076
|
+
progress
|
|
3077
|
+
);
|
|
3078
|
+
const result = {
|
|
3079
|
+
overallScore: evaluation?.qualityScore ?? progress.score * 100,
|
|
3080
|
+
criteria: evaluation?.codeQuality ?? {
|
|
3081
|
+
correctness: progress.metrics.codeQuality * 100,
|
|
3082
|
+
quality: progress.metrics.maintainability * 100,
|
|
3083
|
+
performance: progress.metrics.performance * 100,
|
|
3084
|
+
completeness: progress.metrics.completeness * 100
|
|
3085
|
+
},
|
|
3086
|
+
recommendation,
|
|
3087
|
+
reasoning: judgeResult.reasoning || `Progress: ${(progress.score * 100).toFixed(1)}%`,
|
|
3088
|
+
confidence: judgeResult.metadata?.confidence ?? progress.confidence
|
|
3089
|
+
};
|
|
3090
|
+
this.emit("ai_judge_evaluation", {
|
|
3091
|
+
type: "ai_judge_evaluation",
|
|
3092
|
+
evaluation: result
|
|
3093
|
+
});
|
|
3094
|
+
return result;
|
|
3095
|
+
} catch (error) {
|
|
3096
|
+
this.telemetry?.trackError(error, {
|
|
3097
|
+
_iteration,
|
|
3098
|
+
context: "ai_judge"
|
|
3099
|
+
});
|
|
3100
|
+
return void 0;
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
/**
|
|
3104
|
+
* Count actual change lines in a git diff (lines starting with + or -).
|
|
3105
|
+
* Excludes diff metadata lines (@@, diff, index, ---, +++).
|
|
3106
|
+
*/
|
|
3107
|
+
countActualDiffLines(gitDiff) {
|
|
3108
|
+
let count = 0;
|
|
3109
|
+
for (const line of gitDiff.split("\n")) {
|
|
3110
|
+
if ((line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")) {
|
|
3111
|
+
count++;
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
return count;
|
|
3115
|
+
}
|
|
3116
|
+
/**
|
|
3117
|
+
* Run semantic validation using AI-powered progress checks.
|
|
3118
|
+
*
|
|
3119
|
+
* This validates:
|
|
3120
|
+
* 1. Progress toward goals (via semantic-progress-rater)
|
|
3121
|
+
* 2. Acceptance criteria satisfaction (via acceptance-criteria-checker)
|
|
3122
|
+
*
|
|
3123
|
+
* Graceful degradation: If provider calls fail (auth errors, timeouts, parse errors),
|
|
3124
|
+
* semantic validation is skipped with a warning rather than failing the loop (unless strictMode).
|
|
3125
|
+
* Routing (provider and model) is resolved by the caller; when no override is given, checks run on the
|
|
3126
|
+
* task's own engine/model, and missing provider/auth simply logs a warning and continues without
|
|
3127
|
+
* validation. The CLI gates only at completion boundaries by default; the check itself is opt-in.
|
|
3128
|
+
* Provider/auth warnings become hard failures only when `strictMode` is true (default false).
|
|
3129
|
+
*
|
|
3130
|
+
* Mode behavior:
|
|
3131
|
+
* - `completion-only` (default): Only runs when `isCompletionOrBounds` is true
|
|
3132
|
+
* - `every-iteration`: Runs every N iterations (controlled by runEveryNIterations)
|
|
3133
|
+
*
|
|
3134
|
+
* @param iteration - Current iteration number
|
|
3135
|
+
* @param _outputForChecks - Provider output text for checks
|
|
3136
|
+
* @param isCompletionOrBounds - True if completion signal matched or at bounds (last iteration)
|
|
3137
|
+
* @returns Semantic validation result
|
|
3138
|
+
*/
|
|
3139
|
+
async runSemanticValidation(iteration, _outputForChecks, isCompletionOrBounds) {
|
|
3140
|
+
const config = this.config.semanticCheck;
|
|
3141
|
+
if (!config?.enabled) {
|
|
3142
|
+
return semanticDisabled();
|
|
3143
|
+
}
|
|
3144
|
+
const mode = config.mode ?? "completion-only";
|
|
3145
|
+
if (mode === "completion-only" && !isCompletionOrBounds) {
|
|
3146
|
+
return semanticSkipped("not_completion_bounds");
|
|
3147
|
+
}
|
|
3148
|
+
if (!config.provider) {
|
|
3149
|
+
emitWarning(
|
|
3150
|
+
"SEM-000",
|
|
3151
|
+
{
|
|
3152
|
+
taskId: "semantic-validation",
|
|
3153
|
+
subsystem: "autonomous-loop-controller",
|
|
3154
|
+
executionPhase: "validation"
|
|
3155
|
+
},
|
|
3156
|
+
{
|
|
3157
|
+
severity: "WARN" /* WARN */,
|
|
3158
|
+
metadata: {
|
|
3159
|
+
error: "Semantic validation enabled but no provider configured; skipping",
|
|
3160
|
+
iteration
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
);
|
|
3164
|
+
return semanticSkipped("provider_error");
|
|
3165
|
+
}
|
|
3166
|
+
if (mode === "every-iteration") {
|
|
3167
|
+
const runEveryN = config.runEveryNIterations ?? 1;
|
|
3168
|
+
if (runEveryN > 1 && iteration % runEveryN !== 0) {
|
|
3169
|
+
return semanticSkipped("iteration_skip");
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
const baseRef = this.semanticBaselineRef ?? this.config.progressConfig.baseRef ?? "HEAD~1";
|
|
3173
|
+
let gitDiff;
|
|
3174
|
+
try {
|
|
3175
|
+
if (!isSafeGitRef2(baseRef)) {
|
|
3176
|
+
throw new Error(`Invalid git baseRef: "${baseRef}"`);
|
|
3177
|
+
}
|
|
3178
|
+
const { execFileSync } = await import("child_process");
|
|
3179
|
+
gitDiff = execFileSync("git", ["diff", baseRef], {
|
|
3180
|
+
cwd: this.workingDir,
|
|
3181
|
+
timeout: 1e4,
|
|
3182
|
+
maxBuffer: 5 * 1024 * 1024,
|
|
3183
|
+
// 5MB
|
|
3184
|
+
encoding: "utf-8",
|
|
3185
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3186
|
+
}).trim();
|
|
3187
|
+
} catch (error) {
|
|
3188
|
+
this.telemetry?.logEvent({
|
|
3189
|
+
name: "semantic_validation_skipped",
|
|
3190
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3191
|
+
properties: {
|
|
3192
|
+
iteration,
|
|
3193
|
+
reason: "git_diff_failed",
|
|
3194
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3195
|
+
}
|
|
3196
|
+
});
|
|
3197
|
+
return semanticSkipped("provider_error");
|
|
3198
|
+
}
|
|
3199
|
+
const taskText = this.config.requirementsTaskText;
|
|
3200
|
+
if (!taskText) {
|
|
3201
|
+
return semanticSkipped("no_task_spec");
|
|
3202
|
+
}
|
|
3203
|
+
gitDiff = filterSemanticValidationDiff(gitDiff, taskText).trim();
|
|
3204
|
+
const minDiffLines = config.minDiffLines ?? 10;
|
|
3205
|
+
const actualDiffLines = this.countActualDiffLines(gitDiff);
|
|
3206
|
+
if (!isCompletionOrBounds && actualDiffLines < minDiffLines) {
|
|
3207
|
+
return semanticSkipped("trivial_diff");
|
|
3208
|
+
}
|
|
3209
|
+
const remainingMs = this.ensureRemainingTimeboxMs("semantic validation");
|
|
3210
|
+
const deadlineMs = Date.now() + remainingMs;
|
|
3211
|
+
const abortSignal = this.config.abortSignal;
|
|
3212
|
+
const configuredTimeoutMs = config.timeoutMs;
|
|
3213
|
+
const timeoutMs = configuredTimeoutMs != null ? Math.min(configuredTimeoutMs, remainingMs) : remainingMs;
|
|
3214
|
+
let progressResult;
|
|
3215
|
+
try {
|
|
3216
|
+
progressResult = await rateProgress(taskText, gitDiff, {
|
|
3217
|
+
provider: config.provider,
|
|
3218
|
+
workingDir: this.workingDir,
|
|
3219
|
+
profile: config.profile,
|
|
3220
|
+
model: config.model,
|
|
3221
|
+
timeoutMs,
|
|
3222
|
+
deadlineMs,
|
|
3223
|
+
abortSignal,
|
|
3224
|
+
workspaceMode: config.workspaceMode
|
|
3225
|
+
});
|
|
3226
|
+
} catch (error) {
|
|
3227
|
+
if (config.strictMode) throw error;
|
|
3228
|
+
emitWarning(
|
|
3229
|
+
"SEM-001",
|
|
3230
|
+
{
|
|
3231
|
+
taskId: "semantic-validation",
|
|
3232
|
+
subsystem: "autonomous-loop-controller",
|
|
3233
|
+
executionPhase: "validation"
|
|
3234
|
+
},
|
|
3235
|
+
{
|
|
3236
|
+
severity: "WARN" /* WARN */,
|
|
3237
|
+
metadata: {
|
|
3238
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3239
|
+
iteration,
|
|
3240
|
+
operation: "rateProgress"
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
);
|
|
3244
|
+
return semanticSkipped("provider_error");
|
|
3245
|
+
}
|
|
3246
|
+
let acResults = [];
|
|
3247
|
+
let satisfactionScore = 0;
|
|
3248
|
+
try {
|
|
3249
|
+
acResults = await checkAcceptanceCriteria(taskText, gitDiff, {
|
|
3250
|
+
provider: config.provider,
|
|
3251
|
+
workingDir: this.workingDir,
|
|
3252
|
+
profile: config.profile,
|
|
3253
|
+
model: config.model,
|
|
3254
|
+
timeoutMs,
|
|
3255
|
+
deadlineMs,
|
|
3256
|
+
abortSignal,
|
|
3257
|
+
workspaceMode: config.workspaceMode
|
|
3258
|
+
});
|
|
3259
|
+
const hasAnyConfidence = acResults.some((r) => r.confidence > 0);
|
|
3260
|
+
if (acResults.length > 0 && !hasAnyConfidence) {
|
|
3261
|
+
emitWarning(
|
|
3262
|
+
"SEM-002",
|
|
3263
|
+
{
|
|
3264
|
+
taskId: "semantic-validation",
|
|
3265
|
+
subsystem: "autonomous-loop-controller",
|
|
3266
|
+
executionPhase: "validation"
|
|
3267
|
+
},
|
|
3268
|
+
{
|
|
3269
|
+
severity: "WARN" /* WARN */,
|
|
3270
|
+
metadata: {
|
|
3271
|
+
error: "All acceptance criteria checks returned zero confidence; evaluating as unsatisfied",
|
|
3272
|
+
iteration,
|
|
3273
|
+
operation: "checkAcceptanceCriteria"
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
);
|
|
3277
|
+
}
|
|
3278
|
+
if (acResults.length > 0) satisfactionScore = calculateSatisfactionScore(acResults);
|
|
3279
|
+
} catch (error) {
|
|
3280
|
+
if (config.strictMode) throw error;
|
|
3281
|
+
emitWarning(
|
|
3282
|
+
"SEM-002",
|
|
3283
|
+
{
|
|
3284
|
+
taskId: "semantic-validation",
|
|
3285
|
+
subsystem: "autonomous-loop-controller",
|
|
3286
|
+
executionPhase: "validation"
|
|
3287
|
+
},
|
|
3288
|
+
{
|
|
3289
|
+
severity: "WARN" /* WARN */,
|
|
3290
|
+
metadata: {
|
|
3291
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3292
|
+
iteration,
|
|
3293
|
+
operation: "checkAcceptanceCriteria"
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
);
|
|
3297
|
+
return semanticSkipped("provider_error");
|
|
3298
|
+
}
|
|
3299
|
+
let passed;
|
|
3300
|
+
const minProgressConfidence = this.config.progressConfig.confidenceThreshold ?? 0.7;
|
|
3301
|
+
const significantProgress = isSignificantProgress(progressResult, minProgressConfidence);
|
|
3302
|
+
if (acResults.length > 0) {
|
|
3303
|
+
passed = significantProgress || satisfactionScore >= 0.5;
|
|
3304
|
+
} else {
|
|
3305
|
+
passed = significantProgress;
|
|
3306
|
+
}
|
|
3307
|
+
this.telemetry?.logEvent({
|
|
3308
|
+
name: "semantic_validation_complete",
|
|
3309
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3310
|
+
properties: {
|
|
3311
|
+
iteration,
|
|
3312
|
+
movedCloser: progressResult.movedCloser,
|
|
3313
|
+
progressConfidence: progressResult.confidence,
|
|
3314
|
+
satisfactionScore,
|
|
3315
|
+
totalACs: acResults.length,
|
|
3316
|
+
satisfiedACs: acResults.filter((r) => r.satisfied).length,
|
|
3317
|
+
passed,
|
|
3318
|
+
hasACs: acResults.length > 0
|
|
3319
|
+
}
|
|
3320
|
+
});
|
|
3321
|
+
return {
|
|
3322
|
+
enabled: true,
|
|
3323
|
+
passed,
|
|
3324
|
+
progressResult,
|
|
3325
|
+
acResults,
|
|
3326
|
+
satisfactionScore
|
|
3327
|
+
};
|
|
3328
|
+
}
|
|
3329
|
+
/**
|
|
3330
|
+
* Determine recommendation based on score and progress trends
|
|
3331
|
+
*/
|
|
3332
|
+
determineRecommendation(score, progress) {
|
|
3333
|
+
if (score >= 80 && progress.trend === "improving") return "continue";
|
|
3334
|
+
if (score >= 80 && progress.trend === "stable" && !progress.isSignificant) return "terminate";
|
|
3335
|
+
if (score < 40 && progress.trend === "declining") return "terminate";
|
|
3336
|
+
if (progress.isSignificant) return "continue";
|
|
3337
|
+
return score >= 60 ? "continue" : "pivot";
|
|
3338
|
+
}
|
|
3339
|
+
/**
|
|
3340
|
+
* Handle a 'pivot' recommendation from determineRecommendation.
|
|
3341
|
+
*
|
|
3342
|
+
* Behavior depends on the POETIC_CROSS_PROVIDER_PIVOT feature flag:
|
|
3343
|
+
* - 'off': No action taken
|
|
3344
|
+
* - 'shadow': Emits telemetry events but does not switch provider
|
|
3345
|
+
* - 'on': Switches to the next configured alternate provider
|
|
3346
|
+
*/
|
|
3347
|
+
async handlePivotRecommendation(result) {
|
|
3348
|
+
if (!this.config.enableCrossProviderPivot) return;
|
|
3349
|
+
const flagMode = ORCHESTRATOR_FEATURE_FLAGS.CROSS_PROVIDER_PIVOT;
|
|
3350
|
+
if (flagMode === "off") return;
|
|
3351
|
+
const fromProvider = this.currentProvider ?? this.config.routingDecision?.primary.provider ?? "unknown";
|
|
3352
|
+
const nextAlternate = this.availableAlternates.find(
|
|
3353
|
+
(alt) => alt.provider !== this.currentProvider
|
|
3354
|
+
);
|
|
3355
|
+
this.emit("pivot_triggered", {
|
|
3356
|
+
type: "pivot_triggered",
|
|
3357
|
+
iteration: result._iteration,
|
|
3358
|
+
fromProvider,
|
|
3359
|
+
toProvider: nextAlternate?.provider,
|
|
3360
|
+
reason: `Score ${result.judgeEvaluation?.overallScore ?? "N/A"} < 60 with insufficient progress`,
|
|
3361
|
+
mode: flagMode
|
|
3362
|
+
});
|
|
3363
|
+
this.telemetry?.logEvent({
|
|
3364
|
+
name: "cross_provider_pivot_triggered",
|
|
3365
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3366
|
+
properties: {
|
|
3367
|
+
iteration: result._iteration,
|
|
3368
|
+
fromProvider,
|
|
3369
|
+
toProvider: nextAlternate?.provider ?? null,
|
|
3370
|
+
mode: flagMode,
|
|
3371
|
+
score: result.judgeEvaluation?.overallScore,
|
|
3372
|
+
hasAlternates: this.availableAlternates.length > 0
|
|
3373
|
+
}
|
|
3374
|
+
});
|
|
3375
|
+
if (flagMode === "shadow") return;
|
|
3376
|
+
if (nextAlternate) {
|
|
3377
|
+
const previousProvider = this.currentProvider;
|
|
3378
|
+
this.currentProvider = nextAlternate.provider;
|
|
3379
|
+
this.currentProviderSetup = nextAlternate.setup;
|
|
3380
|
+
this.availableAlternates = this.availableAlternates.filter(
|
|
3381
|
+
(alt) => alt.provider !== nextAlternate.provider
|
|
3382
|
+
);
|
|
3383
|
+
this.emit("provider_switched", {
|
|
3384
|
+
type: "provider_switched",
|
|
3385
|
+
iteration: result._iteration,
|
|
3386
|
+
fromProvider: previousProvider ?? "unknown",
|
|
3387
|
+
toProvider: nextAlternate.provider
|
|
3388
|
+
});
|
|
3389
|
+
this.telemetry?.logEvent({
|
|
3390
|
+
name: "cross_provider_switched",
|
|
3391
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3392
|
+
properties: {
|
|
3393
|
+
iteration: result._iteration,
|
|
3394
|
+
fromProvider: previousProvider,
|
|
3395
|
+
toProvider: nextAlternate.provider,
|
|
3396
|
+
remainingAlternates: this.availableAlternates.length
|
|
3397
|
+
}
|
|
3398
|
+
});
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
/**
|
|
3402
|
+
* Check if loop should terminate
|
|
3403
|
+
*/
|
|
3404
|
+
async shouldTerminate(_iteration) {
|
|
3405
|
+
if (this.state.status !== "running") {
|
|
3406
|
+
return true;
|
|
3407
|
+
}
|
|
3408
|
+
const elapsed = this.getElapsedRuntimeMs();
|
|
3409
|
+
if (elapsed >= this.config.timeboxMs) {
|
|
3410
|
+
this.terminate("timebox_exceeded");
|
|
3411
|
+
return true;
|
|
3412
|
+
}
|
|
3413
|
+
const resources = getResourceUsage();
|
|
3414
|
+
if (resources.memory.heapUsed > this.config.resourceLimits.maxMemoryMB * 1024 * 1024) {
|
|
3415
|
+
this.terminate("resource_exhaustion");
|
|
3416
|
+
return true;
|
|
3417
|
+
}
|
|
3418
|
+
if (!this.recursionTracker.canSpawnChildren()) {
|
|
3419
|
+
this.terminate("recursion_limit");
|
|
3420
|
+
return true;
|
|
3421
|
+
}
|
|
3422
|
+
return false;
|
|
3423
|
+
}
|
|
3424
|
+
/**
|
|
3425
|
+
* Check if loop should continue based on progress, completion signal, and validation mode.
|
|
3426
|
+
*
|
|
3427
|
+
* Termination priority (first match wins):
|
|
3428
|
+
* 1. Iteration failure → retry if under limit
|
|
3429
|
+
* 2. Compilation failure (new TS errors) → continue (cannot complete with compilation errors)
|
|
3430
|
+
* 3. Completion signal matched → terminate with 'completion_signal' (unless blocked by gates)
|
|
3431
|
+
* - Gates: quality regressions, requirements, progress (heuristic), semantic validation
|
|
3432
|
+
* - Semantic check gates completion: if enabled and fails, ignore completion signal
|
|
3433
|
+
* - At bounds + semantic fails → terminate with 'semantic_criteria_unsatisfied'
|
|
3434
|
+
* 4. Bounds reached + semantic fails → terminate with 'semantic_criteria_unsatisfied'
|
|
3435
|
+
* 5. Deterministic mode + all quality gates pass (or non-regressions only) → terminate
|
|
3436
|
+
* 6. Heuristic mode: completion threshold / stagnation / AI Judge
|
|
3437
|
+
* 7. None mode: only bounds + completion signal can stop (no stagnation detection)
|
|
3438
|
+
*
|
|
3439
|
+
* Baseline-aware rules:
|
|
3440
|
+
* - Quality gate failures with isRegression === false (pre-existing) do NOT block completion
|
|
3441
|
+
* - Only gates with isRegression === true block completion
|
|
3442
|
+
*
|
|
3443
|
+
* Semantic validation as gate (not parallel termination):
|
|
3444
|
+
* - Semantic check is a gate on "DONE" (completion signal or bounds)
|
|
3445
|
+
* - It does NOT terminate mid-loop on its own; only at completion/bounds checkpoints
|
|
3446
|
+
*/
|
|
3447
|
+
async shouldContinue(result) {
|
|
3448
|
+
if (this.state.status === "terminated") {
|
|
3449
|
+
return false;
|
|
3450
|
+
}
|
|
3451
|
+
if (!result.success) {
|
|
3452
|
+
const initialDisposition = result.failureRecovery?.recovery.disposition;
|
|
3453
|
+
if (initialDisposition === "operator_stop") {
|
|
3454
|
+
this.terminate("system_error");
|
|
3455
|
+
return false;
|
|
3456
|
+
}
|
|
3457
|
+
if (this.tryIdleStopAfterRealFirstDelivery(result)) {
|
|
3458
|
+
if (result.failureRecovery) {
|
|
3459
|
+
result.failureRecovery = serializeDirectAutoloopFailureRecovery(
|
|
3460
|
+
result.failureRecovery.failure,
|
|
3461
|
+
"delivery_rescue"
|
|
3462
|
+
);
|
|
3463
|
+
}
|
|
3464
|
+
return false;
|
|
3465
|
+
}
|
|
3466
|
+
if (initialDisposition === "terminal_stop") {
|
|
3467
|
+
this.telemetry?.logEvent({
|
|
3468
|
+
name: "autoloop_terminal_failure_stop",
|
|
3469
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3470
|
+
properties: {
|
|
3471
|
+
iteration: result._iteration,
|
|
3472
|
+
category: result.failureRecovery?.failure.category,
|
|
3473
|
+
evidenceSource: result.failureRecovery?.failure.evidenceSource
|
|
3474
|
+
}
|
|
3475
|
+
});
|
|
3476
|
+
this.terminate("system_error");
|
|
3477
|
+
return false;
|
|
3478
|
+
}
|
|
3479
|
+
if (result.error) {
|
|
3480
|
+
const signature = computeErrorSignature(result);
|
|
3481
|
+
if (signature.hash === this.lastErrorSignature) {
|
|
3482
|
+
this.consecutiveIdenticalCount += 1;
|
|
3483
|
+
} else {
|
|
3484
|
+
this.consecutiveIdenticalCount = 1;
|
|
3485
|
+
}
|
|
3486
|
+
this.lastErrorSignature = signature.hash;
|
|
3487
|
+
if (this.consecutiveIdenticalCount >= 2) {
|
|
3488
|
+
const escalated = this.escalatePolicy("identical_error_pattern", {
|
|
3489
|
+
iteration: result._iteration,
|
|
3490
|
+
signature: signature.hash,
|
|
3491
|
+
components: signature.components,
|
|
3492
|
+
consecutiveCount: this.consecutiveIdenticalCount
|
|
3493
|
+
});
|
|
3494
|
+
if (escalated) {
|
|
3495
|
+
this.consecutiveIdenticalCount = 0;
|
|
3496
|
+
this.lastErrorSignature = null;
|
|
3497
|
+
return this.continueAfterFailureOrTerminate();
|
|
3498
|
+
}
|
|
3499
|
+
this.telemetry?.logEvent({
|
|
3500
|
+
name: "autoloop_identical_error_exit",
|
|
3501
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3502
|
+
properties: {
|
|
3503
|
+
iteration: result._iteration,
|
|
3504
|
+
signature: signature.hash,
|
|
3505
|
+
components: signature.components,
|
|
3506
|
+
consecutiveCount: this.consecutiveIdenticalCount
|
|
3507
|
+
}
|
|
3508
|
+
});
|
|
3509
|
+
this.terminate("identical_error_pattern");
|
|
3510
|
+
return false;
|
|
3511
|
+
}
|
|
3512
|
+
} else {
|
|
3513
|
+
this.lastErrorSignature = null;
|
|
3514
|
+
this.consecutiveIdenticalCount = 0;
|
|
3515
|
+
}
|
|
3516
|
+
return this.continueAfterFailureOrTerminate();
|
|
3517
|
+
}
|
|
3518
|
+
this.lastErrorSignature = null;
|
|
3519
|
+
this.consecutiveIdenticalCount = 0;
|
|
3520
|
+
const requirementsUnmet = Boolean(result.requirements?.enabled && !result.requirements.passed);
|
|
3521
|
+
const hasCompilationFailure = this.detectCompilationFailure(result);
|
|
3522
|
+
if (hasCompilationFailure) {
|
|
3523
|
+
this.telemetry?.logEvent({
|
|
3524
|
+
name: "completion_blocked_compilation_errors",
|
|
3525
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3526
|
+
properties: {
|
|
3527
|
+
iteration: result._iteration,
|
|
3528
|
+
progressScore: result.progress.score
|
|
3529
|
+
}
|
|
3530
|
+
});
|
|
3531
|
+
return true;
|
|
3532
|
+
}
|
|
3533
|
+
if (result.completionSummary?.status === "BASELINE_BLOCKED") {
|
|
3534
|
+
this.telemetry?.logEvent({
|
|
3535
|
+
name: "loop_terminated_baseline_blocked",
|
|
3536
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3537
|
+
properties: {
|
|
3538
|
+
iteration: result._iteration,
|
|
3539
|
+
baselineGateCount: (result.qualityGates?.filter((gate) => !gate.passed && gate.isRegression === false).length ?? 0) + (result.customGateResults?.filter((gate) => !gate.passed && gate.isRegression === false).length ?? 0)
|
|
3540
|
+
}
|
|
3541
|
+
});
|
|
3542
|
+
this.terminate("baseline_blocked");
|
|
3543
|
+
return false;
|
|
3544
|
+
}
|
|
3545
|
+
if (this.tryIdleStopAfterRealFirstDelivery(result)) {
|
|
3546
|
+
return false;
|
|
3547
|
+
}
|
|
3548
|
+
if (this.completionSignalMatched) {
|
|
3549
|
+
const customGatesOk = customGatesAllowCompletion(result.customGateResults);
|
|
3550
|
+
const blockingQualityGates = (result.qualityGates ?? []).filter(
|
|
3551
|
+
(gate) => isBlockingQualityGateForCompletion(gate) && !(customGatesOk && isUnavailableOrSkippedQualityGate(gate))
|
|
3552
|
+
);
|
|
3553
|
+
if (blockingQualityGates.length > 0) {
|
|
3554
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3555
|
+
iteration: result._iteration,
|
|
3556
|
+
gate: "quality_regression"
|
|
3557
|
+
});
|
|
3558
|
+
this.telemetry?.logEvent({
|
|
3559
|
+
name: "completion_signal_ignored_failed_gates",
|
|
3560
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3561
|
+
properties: {
|
|
3562
|
+
iteration: result._iteration,
|
|
3563
|
+
signalType: this.config.completionSignal?.type,
|
|
3564
|
+
failingGateIds: blockingQualityGates.map((g) => g.gateId),
|
|
3565
|
+
preExistingFailures: result.qualityGates?.filter((g) => !g.passed && g.isRegression === false).map((g) => g.gateId)
|
|
3566
|
+
}
|
|
3567
|
+
});
|
|
3568
|
+
return true;
|
|
3569
|
+
}
|
|
3570
|
+
const blockingCustomGates = (result.customGateResults ?? []).filter(
|
|
3571
|
+
isBlockingCustomGateForCompletion
|
|
3572
|
+
);
|
|
3573
|
+
if (blockingCustomGates.length > 0) {
|
|
3574
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3575
|
+
iteration: result._iteration,
|
|
3576
|
+
gate: "custom_regression"
|
|
3577
|
+
});
|
|
3578
|
+
this.telemetry?.logEvent({
|
|
3579
|
+
name: "completion_signal_ignored_failed_custom_gates",
|
|
3580
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3581
|
+
properties: {
|
|
3582
|
+
iteration: result._iteration,
|
|
3583
|
+
signalType: this.config.completionSignal?.type,
|
|
3584
|
+
failingGateIds: blockingCustomGates.map((g) => g.id),
|
|
3585
|
+
preExistingFailures: result.customGateResults?.filter((g) => !g.passed && g.isRegression === false).map((g) => g.id)
|
|
3586
|
+
}
|
|
3587
|
+
});
|
|
3588
|
+
return true;
|
|
3589
|
+
}
|
|
3590
|
+
const verificationEvidenceSatisfied = qualityGatesAllowCompletion(result.qualityGates) || customGatesOk;
|
|
3591
|
+
if (this.config.runQualityGates && !verificationEvidenceSatisfied) {
|
|
3592
|
+
if (verificationGatesUnavailableOnly({
|
|
3593
|
+
qualityGates: result.qualityGates,
|
|
3594
|
+
customGateResults: result.customGateResults
|
|
3595
|
+
})) {
|
|
3596
|
+
this.telemetry?.logEvent({
|
|
3597
|
+
name: "loop_terminated_verification_unavailable",
|
|
3598
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3599
|
+
properties: {
|
|
3600
|
+
iteration: result._iteration,
|
|
3601
|
+
signalType: this.config.completionSignal?.type,
|
|
3602
|
+
gateCount: result.qualityGates?.length ?? 0,
|
|
3603
|
+
customGateCount: result.customGateResults?.length ?? 0
|
|
3604
|
+
}
|
|
3605
|
+
});
|
|
3606
|
+
this.terminate("verification_unavailable");
|
|
3607
|
+
return false;
|
|
3608
|
+
}
|
|
3609
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3610
|
+
iteration: result._iteration,
|
|
3611
|
+
gate: "quality_unverified"
|
|
3612
|
+
});
|
|
3613
|
+
this.telemetry?.logEvent({
|
|
3614
|
+
name: "completion_signal_ignored_unverified_gates",
|
|
3615
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3616
|
+
properties: {
|
|
3617
|
+
iteration: result._iteration,
|
|
3618
|
+
signalType: this.config.completionSignal?.type,
|
|
3619
|
+
gateCount: result.qualityGates?.length ?? 0,
|
|
3620
|
+
skippedGateIds: result.qualityGates?.filter((g) => g.skipped === true).map((g) => g.gateId),
|
|
3621
|
+
customGateCount: result.customGateResults?.length ?? 0,
|
|
3622
|
+
skippedCustomGateIds: result.customGateResults?.filter((g) => g.skipped === true).map((g) => g.id)
|
|
3623
|
+
}
|
|
3624
|
+
});
|
|
3625
|
+
return true;
|
|
3626
|
+
}
|
|
3627
|
+
if (requirementsUnmet) {
|
|
3628
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3629
|
+
iteration: result._iteration,
|
|
3630
|
+
gate: "requirements",
|
|
3631
|
+
coverage: result.requirements?.coverage
|
|
3632
|
+
});
|
|
3633
|
+
this.telemetry?.logEvent({
|
|
3634
|
+
name: "completion_signal_ignored_requirements_unmet",
|
|
3635
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3636
|
+
properties: {
|
|
3637
|
+
iteration: result._iteration,
|
|
3638
|
+
coverage: result.requirements?.coverage,
|
|
3639
|
+
blockingIssues: result.requirements?.blockingIssues?.slice(0, 5)
|
|
3640
|
+
}
|
|
3641
|
+
});
|
|
3642
|
+
return true;
|
|
3643
|
+
}
|
|
3644
|
+
const hasPositiveVerificationEvidence = qualityGatesAllowCompletion(result.qualityGates) || customGatesOk;
|
|
3645
|
+
if (this.config.validationMode === "heuristic" && result.progress.verificationUnavailable === true && !hasPositiveVerificationEvidence && this.config.qualityGatePolicy !== "explicitly_disabled") {
|
|
3646
|
+
this.telemetry?.logEvent({
|
|
3647
|
+
name: "loop_terminated_verification_unavailable",
|
|
3648
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3649
|
+
properties: {
|
|
3650
|
+
iteration: result._iteration,
|
|
3651
|
+
signalType: this.config.completionSignal?.type,
|
|
3652
|
+
reason: result.progress.verificationUnavailableReason
|
|
3653
|
+
}
|
|
3654
|
+
});
|
|
3655
|
+
this.terminate("verification_unavailable");
|
|
3656
|
+
return false;
|
|
3657
|
+
}
|
|
3658
|
+
if (this.config.validationMode === "heuristic") {
|
|
3659
|
+
const COMPLETION_SIGNAL_MIN_SCORE = 0.3;
|
|
3660
|
+
const validationUnavailable = result.progress.toolingFailure === true || result.progress.verificationUnavailable === true;
|
|
3661
|
+
const durableEvidenceCanSubstituteForTooling = validationUnavailable && this.hasDurableCompletionEvidence(result);
|
|
3662
|
+
const gateEvidenceCanSubstituteForTooling = validationUnavailable && customGatesOk;
|
|
3663
|
+
const isProgressSufficient = durableEvidenceCanSubstituteForTooling || gateEvidenceCanSubstituteForTooling || !validationUnavailable && result.progress.trend !== "declining" && (result.progress.isSignificant || result.progress.score >= COMPLETION_SIGNAL_MIN_SCORE);
|
|
3664
|
+
if (!isProgressSufficient) {
|
|
3665
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3666
|
+
iteration: result._iteration,
|
|
3667
|
+
gate: "progress",
|
|
3668
|
+
trend: result.progress.trend
|
|
3669
|
+
});
|
|
3670
|
+
this.telemetry?.logEvent({
|
|
3671
|
+
name: "completion_signal_ignored_progress_insufficient",
|
|
3672
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3673
|
+
properties: {
|
|
3674
|
+
iteration: result._iteration,
|
|
3675
|
+
signalType: this.config.completionSignal?.type,
|
|
3676
|
+
score: result.progress.score,
|
|
3677
|
+
trend: result.progress.trend,
|
|
3678
|
+
isSignificant: result.progress.isSignificant,
|
|
3679
|
+
minScore: COMPLETION_SIGNAL_MIN_SCORE
|
|
3680
|
+
}
|
|
3681
|
+
});
|
|
3682
|
+
return true;
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
const hostVerifiedCompletionEvidence = result.success === true && this.hasDurableCompletionEvidence(result) && customGatesOk;
|
|
3686
|
+
if (isSemanticCheckBlocking(result.semanticValidation) && !hostVerifiedCompletionEvidence) {
|
|
3687
|
+
const atBounds2 = result._iteration >= this.config.maxIterations;
|
|
3688
|
+
if (atBounds2) {
|
|
3689
|
+
this.telemetry?.logEvent({
|
|
3690
|
+
name: "loop_terminated_semantic_criteria_unsatisfied",
|
|
3691
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3692
|
+
properties: {
|
|
3693
|
+
iteration: result._iteration,
|
|
3694
|
+
context: "completion_signal_gated_at_bounds",
|
|
3695
|
+
movedCloser: result.semanticValidation?.progressResult?.movedCloser,
|
|
3696
|
+
satisfactionScore: result.semanticValidation?.satisfactionScore,
|
|
3697
|
+
totalACs: result.semanticValidation?.acResults?.length ?? 0,
|
|
3698
|
+
satisfiedACs: result.semanticValidation?.acResults?.filter((r) => r.satisfied).length ?? 0
|
|
3699
|
+
}
|
|
3700
|
+
});
|
|
3701
|
+
this.terminate("semantic_criteria_unsatisfied");
|
|
3702
|
+
return false;
|
|
3703
|
+
}
|
|
3704
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3705
|
+
iteration: result._iteration,
|
|
3706
|
+
gate: "semantic",
|
|
3707
|
+
satisfactionScore: result.semanticValidation?.satisfactionScore
|
|
3708
|
+
});
|
|
3709
|
+
this.telemetry?.logEvent({
|
|
3710
|
+
name: "completion_signal_ignored_semantic_failed",
|
|
3711
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3712
|
+
properties: {
|
|
3713
|
+
iteration: result._iteration,
|
|
3714
|
+
signalType: this.config.completionSignal?.type,
|
|
3715
|
+
movedCloser: result.semanticValidation?.progressResult?.movedCloser,
|
|
3716
|
+
satisfactionScore: result.semanticValidation?.satisfactionScore,
|
|
3717
|
+
totalACs: result.semanticValidation?.acResults?.length ?? 0,
|
|
3718
|
+
satisfiedACs: result.semanticValidation?.acResults?.filter((r) => r.satisfied).length ?? 0
|
|
3719
|
+
}
|
|
3720
|
+
});
|
|
3721
|
+
return true;
|
|
3722
|
+
}
|
|
3723
|
+
if (!completionStatusAllowsSuccess(result.completionSummary?.status)) {
|
|
3724
|
+
this.escalatePolicy("completion_signal_gated", {
|
|
3725
|
+
iteration: result._iteration,
|
|
3726
|
+
gate: "completion_summary",
|
|
3727
|
+
status: result.completionSummary?.status
|
|
3728
|
+
});
|
|
3729
|
+
this.telemetry?.logEvent({
|
|
3730
|
+
name: "completion_signal_ignored_incomplete_summary",
|
|
3731
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3732
|
+
properties: {
|
|
3733
|
+
iteration: result._iteration,
|
|
3734
|
+
signalType: this.config.completionSignal?.type,
|
|
3735
|
+
status: result.completionSummary?.status,
|
|
3736
|
+
blockingIssues: result.completionSummary?.blockingIssues.slice(0, 5)
|
|
3737
|
+
}
|
|
3738
|
+
});
|
|
3739
|
+
return true;
|
|
3740
|
+
}
|
|
3741
|
+
this.telemetry?.logEvent({
|
|
3742
|
+
name: "loop_terminated_completion_signal",
|
|
3743
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3744
|
+
properties: {
|
|
3745
|
+
iteration: result._iteration,
|
|
3746
|
+
signalType: this.config.completionSignal?.type
|
|
3747
|
+
}
|
|
3748
|
+
});
|
|
3749
|
+
this.terminate("completion_signal");
|
|
3750
|
+
return false;
|
|
3751
|
+
}
|
|
3752
|
+
const atBounds = result._iteration >= this.config.maxIterations;
|
|
3753
|
+
if (atBounds && isSemanticCheckBlocking(result.semanticValidation)) {
|
|
3754
|
+
this.telemetry?.logEvent({
|
|
3755
|
+
name: "loop_terminated_semantic_criteria_unsatisfied",
|
|
3756
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3757
|
+
properties: {
|
|
3758
|
+
iteration: result._iteration,
|
|
3759
|
+
context: "bounds_reached",
|
|
3760
|
+
movedCloser: result.semanticValidation?.progressResult?.movedCloser,
|
|
3761
|
+
satisfactionScore: result.semanticValidation?.satisfactionScore,
|
|
3762
|
+
totalACs: result.semanticValidation?.acResults?.length ?? 0,
|
|
3763
|
+
satisfiedACs: result.semanticValidation?.acResults?.filter((r) => r.satisfied).length ?? 0
|
|
3764
|
+
}
|
|
3765
|
+
});
|
|
3766
|
+
this.terminate("semantic_criteria_unsatisfied");
|
|
3767
|
+
return false;
|
|
3768
|
+
}
|
|
3769
|
+
const customGatesAtBoundsEvidence = customGatesAllowCompletion(result.customGateResults);
|
|
3770
|
+
const qualityGatesAtBoundsBlocking = qualityGatesHaveBlockingFailure(result.qualityGates, {
|
|
3771
|
+
customGatesProvideEvidence: customGatesAtBoundsEvidence
|
|
3772
|
+
});
|
|
3773
|
+
const qualityGatesAtBoundsOk = !this.config.runQualityGates || (qualityGatesAllowCompletion(result.qualityGates) || customGatesAtBoundsEvidence) && !qualityGatesAtBoundsBlocking;
|
|
3774
|
+
const customGatesAtBoundsOk = !customGatesHaveBlockingFailure(result.customGateResults);
|
|
3775
|
+
if (atBounds && this.config.validationMode !== "deterministic" && result.success === true && isSemanticCompletionSatisfied(result.semanticValidation) && this.hasSubstantiveCompletionEvidence(result) && qualityGatesAtBoundsOk && customGatesAtBoundsOk && !requirementsUnmet) {
|
|
3776
|
+
this.telemetry?.logEvent({
|
|
3777
|
+
name: "loop_terminated_semantic_complete",
|
|
3778
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3779
|
+
properties: {
|
|
3780
|
+
iteration: result._iteration,
|
|
3781
|
+
movedCloser: result.semanticValidation?.progressResult?.movedCloser,
|
|
3782
|
+
satisfactionScore: result.semanticValidation?.satisfactionScore,
|
|
3783
|
+
totalACs: result.semanticValidation?.acResults?.length ?? 0,
|
|
3784
|
+
satisfiedACs: result.semanticValidation?.acResults?.filter((r) => r.satisfied).length ?? 0
|
|
3785
|
+
}
|
|
3786
|
+
});
|
|
3787
|
+
this.terminate("semantic_complete");
|
|
3788
|
+
return false;
|
|
3789
|
+
}
|
|
3790
|
+
if (this.config.validationMode === "deterministic") {
|
|
3791
|
+
const allGatesPassed = result.qualityGates && result.qualityGates.length > 0 && result.qualityGates.every((g) => g.passed);
|
|
3792
|
+
const qualityGatesOk = qualityGatesAllowCompletion(result.qualityGates);
|
|
3793
|
+
const customGatesOk = customGatesAllowCompletion(result.customGateResults);
|
|
3794
|
+
const qualityGatesBlocking = qualityGatesHaveBlockingFailure(result.qualityGates, {
|
|
3795
|
+
customGatesProvideEvidence: customGatesOk
|
|
3796
|
+
});
|
|
3797
|
+
const customGatesBlocking = customGatesHaveBlockingFailure(result.customGateResults);
|
|
3798
|
+
if ((allGatesPassed || qualityGatesOk || customGatesOk) && !qualityGatesBlocking && !customGatesBlocking && !requirementsUnmet && completionStatusAllowsSuccess(result.completionSummary?.status)) {
|
|
3799
|
+
this.telemetry?.logEvent({
|
|
3800
|
+
name: "loop_terminated_deterministic_complete",
|
|
3801
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3802
|
+
properties: {
|
|
3803
|
+
iteration: result._iteration,
|
|
3804
|
+
gateCount: result.qualityGates?.length,
|
|
3805
|
+
customGateCount: result.customGateResults?.length,
|
|
3806
|
+
allPassed: allGatesPassed,
|
|
3807
|
+
preExistingFailuresOnly: !allGatesPassed && qualityGatesOk,
|
|
3808
|
+
preExistingFailures: result.qualityGates?.filter((g) => !g.passed && g.isRegression === false).map((g) => g.gateId)
|
|
3809
|
+
}
|
|
3810
|
+
});
|
|
3811
|
+
this.terminate("deterministic_complete");
|
|
3812
|
+
return false;
|
|
3813
|
+
}
|
|
3814
|
+
return true;
|
|
3815
|
+
}
|
|
3816
|
+
if (this.config.validationMode === "none") {
|
|
3817
|
+
if (result.judgeEvaluation?.recommendation === "terminate" && !requirementsUnmet) {
|
|
3818
|
+
this.terminate("ai_judge_recommendation");
|
|
3819
|
+
return false;
|
|
3820
|
+
}
|
|
3821
|
+
if (result.judgeEvaluation?.recommendation === "pivot") {
|
|
3822
|
+
await this.handlePivotRecommendation(result);
|
|
3823
|
+
}
|
|
3824
|
+
return true;
|
|
3825
|
+
}
|
|
3826
|
+
const completionThreshold = 0.8;
|
|
3827
|
+
const stableHighScore = result.progress.trend === "stable" && !result.progress.isSignificant && result.progress.score >= completionThreshold && result.progress.verificationUnavailable !== true && result.progress.toolingFailure !== true && !requirementsUnmet;
|
|
3828
|
+
const completionSummary = result.completionSummary;
|
|
3829
|
+
if (stableHighScore && completionSummary !== void 0 && completionStatusAllowsSuccess(completionSummary.status) && completionSummary.hasSubstantiveEvidence && completionSummary.blockingIssues.length === 0) {
|
|
3830
|
+
this.telemetry?.logEvent({
|
|
3831
|
+
name: "loop_terminated_heuristic_complete",
|
|
3832
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3833
|
+
properties: {
|
|
3834
|
+
iteration: result._iteration,
|
|
3835
|
+
progressScore: result.progress.score,
|
|
3836
|
+
trend: result.progress.trend
|
|
3837
|
+
}
|
|
3838
|
+
});
|
|
3839
|
+
this.terminate("heuristic_complete");
|
|
3840
|
+
return false;
|
|
3841
|
+
}
|
|
3842
|
+
if (!result.progress.isSignificant) {
|
|
3843
|
+
const recentResults = this.iterationHistory.slice(-this.config.progressConfig.windowSize);
|
|
3844
|
+
const stagnantCount = recentResults.filter((r) => !r.progress.isSignificant).length;
|
|
3845
|
+
if (stagnantCount >= this.config.progressConfig.windowSize) {
|
|
3846
|
+
if (result._iteration < this.config.maxIterations) {
|
|
3847
|
+
this.terminate("progress_stagnation");
|
|
3848
|
+
return false;
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
if (result.judgeEvaluation?.recommendation === "terminate") {
|
|
3853
|
+
this.terminate("ai_judge_recommendation");
|
|
3854
|
+
return false;
|
|
3855
|
+
}
|
|
3856
|
+
if (result.judgeEvaluation?.recommendation === "pivot") {
|
|
3857
|
+
await this.handlePivotRecommendation(result);
|
|
3858
|
+
}
|
|
3859
|
+
return true;
|
|
3860
|
+
}
|
|
3861
|
+
idleStopEnabledChecks() {
|
|
3862
|
+
return {
|
|
3863
|
+
qualityGates: this.config.runQualityGates === true,
|
|
3864
|
+
customGates: this.config.runQualityGates === true && (this.config.customGateCommands?.length ?? 0) > 0,
|
|
3865
|
+
qualityGatePolicy: this.config.qualityGatePolicy ?? (this.config.runQualityGates === true ? "enabled" : "not_configured")
|
|
3866
|
+
};
|
|
3867
|
+
}
|
|
3868
|
+
/**
|
|
3869
|
+
* After a mature delivery, stop on the next empty-diff iteration instead
|
|
3870
|
+
* of burning retries. Do not stop on the successful delivery itself — that
|
|
3871
|
+
* would bypass the completion-signal progress floor and semantic oracle.
|
|
3872
|
+
* Baseline-only green does not qualify.
|
|
3873
|
+
*/
|
|
3874
|
+
tryIdleStopAfterRealFirstDelivery(result) {
|
|
3875
|
+
const enabled = this.idleStopEnabledChecks();
|
|
3876
|
+
const snapshot = {
|
|
3877
|
+
success: result.success,
|
|
3878
|
+
iterationFingerprint: result.iterationFingerprint,
|
|
3879
|
+
error: result.error,
|
|
3880
|
+
qualityGates: result.qualityGates,
|
|
3881
|
+
customGateResults: result.customGateResults,
|
|
3882
|
+
requirements: result.requirements,
|
|
3883
|
+
completionSummary: result.completionSummary,
|
|
3884
|
+
semanticValidation: result.semanticValidation
|
|
3885
|
+
};
|
|
3886
|
+
const prior = this.iterationHistory.filter((iteration) => iteration !== result);
|
|
3887
|
+
const resolution = resolveIdleStopAfterRealFirstDelivery(prior, snapshot, enabled, {
|
|
3888
|
+
iterationChangeEvidenceTrusted: this.config.iterationChangeEvidenceTrusted !== false
|
|
3889
|
+
});
|
|
3890
|
+
if (!resolution.shouldStop) {
|
|
3891
|
+
return false;
|
|
3892
|
+
}
|
|
3893
|
+
this.idleStoppedAfterRealFirstDelivery = true;
|
|
3894
|
+
const priorResult = prior[resolution.priorIterationIndex];
|
|
3895
|
+
result.earlyFinalization = {
|
|
3896
|
+
reason: "mature_delivery_followed_by_no_op",
|
|
3897
|
+
priorIteration: Number(priorResult?._iteration ?? resolution.priorIterationIndex + 1),
|
|
3898
|
+
verification: resolution.verification
|
|
3899
|
+
};
|
|
3900
|
+
this.telemetry?.logEvent({
|
|
3901
|
+
name: "loop_terminated_idle_after_first_delivery",
|
|
3902
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3903
|
+
properties: {
|
|
3904
|
+
iteration: result._iteration,
|
|
3905
|
+
emptyDiffAfterDelivery: true,
|
|
3906
|
+
gateCount: result.qualityGates?.length ?? 0,
|
|
3907
|
+
verification: resolution.verification
|
|
3908
|
+
}
|
|
3909
|
+
});
|
|
3910
|
+
this.terminate("deterministic_complete");
|
|
3911
|
+
return true;
|
|
3912
|
+
}
|
|
3913
|
+
/**
|
|
3914
|
+
* Decide whether a failed iteration may retry. Terminates the loop with
|
|
3915
|
+
* 'max_retries_exceeded' once the backoff/retry budget is exhausted so retry
|
|
3916
|
+
* exhaustion surfaces as a specific termination reason rather than a generic
|
|
3917
|
+
* failure. backoffAttempts is incremented by applyBackoff() after each
|
|
3918
|
+
* retry-granting failure, so this check gates the NEXT retry.
|
|
3919
|
+
*/
|
|
3920
|
+
continueAfterFailureOrTerminate() {
|
|
3921
|
+
if (this.backoffAttempts >= this.config.backoffConfig.maxRetries) {
|
|
3922
|
+
this.terminate("max_retries_exceeded");
|
|
3923
|
+
return false;
|
|
3924
|
+
}
|
|
3925
|
+
return true;
|
|
3926
|
+
}
|
|
3927
|
+
/**
|
|
3928
|
+
* Apply exponential backoff for failed iterations
|
|
3929
|
+
*/
|
|
3930
|
+
async applyBackoff() {
|
|
3931
|
+
if (this.backoffAttempts >= this.config.backoffConfig.maxRetries) {
|
|
3932
|
+
this.terminate("max_retries_exceeded");
|
|
3933
|
+
return;
|
|
3934
|
+
}
|
|
3935
|
+
const delay = calculateBackoffDelay(this.backoffAttempts, this.config.backoffConfig);
|
|
3936
|
+
this.backoffAttempts++;
|
|
3937
|
+
this.emit("backoff_triggered", {
|
|
3938
|
+
type: "backoff_triggered",
|
|
3939
|
+
delay,
|
|
3940
|
+
reason: "iteration_failed"
|
|
3941
|
+
});
|
|
3942
|
+
await abortableDelay(delay, this.config.abortSignal);
|
|
3943
|
+
}
|
|
3944
|
+
/**
|
|
3945
|
+
* Check resource limits and emit warnings.
|
|
3946
|
+
* Near-limit warnings are memory-only; CPU/process stay diagnostic-only.
|
|
3947
|
+
*/
|
|
3948
|
+
checkResourceLimits() {
|
|
3949
|
+
const resources = getResourceUsage();
|
|
3950
|
+
const memoryMB = resources.memory.heapUsed / (1024 * 1024);
|
|
3951
|
+
if (memoryMB > this.config.resourceLimits.maxMemoryMB * 0.8) {
|
|
3952
|
+
if (!this.resourceWarnings.has("memory")) {
|
|
3953
|
+
this.resourceWarnings.add("memory");
|
|
3954
|
+
this.emit("resource_warning", {
|
|
3955
|
+
type: "resource_warning",
|
|
3956
|
+
resource: "memory",
|
|
3957
|
+
usage: memoryMB,
|
|
3958
|
+
limit: this.config.resourceLimits.maxMemoryMB
|
|
3959
|
+
});
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
}
|
|
3963
|
+
/**
|
|
3964
|
+
* Set up event forwarding to dependencies
|
|
3965
|
+
*/
|
|
3966
|
+
setupEventForwarding() {
|
|
3967
|
+
if (this.resultStreamer) {
|
|
3968
|
+
this.on("iteration_complete", (data) => {
|
|
3969
|
+
this.resultStreamer?.emit("iterationComplete", data);
|
|
3970
|
+
});
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3973
|
+
/**
|
|
3974
|
+
* Set up cleanup handlers
|
|
3975
|
+
*/
|
|
3976
|
+
setupCleanupHandlers() {
|
|
3977
|
+
signalCoordinator.register(this.instanceId, async () => {
|
|
3978
|
+
await this.cleanup();
|
|
3979
|
+
});
|
|
3980
|
+
this.cleanupHandlers = [() => signalCoordinator.unregister(this.instanceId)];
|
|
3981
|
+
}
|
|
3982
|
+
/**
|
|
3983
|
+
* Clean up resources and remove event listeners
|
|
3984
|
+
*/
|
|
3985
|
+
close() {
|
|
3986
|
+
this.cleanupHandlers.forEach((cleanup) => {
|
|
3987
|
+
try {
|
|
3988
|
+
cleanup();
|
|
3989
|
+
} catch (_error) {
|
|
3990
|
+
}
|
|
3991
|
+
});
|
|
3992
|
+
this.cleanupHandlers = [];
|
|
3993
|
+
this.removeAllListeners();
|
|
3994
|
+
}
|
|
3995
|
+
/**
|
|
3996
|
+
* Clean up resources
|
|
3997
|
+
*/
|
|
3998
|
+
async cleanup() {
|
|
3999
|
+
if (this.cleanupStarted) return;
|
|
4000
|
+
this.cleanupStarted = true;
|
|
4001
|
+
try {
|
|
4002
|
+
await this.recursionTracker.exit();
|
|
4003
|
+
if (this.telemetry) {
|
|
4004
|
+
await this.telemetry.flush();
|
|
4005
|
+
}
|
|
4006
|
+
this.emit("loop_cleanup", { type: "loop_cleanup", state: this.state });
|
|
4007
|
+
} catch (error) {
|
|
4008
|
+
console.error("Error during cleanup:", error);
|
|
4009
|
+
}
|
|
4010
|
+
}
|
|
4011
|
+
};
|
|
4012
|
+
function createAutonomousLoopController(config = {}, dependencies = {}) {
|
|
4013
|
+
return new AutonomousLoopController(config, dependencies);
|
|
4014
|
+
}
|
|
4015
|
+
var DEFAULT_COMPLETION_SIGNALS = [
|
|
4016
|
+
"xml:<task_complete/>",
|
|
4017
|
+
"xml:<TASK_COMPLETE/>",
|
|
4018
|
+
"regex:task\\s+complete|task\\s+finished|all\\s+done"
|
|
4019
|
+
];
|
|
4020
|
+
function createConfigFromEnv(cliFlags = {}) {
|
|
4021
|
+
const readPositiveNumber = (envName, fallback, max) => {
|
|
4022
|
+
const raw = readRawEnv(envName);
|
|
4023
|
+
if (raw === void 0 || raw === "") return fallback;
|
|
4024
|
+
const value = Number(raw);
|
|
4025
|
+
if (!Number.isFinite(value) || value <= 0) return fallback;
|
|
4026
|
+
return max === void 0 ? value : Math.min(value, max);
|
|
4027
|
+
};
|
|
4028
|
+
const readUnitInterval = (envName, fallback) => {
|
|
4029
|
+
const raw = readRawEnv(envName);
|
|
4030
|
+
if (raw === void 0 || raw === "") return fallback;
|
|
4031
|
+
const value = Number(raw);
|
|
4032
|
+
return Number.isFinite(value) && value >= 0 && value <= 1 ? value : fallback;
|
|
4033
|
+
};
|
|
4034
|
+
const maxIterations = readPositiveNumber(
|
|
4035
|
+
POETIC_AUTOLOOP_MAX_ITERATIONS,
|
|
4036
|
+
3,
|
|
4037
|
+
MAX_AUTOLOOP_ENV_ITERATIONS
|
|
4038
|
+
);
|
|
4039
|
+
const timeboxMs = resolveAutoloopTimeboxMs();
|
|
4040
|
+
const minProgress = readUnitInterval(POETIC_AUTOLOOP_MIN_PROGRESS, 0.05);
|
|
4041
|
+
const maxMemoryRaw = readRawEnv(POETIC_AUTOLOOP_MAX_MEMORY);
|
|
4042
|
+
const maxCpuRaw = readRawEnv(POETIC_AUTOLOOP_MAX_CPU);
|
|
4043
|
+
const maxProcessesRaw = readRawEnv(POETIC_AUTOLOOP_MAX_PROCESSES);
|
|
4044
|
+
const maxMemoryMB = maxMemoryRaw === void 0 ? DEFAULT_AUTOLOOP_RESOURCE_LIMITS.maxMemoryMB : readPositiveNumber(
|
|
4045
|
+
POETIC_AUTOLOOP_MAX_MEMORY,
|
|
4046
|
+
DEFAULT_AUTOLOOP_RESOURCE_LIMITS.maxMemoryMB
|
|
4047
|
+
);
|
|
4048
|
+
const maxCpuPercent = maxCpuRaw === void 0 ? DEFAULT_AUTOLOOP_RESOURCE_LIMITS.maxCpuPercent : readPositiveNumber(POETIC_AUTOLOOP_MAX_CPU, DEFAULT_AUTOLOOP_RESOURCE_LIMITS.maxCpuPercent);
|
|
4049
|
+
const maxProcesses = maxProcessesRaw === void 0 ? DEFAULT_AUTOLOOP_RESOURCE_LIMITS.maxProcesses : readPositiveNumber(
|
|
4050
|
+
POETIC_AUTOLOOP_MAX_PROCESSES,
|
|
4051
|
+
DEFAULT_AUTOLOOP_RESOURCE_LIMITS.maxProcesses,
|
|
4052
|
+
MAX_AUTOLOOP_ENV_PROCESSES
|
|
4053
|
+
);
|
|
4054
|
+
const cliValidation = cliFlags["--autoloop-validation"];
|
|
4055
|
+
const validationMode = resolveAutoloopValidationMode(cliValidation);
|
|
4056
|
+
const completionSignalRaw = validationMode === "deterministic" ? void 0 : cliFlags["--autoloop-completion-signal"] || readEnv(POETIC_AUTOLOOP_COMPLETION_SIGNAL).value;
|
|
4057
|
+
let completionSignal;
|
|
4058
|
+
if (completionSignalRaw) {
|
|
4059
|
+
completionSignal = parseCompletionSignal(completionSignalRaw) ?? void 0;
|
|
4060
|
+
} else if (validationMode !== "deterministic" && validationMode !== "none") {
|
|
4061
|
+
for (const defaultSignal of DEFAULT_COMPLETION_SIGNALS) {
|
|
4062
|
+
const parsed = parseCompletionSignal(defaultSignal);
|
|
4063
|
+
if (parsed) {
|
|
4064
|
+
completionSignal = parsed;
|
|
4065
|
+
break;
|
|
4066
|
+
}
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
const qualityGatesModeRaw = cliFlags["--autoloop-quality-gates-mode"] || readRawEnv(POETIC_AUTOLOOP_QUALITY_GATES_MODE);
|
|
4070
|
+
const qualityGatesMode = qualityGatesModeRaw === "full" || qualityGatesModeRaw === "safe" || qualityGatesModeRaw === "fast" ? qualityGatesModeRaw : "fast";
|
|
4071
|
+
return {
|
|
4072
|
+
maxIterations: createIterationCount(maxIterations),
|
|
4073
|
+
timeboxMs: createDurationMs(timeboxMs),
|
|
4074
|
+
minProgressThreshold: createProgressScore(minProgress),
|
|
4075
|
+
useAIJudge: readEnv(POETIC_AUTOLOOP_JUDGE).value === "1" || cliFlags["--autoloop-judge"] === true,
|
|
4076
|
+
runQualityGates: cliFlags["--autoloop-quality-gates"] === true,
|
|
4077
|
+
qualityGatesMode,
|
|
4078
|
+
resourceLimits: {
|
|
4079
|
+
maxMemoryMB,
|
|
4080
|
+
maxCpuPercent,
|
|
4081
|
+
maxProcesses
|
|
4082
|
+
},
|
|
4083
|
+
...completionSignal ? { completionSignal } : {},
|
|
4084
|
+
validationMode
|
|
4085
|
+
};
|
|
4086
|
+
}
|
|
4087
|
+
var autonomous_loop_controller_default = AutonomousLoopController;
|
|
4088
|
+
export {
|
|
4089
|
+
AutonomousLoopController,
|
|
4090
|
+
COMPLETION_SIGNAL_TAIL_BYTES,
|
|
4091
|
+
DEFAULT_AUTOLOOP_RESOURCE_LIMITS,
|
|
4092
|
+
DEFAULT_COMPLETION_SIGNALS,
|
|
4093
|
+
MAX_FIRST_ITERATION_RESERVE_MS,
|
|
4094
|
+
MIN_FIRST_ITERATION_RESERVE_MS,
|
|
4095
|
+
buildCustomGateId,
|
|
4096
|
+
classifyCoverageBaselineComparison,
|
|
4097
|
+
classifyError,
|
|
4098
|
+
classifyQualityGateFailure,
|
|
4099
|
+
createAutonomousLoopController,
|
|
4100
|
+
createConfigFromEnv,
|
|
4101
|
+
createDurationMs,
|
|
4102
|
+
createIterationCount,
|
|
4103
|
+
createProgressScore,
|
|
4104
|
+
autonomous_loop_controller_default as default,
|
|
4105
|
+
extractFailureCountWithMethod,
|
|
4106
|
+
hasCompilationProgressSignal,
|
|
4107
|
+
isBenignSemanticSkip,
|
|
4108
|
+
isEmptyDiffIdleFailure,
|
|
4109
|
+
isRealFirstDeliveryIteration,
|
|
4110
|
+
isSemanticCompletionSatisfied,
|
|
4111
|
+
isSemanticErrorSkip,
|
|
4112
|
+
matchesCompletionSignal,
|
|
4113
|
+
parseCompletionSignal,
|
|
4114
|
+
resolveIdleStopAfterRealFirstDelivery,
|
|
4115
|
+
selectTaskOutputForChecks,
|
|
4116
|
+
semanticDisabled,
|
|
4117
|
+
semanticSkipped,
|
|
4118
|
+
shouldIdleStopAfterRealFirstDelivery
|
|
4119
|
+
};
|
|
4120
|
+
//# sourceMappingURL=autonomous-loop-controller-PW4XVFGQ.js.map
|