@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,1581 @@
|
|
|
1
|
+
import {
|
|
2
|
+
killTmuxSessionWithPaneFallback,
|
|
3
|
+
markTmuxSessionOrphaned,
|
|
4
|
+
recordTmuxSessionPanePid,
|
|
5
|
+
registerTmuxSession,
|
|
6
|
+
unregisterTmuxSession
|
|
7
|
+
} from "./chunk-4CUY7AFY.js";
|
|
8
|
+
import {
|
|
9
|
+
CircuitBreakerError,
|
|
10
|
+
createCircuitBreakerOptions,
|
|
11
|
+
executeWithCircuitBreaker
|
|
12
|
+
} from "./chunk-MWK5UZQ3.js";
|
|
13
|
+
import {
|
|
14
|
+
shouldExcludeFile
|
|
15
|
+
} from "./chunk-NS33V3IM.js";
|
|
16
|
+
import {
|
|
17
|
+
DEFAULT_TIMEOUT,
|
|
18
|
+
POETIC_PROCESS_GROUP_OWNER_ENV,
|
|
19
|
+
TMUX_COMPLETION_SIGNAL_GRACE_MS,
|
|
20
|
+
acquireProcessSlot,
|
|
21
|
+
assertProviderBypassHasBoundaryProof,
|
|
22
|
+
createLogger,
|
|
23
|
+
getProcessLifecycleManager,
|
|
24
|
+
globalProcessLimiter,
|
|
25
|
+
providerExecutionTransportStreamOptions,
|
|
26
|
+
resolveProviderProcessGroupOwnership
|
|
27
|
+
} from "./chunk-PFTQBXS6.js";
|
|
28
|
+
import {
|
|
29
|
+
evaluateCpuTimeProgressStreak,
|
|
30
|
+
readCpuTimeSeconds,
|
|
31
|
+
resolveIdleTimeoutsMs
|
|
32
|
+
} from "./chunk-E3NTPHEO.js";
|
|
33
|
+
import {
|
|
34
|
+
getProviderRuntimeQuirks
|
|
35
|
+
} from "./chunk-FC23CTXV.js";
|
|
36
|
+
import {
|
|
37
|
+
createRetryOptions,
|
|
38
|
+
withRetry
|
|
39
|
+
} from "./chunk-CKNX3TTP.js";
|
|
40
|
+
import {
|
|
41
|
+
ModelInvocationsDB,
|
|
42
|
+
ensurePendingInvocationCostEnrichment,
|
|
43
|
+
generateInvocationId,
|
|
44
|
+
resolveInvocationRegistryVersion,
|
|
45
|
+
resolveInvocationsDbPath
|
|
46
|
+
} from "./chunk-GKN3HMN4.js";
|
|
47
|
+
import {
|
|
48
|
+
JsonParseError,
|
|
49
|
+
safeJsonParse
|
|
50
|
+
} from "./chunk-S54MKU6V.js";
|
|
51
|
+
import {
|
|
52
|
+
isSandboxAuthorityEnvVar
|
|
53
|
+
} from "./chunk-6TZJRKNW.js";
|
|
54
|
+
import {
|
|
55
|
+
wrapWithSandbox
|
|
56
|
+
} from "./chunk-PCAGC5MR.js";
|
|
57
|
+
import {
|
|
58
|
+
execGit
|
|
59
|
+
} from "./chunk-KNDYMVWN.js";
|
|
60
|
+
import {
|
|
61
|
+
ProviderExecutionError,
|
|
62
|
+
providerExecutionErrorStreamOptions
|
|
63
|
+
} from "./chunk-LUVKFFWR.js";
|
|
64
|
+
import {
|
|
65
|
+
quotePosixShellArg
|
|
66
|
+
} from "./chunk-N5DX4JAK.js";
|
|
67
|
+
import {
|
|
68
|
+
ProviderRegistry
|
|
69
|
+
} from "./chunk-AT4TNPWW.js";
|
|
70
|
+
import {
|
|
71
|
+
resolvePoeticRoot
|
|
72
|
+
} from "./chunk-LEIIWPWQ.js";
|
|
73
|
+
import {
|
|
74
|
+
debugLog,
|
|
75
|
+
emitWarning
|
|
76
|
+
} from "./chunk-EJGCZGUF.js";
|
|
77
|
+
import {
|
|
78
|
+
POETIC_ACTIVE_TASK_ID,
|
|
79
|
+
POETIC_MOCK_PROVIDERS,
|
|
80
|
+
POETIC_TIMEOUT_MS,
|
|
81
|
+
POETIC_WORKER_VARIANT,
|
|
82
|
+
readEnv
|
|
83
|
+
} from "./chunk-5DLKYTQX.js";
|
|
84
|
+
|
|
85
|
+
// src/core/providers/shared/execution-transport.ts
|
|
86
|
+
import { randomBytes } from "crypto";
|
|
87
|
+
import * as fs from "fs/promises";
|
|
88
|
+
import { open as fsOpen } from "fs/promises";
|
|
89
|
+
import * as path from "path";
|
|
90
|
+
import { StringDecoder } from "string_decoder";
|
|
91
|
+
import { execa } from "execa";
|
|
92
|
+
var transportLogger = createLogger("ExecutionTransport");
|
|
93
|
+
var VALID_EXECUTION_TRANSPORT_MODES = [
|
|
94
|
+
"auto",
|
|
95
|
+
"headless",
|
|
96
|
+
"tmux-exec",
|
|
97
|
+
"interactive"
|
|
98
|
+
];
|
|
99
|
+
function isTmuxExecStatusAuthoritative(input) {
|
|
100
|
+
return input.statusPresent && !input.sessionAlive;
|
|
101
|
+
}
|
|
102
|
+
function parseExecutionTransportMode(value) {
|
|
103
|
+
if (!value) return void 0;
|
|
104
|
+
const normalized = value.trim().toLowerCase();
|
|
105
|
+
if (normalized === "interactive") {
|
|
106
|
+
return "tmux-exec";
|
|
107
|
+
}
|
|
108
|
+
if (VALID_EXECUTION_TRANSPORT_MODES.includes(normalized)) {
|
|
109
|
+
return normalized;
|
|
110
|
+
}
|
|
111
|
+
return void 0;
|
|
112
|
+
}
|
|
113
|
+
var tmuxAvailabilityProbe;
|
|
114
|
+
async function isTmuxAvailable() {
|
|
115
|
+
if (tmuxAvailabilityProbe === void 0) {
|
|
116
|
+
tmuxAvailabilityProbe = (async () => {
|
|
117
|
+
try {
|
|
118
|
+
const result = await execa("tmux", ["-V"], { reject: false });
|
|
119
|
+
return result.exitCode === 0;
|
|
120
|
+
} catch {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
})();
|
|
124
|
+
}
|
|
125
|
+
return tmuxAvailabilityProbe;
|
|
126
|
+
}
|
|
127
|
+
function resolveRequestedTransportMode(options) {
|
|
128
|
+
const providerKey = options.provider?.trim().toUpperCase().replace(/[^A-Z0-9_]/g, "_");
|
|
129
|
+
const envRequested = (providerKey ? parseExecutionTransportMode(options.env?.[`POETIC_${providerKey}_EXECUTION_TRANSPORT`]) : void 0) ?? parseExecutionTransportMode(options.env?.POETIC_PROVIDER_EXECUTION_TRANSPORT) ?? parseExecutionTransportMode(options.env?.POETIC_EXECUTION_TRANSPORT);
|
|
130
|
+
const requested = options.requested ?? envRequested ?? options.configured ?? "headless";
|
|
131
|
+
return requested === "interactive" ? "tmux-exec" : requested;
|
|
132
|
+
}
|
|
133
|
+
async function resolveExecutionTransportMode(options) {
|
|
134
|
+
const normalizedRequested = resolveRequestedTransportMode({
|
|
135
|
+
requested: options.requested,
|
|
136
|
+
configured: options.configured,
|
|
137
|
+
env: options.env,
|
|
138
|
+
provider: options.provider
|
|
139
|
+
});
|
|
140
|
+
if (normalizedRequested === "headless") return "headless";
|
|
141
|
+
const available = await (options.tmuxAvailable ?? isTmuxAvailable)();
|
|
142
|
+
if (available) return "tmux-exec";
|
|
143
|
+
if (normalizedRequested === "tmux-exec") {
|
|
144
|
+
throw new ProviderExecutionError(
|
|
145
|
+
"tmux-exec provider execution transport requires tmux, but tmux was not found on PATH.",
|
|
146
|
+
{ retryable: false, reason: "tmux_exec_transport_unavailable" }
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
return "headless";
|
|
150
|
+
}
|
|
151
|
+
async function resolveProviderTransportDecision(options) {
|
|
152
|
+
const quirks = getProviderRuntimeQuirks(options.provider);
|
|
153
|
+
const requestedMode = resolveRequestedTransportMode({
|
|
154
|
+
requested: options.requested,
|
|
155
|
+
configured: options.configured,
|
|
156
|
+
env: options.env,
|
|
157
|
+
provider: options.provider
|
|
158
|
+
});
|
|
159
|
+
if (options.forceHeadlessReason) {
|
|
160
|
+
const requested = requestedMode === "headless" ? "headless" : "tmux-exec";
|
|
161
|
+
return {
|
|
162
|
+
resolved: "headless",
|
|
163
|
+
requested,
|
|
164
|
+
downgradeReason: requested === "tmux-exec" ? options.forceHeadlessReason : void 0
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
const support = quirks?.tmuxExecSupport ?? "none";
|
|
168
|
+
if (support === "none") {
|
|
169
|
+
if (requestedMode === "tmux-exec") {
|
|
170
|
+
return {
|
|
171
|
+
resolved: "headless",
|
|
172
|
+
requested: "tmux-exec",
|
|
173
|
+
downgradeReason: `${options.provider} is not validated for tmux-exec under a pane pty; using headless`
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
return { resolved: "headless", requested: "headless" };
|
|
177
|
+
}
|
|
178
|
+
const resolved = await resolveExecutionTransportMode({
|
|
179
|
+
requested: options.requested,
|
|
180
|
+
configured: options.configured,
|
|
181
|
+
env: options.env,
|
|
182
|
+
provider: options.provider,
|
|
183
|
+
tmuxAvailable: options.tmuxAvailable
|
|
184
|
+
});
|
|
185
|
+
if (resolved !== "tmux-exec") {
|
|
186
|
+
return { resolved, requested: resolved };
|
|
187
|
+
}
|
|
188
|
+
if (support === "read-only") {
|
|
189
|
+
const isReadOnly = options.executionIntent === "analysis" || options.readOnlyWorkingDir === true;
|
|
190
|
+
if (!isReadOnly) {
|
|
191
|
+
return {
|
|
192
|
+
resolved: "headless",
|
|
193
|
+
requested: "tmux-exec",
|
|
194
|
+
downgradeReason: `${options.provider} supports tmux-exec only for analysis/read-only runs; using headless for this write-intent run`
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return { resolved: "tmux-exec", requested: "tmux-exec" };
|
|
199
|
+
}
|
|
200
|
+
function reportTransportDecision(provider, decision, debug) {
|
|
201
|
+
if (decision.downgradeReason) {
|
|
202
|
+
transportLogger.warn(
|
|
203
|
+
`[${provider}] execution transport downgraded: ${decision.downgradeReason}`,
|
|
204
|
+
{
|
|
205
|
+
provider,
|
|
206
|
+
requested: decision.requested,
|
|
207
|
+
resolved: decision.resolved
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
debug?.(`[${provider}] execution transport resolved to ${decision.resolved}`, {
|
|
213
|
+
provider,
|
|
214
|
+
resolved: decision.resolved
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
async function selectProviderExecutor(options) {
|
|
218
|
+
const decision = await resolveProviderTransportDecision(options);
|
|
219
|
+
options.onDecision?.(decision);
|
|
220
|
+
const execute = decision.resolved === "tmux-exec" ? executeProviderCommandTmuxExec : options.headless;
|
|
221
|
+
return { execute, decision };
|
|
222
|
+
}
|
|
223
|
+
function sessionName(providerName) {
|
|
224
|
+
const safeProvider = providerName.toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/^-+|-+$/g, "").slice(0, 24);
|
|
225
|
+
return `poetic-${safeProvider || "provider"}-${randomBytes(4).toString("hex")}`;
|
|
226
|
+
}
|
|
227
|
+
async function writePromptFile(tmpDir, input) {
|
|
228
|
+
if (input === void 0) return void 0;
|
|
229
|
+
const file = path.join(tmpDir, "prompt.txt");
|
|
230
|
+
await fs.writeFile(file, input, { mode: 384 });
|
|
231
|
+
return file;
|
|
232
|
+
}
|
|
233
|
+
async function writeEnvFile(tmpDir, env) {
|
|
234
|
+
const ownership = resolveProviderProcessGroupOwnership();
|
|
235
|
+
const paneEnv = {
|
|
236
|
+
...commandEnvironment(env),
|
|
237
|
+
[POETIC_PROCESS_GROUP_OWNER_ENV]: ownership.owner
|
|
238
|
+
};
|
|
239
|
+
const lines = Object.entries(commandEnvironment(paneEnv)).filter(
|
|
240
|
+
(entry) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(entry[0]) && typeof entry[1] === "string"
|
|
241
|
+
).map(([key, value]) => `export ${key}=${quotePosixShellArg(value)}`);
|
|
242
|
+
const file = path.join(tmpDir, "env.sh");
|
|
243
|
+
await fs.writeFile(file, lines.length > 0 ? `${lines.join("\n")}
|
|
244
|
+
` : "", { mode: 384 });
|
|
245
|
+
return file;
|
|
246
|
+
}
|
|
247
|
+
function resolveCommandName(command) {
|
|
248
|
+
const posix2 = path.posix.basename(command);
|
|
249
|
+
const win322 = path.win32.basename(command);
|
|
250
|
+
const basename = posix2.length <= win322.length ? posix2 : win322;
|
|
251
|
+
return basename.replace(/\.(exe|cmd|bat|ps1)$/i, "").toLowerCase().replace(/[^a-z0-9_-]/g, "_");
|
|
252
|
+
}
|
|
253
|
+
function commandEnvironment(env) {
|
|
254
|
+
const source = env ?? process.env;
|
|
255
|
+
const next = { ...source };
|
|
256
|
+
for (const key of Object.keys(next)) {
|
|
257
|
+
if (isSandboxAuthorityEnvVar(key)) {
|
|
258
|
+
delete next[key];
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return next;
|
|
262
|
+
}
|
|
263
|
+
function buildTmuxShellCommand(options) {
|
|
264
|
+
const argv = [options.command, ...options.args].map(quotePosixShellArg).join(" ");
|
|
265
|
+
const input = options.promptFile ? ` < ${quotePosixShellArg(options.promptFile)}` : " < /dev/null";
|
|
266
|
+
const output = ` > ${quotePosixShellArg(options.stdoutFile)} 2> ${quotePosixShellArg(options.stderrFile)}`;
|
|
267
|
+
const innerScript = [
|
|
268
|
+
`. ${quotePosixShellArg(options.envFile)}`,
|
|
269
|
+
`rm -f ${quotePosixShellArg(options.envFile)}`,
|
|
270
|
+
`exec ${argv}${input}${output}`
|
|
271
|
+
].join("; ");
|
|
272
|
+
const runner = `env -i sh -c ${quotePosixShellArg(innerScript)}`;
|
|
273
|
+
return [
|
|
274
|
+
runner,
|
|
275
|
+
"status=$?",
|
|
276
|
+
`printf '%s' "$status" > ${quotePosixShellArg(options.statusFile)}`,
|
|
277
|
+
'exit "$status"'
|
|
278
|
+
].join("; ");
|
|
279
|
+
}
|
|
280
|
+
async function readTextIfPresent(file) {
|
|
281
|
+
try {
|
|
282
|
+
return await fs.readFile(file, "utf8");
|
|
283
|
+
} catch (error) {
|
|
284
|
+
if (error.code === "ENOENT") return "";
|
|
285
|
+
throw error;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
var OutputFileTail = class {
|
|
289
|
+
constructor(file) {
|
|
290
|
+
this.file = file;
|
|
291
|
+
}
|
|
292
|
+
file;
|
|
293
|
+
offset = 0;
|
|
294
|
+
decoder = new StringDecoder("utf8");
|
|
295
|
+
/** Read any bytes appended since the last call (bytes + decoded text). */
|
|
296
|
+
async read() {
|
|
297
|
+
let handle;
|
|
298
|
+
try {
|
|
299
|
+
handle = await fsOpen(this.file, "r");
|
|
300
|
+
const { size } = await handle.stat();
|
|
301
|
+
if (size <= this.offset) {
|
|
302
|
+
if (size < this.offset) {
|
|
303
|
+
this.offset = 0;
|
|
304
|
+
this.decoder = new StringDecoder("utf8");
|
|
305
|
+
}
|
|
306
|
+
return { bytes: Buffer.alloc(0), text: "" };
|
|
307
|
+
}
|
|
308
|
+
const length = size - this.offset;
|
|
309
|
+
const buffer = Buffer.allocUnsafe(length);
|
|
310
|
+
const { bytesRead } = await handle.read(buffer, 0, length, this.offset);
|
|
311
|
+
this.offset += bytesRead;
|
|
312
|
+
const bytes = Buffer.from(buffer.subarray(0, bytesRead));
|
|
313
|
+
const text = this.decoder.write(bytes);
|
|
314
|
+
return { bytes, text };
|
|
315
|
+
} catch (error) {
|
|
316
|
+
if (error.code === "ENOENT") {
|
|
317
|
+
return { bytes: Buffer.alloc(0), text: "" };
|
|
318
|
+
}
|
|
319
|
+
throw error;
|
|
320
|
+
} finally {
|
|
321
|
+
await handle?.close().catch(() => {
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Flush incomplete multibyte sequence as presentation text only.
|
|
327
|
+
* Authoritative raw observers already received those bytes on the read that
|
|
328
|
+
* advanced the offset — do not re-deliver them as raw chunks.
|
|
329
|
+
*/
|
|
330
|
+
flushText() {
|
|
331
|
+
return this.decoder.end();
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
function deliverRawBytes(observer, bytes) {
|
|
335
|
+
if (!observer || bytes.length === 0) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
try {
|
|
339
|
+
observer(bytes);
|
|
340
|
+
} catch {
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function sleep(ms) {
|
|
344
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
345
|
+
}
|
|
346
|
+
function parseTmuxPanePid(value) {
|
|
347
|
+
const text = value?.trim();
|
|
348
|
+
if (!text || !/^\d+$/.test(text)) return void 0;
|
|
349
|
+
const pid = Number.parseInt(text, 10);
|
|
350
|
+
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
351
|
+
}
|
|
352
|
+
function firstUsefulDiagnosticLine(text) {
|
|
353
|
+
return text.split(/\r?\n/).map((line) => line.trim()).find((line) => line.length > 0) ?? "no error output";
|
|
354
|
+
}
|
|
355
|
+
function tmuxTransportStreamOptions(fullStdout, fullStderr, options) {
|
|
356
|
+
return providerExecutionTransportStreamOptions(fullStdout, fullStderr, {
|
|
357
|
+
maxPublicLength: options?.maxPublicLength ?? 4096
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
function throwIfTmuxNonZeroExit(options, result, fullStreams) {
|
|
361
|
+
if (result.exitCode === 0) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const streams = tmuxTransportStreamOptions(
|
|
365
|
+
fullStreams?.stdout ?? result.stdout,
|
|
366
|
+
fullStreams?.stderr ?? result.stderr,
|
|
367
|
+
{ maxPublicLength: 4096 }
|
|
368
|
+
);
|
|
369
|
+
const diagnostic = firstUsefulDiagnosticLine(streams.stderr || streams.stdout || "");
|
|
370
|
+
throw new ProviderExecutionError(
|
|
371
|
+
`${options.metadata.name} CLI exited with code ${result.exitCode}: ${diagnostic}`,
|
|
372
|
+
{
|
|
373
|
+
retryable: false,
|
|
374
|
+
exitCode: result.exitCode,
|
|
375
|
+
reason: "non_zero_exit",
|
|
376
|
+
...streams
|
|
377
|
+
}
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
async function tmuxSessionExists(session, env) {
|
|
381
|
+
const result = await execa("tmux", ["has-session", "-t", session], {
|
|
382
|
+
env: tmuxClientEnv(env),
|
|
383
|
+
reject: false,
|
|
384
|
+
timeout: 5e3
|
|
385
|
+
}).catch(() => void 0);
|
|
386
|
+
return result?.exitCode === 0;
|
|
387
|
+
}
|
|
388
|
+
async function killTmuxSession(params) {
|
|
389
|
+
return killTmuxSessionWithPaneFallback({
|
|
390
|
+
session: params.session,
|
|
391
|
+
tmuxEnv: params.env,
|
|
392
|
+
panePid: params.panePid,
|
|
393
|
+
timeoutMs: 1e4
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
async function registerTmuxProcessLifecycle(params) {
|
|
397
|
+
const plm = getProcessLifecycleManager();
|
|
398
|
+
if (!plm) return void 0;
|
|
399
|
+
try {
|
|
400
|
+
return await plm.registerProcessWithOptions({
|
|
401
|
+
completionPromise: params.completionPromise,
|
|
402
|
+
terminateFn: async () => {
|
|
403
|
+
await params.terminate();
|
|
404
|
+
},
|
|
405
|
+
verificationFn: async () => true,
|
|
406
|
+
processType: "local",
|
|
407
|
+
timeoutMs: 0,
|
|
408
|
+
metadata: {
|
|
409
|
+
provider: params.options.metadata.name,
|
|
410
|
+
command: params.options.command,
|
|
411
|
+
args: params.options.args,
|
|
412
|
+
cwd: params.options.workingDir,
|
|
413
|
+
transport: "tmux-exec",
|
|
414
|
+
session: params.session,
|
|
415
|
+
...params.panePid !== void 0 ? { panePid: params.panePid } : {},
|
|
416
|
+
startTime: Date.now()
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
} catch (error) {
|
|
420
|
+
transportLogger.warn("[tmux-exec] ProcessLifecycleManager registration failed", {
|
|
421
|
+
provider: params.options.metadata.name,
|
|
422
|
+
error: error instanceof Error ? error.message : String(error)
|
|
423
|
+
});
|
|
424
|
+
return void 0;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
function tmuxClientEnv(env) {
|
|
428
|
+
const source = env ?? process.env;
|
|
429
|
+
const allowList = ["PATH", "HOME", "TMUX", "TMUX_TMPDIR", "TMPDIR", "USER", "LOGNAME", "TERM"];
|
|
430
|
+
const minimal = {};
|
|
431
|
+
for (const key of allowList) {
|
|
432
|
+
const value = source[key];
|
|
433
|
+
if (typeof value === "string") {
|
|
434
|
+
minimal[key] = value;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return minimal;
|
|
438
|
+
}
|
|
439
|
+
async function removeTmpDir(tmpDir) {
|
|
440
|
+
await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
async function executeProviderCommandTmuxExec(options) {
|
|
444
|
+
const session = sessionName(options.metadata.id ?? options.metadata.name);
|
|
445
|
+
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
446
|
+
const idleTimeouts = resolveIdleTimeoutsMs(options.command, options.args, timeout, {
|
|
447
|
+
idleWarnMs: options.idleWarnMs,
|
|
448
|
+
idleKillMs: options.idleKillMs
|
|
449
|
+
});
|
|
450
|
+
const tmpDir = await fs.mkdtemp(path.join("/var/tmp", "poetic-tmux-exec-"));
|
|
451
|
+
const stdoutFile = path.join(tmpDir, "stdout.log");
|
|
452
|
+
const stderrFile = path.join(tmpDir, "stderr.log");
|
|
453
|
+
const statusFile = path.join(tmpDir, "status");
|
|
454
|
+
let shellCommand;
|
|
455
|
+
try {
|
|
456
|
+
const promptFile = await writePromptFile(tmpDir, options.input);
|
|
457
|
+
const envFile = await writeEnvFile(tmpDir, options.env);
|
|
458
|
+
await fs.writeFile(stdoutFile, "");
|
|
459
|
+
await fs.writeFile(stderrFile, "");
|
|
460
|
+
const sandboxed = options.disablePoeticSandbox === true ? { command: options.command, args: options.args, sandboxed: false } : wrapWithSandbox({
|
|
461
|
+
workingDir: options.workingDir,
|
|
462
|
+
command: options.command,
|
|
463
|
+
args: options.args,
|
|
464
|
+
providerName: options.metadata.name,
|
|
465
|
+
extraWritePaths: options.extraWritePaths,
|
|
466
|
+
readOnlyWorkingDir: options.readOnlyWorkingDir,
|
|
467
|
+
// Provider execution path (tmux transport), so the same
|
|
468
|
+
// write-boundary requirement as base-runner applies. Read-only runs
|
|
469
|
+
// still pass readOnlyWorkingDir and stay exempt.
|
|
470
|
+
requiresBoundaryForWrites: true,
|
|
471
|
+
env: options.env,
|
|
472
|
+
providerId: options.metadata.id ?? resolveCommandName(options.command)
|
|
473
|
+
});
|
|
474
|
+
assertProviderBypassHasBoundaryProof(
|
|
475
|
+
options.metadata,
|
|
476
|
+
options.args,
|
|
477
|
+
sandboxed,
|
|
478
|
+
options.providerInternalSandboxBypass
|
|
479
|
+
);
|
|
480
|
+
shellCommand = buildTmuxShellCommand({
|
|
481
|
+
command: sandboxed.command,
|
|
482
|
+
args: sandboxed.args,
|
|
483
|
+
envFile,
|
|
484
|
+
promptFile,
|
|
485
|
+
stdoutFile,
|
|
486
|
+
stderrFile,
|
|
487
|
+
statusFile
|
|
488
|
+
});
|
|
489
|
+
} catch (error) {
|
|
490
|
+
await removeTmpDir(tmpDir);
|
|
491
|
+
throw error;
|
|
492
|
+
}
|
|
493
|
+
const readFullTerminalStdout = () => readTextIfPresent(stdoutFile);
|
|
494
|
+
const readFullTerminalStderr = () => readTextIfPresent(stderrFile);
|
|
495
|
+
const startedAt = Date.now();
|
|
496
|
+
let aborted = false;
|
|
497
|
+
let stdoutTail;
|
|
498
|
+
let stderrTail;
|
|
499
|
+
let firstOutputSeen = false;
|
|
500
|
+
let completionSignalSeen = false;
|
|
501
|
+
let completionSignalSeenAt = null;
|
|
502
|
+
let exitedForCompletionSignal = false;
|
|
503
|
+
let lastActivityAt = startedAt;
|
|
504
|
+
const completionSignalGraceMs = Math.max(
|
|
505
|
+
0,
|
|
506
|
+
options.completionSignalGraceMs ?? TMUX_COMPLETION_SIGNAL_GRACE_MS
|
|
507
|
+
);
|
|
508
|
+
let tmuxPanePid;
|
|
509
|
+
let lastCpuTimeSeconds;
|
|
510
|
+
let consecutiveBusyCpuPolls = 0;
|
|
511
|
+
const abort = async () => {
|
|
512
|
+
aborted = true;
|
|
513
|
+
return killTmuxSession({ session, env: options.env, panePid: tmuxPanePid });
|
|
514
|
+
};
|
|
515
|
+
const abortListener = () => {
|
|
516
|
+
void abort();
|
|
517
|
+
};
|
|
518
|
+
const limiterDescription = `${options.metadata.name} tmux-exec provider command: ${options.command}`.trim();
|
|
519
|
+
let reservation;
|
|
520
|
+
try {
|
|
521
|
+
stdoutTail = new OutputFileTail(stdoutFile);
|
|
522
|
+
stderrTail = new OutputFileTail(stderrFile);
|
|
523
|
+
if (options.abortSignal?.aborted) {
|
|
524
|
+
throw new ProviderExecutionError(`[${options.metadata.name}] Provider execution aborted`, {
|
|
525
|
+
retryable: false,
|
|
526
|
+
reason: "abort"
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
const reservationOrWait = acquireProcessSlot(limiterDescription, options.abortSignal);
|
|
530
|
+
reservation = reservationOrWait instanceof Promise ? await reservationOrWait : reservationOrWait;
|
|
531
|
+
} catch (error) {
|
|
532
|
+
await removeTmpDir(tmpDir);
|
|
533
|
+
throw error;
|
|
534
|
+
}
|
|
535
|
+
let activeReservationId = typeof reservation === "number" ? reservation : void 0;
|
|
536
|
+
const reservationRenewTimer = activeReservationId !== void 0 ? setInterval(() => {
|
|
537
|
+
if (activeReservationId === void 0) return;
|
|
538
|
+
if (globalProcessLimiter.renewReservation(activeReservationId)) return;
|
|
539
|
+
const replacement = globalProcessLimiter.reserve();
|
|
540
|
+
activeReservationId = typeof replacement === "number" ? replacement : void 0;
|
|
541
|
+
}, 1e4) : void 0;
|
|
542
|
+
reservationRenewTimer?.unref?.();
|
|
543
|
+
const releaseReservation = () => {
|
|
544
|
+
if (reservationRenewTimer) {
|
|
545
|
+
clearInterval(reservationRenewTimer);
|
|
546
|
+
}
|
|
547
|
+
if (activeReservationId !== void 0) {
|
|
548
|
+
globalProcessLimiter.cancelReservation(activeReservationId);
|
|
549
|
+
activeReservationId = void 0;
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
options.abortSignal?.addEventListener("abort", abortListener, { once: true });
|
|
553
|
+
let tmuxPlmProcessId;
|
|
554
|
+
let registryPersisted = false;
|
|
555
|
+
let sessionStarted = false;
|
|
556
|
+
let settleTmuxPlmCompletion;
|
|
557
|
+
try {
|
|
558
|
+
await registerTmuxSession(session, {
|
|
559
|
+
env: options.env,
|
|
560
|
+
category: "variant",
|
|
561
|
+
type: "spawned",
|
|
562
|
+
provider: options.metadata.id ?? options.metadata.name,
|
|
563
|
+
tmpDir
|
|
564
|
+
});
|
|
565
|
+
registryPersisted = true;
|
|
566
|
+
if (aborted || options.abortSignal?.aborted) {
|
|
567
|
+
throw new ProviderExecutionError(`[${options.metadata.name}] Provider execution aborted`, {
|
|
568
|
+
retryable: false,
|
|
569
|
+
reason: "abort",
|
|
570
|
+
...tmuxTransportStreamOptions(
|
|
571
|
+
await readFullTerminalStdout(),
|
|
572
|
+
await readFullTerminalStderr()
|
|
573
|
+
)
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
options.beforeSpawn?.();
|
|
577
|
+
const tmuxLaunch = await execa(
|
|
578
|
+
"tmux",
|
|
579
|
+
[
|
|
580
|
+
"new-session",
|
|
581
|
+
"-d",
|
|
582
|
+
"-P",
|
|
583
|
+
"-F",
|
|
584
|
+
"#{pane_pid}",
|
|
585
|
+
"-s",
|
|
586
|
+
session,
|
|
587
|
+
"-c",
|
|
588
|
+
options.workingDir,
|
|
589
|
+
shellCommand
|
|
590
|
+
],
|
|
591
|
+
{
|
|
592
|
+
// Launch the tmux CLIENT with a minimal env. Provider secrets travel
|
|
593
|
+
// ONLY through the 0600 env file sourced inside the pane; handing them
|
|
594
|
+
// to the client would leak them into the tmux server/session env if
|
|
595
|
+
// this call starts the server.
|
|
596
|
+
env: tmuxClientEnv(options.env),
|
|
597
|
+
cancelSignal: options.abortSignal,
|
|
598
|
+
reject: true
|
|
599
|
+
}
|
|
600
|
+
);
|
|
601
|
+
sessionStarted = true;
|
|
602
|
+
tmuxPanePid = parseTmuxPanePid(tmuxLaunch.stdout);
|
|
603
|
+
await recordTmuxSessionPanePid(session, tmuxPanePid);
|
|
604
|
+
const tmuxPlmCompletion = new Promise((resolve2, reject) => {
|
|
605
|
+
settleTmuxPlmCompletion = { resolve: resolve2, reject, settled: false };
|
|
606
|
+
});
|
|
607
|
+
tmuxPlmCompletion.catch(() => {
|
|
608
|
+
});
|
|
609
|
+
tmuxPlmProcessId = await registerTmuxProcessLifecycle({
|
|
610
|
+
options,
|
|
611
|
+
session,
|
|
612
|
+
panePid: tmuxPanePid,
|
|
613
|
+
completionPromise: tmuxPlmCompletion,
|
|
614
|
+
terminate: abort
|
|
615
|
+
});
|
|
616
|
+
const drainUnreadRawTails = async () => {
|
|
617
|
+
const stdout = await stdoutTail.read();
|
|
618
|
+
const stderr = await stderrTail.read();
|
|
619
|
+
deliverRawBytes(options.onStdoutChunk, stdout.bytes);
|
|
620
|
+
deliverRawBytes(options.onStderrChunk, stderr.bytes);
|
|
621
|
+
};
|
|
622
|
+
while (!aborted) {
|
|
623
|
+
const stdoutChunk = await stdoutTail.read();
|
|
624
|
+
const stderrChunk = await stderrTail.read();
|
|
625
|
+
if (stdoutChunk.bytes.length > 0) {
|
|
626
|
+
const now = Date.now();
|
|
627
|
+
lastActivityAt = now;
|
|
628
|
+
options.onActivity?.({ source: "stdout", timestampMs: now });
|
|
629
|
+
if (!firstOutputSeen && stdoutChunk.text.trim().length > 0) {
|
|
630
|
+
firstOutputSeen = true;
|
|
631
|
+
options.onFirstOutput?.(now);
|
|
632
|
+
}
|
|
633
|
+
deliverRawBytes(options.onStdoutChunk, stdoutChunk.bytes);
|
|
634
|
+
if (stdoutChunk.text.length > 0) {
|
|
635
|
+
try {
|
|
636
|
+
if (options.completionSignal?.(stdoutChunk.text, "stdout") === true) {
|
|
637
|
+
completionSignalSeen = true;
|
|
638
|
+
completionSignalSeenAt ??= Date.now();
|
|
639
|
+
}
|
|
640
|
+
} catch {
|
|
641
|
+
}
|
|
642
|
+
if (options.streamOutput === true) {
|
|
643
|
+
options.onData?.(stdoutChunk.text);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
if (stderrChunk.bytes.length > 0) {
|
|
648
|
+
const now = Date.now();
|
|
649
|
+
lastActivityAt = now;
|
|
650
|
+
options.onActivity?.({ source: "stderr", timestampMs: now });
|
|
651
|
+
deliverRawBytes(options.onStderrChunk, stderrChunk.bytes);
|
|
652
|
+
if (stderrChunk.text.length > 0) {
|
|
653
|
+
try {
|
|
654
|
+
if (options.completionSignal?.(stderrChunk.text, "stderr") === true) {
|
|
655
|
+
completionSignalSeen = true;
|
|
656
|
+
completionSignalSeenAt ??= Date.now();
|
|
657
|
+
}
|
|
658
|
+
} catch {
|
|
659
|
+
}
|
|
660
|
+
if (options.streamOutput === true) {
|
|
661
|
+
options.onErrorData?.(stderrChunk.text);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
if (idleTimeouts) {
|
|
666
|
+
const currentCpuTimeSeconds = tmuxPanePid === void 0 ? void 0 : readCpuTimeSeconds(tmuxPanePid);
|
|
667
|
+
const cpuProgress = evaluateCpuTimeProgressStreak({
|
|
668
|
+
currentCpuSeconds: currentCpuTimeSeconds,
|
|
669
|
+
previousCpuSeconds: lastCpuTimeSeconds,
|
|
670
|
+
currentBusyPolls: consecutiveBusyCpuPolls
|
|
671
|
+
});
|
|
672
|
+
consecutiveBusyCpuPolls = cpuProgress.nextBusyPolls;
|
|
673
|
+
if (currentCpuTimeSeconds !== void 0) {
|
|
674
|
+
lastCpuTimeSeconds = currentCpuTimeSeconds;
|
|
675
|
+
}
|
|
676
|
+
if (cpuProgress.shouldCountAsActivity) {
|
|
677
|
+
const now = Date.now();
|
|
678
|
+
lastActivityAt = now;
|
|
679
|
+
options.onActivity?.({ source: "cpu", timestampMs: now });
|
|
680
|
+
}
|
|
681
|
+
const idleFor = Date.now() - lastActivityAt;
|
|
682
|
+
if (idleFor >= idleTimeouts.killMs) {
|
|
683
|
+
options.onIdleTermination?.();
|
|
684
|
+
const killResult = await abort();
|
|
685
|
+
await drainUnreadRawTails();
|
|
686
|
+
const fullStdout2 = await readFullTerminalStdout();
|
|
687
|
+
const fullStderr2 = await readFullTerminalStderr();
|
|
688
|
+
const stderrDetail = fullStderr2.trim().length > 0 ? " Recent stderr was captured privately." : "";
|
|
689
|
+
const killDetail = killResult.removed ? "" : " Tmux session removal failed after pane SIGTERM/SIGKILL fallback; registry retained for orphan cleanup.";
|
|
690
|
+
throw new ProviderExecutionError(
|
|
691
|
+
`[${options.metadata.name}] tmux-exec provider execution idle timed out after ${Math.round(
|
|
692
|
+
idleTimeouts.killMs / 1e3
|
|
693
|
+
)}s with no stdout/stderr activity.${stderrDetail}${killDetail}`,
|
|
694
|
+
{
|
|
695
|
+
retryable: false,
|
|
696
|
+
reason: "idle_timeout",
|
|
697
|
+
idleTerminated: true,
|
|
698
|
+
...tmuxTransportStreamOptions(fullStdout2, fullStderr2)
|
|
699
|
+
}
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
const statusText2 = await readTextIfPresent(statusFile);
|
|
704
|
+
if (isTmuxExecStatusAuthoritative({
|
|
705
|
+
statusPresent: statusText2.trim().length > 0,
|
|
706
|
+
sessionAlive: sessionStarted ? await tmuxSessionExists(session, options.env) : false
|
|
707
|
+
})) {
|
|
708
|
+
break;
|
|
709
|
+
}
|
|
710
|
+
if (completionSignalSeen && completionSignalSeenAt !== null && Date.now() - completionSignalSeenAt >= completionSignalGraceMs) {
|
|
711
|
+
exitedForCompletionSignal = true;
|
|
712
|
+
await killTmuxSession({ session, env: options.env, panePid: tmuxPanePid });
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
if (Date.now() - startedAt > timeout) {
|
|
716
|
+
const killResult = await abort();
|
|
717
|
+
await drainUnreadRawTails();
|
|
718
|
+
const killDetail = killResult.removed ? "" : "; tmux session removal failed after pane SIGTERM/SIGKILL fallback; registry retained for orphan cleanup";
|
|
719
|
+
throw new ProviderExecutionError(
|
|
720
|
+
`[${options.metadata.name}] tmux-exec provider execution timed out after ${timeout}ms${killDetail}`,
|
|
721
|
+
{
|
|
722
|
+
retryable: false,
|
|
723
|
+
reason: "timeout",
|
|
724
|
+
...tmuxTransportStreamOptions(
|
|
725
|
+
await readFullTerminalStdout(),
|
|
726
|
+
await readFullTerminalStderr()
|
|
727
|
+
)
|
|
728
|
+
}
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
await sleep(250);
|
|
732
|
+
}
|
|
733
|
+
if (aborted) {
|
|
734
|
+
await drainUnreadRawTails();
|
|
735
|
+
throw new ProviderExecutionError(`[${options.metadata.name}] Provider execution aborted`, {
|
|
736
|
+
retryable: false,
|
|
737
|
+
reason: "abort",
|
|
738
|
+
...tmuxTransportStreamOptions(
|
|
739
|
+
await readFullTerminalStdout(),
|
|
740
|
+
await readFullTerminalStderr()
|
|
741
|
+
)
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
const finalStdout = await stdoutTail.read();
|
|
745
|
+
const finalStderr = await stderrTail.read();
|
|
746
|
+
const finalStdoutText = finalStdout.text + stdoutTail.flushText();
|
|
747
|
+
const finalStderrText = finalStderr.text + stderrTail.flushText();
|
|
748
|
+
deliverRawBytes(options.onStdoutChunk, finalStdout.bytes);
|
|
749
|
+
deliverRawBytes(options.onStderrChunk, finalStderr.bytes);
|
|
750
|
+
if (finalStdoutText.length > 0) {
|
|
751
|
+
try {
|
|
752
|
+
if (options.completionSignal?.(finalStdoutText, "stdout") === true) {
|
|
753
|
+
completionSignalSeen = true;
|
|
754
|
+
completionSignalSeenAt ??= Date.now();
|
|
755
|
+
}
|
|
756
|
+
} catch {
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
if (finalStderrText.length > 0) {
|
|
760
|
+
try {
|
|
761
|
+
if (options.completionSignal?.(finalStderrText, "stderr") === true) {
|
|
762
|
+
completionSignalSeen = true;
|
|
763
|
+
completionSignalSeenAt ??= Date.now();
|
|
764
|
+
}
|
|
765
|
+
} catch {
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
if (options.streamOutput === true) {
|
|
769
|
+
if (finalStdoutText) options.onData?.(finalStdoutText);
|
|
770
|
+
if (finalStderrText) options.onErrorData?.(finalStderrText);
|
|
771
|
+
}
|
|
772
|
+
const statusText = await readTextIfPresent(statusFile);
|
|
773
|
+
const trimmedStatus = statusText.trim();
|
|
774
|
+
const statusIsValid = /^-?\d+$/.test(trimmedStatus);
|
|
775
|
+
let resolvedExitCode;
|
|
776
|
+
if (statusIsValid) {
|
|
777
|
+
resolvedExitCode = Number.parseInt(trimmedStatus, 10);
|
|
778
|
+
} else if (exitedForCompletionSignal || completionSignalSeen) {
|
|
779
|
+
resolvedExitCode = 0;
|
|
780
|
+
} else {
|
|
781
|
+
resolvedExitCode = 1;
|
|
782
|
+
}
|
|
783
|
+
const fullStdout = await readTextIfPresent(stdoutFile);
|
|
784
|
+
const fullStderr = await readTextIfPresent(stderrFile);
|
|
785
|
+
const dualPublic = resolvedExitCode === 0 ? void 0 : tmuxTransportStreamOptions(fullStdout, fullStderr, {
|
|
786
|
+
maxPublicLength: 4096
|
|
787
|
+
});
|
|
788
|
+
const publicStdout = resolvedExitCode === 0 ? fullStdout : dualPublic?.stdout ?? "";
|
|
789
|
+
const publicStderr = resolvedExitCode === 0 ? fullStderr : dualPublic?.stderr ?? "";
|
|
790
|
+
if (options.streamOutput !== true) {
|
|
791
|
+
if (publicStdout) options.onData?.(publicStdout);
|
|
792
|
+
if (publicStderr) options.onErrorData?.(publicStderr);
|
|
793
|
+
} else if (resolvedExitCode === 1 && !statusIsValid && !exitedForCompletionSignal && !completionSignalSeen) {
|
|
794
|
+
options.onErrorData?.(
|
|
795
|
+
`[${options.metadata.name}] tmux-exec produced no terminal exit status; treating as failure.`
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
const result = {
|
|
799
|
+
stdout: publicStdout,
|
|
800
|
+
stderr: publicStderr,
|
|
801
|
+
exitCode: resolvedExitCode,
|
|
802
|
+
...tmuxPanePid !== void 0 ? { pid: tmuxPanePid } : {}
|
|
803
|
+
};
|
|
804
|
+
throwIfTmuxNonZeroExit(options, result, { stdout: fullStdout, stderr: fullStderr });
|
|
805
|
+
if (settleTmuxPlmCompletion && !settleTmuxPlmCompletion.settled) {
|
|
806
|
+
settleTmuxPlmCompletion.settled = true;
|
|
807
|
+
settleTmuxPlmCompletion.resolve(result);
|
|
808
|
+
}
|
|
809
|
+
return result;
|
|
810
|
+
} catch (error) {
|
|
811
|
+
if (settleTmuxPlmCompletion && !settleTmuxPlmCompletion.settled) {
|
|
812
|
+
settleTmuxPlmCompletion.settled = true;
|
|
813
|
+
settleTmuxPlmCompletion.reject(error);
|
|
814
|
+
}
|
|
815
|
+
throw error;
|
|
816
|
+
} finally {
|
|
817
|
+
options.abortSignal?.removeEventListener("abort", abortListener);
|
|
818
|
+
releaseReservation();
|
|
819
|
+
let orphanHandoffSucceeded = false;
|
|
820
|
+
if (registryPersisted) {
|
|
821
|
+
try {
|
|
822
|
+
orphanHandoffSucceeded = await markTmuxSessionOrphaned(session);
|
|
823
|
+
} catch (error) {
|
|
824
|
+
transportLogger.warn("[tmux-exec] failed to mark retained tmux session orphaned", {
|
|
825
|
+
provider: options.metadata.name,
|
|
826
|
+
session,
|
|
827
|
+
error: error instanceof Error ? error.message : String(error)
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
const killResult = registryPersisted || sessionStarted ? await killTmuxSession({ session, env: options.env, panePid: tmuxPanePid }) : { removed: true, killed: false };
|
|
832
|
+
if (killResult.removed) {
|
|
833
|
+
await unregisterTmuxSession(session);
|
|
834
|
+
}
|
|
835
|
+
if (killResult.removed) {
|
|
836
|
+
if (tmuxPlmProcessId) {
|
|
837
|
+
getProcessLifecycleManager()?.unregisterProcess(tmuxPlmProcessId);
|
|
838
|
+
}
|
|
839
|
+
await removeTmpDir(tmpDir);
|
|
840
|
+
} else {
|
|
841
|
+
if (orphanHandoffSucceeded && tmuxPlmProcessId) {
|
|
842
|
+
getProcessLifecycleManager()?.unregisterProcess(tmuxPlmProcessId);
|
|
843
|
+
}
|
|
844
|
+
transportLogger.warn("[tmux-exec] tmux session cleanup failed; retaining registry record", {
|
|
845
|
+
provider: options.metadata.name,
|
|
846
|
+
session,
|
|
847
|
+
...tmuxPanePid !== void 0 ? { panePid: tmuxPanePid } : {},
|
|
848
|
+
registryOrphaned: orphanHandoffSucceeded
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// src/core/providers/shared/invocation-telemetry.ts
|
|
855
|
+
import path2 from "path";
|
|
856
|
+
async function recordInvocationTiming(record) {
|
|
857
|
+
try {
|
|
858
|
+
const requestSentMs = Number(record.timeRequestSentMs);
|
|
859
|
+
if (!Number.isFinite(requestSentMs) || requestSentMs <= 0) {
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
const executionSource = resolveInvocationExecutionSource(record);
|
|
863
|
+
const providerId = normalizeTelemetryId(record.providerId);
|
|
864
|
+
const modelId = normalizeTelemetryId(record.canonicalModelId) ?? normalizeTelemetryId(record.modelId);
|
|
865
|
+
if (executionSource === "live" && (!providerId || !modelId)) {
|
|
866
|
+
debugLog("[Telemetry] Skipped live invocation timing without provider/model identity");
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
const firstTokenMs = typeof record.timeFirstTokenMs === "number" && Number.isFinite(record.timeFirstTokenMs) ? record.timeFirstTokenMs : null;
|
|
870
|
+
const lastTokenMs = typeof record.timeLastTokenMs === "number" && Number.isFinite(record.timeLastTokenMs) ? record.timeLastTokenMs : null;
|
|
871
|
+
const timeToFirstTokenMs = firstTokenMs !== null ? Math.max(0, Math.floor(firstTokenMs - requestSentMs)) : null;
|
|
872
|
+
const totalTimeMs = lastTokenMs !== null ? Math.max(0, Math.floor(lastTokenMs - requestSentMs)) : null;
|
|
873
|
+
const poeticDir = record.poeticDir ?? path2.join(resolvePoeticRoot(process.cwd()), ".poetic");
|
|
874
|
+
const invocationsDbPath = resolveInvocationsDbPath(poeticDir);
|
|
875
|
+
const db = new ModelInvocationsDB(invocationsDbPath);
|
|
876
|
+
try {
|
|
877
|
+
const registryVersion = resolveInvocationRegistryVersion(db);
|
|
878
|
+
db.insertInvocation({
|
|
879
|
+
id: generateInvocationId(),
|
|
880
|
+
timestamp: requestSentMs,
|
|
881
|
+
providerId: providerId ?? "unknown",
|
|
882
|
+
modelId: modelId ?? "auto",
|
|
883
|
+
registryVersion,
|
|
884
|
+
tokensIn: record.tokensIn ?? null,
|
|
885
|
+
tokensOut: record.tokensOut ?? null,
|
|
886
|
+
timeRequestSentMs: requestSentMs,
|
|
887
|
+
timeFirstTokenMs: firstTokenMs,
|
|
888
|
+
timeLastTokenMs: lastTokenMs,
|
|
889
|
+
timeToFirstTokenMs,
|
|
890
|
+
totalTimeMs,
|
|
891
|
+
status: record.status,
|
|
892
|
+
errorCode: record.errorCode ?? null,
|
|
893
|
+
agentRole: record.agentRole ?? null,
|
|
894
|
+
copilotSubcommand: record.copilotSubcommand ?? null,
|
|
895
|
+
parentWorkflowId: record.parentWorkflowId ?? null,
|
|
896
|
+
executionSource,
|
|
897
|
+
// ModelIdentity fields (canonicalModelId already mapped into modelId above)
|
|
898
|
+
requestedModelId: normalizeTelemetryId(record.requestedModelId),
|
|
899
|
+
executionModelId: normalizeTelemetryId(record.executionModelId),
|
|
900
|
+
reportedModelId: normalizeTelemetryId(record.reportedModelId),
|
|
901
|
+
backend: normalizeTelemetryId(record.backend),
|
|
902
|
+
scope: normalizeTelemetryId(record.scope),
|
|
903
|
+
contextSelector: normalizeTelemetryId(record.contextSelector),
|
|
904
|
+
resolutionSource: normalizeTelemetryId(record.resolutionSource),
|
|
905
|
+
...resolveInvocationCostAttribution(record)
|
|
906
|
+
});
|
|
907
|
+
try {
|
|
908
|
+
await ensurePendingInvocationCostEnrichment(db, {
|
|
909
|
+
aggregate: false,
|
|
910
|
+
refreshRegistrySnapshot: false
|
|
911
|
+
});
|
|
912
|
+
} catch (error) {
|
|
913
|
+
debugLog(
|
|
914
|
+
`[Telemetry] Failed to enrich invocation cost: ${error instanceof Error ? error.message : String(error)}`
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
} finally {
|
|
918
|
+
db.close();
|
|
919
|
+
}
|
|
920
|
+
} catch (error) {
|
|
921
|
+
debugLog(
|
|
922
|
+
`[Telemetry] Failed to record invocation timing: ${error instanceof Error ? error.message : String(error)}`
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
function resolveInvocationExecutionSource(record = {}) {
|
|
927
|
+
if (record.executionSource) return record.executionSource;
|
|
928
|
+
const env = record.env;
|
|
929
|
+
if (env?.POETIC_MOCK_PROVIDERS === "1") {
|
|
930
|
+
return "mock";
|
|
931
|
+
}
|
|
932
|
+
if (process.env.NODE_ENV === "test" || process.env.VITEST === "true") return "test";
|
|
933
|
+
if (readEnv(POETIC_MOCK_PROVIDERS).value === "1") return "mock";
|
|
934
|
+
return "live";
|
|
935
|
+
}
|
|
936
|
+
function normalizeTelemetryId(value) {
|
|
937
|
+
if (typeof value !== "string") return null;
|
|
938
|
+
const trimmed = value.trim();
|
|
939
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
940
|
+
}
|
|
941
|
+
function firstTelemetryId(...values) {
|
|
942
|
+
for (const value of values) {
|
|
943
|
+
const normalized = normalizeTelemetryId(value);
|
|
944
|
+
if (normalized) return normalized;
|
|
945
|
+
}
|
|
946
|
+
return null;
|
|
947
|
+
}
|
|
948
|
+
function resolveEnvAttributionId(record, key, spec) {
|
|
949
|
+
if (record.env) {
|
|
950
|
+
return normalizeTelemetryId(record.env[key]);
|
|
951
|
+
}
|
|
952
|
+
const value = readEnv(spec).value;
|
|
953
|
+
return typeof value === "string" ? normalizeTelemetryId(value) : null;
|
|
954
|
+
}
|
|
955
|
+
function resolveInvocationCostAttribution(record) {
|
|
956
|
+
const taskId = firstTelemetryId(
|
|
957
|
+
record.taskId,
|
|
958
|
+
resolveEnvAttributionId(record, POETIC_ACTIVE_TASK_ID.name, POETIC_ACTIVE_TASK_ID)
|
|
959
|
+
);
|
|
960
|
+
const variantId = firstTelemetryId(
|
|
961
|
+
record.variantId,
|
|
962
|
+
resolveEnvAttributionId(record, POETIC_WORKER_VARIANT.name, POETIC_WORKER_VARIANT)
|
|
963
|
+
);
|
|
964
|
+
const competitionId = firstTelemetryId(record.competitionId, taskId);
|
|
965
|
+
return { taskId, competitionId, variantId };
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// src/core/providers/shared/provider-timeout.ts
|
|
969
|
+
function resolveProviderTimeoutMs(providerId, explicitTimeoutMs) {
|
|
970
|
+
if (typeof explicitTimeoutMs === "number" && explicitTimeoutMs > 0) {
|
|
971
|
+
return explicitTimeoutMs;
|
|
972
|
+
}
|
|
973
|
+
const parsedProviderEnv = readProviderTimeoutEnvMs(providerId);
|
|
974
|
+
if (parsedProviderEnv !== void 0) {
|
|
975
|
+
return parsedProviderEnv;
|
|
976
|
+
}
|
|
977
|
+
const parsedGlobalEnv = readEnv(POETIC_TIMEOUT_MS).value;
|
|
978
|
+
if (parsedGlobalEnv !== void 0 && parsedGlobalEnv > 0) {
|
|
979
|
+
return parsedGlobalEnv;
|
|
980
|
+
}
|
|
981
|
+
try {
|
|
982
|
+
const timeoutFromConfig = ProviderRegistry.getTimeout(providerId);
|
|
983
|
+
if (typeof timeoutFromConfig === "number" && timeoutFromConfig > 0) return timeoutFromConfig;
|
|
984
|
+
} catch {
|
|
985
|
+
}
|
|
986
|
+
return DEFAULT_TIMEOUT;
|
|
987
|
+
}
|
|
988
|
+
function readProviderTimeoutEnvMs(providerId) {
|
|
989
|
+
const providerEnvKey = `POETIC_TIMEOUT_${providerId.toUpperCase()}_MS`;
|
|
990
|
+
const providerEnv = process.env[providerEnvKey];
|
|
991
|
+
const parsed = providerEnv ? Number.parseInt(providerEnv, 10) : NaN;
|
|
992
|
+
return !Number.isNaN(parsed) && parsed > 0 ? parsed : void 0;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// src/core/providers/shared/retry-budget.ts
|
|
996
|
+
var RetryBudget = class {
|
|
997
|
+
maxTotalAttempts;
|
|
998
|
+
usedAttempts;
|
|
999
|
+
constructor(options) {
|
|
1000
|
+
this.maxTotalAttempts = options?.maxTotalAttempts ?? 5;
|
|
1001
|
+
this.usedAttempts = 0;
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Returns true if there are remaining attempts in the budget.
|
|
1005
|
+
*/
|
|
1006
|
+
hasRemaining() {
|
|
1007
|
+
return this.usedAttempts < this.maxTotalAttempts;
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Number of remaining attempts.
|
|
1011
|
+
*/
|
|
1012
|
+
get remaining() {
|
|
1013
|
+
return Math.max(0, this.maxTotalAttempts - this.usedAttempts);
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Number of attempts consumed so far.
|
|
1017
|
+
*/
|
|
1018
|
+
get used() {
|
|
1019
|
+
return this.usedAttempts;
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Consume one attempt from the budget.
|
|
1023
|
+
* @returns true if the attempt was allowed, false if the budget is exhausted.
|
|
1024
|
+
*/
|
|
1025
|
+
consume() {
|
|
1026
|
+
if (this.usedAttempts >= this.maxTotalAttempts) {
|
|
1027
|
+
return false;
|
|
1028
|
+
}
|
|
1029
|
+
this.usedAttempts += 1;
|
|
1030
|
+
return true;
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Reset the budget to its initial state.
|
|
1034
|
+
*/
|
|
1035
|
+
reset() {
|
|
1036
|
+
this.usedAttempts = 0;
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1039
|
+
|
|
1040
|
+
// src/core/providers/shared/retry-worktree-state.ts
|
|
1041
|
+
import { createHash } from "crypto";
|
|
1042
|
+
import { promises as fs2 } from "fs";
|
|
1043
|
+
import * as path3 from "path";
|
|
1044
|
+
async function captureRetryWorktreeState(workingDir) {
|
|
1045
|
+
try {
|
|
1046
|
+
const [head, status, staged, unstaged, untracked] = await Promise.all([
|
|
1047
|
+
execGit(["rev-parse", "HEAD"], { cwd: workingDir }),
|
|
1048
|
+
execGit(["status", "--porcelain=v1", "--untracked-files=all", "-z"], {
|
|
1049
|
+
cwd: workingDir
|
|
1050
|
+
}),
|
|
1051
|
+
execGit(["diff", "--cached", "--binary", "--full-index", "--no-ext-diff"], {
|
|
1052
|
+
cwd: workingDir
|
|
1053
|
+
}),
|
|
1054
|
+
execGit(["diff", "--binary", "--full-index", "--no-ext-diff"], { cwd: workingDir }),
|
|
1055
|
+
execGit(["ls-files", "--others", "--exclude-standard", "-z"], { cwd: workingDir })
|
|
1056
|
+
]);
|
|
1057
|
+
const failed = [head, status, staged, unstaged, untracked].find(
|
|
1058
|
+
(result) => result.exitCode !== 0
|
|
1059
|
+
);
|
|
1060
|
+
if (failed) {
|
|
1061
|
+
return {
|
|
1062
|
+
available: false,
|
|
1063
|
+
error: failed.stderr.trim() || "git state query failed"
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
const hash = createHash("sha256");
|
|
1067
|
+
for (const [label, value] of [
|
|
1068
|
+
["head", head.stdout],
|
|
1069
|
+
["status", status.stdout],
|
|
1070
|
+
["staged", staged.stdout],
|
|
1071
|
+
["unstaged", unstaged.stdout]
|
|
1072
|
+
]) {
|
|
1073
|
+
hash.update(label).update("\0").update(value).update("\0");
|
|
1074
|
+
}
|
|
1075
|
+
const untrackedPaths = untracked.stdout.split("\0").filter(Boolean).sort();
|
|
1076
|
+
for (const relativePath of untrackedPaths) {
|
|
1077
|
+
const absolutePath = path3.join(workingDir, relativePath);
|
|
1078
|
+
const stats = await fs2.lstat(absolutePath);
|
|
1079
|
+
hash.update("untracked\0").update(relativePath).update("\0");
|
|
1080
|
+
if (stats.isSymbolicLink()) {
|
|
1081
|
+
hash.update("symlink\0").update(await fs2.readlink(absolutePath));
|
|
1082
|
+
} else if (stats.isFile()) {
|
|
1083
|
+
hash.update("file\0").update(await fs2.readFile(absolutePath));
|
|
1084
|
+
} else {
|
|
1085
|
+
hash.update(`other:${stats.mode}:${stats.size}\0`);
|
|
1086
|
+
}
|
|
1087
|
+
hash.update("\0");
|
|
1088
|
+
}
|
|
1089
|
+
return { available: true, fingerprint: hash.digest("hex") };
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
return {
|
|
1092
|
+
available: false,
|
|
1093
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
function suppressUnsafeRetryAfterMutatedWorktree(providerName, reason, originalError, detail) {
|
|
1098
|
+
const explanation = reason === "changed" ? "the failed attempt changed HEAD, the index, the working tree, or untracked files" : `Poetic could not verify that the worktree stayed unchanged${detail ? `: ${detail}` : ""}`;
|
|
1099
|
+
return new ProviderExecutionError(
|
|
1100
|
+
`${providerName} retry suppressed because ${explanation}. Inspect the worktree and preserve or revert the attempt's changes before running ${providerName} again.`,
|
|
1101
|
+
{
|
|
1102
|
+
retryable: false,
|
|
1103
|
+
reason: reason === "changed" ? "workspace_changed_during_attempt" : "workspace_state_unknown",
|
|
1104
|
+
providerName,
|
|
1105
|
+
cause: originalError
|
|
1106
|
+
}
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
function isRetryableProviderError(error) {
|
|
1110
|
+
return error instanceof ProviderExecutionError && error.retryable === true;
|
|
1111
|
+
}
|
|
1112
|
+
async function rejectUnsafeFullPromptRetry(options) {
|
|
1113
|
+
if (!options.requireCleanState && !isRetryableProviderError(options.error) || options.isResumeSafe === true) {
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
const attemptEndState = await captureRetryWorktreeState(options.workingDir);
|
|
1117
|
+
if (!options.attemptStartState.available || !attemptEndState.available) {
|
|
1118
|
+
throw suppressUnsafeRetryAfterMutatedWorktree(
|
|
1119
|
+
options.providerName,
|
|
1120
|
+
"unavailable",
|
|
1121
|
+
options.error,
|
|
1122
|
+
options.attemptStartState.error ?? attemptEndState.error
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
if (options.attemptStartState.fingerprint !== attemptEndState.fingerprint) {
|
|
1126
|
+
throw suppressUnsafeRetryAfterMutatedWorktree(options.providerName, "changed", options.error);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// src/core/providers/shared/workspace-edits-parser.ts
|
|
1131
|
+
import * as path4 from "path";
|
|
1132
|
+
function isUnsafePath(candidate, options = {}) {
|
|
1133
|
+
if (!candidate) return true;
|
|
1134
|
+
const { rootDir = process.cwd(), allowAbsolute = false, allowHomeExpansion = false } = options;
|
|
1135
|
+
const normalized = candidate.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/\\/g, "/");
|
|
1136
|
+
if (normalized.includes("\0")) return true;
|
|
1137
|
+
if (!allowAbsolute && path4.isAbsolute(candidate)) return true;
|
|
1138
|
+
if (!allowHomeExpansion && normalized.startsWith("~")) return true;
|
|
1139
|
+
if (normalized.startsWith("../")) return true;
|
|
1140
|
+
if (normalized.includes("/../")) return true;
|
|
1141
|
+
if (/^[a-zA-Z]:[\\/]/.test(candidate)) return true;
|
|
1142
|
+
try {
|
|
1143
|
+
const resolved = path4.resolve(rootDir, normalized);
|
|
1144
|
+
const resolvedRoot = path4.resolve(rootDir);
|
|
1145
|
+
const relative2 = path4.relative(resolvedRoot, resolved);
|
|
1146
|
+
const escapesRoot = relative2.startsWith("..") || path4.isAbsolute(relative2);
|
|
1147
|
+
return escapesRoot;
|
|
1148
|
+
} catch {
|
|
1149
|
+
return true;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
function parseWorkspaceEditsFromJsonl(rawOutput, options = {}) {
|
|
1153
|
+
if (!rawOutput) {
|
|
1154
|
+
return { cleanedOutput: rawOutput, edits: [], errors: [] };
|
|
1155
|
+
}
|
|
1156
|
+
const edits = [];
|
|
1157
|
+
const errors = [];
|
|
1158
|
+
const kept = [];
|
|
1159
|
+
const pathSafetyOptions = options.workspaceRoot ? { rootDir: options.workspaceRoot } : {};
|
|
1160
|
+
for (const line of rawOutput.split("\n")) {
|
|
1161
|
+
const trimmed = line.trim();
|
|
1162
|
+
if (!trimmed.startsWith("{")) {
|
|
1163
|
+
kept.push(line);
|
|
1164
|
+
continue;
|
|
1165
|
+
}
|
|
1166
|
+
let parsed = null;
|
|
1167
|
+
try {
|
|
1168
|
+
parsed = safeJsonParse(trimmed, {
|
|
1169
|
+
debug: false,
|
|
1170
|
+
context: "workspace edit JSON"
|
|
1171
|
+
});
|
|
1172
|
+
} catch (error) {
|
|
1173
|
+
const baseMessage = error instanceof JsonParseError ? error.message : `Failed to parse workspace edit JSON: ${error instanceof Error ? error.message : String(error)}`;
|
|
1174
|
+
const message = `Malformed workspace edit (${baseMessage})`;
|
|
1175
|
+
errors.push(message);
|
|
1176
|
+
options.onError?.(message);
|
|
1177
|
+
kept.push(line);
|
|
1178
|
+
continue;
|
|
1179
|
+
}
|
|
1180
|
+
if (parsed.type && parsed.type !== "poetic_edit") {
|
|
1181
|
+
kept.push(line);
|
|
1182
|
+
continue;
|
|
1183
|
+
}
|
|
1184
|
+
if (!parsed.op || !parsed.path) {
|
|
1185
|
+
const message = `Incomplete workspace edit payload (missing op/path): ${trimmed}`;
|
|
1186
|
+
errors.push(message);
|
|
1187
|
+
options.onError?.(message);
|
|
1188
|
+
kept.push(line);
|
|
1189
|
+
continue;
|
|
1190
|
+
}
|
|
1191
|
+
const validOps = ["writeFile", "appendFile", "deleteFile", "renameFile"];
|
|
1192
|
+
if (!validOps.includes(parsed.op)) {
|
|
1193
|
+
const message = `Invalid workspace edit operation "${parsed.op}" (expected: ${validOps.join(", ")})`;
|
|
1194
|
+
errors.push(message);
|
|
1195
|
+
options.onError?.(message);
|
|
1196
|
+
kept.push(line);
|
|
1197
|
+
continue;
|
|
1198
|
+
}
|
|
1199
|
+
if (isUnsafePath(parsed.path, pathSafetyOptions) || parsed.fromPath && isUnsafePath(parsed.fromPath, pathSafetyOptions)) {
|
|
1200
|
+
const message = `Rejected unsafe workspace edit path: ${parsed.path}${parsed.fromPath ? ` (from: ${parsed.fromPath})` : ""}`;
|
|
1201
|
+
errors.push(message);
|
|
1202
|
+
options.onError?.(message);
|
|
1203
|
+
kept.push(line);
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
edits.push({
|
|
1207
|
+
op: parsed.op,
|
|
1208
|
+
path: parsed.path.replace(/\\/g, "/"),
|
|
1209
|
+
contents: parsed.contents,
|
|
1210
|
+
fromPath: parsed.fromPath?.replace(/\\/g, "/")
|
|
1211
|
+
});
|
|
1212
|
+
}
|
|
1213
|
+
return {
|
|
1214
|
+
cleanedOutput: kept.join("\n"),
|
|
1215
|
+
edits,
|
|
1216
|
+
errors
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// src/core/providers/shared/write-workspace-edits.ts
|
|
1221
|
+
import * as fs3 from "fs/promises";
|
|
1222
|
+
import * as path5 from "path";
|
|
1223
|
+
var MAX_WRITE_RETRIES = 3;
|
|
1224
|
+
var RETRY_BASE_DELAY_MS = 10;
|
|
1225
|
+
async function appendWithRetry(editsFile, payload) {
|
|
1226
|
+
let attempt = 0;
|
|
1227
|
+
while (true) {
|
|
1228
|
+
try {
|
|
1229
|
+
await fs3.appendFile(editsFile, payload, "utf8");
|
|
1230
|
+
return;
|
|
1231
|
+
} catch (error) {
|
|
1232
|
+
attempt += 1;
|
|
1233
|
+
if (attempt >= MAX_WRITE_RETRIES) {
|
|
1234
|
+
throw error;
|
|
1235
|
+
}
|
|
1236
|
+
const delayMs = RETRY_BASE_DELAY_MS * 2 ** (attempt - 1);
|
|
1237
|
+
await new Promise((resolve2) => setTimeout(resolve2, delayMs));
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
async function writeWorkspaceEditsToFile(worktreePath, edits) {
|
|
1242
|
+
if (!edits || edits.length === 0) {
|
|
1243
|
+
return { success: true, written: 0, failed: 0, skipped: 0 };
|
|
1244
|
+
}
|
|
1245
|
+
const editsDir = path5.join(worktreePath, ".poetic");
|
|
1246
|
+
const editsFile = path5.join(editsDir, "edits.jsonl");
|
|
1247
|
+
let written = 0;
|
|
1248
|
+
let skipped = 0;
|
|
1249
|
+
try {
|
|
1250
|
+
await fs3.mkdir(editsDir, { recursive: true });
|
|
1251
|
+
const payloads = [];
|
|
1252
|
+
for (const edit of edits) {
|
|
1253
|
+
if (isUnsafePath(edit.path, { rootDir: worktreePath }) || shouldExcludeFile(edit.path) || edit.fromPath && (isUnsafePath(edit.fromPath, { rootDir: worktreePath }) || shouldExcludeFile(edit.fromPath))) {
|
|
1254
|
+
emitWarning(
|
|
1255
|
+
"WS-003",
|
|
1256
|
+
{
|
|
1257
|
+
subsystem: "workspace-edits",
|
|
1258
|
+
executionPhase: "execution"
|
|
1259
|
+
},
|
|
1260
|
+
{
|
|
1261
|
+
severity: "WARN" /* WARN */,
|
|
1262
|
+
metadata: {
|
|
1263
|
+
error: "Unsafe workspace edit path",
|
|
1264
|
+
path: edit.path,
|
|
1265
|
+
fromPath: edit.fromPath,
|
|
1266
|
+
operation: "writeWorkspaceEdits"
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
);
|
|
1270
|
+
skipped += 1;
|
|
1271
|
+
continue;
|
|
1272
|
+
}
|
|
1273
|
+
const payload = {
|
|
1274
|
+
type: "poetic_edit",
|
|
1275
|
+
op: edit.op,
|
|
1276
|
+
path: edit.path,
|
|
1277
|
+
...edit.contents !== void 0 ? { contents: edit.contents } : {},
|
|
1278
|
+
...edit.fromPath !== void 0 ? { fromPath: edit.fromPath } : {}
|
|
1279
|
+
};
|
|
1280
|
+
payloads.push(`${JSON.stringify(payload)}
|
|
1281
|
+
`);
|
|
1282
|
+
}
|
|
1283
|
+
if (payloads.length > 0) {
|
|
1284
|
+
await appendWithRetry(editsFile, payloads.join(""));
|
|
1285
|
+
written = payloads.length;
|
|
1286
|
+
}
|
|
1287
|
+
return {
|
|
1288
|
+
success: written > 0 || skipped === 0,
|
|
1289
|
+
written,
|
|
1290
|
+
failed: written === 0 && skipped > 0 ? skipped : 0,
|
|
1291
|
+
skipped,
|
|
1292
|
+
...written === 0 && skipped > 0 ? { error: "All workspace edits were skipped by safety filters" } : {}
|
|
1293
|
+
};
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
const errorMessage2 = error instanceof Error ? error.message : String(error);
|
|
1296
|
+
emitWarning(
|
|
1297
|
+
"WS-003",
|
|
1298
|
+
{
|
|
1299
|
+
subsystem: "workspace-edits",
|
|
1300
|
+
executionPhase: "execution"
|
|
1301
|
+
},
|
|
1302
|
+
{
|
|
1303
|
+
severity: "ERROR" /* ERROR */,
|
|
1304
|
+
metadata: {
|
|
1305
|
+
error: errorMessage2,
|
|
1306
|
+
operation: "writeWorkspaceEdits",
|
|
1307
|
+
editsFile
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
);
|
|
1311
|
+
return {
|
|
1312
|
+
success: false,
|
|
1313
|
+
written,
|
|
1314
|
+
failed: edits.length - written - skipped,
|
|
1315
|
+
skipped,
|
|
1316
|
+
error: errorMessage2
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
// src/core/providers/shared/runner-lifecycle.ts
|
|
1322
|
+
var DEFAULT_PROVIDER_CIRCUIT_BREAKER_OPTIONS = createCircuitBreakerOptions({
|
|
1323
|
+
failureThreshold: 5,
|
|
1324
|
+
recoveryTimeout: 6e4
|
|
1325
|
+
});
|
|
1326
|
+
async function executeWithResilience(fn, options) {
|
|
1327
|
+
const {
|
|
1328
|
+
providerName,
|
|
1329
|
+
operation = "execute_prompt",
|
|
1330
|
+
maxAttempts = 3,
|
|
1331
|
+
retryBudget,
|
|
1332
|
+
onRetry,
|
|
1333
|
+
abortSignal,
|
|
1334
|
+
circuitBreakerOptions = DEFAULT_PROVIDER_CIRCUIT_BREAKER_OPTIONS,
|
|
1335
|
+
errorParser,
|
|
1336
|
+
providerId,
|
|
1337
|
+
fastRetryMode = false,
|
|
1338
|
+
initialDelayMs,
|
|
1339
|
+
maxDelayMs,
|
|
1340
|
+
backoffMultiplier,
|
|
1341
|
+
deadlineMs,
|
|
1342
|
+
minimumAttemptTimeMs,
|
|
1343
|
+
circuitBreakerScope,
|
|
1344
|
+
retryWorktreeDir,
|
|
1345
|
+
isRetryResumeSafe
|
|
1346
|
+
} = options;
|
|
1347
|
+
const retryOptions = createRetryOptions({
|
|
1348
|
+
providerName,
|
|
1349
|
+
operation,
|
|
1350
|
+
maxAttempts,
|
|
1351
|
+
initialDelayMs: fastRetryMode ? 0 : initialDelayMs,
|
|
1352
|
+
maxDelayMs: fastRetryMode ? 0 : maxDelayMs,
|
|
1353
|
+
backoffMultiplier,
|
|
1354
|
+
retryBudget,
|
|
1355
|
+
onRetry,
|
|
1356
|
+
abortSignal,
|
|
1357
|
+
suppressDelayFloors: fastRetryMode,
|
|
1358
|
+
deadlineMs,
|
|
1359
|
+
minimumAttemptTimeMs
|
|
1360
|
+
});
|
|
1361
|
+
const wrappedFn = async () => {
|
|
1362
|
+
const attemptStartState = retryWorktreeDir ? await captureRetryWorktreeState(retryWorktreeDir) : void 0;
|
|
1363
|
+
try {
|
|
1364
|
+
return await executeWithCircuitBreaker(
|
|
1365
|
+
providerName,
|
|
1366
|
+
fn,
|
|
1367
|
+
circuitBreakerOptions,
|
|
1368
|
+
circuitBreakerScope
|
|
1369
|
+
);
|
|
1370
|
+
} catch (error) {
|
|
1371
|
+
const thrown = errorParser ? wrapProviderError(error, errorParser, providerId ?? providerName) : error;
|
|
1372
|
+
if (retryWorktreeDir && attemptStartState) {
|
|
1373
|
+
await rejectUnsafeFullPromptRetry({
|
|
1374
|
+
workingDir: retryWorktreeDir,
|
|
1375
|
+
attemptStartState,
|
|
1376
|
+
error: thrown,
|
|
1377
|
+
providerName: providerId ?? providerName,
|
|
1378
|
+
isResumeSafe: isRetryResumeSafe?.() === true
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
throw thrown;
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
return withRetry(wrappedFn, retryOptions);
|
|
1385
|
+
}
|
|
1386
|
+
function wrapProviderError(error, errorParser, providerId) {
|
|
1387
|
+
if (error instanceof CircuitBreakerError) {
|
|
1388
|
+
return new ProviderExecutionError(error.message, {
|
|
1389
|
+
retryable: false,
|
|
1390
|
+
reason: "circuit_open",
|
|
1391
|
+
providerName: providerId,
|
|
1392
|
+
cause: error
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
const parsed = errorParser(error);
|
|
1396
|
+
if (error instanceof ProviderExecutionError) {
|
|
1397
|
+
const GENERIC_FALLBACK_REASONS = /* @__PURE__ */ new Set(["non_zero_exit", "provider_cli_error"]);
|
|
1398
|
+
const hasExplicitTerminalReason = typeof error.reason === "string" && error.reason.length > 0 && !GENERIC_FALLBACK_REASONS.has(error.reason);
|
|
1399
|
+
const retryable = error.retryable === false && hasExplicitTerminalReason ? false : parsed.retryable;
|
|
1400
|
+
return new ProviderExecutionError(error.message, {
|
|
1401
|
+
retryable,
|
|
1402
|
+
exitCode: error.exitCode,
|
|
1403
|
+
statusCode: error.statusCode,
|
|
1404
|
+
reason: error.reason,
|
|
1405
|
+
signal: error.signal,
|
|
1406
|
+
terminationSource: error.terminationSource,
|
|
1407
|
+
// Preserve truncated public fields and non-enumerable full raw carriers.
|
|
1408
|
+
...providerExecutionErrorStreamOptions(error),
|
|
1409
|
+
providerName: providerId,
|
|
1410
|
+
cause: error.cause,
|
|
1411
|
+
parsedError: parsed
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
const originalMessage = error instanceof Error ? error.message : String(error);
|
|
1415
|
+
return new ProviderExecutionError(originalMessage, {
|
|
1416
|
+
retryable: parsed.retryable,
|
|
1417
|
+
providerName: providerId,
|
|
1418
|
+
cause: error,
|
|
1419
|
+
parsedError: parsed
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
async function persistWorkspaceEdits(workingDir, edits) {
|
|
1423
|
+
if (edits.length === 0) return;
|
|
1424
|
+
try {
|
|
1425
|
+
await writeWorkspaceEditsToFile(workingDir, edits);
|
|
1426
|
+
} catch (error) {
|
|
1427
|
+
if (process.env.NODE_ENV !== "test") {
|
|
1428
|
+
console.warn(
|
|
1429
|
+
`[runner-lifecycle] Failed to persist workspace edits for ${workingDir}: ${error instanceof Error ? error.message : String(error)}`
|
|
1430
|
+
);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
// src/core/providers/shared/workspace-retry-safety.ts
|
|
1436
|
+
import { createHash as createHash2 } from "crypto";
|
|
1437
|
+
import { promises as fs4 } from "fs";
|
|
1438
|
+
import * as path6 from "path";
|
|
1439
|
+
function isEnoentError(error) {
|
|
1440
|
+
return Boolean(
|
|
1441
|
+
error && typeof error === "object" && "code" in error && error.code === "ENOENT"
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
function errorMessage(error) {
|
|
1445
|
+
return error instanceof Error ? error.message : String(error);
|
|
1446
|
+
}
|
|
1447
|
+
async function captureWorkspaceFingerprintOnce(workingDir) {
|
|
1448
|
+
const [head, status, staged, unstaged, untracked] = await Promise.all([
|
|
1449
|
+
execGit(["rev-parse", "HEAD"], { cwd: workingDir }),
|
|
1450
|
+
execGit(["status", "--porcelain=v1", "--untracked-files=all", "-z"], {
|
|
1451
|
+
cwd: workingDir
|
|
1452
|
+
}),
|
|
1453
|
+
execGit(["diff", "--cached", "--binary", "--full-index", "--no-ext-diff"], {
|
|
1454
|
+
cwd: workingDir
|
|
1455
|
+
}),
|
|
1456
|
+
execGit(["diff", "--binary", "--full-index", "--no-ext-diff"], { cwd: workingDir }),
|
|
1457
|
+
execGit(["ls-files", "--others", "--exclude-standard", "-z"], { cwd: workingDir })
|
|
1458
|
+
]);
|
|
1459
|
+
const failed = [status, staged, unstaged, untracked].find((result) => result.exitCode !== 0);
|
|
1460
|
+
if (failed) {
|
|
1461
|
+
return {
|
|
1462
|
+
kind: "unavailable",
|
|
1463
|
+
error: failed.stderr.trim() || "git state query failed"
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
const hash = createHash2("sha256");
|
|
1467
|
+
for (const [label, value] of [
|
|
1468
|
+
["head", head.exitCode === 0 ? head.stdout : "<unborn>"],
|
|
1469
|
+
["status", status.stdout],
|
|
1470
|
+
["staged", staged.stdout],
|
|
1471
|
+
["unstaged", unstaged.stdout]
|
|
1472
|
+
]) {
|
|
1473
|
+
hash.update(label).update("\0").update(value).update("\0");
|
|
1474
|
+
}
|
|
1475
|
+
const untrackedPaths = untracked.stdout.split("\0").filter(Boolean).sort();
|
|
1476
|
+
for (const relativePath of untrackedPaths) {
|
|
1477
|
+
const absolutePath = path6.join(workingDir, relativePath);
|
|
1478
|
+
let stats;
|
|
1479
|
+
try {
|
|
1480
|
+
stats = await fs4.lstat(absolutePath);
|
|
1481
|
+
} catch (error) {
|
|
1482
|
+
if (isEnoentError(error)) {
|
|
1483
|
+
return { kind: "unstable", error: errorMessage(error) };
|
|
1484
|
+
}
|
|
1485
|
+
throw error;
|
|
1486
|
+
}
|
|
1487
|
+
hash.update("untracked\0").update(relativePath).update("\0");
|
|
1488
|
+
try {
|
|
1489
|
+
if (stats.isSymbolicLink()) {
|
|
1490
|
+
hash.update("symlink\0").update(await fs4.readlink(absolutePath));
|
|
1491
|
+
} else if (stats.isFile()) {
|
|
1492
|
+
hash.update("file\0").update(await fs4.readFile(absolutePath));
|
|
1493
|
+
} else {
|
|
1494
|
+
hash.update(`other:${stats.mode}:${stats.size}\0`);
|
|
1495
|
+
}
|
|
1496
|
+
} catch (error) {
|
|
1497
|
+
if (isEnoentError(error)) {
|
|
1498
|
+
return { kind: "unstable", error: errorMessage(error) };
|
|
1499
|
+
}
|
|
1500
|
+
throw error;
|
|
1501
|
+
}
|
|
1502
|
+
hash.update("\0");
|
|
1503
|
+
}
|
|
1504
|
+
return { kind: "ready", fingerprint: hash.digest("hex") };
|
|
1505
|
+
}
|
|
1506
|
+
async function captureWorkspaceRetryState(workingDir) {
|
|
1507
|
+
try {
|
|
1508
|
+
const insideWorkTree = await execGit(["rev-parse", "--is-inside-work-tree"], {
|
|
1509
|
+
cwd: workingDir
|
|
1510
|
+
});
|
|
1511
|
+
if (insideWorkTree.exitCode !== 0 || insideWorkTree.stdout.trim() !== "true") {
|
|
1512
|
+
return {
|
|
1513
|
+
available: false,
|
|
1514
|
+
error: insideWorkTree.stderr.trim() || "working directory is not inside a Git worktree"
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
const first = await captureWorkspaceFingerprintOnce(workingDir);
|
|
1518
|
+
if (first.kind === "ready") {
|
|
1519
|
+
return { available: true, fingerprint: first.fingerprint };
|
|
1520
|
+
}
|
|
1521
|
+
if (first.kind === "unavailable") {
|
|
1522
|
+
return { available: false, error: first.error };
|
|
1523
|
+
}
|
|
1524
|
+
const second = await captureWorkspaceFingerprintOnce(workingDir);
|
|
1525
|
+
if (second.kind === "ready") {
|
|
1526
|
+
return { available: true, fingerprint: second.fingerprint };
|
|
1527
|
+
}
|
|
1528
|
+
return {
|
|
1529
|
+
available: false,
|
|
1530
|
+
error: second.error
|
|
1531
|
+
};
|
|
1532
|
+
} catch (error) {
|
|
1533
|
+
return {
|
|
1534
|
+
available: false,
|
|
1535
|
+
error: errorMessage(error)
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
async function assertWorkspaceRetryIsSafe(options) {
|
|
1540
|
+
if (!options.retryable) {
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
const attemptEndState = await captureWorkspaceRetryState(options.workingDir);
|
|
1544
|
+
const unavailable = !options.attemptStartState.available || !attemptEndState.available;
|
|
1545
|
+
const changed = !unavailable && options.attemptStartState.fingerprint !== attemptEndState.fingerprint;
|
|
1546
|
+
if (!unavailable && !changed) {
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
const detail = options.attemptStartState.error ?? attemptEndState.error ?? "workspace fingerprint could not be captured";
|
|
1550
|
+
const explanation = changed ? "the failed attempt changed HEAD, the index, the working tree, or untracked files" : `Poetic could not verify that the worktree stayed unchanged: ${detail}`;
|
|
1551
|
+
throw new ProviderExecutionError(
|
|
1552
|
+
`${options.providerName} retry suppressed because ${explanation}. Inspect the worktree and preserve or revert the attempt changes before retrying.`,
|
|
1553
|
+
{
|
|
1554
|
+
retryable: false,
|
|
1555
|
+
reason: changed ? "workspace_changed_during_attempt" : "workspace_state_unknown",
|
|
1556
|
+
providerName: options.providerId,
|
|
1557
|
+
cause: options.originalError instanceof Error ? options.originalError : void 0
|
|
1558
|
+
}
|
|
1559
|
+
);
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
export {
|
|
1563
|
+
resolveProviderTransportDecision,
|
|
1564
|
+
reportTransportDecision,
|
|
1565
|
+
selectProviderExecutor,
|
|
1566
|
+
executeProviderCommandTmuxExec,
|
|
1567
|
+
recordInvocationTiming,
|
|
1568
|
+
resolveProviderTimeoutMs,
|
|
1569
|
+
readProviderTimeoutEnvMs,
|
|
1570
|
+
RetryBudget,
|
|
1571
|
+
captureRetryWorktreeState,
|
|
1572
|
+
rejectUnsafeFullPromptRetry,
|
|
1573
|
+
parseWorkspaceEditsFromJsonl,
|
|
1574
|
+
DEFAULT_PROVIDER_CIRCUIT_BREAKER_OPTIONS,
|
|
1575
|
+
executeWithResilience,
|
|
1576
|
+
wrapProviderError,
|
|
1577
|
+
persistWorkspaceEdits,
|
|
1578
|
+
captureWorkspaceRetryState,
|
|
1579
|
+
assertWorkspaceRetryIsSafe
|
|
1580
|
+
};
|
|
1581
|
+
//# sourceMappingURL=chunk-WZ6U3O7I.js.map
|