@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,1984 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CIRCUIT_BREAKER_WARNING_INTERVAL_MS,
|
|
3
|
+
EXPONENTIAL_BACKOFF_MULTIPLIER,
|
|
4
|
+
GITHUB_API_RETRY_ATTEMPTS,
|
|
5
|
+
GITHUB_API_RETRY_BACKOFF_CAP_MS,
|
|
6
|
+
MAX_FILE_COUNT,
|
|
7
|
+
MAX_FILE_SIZE_BYTES,
|
|
8
|
+
MS_PER_SECOND
|
|
9
|
+
} from "./chunk-3AOKYKA7.js";
|
|
10
|
+
import {
|
|
11
|
+
recordMetric
|
|
12
|
+
} from "./chunk-5RBHQYDB.js";
|
|
13
|
+
import {
|
|
14
|
+
enqueueRemoteBranchCleanup,
|
|
15
|
+
isRemoteBranchMissingError,
|
|
16
|
+
isRetryableRemoteDeleteError,
|
|
17
|
+
resolveExpectedRemoteShaForQueuedBranch
|
|
18
|
+
} from "./chunk-BXI4NXL3.js";
|
|
19
|
+
import {
|
|
20
|
+
resolveVariantStrategy
|
|
21
|
+
} from "./chunk-LWTN3WRV.js";
|
|
22
|
+
import {
|
|
23
|
+
getWorktreeManager
|
|
24
|
+
} from "./chunk-4IYIZQWV.js";
|
|
25
|
+
import {
|
|
26
|
+
gitLock
|
|
27
|
+
} from "./chunk-N65O4XTH.js";
|
|
28
|
+
import {
|
|
29
|
+
matchesErrorPattern
|
|
30
|
+
} from "./chunk-2YFUIER7.js";
|
|
31
|
+
import {
|
|
32
|
+
parseJsonWithContext
|
|
33
|
+
} from "./chunk-QVZMFDYG.js";
|
|
34
|
+
import {
|
|
35
|
+
emitTelemetryFallbackWarning
|
|
36
|
+
} from "./chunk-YMX76IOS.js";
|
|
37
|
+
import {
|
|
38
|
+
isEphemeralPoeticBranchDeletionCandidate,
|
|
39
|
+
resolveDefaultBranch
|
|
40
|
+
} from "./chunk-XQD2B6BB.js";
|
|
41
|
+
import {
|
|
42
|
+
execGit
|
|
43
|
+
} from "./chunk-KNDYMVWN.js";
|
|
44
|
+
import {
|
|
45
|
+
formatBytes
|
|
46
|
+
} from "./chunk-JLS65NUQ.js";
|
|
47
|
+
import {
|
|
48
|
+
GitError,
|
|
49
|
+
PRCreationError,
|
|
50
|
+
wrapError
|
|
51
|
+
} from "./chunk-LUVKFFWR.js";
|
|
52
|
+
import {
|
|
53
|
+
findProjectRoot
|
|
54
|
+
} from "./chunk-L6OM4A22.js";
|
|
55
|
+
import {
|
|
56
|
+
emitWarning
|
|
57
|
+
} from "./chunk-EJGCZGUF.js";
|
|
58
|
+
|
|
59
|
+
// src/orchestrator/github-pr-manager.ts
|
|
60
|
+
import { execa as execa2 } from "execa";
|
|
61
|
+
|
|
62
|
+
// src/orchestrator/pr-manager-core.ts
|
|
63
|
+
import * as fsp2 from "fs/promises";
|
|
64
|
+
import * as path2 from "path";
|
|
65
|
+
import chalk2 from "chalk";
|
|
66
|
+
import { execa } from "execa";
|
|
67
|
+
|
|
68
|
+
// src/core/cleanup/artifact-lifecycle-manager.ts
|
|
69
|
+
import { createHash } from "crypto";
|
|
70
|
+
import { EventEmitter } from "events";
|
|
71
|
+
import * as fsp from "fs/promises";
|
|
72
|
+
import * as path from "path";
|
|
73
|
+
import { promisify } from "util";
|
|
74
|
+
import * as zlib from "zlib";
|
|
75
|
+
import chalk from "chalk";
|
|
76
|
+
var SmartAgingAlgorithm = class {
|
|
77
|
+
weights = {
|
|
78
|
+
age: 0.3,
|
|
79
|
+
size: 0.2,
|
|
80
|
+
access: 0.25,
|
|
81
|
+
tags: 0.15,
|
|
82
|
+
dependencies: 0.1
|
|
83
|
+
};
|
|
84
|
+
calculateRetentionScore(metadata) {
|
|
85
|
+
const now = /* @__PURE__ */ new Date();
|
|
86
|
+
const ageDays = (now.getTime() - metadata.createdAt.getTime()) / (1e3 * 60 * 60 * 24);
|
|
87
|
+
const ageScore = Math.max(0, 1 - ageDays / 365);
|
|
88
|
+
const sizeScore = Math.min(1, metadata.size / (10 * 1024 * 1024));
|
|
89
|
+
const accessDays = (now.getTime() - metadata.lastAccessed.getTime()) / (1e3 * 60 * 60 * 24);
|
|
90
|
+
const accessScore = Math.max(0, 1 - accessDays / 30);
|
|
91
|
+
const tagScore = this.calculateTagScore(metadata.tags);
|
|
92
|
+
const dependencyScore = 0.5;
|
|
93
|
+
return ageScore * this.weights.age + sizeScore * this.weights.size + accessScore * this.weights.access + tagScore * this.weights.tags + dependencyScore * this.weights.dependencies;
|
|
94
|
+
}
|
|
95
|
+
calculateTagScore(tags) {
|
|
96
|
+
const importantTags = ["critical", "production", "reference", "template"];
|
|
97
|
+
let score = 0;
|
|
98
|
+
for (const tag of tags) {
|
|
99
|
+
if (importantTags.includes(tag.toLowerCase())) {
|
|
100
|
+
score += 0.3;
|
|
101
|
+
} else if (tag.startsWith("v")) {
|
|
102
|
+
score += 0.1;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return Math.min(1, score);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
var WorkerPool = class {
|
|
109
|
+
queue = [];
|
|
110
|
+
maxWorkers;
|
|
111
|
+
activeWorkers = 0;
|
|
112
|
+
constructor(maxWorkers) {
|
|
113
|
+
this.maxWorkers = maxWorkers;
|
|
114
|
+
}
|
|
115
|
+
async execute(task) {
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
const wrappedTask = async () => {
|
|
118
|
+
try {
|
|
119
|
+
const result = await task();
|
|
120
|
+
resolve(result);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
reject(error);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
if (this.activeWorkers < this.maxWorkers) {
|
|
126
|
+
this.runTask(wrappedTask);
|
|
127
|
+
} else {
|
|
128
|
+
this.queue.push(wrappedTask);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
async runTask(task) {
|
|
133
|
+
this.activeWorkers++;
|
|
134
|
+
try {
|
|
135
|
+
await task();
|
|
136
|
+
} finally {
|
|
137
|
+
this.activeWorkers--;
|
|
138
|
+
if (this.queue.length > 0) {
|
|
139
|
+
const nextTask = this.queue.shift();
|
|
140
|
+
if (nextTask) {
|
|
141
|
+
this.runTask(nextTask);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async close() {
|
|
147
|
+
while (this.activeWorkers > 0) {
|
|
148
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
async function compressBuffer(data, algorithm = "gzip") {
|
|
153
|
+
switch (algorithm) {
|
|
154
|
+
case "gzip":
|
|
155
|
+
return promisify(zlib.gzip)(data);
|
|
156
|
+
case "deflate":
|
|
157
|
+
return promisify(zlib.deflate)(data);
|
|
158
|
+
case "brotli":
|
|
159
|
+
return promisify(zlib.brotliCompress)(data);
|
|
160
|
+
default:
|
|
161
|
+
throw new Error(`Unsupported compression algorithm: ${algorithm}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
var ArtifactLifecycleManager = class extends EventEmitter {
|
|
165
|
+
config;
|
|
166
|
+
smartAging;
|
|
167
|
+
workerPool;
|
|
168
|
+
telemetry = /* @__PURE__ */ new Map();
|
|
169
|
+
isRunning = false;
|
|
170
|
+
constructor(config = {}) {
|
|
171
|
+
super();
|
|
172
|
+
this.config = this.mergeWithDefaults(config);
|
|
173
|
+
this.smartAging = new SmartAgingAlgorithm();
|
|
174
|
+
this.workerPool = new WorkerPool(this.config.parallelWorkers);
|
|
175
|
+
this.setupEventHandlers();
|
|
176
|
+
}
|
|
177
|
+
mergeWithDefaults(config) {
|
|
178
|
+
const defaults = {
|
|
179
|
+
basePath: ".poetic/implementations",
|
|
180
|
+
retentionPolicy: {
|
|
181
|
+
maxAgeDays: 30,
|
|
182
|
+
maxSizeBytes: 100 * 1024 * 1024,
|
|
183
|
+
// 100MB
|
|
184
|
+
maxCount: 1e3,
|
|
185
|
+
archiveBeforeDelete: true,
|
|
186
|
+
compressionLevel: 6,
|
|
187
|
+
preserveMetadata: true,
|
|
188
|
+
smartAging: true,
|
|
189
|
+
priorityTags: /* @__PURE__ */ new Set(["critical", "production", "reference"]),
|
|
190
|
+
exclusionPatterns: [/\.git\//, /node_modules\//, /\.DS_Store$/]
|
|
191
|
+
},
|
|
192
|
+
parallelWorkers: 4,
|
|
193
|
+
batchSize: 50,
|
|
194
|
+
enableTelemetry: true,
|
|
195
|
+
enableSmartAging: true,
|
|
196
|
+
enableCompression: true,
|
|
197
|
+
archiveFormat: "zip",
|
|
198
|
+
dryRun: false,
|
|
199
|
+
verbose: false
|
|
200
|
+
};
|
|
201
|
+
return this.deepMerge(defaults, config);
|
|
202
|
+
}
|
|
203
|
+
deepMerge(target, source) {
|
|
204
|
+
const result = { ...target };
|
|
205
|
+
for (const key in source) {
|
|
206
|
+
if (source[key] !== void 0) {
|
|
207
|
+
if (typeof source[key] === "object" && source[key] !== null && !Array.isArray(source[key])) {
|
|
208
|
+
result[key] = this.deepMerge(
|
|
209
|
+
target[key],
|
|
210
|
+
source[key]
|
|
211
|
+
);
|
|
212
|
+
} else {
|
|
213
|
+
result[key] = source[key];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
setupEventHandlers() {
|
|
220
|
+
this.on("cleanup:error", (error) => {
|
|
221
|
+
if (this.config.verbose) {
|
|
222
|
+
console.error(chalk.red(`Cleanup error: ${error.message}`));
|
|
223
|
+
if (error.suggestion) {
|
|
224
|
+
console.error(chalk.yellow(`Suggestion: ${error.suggestion}`));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Scan directory for artifacts and build metadata.
|
|
231
|
+
*
|
|
232
|
+
* Walks the base path RECURSIVELY, treating every nested file as an
|
|
233
|
+
* individual artifact. Per-file recursion (rather than treating a
|
|
234
|
+
* first-level directory as one archive unit) is deliberate: it preserves
|
|
235
|
+
* the existing archive format exactly — each artifact is compressed to a
|
|
236
|
+
* single `.archive/<id>.<format>` entry with an optional metadata sidecar —
|
|
237
|
+
* and each nested file's own age/retention score decides its fate, so
|
|
238
|
+
* young files inside an otherwise-old directory always survive.
|
|
239
|
+
*
|
|
240
|
+
* The `.archive` directory is never descended into: archived content is
|
|
241
|
+
* terminal and must not be re-scanned as live artifacts.
|
|
242
|
+
*/
|
|
243
|
+
async scanArtifacts() {
|
|
244
|
+
const startTime = Date.now();
|
|
245
|
+
const artifacts = [];
|
|
246
|
+
try {
|
|
247
|
+
await fsp.mkdir(this.config.basePath, { recursive: true });
|
|
248
|
+
await this.scanDirectory(this.config.basePath, artifacts);
|
|
249
|
+
if (this.config.enableTelemetry) {
|
|
250
|
+
this.telemetry.set("scan:duration", Date.now() - startTime);
|
|
251
|
+
this.telemetry.set("scan:artifactsFound", artifacts.length);
|
|
252
|
+
}
|
|
253
|
+
return artifacts;
|
|
254
|
+
} catch (error) {
|
|
255
|
+
const cleanupError = {
|
|
256
|
+
code: "SCAN_ERROR",
|
|
257
|
+
message: `Failed to scan artifacts: ${error instanceof Error ? error.message : String(error)}`,
|
|
258
|
+
artifactPath: this.config.basePath,
|
|
259
|
+
operation: "scan",
|
|
260
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
261
|
+
recoverable: true,
|
|
262
|
+
suggestion: "Check directory permissions and ensure path exists"
|
|
263
|
+
};
|
|
264
|
+
this.emit("cleanup:error", cleanupError);
|
|
265
|
+
throw error;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Recursively walk a directory, collecting artifact metadata for every
|
|
270
|
+
* nested file. Exclusion patterns are tested against the path relative to
|
|
271
|
+
* the base path (with `/` separators) so directory patterns like
|
|
272
|
+
* `/\.git\//` and `/node_modules\//` match at any depth; for first-level
|
|
273
|
+
* files the relative path equals the filename, preserving prior behavior.
|
|
274
|
+
*/
|
|
275
|
+
async scanDirectory(dir, artifacts) {
|
|
276
|
+
const entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
277
|
+
for (const entry of entries) {
|
|
278
|
+
const entryPath = path.join(dir, entry.name);
|
|
279
|
+
const relativePath = path.relative(this.config.basePath, entryPath).split(path.sep).join("/");
|
|
280
|
+
if (entry.isDirectory()) {
|
|
281
|
+
if (dir === this.config.basePath && entry.name === ".archive") {
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (this.shouldExclude(`${relativePath}/`)) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
await this.scanDirectory(entryPath, artifacts);
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (entry.isFile() && !this.shouldExclude(relativePath)) {
|
|
291
|
+
const metadata = await this.buildArtifactMetadata(entryPath);
|
|
292
|
+
if (metadata) {
|
|
293
|
+
artifacts.push(metadata);
|
|
294
|
+
this.emit("artifact:discovered", metadata);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
shouldExclude(relativePath) {
|
|
300
|
+
return this.config.retentionPolicy.exclusionPatterns.some(
|
|
301
|
+
(pattern) => pattern.test(relativePath)
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Derive a stable artifact id from the path relative to the base path.
|
|
306
|
+
* Path separators become `__` so nested files with the same basename get
|
|
307
|
+
* distinct archive entries; first-level files keep their historical
|
|
308
|
+
* basename-derived ids.
|
|
309
|
+
*
|
|
310
|
+
* Collision hardening: the plain `__` join is not injective when a path
|
|
311
|
+
* segment itself contains `_` (e.g. `a/b__c.md` and `a/b/c.md` both join
|
|
312
|
+
* to `a__b__c`, so the second archive entry would overwrite the first and
|
|
313
|
+
* both originals would then be deleted). To keep the encoding injective
|
|
314
|
+
* without renaming any existing archive entries, ids stay the plain join
|
|
315
|
+
* when no segment contains `_` (the historical format — nothing parses ids
|
|
316
|
+
* back into paths, and all underscore-free ids are unambiguous), and only
|
|
317
|
+
* ambiguous paths (any segment containing `_`) get a deterministic
|
|
318
|
+
* `--<sha256(relPath)[0..8]>` suffix. Every id containing `_` therefore
|
|
319
|
+
* carries a path-hash discriminator, so distinct paths produce distinct
|
|
320
|
+
* ids (modulo an 8-hex-digit hash collision between two different paths,
|
|
321
|
+
* which is accepted as negligible).
|
|
322
|
+
*/
|
|
323
|
+
artifactId(artifactPath) {
|
|
324
|
+
const relative2 = path.relative(this.config.basePath, artifactPath);
|
|
325
|
+
const withoutExt = relative2.slice(0, relative2.length - path.extname(relative2).length);
|
|
326
|
+
const segments = withoutExt.split(path.sep);
|
|
327
|
+
const joined = segments.join("__");
|
|
328
|
+
if (!segments.some((segment) => segment.includes("_"))) {
|
|
329
|
+
return joined;
|
|
330
|
+
}
|
|
331
|
+
const pathHash = createHash("sha256").update(relative2.split(path.sep).join("/")).digest("hex").slice(0, 8);
|
|
332
|
+
return `${joined}--${pathHash}`;
|
|
333
|
+
}
|
|
334
|
+
async buildArtifactMetadata(artifactPath) {
|
|
335
|
+
try {
|
|
336
|
+
const stats = await fsp.stat(artifactPath);
|
|
337
|
+
const content = await fsp.readFile(artifactPath);
|
|
338
|
+
const checksum = createHash("sha256").update(content).digest("hex");
|
|
339
|
+
const tags = this.extractTags(artifactPath, content);
|
|
340
|
+
const baseMetadata = {
|
|
341
|
+
id: this.artifactId(artifactPath),
|
|
342
|
+
path: artifactPath,
|
|
343
|
+
size: stats.size,
|
|
344
|
+
createdAt: stats.birthtime,
|
|
345
|
+
lastAccessed: stats.atime,
|
|
346
|
+
lastModified: stats.mtime,
|
|
347
|
+
checksum,
|
|
348
|
+
tags
|
|
349
|
+
};
|
|
350
|
+
const retentionScore = this.config.enableSmartAging ? this.smartAging.calculateRetentionScore(baseMetadata) : 0.5;
|
|
351
|
+
const metadata = {
|
|
352
|
+
...baseMetadata,
|
|
353
|
+
retentionScore
|
|
354
|
+
};
|
|
355
|
+
this.emit("retention:scored", metadata, retentionScore);
|
|
356
|
+
return metadata;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
if (this.config.verbose) {
|
|
359
|
+
emitWarning(
|
|
360
|
+
"WS-003",
|
|
361
|
+
{
|
|
362
|
+
subsystem: "cleanup",
|
|
363
|
+
executionPhase: "execution"
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
severity: "WARN" /* WARN */,
|
|
367
|
+
metadata: {
|
|
368
|
+
artifactPath,
|
|
369
|
+
error: error instanceof Error ? error.message : String(error),
|
|
370
|
+
operation: "buildMetadata"
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
extractTags(artifactPath, content) {
|
|
379
|
+
const tags = /* @__PURE__ */ new Set();
|
|
380
|
+
const filename = path.basename(artifactPath);
|
|
381
|
+
const filenameTags = filename.match(/-([a-z]+)-/gi);
|
|
382
|
+
if (filenameTags) {
|
|
383
|
+
filenameTags.forEach((tag) => {
|
|
384
|
+
tags.add(tag.slice(1, -1).toLowerCase());
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
const contentStr = content.toString("utf8", 0, Math.min(1024, content.length));
|
|
388
|
+
const yamlMatch = contentStr.match(/^---\s*\n([\s\S]*?)\n---/m);
|
|
389
|
+
if (yamlMatch) {
|
|
390
|
+
const yamlContent = yamlMatch[1] ?? "";
|
|
391
|
+
const tagMatches = yamlContent.match(/tags?:\s*\[(.*?)\]/i);
|
|
392
|
+
if (tagMatches) {
|
|
393
|
+
const list = tagMatches[1] ?? "";
|
|
394
|
+
list.split(",").forEach((tag) => {
|
|
395
|
+
const cleanTag = tag.trim().replace(/['"]/g, "");
|
|
396
|
+
if (cleanTag) tags.add(cleanTag.toLowerCase());
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return tags;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Archive artifacts before deletion
|
|
404
|
+
*/
|
|
405
|
+
async archiveArtifacts(artifacts, options = {}) {
|
|
406
|
+
const dryRun = options.dryRun ?? this.config.dryRun;
|
|
407
|
+
const startTime = Date.now();
|
|
408
|
+
let artifactsProcessed = 0;
|
|
409
|
+
let bytesProcessed = 0;
|
|
410
|
+
const errors = [];
|
|
411
|
+
this.emit("cleanup:started", this.config.retentionPolicy);
|
|
412
|
+
try {
|
|
413
|
+
const archiveDir = path.join(this.config.basePath, ".archive");
|
|
414
|
+
if (!dryRun) {
|
|
415
|
+
await fsp.mkdir(archiveDir, { recursive: true });
|
|
416
|
+
}
|
|
417
|
+
const archivePromises = artifacts.map(
|
|
418
|
+
(artifact) => this.workerPool.execute(() => this.archiveSingleArtifact(artifact, archiveDir, dryRun))
|
|
419
|
+
);
|
|
420
|
+
const results = await Promise.allSettled(archivePromises);
|
|
421
|
+
results.forEach((result, i) => {
|
|
422
|
+
const artifact = artifacts[i];
|
|
423
|
+
if (!artifact) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
if (result.status === "fulfilled") {
|
|
427
|
+
artifactsProcessed++;
|
|
428
|
+
bytesProcessed += artifact.size;
|
|
429
|
+
this.emit("artifact:archived", artifact, result.value);
|
|
430
|
+
} else {
|
|
431
|
+
const error = {
|
|
432
|
+
code: "ARCHIVE_ERROR",
|
|
433
|
+
message: `Failed to archive ${artifact.path}: ${result.reason}`,
|
|
434
|
+
artifactPath: artifact.path,
|
|
435
|
+
operation: "archive",
|
|
436
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
437
|
+
recoverable: true,
|
|
438
|
+
suggestion: "Check disk space and permissions"
|
|
439
|
+
};
|
|
440
|
+
errors.push(error);
|
|
441
|
+
this.emit("cleanup:error", error);
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
const duration = Date.now() - startTime;
|
|
445
|
+
const efficiency = artifactsProcessed / artifacts.length;
|
|
446
|
+
const cleanupResult = {
|
|
447
|
+
operation: "archive",
|
|
448
|
+
artifactsProcessed,
|
|
449
|
+
bytesProcessed,
|
|
450
|
+
bytesFreed: 0,
|
|
451
|
+
// Archives don't free space immediately
|
|
452
|
+
errors,
|
|
453
|
+
duration,
|
|
454
|
+
efficiency
|
|
455
|
+
};
|
|
456
|
+
this.emit("cleanup:completed", cleanupResult);
|
|
457
|
+
return cleanupResult;
|
|
458
|
+
} catch (error) {
|
|
459
|
+
const cleanupError = {
|
|
460
|
+
code: "ARCHIVE_BATCH_ERROR",
|
|
461
|
+
message: `Batch archive failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
462
|
+
artifactPath: this.config.basePath,
|
|
463
|
+
operation: "archive",
|
|
464
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
465
|
+
recoverable: true,
|
|
466
|
+
suggestion: "Check archive directory permissions"
|
|
467
|
+
};
|
|
468
|
+
this.emit("cleanup:error", cleanupError);
|
|
469
|
+
throw error;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
async archiveSingleArtifact(artifact, archiveDir, dryRun) {
|
|
473
|
+
const archivePath = path.join(archiveDir, `${artifact.id}.${this.config.archiveFormat}`);
|
|
474
|
+
if (dryRun) {
|
|
475
|
+
if (this.config.verbose) {
|
|
476
|
+
console.log(chalk.blue(`[DRY RUN] Would archive ${artifact.path} -> ${archivePath}`));
|
|
477
|
+
}
|
|
478
|
+
return archivePath;
|
|
479
|
+
}
|
|
480
|
+
try {
|
|
481
|
+
const content = await fsp.readFile(artifact.path);
|
|
482
|
+
if (this.config.enableCompression) {
|
|
483
|
+
const compressed = await compressBuffer(content, "gzip");
|
|
484
|
+
await fsp.writeFile(archivePath, compressed);
|
|
485
|
+
} else {
|
|
486
|
+
await fsp.writeFile(archivePath, content);
|
|
487
|
+
}
|
|
488
|
+
if (this.config.retentionPolicy.preserveMetadata) {
|
|
489
|
+
const metadataPath = `${archivePath}.meta.json`;
|
|
490
|
+
const metadata = {
|
|
491
|
+
...artifact,
|
|
492
|
+
archivedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
493
|
+
originalSize: artifact.size,
|
|
494
|
+
compressedSize: this.config.enableCompression ? (await fsp.stat(archivePath)).size : void 0
|
|
495
|
+
};
|
|
496
|
+
await fsp.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
|
|
497
|
+
}
|
|
498
|
+
return archivePath;
|
|
499
|
+
} catch (error) {
|
|
500
|
+
throw new Error(`Failed to archive ${artifact.path}: ${error}`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Delete artifacts based on retention policy
|
|
505
|
+
*/
|
|
506
|
+
async deleteArtifacts(artifacts, options = {}) {
|
|
507
|
+
const dryRun = options.dryRun ?? this.config.dryRun;
|
|
508
|
+
const startTime = Date.now();
|
|
509
|
+
let artifactsProcessed = 0;
|
|
510
|
+
let bytesFreed = 0;
|
|
511
|
+
const errors = [];
|
|
512
|
+
try {
|
|
513
|
+
const deletePromises = artifacts.map(
|
|
514
|
+
(artifact) => this.workerPool.execute(() => this.deleteSingleArtifact(artifact, dryRun))
|
|
515
|
+
);
|
|
516
|
+
const results = await Promise.allSettled(deletePromises);
|
|
517
|
+
results.forEach((result, i) => {
|
|
518
|
+
const artifact = artifacts[i];
|
|
519
|
+
if (!artifact) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
if (result.status === "fulfilled") {
|
|
523
|
+
artifactsProcessed++;
|
|
524
|
+
bytesFreed += artifact.size;
|
|
525
|
+
this.emit("artifact:deleted", artifact);
|
|
526
|
+
} else {
|
|
527
|
+
const error = {
|
|
528
|
+
code: "DELETE_ERROR",
|
|
529
|
+
message: `Failed to delete ${artifact.path}: ${result.reason}`,
|
|
530
|
+
artifactPath: artifact.path,
|
|
531
|
+
operation: "delete",
|
|
532
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
533
|
+
recoverable: true,
|
|
534
|
+
suggestion: "Check file permissions and locks"
|
|
535
|
+
};
|
|
536
|
+
errors.push(error);
|
|
537
|
+
this.emit("cleanup:error", error);
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
const duration = Date.now() - startTime;
|
|
541
|
+
const efficiency = artifacts.length === 0 ? 1 : artifactsProcessed / artifacts.length;
|
|
542
|
+
const cleanupResult = {
|
|
543
|
+
operation: "delete",
|
|
544
|
+
artifactsProcessed,
|
|
545
|
+
bytesProcessed: 0,
|
|
546
|
+
bytesFreed,
|
|
547
|
+
errors,
|
|
548
|
+
duration,
|
|
549
|
+
efficiency
|
|
550
|
+
};
|
|
551
|
+
this.emit("cleanup:completed", cleanupResult);
|
|
552
|
+
return cleanupResult;
|
|
553
|
+
} catch (error) {
|
|
554
|
+
const cleanupError = {
|
|
555
|
+
code: "DELETE_BATCH_ERROR",
|
|
556
|
+
message: `Batch delete failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
557
|
+
artifactPath: this.config.basePath,
|
|
558
|
+
operation: "delete",
|
|
559
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
560
|
+
recoverable: true,
|
|
561
|
+
suggestion: "Check file permissions and system resources"
|
|
562
|
+
};
|
|
563
|
+
this.emit("cleanup:error", cleanupError);
|
|
564
|
+
throw error;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
async deleteSingleArtifact(artifact, dryRun) {
|
|
568
|
+
if (dryRun) {
|
|
569
|
+
if (this.config.verbose) {
|
|
570
|
+
console.log(chalk.red(`[DRY RUN] Would delete ${artifact.path}`));
|
|
571
|
+
}
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
try {
|
|
575
|
+
await fsp.unlink(artifact.path);
|
|
576
|
+
} catch (error) {
|
|
577
|
+
throw new Error(`Failed to delete ${artifact.path}: ${error}`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Main cleanup orchestration method
|
|
582
|
+
*/
|
|
583
|
+
async cleanup(options = {}) {
|
|
584
|
+
if (this.isRunning) {
|
|
585
|
+
throw new Error("Cleanup already in progress");
|
|
586
|
+
}
|
|
587
|
+
this.isRunning = true;
|
|
588
|
+
const results = [];
|
|
589
|
+
try {
|
|
590
|
+
const dryRun = options.dryRun ?? this.config.dryRun;
|
|
591
|
+
if (this.config.verbose) {
|
|
592
|
+
console.log(chalk.cyan("Scanning for artifacts..."));
|
|
593
|
+
}
|
|
594
|
+
const allArtifacts = await this.scanArtifacts();
|
|
595
|
+
if (allArtifacts.length === 0) {
|
|
596
|
+
if (this.config.verbose) {
|
|
597
|
+
console.log(chalk.green("No artifacts found to clean up"));
|
|
598
|
+
}
|
|
599
|
+
return results;
|
|
600
|
+
}
|
|
601
|
+
const artifactsToClean = this.applyRetentionPolicy(allArtifacts);
|
|
602
|
+
if (artifactsToClean.length === 0) {
|
|
603
|
+
if (this.config.verbose) {
|
|
604
|
+
console.log(chalk.green("No artifacts need cleanup based on retention policy"));
|
|
605
|
+
}
|
|
606
|
+
return results;
|
|
607
|
+
}
|
|
608
|
+
if (this.config.verbose) {
|
|
609
|
+
console.log(chalk.yellow(`Found ${artifactsToClean.length} artifacts to clean up`));
|
|
610
|
+
}
|
|
611
|
+
let artifactsToDelete = artifactsToClean;
|
|
612
|
+
if (this.config.retentionPolicy.archiveBeforeDelete && options.archiveFirst !== false) {
|
|
613
|
+
if (this.config.verbose) {
|
|
614
|
+
console.log(chalk.blue("Archiving artifacts..."));
|
|
615
|
+
}
|
|
616
|
+
const archiveResult = await this.archiveArtifacts(artifactsToClean, { dryRun });
|
|
617
|
+
results.push(archiveResult);
|
|
618
|
+
const failedArchivePaths = new Set(archiveResult.errors.map((error) => error.artifactPath));
|
|
619
|
+
artifactsToDelete = artifactsToClean.filter(
|
|
620
|
+
(artifact) => !failedArchivePaths.has(artifact.path)
|
|
621
|
+
);
|
|
622
|
+
if (this.config.verbose) {
|
|
623
|
+
console.log(chalk.green(`Archived ${archiveResult.artifactsProcessed} artifacts`));
|
|
624
|
+
if (failedArchivePaths.size > 0) {
|
|
625
|
+
console.log(
|
|
626
|
+
chalk.yellow(
|
|
627
|
+
`Skipping delete for ${failedArchivePaths.size} artifact(s) that failed to archive`
|
|
628
|
+
)
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if (this.config.verbose) {
|
|
634
|
+
console.log(chalk.red("Deleting artifacts..."));
|
|
635
|
+
}
|
|
636
|
+
const deleteResult = await this.deleteArtifacts(artifactsToDelete, { dryRun });
|
|
637
|
+
results.push(deleteResult);
|
|
638
|
+
if (this.config.verbose) {
|
|
639
|
+
console.log(
|
|
640
|
+
chalk.green(
|
|
641
|
+
`Deleted ${deleteResult.artifactsProcessed} artifacts, freed ${formatBytes(deleteResult.bytesFreed)}`
|
|
642
|
+
)
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
return results;
|
|
646
|
+
} finally {
|
|
647
|
+
this.isRunning = false;
|
|
648
|
+
await this.workerPool.close();
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
applyRetentionPolicy(artifacts) {
|
|
652
|
+
const policy = this.config.retentionPolicy;
|
|
653
|
+
const now = /* @__PURE__ */ new Date();
|
|
654
|
+
return artifacts.filter((artifact) => {
|
|
655
|
+
const ageDays = (now.getTime() - artifact.createdAt.getTime()) / (1e3 * 60 * 60 * 24);
|
|
656
|
+
if (ageDays > policy.maxAgeDays) {
|
|
657
|
+
return true;
|
|
658
|
+
}
|
|
659
|
+
if (artifact.size > policy.maxSizeBytes) {
|
|
660
|
+
return true;
|
|
661
|
+
}
|
|
662
|
+
if (policy.smartAging && artifact.retentionScore < 0.3) {
|
|
663
|
+
return true;
|
|
664
|
+
}
|
|
665
|
+
const hasPriorityTag = Array.from(artifact.tags).some(
|
|
666
|
+
(tag) => policy.priorityTags.has(tag.toLowerCase())
|
|
667
|
+
);
|
|
668
|
+
if (hasPriorityTag) {
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
return false;
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Get telemetry data
|
|
676
|
+
*/
|
|
677
|
+
getTelemetry() {
|
|
678
|
+
return new Map(this.telemetry);
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Close the manager and cleanup resources
|
|
682
|
+
*/
|
|
683
|
+
async close() {
|
|
684
|
+
await this.workerPool.close();
|
|
685
|
+
this.removeAllListeners();
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
function createArtifactLifecycleManager(config = {}) {
|
|
689
|
+
return new ArtifactLifecycleManager(config);
|
|
690
|
+
}
|
|
691
|
+
var DefaultConfigs = {
|
|
692
|
+
development: {
|
|
693
|
+
retentionPolicy: {
|
|
694
|
+
maxAgeDays: 7,
|
|
695
|
+
maxSizeBytes: 50 * 1024 * 1024,
|
|
696
|
+
maxCount: 100,
|
|
697
|
+
archiveBeforeDelete: false
|
|
698
|
+
},
|
|
699
|
+
parallelWorkers: 2,
|
|
700
|
+
enableTelemetry: true
|
|
701
|
+
},
|
|
702
|
+
production: {
|
|
703
|
+
retentionPolicy: {
|
|
704
|
+
maxAgeDays: 30,
|
|
705
|
+
maxSizeBytes: 100 * 1024 * 1024,
|
|
706
|
+
maxCount: 1e3,
|
|
707
|
+
archiveBeforeDelete: true,
|
|
708
|
+
preserveMetadata: true
|
|
709
|
+
},
|
|
710
|
+
parallelWorkers: 4,
|
|
711
|
+
enableTelemetry: true,
|
|
712
|
+
enableSmartAging: true
|
|
713
|
+
},
|
|
714
|
+
aggressive: {
|
|
715
|
+
retentionPolicy: {
|
|
716
|
+
maxAgeDays: 3,
|
|
717
|
+
maxSizeBytes: 10 * 1024 * 1024,
|
|
718
|
+
maxCount: 50,
|
|
719
|
+
archiveBeforeDelete: false
|
|
720
|
+
},
|
|
721
|
+
parallelWorkers: 6,
|
|
722
|
+
enableTelemetry: false
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
// src/orchestrator/pr-manager-core.ts
|
|
727
|
+
function stdoutToString(stdout) {
|
|
728
|
+
if (stdout === void 0 || stdout === null) {
|
|
729
|
+
return "";
|
|
730
|
+
}
|
|
731
|
+
if (typeof stdout === "string") {
|
|
732
|
+
return stdout;
|
|
733
|
+
}
|
|
734
|
+
if (Array.isArray(stdout)) {
|
|
735
|
+
return stdout.join("\n");
|
|
736
|
+
}
|
|
737
|
+
if (stdout instanceof Uint8Array) {
|
|
738
|
+
return new TextDecoder().decode(stdout);
|
|
739
|
+
}
|
|
740
|
+
return String(stdout);
|
|
741
|
+
}
|
|
742
|
+
function formatGitCommandFailure(operation, result) {
|
|
743
|
+
const stderr = result.stderr?.trim();
|
|
744
|
+
const stdout = result.stdout?.trim();
|
|
745
|
+
const detail = stderr || stdout || "no output";
|
|
746
|
+
return `${operation} failed with exit code ${result.exitCode ?? "unknown"}: ${detail}`;
|
|
747
|
+
}
|
|
748
|
+
var PRManagerCore = class _PRManagerCore {
|
|
749
|
+
artifactManager;
|
|
750
|
+
ghCircuitConfig = {
|
|
751
|
+
failureThreshold: 3,
|
|
752
|
+
baseCooldownMs: 15e3,
|
|
753
|
+
maxCooldownMs: 5 * 6e4
|
|
754
|
+
};
|
|
755
|
+
static ghCircuitState = {
|
|
756
|
+
failureCount: 0,
|
|
757
|
+
cooldownUntil: 0
|
|
758
|
+
};
|
|
759
|
+
static lastCircuitWarningAt = 0;
|
|
760
|
+
constructor() {
|
|
761
|
+
this.artifactManager = createArtifactLifecycleManager({
|
|
762
|
+
basePath: ".poetic/implementations",
|
|
763
|
+
verbose: false,
|
|
764
|
+
retentionPolicy: {
|
|
765
|
+
maxAgeDays: 30,
|
|
766
|
+
maxSizeBytes: MAX_FILE_SIZE_BYTES,
|
|
767
|
+
maxCount: MAX_FILE_COUNT,
|
|
768
|
+
archiveBeforeDelete: true,
|
|
769
|
+
compressionLevel: 6,
|
|
770
|
+
preserveMetadata: true,
|
|
771
|
+
smartAging: true,
|
|
772
|
+
priorityTags: /* @__PURE__ */ new Set(["critical", "production", "reference"]),
|
|
773
|
+
exclusionPatterns: [/\.git\//, /node_modules\//, /\.DS_Store$/]
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Cleanup artifacts after PR operations
|
|
779
|
+
*/
|
|
780
|
+
async cleanupArtifacts(options = {}) {
|
|
781
|
+
if (!this.artifactManager) {
|
|
782
|
+
emitWarning(
|
|
783
|
+
"CFG-001",
|
|
784
|
+
{
|
|
785
|
+
taskId: "unknown",
|
|
786
|
+
subsystem: "pr-manager",
|
|
787
|
+
executionPhase: "cleanup"
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
metadata: {
|
|
791
|
+
message: "Artifact manager not initialized"
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
);
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
try {
|
|
798
|
+
const results = await this.artifactManager.cleanup({
|
|
799
|
+
dryRun: options.dryRun ?? false,
|
|
800
|
+
force: options.force ?? false,
|
|
801
|
+
archiveFirst: options.archiveFirst ?? true
|
|
802
|
+
});
|
|
803
|
+
if (results.length > 0) {
|
|
804
|
+
const totalProcessed = results.reduce((sum, result) => sum + result.artifactsProcessed, 0);
|
|
805
|
+
const totalFreed = results.reduce((sum, result) => sum + result.bytesFreed, 0);
|
|
806
|
+
console.log(`Cleaned up ${totalProcessed} artifacts, freed ${formatBytes(totalFreed)}`);
|
|
807
|
+
}
|
|
808
|
+
} catch (error) {
|
|
809
|
+
emitWarning(
|
|
810
|
+
"WS-003",
|
|
811
|
+
{
|
|
812
|
+
taskId: "unknown",
|
|
813
|
+
subsystem: "pr-manager",
|
|
814
|
+
executionPhase: "cleanup"
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
severity: "ERROR" /* ERROR */,
|
|
818
|
+
metadata: {
|
|
819
|
+
error: error instanceof Error ? error.message : String(error),
|
|
820
|
+
operation: "artifactCleanup"
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
);
|
|
824
|
+
throw wrapError(error);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Get artifact statistics
|
|
829
|
+
*/
|
|
830
|
+
async getArtifactStats() {
|
|
831
|
+
if (!this.artifactManager) {
|
|
832
|
+
return { totalArtifacts: 0, totalSize: 0 };
|
|
833
|
+
}
|
|
834
|
+
try {
|
|
835
|
+
const artifacts = await this.artifactManager.scanArtifacts();
|
|
836
|
+
const totalSize = artifacts.reduce((sum, artifact) => sum + artifact.size, 0);
|
|
837
|
+
const dates = artifacts.map((artifact) => artifact.createdAt).sort();
|
|
838
|
+
return {
|
|
839
|
+
totalArtifacts: artifacts.length,
|
|
840
|
+
totalSize,
|
|
841
|
+
oldestArtifact: dates[0],
|
|
842
|
+
newestArtifact: dates[dates.length - 1]
|
|
843
|
+
};
|
|
844
|
+
} catch (error) {
|
|
845
|
+
emitWarning(
|
|
846
|
+
"WS-003",
|
|
847
|
+
{
|
|
848
|
+
taskId: "unknown",
|
|
849
|
+
subsystem: "pr-manager",
|
|
850
|
+
executionPhase: "validation"
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
severity: "ERROR" /* ERROR */,
|
|
854
|
+
metadata: {
|
|
855
|
+
error: error instanceof Error ? error.message : String(error),
|
|
856
|
+
operation: "getArtifactStats"
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
);
|
|
860
|
+
return { totalArtifacts: 0, totalSize: 0 };
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Format bytes to human readable string
|
|
865
|
+
*/
|
|
866
|
+
/**
|
|
867
|
+
* Close the manager and cleanup resources
|
|
868
|
+
*/
|
|
869
|
+
async close() {
|
|
870
|
+
if (this.artifactManager) {
|
|
871
|
+
await this.artifactManager.close();
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
getRepositoryRoot(cwd) {
|
|
875
|
+
const startDir = cwd ?? process.cwd();
|
|
876
|
+
return findProjectRoot(startDir, { honorPoeticRepo: cwd === void 0 }) ?? startDir;
|
|
877
|
+
}
|
|
878
|
+
async captureExpectedRemoteSha(branch, repositoryRoot) {
|
|
879
|
+
if (!isEphemeralPoeticBranchDeletionCandidate(branch)) {
|
|
880
|
+
return void 0;
|
|
881
|
+
}
|
|
882
|
+
try {
|
|
883
|
+
return await resolveExpectedRemoteShaForQueuedBranch(branch, {
|
|
884
|
+
remote: "origin",
|
|
885
|
+
cwd: repositoryRoot
|
|
886
|
+
});
|
|
887
|
+
} catch {
|
|
888
|
+
return void 0;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
async enqueueFailedPRBranchCleanup(options) {
|
|
892
|
+
const { branch, repositoryRoot, reason, expectedRemoteSha, taskId = "unknown" } = options;
|
|
893
|
+
if (!isEphemeralPoeticBranchDeletionCandidate(branch)) {
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
try {
|
|
897
|
+
await enqueueRemoteBranchCleanup(branch, {
|
|
898
|
+
remote: "origin",
|
|
899
|
+
reason,
|
|
900
|
+
expectedRemoteSha,
|
|
901
|
+
cwd: repositoryRoot
|
|
902
|
+
});
|
|
903
|
+
} catch (cleanupError) {
|
|
904
|
+
emitWarning(
|
|
905
|
+
"PR-001",
|
|
906
|
+
{ taskId, subsystem: "pr-manager", executionPhase: "cleanup" },
|
|
907
|
+
{
|
|
908
|
+
severity: "WARN" /* WARN */,
|
|
909
|
+
metadata: {
|
|
910
|
+
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError),
|
|
911
|
+
branch,
|
|
912
|
+
operation: "queueFailedPRBranchCleanup"
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
async assertCleanForInPlaceCheckout(cwd) {
|
|
919
|
+
if (await this.isWorkingDirectoryClean(cwd)) {
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
throw new GitError(
|
|
923
|
+
"Refusing in-place branch checkout because the working tree is dirty. Commit or preserve the changes, or use an isolated worktree, before switching branches."
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* Create feature branch and PR for a variant
|
|
928
|
+
*/
|
|
929
|
+
async createVariantPR(options) {
|
|
930
|
+
const { taskId, variant, branch, planContent } = options;
|
|
931
|
+
const repositoryRoot = this.getRepositoryRoot();
|
|
932
|
+
const baseBranch = options.baseBranch ?? await resolveDefaultBranch(repositoryRoot);
|
|
933
|
+
let lock = null;
|
|
934
|
+
let lockReleased = false;
|
|
935
|
+
const releaseLock = () => {
|
|
936
|
+
if (!lock || lockReleased) {
|
|
937
|
+
return;
|
|
938
|
+
}
|
|
939
|
+
lockReleased = true;
|
|
940
|
+
lock.release();
|
|
941
|
+
};
|
|
942
|
+
const worktreeManager = getWorktreeManager({ gitCwd: repositoryRoot });
|
|
943
|
+
let worktreePath = null;
|
|
944
|
+
let branchPushed = false;
|
|
945
|
+
let expectedRemoteSha;
|
|
946
|
+
try {
|
|
947
|
+
worktreePath = await worktreeManager.create(
|
|
948
|
+
taskId,
|
|
949
|
+
branch,
|
|
950
|
+
variant.strategy,
|
|
951
|
+
variant.provider
|
|
952
|
+
);
|
|
953
|
+
lock = await gitLock.acquire();
|
|
954
|
+
const placeholderRelativePath = `.poetic/implementations/${variant.provider}-${variant.strategy}-${taskId}.md`;
|
|
955
|
+
const placeholderPath = path2.join(worktreePath, placeholderRelativePath);
|
|
956
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
957
|
+
const placeholderStrategy = resolveVariantStrategy(variant.strategy);
|
|
958
|
+
const placeholder = `# ${variant.strategy.charAt(0).toUpperCase() + variant.strategy.slice(1)} Implementation for ${taskId}
|
|
959
|
+
|
|
960
|
+
**Variant**: ${variant.strategy}
|
|
961
|
+
**Provider**: ${variant.provider}
|
|
962
|
+
**Model**: ${variant.model || "default"}
|
|
963
|
+
**Execution Mode**: ${variant.executionMode}
|
|
964
|
+
**Created**: ${timestamp}
|
|
965
|
+
|
|
966
|
+
## Approach
|
|
967
|
+
${placeholderStrategy.description}
|
|
968
|
+
|
|
969
|
+
## Status
|
|
970
|
+
- [ ] Implementation started
|
|
971
|
+
- [ ] Tests passing
|
|
972
|
+
- [ ] Coverage >80%
|
|
973
|
+
- [ ] Ready for review
|
|
974
|
+
|
|
975
|
+
## Plan
|
|
976
|
+
${planContent}
|
|
977
|
+
`;
|
|
978
|
+
let placeholderCreated = false;
|
|
979
|
+
const allowPlaceholder = process.env.POETIC_ALLOW_PLACEHOLDER_COMMITS !== "0";
|
|
980
|
+
if (allowPlaceholder) {
|
|
981
|
+
await fsp2.mkdir(path2.dirname(placeholderPath), { recursive: true });
|
|
982
|
+
await fsp2.writeFile(placeholderPath, placeholder, "utf8");
|
|
983
|
+
await this.runGitMutation(["add", placeholderRelativePath], worktreePath);
|
|
984
|
+
await this.runGitMutation(
|
|
985
|
+
[
|
|
986
|
+
"commit",
|
|
987
|
+
"--no-verify",
|
|
988
|
+
"-m",
|
|
989
|
+
`init: ${taskId} ${variant.strategy} variant placeholder`
|
|
990
|
+
],
|
|
991
|
+
worktreePath
|
|
992
|
+
);
|
|
993
|
+
await this.runGitMutation(["push", "-u", "origin", branch], worktreePath);
|
|
994
|
+
placeholderCreated = true;
|
|
995
|
+
branchPushed = true;
|
|
996
|
+
expectedRemoteSha = await this.captureExpectedRemoteSha(branch, repositoryRoot);
|
|
997
|
+
} else {
|
|
998
|
+
emitTelemetryFallbackWarning(
|
|
999
|
+
"Placeholder commits disabled (POETIC_ALLOW_PLACEHOLDER_COMMITS=0); skipping placeholder file creation."
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
if (worktreePath) {
|
|
1003
|
+
await worktreeManager.cleanup(worktreePath);
|
|
1004
|
+
worktreePath = null;
|
|
1005
|
+
}
|
|
1006
|
+
releaseLock();
|
|
1007
|
+
const prTitle = `[${taskId}] ${variant.strategy.charAt(0).toUpperCase() + variant.strategy.slice(1)} Implementation (${variant.provider})`;
|
|
1008
|
+
const prBody = `**Variant**: ${variant.strategy}
|
|
1009
|
+
**Provider**: ${variant.provider}
|
|
1010
|
+
**Model**: ${variant.model || "default"}
|
|
1011
|
+
**Execution Mode**: ${variant.executionMode}
|
|
1012
|
+
|
|
1013
|
+
## Approach
|
|
1014
|
+
${placeholderStrategy.description}
|
|
1015
|
+
|
|
1016
|
+
## Status
|
|
1017
|
+
**Draft PR** - Will be marked ready for review after implementation completes.
|
|
1018
|
+
**Do not merge** until after batch evaluation and synthesis.
|
|
1019
|
+
|
|
1020
|
+
## Plan
|
|
1021
|
+
${planContent}
|
|
1022
|
+
${placeholderCreated ? "" : "\n\n**Note**: Placeholder file was omitted because POETIC_ALLOW_PLACEHOLDER_COMMITS=0. Placeholder commits are enabled by default to support local variant execution. Set POETIC_ALLOW_PLACEHOLDER_COMMITS=0 to disable if needed."}
|
|
1023
|
+
`;
|
|
1024
|
+
const createResult = await this.runGhCommand(
|
|
1025
|
+
[
|
|
1026
|
+
"pr",
|
|
1027
|
+
"create",
|
|
1028
|
+
"--draft",
|
|
1029
|
+
"--title",
|
|
1030
|
+
prTitle,
|
|
1031
|
+
"--body",
|
|
1032
|
+
prBody,
|
|
1033
|
+
"--base",
|
|
1034
|
+
baseBranch,
|
|
1035
|
+
"--head",
|
|
1036
|
+
branch
|
|
1037
|
+
],
|
|
1038
|
+
{
|
|
1039
|
+
operationName: "gh pr create",
|
|
1040
|
+
telemetryTags: { phase: "create_pr" },
|
|
1041
|
+
cwd: repositoryRoot
|
|
1042
|
+
}
|
|
1043
|
+
);
|
|
1044
|
+
const stdout = stdoutToString(createResult.stdout);
|
|
1045
|
+
const prUrl = stdout.match(/https:\/\/github\.com[^\s]*\/pull\/\d+[^\s]*/)?.[0];
|
|
1046
|
+
if (!prUrl) {
|
|
1047
|
+
throw new PRCreationError(branch, "Failed to extract PR URL from gh CLI output");
|
|
1048
|
+
}
|
|
1049
|
+
const prNumberMatch = prUrl.match(/\/pull\/(\d+)/);
|
|
1050
|
+
const prNumber = prNumberMatch?.[1] ? parseInt(prNumberMatch[1], 10) : 0;
|
|
1051
|
+
if (!prNumber) {
|
|
1052
|
+
throw new PRCreationError(branch, "Failed to extract PR number from URL");
|
|
1053
|
+
}
|
|
1054
|
+
return {
|
|
1055
|
+
number: prNumber,
|
|
1056
|
+
url: prUrl,
|
|
1057
|
+
branch
|
|
1058
|
+
};
|
|
1059
|
+
} catch (error) {
|
|
1060
|
+
if (worktreePath) {
|
|
1061
|
+
try {
|
|
1062
|
+
await worktreeManager.cleanup(worktreePath);
|
|
1063
|
+
} catch (cleanupError) {
|
|
1064
|
+
emitWarning(
|
|
1065
|
+
"WS-003",
|
|
1066
|
+
{
|
|
1067
|
+
taskId,
|
|
1068
|
+
subsystem: "pr-manager",
|
|
1069
|
+
executionPhase: "cleanup"
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
severity: "ERROR" /* ERROR */,
|
|
1073
|
+
metadata: {
|
|
1074
|
+
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError),
|
|
1075
|
+
worktreePath,
|
|
1076
|
+
operation: "worktreeCleanupOnError"
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
if (branchPushed) {
|
|
1083
|
+
await this.enqueueFailedPRBranchCleanup({
|
|
1084
|
+
branch,
|
|
1085
|
+
repositoryRoot,
|
|
1086
|
+
reason: "createVariantPR failed after remote branch push",
|
|
1087
|
+
expectedRemoteSha,
|
|
1088
|
+
taskId
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
releaseLock();
|
|
1092
|
+
throw wrapError(error);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
async createDraftPRForBranch(options) {
|
|
1096
|
+
const { branch, title, body, draft = true, timeoutMs } = options;
|
|
1097
|
+
const repositoryRoot = this.getRepositoryRoot();
|
|
1098
|
+
const baseBranch = options.baseBranch ?? await resolveDefaultBranch(repositoryRoot);
|
|
1099
|
+
const expectedRemoteSha = await this.captureExpectedRemoteSha(branch, repositoryRoot);
|
|
1100
|
+
try {
|
|
1101
|
+
const result = await this.runGhCommand(
|
|
1102
|
+
[
|
|
1103
|
+
"pr",
|
|
1104
|
+
"create",
|
|
1105
|
+
...draft ? ["--draft"] : [],
|
|
1106
|
+
"--title",
|
|
1107
|
+
title,
|
|
1108
|
+
"--body",
|
|
1109
|
+
body,
|
|
1110
|
+
"--base",
|
|
1111
|
+
baseBranch,
|
|
1112
|
+
"--head",
|
|
1113
|
+
branch
|
|
1114
|
+
],
|
|
1115
|
+
{
|
|
1116
|
+
operationName: "gh pr create",
|
|
1117
|
+
telemetryTags: { phase: "create_pr", branch },
|
|
1118
|
+
cwd: repositoryRoot,
|
|
1119
|
+
...typeof timeoutMs === "number" ? { timeout: timeoutMs } : {}
|
|
1120
|
+
}
|
|
1121
|
+
);
|
|
1122
|
+
const stdout = stdoutToString(result.stdout);
|
|
1123
|
+
const prUrl = stdout.match(/https:\/\/github\.com[^\s]+/)?.[0];
|
|
1124
|
+
if (!prUrl) {
|
|
1125
|
+
throw new PRCreationError(branch, "Failed to extract PR URL from gh CLI output");
|
|
1126
|
+
}
|
|
1127
|
+
const prNumberMatch = prUrl.match(/\/pull\/(\d+)/);
|
|
1128
|
+
const prNumber = prNumberMatch?.[1] ? parseInt(prNumberMatch[1], 10) : 0;
|
|
1129
|
+
if (!prNumber) {
|
|
1130
|
+
throw new PRCreationError(branch, "Failed to extract PR number from URL");
|
|
1131
|
+
}
|
|
1132
|
+
return {
|
|
1133
|
+
number: prNumber,
|
|
1134
|
+
url: prUrl,
|
|
1135
|
+
branch
|
|
1136
|
+
};
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
await this.enqueueFailedPRBranchCleanup({
|
|
1139
|
+
branch,
|
|
1140
|
+
repositoryRoot,
|
|
1141
|
+
reason: "createDraftPRForBranch failed",
|
|
1142
|
+
expectedRemoteSha
|
|
1143
|
+
});
|
|
1144
|
+
throw error;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Get owner/repo from git remote
|
|
1149
|
+
* Returns format: "owner/repo"
|
|
1150
|
+
*/
|
|
1151
|
+
async getOwnerRepo() {
|
|
1152
|
+
try {
|
|
1153
|
+
const result = await execa("git", ["remote", "get-url", "origin"]);
|
|
1154
|
+
const match = result.stdout.match(/github\.com[:/](.+\/.+?)(?:\.git)?$/);
|
|
1155
|
+
if (!match || !match[1]) {
|
|
1156
|
+
throw new GitError("Could not determine GitHub owner/repo from git remote");
|
|
1157
|
+
}
|
|
1158
|
+
return match[1];
|
|
1159
|
+
} catch (error) {
|
|
1160
|
+
throw wrapError(error);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Get PR branch name
|
|
1165
|
+
*/
|
|
1166
|
+
async getPRBranch(prNumber) {
|
|
1167
|
+
const result = await this.runGhCommand(
|
|
1168
|
+
["pr", "view", String(prNumber), "--json", "headRefName", "--jq", ".headRefName"],
|
|
1169
|
+
{
|
|
1170
|
+
operationName: "gh pr view headRefName",
|
|
1171
|
+
telemetryTags: { pr: String(prNumber) }
|
|
1172
|
+
}
|
|
1173
|
+
);
|
|
1174
|
+
return stdoutToString(result.stdout).trim();
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Check if branch exists locally
|
|
1178
|
+
*/
|
|
1179
|
+
async branchExists(branch, cwd) {
|
|
1180
|
+
try {
|
|
1181
|
+
if (cwd) {
|
|
1182
|
+
await execa("git", ["rev-parse", "--verify", branch], { cwd });
|
|
1183
|
+
} else {
|
|
1184
|
+
await execa("git", ["rev-parse", "--verify", branch]);
|
|
1185
|
+
}
|
|
1186
|
+
return true;
|
|
1187
|
+
} catch {
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Checkout branch (creates if needed from remote)
|
|
1193
|
+
*/
|
|
1194
|
+
async checkoutBranch(branch) {
|
|
1195
|
+
const lock = await gitLock.acquire();
|
|
1196
|
+
try {
|
|
1197
|
+
const repositoryRoot = this.getRepositoryRoot();
|
|
1198
|
+
await this.assertCleanForInPlaceCheckout(repositoryRoot);
|
|
1199
|
+
const exists = await this.branchExists(branch, repositoryRoot);
|
|
1200
|
+
if (exists) {
|
|
1201
|
+
await this.runGitMutation(["checkout", branch], repositoryRoot);
|
|
1202
|
+
await this.runGitMutation(["pull", "origin", branch], repositoryRoot);
|
|
1203
|
+
} else {
|
|
1204
|
+
await this.runGitMutation(["fetch", "origin", branch], repositoryRoot);
|
|
1205
|
+
await this.runGitMutation(["checkout", "-b", branch, `origin/${branch}`], repositoryRoot);
|
|
1206
|
+
}
|
|
1207
|
+
const currentBranch = await this.getCurrentBranch(repositoryRoot);
|
|
1208
|
+
if (currentBranch !== branch) {
|
|
1209
|
+
throw new Error(
|
|
1210
|
+
`Branch checkout validation failed: Expected branch "${branch}", but git is on "${currentBranch}". This indicates the checkout command failed silently. Check git output above.`
|
|
1211
|
+
);
|
|
1212
|
+
}
|
|
1213
|
+
} finally {
|
|
1214
|
+
lock.release();
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
/**
|
|
1218
|
+
* Get current git branch
|
|
1219
|
+
*/
|
|
1220
|
+
async getCurrentBranch(cwd) {
|
|
1221
|
+
const result = await execa("git", ["branch", "--show-current"], { cwd });
|
|
1222
|
+
return result.stdout.trim();
|
|
1223
|
+
}
|
|
1224
|
+
async runGitMutation(args, cwd) {
|
|
1225
|
+
const result = await execGit(args, { cwd });
|
|
1226
|
+
if (result.exitCode !== 0) {
|
|
1227
|
+
throw new GitError(result.stderr || `git ${args.join(" ")} exited ${result.exitCode}`);
|
|
1228
|
+
}
|
|
1229
|
+
return result;
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* Check if working directory is clean
|
|
1233
|
+
*/
|
|
1234
|
+
async isWorkingDirectoryClean(cwd) {
|
|
1235
|
+
try {
|
|
1236
|
+
const result = await execa("git", ["status", "--porcelain", "--untracked-files=all"], {
|
|
1237
|
+
cwd
|
|
1238
|
+
});
|
|
1239
|
+
return result.stdout.trim().length === 0;
|
|
1240
|
+
} catch {
|
|
1241
|
+
return false;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Stage all changes
|
|
1246
|
+
*/
|
|
1247
|
+
async stageAll() {
|
|
1248
|
+
const lock = await gitLock.acquire();
|
|
1249
|
+
try {
|
|
1250
|
+
await this.runGitMutation(["add", "."], this.getRepositoryRoot());
|
|
1251
|
+
} finally {
|
|
1252
|
+
lock.release();
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Commit changes
|
|
1257
|
+
*/
|
|
1258
|
+
async commit(message) {
|
|
1259
|
+
const lock = await gitLock.acquire();
|
|
1260
|
+
try {
|
|
1261
|
+
await this.runGitMutation(["commit", "-m", message], this.getRepositoryRoot());
|
|
1262
|
+
} finally {
|
|
1263
|
+
lock.release();
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Commit changes to a specific branch with branch validation.
|
|
1268
|
+
*
|
|
1269
|
+
* DEFENSIVE VALIDATION: Verifies we're on the expected branch before committing.
|
|
1270
|
+
*/
|
|
1271
|
+
async commitToBranch(branchName, message, cwd) {
|
|
1272
|
+
const lock = await gitLock.acquire();
|
|
1273
|
+
try {
|
|
1274
|
+
const currentBranch = await this.getCurrentBranch(cwd);
|
|
1275
|
+
if (currentBranch !== branchName) {
|
|
1276
|
+
throw new Error(
|
|
1277
|
+
`SAFETY: Prevented commit to wrong branch!
|
|
1278
|
+
Expected: ${branchName}
|
|
1279
|
+
Current: ${currentBranch}
|
|
1280
|
+
This indicates a git lock race condition. The commit was blocked to prevent data corruption.`
|
|
1281
|
+
);
|
|
1282
|
+
}
|
|
1283
|
+
const commitResult = await execGit(["commit", "-m", message], {
|
|
1284
|
+
cwd: this.getRepositoryRoot(cwd)
|
|
1285
|
+
});
|
|
1286
|
+
if (commitResult.exitCode !== 0) {
|
|
1287
|
+
emitWarning(
|
|
1288
|
+
"PR-001",
|
|
1289
|
+
{
|
|
1290
|
+
taskId: "unknown",
|
|
1291
|
+
subsystem: "pr-manager",
|
|
1292
|
+
executionPhase: "execution"
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
severity: "WARN" /* WARN */,
|
|
1296
|
+
metadata: {
|
|
1297
|
+
operation: "gitCommitToBranch",
|
|
1298
|
+
branch: branchName,
|
|
1299
|
+
message,
|
|
1300
|
+
exitCode: commitResult.exitCode,
|
|
1301
|
+
stderr: commitResult.stderr,
|
|
1302
|
+
stdout: commitResult.stdout
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
);
|
|
1306
|
+
throw new GitError(formatGitCommandFailure("git commit", commitResult));
|
|
1307
|
+
}
|
|
1308
|
+
} finally {
|
|
1309
|
+
lock.release();
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* Push to remote
|
|
1314
|
+
*/
|
|
1315
|
+
async push(branch) {
|
|
1316
|
+
const lock = await gitLock.acquire();
|
|
1317
|
+
try {
|
|
1318
|
+
await this.runGitMutation(["push", "origin", branch], this.getRepositoryRoot());
|
|
1319
|
+
} finally {
|
|
1320
|
+
lock.release();
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Get PR URL
|
|
1325
|
+
*/
|
|
1326
|
+
async getPRUrl(prNumber) {
|
|
1327
|
+
const result = await this.runGhCommand(
|
|
1328
|
+
["pr", "view", String(prNumber), "--json", "url", "--jq", ".url"],
|
|
1329
|
+
{
|
|
1330
|
+
operationName: "gh pr view url",
|
|
1331
|
+
telemetryTags: { pr: String(prNumber) }
|
|
1332
|
+
}
|
|
1333
|
+
);
|
|
1334
|
+
return stdoutToString(result.stdout).trim();
|
|
1335
|
+
}
|
|
1336
|
+
/**
|
|
1337
|
+
* Close PR without merging
|
|
1338
|
+
*/
|
|
1339
|
+
async closePR(prNumber) {
|
|
1340
|
+
try {
|
|
1341
|
+
await this.runGhCommand(["pr", "close", prNumber.toString()], {
|
|
1342
|
+
operationName: "gh pr close",
|
|
1343
|
+
telemetryTags: { pr: String(prNumber) }
|
|
1344
|
+
});
|
|
1345
|
+
} catch (error) {
|
|
1346
|
+
throw wrapError(error);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Delete branch (both local and remote)
|
|
1351
|
+
*/
|
|
1352
|
+
async deleteBranch(branch, options = {}) {
|
|
1353
|
+
const { deleteLocal = true, deleteRemote = true, force = false, cwd } = options;
|
|
1354
|
+
const repositoryRoot = this.getRepositoryRoot(cwd);
|
|
1355
|
+
const runGit = (args) => this.runGitMutation(args, repositoryRoot);
|
|
1356
|
+
const lock = await gitLock.acquire();
|
|
1357
|
+
try {
|
|
1358
|
+
const currentBranch = await this.getCurrentBranch(cwd);
|
|
1359
|
+
if (currentBranch === branch) {
|
|
1360
|
+
await this.assertCleanForInPlaceCheckout(repositoryRoot);
|
|
1361
|
+
const defaultBranch = await resolveDefaultBranch(repositoryRoot);
|
|
1362
|
+
await runGit(["checkout", defaultBranch]);
|
|
1363
|
+
const { stdout: verifiedBranch } = await runGit(["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
1364
|
+
const normalizedVerified = verifiedBranch.trim() || defaultBranch;
|
|
1365
|
+
if (normalizedVerified !== defaultBranch) {
|
|
1366
|
+
throw new Error(`Branch mismatch: expected ${defaultBranch}, got ${normalizedVerified}`);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
const errors = [];
|
|
1370
|
+
if (deleteLocal) {
|
|
1371
|
+
const exists = await this.branchExists(branch, cwd);
|
|
1372
|
+
if (exists) {
|
|
1373
|
+
try {
|
|
1374
|
+
const deleteFlag = force ? "-D" : "-d";
|
|
1375
|
+
await runGit(["branch", deleteFlag, branch]);
|
|
1376
|
+
console.log(chalk2.green(` Deleted local branch: ${branch}`));
|
|
1377
|
+
} catch (error) {
|
|
1378
|
+
const errorMsg = `Failed to delete local branch ${branch}: ${error instanceof Error ? error.message : String(error)}`;
|
|
1379
|
+
errors.push(errorMsg);
|
|
1380
|
+
console.log(chalk2.yellow(` ${errorMsg}`));
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
if (deleteRemote) {
|
|
1385
|
+
try {
|
|
1386
|
+
await runGit(["push", "origin", "--delete", branch]);
|
|
1387
|
+
console.log(chalk2.green(` Deleted remote branch: ${branch}`));
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1390
|
+
if (isRemoteBranchMissingError(message)) {
|
|
1391
|
+
console.log(chalk2.gray(` Remote branch ${branch} already absent`));
|
|
1392
|
+
} else {
|
|
1393
|
+
const errorMsg = `Failed to delete remote branch ${branch}: ${message}`;
|
|
1394
|
+
if (isRetryableRemoteDeleteError(message)) {
|
|
1395
|
+
try {
|
|
1396
|
+
const cleanupCwd = cwd ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
1397
|
+
const expectedRemoteSha = await resolveExpectedRemoteShaForQueuedBranch(branch, {
|
|
1398
|
+
remote: "origin",
|
|
1399
|
+
cwd: cleanupCwd
|
|
1400
|
+
});
|
|
1401
|
+
await enqueueRemoteBranchCleanup(branch, {
|
|
1402
|
+
remote: "origin",
|
|
1403
|
+
reason: "deleteBranch(remote)",
|
|
1404
|
+
expectedRemoteSha,
|
|
1405
|
+
cwd: cleanupCwd
|
|
1406
|
+
});
|
|
1407
|
+
console.log(
|
|
1408
|
+
chalk2.yellow(
|
|
1409
|
+
` \u21AA Queued remote branch deletion for cleanup: ${branch} (run 'poetic cleanup stale --include-branches --execute')`
|
|
1410
|
+
)
|
|
1411
|
+
);
|
|
1412
|
+
} catch (_queueErr) {
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
errors.push(errorMsg);
|
|
1416
|
+
console.log(chalk2.yellow(` ${errorMsg}`));
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
if (errors.length > 0) {
|
|
1421
|
+
throw new Error(`Branch deletion failed:
|
|
1422
|
+
${errors.join("\n")}`);
|
|
1423
|
+
}
|
|
1424
|
+
} finally {
|
|
1425
|
+
lock.release();
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* Find PR by branch name
|
|
1430
|
+
*/
|
|
1431
|
+
async findPRByBranch(branch) {
|
|
1432
|
+
try {
|
|
1433
|
+
const result = await this.runGhCommand(
|
|
1434
|
+
[
|
|
1435
|
+
"pr",
|
|
1436
|
+
"list",
|
|
1437
|
+
"--json",
|
|
1438
|
+
"number,url,headRefName",
|
|
1439
|
+
"--jq",
|
|
1440
|
+
`.[] | select(.headRefName == "${branch}")`
|
|
1441
|
+
],
|
|
1442
|
+
{
|
|
1443
|
+
operationName: "gh pr list",
|
|
1444
|
+
telemetryTags: { branch }
|
|
1445
|
+
}
|
|
1446
|
+
);
|
|
1447
|
+
const stdout = stdoutToString(result.stdout);
|
|
1448
|
+
if (!stdout.trim()) {
|
|
1449
|
+
return null;
|
|
1450
|
+
}
|
|
1451
|
+
const data = parseJsonWithContext(stdout, "GitHub PR info");
|
|
1452
|
+
return {
|
|
1453
|
+
number: data.number ?? 0,
|
|
1454
|
+
url: data.url ?? "",
|
|
1455
|
+
branch: data.headRefName ?? ""
|
|
1456
|
+
};
|
|
1457
|
+
} catch {
|
|
1458
|
+
return null;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
async listOpenPullRequests(limit = 50) {
|
|
1462
|
+
try {
|
|
1463
|
+
const result = await this.runGhCommand(
|
|
1464
|
+
[
|
|
1465
|
+
"pr",
|
|
1466
|
+
"list",
|
|
1467
|
+
"--state",
|
|
1468
|
+
"open",
|
|
1469
|
+
"--json",
|
|
1470
|
+
"number,url,headRefName",
|
|
1471
|
+
"--limit",
|
|
1472
|
+
String(limit)
|
|
1473
|
+
],
|
|
1474
|
+
{
|
|
1475
|
+
operationName: "gh pr list"
|
|
1476
|
+
}
|
|
1477
|
+
);
|
|
1478
|
+
const stdout = stdoutToString(result.stdout);
|
|
1479
|
+
const trimmed = stdout.trim();
|
|
1480
|
+
if (!trimmed) {
|
|
1481
|
+
return [];
|
|
1482
|
+
}
|
|
1483
|
+
const parsed = parseJsonWithContext(trimmed, "GitHub PR list");
|
|
1484
|
+
return parsed.map((pr) => ({
|
|
1485
|
+
number: Number(pr.number ?? 0),
|
|
1486
|
+
url: pr.url ?? "",
|
|
1487
|
+
branch: pr.headRefName ?? ""
|
|
1488
|
+
})).filter((pr) => pr.number > 0 && pr.branch.trim().length > 0);
|
|
1489
|
+
} catch (error) {
|
|
1490
|
+
const wrapped = wrapError(error, "Failed to list open pull requests");
|
|
1491
|
+
if (wrapped instanceof GitError) {
|
|
1492
|
+
throw wrapped;
|
|
1493
|
+
}
|
|
1494
|
+
throw new GitError(wrapped.message, {
|
|
1495
|
+
operation: "gh pr list"
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Execute gh command with circuit breaker pattern and timeout
|
|
1501
|
+
*
|
|
1502
|
+
* **CRITICAL FIX (CC-009)**: Added default timeout to prevent hangs.
|
|
1503
|
+
* All GitHub API calls now have 30s timeout unless explicitly overridden.
|
|
1504
|
+
*/
|
|
1505
|
+
async runGhCommand(args, options) {
|
|
1506
|
+
const opts = options ?? {};
|
|
1507
|
+
const operationName = opts.operationName;
|
|
1508
|
+
const telemetryTags = opts.telemetryTags;
|
|
1509
|
+
const { operationName: _, telemetryTags: __, ...execaOptions } = opts;
|
|
1510
|
+
const timeout = execaOptions.timeout ?? 3e4;
|
|
1511
|
+
const execaOptionsWithTimeout = {
|
|
1512
|
+
...execaOptions,
|
|
1513
|
+
timeout,
|
|
1514
|
+
killSignal: "SIGTERM"
|
|
1515
|
+
// Graceful termination on timeout
|
|
1516
|
+
};
|
|
1517
|
+
const now = Date.now();
|
|
1518
|
+
if (_PRManagerCore.ghCircuitState.cooldownUntil && now < _PRManagerCore.ghCircuitState.cooldownUntil) {
|
|
1519
|
+
const remainingMs = _PRManagerCore.ghCircuitState.cooldownUntil - now;
|
|
1520
|
+
try {
|
|
1521
|
+
recordMetric("github_api_circuit_block", 1, {
|
|
1522
|
+
provider: "github",
|
|
1523
|
+
operation: operationName ?? args.join(" ")
|
|
1524
|
+
});
|
|
1525
|
+
} catch {
|
|
1526
|
+
}
|
|
1527
|
+
const seconds = Math.ceil(remainingMs / MS_PER_SECOND);
|
|
1528
|
+
throw new Error(
|
|
1529
|
+
`GitHub API temporarily unavailable (circuit breaker cooldown ${seconds}s remaining)`
|
|
1530
|
+
);
|
|
1531
|
+
}
|
|
1532
|
+
try {
|
|
1533
|
+
const result = await execa("gh", args, execaOptionsWithTimeout);
|
|
1534
|
+
this.resetGhCircuit();
|
|
1535
|
+
return result;
|
|
1536
|
+
} catch (error) {
|
|
1537
|
+
if (error && typeof error === "object" && "timedOut" in error && error.timedOut) {
|
|
1538
|
+
const timeoutError = new Error(
|
|
1539
|
+
`GitHub CLI command timed out after ${timeout}ms: gh ${args.join(" ")}`
|
|
1540
|
+
);
|
|
1541
|
+
this.noteGhFailure(operationName ?? args.join(" "), telemetryTags, timeoutError);
|
|
1542
|
+
throw timeoutError;
|
|
1543
|
+
}
|
|
1544
|
+
this.noteGhFailure(operationName ?? args.join(" "), telemetryTags, error);
|
|
1545
|
+
throw error;
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
resetGhCircuit() {
|
|
1549
|
+
if (_PRManagerCore.ghCircuitState.failureCount === 0 && _PRManagerCore.ghCircuitState.cooldownUntil === 0) {
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
_PRManagerCore.ghCircuitState = { failureCount: 0, cooldownUntil: 0 };
|
|
1553
|
+
}
|
|
1554
|
+
noteGhFailure(operationName, telemetryTags, error) {
|
|
1555
|
+
_PRManagerCore.ghCircuitState.failureCount += 1;
|
|
1556
|
+
try {
|
|
1557
|
+
recordMetric("github_api_failure", 1, {
|
|
1558
|
+
provider: "github",
|
|
1559
|
+
operation: operationName,
|
|
1560
|
+
...telemetryTags
|
|
1561
|
+
});
|
|
1562
|
+
} catch {
|
|
1563
|
+
}
|
|
1564
|
+
const { failureThreshold, baseCooldownMs, maxCooldownMs } = this.ghCircuitConfig;
|
|
1565
|
+
if (_PRManagerCore.ghCircuitState.failureCount >= failureThreshold) {
|
|
1566
|
+
const exponent = _PRManagerCore.ghCircuitState.failureCount - failureThreshold;
|
|
1567
|
+
const backoff = Math.min(baseCooldownMs * 2 ** Math.max(0, exponent), maxCooldownMs);
|
|
1568
|
+
_PRManagerCore.ghCircuitState.cooldownUntil = Date.now() + backoff;
|
|
1569
|
+
const now = Date.now();
|
|
1570
|
+
if (now - _PRManagerCore.lastCircuitWarningAt > CIRCUIT_BREAKER_WARNING_INTERVAL_MS) {
|
|
1571
|
+
emitWarning(
|
|
1572
|
+
"PR-003",
|
|
1573
|
+
{
|
|
1574
|
+
taskId: "unknown",
|
|
1575
|
+
subsystem: "pr-manager",
|
|
1576
|
+
provider: "github",
|
|
1577
|
+
executionPhase: "execution"
|
|
1578
|
+
},
|
|
1579
|
+
{
|
|
1580
|
+
metadata: {
|
|
1581
|
+
operation: operationName,
|
|
1582
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1583
|
+
cooldownSeconds: Math.round(backoff / MS_PER_SECOND),
|
|
1584
|
+
failureCount: _PRManagerCore.ghCircuitState.failureCount
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
);
|
|
1588
|
+
_PRManagerCore.lastCircuitWarningAt = now;
|
|
1589
|
+
}
|
|
1590
|
+
try {
|
|
1591
|
+
recordMetric("github_api_circuit_open", 1, {
|
|
1592
|
+
provider: "github",
|
|
1593
|
+
operation: operationName,
|
|
1594
|
+
cooldown_ms: String(backoff),
|
|
1595
|
+
...telemetryTags
|
|
1596
|
+
});
|
|
1597
|
+
} catch {
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
/**
|
|
1602
|
+
* Execute with retry logic and exponential backoff
|
|
1603
|
+
*/
|
|
1604
|
+
async executeWithRetry(operation, operationName, maxRetries = GITHUB_API_RETRY_ATTEMPTS) {
|
|
1605
|
+
let lastError = null;
|
|
1606
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
1607
|
+
try {
|
|
1608
|
+
return await operation();
|
|
1609
|
+
} catch (error) {
|
|
1610
|
+
lastError = error;
|
|
1611
|
+
const err = error;
|
|
1612
|
+
const errMsg = err?.message?.toLowerCase() ?? "";
|
|
1613
|
+
const isTransient = err?.code === "ECONNRESET" || err?.code === "ETIMEDOUT" || errMsg.includes("rate limit") || errMsg.includes("secondary rate limit") || matchesErrorPattern(errMsg, "429") || matchesErrorPattern(errMsg, "403") || errMsg.includes("timeout");
|
|
1614
|
+
if (isTransient && attempt < maxRetries) {
|
|
1615
|
+
const backoffMs = Math.min(
|
|
1616
|
+
1e3 * EXPONENTIAL_BACKOFF_MULTIPLIER ** (attempt - 1),
|
|
1617
|
+
GITHUB_API_RETRY_BACKOFF_CAP_MS
|
|
1618
|
+
);
|
|
1619
|
+
emitWarning(
|
|
1620
|
+
"PR-001",
|
|
1621
|
+
{
|
|
1622
|
+
taskId: "unknown",
|
|
1623
|
+
subsystem: "pr-manager",
|
|
1624
|
+
provider: "github",
|
|
1625
|
+
executionPhase: "execution"
|
|
1626
|
+
},
|
|
1627
|
+
{
|
|
1628
|
+
severity: "WARN" /* WARN */,
|
|
1629
|
+
metadata: {
|
|
1630
|
+
operation: operationName,
|
|
1631
|
+
error: err.message || String(error),
|
|
1632
|
+
attempt,
|
|
1633
|
+
maxRetries,
|
|
1634
|
+
backoffMs,
|
|
1635
|
+
isTransient
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
);
|
|
1639
|
+
await new Promise((resolve) => setTimeout(resolve, backoffMs));
|
|
1640
|
+
} else {
|
|
1641
|
+
emitWarning(
|
|
1642
|
+
"PR-001",
|
|
1643
|
+
{
|
|
1644
|
+
taskId: "unknown",
|
|
1645
|
+
subsystem: "pr-manager",
|
|
1646
|
+
provider: "github",
|
|
1647
|
+
executionPhase: "execution"
|
|
1648
|
+
},
|
|
1649
|
+
{
|
|
1650
|
+
severity: "ERROR" /* ERROR */,
|
|
1651
|
+
metadata: {
|
|
1652
|
+
operation: operationName,
|
|
1653
|
+
error: err.message || String(error),
|
|
1654
|
+
attempt,
|
|
1655
|
+
exhaustedRetries: true
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
);
|
|
1659
|
+
throw lastError ?? new Error(`Retries exhausted for ${operationName}`);
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
if (lastError) {
|
|
1664
|
+
emitWarning(
|
|
1665
|
+
"PR-001",
|
|
1666
|
+
{
|
|
1667
|
+
taskId: "unknown",
|
|
1668
|
+
subsystem: "pr-manager",
|
|
1669
|
+
provider: "github",
|
|
1670
|
+
executionPhase: "execution"
|
|
1671
|
+
},
|
|
1672
|
+
{
|
|
1673
|
+
severity: "ERROR" /* ERROR */,
|
|
1674
|
+
metadata: {
|
|
1675
|
+
operation: operationName,
|
|
1676
|
+
error: lastError.message,
|
|
1677
|
+
exhaustedRetries: true,
|
|
1678
|
+
totalAttempts: maxRetries
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
);
|
|
1682
|
+
}
|
|
1683
|
+
throw lastError ?? new Error(`Retries exhausted for ${operationName}`);
|
|
1684
|
+
}
|
|
1685
|
+
};
|
|
1686
|
+
|
|
1687
|
+
// src/orchestrator/pr-analyzer.ts
|
|
1688
|
+
var PRAnalyzer = class {
|
|
1689
|
+
constructor(core) {
|
|
1690
|
+
this.core = core;
|
|
1691
|
+
}
|
|
1692
|
+
core;
|
|
1693
|
+
/**
|
|
1694
|
+
* Get PR statistics (files changed, additions, deletions, commits)
|
|
1695
|
+
*/
|
|
1696
|
+
async getPRStats(prNumber) {
|
|
1697
|
+
const result = await this.core.runGhCommand(
|
|
1698
|
+
["pr", "view", prNumber.toString(), "--json", "additions,deletions,files,commits,url"],
|
|
1699
|
+
{
|
|
1700
|
+
operationName: "gh pr view stats",
|
|
1701
|
+
telemetryTags: { pr: String(prNumber) }
|
|
1702
|
+
}
|
|
1703
|
+
);
|
|
1704
|
+
const stdout = stdoutToString(result.stdout);
|
|
1705
|
+
const data = parseJsonWithContext(stdout, "GitHub PR stats");
|
|
1706
|
+
const files = Array.isArray(data.files) ? data.files.map((file) => file.path || "").filter(Boolean) : [];
|
|
1707
|
+
return {
|
|
1708
|
+
additions: data.additions ?? 0,
|
|
1709
|
+
deletions: data.deletions ?? 0,
|
|
1710
|
+
changedFiles: files.length,
|
|
1711
|
+
commits: Array.isArray(data.commits) ? data.commits.length : 0,
|
|
1712
|
+
url: data.url ?? "",
|
|
1713
|
+
files
|
|
1714
|
+
};
|
|
1715
|
+
}
|
|
1716
|
+
/**
|
|
1717
|
+
* Fetch PR commits for validation
|
|
1718
|
+
*/
|
|
1719
|
+
async fetchPRCommits(prNumber) {
|
|
1720
|
+
const result = await this.core.executeWithRetry(async () => {
|
|
1721
|
+
const execResult = await this.core.runGhCommand(
|
|
1722
|
+
[
|
|
1723
|
+
"pr",
|
|
1724
|
+
"view",
|
|
1725
|
+
String(prNumber),
|
|
1726
|
+
"--json",
|
|
1727
|
+
"commits",
|
|
1728
|
+
"--jq",
|
|
1729
|
+
".commits[] | {sha: .oid, message: .messageHeadline}"
|
|
1730
|
+
],
|
|
1731
|
+
{
|
|
1732
|
+
operationName: "gh pr view commits",
|
|
1733
|
+
telemetryTags: { pr: String(prNumber) }
|
|
1734
|
+
}
|
|
1735
|
+
);
|
|
1736
|
+
const stdout = stdoutToString(execResult.stdout);
|
|
1737
|
+
if (!stdout.trim()) {
|
|
1738
|
+
return [];
|
|
1739
|
+
}
|
|
1740
|
+
return stdout.trim().split("\n").map((line) => {
|
|
1741
|
+
const parsed = parseJsonWithContext(
|
|
1742
|
+
line,
|
|
1743
|
+
`PR commit line (PR #${prNumber})`
|
|
1744
|
+
);
|
|
1745
|
+
return {
|
|
1746
|
+
sha: String(parsed.sha ?? ""),
|
|
1747
|
+
message: String(parsed.message ?? "")
|
|
1748
|
+
};
|
|
1749
|
+
});
|
|
1750
|
+
}, `fetchPRCommits(PR #${prNumber})`);
|
|
1751
|
+
return result || [];
|
|
1752
|
+
}
|
|
1753
|
+
async getPRCommits(prNumber) {
|
|
1754
|
+
const result = await this.core.executeWithRetry(async () => {
|
|
1755
|
+
const execResult = await this.core.runGhCommand(
|
|
1756
|
+
[
|
|
1757
|
+
"pr",
|
|
1758
|
+
"view",
|
|
1759
|
+
String(prNumber),
|
|
1760
|
+
"--json",
|
|
1761
|
+
"commits",
|
|
1762
|
+
"--jq",
|
|
1763
|
+
".commits[] | {sha: .oid, message: .messageHeadline, createdAt: .committedDate}"
|
|
1764
|
+
],
|
|
1765
|
+
{
|
|
1766
|
+
operationName: "gh pr view commits",
|
|
1767
|
+
telemetryTags: { pr: String(prNumber), detail: "timestamps" }
|
|
1768
|
+
}
|
|
1769
|
+
);
|
|
1770
|
+
const stdout = stdoutToString(execResult.stdout);
|
|
1771
|
+
if (!stdout.trim()) {
|
|
1772
|
+
return [];
|
|
1773
|
+
}
|
|
1774
|
+
return stdout.trim().split("\n").map((line) => {
|
|
1775
|
+
const parsed = parseJsonWithContext(line, `PR commit line (PR #${prNumber})`);
|
|
1776
|
+
return {
|
|
1777
|
+
sha: String(parsed.sha ?? ""),
|
|
1778
|
+
message: String(parsed.message ?? ""),
|
|
1779
|
+
createdAt: parsed.createdAt
|
|
1780
|
+
};
|
|
1781
|
+
});
|
|
1782
|
+
}, `getPRCommits(PR #${prNumber})`);
|
|
1783
|
+
return result || [];
|
|
1784
|
+
}
|
|
1785
|
+
/**
|
|
1786
|
+
* Fetch modified files for a specific commit
|
|
1787
|
+
*/
|
|
1788
|
+
async fetchCommitFiles(sha) {
|
|
1789
|
+
const result = await this.core.executeWithRetry(async () => {
|
|
1790
|
+
const ownerRepo = await this.core.getOwnerRepo();
|
|
1791
|
+
const execResult = await this.core.runGhCommand(
|
|
1792
|
+
["api", `/repos/${ownerRepo}/commits/${sha}`, "--jq", ".files[].filename"],
|
|
1793
|
+
{
|
|
1794
|
+
operationName: "gh api commit files",
|
|
1795
|
+
telemetryTags: { commit: sha.slice(0, 7) }
|
|
1796
|
+
}
|
|
1797
|
+
);
|
|
1798
|
+
const stdout = stdoutToString(execResult.stdout);
|
|
1799
|
+
if (!stdout.trim()) {
|
|
1800
|
+
return [];
|
|
1801
|
+
}
|
|
1802
|
+
return stdout.split("\n").filter(Boolean);
|
|
1803
|
+
}, `fetchCommitFiles(${sha})`);
|
|
1804
|
+
return result || [];
|
|
1805
|
+
}
|
|
1806
|
+
/**
|
|
1807
|
+
* Get all modified files across all commits in a PR
|
|
1808
|
+
*/
|
|
1809
|
+
async getPRModifiedFiles(prNumber) {
|
|
1810
|
+
const commits = await this.fetchPRCommits(prNumber);
|
|
1811
|
+
if (commits.length === 0) {
|
|
1812
|
+
return [];
|
|
1813
|
+
}
|
|
1814
|
+
const modifiedFilesPerCommit = await Promise.all(
|
|
1815
|
+
commits.map((commit) => this.fetchCommitFiles(commit.sha))
|
|
1816
|
+
);
|
|
1817
|
+
const allFiles = modifiedFilesPerCommit.flat();
|
|
1818
|
+
return Array.from(new Set(allFiles));
|
|
1819
|
+
}
|
|
1820
|
+
/**
|
|
1821
|
+
* Get modified files for PR commits created after a specific timestamp.
|
|
1822
|
+
* Used to prevent stale commits (from previous tasks) from passing validation.
|
|
1823
|
+
*/
|
|
1824
|
+
async getPRModifiedFilesAfter(prNumber, after) {
|
|
1825
|
+
const threshold = after.getTime();
|
|
1826
|
+
if (Number.isNaN(threshold)) {
|
|
1827
|
+
return [];
|
|
1828
|
+
}
|
|
1829
|
+
const commits = await this.getPRCommits(prNumber);
|
|
1830
|
+
if (commits.length === 0) {
|
|
1831
|
+
return [];
|
|
1832
|
+
}
|
|
1833
|
+
const recentCommits = commits.filter((commit) => {
|
|
1834
|
+
if (!commit.createdAt) {
|
|
1835
|
+
return false;
|
|
1836
|
+
}
|
|
1837
|
+
const created = new Date(commit.createdAt);
|
|
1838
|
+
return !Number.isNaN(created.getTime()) && created.getTime() > threshold;
|
|
1839
|
+
});
|
|
1840
|
+
if (recentCommits.length === 0) {
|
|
1841
|
+
return [];
|
|
1842
|
+
}
|
|
1843
|
+
const modifiedFilesPerCommit = await Promise.all(
|
|
1844
|
+
recentCommits.map((commit) => this.fetchCommitFiles(commit.sha))
|
|
1845
|
+
);
|
|
1846
|
+
const allFiles = modifiedFilesPerCommit.flat();
|
|
1847
|
+
return Array.from(new Set(allFiles));
|
|
1848
|
+
}
|
|
1849
|
+
};
|
|
1850
|
+
|
|
1851
|
+
// src/orchestrator/github-pr-manager.ts
|
|
1852
|
+
var GitHubPRManager = class {
|
|
1853
|
+
core;
|
|
1854
|
+
analyzer;
|
|
1855
|
+
constructor() {
|
|
1856
|
+
this.core = new PRManagerCore();
|
|
1857
|
+
this.analyzer = new PRAnalyzer(this.core);
|
|
1858
|
+
}
|
|
1859
|
+
// ===== Artifact Management (from PRManagerCore) =====
|
|
1860
|
+
async cleanupArtifacts(options = {}) {
|
|
1861
|
+
return this.core.cleanupArtifacts(options);
|
|
1862
|
+
}
|
|
1863
|
+
async getArtifactStats() {
|
|
1864
|
+
return this.core.getArtifactStats();
|
|
1865
|
+
}
|
|
1866
|
+
async close() {
|
|
1867
|
+
return this.core.close();
|
|
1868
|
+
}
|
|
1869
|
+
// ===== PR Creation and Branch Management (from PRManagerCore) =====
|
|
1870
|
+
async createVariantPR(options) {
|
|
1871
|
+
return this.core.createVariantPR(options);
|
|
1872
|
+
}
|
|
1873
|
+
async createDraftPRForBranch(options) {
|
|
1874
|
+
return this.core.createDraftPRForBranch(options);
|
|
1875
|
+
}
|
|
1876
|
+
async getOwnerRepo() {
|
|
1877
|
+
return this.core.getOwnerRepo();
|
|
1878
|
+
}
|
|
1879
|
+
async checkCursorCloudAvailability() {
|
|
1880
|
+
const status = await this.getCursorCloudPrerequisitesStatus();
|
|
1881
|
+
return status.isAvailable;
|
|
1882
|
+
}
|
|
1883
|
+
async getCursorCloudPrerequisitesStatus() {
|
|
1884
|
+
const missingPrerequisites = [];
|
|
1885
|
+
const suggestions = [];
|
|
1886
|
+
try {
|
|
1887
|
+
await execa2("gh", ["--version"]);
|
|
1888
|
+
} catch {
|
|
1889
|
+
missingPrerequisites.push("GitHub CLI (gh) not installed");
|
|
1890
|
+
suggestions.push("Install GitHub CLI: https://cli.github.com/");
|
|
1891
|
+
return { isAvailable: false, missingPrerequisites, suggestions };
|
|
1892
|
+
}
|
|
1893
|
+
try {
|
|
1894
|
+
await execa2("gh", ["auth", "status"]);
|
|
1895
|
+
} catch {
|
|
1896
|
+
missingPrerequisites.push("GitHub CLI not authenticated");
|
|
1897
|
+
suggestions.push("Run: gh auth login");
|
|
1898
|
+
}
|
|
1899
|
+
try {
|
|
1900
|
+
const { stdout } = await execa2("git", ["remote", "get-url", "origin"]);
|
|
1901
|
+
if (!/github\.com[:/][^/\s]+\/[^/\s]+(?:\.git)?$/i.test(stdout.trim())) {
|
|
1902
|
+
missingPrerequisites.push("No git remote origin configured");
|
|
1903
|
+
suggestions.push("Set up git remote: git remote add origin <github-repo-url>");
|
|
1904
|
+
}
|
|
1905
|
+
} catch {
|
|
1906
|
+
missingPrerequisites.push("No git remote origin configured");
|
|
1907
|
+
suggestions.push("Set up git remote: git remote add origin <github-repo-url>");
|
|
1908
|
+
}
|
|
1909
|
+
return {
|
|
1910
|
+
isAvailable: missingPrerequisites.length === 0,
|
|
1911
|
+
missingPrerequisites,
|
|
1912
|
+
suggestions
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
async getPRBranch(prNumber) {
|
|
1916
|
+
return this.core.getPRBranch(prNumber);
|
|
1917
|
+
}
|
|
1918
|
+
async branchExists(branch, cwd) {
|
|
1919
|
+
return this.core.branchExists(branch, cwd);
|
|
1920
|
+
}
|
|
1921
|
+
async checkoutBranch(branch) {
|
|
1922
|
+
return this.core.checkoutBranch(branch);
|
|
1923
|
+
}
|
|
1924
|
+
async getCurrentBranch(cwd) {
|
|
1925
|
+
return this.core.getCurrentBranch(cwd);
|
|
1926
|
+
}
|
|
1927
|
+
async isWorkingDirectoryClean(cwd) {
|
|
1928
|
+
return this.core.isWorkingDirectoryClean(cwd);
|
|
1929
|
+
}
|
|
1930
|
+
async stageAll() {
|
|
1931
|
+
return this.core.stageAll();
|
|
1932
|
+
}
|
|
1933
|
+
async commit(message) {
|
|
1934
|
+
return this.core.commit(message);
|
|
1935
|
+
}
|
|
1936
|
+
async commitToBranch(branchName, message, cwd) {
|
|
1937
|
+
return this.core.commitToBranch(branchName, message, cwd);
|
|
1938
|
+
}
|
|
1939
|
+
async push(branch) {
|
|
1940
|
+
return this.core.push(branch);
|
|
1941
|
+
}
|
|
1942
|
+
async getPRUrl(prNumber) {
|
|
1943
|
+
return this.core.getPRUrl(prNumber);
|
|
1944
|
+
}
|
|
1945
|
+
async closePR(prNumber) {
|
|
1946
|
+
return this.core.closePR(prNumber);
|
|
1947
|
+
}
|
|
1948
|
+
async deleteBranch(branch, options = {}) {
|
|
1949
|
+
return this.core.deleteBranch(branch, options);
|
|
1950
|
+
}
|
|
1951
|
+
async findPRByBranch(branch) {
|
|
1952
|
+
return this.core.findPRByBranch(branch);
|
|
1953
|
+
}
|
|
1954
|
+
async listOpenPullRequests(limit = 50) {
|
|
1955
|
+
return this.core.listOpenPullRequests(limit);
|
|
1956
|
+
}
|
|
1957
|
+
async executeWithRetry(operation, operationName, maxRetries = 3) {
|
|
1958
|
+
return this.core.executeWithRetry(operation, operationName, maxRetries);
|
|
1959
|
+
}
|
|
1960
|
+
// ===== PR Analysis (from PRAnalyzer) =====
|
|
1961
|
+
async getPRStats(prNumber) {
|
|
1962
|
+
return this.analyzer.getPRStats(prNumber);
|
|
1963
|
+
}
|
|
1964
|
+
async fetchPRCommits(prNumber) {
|
|
1965
|
+
return this.analyzer.fetchPRCommits(prNumber);
|
|
1966
|
+
}
|
|
1967
|
+
async getPRCommits(prNumber) {
|
|
1968
|
+
return this.analyzer.getPRCommits(prNumber);
|
|
1969
|
+
}
|
|
1970
|
+
async fetchCommitFiles(sha) {
|
|
1971
|
+
return this.analyzer.fetchCommitFiles(sha);
|
|
1972
|
+
}
|
|
1973
|
+
async getPRModifiedFiles(prNumber) {
|
|
1974
|
+
return this.analyzer.getPRModifiedFiles(prNumber);
|
|
1975
|
+
}
|
|
1976
|
+
async getPRModifiedFilesAfter(prNumber, after) {
|
|
1977
|
+
return this.analyzer.getPRModifiedFilesAfter(prNumber, after);
|
|
1978
|
+
}
|
|
1979
|
+
};
|
|
1980
|
+
|
|
1981
|
+
export {
|
|
1982
|
+
GitHubPRManager
|
|
1983
|
+
};
|
|
1984
|
+
//# sourceMappingURL=chunk-VPHVFK4A.js.map
|