@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,2931 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findPoeticPackageRoot
|
|
3
|
+
} from "./chunk-GSGD5E4C.js";
|
|
4
|
+
import {
|
|
5
|
+
getExecutionContext
|
|
6
|
+
} from "./chunk-UI2F6DJ5.js";
|
|
7
|
+
import {
|
|
8
|
+
normalizeReasoningEffortInput
|
|
9
|
+
} from "./chunk-4BTDUT2S.js";
|
|
10
|
+
import {
|
|
11
|
+
findProjectRoot,
|
|
12
|
+
getConfigPaths,
|
|
13
|
+
resolveProvidersConfigPath
|
|
14
|
+
} from "./chunk-L6OM4A22.js";
|
|
15
|
+
import {
|
|
16
|
+
validateConfigPath
|
|
17
|
+
} from "./chunk-XZE4XARH.js";
|
|
18
|
+
import {
|
|
19
|
+
debugLog,
|
|
20
|
+
emitWarning
|
|
21
|
+
} from "./chunk-EJGCZGUF.js";
|
|
22
|
+
import {
|
|
23
|
+
KEYS
|
|
24
|
+
} from "./chunk-5DLKYTQX.js";
|
|
25
|
+
|
|
26
|
+
// src/core/config/provider-registry.ts
|
|
27
|
+
import { createHash as createHash2 } from "crypto";
|
|
28
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
29
|
+
import { homedir } from "os";
|
|
30
|
+
import { join, resolve as resolve3, sep } from "path";
|
|
31
|
+
import { fileURLToPath } from "url";
|
|
32
|
+
import yaml from "js-yaml";
|
|
33
|
+
import { z as z2 } from "zod";
|
|
34
|
+
|
|
35
|
+
// src/core/providers/generated/catalog-digest.ts
|
|
36
|
+
var PROVIDER_CATALOG_SHA256 = "436ed6466f6b99fc21ef1e09ac23735ba4733abe4f8288fbd446ea03996352b5";
|
|
37
|
+
|
|
38
|
+
// src/core/providers/refresh/overlay.ts
|
|
39
|
+
import { existsSync, readFileSync } from "fs";
|
|
40
|
+
import * as fs from "fs/promises";
|
|
41
|
+
import { z } from "zod";
|
|
42
|
+
var REFRESH_OVERLAY_SCHEMA_VERSION = 1;
|
|
43
|
+
var UsdPer1MSchema = z.union([
|
|
44
|
+
z.number().nonnegative(),
|
|
45
|
+
z.string().regex(/^\d+(?:\.\d+)?$/, "Must be non-negative USD")
|
|
46
|
+
]);
|
|
47
|
+
var OverlayModelAvailableEntrySchema = z.object({
|
|
48
|
+
id: z.string().trim().min(1),
|
|
49
|
+
display_name: z.string().min(1),
|
|
50
|
+
full_name: z.string().optional(),
|
|
51
|
+
capabilities: z.array(z.string()),
|
|
52
|
+
context_window: z.number().int().positive().optional(),
|
|
53
|
+
max_output_tokens: z.number().int().positive().optional(),
|
|
54
|
+
reasoning_effort_levels: z.array(z.string()).optional(),
|
|
55
|
+
notes: z.string().optional()
|
|
56
|
+
}).strict();
|
|
57
|
+
var OverlayPricingRowSchema = z.object({
|
|
58
|
+
input_per_1m_tokens: UsdPer1MSchema.optional(),
|
|
59
|
+
output_per_1m_tokens: UsdPer1MSchema.optional(),
|
|
60
|
+
cache_read_per_1m_tokens: UsdPer1MSchema.optional(),
|
|
61
|
+
cache_write_per_1m_tokens: UsdPer1MSchema.optional(),
|
|
62
|
+
context_window: z.number().int().positive().optional(),
|
|
63
|
+
features: z.record(z.string(), z.boolean()).optional(),
|
|
64
|
+
notes: z.string().optional(),
|
|
65
|
+
last_updated: z.string().optional()
|
|
66
|
+
}).strict();
|
|
67
|
+
var REFRESH_SOURCES = [
|
|
68
|
+
"API",
|
|
69
|
+
"doc-poll",
|
|
70
|
+
"pricing-only",
|
|
71
|
+
"discovery",
|
|
72
|
+
"static"
|
|
73
|
+
];
|
|
74
|
+
var OverlaySliceProvenanceSchema = z.object({
|
|
75
|
+
source: z.enum(REFRESH_SOURCES),
|
|
76
|
+
fetchedAt: z.string().min(1),
|
|
77
|
+
freshnessMs: z.number().int().nonnegative().optional()
|
|
78
|
+
}).strict();
|
|
79
|
+
var OverlayProviderPayloadSchema = z.object({
|
|
80
|
+
models: z.object({
|
|
81
|
+
available: z.array(OverlayModelAvailableEntrySchema),
|
|
82
|
+
/** Treat available as the complete provider inventory, not an additive patch. */
|
|
83
|
+
replaceInventory: z.literal(true).optional()
|
|
84
|
+
}).strict().optional(),
|
|
85
|
+
pricing: z.object({
|
|
86
|
+
models: z.record(z.string(), OverlayPricingRowSchema)
|
|
87
|
+
}).strict().optional(),
|
|
88
|
+
/** Provider-level freshness / provenance. */
|
|
89
|
+
provenance: OverlaySliceProvenanceSchema.optional(),
|
|
90
|
+
/** Per-slice freshness / provenance (models vs pricing). */
|
|
91
|
+
slices: z.object({
|
|
92
|
+
models: OverlaySliceProvenanceSchema.optional(),
|
|
93
|
+
pricing: OverlaySliceProvenanceSchema.optional()
|
|
94
|
+
}).strict().optional()
|
|
95
|
+
}).strict();
|
|
96
|
+
var RefreshOverlayDocumentSchema = z.object({
|
|
97
|
+
schemaVersion: z.literal(REFRESH_OVERLAY_SCHEMA_VERSION),
|
|
98
|
+
baseCatalogDigest: z.string().min(1),
|
|
99
|
+
providers: z.record(z.string(), OverlayProviderPayloadSchema)
|
|
100
|
+
}).strict();
|
|
101
|
+
var REFRESH_OVERLAY_RERUN_GUIDANCE = "Refresh overlay ignored because the release catalog digest changed. Run: poetic provider refresh";
|
|
102
|
+
function noticeFromRefreshOverlayDisposition(disposition) {
|
|
103
|
+
if (disposition.status === "degraded") {
|
|
104
|
+
return {
|
|
105
|
+
status: "degraded",
|
|
106
|
+
reason: disposition.reason,
|
|
107
|
+
message: disposition.warning,
|
|
108
|
+
guidance: REFRESH_OVERLAY_RERUN_GUIDANCE
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (disposition.status === "rejected") {
|
|
112
|
+
return {
|
|
113
|
+
status: "rejected",
|
|
114
|
+
reason: disposition.reason,
|
|
115
|
+
message: disposition.error,
|
|
116
|
+
guidance: "Refresh overlay is invalid and was ignored. Run: poetic provider refresh"
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return void 0;
|
|
120
|
+
}
|
|
121
|
+
function getRefreshOverlayOperatorNotice(overlayPath, expectedBaseCatalogDigest) {
|
|
122
|
+
if (!existsSync(overlayPath)) return void 0;
|
|
123
|
+
try {
|
|
124
|
+
const disposition = resolveRefreshOverlayDisposition(readFileSync(overlayPath, "utf8"), {
|
|
125
|
+
expectedBaseCatalogDigest
|
|
126
|
+
});
|
|
127
|
+
return noticeFromRefreshOverlayDisposition(disposition);
|
|
128
|
+
} catch {
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function sortKeysDeep(value) {
|
|
133
|
+
if (Array.isArray(value)) {
|
|
134
|
+
return value.map(sortKeysDeep);
|
|
135
|
+
}
|
|
136
|
+
if (value && typeof value === "object") {
|
|
137
|
+
const sorted = {};
|
|
138
|
+
for (const key of Object.keys(value).sort()) {
|
|
139
|
+
sorted[key] = sortKeysDeep(value[key]);
|
|
140
|
+
}
|
|
141
|
+
return sorted;
|
|
142
|
+
}
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
function emptyRefreshOverlay(baseCatalogDigest) {
|
|
146
|
+
return {
|
|
147
|
+
schemaVersion: REFRESH_OVERLAY_SCHEMA_VERSION,
|
|
148
|
+
baseCatalogDigest,
|
|
149
|
+
providers: {}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function serializeRefreshOverlay(overlay) {
|
|
153
|
+
const parsed = RefreshOverlayDocumentSchema.safeParse(overlay);
|
|
154
|
+
if (!parsed.success) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`Cannot serialize invalid refresh overlay: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
return `${JSON.stringify(sortKeysDeep(parsed.data), null, 2)}
|
|
160
|
+
`;
|
|
161
|
+
}
|
|
162
|
+
function parseRefreshOverlayValue(value) {
|
|
163
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
164
|
+
return { ok: false, error: "Refresh overlay must be a JSON object" };
|
|
165
|
+
}
|
|
166
|
+
const parsed = RefreshOverlayDocumentSchema.safeParse(value);
|
|
167
|
+
if (!parsed.success) {
|
|
168
|
+
return {
|
|
169
|
+
ok: false,
|
|
170
|
+
error: `Invalid refresh overlay schema: ${parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"}: ${issue.message}`).join("; ")}`
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return { ok: true, overlay: parsed.data };
|
|
174
|
+
}
|
|
175
|
+
function parseRefreshOverlay(raw) {
|
|
176
|
+
let value;
|
|
177
|
+
try {
|
|
178
|
+
value = JSON.parse(raw);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
return {
|
|
181
|
+
ok: false,
|
|
182
|
+
error: `Refresh overlay is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return parseRefreshOverlayValue(value);
|
|
186
|
+
}
|
|
187
|
+
function resolveRefreshOverlayDisposition(input, options) {
|
|
188
|
+
const parsed = typeof input === "string" ? parseRefreshOverlay(input) : parseRefreshOverlayValue(input);
|
|
189
|
+
if (!parsed.ok) {
|
|
190
|
+
return { status: "rejected", reason: "invalid_schema", error: parsed.error };
|
|
191
|
+
}
|
|
192
|
+
if (options.expectedBaseCatalogDigest !== parsed.overlay.baseCatalogDigest) {
|
|
193
|
+
return {
|
|
194
|
+
status: "degraded",
|
|
195
|
+
reason: "base_digest_mismatch",
|
|
196
|
+
warning: `Refresh overlay base catalog digest mismatch: overlay=${parsed.overlay.baseCatalogDigest} expected=${options.expectedBaseCatalogDigest}; overlay ignored`,
|
|
197
|
+
overlay: parsed.overlay
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
return { status: "ready", overlay: parsed.overlay };
|
|
201
|
+
}
|
|
202
|
+
async function loadRefreshOverlayFile(overlayPath, options) {
|
|
203
|
+
try {
|
|
204
|
+
const stat = await fs.lstat(overlayPath);
|
|
205
|
+
if (stat.isSymbolicLink()) {
|
|
206
|
+
return {
|
|
207
|
+
status: "rejected",
|
|
208
|
+
reason: "invalid_schema",
|
|
209
|
+
error: `Provider refresh refuses a symlinked overlay: ${overlayPath}`
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
if (!stat.isFile()) {
|
|
213
|
+
return {
|
|
214
|
+
status: "rejected",
|
|
215
|
+
reason: "invalid_schema",
|
|
216
|
+
error: `Provider refresh overlay target is not a regular file: ${overlayPath}`
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
const raw = await fs.readFile(overlayPath, "utf8");
|
|
220
|
+
return resolveRefreshOverlayDisposition(raw, options);
|
|
221
|
+
} catch (error) {
|
|
222
|
+
if (error.code === "ENOENT") {
|
|
223
|
+
return { status: "absent" };
|
|
224
|
+
}
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// src/core/config/cache-fingerprint.ts
|
|
230
|
+
import { createHash } from "crypto";
|
|
231
|
+
import { statSync } from "fs";
|
|
232
|
+
import { resolve } from "path";
|
|
233
|
+
function digest(value) {
|
|
234
|
+
return createHash("sha256").update(value).digest("hex");
|
|
235
|
+
}
|
|
236
|
+
function fingerprintEnvironment(env, include = (name) => name.startsWith("POETIC_")) {
|
|
237
|
+
const entries = Object.entries(env).filter(([name, value]) => include(name) && value !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([name, value]) => [name, digest(value ?? "")]);
|
|
238
|
+
return digest(JSON.stringify(entries));
|
|
239
|
+
}
|
|
240
|
+
function fingerprintFile(filePath) {
|
|
241
|
+
const normalized = resolve(filePath);
|
|
242
|
+
try {
|
|
243
|
+
const stat = statSync(normalized);
|
|
244
|
+
return JSON.stringify({
|
|
245
|
+
path: normalized,
|
|
246
|
+
exists: true,
|
|
247
|
+
dev: stat.dev,
|
|
248
|
+
ino: stat.ino,
|
|
249
|
+
size: stat.size,
|
|
250
|
+
mtimeMs: stat.mtimeMs,
|
|
251
|
+
ctimeMs: stat.ctimeMs
|
|
252
|
+
});
|
|
253
|
+
} catch (error) {
|
|
254
|
+
const code = error.code;
|
|
255
|
+
return JSON.stringify({ path: normalized, exists: false, code: code ?? "UNKNOWN" });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function fingerprintFiles(filePaths) {
|
|
259
|
+
return digest(JSON.stringify([...new Set(filePaths)].sort().map(fingerprintFile)));
|
|
260
|
+
}
|
|
261
|
+
function combineCacheFingerprints(...parts) {
|
|
262
|
+
return digest(JSON.stringify(parts.filter((part) => part !== void 0)));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// src/core/config/config-errors.ts
|
|
266
|
+
var InvalidExplicitConfigError = class extends Error {
|
|
267
|
+
constructor(message, sourceError) {
|
|
268
|
+
super(message);
|
|
269
|
+
this.sourceError = sourceError;
|
|
270
|
+
this.name = "InvalidExplicitConfigError";
|
|
271
|
+
}
|
|
272
|
+
sourceError;
|
|
273
|
+
code = "POETIC_INVALID_EXPLICIT_CONFIG";
|
|
274
|
+
};
|
|
275
|
+
function isInvalidExplicitConfigError(error) {
|
|
276
|
+
return error instanceof InvalidExplicitConfigError || error instanceof Error && error.code === "POETIC_INVALID_EXPLICIT_CONFIG";
|
|
277
|
+
}
|
|
278
|
+
function isConfigValidityError(error) {
|
|
279
|
+
if (isInvalidExplicitConfigError(error)) return true;
|
|
280
|
+
return error instanceof Error && error.code === "POETIC_CONFIG_READ_INVALID";
|
|
281
|
+
}
|
|
282
|
+
function rethrowConfigValidityError(error) {
|
|
283
|
+
if (isConfigValidityError(error)) throw error;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/core/config/registry/dynamic-keys.ts
|
|
287
|
+
var DYNAMIC_KEYS = [
|
|
288
|
+
// Per-command idle timeouts
|
|
289
|
+
// Source: src/core/providers/shared/base-runner.ts
|
|
290
|
+
// process.env[`POETIC_IDLE_WARN_${commandName}_MS`]
|
|
291
|
+
{
|
|
292
|
+
pattern: /^POETIC_IDLE_WARN_[A-Z][A-Z0-9_]*_MS$/,
|
|
293
|
+
extract: (name) => {
|
|
294
|
+
const m = name.match(/^POETIC_IDLE_WARN_([A-Z][A-Z0-9_]*)_MS$/);
|
|
295
|
+
if (!m || m[1] === void 0) return null;
|
|
296
|
+
return { command: m[1] };
|
|
297
|
+
},
|
|
298
|
+
category: "provider",
|
|
299
|
+
status: "active",
|
|
300
|
+
description: "Per-command idle warning threshold: POETIC_IDLE_WARN_<CMD>_MS",
|
|
301
|
+
type: "number"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
pattern: /^POETIC_IDLE_KILL_[A-Z][A-Z0-9_]*_MS$/,
|
|
305
|
+
extract: (name) => {
|
|
306
|
+
const m = name.match(/^POETIC_IDLE_KILL_([A-Z][A-Z0-9_]*)_MS$/);
|
|
307
|
+
if (!m || m[1] === void 0) return null;
|
|
308
|
+
return { command: m[1] };
|
|
309
|
+
},
|
|
310
|
+
category: "provider",
|
|
311
|
+
status: "active",
|
|
312
|
+
description: "Per-command idle kill threshold: POETIC_IDLE_KILL_<CMD>_MS",
|
|
313
|
+
type: "number"
|
|
314
|
+
},
|
|
315
|
+
// Per-provider timeout overrides
|
|
316
|
+
// Source: src/core/timeout/timeout-config.ts
|
|
317
|
+
// `POETIC_TIMEOUT_${normalizedProvider.toUpperCase()}_${mode.toUpperCase()}`
|
|
318
|
+
// `POETIC_TIMEOUT_DEFAULT_${mode.toUpperCase()}`
|
|
319
|
+
// Modes observed: LOCAL, CLOUD, API, REMOTE, MS, and any future mode string.
|
|
320
|
+
{
|
|
321
|
+
pattern: /^POETIC_TIMEOUT_[A-Z][A-Z0-9_]*_[A-Z][A-Z0-9]*$/,
|
|
322
|
+
extract: (name) => {
|
|
323
|
+
const m = name.match(/^POETIC_TIMEOUT_([A-Z][A-Z0-9_]*)_([A-Z][A-Z0-9]*)$/);
|
|
324
|
+
if (!m || m[1] === void 0 || m[2] === void 0) return null;
|
|
325
|
+
return { provider: m[1], mode: m[2] };
|
|
326
|
+
},
|
|
327
|
+
category: "provider",
|
|
328
|
+
status: "active",
|
|
329
|
+
description: "Per-provider/mode timeout override (ms): POETIC_TIMEOUT_<PROVIDER>_<MODE> or POETIC_TIMEOUT_DEFAULT_<MODE>",
|
|
330
|
+
type: "number"
|
|
331
|
+
},
|
|
332
|
+
// Per-provider timeout from provider-timeout.ts
|
|
333
|
+
// Source: src/core/providers/shared/provider-timeout.ts
|
|
334
|
+
// `POETIC_TIMEOUT_${providerId.toUpperCase()}_MS`
|
|
335
|
+
// This is a subset of the pattern above; the combined pattern already covers it.
|
|
336
|
+
// Per-provider sandbox toggles
|
|
337
|
+
// Source: src/core/sandbox/index.ts
|
|
338
|
+
// process.env[`POETIC_SANDBOX_${normalizedName}_ENABLED`]
|
|
339
|
+
// process.env[`POETIC_SANDBOX_${normalizedId}_ENABLED`]
|
|
340
|
+
{
|
|
341
|
+
pattern: /^POETIC_SANDBOX_[A-Z][A-Z0-9_]*_ENABLED$/,
|
|
342
|
+
extract: (name) => {
|
|
343
|
+
const m = name.match(/^POETIC_SANDBOX_([A-Z][A-Z0-9_]*)_ENABLED$/);
|
|
344
|
+
if (!m || m[1] === void 0) return null;
|
|
345
|
+
return { provider: m[1] };
|
|
346
|
+
},
|
|
347
|
+
category: "sandbox",
|
|
348
|
+
status: "active",
|
|
349
|
+
description: "Per-provider sandbox enable toggle: POETIC_SANDBOX_<PROVIDER>_ENABLED",
|
|
350
|
+
type: "boolean"
|
|
351
|
+
},
|
|
352
|
+
// Per-provider execution policy enforcement
|
|
353
|
+
// Source: src/orchestrator/execution-policy.ts
|
|
354
|
+
// `POETIC_EXECUTION_POLICY_ENFORCE_${provider.toUpperCase()}`
|
|
355
|
+
{
|
|
356
|
+
pattern: /^POETIC_EXECUTION_POLICY_ENFORCE_[A-Z][A-Z0-9_]*$/,
|
|
357
|
+
extract: (name) => {
|
|
358
|
+
const m = name.match(/^POETIC_EXECUTION_POLICY_ENFORCE_([A-Z][A-Z0-9_]*)$/);
|
|
359
|
+
if (!m || m[1] === void 0) return null;
|
|
360
|
+
return { provider: m[1] };
|
|
361
|
+
},
|
|
362
|
+
category: "orchestrator",
|
|
363
|
+
status: "active",
|
|
364
|
+
description: "Per-provider execution policy enforcement toggle: POETIC_EXECUTION_POLICY_ENFORCE_<PROVIDER>",
|
|
365
|
+
type: "boolean"
|
|
366
|
+
},
|
|
367
|
+
// Per-provider config overrides
|
|
368
|
+
// Source: src/core/config/provider-registry.ts
|
|
369
|
+
// POETIC_PROVIDER_<ID>_<KEY>=value (e.g. POETIC_PROVIDER_CODEX_TIMEOUT_MS,
|
|
370
|
+
// POETIC_PROVIDER_CLAUDE_ENABLED, POETIC_PROVIDER_GEMINI_MODELS_DEFAULT).
|
|
371
|
+
// Static REGISTRY entries that begin with POETIC_PROVIDER_ are checked
|
|
372
|
+
// first by isRecognizedEnvVar; this fallback recognizes the dynamic
|
|
373
|
+
// <PROVIDER>_<KEY> shape so legitimate overrides aren't flagged. The
|
|
374
|
+
// provider/key boundary is registry-dependent because both may contain
|
|
375
|
+
// underscores; ProviderRegistry resolves the longest registered prefix.
|
|
376
|
+
{
|
|
377
|
+
pattern: /^POETIC_PROVIDER_[A-Z0-9][A-Z0-9_-]*_[A-Z][A-Z0-9_]*$/,
|
|
378
|
+
extract: (name) => {
|
|
379
|
+
const m = name.match(/^POETIC_PROVIDER_([A-Z0-9][A-Z0-9_-]*_[A-Z][A-Z0-9_]*)$/);
|
|
380
|
+
if (!m || m[1] === void 0) return null;
|
|
381
|
+
return { providerAndKey: m[1] };
|
|
382
|
+
},
|
|
383
|
+
category: "provider",
|
|
384
|
+
status: "active",
|
|
385
|
+
description: "Per-provider config override: POETIC_PROVIDER_<ID>_<KEY>",
|
|
386
|
+
type: "string"
|
|
387
|
+
}
|
|
388
|
+
];
|
|
389
|
+
|
|
390
|
+
// src/core/config/env-var-registry.ts
|
|
391
|
+
var REGISTRY = Object.fromEntries(
|
|
392
|
+
Object.entries(KEYS).map(([name, spec]) => [
|
|
393
|
+
name,
|
|
394
|
+
{
|
|
395
|
+
category: spec.category,
|
|
396
|
+
status: spec.status,
|
|
397
|
+
description: spec.description,
|
|
398
|
+
...spec.replacement !== void 0 ? { replacement: spec.replacement } : {}
|
|
399
|
+
}
|
|
400
|
+
])
|
|
401
|
+
);
|
|
402
|
+
function isRecognizedEnvVar(name) {
|
|
403
|
+
if (REGISTRY[name]) return true;
|
|
404
|
+
return DYNAMIC_KEYS.some((spec) => spec.pattern.test(name));
|
|
405
|
+
}
|
|
406
|
+
function getEnvVarEntry(name) {
|
|
407
|
+
return REGISTRY[name];
|
|
408
|
+
}
|
|
409
|
+
function levenshtein(a, b, maxDist) {
|
|
410
|
+
if (Math.abs(a.length - b.length) > maxDist) return maxDist + 1;
|
|
411
|
+
const prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
412
|
+
const curr = new Array(b.length + 1);
|
|
413
|
+
for (let i = 1; i <= a.length; i++) {
|
|
414
|
+
curr[0] = i;
|
|
415
|
+
for (let j = 1; j <= b.length; j++) {
|
|
416
|
+
curr[j] = a[i - 1] === b[j - 1] ? prev[j - 1] : 1 + Math.min(prev[j], curr[j - 1], prev[j - 1]);
|
|
417
|
+
}
|
|
418
|
+
for (let j = 0; j <= b.length; j++) prev[j] = curr[j];
|
|
419
|
+
}
|
|
420
|
+
return prev[b.length];
|
|
421
|
+
}
|
|
422
|
+
function closestRegisteredKeys(unknown, maxDist, limit) {
|
|
423
|
+
const candidates = [];
|
|
424
|
+
for (const name of Object.keys(REGISTRY)) {
|
|
425
|
+
const dist = levenshtein(unknown, name, maxDist);
|
|
426
|
+
if (dist <= maxDist) candidates.push({ name, dist });
|
|
427
|
+
}
|
|
428
|
+
candidates.sort((a, b) => a.dist - b.dist);
|
|
429
|
+
return candidates.slice(0, limit).map((c) => c.name);
|
|
430
|
+
}
|
|
431
|
+
function validateEnvironmentVars() {
|
|
432
|
+
const unrecognized = [];
|
|
433
|
+
for (const key of Object.keys(process.env)) {
|
|
434
|
+
if (!key.startsWith("POETIC_")) continue;
|
|
435
|
+
if (!isRecognizedEnvVar(key)) {
|
|
436
|
+
unrecognized.push(key);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (process.env.POETIC_STRICT_ENV === "1" && unrecognized.length > 0) {
|
|
440
|
+
for (const key of unrecognized) {
|
|
441
|
+
const suggestions = closestRegisteredKeys(key, 2, 3);
|
|
442
|
+
const hint = suggestions.length > 0 ? ` (did you mean: ${suggestions.join(", ")}?)` : "";
|
|
443
|
+
console.warn(`[poetic] POETIC_STRICT_ENV: unrecognized env var: ${key}${hint}`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return unrecognized;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/core/config/project-trust.ts
|
|
450
|
+
import { realpathSync } from "fs";
|
|
451
|
+
import { isAbsolute, resolve as resolve2 } from "path";
|
|
452
|
+
var PROJECT_EXECUTION_TRUST_ENV = "POETIC_TRUST_PROJECT_PROVIDER_TEMPLATES";
|
|
453
|
+
function isTrustedProjectRoot(projectRoot) {
|
|
454
|
+
const projectTrustValue = String(process.env[PROJECT_EXECUTION_TRUST_ENV] ?? "").trim();
|
|
455
|
+
if (!projectTrustValue || !isAbsolute(projectTrustValue)) return false;
|
|
456
|
+
try {
|
|
457
|
+
return realpathSync(resolve2(projectTrustValue)) === realpathSync(projectRoot);
|
|
458
|
+
} catch {
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function formatProjectTrustInstruction(projectRoot) {
|
|
463
|
+
let canonical = projectRoot;
|
|
464
|
+
try {
|
|
465
|
+
canonical = realpathSync(projectRoot);
|
|
466
|
+
} catch {
|
|
467
|
+
}
|
|
468
|
+
return ` export ${PROJECT_EXECUTION_TRUST_ENV}=${JSON.stringify(canonical)}`;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// src/core/config/provider-registry-reload-invalidators.ts
|
|
472
|
+
var reloadInvalidators = /* @__PURE__ */ new Set();
|
|
473
|
+
function registerProviderRegistryReloadInvalidator(invalidator) {
|
|
474
|
+
reloadInvalidators.add(invalidator);
|
|
475
|
+
return () => {
|
|
476
|
+
reloadInvalidators.delete(invalidator);
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
function runProviderRegistryReloadInvalidators() {
|
|
480
|
+
for (const invalidator of reloadInvalidators) {
|
|
481
|
+
invalidator();
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// src/core/config/provider-registry.ts
|
|
486
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
487
|
+
function getEmbeddedProviderConfigPaths() {
|
|
488
|
+
const packageRoot = findPoeticPackageRoot(__filename);
|
|
489
|
+
if (!packageRoot) return [];
|
|
490
|
+
return [
|
|
491
|
+
// A source checkout authors the canonical YAML directly. Prefer it over the
|
|
492
|
+
// ignored generated asset so a stale prebuild output cannot shadow or break
|
|
493
|
+
// local authoring. The YAML path is not published in the npm package.
|
|
494
|
+
resolve3(packageRoot, ".poetic/config/providers.yaml"),
|
|
495
|
+
// Installed runtimes therefore require the packaged, digest-checked asset.
|
|
496
|
+
resolve3(packageRoot, ".poetic/providers/catalog.json")
|
|
497
|
+
];
|
|
498
|
+
}
|
|
499
|
+
function getUserProviderRegistryPaths(cwd = process.cwd()) {
|
|
500
|
+
let home = "";
|
|
501
|
+
try {
|
|
502
|
+
home = homedir() ?? "";
|
|
503
|
+
} catch {
|
|
504
|
+
home = "";
|
|
505
|
+
}
|
|
506
|
+
if (!home) home = (process.env.HOME ?? process.env.USERPROFILE ?? "").trim();
|
|
507
|
+
const canonicalUserDir = getConfigPaths(cwd).userConfigDir;
|
|
508
|
+
const defaultUserDir = home ? join(home, ".poetic", "config") : "";
|
|
509
|
+
return [
|
|
510
|
+
join(canonicalUserDir, "providers.yaml"),
|
|
511
|
+
// ~/.config/poetic is the pre-default (XDG) registry location, kept as a
|
|
512
|
+
// compatibility fallback for the default layout only. An explicit
|
|
513
|
+
// POETIC_CONFIG_DIR/XDG root is authoritative and must not be contaminated
|
|
514
|
+
// by state from another user-config tree.
|
|
515
|
+
...home && resolve3(canonicalUserDir) === resolve3(defaultUserDir) ? [join(home, ".config", "poetic", "providers.yaml")] : []
|
|
516
|
+
];
|
|
517
|
+
}
|
|
518
|
+
function getConfiguredProviderRegistryPaths(cwd = process.cwd()) {
|
|
519
|
+
const projectRoot = findProjectRoot(cwd) ?? cwd;
|
|
520
|
+
return [
|
|
521
|
+
...getUserProviderRegistryPaths(projectRoot),
|
|
522
|
+
resolveProvidersConfigPath({ cwd: projectRoot }),
|
|
523
|
+
resolve3(projectRoot, ".poetic", "config", "provider-registry.yaml.v1.backup")
|
|
524
|
+
];
|
|
525
|
+
}
|
|
526
|
+
function getProviderRegistryInputPaths(cwd = process.cwd()) {
|
|
527
|
+
const projectRoot = findProjectRoot(cwd) ?? cwd;
|
|
528
|
+
return [
|
|
529
|
+
...getEmbeddedProviderConfigPaths(),
|
|
530
|
+
resolve3(projectRoot, ".poetic", "cache", "model-update", "refresh-overlay.json"),
|
|
531
|
+
...getConfiguredProviderRegistryPaths(projectRoot)
|
|
532
|
+
];
|
|
533
|
+
}
|
|
534
|
+
var REMOVED_BUILTIN_PROVIDER_IDS = /* @__PURE__ */ new Set(["glm"]);
|
|
535
|
+
var PROJECT_POLICY_PROVIDER_FIELDS = [
|
|
536
|
+
"enabled",
|
|
537
|
+
"order",
|
|
538
|
+
"concurrency_hint",
|
|
539
|
+
"concurrency",
|
|
540
|
+
"timeout_ms",
|
|
541
|
+
"health_check_timeout_ms",
|
|
542
|
+
"memory",
|
|
543
|
+
"polling",
|
|
544
|
+
"bot_identity",
|
|
545
|
+
"env",
|
|
546
|
+
"retry",
|
|
547
|
+
"circuit_breaker",
|
|
548
|
+
"rate_limits",
|
|
549
|
+
"workspace_edits",
|
|
550
|
+
"generation",
|
|
551
|
+
"task_settings",
|
|
552
|
+
"options"
|
|
553
|
+
];
|
|
554
|
+
var PROJECT_TRUSTED_EXTENSION_FIELDS = [
|
|
555
|
+
"transport",
|
|
556
|
+
"api",
|
|
557
|
+
"auth",
|
|
558
|
+
"cli",
|
|
559
|
+
"exec",
|
|
560
|
+
"engine",
|
|
561
|
+
"plugins",
|
|
562
|
+
"route_id",
|
|
563
|
+
"route",
|
|
564
|
+
"allow_unsafe_binary",
|
|
565
|
+
"requires",
|
|
566
|
+
"requires_if"
|
|
567
|
+
];
|
|
568
|
+
var EXECUTION_SENSITIVE_PROVIDER_FIELDS = ["cli", "exec", "engine", "plugins"];
|
|
569
|
+
var CURSOR_ID_SYNTAX_ADMISSION_PATTERN = "^[a-z0-9][a-z0-9._-]{0,63}$";
|
|
570
|
+
var DateLikeStringSchema = z2.union([z2.string(), z2.date()]).transform((value) => value instanceof Date ? value.toISOString() : value);
|
|
571
|
+
function normalizeProviderConfigId(providerId) {
|
|
572
|
+
const normalized = providerId.trim().toLowerCase();
|
|
573
|
+
if (normalized === "cursor-cli") return "cursor";
|
|
574
|
+
if (normalized === "copilot-cli") return "copilot";
|
|
575
|
+
if (normalized === "anti-gravity" || normalized === "antigravity-cli" || normalized === "agy") {
|
|
576
|
+
return "antigravity";
|
|
577
|
+
}
|
|
578
|
+
return normalized;
|
|
579
|
+
}
|
|
580
|
+
function dropRemovedBuiltinProviders(raw) {
|
|
581
|
+
if (!raw || typeof raw !== "object") return raw;
|
|
582
|
+
const providers = raw.providers;
|
|
583
|
+
if (!providers || typeof providers !== "object") return raw;
|
|
584
|
+
for (const providerId of REMOVED_BUILTIN_PROVIDER_IDS) {
|
|
585
|
+
delete providers[providerId];
|
|
586
|
+
}
|
|
587
|
+
return raw;
|
|
588
|
+
}
|
|
589
|
+
function ensureCursorIdSyntaxAdmissionPattern(raw) {
|
|
590
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return raw;
|
|
591
|
+
const providers = raw.providers;
|
|
592
|
+
if (!providers || typeof providers !== "object" || Array.isArray(providers)) return raw;
|
|
593
|
+
const cursor = providers.cursor;
|
|
594
|
+
if (!cursor || typeof cursor !== "object" || Array.isArray(cursor)) return raw;
|
|
595
|
+
const models = cursor.models;
|
|
596
|
+
if (!models || typeof models !== "object" || Array.isArray(models)) return raw;
|
|
597
|
+
const patterns = models.allowed_patterns;
|
|
598
|
+
if (!Array.isArray(patterns)) return raw;
|
|
599
|
+
if (!patterns.every((pattern) => typeof pattern === "string")) return raw;
|
|
600
|
+
if (patterns.includes(CURSOR_ID_SYNTAX_ADMISSION_PATTERN)) return raw;
|
|
601
|
+
models.allowed_patterns = [
|
|
602
|
+
...patterns,
|
|
603
|
+
CURSOR_ID_SYNTAX_ADMISSION_PATTERN
|
|
604
|
+
];
|
|
605
|
+
return raw;
|
|
606
|
+
}
|
|
607
|
+
function projectProjectRegistryPolicy(projectRaw, embeddedRaw, options) {
|
|
608
|
+
if (!projectRaw || typeof projectRaw !== "object" || Array.isArray(projectRaw)) {
|
|
609
|
+
return projectRaw;
|
|
610
|
+
}
|
|
611
|
+
const embeddedProvidersValue = embeddedRaw && typeof embeddedRaw === "object" && !Array.isArray(embeddedRaw) ? embeddedRaw.providers : null;
|
|
612
|
+
if (!embeddedProvidersValue || typeof embeddedProvidersValue !== "object" || Array.isArray(embeddedProvidersValue)) {
|
|
613
|
+
return projectRaw;
|
|
614
|
+
}
|
|
615
|
+
const projectProvidersValue = projectRaw.providers;
|
|
616
|
+
if (!projectProvidersValue || typeof projectProvidersValue !== "object" || Array.isArray(projectProvidersValue)) {
|
|
617
|
+
return projectRaw;
|
|
618
|
+
}
|
|
619
|
+
const embeddedProviders = embeddedProvidersValue;
|
|
620
|
+
const projectedProviders = {};
|
|
621
|
+
for (const [providerId, providerValue] of Object.entries(
|
|
622
|
+
projectProvidersValue
|
|
623
|
+
)) {
|
|
624
|
+
if (!(providerId in embeddedProviders)) {
|
|
625
|
+
projectedProviders[providerId] = providerValue;
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
if (!providerValue || typeof providerValue !== "object" || Array.isArray(providerValue)) {
|
|
629
|
+
projectedProviders[providerId] = providerValue;
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
const sourceProvider = providerValue;
|
|
633
|
+
const provider = {};
|
|
634
|
+
for (const field of PROJECT_POLICY_PROVIDER_FIELDS) {
|
|
635
|
+
if (sourceProvider[field] !== void 0) provider[field] = sourceProvider[field];
|
|
636
|
+
}
|
|
637
|
+
if (options.trusted) {
|
|
638
|
+
for (const field of PROJECT_TRUSTED_EXTENSION_FIELDS) {
|
|
639
|
+
if (sourceProvider[field] !== void 0) provider[field] = sourceProvider[field];
|
|
640
|
+
}
|
|
641
|
+
} else if (sourceProvider.api && typeof sourceProvider.api === "object" && !Array.isArray(sourceProvider.api)) {
|
|
642
|
+
const sourceApi = sourceProvider.api;
|
|
643
|
+
const api = {};
|
|
644
|
+
for (const field of [
|
|
645
|
+
"stream",
|
|
646
|
+
"max_tokens",
|
|
647
|
+
"max_tool_iterations",
|
|
648
|
+
"per_tool_timeout_ms"
|
|
649
|
+
]) {
|
|
650
|
+
if (sourceApi[field] !== void 0) api[field] = sourceApi[field];
|
|
651
|
+
}
|
|
652
|
+
if (Object.keys(api).length > 0) provider.api = api;
|
|
653
|
+
}
|
|
654
|
+
const modelsValue = sourceProvider.models;
|
|
655
|
+
if (modelsValue && typeof modelsValue === "object" && !Array.isArray(modelsValue)) {
|
|
656
|
+
const sourceModels = modelsValue;
|
|
657
|
+
const models = {};
|
|
658
|
+
for (const field of ["default", "default_reasoning_effort", "roles", "mappings"]) {
|
|
659
|
+
if (sourceModels[field] !== void 0) models[field] = sourceModels[field];
|
|
660
|
+
}
|
|
661
|
+
provider.models = models;
|
|
662
|
+
}
|
|
663
|
+
projectedProviders[providerId] = provider;
|
|
664
|
+
}
|
|
665
|
+
return {
|
|
666
|
+
providers: projectedProviders
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
function applyRefreshOverlay(baseRaw, overlay) {
|
|
670
|
+
if (!baseRaw || typeof baseRaw !== "object" || Array.isArray(baseRaw)) return baseRaw;
|
|
671
|
+
const base = structuredClone(baseRaw);
|
|
672
|
+
const providers = base.providers;
|
|
673
|
+
if (!providers || typeof providers !== "object" || Array.isArray(providers)) return baseRaw;
|
|
674
|
+
for (const [providerId, payload] of Object.entries(overlay.providers)) {
|
|
675
|
+
const provider = providers[providerId];
|
|
676
|
+
if (!provider || typeof provider !== "object" || Array.isArray(provider)) continue;
|
|
677
|
+
const providerObject = provider;
|
|
678
|
+
if (payload.models) {
|
|
679
|
+
const models = providerObject.models;
|
|
680
|
+
if (models && typeof models === "object" && !Array.isArray(models)) {
|
|
681
|
+
const modelObject = models;
|
|
682
|
+
if (payload.models.replaceInventory) {
|
|
683
|
+
modelObject.available = payload.models.available;
|
|
684
|
+
const access = modelObject.access;
|
|
685
|
+
if (access && typeof access === "object" && !Array.isArray(access)) {
|
|
686
|
+
const accessObject = access;
|
|
687
|
+
const overrides = accessObject.overrides;
|
|
688
|
+
if (overrides && typeof overrides === "object" && !Array.isArray(overrides)) {
|
|
689
|
+
const availableIds = new Set(payload.models.available.map((entry) => entry.id));
|
|
690
|
+
accessObject.overrides = Object.fromEntries(
|
|
691
|
+
Object.entries(overrides).filter(
|
|
692
|
+
([modelId]) => availableIds.has(modelId)
|
|
693
|
+
)
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
} else {
|
|
698
|
+
const current = Array.isArray(modelObject.available) ? modelObject.available : [];
|
|
699
|
+
const overlayById = new Map(payload.models.available.map((entry) => [entry.id, entry]));
|
|
700
|
+
const merged = current.map((entry) => {
|
|
701
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return entry;
|
|
702
|
+
const id = entry.id;
|
|
703
|
+
const updated = typeof id === "string" ? overlayById.get(id) : void 0;
|
|
704
|
+
if (!updated) return entry;
|
|
705
|
+
overlayById.delete(id);
|
|
706
|
+
return { ...entry, ...updated };
|
|
707
|
+
});
|
|
708
|
+
modelObject.available = [...merged, ...overlayById.values()];
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
if (payload.pricing) {
|
|
713
|
+
const pricing = providerObject.pricing;
|
|
714
|
+
if (pricing && typeof pricing === "object" && !Array.isArray(pricing)) {
|
|
715
|
+
const pricingObject = pricing;
|
|
716
|
+
const currentModels = pricingObject.models && typeof pricingObject.models === "object" && !Array.isArray(pricingObject.models) ? pricingObject.models : {};
|
|
717
|
+
pricingObject.models = Object.fromEntries(
|
|
718
|
+
Object.entries({ ...currentModels, ...payload.pricing.models }).map(([id, row]) => [
|
|
719
|
+
id,
|
|
720
|
+
currentModels[id] && typeof currentModels[id] === "object" ? { ...currentModels[id], ...row } : row
|
|
721
|
+
])
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
return base;
|
|
727
|
+
}
|
|
728
|
+
var RetryConfigSchema = z2.object({
|
|
729
|
+
max_attempts: z2.number().int().min(1).max(10),
|
|
730
|
+
initial_delay_ms: z2.number().int().min(0),
|
|
731
|
+
max_delay_ms: z2.number().int().min(0),
|
|
732
|
+
backoff_multiplier: z2.number().min(1)
|
|
733
|
+
}).strict();
|
|
734
|
+
var CircuitBreakerConfigSchema = z2.object({
|
|
735
|
+
failure_threshold: z2.number().int().min(1),
|
|
736
|
+
cooldown_ms: z2.number().int().min(0),
|
|
737
|
+
half_open_max_attempts: z2.number().int().min(1).optional()
|
|
738
|
+
}).strict();
|
|
739
|
+
var RateLimitEntrySchema = z2.object({
|
|
740
|
+
rpm: z2.number().int().min(1),
|
|
741
|
+
// Requests per minute
|
|
742
|
+
bucket_size: z2.number().int().min(1),
|
|
743
|
+
// Token bucket burst capacity
|
|
744
|
+
refill_rate: z2.number().min(0)
|
|
745
|
+
// Tokens per second
|
|
746
|
+
}).strict();
|
|
747
|
+
var RateLimitsConfigSchema = z2.object({
|
|
748
|
+
rpm: z2.number().int().min(1).optional(),
|
|
749
|
+
// Default RPM (convenience alias)
|
|
750
|
+
bucket_size: z2.number().int().min(1).optional(),
|
|
751
|
+
// Default bucket size
|
|
752
|
+
refill_rate: z2.number().min(0).optional(),
|
|
753
|
+
// Default refill rate
|
|
754
|
+
default: RateLimitEntrySchema.optional(),
|
|
755
|
+
// Explicit default config
|
|
756
|
+
models: z2.record(z2.string(), RateLimitEntrySchema).optional()
|
|
757
|
+
// Per-model overrides
|
|
758
|
+
}).strict();
|
|
759
|
+
var MemoryConfigSchema = z2.object({
|
|
760
|
+
warn_threshold: z2.number().min(0).max(1),
|
|
761
|
+
critical_threshold: z2.number().min(0).max(1),
|
|
762
|
+
emergency_threshold: z2.number().min(0).max(1),
|
|
763
|
+
max_processes: z2.number().int().min(1)
|
|
764
|
+
}).strict();
|
|
765
|
+
var PollingConfigSchema = z2.object({
|
|
766
|
+
initial_interval_ms: z2.number().int().min(0),
|
|
767
|
+
max_interval_ms: z2.number().int().min(0),
|
|
768
|
+
backoff_multiplier: z2.number().min(1),
|
|
769
|
+
timeout_ms: z2.number().int().min(0).optional(),
|
|
770
|
+
show_progress: z2.boolean()
|
|
771
|
+
}).strict();
|
|
772
|
+
var CLIConfigSchema = z2.object({
|
|
773
|
+
command: z2.string(),
|
|
774
|
+
binary: z2.string(),
|
|
775
|
+
install_command: z2.string().default(""),
|
|
776
|
+
// Installation metadata for setup automation
|
|
777
|
+
// - manual: show instructions only (no command execution)
|
|
778
|
+
// - curl: requires explicit opt-in via POETIC_ALLOW_CURL_BASH=1
|
|
779
|
+
install_method: z2.enum(["npm", "brew", "pipx", "curl", "manual"]).optional().default("manual"),
|
|
780
|
+
min_node_version: z2.string().optional(),
|
|
781
|
+
risk_level: z2.enum(["safe", "needs-confirmation"]).optional().default("safe"),
|
|
782
|
+
install_note: z2.string().optional()
|
|
783
|
+
}).strict();
|
|
784
|
+
var AuthConfigSchema = z2.object({
|
|
785
|
+
type: z2.enum(["cli_login", "api_key", "oauth", "cli_wrapper"]),
|
|
786
|
+
env_vars: z2.array(z2.string()),
|
|
787
|
+
skip_env_var: z2.string().optional(),
|
|
788
|
+
note: z2.string().optional()
|
|
789
|
+
}).strict();
|
|
790
|
+
var TemplatedAuthConfigSchema = AuthConfigSchema.default({
|
|
791
|
+
type: "cli_login",
|
|
792
|
+
env_vars: [],
|
|
793
|
+
skip_env_var: "POETIC_SKIP_AUTH"
|
|
794
|
+
});
|
|
795
|
+
var ProviderReleaseStatusSchema = z2.enum([
|
|
796
|
+
"primary_validated",
|
|
797
|
+
"supported_validated",
|
|
798
|
+
"supported_beta",
|
|
799
|
+
"experimental"
|
|
800
|
+
]);
|
|
801
|
+
var JsonScalarSchema = z2.union([z2.string(), z2.number(), z2.boolean(), z2.null()]);
|
|
802
|
+
var ProbeExpectationSchema = z2.union([
|
|
803
|
+
JsonScalarSchema,
|
|
804
|
+
z2.object({
|
|
805
|
+
present: z2.boolean().optional(),
|
|
806
|
+
truthy: z2.boolean().optional(),
|
|
807
|
+
equals: JsonScalarSchema.optional()
|
|
808
|
+
}).strict()
|
|
809
|
+
]);
|
|
810
|
+
var CommandProbeSchema = z2.object({
|
|
811
|
+
command_argv: z2.array(z2.string()).min(1),
|
|
812
|
+
parse_as: z2.enum(["json", "exit_code"]).optional().default("json"),
|
|
813
|
+
json_path: z2.string().optional(),
|
|
814
|
+
expect: ProbeExpectationSchema.optional(),
|
|
815
|
+
timeout_ms: z2.number().int().min(1).optional()
|
|
816
|
+
}).strict();
|
|
817
|
+
var ModelsDiscoverySchema = z2.object({
|
|
818
|
+
command_argv: z2.array(z2.string()).min(1),
|
|
819
|
+
json_path: z2.string().optional().default("$"),
|
|
820
|
+
id_path: z2.string().optional().default("id"),
|
|
821
|
+
ttl_hours: z2.number().positive().optional().default(24),
|
|
822
|
+
timeout_ms: z2.number().int().min(1).optional()
|
|
823
|
+
}).strict();
|
|
824
|
+
var LongContextPricingSchema = z2.object({
|
|
825
|
+
threshold_tokens: z2.number().int().optional(),
|
|
826
|
+
threshold: z2.number().int().optional(),
|
|
827
|
+
input_multiplier: z2.number().positive(),
|
|
828
|
+
output_multiplier: z2.number().positive(),
|
|
829
|
+
note: z2.string().optional()
|
|
830
|
+
}).strict().superRefine((value, ctx) => {
|
|
831
|
+
if (value.threshold_tokens === void 0 && value.threshold === void 0) {
|
|
832
|
+
ctx.addIssue({
|
|
833
|
+
code: z2.ZodIssueCode.custom,
|
|
834
|
+
message: "long_context_pricing requires threshold_tokens or threshold",
|
|
835
|
+
path: ["threshold_tokens"]
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
}).transform((value) => ({
|
|
839
|
+
threshold_tokens: value.threshold_tokens ?? value.threshold,
|
|
840
|
+
input_multiplier: value.input_multiplier,
|
|
841
|
+
output_multiplier: value.output_multiplier,
|
|
842
|
+
...value.note ? { note: value.note } : {}
|
|
843
|
+
}));
|
|
844
|
+
var ModelInfoSchema = z2.object({
|
|
845
|
+
id: z2.string().trim().min(1),
|
|
846
|
+
display_name: z2.string(),
|
|
847
|
+
full_name: z2.string().optional(),
|
|
848
|
+
capabilities: z2.array(z2.string()),
|
|
849
|
+
context_window: z2.number().int().optional(),
|
|
850
|
+
long_context_pricing: LongContextPricingSchema.optional(),
|
|
851
|
+
context_window_beta: z2.object({
|
|
852
|
+
max_tokens: z2.number().int(),
|
|
853
|
+
beta_header: z2.string(),
|
|
854
|
+
pricing_note: z2.string().optional()
|
|
855
|
+
}).optional(),
|
|
856
|
+
max_output_tokens: z2.number().int().optional(),
|
|
857
|
+
/**
|
|
858
|
+
* Claude-CLI context-window selector to append to this model's `--model`
|
|
859
|
+
* value (only `[1m]` exists today).
|
|
860
|
+
*
|
|
861
|
+
* Deliberately top-level: the selector applies on every CLI backend, so
|
|
862
|
+
* nesting it under `bedrock` made it structurally impossible to declare for
|
|
863
|
+
* Anthropic first-party or Vertex. The nested
|
|
864
|
+
* `bedrock.claude_cli_context_selector` is still read as a fallback for
|
|
865
|
+
* configs written against the old shape.
|
|
866
|
+
*
|
|
867
|
+
* The backends are NOT identical, which is why one field plus a per-backend
|
|
868
|
+
* application rule beats duplicating it. What we actually know:
|
|
869
|
+
* - Bedrock — TESTED (live probes 2026-07-26). opus-5 / fable-5 / opus-4-8 /
|
|
870
|
+
* opus-4-7 / opus-4-6 / sonnet-4-6 report 200K bare and need the suffix;
|
|
871
|
+
* sonnet-5 is 1M bare.
|
|
872
|
+
* - Anthropic first-party — TESTED (live probes 2026-07-26, clean HOME so
|
|
873
|
+
* only the API key could authenticate). opus-5 / sonnet-5 / fable-5 /
|
|
874
|
+
* opus-4-8 / opus-4-7 are already 1M BARE; only opus-4-6 and sonnet-4-6
|
|
875
|
+
* report 200K and need the suffix. Appending to an already-1M model is a
|
|
876
|
+
* no-op we confirmed.
|
|
877
|
+
* - Vertex — NOT TESTED. No Google Cloud credits, so no probe has run. It is
|
|
878
|
+
* included on the strength of Anthropic's documentation, which says the
|
|
879
|
+
* same models support 1M there and that a model ID without `[1m]` uses
|
|
880
|
+
* 200K on Vertex. Documentation, not measurement.
|
|
881
|
+
*
|
|
882
|
+
* Present ONLY for models where the selector is necessary on at least one
|
|
883
|
+
* backend. Models at 1M unsuffixed everywhere (claude-sonnet-5) omit it, as do
|
|
884
|
+
* models whose declared window is 200K.
|
|
885
|
+
*
|
|
886
|
+
* `z.literal` + the surrounding `.strict()` are load-bearing: without them a
|
|
887
|
+
* misspelled key or value is accepted and silently dropped, which looks
|
|
888
|
+
* identical to "this model does not need the selector".
|
|
889
|
+
*/
|
|
890
|
+
claude_cli_context_selector: z2.literal("[1m]").optional(),
|
|
891
|
+
bedrock: z2.object({
|
|
892
|
+
base_model_id: z2.string(),
|
|
893
|
+
global: z2.string().optional(),
|
|
894
|
+
us: z2.string().optional(),
|
|
895
|
+
eu: z2.string().optional(),
|
|
896
|
+
jp: z2.string().optional(),
|
|
897
|
+
apac: z2.string().optional(),
|
|
898
|
+
/**
|
|
899
|
+
* Deprecated location for {@link ModelInfoSchema}'s top-level
|
|
900
|
+
* `claude_cli_context_selector`. Retained so existing/consumer configs
|
|
901
|
+
* keep working; new entries declare the top-level field instead.
|
|
902
|
+
*/
|
|
903
|
+
claude_cli_context_selector: z2.literal("[1m]").optional()
|
|
904
|
+
}).strict().optional(),
|
|
905
|
+
thinking: z2.object({
|
|
906
|
+
supported: z2.boolean().optional(),
|
|
907
|
+
adaptive: z2.boolean().optional(),
|
|
908
|
+
budget_tokens_supported: z2.boolean().optional(),
|
|
909
|
+
min_budget_tokens: z2.number().int().optional(),
|
|
910
|
+
default_budget_tokens: z2.number().int().optional(),
|
|
911
|
+
max_budget_tokens: z2.number().int().optional()
|
|
912
|
+
}).optional(),
|
|
913
|
+
reasoning_effort_levels: z2.array(z2.string()).optional(),
|
|
914
|
+
// Templated CLI provider support (Phase 1)
|
|
915
|
+
canonical_id: z2.string().optional(),
|
|
916
|
+
// Stable identity for comparisons (e.g., "claude-sonnet-4-5")
|
|
917
|
+
routing_id: z2.string().optional(),
|
|
918
|
+
// Actual ID passed to CLI (e.g., "anthropic/claude-sonnet-4-5")
|
|
919
|
+
notes: z2.string().optional(),
|
|
920
|
+
deprecation: z2.record(z2.string(), z2.unknown()).optional(),
|
|
921
|
+
_model_update: z2.record(z2.string(), z2.unknown()).optional()
|
|
922
|
+
}).strict();
|
|
923
|
+
var ModelAccessClassSchema = z2.enum(["first_party_pool", "premium_pool"]);
|
|
924
|
+
var ModelAccessConfigSchema = z2.object({
|
|
925
|
+
default: ModelAccessClassSchema,
|
|
926
|
+
overrides: z2.record(z2.string().trim().min(1), ModelAccessClassSchema).default({})
|
|
927
|
+
}).strict();
|
|
928
|
+
var ModelsConfigSchema = z2.object({
|
|
929
|
+
default: z2.string().trim().min(1),
|
|
930
|
+
default_reasoning_effort: z2.string().optional(),
|
|
931
|
+
roles: z2.record(z2.string().trim().min(1), z2.string().trim().min(1)).optional().default({}),
|
|
932
|
+
allowed_patterns: z2.array(z2.string()),
|
|
933
|
+
mappings: z2.record(z2.string().trim().min(1), z2.string().trim().min(1)),
|
|
934
|
+
// Zod v4: explicit key and value schemas
|
|
935
|
+
available: z2.array(ModelInfoSchema),
|
|
936
|
+
/**
|
|
937
|
+
* Admission policy for the exact-model invoke bridge.
|
|
938
|
+
*
|
|
939
|
+
* A provider whose `allowed_patterns` deliberately admit bounded future model-id
|
|
940
|
+
* SYNTAX (so a newly released id works before the catalog is refreshed) accepts ids
|
|
941
|
+
* that are well-formed but not in `available`. That is correct for ordinary
|
|
942
|
+
* execution and wrong for an exact pin, where a typo should be rejected before
|
|
943
|
+
* spawn rather than handed to the CLI.
|
|
944
|
+
*
|
|
945
|
+
* Set this on such a provider to make the exact bridge additionally require the
|
|
946
|
+
* resolved id to be present in the effective inventory. Providers that do not admit
|
|
947
|
+
* syntax-only ids leave it false and keep their declared resolution contract.
|
|
948
|
+
*
|
|
949
|
+
* This is model-resolution admission policy, NOT a runtime CLI quirk, so it belongs
|
|
950
|
+
* here rather than behind `getProviderRuntimeQuirks()`.
|
|
951
|
+
*/
|
|
952
|
+
exact_invoke_requires_inventory: z2.boolean().optional().default(false),
|
|
953
|
+
access: ModelAccessConfigSchema.optional(),
|
|
954
|
+
discovery: ModelsDiscoverySchema.optional()
|
|
955
|
+
}).strict().superRefine((models, ctx) => {
|
|
956
|
+
if (!models.access) return;
|
|
957
|
+
const availableIds = new Set(models.available.map((model) => model.id));
|
|
958
|
+
for (const modelId of Object.keys(models.access.overrides)) {
|
|
959
|
+
if (!availableIds.has(modelId)) {
|
|
960
|
+
ctx.addIssue({
|
|
961
|
+
code: z2.ZodIssueCode.custom,
|
|
962
|
+
message: `models.access override references unavailable model: ${modelId}`,
|
|
963
|
+
path: ["access", "overrides", modelId]
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
});
|
|
968
|
+
var TemplatedModelsConfigSchema = z2.object({
|
|
969
|
+
default: z2.string().trim().min(1),
|
|
970
|
+
default_reasoning_effort: z2.string().optional(),
|
|
971
|
+
roles: z2.record(z2.string().trim().min(1), z2.string().trim().min(1)).optional().default({}),
|
|
972
|
+
allowed_patterns: z2.array(z2.string()).default([".*"]),
|
|
973
|
+
mappings: z2.record(z2.string().trim().min(1), z2.string().trim().min(1)).default({}),
|
|
974
|
+
available: z2.array(ModelInfoSchema).default([]),
|
|
975
|
+
/**
|
|
976
|
+
* See `ModelsConfigSchema.exact_invoke_requires_inventory`. Declared here too so the
|
|
977
|
+
* flag is readable off the `ProviderConfig` union without narrowing to the native
|
|
978
|
+
* branch first. It matters at least as much for templated providers, whose
|
|
979
|
+
* `allowed_patterns` default to `['.*']` and therefore admit any syntax.
|
|
980
|
+
*/
|
|
981
|
+
exact_invoke_requires_inventory: z2.boolean().optional().default(false),
|
|
982
|
+
access: ModelAccessConfigSchema.optional(),
|
|
983
|
+
discovery: ModelsDiscoverySchema.optional()
|
|
984
|
+
}).strict().superRefine((models, ctx) => {
|
|
985
|
+
if (!models.access) return;
|
|
986
|
+
const availableIds = new Set(models.available.map((model) => model.id));
|
|
987
|
+
for (const modelId of Object.keys(models.access.overrides)) {
|
|
988
|
+
if (!availableIds.has(modelId)) {
|
|
989
|
+
ctx.addIssue({
|
|
990
|
+
code: z2.ZodIssueCode.custom,
|
|
991
|
+
message: `models.access override references unavailable model: ${modelId}`,
|
|
992
|
+
path: ["access", "overrides", modelId]
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
});
|
|
997
|
+
var TuiConversationOperationSchema = z2.enum(["start", "load/resume", "prompt", "cancel"]);
|
|
998
|
+
var TuiConversationCapabilityConfigSchema = z2.object({
|
|
999
|
+
operations: z2.array(TuiConversationOperationSchema).min(1),
|
|
1000
|
+
output: z2.enum(["streaming", "buffered"]),
|
|
1001
|
+
read_only: z2.enum(["enforced", "unproven"]),
|
|
1002
|
+
qualification: z2.enum(["version", "handshake"]).optional()
|
|
1003
|
+
}).strict();
|
|
1004
|
+
var CapabilitiesConfigSchema = z2.object({
|
|
1005
|
+
streaming: z2.boolean(),
|
|
1006
|
+
tool_use: z2.boolean(),
|
|
1007
|
+
vision: z2.boolean(),
|
|
1008
|
+
function_calling: z2.boolean(),
|
|
1009
|
+
// Provider has some historically tracked subagent-capable behavior.
|
|
1010
|
+
sub_agents: z2.boolean().optional().default(false),
|
|
1011
|
+
// Poetic can invoke provider-native subagents for `run --subagents`.
|
|
1012
|
+
provider_native_subagents: z2.boolean().optional().default(false),
|
|
1013
|
+
// Provider-level execution capabilities (narrow matrix — model-level traits are out of scope)
|
|
1014
|
+
// requires_pty: provider CLI needs a PTY for headless runs
|
|
1015
|
+
requires_pty: z2.boolean().optional(),
|
|
1016
|
+
// owns_rate_limit_token: provider enforces its own rate limit / handles 429 internally
|
|
1017
|
+
owns_rate_limit_token: z2.boolean().optional(),
|
|
1018
|
+
// supports_api_judge: provider has a non-CLI API channel usable by the judge/synthesis path
|
|
1019
|
+
supports_api_judge: z2.boolean().optional(),
|
|
1020
|
+
// supports_tui_agent_actions: provider may propose bounded TUI agent actions
|
|
1021
|
+
supports_tui_agent_actions: z2.boolean().optional(),
|
|
1022
|
+
// supports_ask_consult: provider has a tested read-only one-shot consultation path
|
|
1023
|
+
supports_ask_consult: z2.boolean().optional(),
|
|
1024
|
+
// requires_sandbox_interlock: provider must verify outer sandbox before spawning
|
|
1025
|
+
requires_sandbox_interlock: z2.boolean().optional(),
|
|
1026
|
+
// native_model_fallback: provider CLI supports a native fallback-model flag
|
|
1027
|
+
// (e.g. Claude's --fallback-model). Gates role-candidate `fallbackModelRole`.
|
|
1028
|
+
native_model_fallback: z2.boolean().optional(),
|
|
1029
|
+
// Persistent TUI conversation support is a cohesive adapter contract rather
|
|
1030
|
+
// than a set of independent booleans. Eligibility still requires runtime
|
|
1031
|
+
// readiness, qualification (when declared), and enforced read-only posture.
|
|
1032
|
+
tui_conversation: TuiConversationCapabilityConfigSchema.optional()
|
|
1033
|
+
}).strict();
|
|
1034
|
+
var TemplatedCapabilitiesConfigSchema = z2.object({
|
|
1035
|
+
streaming: z2.boolean().default(false),
|
|
1036
|
+
tool_use: z2.boolean().default(false),
|
|
1037
|
+
vision: z2.boolean().default(false),
|
|
1038
|
+
function_calling: z2.boolean().default(false),
|
|
1039
|
+
// Provider has some historically tracked subagent-capable behavior.
|
|
1040
|
+
sub_agents: z2.boolean().default(false),
|
|
1041
|
+
// Poetic can invoke provider-native subagents for `run --subagents`.
|
|
1042
|
+
provider_native_subagents: z2.boolean().default(false),
|
|
1043
|
+
// Provider-level execution capabilities (narrow matrix — model-level traits are out of scope)
|
|
1044
|
+
requires_pty: z2.boolean().optional(),
|
|
1045
|
+
owns_rate_limit_token: z2.boolean().optional(),
|
|
1046
|
+
supports_api_judge: z2.boolean().optional(),
|
|
1047
|
+
supports_tui_agent_actions: z2.boolean().optional(),
|
|
1048
|
+
supports_ask_consult: z2.boolean().optional(),
|
|
1049
|
+
requires_sandbox_interlock: z2.boolean().optional(),
|
|
1050
|
+
native_model_fallback: z2.boolean().optional(),
|
|
1051
|
+
tui_conversation: TuiConversationCapabilityConfigSchema.optional()
|
|
1052
|
+
}).strict().default({
|
|
1053
|
+
streaming: false,
|
|
1054
|
+
tool_use: false,
|
|
1055
|
+
vision: false,
|
|
1056
|
+
function_calling: false,
|
|
1057
|
+
sub_agents: false,
|
|
1058
|
+
provider_native_subagents: false
|
|
1059
|
+
});
|
|
1060
|
+
var BotIdentityConfigSchema = z2.object({
|
|
1061
|
+
display_name: z2.string(),
|
|
1062
|
+
usernames: z2.array(z2.string())
|
|
1063
|
+
}).strict();
|
|
1064
|
+
var EnvConfigSchema = z2.record(z2.string(), z2.string());
|
|
1065
|
+
var ModelPricingSchema = z2.object({
|
|
1066
|
+
// Prices may be stored as strings for precision/deterministic diffs (e.g. "3.00").
|
|
1067
|
+
// Normalize to numbers at load time for runtime cost calculation.
|
|
1068
|
+
input_per_1m_tokens: z2.union([z2.number(), z2.string()]).transform((value) => typeof value === "string" ? Number(value) : value).pipe(z2.number().min(0)).optional(),
|
|
1069
|
+
output_per_1m_tokens: z2.union([z2.number(), z2.string()]).transform((value) => typeof value === "string" ? Number(value) : value).pipe(z2.number().min(0)).optional(),
|
|
1070
|
+
cache_read_per_1m_tokens: z2.union([z2.number(), z2.string()]).transform((value) => typeof value === "string" ? Number(value) : value).pipe(z2.number().min(0)).optional(),
|
|
1071
|
+
cache_write_per_1m_tokens: z2.union([z2.number(), z2.string()]).transform((value) => typeof value === "string" ? Number(value) : value).pipe(z2.number().min(0)).optional(),
|
|
1072
|
+
input_per_1k_tokens: z2.union([z2.number(), z2.string()]).transform((value) => typeof value === "string" ? Number(value) : value).pipe(z2.number().min(0)).optional(),
|
|
1073
|
+
output_per_1k_tokens: z2.union([z2.number(), z2.string()]).transform((value) => typeof value === "string" ? Number(value) : value).pipe(z2.number().min(0)).optional(),
|
|
1074
|
+
base_rate_per_1k_tokens: z2.union([z2.number(), z2.string()]).transform((value) => typeof value === "string" ? Number(value) : value).pipe(z2.number().min(0)).optional(),
|
|
1075
|
+
premium_multiplier: z2.union([z2.number(), z2.string()]).transform((value) => typeof value === "string" ? Number(value) : value).pipe(z2.number().min(0)).optional(),
|
|
1076
|
+
context_window: z2.number().int().optional(),
|
|
1077
|
+
long_context_pricing: LongContextPricingSchema.optional(),
|
|
1078
|
+
features: z2.record(z2.string(), z2.boolean()).optional(),
|
|
1079
|
+
// Telemetry-only placeholder: pricing is intentionally absent and
|
|
1080
|
+
// missing-pricing telemetry errors log at debug instead of warn.
|
|
1081
|
+
non_metered: z2.boolean().optional(),
|
|
1082
|
+
notes: z2.string().optional(),
|
|
1083
|
+
last_updated: DateLikeStringSchema.optional(),
|
|
1084
|
+
_meta: z2.record(z2.string(), z2.unknown()).optional()
|
|
1085
|
+
}).strict();
|
|
1086
|
+
var ToolPricingSchema = z2.object({
|
|
1087
|
+
cost_per_request: z2.number().min(0).optional(),
|
|
1088
|
+
cost_per_read_1m_tokens: z2.number().min(0).optional(),
|
|
1089
|
+
cost_per_write_1m_tokens: z2.number().min(0).optional(),
|
|
1090
|
+
unit: z2.string().optional(),
|
|
1091
|
+
notes: z2.string().optional(),
|
|
1092
|
+
available_in: z2.array(z2.string()).optional()
|
|
1093
|
+
}).strict();
|
|
1094
|
+
var SubscriptionPricingSchema = z2.object({
|
|
1095
|
+
monthly_cost: z2.number().min(0).optional(),
|
|
1096
|
+
included_credits: z2.number().min(0).optional(),
|
|
1097
|
+
overage_rate_per_credit: z2.number().min(0).optional(),
|
|
1098
|
+
individual_monthly: z2.number().min(0).optional(),
|
|
1099
|
+
business_monthly_per_user: z2.number().min(0).optional(),
|
|
1100
|
+
enterprise_monthly_per_user: z2.number().min(0).optional()
|
|
1101
|
+
}).strict();
|
|
1102
|
+
var InfrastructurePricingSchema = z2.object({
|
|
1103
|
+
cloud_execution_per_minute: z2.number().min(0).optional(),
|
|
1104
|
+
premium_execution_per_minute: z2.number().min(0).optional(),
|
|
1105
|
+
proxy_routing_per_request: z2.number().min(0).optional(),
|
|
1106
|
+
notes: z2.string().optional()
|
|
1107
|
+
}).strict();
|
|
1108
|
+
var ProviderPricingSchema = z2.object({
|
|
1109
|
+
billing_mode: z2.enum(["metered", "subscription", "hybrid"]),
|
|
1110
|
+
currency: z2.string(),
|
|
1111
|
+
last_updated: DateLikeStringSchema.optional(),
|
|
1112
|
+
notes: z2.string().optional(),
|
|
1113
|
+
exchange_rate_note: z2.string().optional(),
|
|
1114
|
+
models: z2.record(z2.string(), ModelPricingSchema).optional(),
|
|
1115
|
+
tools: z2.record(z2.string(), ToolPricingSchema).optional(),
|
|
1116
|
+
subscription: SubscriptionPricingSchema.optional(),
|
|
1117
|
+
infrastructure: InfrastructurePricingSchema.optional(),
|
|
1118
|
+
features: z2.record(z2.string(), z2.unknown()).optional(),
|
|
1119
|
+
_meta: z2.record(z2.string(), z2.unknown()).optional()
|
|
1120
|
+
}).strict();
|
|
1121
|
+
var RefreshStrategyConfigSchema = z2.discriminatedUnion("kind", [
|
|
1122
|
+
z2.object({
|
|
1123
|
+
kind: z2.literal("direct"),
|
|
1124
|
+
// Deterministic models API to poll; absent = doc-poll only (e.g. xAI).
|
|
1125
|
+
models_api: z2.enum(["anthropic", "openai", "google"]).optional(),
|
|
1126
|
+
doc_poll: z2.boolean(),
|
|
1127
|
+
cli_inventory: z2.enum(["cursor", "grok"]).optional()
|
|
1128
|
+
}).strict(),
|
|
1129
|
+
z2.object({ kind: z2.literal("aggregator") }).strict(),
|
|
1130
|
+
z2.object({
|
|
1131
|
+
kind: z2.literal("static"),
|
|
1132
|
+
reason: z2.string().trim().min(1).optional(),
|
|
1133
|
+
cli_inventory: z2.enum(["cursor", "grok"]).optional()
|
|
1134
|
+
}).strict()
|
|
1135
|
+
]);
|
|
1136
|
+
var DefaultPricingSchema = z2.object({
|
|
1137
|
+
billing_mode: z2.string(),
|
|
1138
|
+
currency: z2.string(),
|
|
1139
|
+
unit: z2.string()
|
|
1140
|
+
}).strict();
|
|
1141
|
+
var ConcurrencyConfigSchema = z2.object({
|
|
1142
|
+
max: z2.number().int().min(1),
|
|
1143
|
+
hybrid_batching: z2.boolean().optional().default(false),
|
|
1144
|
+
rationale: z2.string().trim().min(1)
|
|
1145
|
+
}).strict();
|
|
1146
|
+
var RouteConfigSchema = z2.object({
|
|
1147
|
+
// Environment variables to inject (e.g., API keys, endpoints)
|
|
1148
|
+
env: z2.record(z2.string(), z2.string()).optional(),
|
|
1149
|
+
// Auth commands to run before execution.
|
|
1150
|
+
//
|
|
1151
|
+
// SECURITY: Prefer argv form (auth_check_argv/auth_command_argv). String form is
|
|
1152
|
+
// treated as guidance-only and is not executed by Poetic.
|
|
1153
|
+
auth_check: z2.string().optional(),
|
|
1154
|
+
auth_command: z2.string().optional(),
|
|
1155
|
+
auth_clear: z2.string().optional(),
|
|
1156
|
+
auth_check_argv: z2.array(z2.string()).optional(),
|
|
1157
|
+
auth_command_argv: z2.array(z2.string()).optional(),
|
|
1158
|
+
auth_clear_argv: z2.array(z2.string()).optional(),
|
|
1159
|
+
auth_probe: CommandProbeSchema.optional(),
|
|
1160
|
+
// Model ID transform function name (if custom logic needed)
|
|
1161
|
+
model_transform: z2.string().optional()
|
|
1162
|
+
}).strict();
|
|
1163
|
+
var WorkspaceEditsConfigSchema = z2.object({
|
|
1164
|
+
// Detection mode: 'passthrough' (git-only), 'structured' (JSONL), or 'text-only' (analysis mode)
|
|
1165
|
+
mode: z2.enum(["passthrough", "structured", "text-only"]),
|
|
1166
|
+
// Whether to inject JSONL format instructions into prompts
|
|
1167
|
+
inject_jsonl: z2.boolean().optional(),
|
|
1168
|
+
// Whether to enforce FILE: specification in prompts
|
|
1169
|
+
enforce_file_targets: z2.boolean().optional()
|
|
1170
|
+
}).strict();
|
|
1171
|
+
var GenerationConfigSchema = z2.object({
|
|
1172
|
+
// Temperature controls output randomness (0.0 = deterministic, 1.0+ = creative)
|
|
1173
|
+
// For code generation, 0.2-0.4 is recommended for more deterministic output
|
|
1174
|
+
temperature: z2.number().min(0).max(2).optional(),
|
|
1175
|
+
// Nucleus sampling threshold (0.0-1.0)
|
|
1176
|
+
top_p: z2.number().min(0).max(1).optional(),
|
|
1177
|
+
// Top-k sampling (limits token choices)
|
|
1178
|
+
top_k: z2.number().int().min(1).optional(),
|
|
1179
|
+
// Maximum output tokens
|
|
1180
|
+
max_output_tokens: z2.number().int().min(1).optional()
|
|
1181
|
+
}).strict();
|
|
1182
|
+
var TaskSettingsSchema = z2.record(
|
|
1183
|
+
z2.string(),
|
|
1184
|
+
z2.object({
|
|
1185
|
+
temperature: z2.number().min(0).max(2).optional(),
|
|
1186
|
+
top_p: z2.number().min(0).max(1).optional(),
|
|
1187
|
+
top_k: z2.number().int().min(1).optional(),
|
|
1188
|
+
reasoning_effort: z2.preprocess((value) => {
|
|
1189
|
+
if (value === void 0 || value === null) return void 0;
|
|
1190
|
+
const normalized = normalizeReasoningEffortInput(value);
|
|
1191
|
+
return normalized ?? value;
|
|
1192
|
+
}, z2.enum(["low", "medium", "high", "xhigh", "max"]).optional()),
|
|
1193
|
+
thinking_budget: z2.number().int().min(1).optional()
|
|
1194
|
+
}).strict()
|
|
1195
|
+
).optional();
|
|
1196
|
+
var PluginVerifySchema = z2.object({
|
|
1197
|
+
// Command to run for verification (e.g., "provider-plugin --version")
|
|
1198
|
+
command: z2.string().optional(),
|
|
1199
|
+
// File path that should exist (e.g., "~/.config/plugin/config.json")
|
|
1200
|
+
file: z2.string().optional(),
|
|
1201
|
+
// Pattern to match in command output
|
|
1202
|
+
pattern: z2.string().optional()
|
|
1203
|
+
}).strict();
|
|
1204
|
+
var PluginConfigureStepSchema = z2.object({
|
|
1205
|
+
// Description of what this step does
|
|
1206
|
+
description: z2.string(),
|
|
1207
|
+
// Command to run (if automated)
|
|
1208
|
+
command: z2.string().optional(),
|
|
1209
|
+
// Manual instructions (if user action required)
|
|
1210
|
+
instructions: z2.string().optional()
|
|
1211
|
+
}).strict();
|
|
1212
|
+
var RequirementSchema = z2.union([
|
|
1213
|
+
z2.object({ provider: z2.string() }).strict(),
|
|
1214
|
+
z2.object({ plugin: z2.string() }).strict(),
|
|
1215
|
+
z2.object({ binary: z2.string() }).strict()
|
|
1216
|
+
]);
|
|
1217
|
+
var PluginSchema = z2.object({
|
|
1218
|
+
// Unique identifier (e.g., "provider-plugin")
|
|
1219
|
+
id: z2.string(),
|
|
1220
|
+
// Display name (e.g., "Provider Plugin")
|
|
1221
|
+
name: z2.string(),
|
|
1222
|
+
// Human-readable description
|
|
1223
|
+
description: z2.string(),
|
|
1224
|
+
// Plugin type (free-form: 'auth', 'tools', 'slash', 'agents', etc.)
|
|
1225
|
+
type: z2.string(),
|
|
1226
|
+
// Installation command
|
|
1227
|
+
install_command: z2.string(),
|
|
1228
|
+
// Installation method
|
|
1229
|
+
install_method: z2.enum(["npm", "brew", "pipx", "curl", "manual"]),
|
|
1230
|
+
// Risk level for user confirmation
|
|
1231
|
+
risk_level: z2.enum(["safe", "needs-confirmation"]),
|
|
1232
|
+
// Verification checks
|
|
1233
|
+
verify: PluginVerifySchema.optional(),
|
|
1234
|
+
// Configuration steps (optional)
|
|
1235
|
+
configure: z2.array(PluginConfigureStepSchema).optional(),
|
|
1236
|
+
// Plugin dependencies (optional)
|
|
1237
|
+
requires: z2.array(RequirementSchema).optional()
|
|
1238
|
+
}).strict();
|
|
1239
|
+
var ProviderOptionSchema = z2.object({
|
|
1240
|
+
// Option type
|
|
1241
|
+
type: z2.enum(["enum", "string", "bool"]),
|
|
1242
|
+
// Allowed values (for enum type)
|
|
1243
|
+
allowed: z2.array(z2.string()).optional(),
|
|
1244
|
+
// Default value
|
|
1245
|
+
default: z2.union([z2.string(), z2.boolean()]),
|
|
1246
|
+
// Description (shown in wizard)
|
|
1247
|
+
description: z2.string()
|
|
1248
|
+
}).strict();
|
|
1249
|
+
var ProviderOptionsSchema = z2.record(z2.string(), ProviderOptionSchema);
|
|
1250
|
+
var ConditionalRequiresSchema = z2.record(z2.string(), z2.array(RequirementSchema));
|
|
1251
|
+
var ProviderRequiresSchema = z2.object({
|
|
1252
|
+
// Always-required dependencies
|
|
1253
|
+
requires: z2.array(RequirementSchema).optional(),
|
|
1254
|
+
// Conditionally-required dependencies based on option values
|
|
1255
|
+
requires_if: ConditionalRequiresSchema.optional()
|
|
1256
|
+
}).strict();
|
|
1257
|
+
var ApiConfigSchema = z2.object({
|
|
1258
|
+
/** API base URL (host only, e.g., "https://api.anthropic.com"). */
|
|
1259
|
+
base_url: z2.url(),
|
|
1260
|
+
/** Environment variable name containing the API key. */
|
|
1261
|
+
api_key_env_var: z2.string(),
|
|
1262
|
+
/** Whether to use streaming responses (default: true). */
|
|
1263
|
+
stream: z2.boolean().optional().default(true),
|
|
1264
|
+
/** Additional HTTP headers to send with requests. */
|
|
1265
|
+
headers: z2.record(z2.string(), z2.string()).optional(),
|
|
1266
|
+
/** Max output tokens per API call. */
|
|
1267
|
+
max_tokens: z2.number().int().positive().optional(),
|
|
1268
|
+
/** Max tool-use iterations in the agentic loop (default: 50). */
|
|
1269
|
+
max_tool_iterations: z2.number().int().min(1).max(200).optional().default(50),
|
|
1270
|
+
/** Timeout per individual tool execution in ms (default: 30000). */
|
|
1271
|
+
per_tool_timeout_ms: z2.number().int().min(1e3).optional().default(3e4)
|
|
1272
|
+
}).strict().optional();
|
|
1273
|
+
var TemplatedCLIExecutionSchema = z2.object({
|
|
1274
|
+
// Base command arguments (before prompt)
|
|
1275
|
+
args: z2.array(z2.string()),
|
|
1276
|
+
// Command-line flags (e.g., {"--quiet": true, "--cwd": "{{workspace}}"})
|
|
1277
|
+
flags: z2.record(z2.string(), z2.union([z2.boolean(), z2.string()])).optional(),
|
|
1278
|
+
// Prompt placement: 'positional' (in args array) or 'stdin'
|
|
1279
|
+
prompt_placement: z2.enum(["positional", "stdin"]),
|
|
1280
|
+
// Whether to add "--" before the prompt when using positional prompt placement.
|
|
1281
|
+
// Defaults to true (safer); set false for CLIs that don't support "--".
|
|
1282
|
+
double_dash_before_prompt: z2.boolean().optional(),
|
|
1283
|
+
// Whether stdin is supported as fallback
|
|
1284
|
+
stdin_fallback: z2.boolean().optional(),
|
|
1285
|
+
// Template variables available for interpolation
|
|
1286
|
+
// (e.g., {{prompt}}, {{model.routing_id}}, {{workspace}})
|
|
1287
|
+
template_vars: z2.array(z2.string()).optional()
|
|
1288
|
+
}).strict();
|
|
1289
|
+
var NativeProviderConfigSchema = z2.object({
|
|
1290
|
+
// Basic metadata
|
|
1291
|
+
id: z2.string(),
|
|
1292
|
+
name: z2.string(),
|
|
1293
|
+
display_name: z2.string(),
|
|
1294
|
+
description: z2.string(),
|
|
1295
|
+
vendor: z2.string(),
|
|
1296
|
+
enabled: z2.boolean(),
|
|
1297
|
+
experimental: z2.boolean(),
|
|
1298
|
+
release_status: ProviderReleaseStatusSchema.optional(),
|
|
1299
|
+
order: z2.number().int(),
|
|
1300
|
+
// Provider type and transport
|
|
1301
|
+
type: z2.enum(["cli", "api", "cloud_cli", "cli_wrapper"]),
|
|
1302
|
+
transport: z2.enum(["cli", "api", "hybrid"]),
|
|
1303
|
+
channels: z2.array(z2.string()),
|
|
1304
|
+
// CLI configuration
|
|
1305
|
+
cli: CLIConfigSchema,
|
|
1306
|
+
// API transport configuration (optional, for direct API inference)
|
|
1307
|
+
api: ApiConfigSchema,
|
|
1308
|
+
// Authentication
|
|
1309
|
+
auth: AuthConfigSchema,
|
|
1310
|
+
// Models
|
|
1311
|
+
models: ModelsConfigSchema,
|
|
1312
|
+
// Capabilities
|
|
1313
|
+
capabilities: CapabilitiesConfigSchema,
|
|
1314
|
+
// Performance
|
|
1315
|
+
concurrency_hint: z2.enum(["low", "medium", "high"]),
|
|
1316
|
+
concurrency: ConcurrencyConfigSchema.optional(),
|
|
1317
|
+
// Timeouts
|
|
1318
|
+
timeout_ms: z2.number().int().min(1),
|
|
1319
|
+
health_check_timeout_ms: z2.number().int().min(1).optional(),
|
|
1320
|
+
// Memory management
|
|
1321
|
+
memory: MemoryConfigSchema,
|
|
1322
|
+
// Polling (optional, for cloud providers)
|
|
1323
|
+
polling: PollingConfigSchema.optional(),
|
|
1324
|
+
// Bot identity (optional, for cloud providers)
|
|
1325
|
+
bot_identity: BotIdentityConfigSchema.optional(),
|
|
1326
|
+
// Environment variables
|
|
1327
|
+
env: EnvConfigSchema,
|
|
1328
|
+
// Retry and circuit breaker (optional overrides)
|
|
1329
|
+
retry: RetryConfigSchema.optional(),
|
|
1330
|
+
circuit_breaker: CircuitBreakerConfigSchema.optional(),
|
|
1331
|
+
// Rate limits (optional overrides, new in v2.1)
|
|
1332
|
+
rate_limits: RateLimitsConfigSchema.optional(),
|
|
1333
|
+
// Pricing (optional, new in v2.0)
|
|
1334
|
+
pricing: ProviderPricingSchema.optional(),
|
|
1335
|
+
// Refresh strategy for `poetic provider refresh` (optional; providers
|
|
1336
|
+
// without a declaration are treated as static by the refresh dispatcher).
|
|
1337
|
+
refresh_strategy: RefreshStrategyConfigSchema.optional(),
|
|
1338
|
+
// Engine type. 'templated_cli' is DEPRECATED: the templated CLI engine was
|
|
1339
|
+
// removed (2026-06) and providers declaring it are no longer registered —
|
|
1340
|
+
// the registry emits a TMPL-001 warning instead. The value stays in the
|
|
1341
|
+
// schema only so user overlays still validate and the project-config
|
|
1342
|
+
// trust-gating security checks below keep rejecting untrusted templated
|
|
1343
|
+
// providers explicitly rather than failing on an unknown enum value.
|
|
1344
|
+
engine: z2.enum(["native", "templated_cli"]).optional().default("native"),
|
|
1345
|
+
// Templated CLI execution config (deprecated with engine=templated_cli)
|
|
1346
|
+
exec: TemplatedCLIExecutionSchema.optional(),
|
|
1347
|
+
// Route configuration (for model ID transforms and env injection)
|
|
1348
|
+
route_id: z2.string().optional(),
|
|
1349
|
+
// Reference to named route (future: top-level routes: section)
|
|
1350
|
+
route: RouteConfigSchema.optional(),
|
|
1351
|
+
// Inline route override
|
|
1352
|
+
// Workspace edit detection strategy
|
|
1353
|
+
workspace_edits: WorkspaceEditsConfigSchema.optional(),
|
|
1354
|
+
// Generation parameters (temperature, topP, etc.)
|
|
1355
|
+
generation: GenerationConfigSchema.optional(),
|
|
1356
|
+
// Task-type-aware generation settings (overrides generation defaults)
|
|
1357
|
+
task_settings: TaskSettingsSchema,
|
|
1358
|
+
// Binary allowlist for security (only used if engine=templated_cli)
|
|
1359
|
+
allow_unsafe_binary: z2.boolean().optional().default(false),
|
|
1360
|
+
// Explicit opt-in for non-allowlisted binaries
|
|
1361
|
+
// Plugin system (generic, any provider)
|
|
1362
|
+
plugins: z2.array(PluginSchema).optional(),
|
|
1363
|
+
// Provider options (generic, any provider)
|
|
1364
|
+
options: ProviderOptionsSchema.optional(),
|
|
1365
|
+
// Dependency management (generic, any provider)
|
|
1366
|
+
requires: z2.array(RequirementSchema).optional(),
|
|
1367
|
+
requires_if: ConditionalRequiresSchema.optional()
|
|
1368
|
+
}).strict();
|
|
1369
|
+
var TemplatedProviderConfigSchema = z2.object({
|
|
1370
|
+
// Basic metadata
|
|
1371
|
+
id: z2.string(),
|
|
1372
|
+
name: z2.string(),
|
|
1373
|
+
display_name: z2.string().optional().default(""),
|
|
1374
|
+
description: z2.string().optional().default(""),
|
|
1375
|
+
vendor: z2.string().optional().default("custom"),
|
|
1376
|
+
enabled: z2.boolean().optional().default(true),
|
|
1377
|
+
experimental: z2.boolean().optional().default(false),
|
|
1378
|
+
release_status: ProviderReleaseStatusSchema.optional(),
|
|
1379
|
+
order: z2.number().int().optional().default(99),
|
|
1380
|
+
// Provider type and transport
|
|
1381
|
+
type: z2.enum(["cli", "api", "cloud_cli", "cli_wrapper"]).optional().default("cli_wrapper"),
|
|
1382
|
+
transport: z2.enum(["cli", "api", "hybrid"]).optional().default("cli"),
|
|
1383
|
+
channels: z2.array(z2.string()).optional().default(["cli"]),
|
|
1384
|
+
// CLI configuration
|
|
1385
|
+
cli: CLIConfigSchema,
|
|
1386
|
+
// API transport configuration (optional, for direct API inference)
|
|
1387
|
+
api: ApiConfigSchema,
|
|
1388
|
+
// Authentication
|
|
1389
|
+
auth: TemplatedAuthConfigSchema,
|
|
1390
|
+
// Models
|
|
1391
|
+
models: TemplatedModelsConfigSchema,
|
|
1392
|
+
// Capabilities
|
|
1393
|
+
capabilities: TemplatedCapabilitiesConfigSchema,
|
|
1394
|
+
// Performance
|
|
1395
|
+
concurrency_hint: z2.enum(["low", "medium", "high"]).optional().default("low"),
|
|
1396
|
+
concurrency: ConcurrencyConfigSchema.optional(),
|
|
1397
|
+
// Timeouts
|
|
1398
|
+
timeout_ms: z2.number().int().min(1).optional().default(6e5),
|
|
1399
|
+
health_check_timeout_ms: z2.number().int().min(1).optional(),
|
|
1400
|
+
// Memory management
|
|
1401
|
+
memory: MemoryConfigSchema.default({
|
|
1402
|
+
warn_threshold: 0.85,
|
|
1403
|
+
critical_threshold: 0.9,
|
|
1404
|
+
emergency_threshold: 0.95,
|
|
1405
|
+
max_processes: 3
|
|
1406
|
+
}),
|
|
1407
|
+
// Polling (optional, for cloud providers)
|
|
1408
|
+
polling: PollingConfigSchema.optional(),
|
|
1409
|
+
// Bot identity (optional, for cloud providers)
|
|
1410
|
+
bot_identity: BotIdentityConfigSchema.optional(),
|
|
1411
|
+
// Environment variables
|
|
1412
|
+
env: EnvConfigSchema.default({}),
|
|
1413
|
+
// Retry and circuit breaker (optional overrides)
|
|
1414
|
+
retry: RetryConfigSchema.optional(),
|
|
1415
|
+
circuit_breaker: CircuitBreakerConfigSchema.optional(),
|
|
1416
|
+
// Rate limits (optional overrides)
|
|
1417
|
+
rate_limits: RateLimitsConfigSchema.optional(),
|
|
1418
|
+
// Pricing (optional)
|
|
1419
|
+
pricing: ProviderPricingSchema.optional(),
|
|
1420
|
+
// Engine selection (templated)
|
|
1421
|
+
engine: z2.literal("templated_cli"),
|
|
1422
|
+
// Templated CLI execution config (required)
|
|
1423
|
+
exec: TemplatedCLIExecutionSchema,
|
|
1424
|
+
// Route configuration (optional)
|
|
1425
|
+
route_id: z2.string().optional(),
|
|
1426
|
+
route: RouteConfigSchema.optional(),
|
|
1427
|
+
// Workspace edit detection strategy (optional)
|
|
1428
|
+
workspace_edits: WorkspaceEditsConfigSchema.optional(),
|
|
1429
|
+
// Generation parameters (temperature, topP, etc.)
|
|
1430
|
+
generation: GenerationConfigSchema.optional(),
|
|
1431
|
+
// Task-type-aware generation settings (overrides generation defaults)
|
|
1432
|
+
task_settings: TaskSettingsSchema,
|
|
1433
|
+
// Binary allowlist override
|
|
1434
|
+
allow_unsafe_binary: z2.boolean().optional().default(false),
|
|
1435
|
+
// Plugin system (generic, any provider)
|
|
1436
|
+
plugins: z2.array(PluginSchema).optional(),
|
|
1437
|
+
// Provider options (generic, any provider)
|
|
1438
|
+
options: ProviderOptionsSchema.optional(),
|
|
1439
|
+
// Dependency management (generic, any provider)
|
|
1440
|
+
requires: z2.array(RequirementSchema).optional(),
|
|
1441
|
+
requires_if: ConditionalRequiresSchema.optional()
|
|
1442
|
+
}).strict().transform((provider) => ({
|
|
1443
|
+
...provider,
|
|
1444
|
+
display_name: provider.display_name?.trim() ? provider.display_name : provider.name,
|
|
1445
|
+
description: provider.description ?? ""
|
|
1446
|
+
}));
|
|
1447
|
+
var ProviderConfigSchema = z2.union([
|
|
1448
|
+
TemplatedProviderConfigSchema,
|
|
1449
|
+
NativeProviderConfigSchema
|
|
1450
|
+
]);
|
|
1451
|
+
var DefaultsConfigSchema = z2.object({
|
|
1452
|
+
timeout_ms: z2.number().int().min(1),
|
|
1453
|
+
retry: RetryConfigSchema,
|
|
1454
|
+
circuit_breaker: CircuitBreakerConfigSchema,
|
|
1455
|
+
rate_limits: RateLimitsConfigSchema.optional(),
|
|
1456
|
+
memory: MemoryConfigSchema,
|
|
1457
|
+
polling: PollingConfigSchema,
|
|
1458
|
+
pricing: DefaultPricingSchema.optional()
|
|
1459
|
+
}).strict();
|
|
1460
|
+
var MetadataConfigSchema = z2.object({
|
|
1461
|
+
schema_version: z2.string(),
|
|
1462
|
+
generated_at: DateLikeStringSchema,
|
|
1463
|
+
description: z2.string(),
|
|
1464
|
+
documentation: z2.string(),
|
|
1465
|
+
migration_notes: z2.string().optional(),
|
|
1466
|
+
last_updated: DateLikeStringSchema.optional()
|
|
1467
|
+
}).strict();
|
|
1468
|
+
var ProviderRegistryConfigSchema = z2.object({
|
|
1469
|
+
version: z2.string(),
|
|
1470
|
+
defaults: DefaultsConfigSchema,
|
|
1471
|
+
guidance_profiles: z2.record(z2.string(), z2.unknown()).optional(),
|
|
1472
|
+
judge: z2.record(z2.string(), z2.unknown()).optional(),
|
|
1473
|
+
providers: z2.record(z2.string(), ProviderConfigSchema),
|
|
1474
|
+
metadata: MetadataConfigSchema
|
|
1475
|
+
}).strict();
|
|
1476
|
+
function cloneProviderRegistryValue(value) {
|
|
1477
|
+
return structuredClone(value);
|
|
1478
|
+
}
|
|
1479
|
+
function verifySchemaDefinitions() {
|
|
1480
|
+
const schemas = {
|
|
1481
|
+
RetryConfigSchema,
|
|
1482
|
+
CircuitBreakerConfigSchema,
|
|
1483
|
+
MemoryConfigSchema,
|
|
1484
|
+
PollingConfigSchema,
|
|
1485
|
+
CLIConfigSchema,
|
|
1486
|
+
AuthConfigSchema,
|
|
1487
|
+
ModelInfoSchema,
|
|
1488
|
+
ModelsConfigSchema,
|
|
1489
|
+
TuiConversationCapabilityConfigSchema,
|
|
1490
|
+
CapabilitiesConfigSchema,
|
|
1491
|
+
BotIdentityConfigSchema,
|
|
1492
|
+
EnvConfigSchema,
|
|
1493
|
+
ModelPricingSchema,
|
|
1494
|
+
ToolPricingSchema,
|
|
1495
|
+
SubscriptionPricingSchema,
|
|
1496
|
+
InfrastructurePricingSchema,
|
|
1497
|
+
ProviderPricingSchema,
|
|
1498
|
+
DefaultPricingSchema,
|
|
1499
|
+
PluginVerifySchema,
|
|
1500
|
+
PluginConfigureStepSchema,
|
|
1501
|
+
RequirementSchema,
|
|
1502
|
+
PluginSchema,
|
|
1503
|
+
ProviderOptionSchema,
|
|
1504
|
+
ProviderOptionsSchema,
|
|
1505
|
+
ConditionalRequiresSchema,
|
|
1506
|
+
ProviderRequiresSchema,
|
|
1507
|
+
ProviderConfigSchema,
|
|
1508
|
+
DefaultsConfigSchema,
|
|
1509
|
+
MetadataConfigSchema,
|
|
1510
|
+
ProviderRegistryConfigSchema
|
|
1511
|
+
};
|
|
1512
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
1513
|
+
if (!schema || !("_zod" in schema)) {
|
|
1514
|
+
throw new Error(
|
|
1515
|
+
`Schema ${name} is undefined or invalid. This indicates a schema definition error. Check that all nested schemas in ${name} are properly defined. Common issue: Zod v4 requires z.record(keySchema, valueSchema) with explicit parameters.`
|
|
1516
|
+
);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
verifySchemaDefinitions();
|
|
1521
|
+
var ProviderRegistry = class _ProviderRegistry {
|
|
1522
|
+
static instance = null;
|
|
1523
|
+
static configPath = null;
|
|
1524
|
+
static configSources = [];
|
|
1525
|
+
static cacheKey = null;
|
|
1526
|
+
static cacheMode = null;
|
|
1527
|
+
static cacheProjectRoot = null;
|
|
1528
|
+
constructor() {
|
|
1529
|
+
}
|
|
1530
|
+
static replaceCachedRegistry(config, configPath, cacheKey, cacheMode, projectRoot, configSources = [configPath]) {
|
|
1531
|
+
const replacedExistingCache = _ProviderRegistry.instance !== null && (_ProviderRegistry.configPath !== configPath || _ProviderRegistry.cacheKey !== cacheKey || _ProviderRegistry.cacheMode !== cacheMode);
|
|
1532
|
+
_ProviderRegistry.instance = config;
|
|
1533
|
+
_ProviderRegistry.configPath = configPath;
|
|
1534
|
+
_ProviderRegistry.configSources = [...configSources];
|
|
1535
|
+
_ProviderRegistry.cacheKey = cacheKey;
|
|
1536
|
+
_ProviderRegistry.cacheMode = cacheMode;
|
|
1537
|
+
_ProviderRegistry.cacheProjectRoot = projectRoot;
|
|
1538
|
+
if (replacedExistingCache) {
|
|
1539
|
+
runProviderRegistryReloadInvalidators();
|
|
1540
|
+
}
|
|
1541
|
+
return config;
|
|
1542
|
+
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Load the unified provider registry from YAML
|
|
1545
|
+
*
|
|
1546
|
+
* @param configPath - Path to providers.yaml (defaults to .poetic/config/providers.yaml)
|
|
1547
|
+
* @returns Validated and merged configuration
|
|
1548
|
+
*/
|
|
1549
|
+
static load(configPath, cwd = process.cwd()) {
|
|
1550
|
+
const projectRoot = findProjectRoot(cwd) ?? cwd;
|
|
1551
|
+
configPath = configPath ? resolve3(projectRoot, configPath) : void 0;
|
|
1552
|
+
const envCacheKey = _ProviderRegistry.buildEnvOverrideCacheKey();
|
|
1553
|
+
const requestedCacheKey = _ProviderRegistry.buildCacheKey(configPath, envCacheKey, projectRoot);
|
|
1554
|
+
if (_ProviderRegistry.instance && (_ProviderRegistry.cacheKey === requestedCacheKey || !configPath && _ProviderRegistry.cacheMode === "explicit" && _ProviderRegistry.configPath !== null && _ProviderRegistry.canReuseExplicitCacheForImplicit(
|
|
1555
|
+
_ProviderRegistry.configPath,
|
|
1556
|
+
projectRoot
|
|
1557
|
+
) && _ProviderRegistry.cacheKey === _ProviderRegistry.buildCacheKey(_ProviderRegistry.configPath, envCacheKey, projectRoot))) {
|
|
1558
|
+
return _ProviderRegistry.instance;
|
|
1559
|
+
}
|
|
1560
|
+
const embeddedConfigPaths = getEmbeddedProviderConfigPaths();
|
|
1561
|
+
const isTrustedProjectForTemplatedProviders = () => isTrustedProjectRoot(projectRoot);
|
|
1562
|
+
const projectTrustInstruction = formatProjectTrustInstruction(projectRoot);
|
|
1563
|
+
const loadYamlRawIfExists = (filePath) => {
|
|
1564
|
+
if (!existsSync2(filePath)) return null;
|
|
1565
|
+
try {
|
|
1566
|
+
const rawYaml = readFileSync2(filePath, "utf-8");
|
|
1567
|
+
return yaml.load(rawYaml);
|
|
1568
|
+
} catch (error) {
|
|
1569
|
+
throw new Error(
|
|
1570
|
+
`Failed to load YAML at ${filePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1573
|
+
};
|
|
1574
|
+
const loadEmbeddedRaw = () => {
|
|
1575
|
+
for (const embeddedConfigPath of embeddedConfigPaths) {
|
|
1576
|
+
if (!existsSync2(embeddedConfigPath)) continue;
|
|
1577
|
+
try {
|
|
1578
|
+
const bytes = readFileSync2(embeddedConfigPath);
|
|
1579
|
+
if (embeddedConfigPath.endsWith("catalog.json")) {
|
|
1580
|
+
const digest2 = createHash2("sha256").update(bytes).digest("hex");
|
|
1581
|
+
if (digest2 !== PROVIDER_CATALOG_SHA256) {
|
|
1582
|
+
throw new Error(
|
|
1583
|
+
`Provider catalog digest mismatch: expected ${PROVIDER_CATALOG_SHA256}, received ${digest2}`
|
|
1584
|
+
);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
const raw = yaml.load(bytes.toString("utf8"));
|
|
1588
|
+
if (!raw) continue;
|
|
1589
|
+
return { path: embeddedConfigPath, raw };
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
throw new Error(
|
|
1592
|
+
`Failed to load packaged provider catalog at ${embeddedConfigPath}: ${error instanceof Error ? error.message : String(error)}`
|
|
1593
|
+
);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
return null;
|
|
1597
|
+
};
|
|
1598
|
+
const deepMerge = (base, overlay) => {
|
|
1599
|
+
if (!overlay || typeof overlay !== "object") return base;
|
|
1600
|
+
if (!base || typeof base !== "object") return overlay;
|
|
1601
|
+
const baseObj = base;
|
|
1602
|
+
const overlayObj = overlay;
|
|
1603
|
+
const out = { ...baseObj };
|
|
1604
|
+
for (const [key, overlayValue] of Object.entries(overlayObj)) {
|
|
1605
|
+
const baseValue = baseObj[key];
|
|
1606
|
+
if (key === "providers" && overlayValue && typeof overlayValue === "object" && !Array.isArray(overlayValue)) {
|
|
1607
|
+
const existingProviders = baseValue && typeof baseValue === "object" && !Array.isArray(baseValue) ? baseValue : {};
|
|
1608
|
+
const overlayProviders = overlayValue;
|
|
1609
|
+
const mergedProviders = { ...existingProviders };
|
|
1610
|
+
for (const [providerId, providerOverlay] of Object.entries(overlayProviders)) {
|
|
1611
|
+
const existingProvider = existingProviders[providerId];
|
|
1612
|
+
if (existingProvider && typeof existingProvider === "object" && !Array.isArray(existingProvider) && providerOverlay && typeof providerOverlay === "object" && !Array.isArray(providerOverlay)) {
|
|
1613
|
+
mergedProviders[providerId] = deepMerge(existingProvider, providerOverlay);
|
|
1614
|
+
} else {
|
|
1615
|
+
mergedProviders[providerId] = providerOverlay;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
out.providers = mergedProviders;
|
|
1619
|
+
continue;
|
|
1620
|
+
}
|
|
1621
|
+
if (overlayValue && typeof overlayValue === "object" && !Array.isArray(overlayValue) && !(overlayValue instanceof Date) && baseValue && typeof baseValue === "object" && !Array.isArray(baseValue) && !(baseValue instanceof Date)) {
|
|
1622
|
+
out[key] = deepMerge(baseValue, overlayValue);
|
|
1623
|
+
continue;
|
|
1624
|
+
}
|
|
1625
|
+
out[key] = overlayValue;
|
|
1626
|
+
}
|
|
1627
|
+
return out;
|
|
1628
|
+
};
|
|
1629
|
+
const isFullRegistrySnapshot = (raw, base) => {
|
|
1630
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return false;
|
|
1631
|
+
if (!base || typeof base !== "object" || Array.isArray(base)) return false;
|
|
1632
|
+
const rawObject = raw;
|
|
1633
|
+
const baseObject = base;
|
|
1634
|
+
const rawProviders = rawObject.providers;
|
|
1635
|
+
const baseProviders = baseObject.providers;
|
|
1636
|
+
if (!rawProviders || typeof rawProviders !== "object" || Array.isArray(rawProviders) || !baseProviders || typeof baseProviders !== "object" || Array.isArray(baseProviders)) {
|
|
1637
|
+
return false;
|
|
1638
|
+
}
|
|
1639
|
+
return "version" in rawObject && "defaults" in rawObject && "metadata" in rawObject && Object.keys(rawProviders).length > 0;
|
|
1640
|
+
};
|
|
1641
|
+
const migrateLegacyFullSnapshotOverlay = (raw, base) => {
|
|
1642
|
+
if (!isFullRegistrySnapshot(raw, base)) return raw;
|
|
1643
|
+
const migrated = cloneProviderRegistryValue(raw);
|
|
1644
|
+
const migratedProviders = migrated.providers;
|
|
1645
|
+
const baseProviders = base.providers;
|
|
1646
|
+
for (const [providerId, providerValue] of Object.entries(migratedProviders)) {
|
|
1647
|
+
const baseProviderValue = baseProviders[providerId];
|
|
1648
|
+
if (!baseProviderValue || typeof baseProviderValue !== "object" || Array.isArray(baseProviderValue)) {
|
|
1649
|
+
continue;
|
|
1650
|
+
}
|
|
1651
|
+
if (!providerValue || typeof providerValue !== "object" || Array.isArray(providerValue)) {
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
const provider = providerValue;
|
|
1655
|
+
const modelsValue = provider.models;
|
|
1656
|
+
const baseModelsValue = baseProviderValue.models;
|
|
1657
|
+
if (!modelsValue || typeof modelsValue !== "object" || Array.isArray(modelsValue)) {
|
|
1658
|
+
continue;
|
|
1659
|
+
}
|
|
1660
|
+
if (!baseModelsValue || typeof baseModelsValue !== "object" || Array.isArray(baseModelsValue)) {
|
|
1661
|
+
continue;
|
|
1662
|
+
}
|
|
1663
|
+
const models = modelsValue;
|
|
1664
|
+
const baseModels = baseModelsValue;
|
|
1665
|
+
if (Array.isArray(baseModels.available) && Array.isArray(models.available)) {
|
|
1666
|
+
const availableById = /* @__PURE__ */ new Map();
|
|
1667
|
+
const combinedAvailable = [...baseModels.available, ...models.available];
|
|
1668
|
+
if (combinedAvailable.every(
|
|
1669
|
+
(entry) => entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.id === "string"
|
|
1670
|
+
)) {
|
|
1671
|
+
for (const entry of combinedAvailable) {
|
|
1672
|
+
availableById.set(entry.id, entry);
|
|
1673
|
+
}
|
|
1674
|
+
models.available = [...availableById.values()];
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
if (Array.isArray(baseModels.allowed_patterns) && Array.isArray(models.allowed_patterns) && [...baseModels.allowed_patterns, ...models.allowed_patterns].every(
|
|
1678
|
+
(pattern) => typeof pattern === "string"
|
|
1679
|
+
)) {
|
|
1680
|
+
models.allowed_patterns = [
|
|
1681
|
+
.../* @__PURE__ */ new Set([...baseModels.allowed_patterns, ...models.allowed_patterns])
|
|
1682
|
+
];
|
|
1683
|
+
}
|
|
1684
|
+
for (const key of ["mappings", "roles"]) {
|
|
1685
|
+
const baseRecord = baseModels[key];
|
|
1686
|
+
const overlayRecord = models[key];
|
|
1687
|
+
if (baseRecord && typeof baseRecord === "object" && !Array.isArray(baseRecord) && overlayRecord && typeof overlayRecord === "object" && !Array.isArray(overlayRecord)) {
|
|
1688
|
+
models[key] = {
|
|
1689
|
+
...baseRecord,
|
|
1690
|
+
...overlayRecord
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
return migrated;
|
|
1696
|
+
};
|
|
1697
|
+
const mergeUserAvailableModels = (raw, base) => {
|
|
1698
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return raw;
|
|
1699
|
+
if (!base || typeof base !== "object" || Array.isArray(base)) return raw;
|
|
1700
|
+
const projected = cloneProviderRegistryValue(raw);
|
|
1701
|
+
const projectedProviders = projected.providers;
|
|
1702
|
+
const baseProviders = base.providers;
|
|
1703
|
+
if (!projectedProviders || typeof projectedProviders !== "object" || Array.isArray(projectedProviders) || !baseProviders || typeof baseProviders !== "object" || Array.isArray(baseProviders)) {
|
|
1704
|
+
return projected;
|
|
1705
|
+
}
|
|
1706
|
+
for (const [providerId, providerValue] of Object.entries(
|
|
1707
|
+
projectedProviders
|
|
1708
|
+
)) {
|
|
1709
|
+
const baseProviderValue = baseProviders[providerId];
|
|
1710
|
+
if (!providerValue || typeof providerValue !== "object" || Array.isArray(providerValue) || !baseProviderValue || typeof baseProviderValue !== "object" || Array.isArray(baseProviderValue)) {
|
|
1711
|
+
continue;
|
|
1712
|
+
}
|
|
1713
|
+
const models = providerValue.models;
|
|
1714
|
+
const baseModels = baseProviderValue.models;
|
|
1715
|
+
if (!models || typeof models !== "object" || Array.isArray(models) || !baseModels || typeof baseModels !== "object" || Array.isArray(baseModels)) {
|
|
1716
|
+
continue;
|
|
1717
|
+
}
|
|
1718
|
+
const userAvailable = models.available;
|
|
1719
|
+
const baseAvailable = baseModels.available;
|
|
1720
|
+
if (!Array.isArray(userAvailable) || !Array.isArray(baseAvailable)) continue;
|
|
1721
|
+
const combined = [...baseAvailable, ...userAvailable];
|
|
1722
|
+
if (!combined.every(
|
|
1723
|
+
(entry) => entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.id === "string"
|
|
1724
|
+
)) {
|
|
1725
|
+
continue;
|
|
1726
|
+
}
|
|
1727
|
+
const availableById = /* @__PURE__ */ new Map();
|
|
1728
|
+
for (const entry of combined) {
|
|
1729
|
+
const entryObject = entry;
|
|
1730
|
+
const id = entryObject.id;
|
|
1731
|
+
const existing = availableById.get(id);
|
|
1732
|
+
availableById.set(
|
|
1733
|
+
id,
|
|
1734
|
+
existing && typeof existing === "object" && !Array.isArray(existing) ? { ...existing, ...entryObject } : entry
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1737
|
+
models.available = [...availableById.values()];
|
|
1738
|
+
}
|
|
1739
|
+
return projected;
|
|
1740
|
+
};
|
|
1741
|
+
const listTemplatedProviderIds = (raw) => {
|
|
1742
|
+
if (!raw || typeof raw !== "object") return [];
|
|
1743
|
+
const providers = raw.providers;
|
|
1744
|
+
if (!providers || typeof providers !== "object") return [];
|
|
1745
|
+
const templated = [];
|
|
1746
|
+
for (const [id, value] of Object.entries(providers)) {
|
|
1747
|
+
if (!value || typeof value !== "object") continue;
|
|
1748
|
+
const engine = value.engine;
|
|
1749
|
+
if (engine === "templated_cli") {
|
|
1750
|
+
templated.push(id);
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
return templated;
|
|
1754
|
+
};
|
|
1755
|
+
const getRawProvider = (raw, providerId) => {
|
|
1756
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
1757
|
+
const providers = raw.providers;
|
|
1758
|
+
if (!providers || typeof providers !== "object") return void 0;
|
|
1759
|
+
return providers[providerId];
|
|
1760
|
+
};
|
|
1761
|
+
const stableJson = (value) => {
|
|
1762
|
+
if (Array.isArray(value)) {
|
|
1763
|
+
return `[${value.map((entry) => stableJson(entry)).join(",")}]`;
|
|
1764
|
+
}
|
|
1765
|
+
if (value && typeof value === "object") {
|
|
1766
|
+
return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`).join(",")}}`;
|
|
1767
|
+
}
|
|
1768
|
+
return JSON.stringify(value);
|
|
1769
|
+
};
|
|
1770
|
+
const normalizeProviderForTrustComparison = (providerId, provider) => {
|
|
1771
|
+
try {
|
|
1772
|
+
return ProviderConfigSchema.parse(provider);
|
|
1773
|
+
} catch (error) {
|
|
1774
|
+
debugLog(
|
|
1775
|
+
`[provider-registry] Failed to normalize templated provider "${providerId}" for trust comparison`,
|
|
1776
|
+
error instanceof Error ? error.message : String(error)
|
|
1777
|
+
);
|
|
1778
|
+
return provider;
|
|
1779
|
+
}
|
|
1780
|
+
};
|
|
1781
|
+
const listUntrustedTemplatedProviderIds = (raw, trustedRaw) => listTemplatedProviderIds(raw).filter((providerId) => {
|
|
1782
|
+
const candidate = getRawProvider(raw, providerId);
|
|
1783
|
+
const trusted = getRawProvider(trustedRaw, providerId);
|
|
1784
|
+
return !trusted || stableJson(normalizeProviderForTrustComparison(providerId, candidate)) !== stableJson(normalizeProviderForTrustComparison(providerId, trusted));
|
|
1785
|
+
});
|
|
1786
|
+
const listUntrustedExecutionFieldChanges = (raw, trustedRaw) => {
|
|
1787
|
+
if (!raw || typeof raw !== "object") return [];
|
|
1788
|
+
const providers = raw.providers;
|
|
1789
|
+
if (!providers || typeof providers !== "object" || Array.isArray(providers)) return [];
|
|
1790
|
+
const changes = [];
|
|
1791
|
+
for (const [providerId, candidate] of Object.entries(providers)) {
|
|
1792
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) continue;
|
|
1793
|
+
const candidateProvider = candidate;
|
|
1794
|
+
const trusted = getRawProvider(trustedRaw, providerId);
|
|
1795
|
+
const trustedProvider = trusted && typeof trusted === "object" && !Array.isArray(trusted) ? trusted : null;
|
|
1796
|
+
if (!trustedProvider) {
|
|
1797
|
+
const declaredFields = EXECUTION_SENSITIVE_PROVIDER_FIELDS.filter(
|
|
1798
|
+
(field) => candidateProvider[field] !== void 0
|
|
1799
|
+
);
|
|
1800
|
+
if (declaredFields.length > 0) {
|
|
1801
|
+
changes.push({ providerId, fields: [...declaredFields] });
|
|
1802
|
+
}
|
|
1803
|
+
continue;
|
|
1804
|
+
}
|
|
1805
|
+
const effective = normalizeProviderForTrustComparison(
|
|
1806
|
+
providerId,
|
|
1807
|
+
deepMerge(trustedProvider, candidateProvider)
|
|
1808
|
+
);
|
|
1809
|
+
const baseline = normalizeProviderForTrustComparison(providerId, trustedProvider);
|
|
1810
|
+
const changedFields = EXECUTION_SENSITIVE_PROVIDER_FIELDS.filter((field) => {
|
|
1811
|
+
if (candidateProvider[field] === void 0) return false;
|
|
1812
|
+
return stableJson(effective?.[field]) !== stableJson(baseline?.[field]);
|
|
1813
|
+
});
|
|
1814
|
+
if (changedFields.length > 0) {
|
|
1815
|
+
changes.push({ providerId, fields: [...changedFields] });
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
return changes;
|
|
1819
|
+
};
|
|
1820
|
+
const listUntrustedApiIdentityChanges = (projectRaw, effectiveRaw, trustedRaw) => {
|
|
1821
|
+
if (!projectRaw || typeof projectRaw !== "object" || Array.isArray(projectRaw)) return [];
|
|
1822
|
+
const projectProviders = projectRaw.providers;
|
|
1823
|
+
if (!projectProviders || typeof projectProviders !== "object" || Array.isArray(projectProviders)) {
|
|
1824
|
+
return [];
|
|
1825
|
+
}
|
|
1826
|
+
const changes = [];
|
|
1827
|
+
for (const [providerId, projectValue] of Object.entries(
|
|
1828
|
+
projectProviders
|
|
1829
|
+
)) {
|
|
1830
|
+
if (!projectValue || typeof projectValue !== "object" || Array.isArray(projectValue)) {
|
|
1831
|
+
continue;
|
|
1832
|
+
}
|
|
1833
|
+
const projectProvider = projectValue;
|
|
1834
|
+
const effectiveProviderValue = getRawProvider(effectiveRaw, providerId);
|
|
1835
|
+
const trustedProviderValue = getRawProvider(trustedRaw, providerId);
|
|
1836
|
+
if (!effectiveProviderValue || typeof effectiveProviderValue !== "object" || Array.isArray(effectiveProviderValue)) {
|
|
1837
|
+
continue;
|
|
1838
|
+
}
|
|
1839
|
+
const effectiveProvider = effectiveProviderValue;
|
|
1840
|
+
const trustedProvider = trustedProviderValue && typeof trustedProviderValue === "object" && !Array.isArray(trustedProviderValue) ? trustedProviderValue : {};
|
|
1841
|
+
const effectiveApi = effectiveProvider.api && typeof effectiveProvider.api === "object" && !Array.isArray(effectiveProvider.api) ? effectiveProvider.api : {};
|
|
1842
|
+
const trustedApi = trustedProvider.api && typeof trustedProvider.api === "object" && !Array.isArray(trustedProvider.api) ? trustedProvider.api : {};
|
|
1843
|
+
const projectApi = projectProvider.api && typeof projectProvider.api === "object" && !Array.isArray(projectProvider.api) ? projectProvider.api : {};
|
|
1844
|
+
const effectiveChannels = Array.isArray(effectiveProvider.channels) ? effectiveProvider.channels : [];
|
|
1845
|
+
const apiCanRun = effectiveProvider.transport === "api" || effectiveChannels.includes("api");
|
|
1846
|
+
if (!apiCanRun) continue;
|
|
1847
|
+
const fields = [];
|
|
1848
|
+
if (projectProvider.transport !== void 0 && effectiveProvider.transport === "api" && trustedProvider.transport !== "api") {
|
|
1849
|
+
fields.push("transport");
|
|
1850
|
+
}
|
|
1851
|
+
for (const field of ["base_url", "api_key_env_var"]) {
|
|
1852
|
+
if (projectApi[field] !== void 0 && stableJson(effectiveApi[field]) !== stableJson(trustedApi[field])) {
|
|
1853
|
+
fields.push(`api.${field}`);
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
if (fields.length > 0) {
|
|
1857
|
+
changes.push({ providerId, fields });
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
return changes;
|
|
1861
|
+
};
|
|
1862
|
+
const describeExecutionFieldChanges = (changes) => changes.map(({ providerId, fields }) => `${providerId} (${fields.join(", ")})`).join(", ");
|
|
1863
|
+
const buildUntrustedExecutionFieldError = (changes, root) => new Error(
|
|
1864
|
+
`Security: Project config changes provider execution fields (${describeExecutionFieldChanges(changes)}) which are not allowed unless POETIC_TRUST_PROJECT_PROVIDER_TEMPLATES names this canonical project root.
|
|
1865
|
+
|
|
1866
|
+
These fields can select the binary Poetic executes or installs, or redirect a credentialed API request, so a cloned repo could otherwise redirect a built-in provider to attacker-controlled code or infrastructure:
|
|
1867
|
+
- User config: ${getUserProviderRegistryPaths(root)[0]}
|
|
1868
|
+
- Project config: .poetic/config/providers.yaml (requires explicit trust)
|
|
1869
|
+
|
|
1870
|
+
Providers are trusted only when their normalized execution config matches the embedded template.
|
|
1871
|
+
|
|
1872
|
+
To trust only this project, run:
|
|
1873
|
+
` + projectTrustInstruction
|
|
1874
|
+
);
|
|
1875
|
+
const isAutoLoadedProjectRegistryPath = (candidatePath, root) => [
|
|
1876
|
+
resolveProvidersConfigPath({ cwd: root }),
|
|
1877
|
+
resolve3(root, ".poetic", "config", "provider-registry.yaml.v1.backup")
|
|
1878
|
+
].some((registryPath) => resolve3(registryPath) === resolve3(candidatePath));
|
|
1879
|
+
const embedded = loadEmbeddedRaw();
|
|
1880
|
+
if (!embedded) {
|
|
1881
|
+
throw new Error("Failed to load the provider catalog. Run the provider generator and retry.");
|
|
1882
|
+
}
|
|
1883
|
+
if (configPath) {
|
|
1884
|
+
const pathValidation = validateConfigPath(configPath, projectRoot, { allowTempDir: false });
|
|
1885
|
+
if (!pathValidation.isValid) {
|
|
1886
|
+
throw new Error(
|
|
1887
|
+
`Security Error: Invalid config path "${configPath}": ${pathValidation.reason}. Risk level: ${pathValidation.riskLevel}`
|
|
1888
|
+
);
|
|
1889
|
+
}
|
|
1890
|
+
const raw = loadYamlRawIfExists(pathValidation.normalizedPath);
|
|
1891
|
+
if (!raw) {
|
|
1892
|
+
throw new Error(
|
|
1893
|
+
`Failed to read unified provider config at ${pathValidation.normalizedPath}`
|
|
1894
|
+
);
|
|
1895
|
+
}
|
|
1896
|
+
const templatedProviders = listUntrustedTemplatedProviderIds(raw, embedded.raw);
|
|
1897
|
+
const projectPoeticDir = resolve3(projectRoot, ".poetic");
|
|
1898
|
+
const isProjectConfig = pathValidation.normalizedPath.startsWith(projectPoeticDir + sep);
|
|
1899
|
+
if (isProjectConfig && templatedProviders.length > 0 && !isTrustedProjectForTemplatedProviders()) {
|
|
1900
|
+
throw new Error(
|
|
1901
|
+
`Security: Project config contains templated_cli providers (${templatedProviders.join(", ")}) which are not allowed unless POETIC_TRUST_PROJECT_PROVIDER_TEMPLATES names this canonical project root.
|
|
1902
|
+
|
|
1903
|
+
Templated CLI providers execute external binaries and should normally be configured in user scope:
|
|
1904
|
+
- User config: ${getUserProviderRegistryPaths(projectRoot)[0]}
|
|
1905
|
+
- Project config: .poetic/config/providers.yaml (requires explicit trust)
|
|
1906
|
+
|
|
1907
|
+
Built-in templated providers are trusted only when their normalized config matches the embedded template.
|
|
1908
|
+
|
|
1909
|
+
To trust only this project, run:
|
|
1910
|
+
` + projectTrustInstruction
|
|
1911
|
+
);
|
|
1912
|
+
}
|
|
1913
|
+
if (isProjectConfig && isAutoLoadedProjectRegistryPath(pathValidation.normalizedPath, projectRoot) && !isTrustedProjectForTemplatedProviders()) {
|
|
1914
|
+
const executionFieldChanges = listUntrustedExecutionFieldChanges(raw, embedded.raw);
|
|
1915
|
+
if (executionFieldChanges.length > 0) {
|
|
1916
|
+
throw buildUntrustedExecutionFieldError(executionFieldChanges, projectRoot);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
if (isProjectConfig && isAutoLoadedProjectRegistryPath(pathValidation.normalizedPath, projectRoot) && !isTrustedProjectForTemplatedProviders()) {
|
|
1920
|
+
const apiIdentityChanges = listUntrustedApiIdentityChanges(raw, raw, embedded.raw);
|
|
1921
|
+
if (apiIdentityChanges.length > 0) {
|
|
1922
|
+
throw buildUntrustedExecutionFieldError(apiIdentityChanges, projectRoot);
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
const withEnvOverrides2 = _ProviderRegistry.applyEnvOverrides(
|
|
1926
|
+
dropRemovedBuiltinProviders(ensureCursorIdSyntaxAdmissionPattern(raw))
|
|
1927
|
+
);
|
|
1928
|
+
const validated2 = _ProviderRegistry.parseRegistryConfig(withEnvOverrides2);
|
|
1929
|
+
return _ProviderRegistry.replaceCachedRegistry(
|
|
1930
|
+
validated2,
|
|
1931
|
+
pathValidation.normalizedPath,
|
|
1932
|
+
requestedCacheKey,
|
|
1933
|
+
"explicit",
|
|
1934
|
+
projectRoot,
|
|
1935
|
+
[pathValidation.normalizedPath]
|
|
1936
|
+
);
|
|
1937
|
+
}
|
|
1938
|
+
let mergedRaw = embedded.raw;
|
|
1939
|
+
const overlayPath = resolve3(
|
|
1940
|
+
projectRoot,
|
|
1941
|
+
".poetic",
|
|
1942
|
+
"cache",
|
|
1943
|
+
"model-update",
|
|
1944
|
+
"refresh-overlay.json"
|
|
1945
|
+
);
|
|
1946
|
+
let appliedOverlayPath;
|
|
1947
|
+
if (existsSync2(overlayPath)) {
|
|
1948
|
+
const disposition = resolveRefreshOverlayDisposition(readFileSync2(overlayPath, "utf8"), {
|
|
1949
|
+
expectedBaseCatalogDigest: PROVIDER_CATALOG_SHA256
|
|
1950
|
+
});
|
|
1951
|
+
if (disposition.status === "ready") {
|
|
1952
|
+
mergedRaw = applyRefreshOverlay(mergedRaw, disposition.overlay);
|
|
1953
|
+
appliedOverlayPath = overlayPath;
|
|
1954
|
+
} else if (disposition.status !== "absent") {
|
|
1955
|
+
debugLog(
|
|
1956
|
+
disposition.status === "degraded" ? disposition.warning : `Refresh overlay ignored: ${disposition.error}`
|
|
1957
|
+
);
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
let securityMergedRaw = mergedRaw;
|
|
1961
|
+
let trustedMergedRaw = mergedRaw;
|
|
1962
|
+
let loadedProjectRaw = null;
|
|
1963
|
+
const loadedConfigSources = [
|
|
1964
|
+
embedded.path,
|
|
1965
|
+
...appliedOverlayPath ? [appliedOverlayPath] : []
|
|
1966
|
+
];
|
|
1967
|
+
const projectConfigV2 = resolveProvidersConfigPath({ cwd: projectRoot });
|
|
1968
|
+
const projectConfigV1 = resolve3(
|
|
1969
|
+
projectRoot,
|
|
1970
|
+
".poetic",
|
|
1971
|
+
"config",
|
|
1972
|
+
"provider-registry.yaml.v1.backup"
|
|
1973
|
+
);
|
|
1974
|
+
const discoveredProjectConfigPath = existsSync2(projectConfigV2) ? projectConfigV2 : existsSync2(projectConfigV1) ? projectConfigV1 : null;
|
|
1975
|
+
const projectConfigPath = discoveredProjectConfigPath && resolve3(discoveredProjectConfigPath) !== resolve3(embedded.path) ? discoveredProjectConfigPath : null;
|
|
1976
|
+
let loadedConfigPath = embedded.path;
|
|
1977
|
+
if (projectConfigPath) {
|
|
1978
|
+
const configParentDir = resolve3(projectRoot, ".poetic", "config");
|
|
1979
|
+
if (!existsSync2(configParentDir)) {
|
|
1980
|
+
throw new Error(
|
|
1981
|
+
`Poetic not initialized: directory '${configParentDir}' does not exist.
|
|
1982
|
+
Run 'poetic init' to initialize Poetic in this project.`
|
|
1983
|
+
);
|
|
1984
|
+
}
|
|
1985
|
+
const pathValidation = validateConfigPath(projectConfigPath, projectRoot, {
|
|
1986
|
+
allowTempDir: false
|
|
1987
|
+
});
|
|
1988
|
+
if (!pathValidation.isValid) {
|
|
1989
|
+
throw new Error(
|
|
1990
|
+
`Security Error: Invalid config path "${projectConfigPath}": ${pathValidation.reason}. Risk level: ${pathValidation.riskLevel}`
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
const projectRaw = loadYamlRawIfExists(pathValidation.normalizedPath);
|
|
1994
|
+
if (!projectRaw) {
|
|
1995
|
+
throw new Error(
|
|
1996
|
+
`Failed to read unified provider config at ${pathValidation.normalizedPath}`
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1999
|
+
loadedProjectRaw = projectRaw;
|
|
2000
|
+
const templatedProviders = listUntrustedTemplatedProviderIds(projectRaw, embedded.raw);
|
|
2001
|
+
if (templatedProviders.length > 0 && !isTrustedProjectForTemplatedProviders()) {
|
|
2002
|
+
throw new Error(
|
|
2003
|
+
`Security: Project config contains templated_cli providers (${templatedProviders.join(", ")}) which are not allowed unless POETIC_TRUST_PROJECT_PROVIDER_TEMPLATES names this canonical project root.
|
|
2004
|
+
|
|
2005
|
+
Templated CLI providers execute external binaries and should normally be configured in user scope:
|
|
2006
|
+
- User config: ${getUserProviderRegistryPaths(projectRoot)[0]}
|
|
2007
|
+
- Project config: .poetic/config/providers.yaml (requires explicit trust)
|
|
2008
|
+
|
|
2009
|
+
Built-in templated providers are trusted only when their normalized config matches the embedded template.
|
|
2010
|
+
|
|
2011
|
+
To trust only this project, run:
|
|
2012
|
+
` + projectTrustInstruction
|
|
2013
|
+
);
|
|
2014
|
+
}
|
|
2015
|
+
const projectIsTrusted = isTrustedProjectForTemplatedProviders();
|
|
2016
|
+
securityMergedRaw = deepMerge(securityMergedRaw, projectRaw);
|
|
2017
|
+
if (!projectIsTrusted) {
|
|
2018
|
+
const executionFieldChanges = listUntrustedExecutionFieldChanges(projectRaw, embedded.raw);
|
|
2019
|
+
if (executionFieldChanges.length > 0) {
|
|
2020
|
+
throw buildUntrustedExecutionFieldError(executionFieldChanges, projectRoot);
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
const projectedProjectRaw = projectProjectRegistryPolicy(projectRaw, embedded.raw, {
|
|
2024
|
+
trusted: projectIsTrusted
|
|
2025
|
+
});
|
|
2026
|
+
mergedRaw = deepMerge(mergedRaw, projectedProjectRaw);
|
|
2027
|
+
loadedConfigPath = pathValidation.normalizedPath;
|
|
2028
|
+
loadedConfigSources.push(pathValidation.normalizedPath);
|
|
2029
|
+
}
|
|
2030
|
+
const userRegistryPaths = getUserProviderRegistryPaths(projectRoot);
|
|
2031
|
+
for (const [index, candidate] of userRegistryPaths.entries()) {
|
|
2032
|
+
const userRaw = loadYamlRawIfExists(candidate);
|
|
2033
|
+
if (userRaw) {
|
|
2034
|
+
const migratedUserOverlay = index > 0 ? migrateLegacyFullSnapshotOverlay(userRaw, mergedRaw) : userRaw;
|
|
2035
|
+
const userOverlay = mergeUserAvailableModels(migratedUserOverlay, mergedRaw);
|
|
2036
|
+
mergedRaw = deepMerge(mergedRaw, userOverlay);
|
|
2037
|
+
securityMergedRaw = deepMerge(securityMergedRaw, userOverlay);
|
|
2038
|
+
trustedMergedRaw = deepMerge(trustedMergedRaw, userOverlay);
|
|
2039
|
+
loadedConfigSources.push(candidate);
|
|
2040
|
+
break;
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
if (loadedProjectRaw && !isTrustedProjectForTemplatedProviders()) {
|
|
2044
|
+
const apiIdentityChanges = listUntrustedApiIdentityChanges(
|
|
2045
|
+
loadedProjectRaw,
|
|
2046
|
+
securityMergedRaw,
|
|
2047
|
+
trustedMergedRaw
|
|
2048
|
+
);
|
|
2049
|
+
if (apiIdentityChanges.length > 0) {
|
|
2050
|
+
throw buildUntrustedExecutionFieldError(apiIdentityChanges, projectRoot);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
const withEnvOverrides = _ProviderRegistry.applyEnvOverrides(
|
|
2054
|
+
dropRemovedBuiltinProviders(ensureCursorIdSyntaxAdmissionPattern(mergedRaw))
|
|
2055
|
+
);
|
|
2056
|
+
const validated = _ProviderRegistry.parseRegistryConfig(withEnvOverrides);
|
|
2057
|
+
return _ProviderRegistry.replaceCachedRegistry(
|
|
2058
|
+
validated,
|
|
2059
|
+
loadedConfigPath,
|
|
2060
|
+
requestedCacheKey,
|
|
2061
|
+
"implicit",
|
|
2062
|
+
projectRoot,
|
|
2063
|
+
loadedConfigSources
|
|
2064
|
+
);
|
|
2065
|
+
}
|
|
2066
|
+
/**
|
|
2067
|
+
* Resolve every live registry read through the same active-root view.
|
|
2068
|
+
*
|
|
2069
|
+
* A prior explicit-root load establishes which project this process is
|
|
2070
|
+
* serving. Rechecking that root on each read preserves file/environment
|
|
2071
|
+
* fingerprint invalidation without letting a later process.cwd() change
|
|
2072
|
+
* silently switch the live registry to another checkout.
|
|
2073
|
+
*/
|
|
2074
|
+
static getActiveRegistry(registryOverride) {
|
|
2075
|
+
if (registryOverride) {
|
|
2076
|
+
return registryOverride;
|
|
2077
|
+
}
|
|
2078
|
+
if (!_ProviderRegistry.instance || !_ProviderRegistry.cacheProjectRoot) {
|
|
2079
|
+
return _ProviderRegistry.load();
|
|
2080
|
+
}
|
|
2081
|
+
if (_ProviderRegistry.cacheMode === "explicit" && _ProviderRegistry.configPath) {
|
|
2082
|
+
return _ProviderRegistry.load(_ProviderRegistry.configPath, _ProviderRegistry.cacheProjectRoot);
|
|
2083
|
+
}
|
|
2084
|
+
return _ProviderRegistry.load(void 0, _ProviderRegistry.cacheProjectRoot);
|
|
2085
|
+
}
|
|
2086
|
+
/**
|
|
2087
|
+
* Get configuration for a specific provider
|
|
2088
|
+
*
|
|
2089
|
+
* @param providerId - Provider identifier (e.g., 'claude', 'codex')
|
|
2090
|
+
* @returns Provider configuration with defaults applied
|
|
2091
|
+
*/
|
|
2092
|
+
static getProviderConfig(providerId, registryOverride) {
|
|
2093
|
+
const registry = _ProviderRegistry.getActiveRegistry(registryOverride);
|
|
2094
|
+
const normalizedProviderId = normalizeProviderConfigId(providerId);
|
|
2095
|
+
const providerConfig = registry.providers[providerId] ?? registry.providers[normalizedProviderId];
|
|
2096
|
+
if (!providerConfig) {
|
|
2097
|
+
const availableProviders = Object.values(registry.providers).filter((provider) => provider.enabled).sort((a, b) => a.order - b.order).map((provider) => provider.id).join(", ");
|
|
2098
|
+
throw new Error(
|
|
2099
|
+
`Provider '${providerId}' not found in unified config. Available providers: ${availableProviders}`
|
|
2100
|
+
);
|
|
2101
|
+
}
|
|
2102
|
+
return cloneProviderRegistryValue({
|
|
2103
|
+
...providerConfig,
|
|
2104
|
+
retry: providerConfig.retry || registry.defaults.retry,
|
|
2105
|
+
circuit_breaker: providerConfig.circuit_breaker || registry.defaults.circuit_breaker,
|
|
2106
|
+
polling: providerConfig.polling || registry.defaults.polling
|
|
2107
|
+
});
|
|
2108
|
+
}
|
|
2109
|
+
/**
|
|
2110
|
+
* Get all provider IDs
|
|
2111
|
+
*
|
|
2112
|
+
* @returns Array of provider IDs
|
|
2113
|
+
*/
|
|
2114
|
+
static getAllProviderIds() {
|
|
2115
|
+
const registry = _ProviderRegistry.getActiveRegistry();
|
|
2116
|
+
return Object.keys(registry.providers);
|
|
2117
|
+
}
|
|
2118
|
+
/**
|
|
2119
|
+
* Get all enabled providers
|
|
2120
|
+
*
|
|
2121
|
+
* @returns Array of enabled provider configurations
|
|
2122
|
+
*/
|
|
2123
|
+
static getEnabledProviders(registryOverride) {
|
|
2124
|
+
const registry = _ProviderRegistry.getActiveRegistry(registryOverride);
|
|
2125
|
+
return Object.values(registry.providers).filter((p) => p.enabled).sort((a, b) => a.order - b.order);
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Check if a provider is enabled
|
|
2129
|
+
*
|
|
2130
|
+
* @param providerId - Provider identifier
|
|
2131
|
+
* @returns True if provider exists and is enabled
|
|
2132
|
+
*/
|
|
2133
|
+
static isProviderEnabled(providerId) {
|
|
2134
|
+
const registry = _ProviderRegistry.getActiveRegistry();
|
|
2135
|
+
const normalizedProviderId = normalizeProviderConfigId(providerId);
|
|
2136
|
+
const providerConfig = registry.providers[providerId] ?? registry.providers[normalizedProviderId];
|
|
2137
|
+
return providerConfig?.enabled || false;
|
|
2138
|
+
}
|
|
2139
|
+
/**
|
|
2140
|
+
* Report the source path the currently-cached registry was actually loaded
|
|
2141
|
+
* from.
|
|
2142
|
+
*
|
|
2143
|
+
* This is the coherent provenance signal: when the project providers.yaml is
|
|
2144
|
+
* absent and `load()` falls back to the embedded template seed, this returns
|
|
2145
|
+
* the embedded template path that was actually used — NOT the nonexistent
|
|
2146
|
+
* project `.poetic/config/providers.yaml` path. Diagnostics and logs should
|
|
2147
|
+
* read this instead of recomputing the project path (e.g. via
|
|
2148
|
+
* `resolveProvidersConfigPath`), which would falsely claim a project registry
|
|
2149
|
+
* that is not present on disk.
|
|
2150
|
+
*
|
|
2151
|
+
* Returns `null` when no registry has been loaded yet in this process.
|
|
2152
|
+
*
|
|
2153
|
+
* @returns Absolute path of the loaded registry source, or `null`.
|
|
2154
|
+
*/
|
|
2155
|
+
static getLoadedConfigPath() {
|
|
2156
|
+
return _ProviderRegistry.configPath;
|
|
2157
|
+
}
|
|
2158
|
+
/**
|
|
2159
|
+
* Report every source that contributed to the currently-cached registry,
|
|
2160
|
+
* ordered from lowest to highest precedence.
|
|
2161
|
+
*/
|
|
2162
|
+
static getLoadedConfigSources() {
|
|
2163
|
+
return [..._ProviderRegistry.configSources];
|
|
2164
|
+
}
|
|
2165
|
+
/**
|
|
2166
|
+
* Force reload configuration from disk
|
|
2167
|
+
* Useful for testing or when config file has been modified
|
|
2168
|
+
*/
|
|
2169
|
+
/**
|
|
2170
|
+
* Per-provider `concurrency.max` set in USER-scope provider config only.
|
|
2171
|
+
*
|
|
2172
|
+
* Deliberately NOT read through `getProviderConfig()`. That returns the merged
|
|
2173
|
+
* embedded < project < user view, and `concurrency` is in
|
|
2174
|
+
* PROJECT_POLICY_PROVIDER_FIELDS — a list retained even for UNTRUSTED project
|
|
2175
|
+
* snapshots — so a cloned repository's `.poetic/config/providers.yaml` can set
|
|
2176
|
+
* it. The orchestrator raises how many provider processes actually run from
|
|
2177
|
+
* this value, spending the operator's host resources and account quota, so it
|
|
2178
|
+
* must come from config the operator owns. A project may still ship a lower
|
|
2179
|
+
* value for its own planning; it just cannot raise process concurrency.
|
|
2180
|
+
*
|
|
2181
|
+
* Returns raw declared maxima without validation or clamping; the caller owns
|
|
2182
|
+
* normalization and correctness ceilings. Unreadable or malformed user config
|
|
2183
|
+
* yields an empty map rather than failing the run: the shipped baseline is
|
|
2184
|
+
* always a safe fallback.
|
|
2185
|
+
*/
|
|
2186
|
+
static getUserScopeProviderConcurrencyMax(cwd = process.cwd()) {
|
|
2187
|
+
const projectRoot = findProjectRoot(cwd) ?? cwd;
|
|
2188
|
+
const result = {};
|
|
2189
|
+
for (const candidate of getUserProviderRegistryPaths(projectRoot)) {
|
|
2190
|
+
if (!existsSync2(candidate)) continue;
|
|
2191
|
+
let raw;
|
|
2192
|
+
try {
|
|
2193
|
+
raw = yaml.load(readFileSync2(candidate, "utf-8"));
|
|
2194
|
+
} catch {
|
|
2195
|
+
return {};
|
|
2196
|
+
}
|
|
2197
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
2198
|
+
continue;
|
|
2199
|
+
}
|
|
2200
|
+
const providers = raw.providers;
|
|
2201
|
+
if (!providers || typeof providers !== "object" || Array.isArray(providers)) {
|
|
2202
|
+
return result;
|
|
2203
|
+
}
|
|
2204
|
+
for (const [providerId, providerValue] of Object.entries(
|
|
2205
|
+
providers
|
|
2206
|
+
)) {
|
|
2207
|
+
if (!providerValue || typeof providerValue !== "object" || Array.isArray(providerValue)) {
|
|
2208
|
+
continue;
|
|
2209
|
+
}
|
|
2210
|
+
const concurrency = providerValue.concurrency;
|
|
2211
|
+
if (!concurrency || typeof concurrency !== "object" || Array.isArray(concurrency)) {
|
|
2212
|
+
continue;
|
|
2213
|
+
}
|
|
2214
|
+
const max = concurrency.max;
|
|
2215
|
+
if (typeof max === "number" && Number.isFinite(max)) {
|
|
2216
|
+
result[providerId] = max;
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
return result;
|
|
2220
|
+
}
|
|
2221
|
+
return result;
|
|
2222
|
+
}
|
|
2223
|
+
static reload() {
|
|
2224
|
+
_ProviderRegistry.instance = null;
|
|
2225
|
+
_ProviderRegistry.configPath = null;
|
|
2226
|
+
_ProviderRegistry.configSources = [];
|
|
2227
|
+
_ProviderRegistry.cacheKey = null;
|
|
2228
|
+
_ProviderRegistry.cacheMode = null;
|
|
2229
|
+
_ProviderRegistry.cacheProjectRoot = null;
|
|
2230
|
+
runProviderRegistryReloadInvalidators();
|
|
2231
|
+
}
|
|
2232
|
+
static buildEnvOverrideCacheKey() {
|
|
2233
|
+
return fingerprintEnvironment(
|
|
2234
|
+
{ ...process.env, ...getExecutionContext().envOverrides },
|
|
2235
|
+
(name) => name.startsWith("POETIC_PROVIDER_") || [
|
|
2236
|
+
"POETIC_TRUST_PROJECT_PROVIDER_TEMPLATES",
|
|
2237
|
+
"POETIC_CONFIG_DIR",
|
|
2238
|
+
"XDG_CONFIG_HOME",
|
|
2239
|
+
"HOME",
|
|
2240
|
+
"USERPROFILE"
|
|
2241
|
+
].includes(name)
|
|
2242
|
+
);
|
|
2243
|
+
}
|
|
2244
|
+
static buildCacheKey(configPath, envKey, projectRoot) {
|
|
2245
|
+
if (configPath) {
|
|
2246
|
+
return combineCacheFingerprints(
|
|
2247
|
+
`path:${resolve3(configPath)}`,
|
|
2248
|
+
`root:${projectRoot}`,
|
|
2249
|
+
envKey,
|
|
2250
|
+
fingerprintFiles([configPath])
|
|
2251
|
+
);
|
|
2252
|
+
}
|
|
2253
|
+
return combineCacheFingerprints(
|
|
2254
|
+
`root:${projectRoot}`,
|
|
2255
|
+
envKey,
|
|
2256
|
+
fingerprintFiles(getProviderRegistryInputPaths(projectRoot))
|
|
2257
|
+
);
|
|
2258
|
+
}
|
|
2259
|
+
static canReuseExplicitCacheForImplicit(configPath, projectRoot) {
|
|
2260
|
+
return resolve3(configPath) !== resolveProvidersConfigPath({ cwd: projectRoot });
|
|
2261
|
+
}
|
|
2262
|
+
/**
|
|
2263
|
+
* Apply environment variable overrides
|
|
2264
|
+
* Supports: POETIC_PROVIDER_<ID>_<KEY>=value
|
|
2265
|
+
*
|
|
2266
|
+
* Examples:
|
|
2267
|
+
* - POETIC_PROVIDER_CODEX_TIMEOUT_MS=900000
|
|
2268
|
+
* - POETIC_PROVIDER_CLAUDE_ENABLED=false
|
|
2269
|
+
* - POETIC_PROVIDER_GEMINI_MODELS_DEFAULT=gemini-2.5-flash
|
|
2270
|
+
*
|
|
2271
|
+
* @param config - Parsed YAML configuration
|
|
2272
|
+
* @returns Configuration with environment overrides applied
|
|
2273
|
+
*/
|
|
2274
|
+
static applyEnvOverrides(config) {
|
|
2275
|
+
if (!config || typeof config !== "object") {
|
|
2276
|
+
return config;
|
|
2277
|
+
}
|
|
2278
|
+
const result = cloneProviderRegistryValue(config);
|
|
2279
|
+
const runtimeEnv = {
|
|
2280
|
+
...process.env,
|
|
2281
|
+
...getExecutionContext().envOverrides
|
|
2282
|
+
};
|
|
2283
|
+
for (const [key, value] of Object.entries(runtimeEnv)) {
|
|
2284
|
+
if (!key.startsWith("POETIC_PROVIDER_")) {
|
|
2285
|
+
continue;
|
|
2286
|
+
}
|
|
2287
|
+
if (getEnvVarEntry(key)) {
|
|
2288
|
+
continue;
|
|
2289
|
+
}
|
|
2290
|
+
const overrideName = key.substring("POETIC_PROVIDER_".length);
|
|
2291
|
+
if (!overrideName.includes("_")) {
|
|
2292
|
+
continue;
|
|
2293
|
+
}
|
|
2294
|
+
const providers = result.providers;
|
|
2295
|
+
const providerEntries = providers && typeof providers === "object" ? Object.keys(providers) : [];
|
|
2296
|
+
const providerId = providerEntries.filter((id) => overrideName.startsWith(`${id.toUpperCase()}_`)).sort((a, b) => b.length - a.length)[0];
|
|
2297
|
+
if (!providerId) {
|
|
2298
|
+
const claimedProvider = overrideName.split("_")[0]?.toLowerCase() ?? overrideName;
|
|
2299
|
+
throw new InvalidExplicitConfigError(
|
|
2300
|
+
`Environment variable ${key} targets unknown provider '${claimedProvider}'.`
|
|
2301
|
+
);
|
|
2302
|
+
}
|
|
2303
|
+
const configKey = overrideName.slice(providerId.length + 1).toLowerCase();
|
|
2304
|
+
const providerConfig = providers[providerId];
|
|
2305
|
+
if (providerConfig && typeof providerConfig === "object") {
|
|
2306
|
+
_ProviderRegistry.setNestedValue(
|
|
2307
|
+
providerConfig,
|
|
2308
|
+
configKey,
|
|
2309
|
+
String(value ?? ""),
|
|
2310
|
+
key
|
|
2311
|
+
);
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
return result;
|
|
2315
|
+
}
|
|
2316
|
+
static dynamicProviderOverrideKeys() {
|
|
2317
|
+
const runtimeEnv = {
|
|
2318
|
+
...process.env,
|
|
2319
|
+
...getExecutionContext().envOverrides
|
|
2320
|
+
};
|
|
2321
|
+
return Object.keys(runtimeEnv).filter((key) => {
|
|
2322
|
+
if (!key.startsWith("POETIC_PROVIDER_") || getEnvVarEntry(key)) return false;
|
|
2323
|
+
return key.substring("POETIC_PROVIDER_".length).includes("_");
|
|
2324
|
+
});
|
|
2325
|
+
}
|
|
2326
|
+
static parseRegistryConfig(config) {
|
|
2327
|
+
try {
|
|
2328
|
+
return ProviderRegistryConfigSchema.parse(config);
|
|
2329
|
+
} catch (error) {
|
|
2330
|
+
if (error instanceof z2.ZodError) {
|
|
2331
|
+
const issues = error.issues.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`).join("\n");
|
|
2332
|
+
const overrideKeys = _ProviderRegistry.dynamicProviderOverrideKeys();
|
|
2333
|
+
if (overrideKeys.length > 0) {
|
|
2334
|
+
throw new InvalidExplicitConfigError(
|
|
2335
|
+
`Invalid provider environment override (${overrideKeys.join(", ")}):
|
|
2336
|
+
${issues}`,
|
|
2337
|
+
error
|
|
2338
|
+
);
|
|
2339
|
+
}
|
|
2340
|
+
throw new Error(`Unified provider config validation failed:
|
|
2341
|
+
${issues}`);
|
|
2342
|
+
}
|
|
2343
|
+
if (error instanceof TypeError && error.message.includes("_zod")) {
|
|
2344
|
+
throw new Error(
|
|
2345
|
+
`Schema validation failed due to undefined nested schema. This typically indicates incorrect Zod v4 syntax (e.g., z.record() requires two parameters). Original error: ${error.message}
|
|
2346
|
+
|
|
2347
|
+
Fix: Change z.record(z.string()) to z.record(z.string(), z.string()) in schema definitions.`
|
|
2348
|
+
);
|
|
2349
|
+
}
|
|
2350
|
+
throw error;
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
/**
|
|
2354
|
+
* Set a nested value in an object using underscore notation
|
|
2355
|
+
*
|
|
2356
|
+
* @param obj - Object to modify
|
|
2357
|
+
* @param path - Underscore-separated path (TIMEOUT_MS -> timeout_ms, MODELS_DEFAULT -> models.default)
|
|
2358
|
+
* @param value - Value to set
|
|
2359
|
+
*/
|
|
2360
|
+
static setNestedValue(obj, path, value, envKey) {
|
|
2361
|
+
const normalizedPath = path.toLowerCase();
|
|
2362
|
+
if (normalizedPath in obj) {
|
|
2363
|
+
obj[normalizedPath] = _ProviderRegistry.coerceOverrideValue(
|
|
2364
|
+
value,
|
|
2365
|
+
obj[normalizedPath],
|
|
2366
|
+
envKey
|
|
2367
|
+
);
|
|
2368
|
+
return;
|
|
2369
|
+
}
|
|
2370
|
+
const parts = normalizedPath.split("_");
|
|
2371
|
+
if (parts[0] === "models" && parts.length > 1) {
|
|
2372
|
+
if (typeof obj.models !== "object" || obj.models === null || Array.isArray(obj.models)) {
|
|
2373
|
+
obj.models = {};
|
|
2374
|
+
}
|
|
2375
|
+
const nestedPath = parts.slice(1).join("_");
|
|
2376
|
+
if (nestedPath === "default" && !("default" in obj.models)) {
|
|
2377
|
+
obj.models.default = value;
|
|
2378
|
+
return;
|
|
2379
|
+
}
|
|
2380
|
+
_ProviderRegistry.setNestedValue(
|
|
2381
|
+
obj.models,
|
|
2382
|
+
nestedPath,
|
|
2383
|
+
value,
|
|
2384
|
+
envKey
|
|
2385
|
+
);
|
|
2386
|
+
return;
|
|
2387
|
+
}
|
|
2388
|
+
for (let i = 1; i < parts.length; i++) {
|
|
2389
|
+
const firstKey = parts.slice(0, i).join("_");
|
|
2390
|
+
const restKey = parts.slice(i).join("_");
|
|
2391
|
+
if (firstKey in obj && typeof obj[firstKey] === "object" && obj[firstKey] !== null) {
|
|
2392
|
+
_ProviderRegistry.setNestedValue(
|
|
2393
|
+
obj[firstKey],
|
|
2394
|
+
restKey,
|
|
2395
|
+
value,
|
|
2396
|
+
envKey
|
|
2397
|
+
);
|
|
2398
|
+
return;
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
throw new InvalidExplicitConfigError(
|
|
2402
|
+
`Environment variable ${envKey} targets unknown provider configuration key '${normalizedPath}'.`
|
|
2403
|
+
);
|
|
2404
|
+
}
|
|
2405
|
+
/**
|
|
2406
|
+
* Parse environment variable value to appropriate type
|
|
2407
|
+
*
|
|
2408
|
+
* @param value - String value from environment
|
|
2409
|
+
* @returns Parsed value (boolean, number, or string)
|
|
2410
|
+
*/
|
|
2411
|
+
static coerceOverrideValue(value, destination, envKey) {
|
|
2412
|
+
if (typeof destination === "boolean") {
|
|
2413
|
+
const normalized = value.trim().toLowerCase();
|
|
2414
|
+
if (["1", "true", "yes", "on"].includes(normalized)) return true;
|
|
2415
|
+
if (["0", "false", "no", "off"].includes(normalized)) return false;
|
|
2416
|
+
throw new InvalidExplicitConfigError(
|
|
2417
|
+
`Environment variable ${envKey} must be a boolean (true/false, yes/no, on/off, or 1/0).`
|
|
2418
|
+
);
|
|
2419
|
+
}
|
|
2420
|
+
if (typeof destination === "number") {
|
|
2421
|
+
const numeric = Number(value);
|
|
2422
|
+
if (Number.isFinite(numeric)) return numeric;
|
|
2423
|
+
throw new InvalidExplicitConfigError(
|
|
2424
|
+
`Environment variable ${envKey} must be a finite number.`
|
|
2425
|
+
);
|
|
2426
|
+
}
|
|
2427
|
+
return value;
|
|
2428
|
+
}
|
|
2429
|
+
/**
|
|
2430
|
+
* Get global defaults
|
|
2431
|
+
*
|
|
2432
|
+
* @returns Global defaults configuration
|
|
2433
|
+
*/
|
|
2434
|
+
static getDefaults() {
|
|
2435
|
+
const registry = _ProviderRegistry.getActiveRegistry();
|
|
2436
|
+
return registry.defaults;
|
|
2437
|
+
}
|
|
2438
|
+
/**
|
|
2439
|
+
* Get configuration metadata
|
|
2440
|
+
*
|
|
2441
|
+
* @returns Configuration metadata
|
|
2442
|
+
*/
|
|
2443
|
+
static getMetadata() {
|
|
2444
|
+
const registry = _ProviderRegistry.getActiveRegistry();
|
|
2445
|
+
return registry.metadata;
|
|
2446
|
+
}
|
|
2447
|
+
/**
|
|
2448
|
+
* Resolve a model name for a specific provider
|
|
2449
|
+
* Applies model mappings and validates against allowed patterns
|
|
2450
|
+
*
|
|
2451
|
+
* @param providerId - Provider identifier
|
|
2452
|
+
* @param model - Model name to resolve (may be generic like 'gpt-4')
|
|
2453
|
+
* @returns Resolved provider-specific model name
|
|
2454
|
+
*/
|
|
2455
|
+
static resolveModel(providerId, model, registryOverride) {
|
|
2456
|
+
const config = _ProviderRegistry.getProviderConfig(providerId, registryOverride);
|
|
2457
|
+
const trimmedModel = !model || model.trim() === "" ? config.models.default : model.trim();
|
|
2458
|
+
if (trimmedModel in config.models.mappings) {
|
|
2459
|
+
const mapped = config.models.mappings[trimmedModel];
|
|
2460
|
+
if (mapped !== void 0) {
|
|
2461
|
+
return mapped;
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
for (const pattern of config.models.allowed_patterns) {
|
|
2465
|
+
let regex;
|
|
2466
|
+
try {
|
|
2467
|
+
regex = new RegExp(pattern);
|
|
2468
|
+
} catch (error) {
|
|
2469
|
+
debugLog(
|
|
2470
|
+
`Skipping invalid allowed_patterns regex for provider '${providerId}': ${pattern} (${error instanceof Error ? error.message : String(error)})`
|
|
2471
|
+
);
|
|
2472
|
+
continue;
|
|
2473
|
+
}
|
|
2474
|
+
if (regex.test(trimmedModel)) {
|
|
2475
|
+
return trimmedModel;
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
const availableModels = config.models.available.map((info) => info.id);
|
|
2479
|
+
if (availableModels.includes(trimmedModel)) {
|
|
2480
|
+
return trimmedModel;
|
|
2481
|
+
}
|
|
2482
|
+
const validModels = availableModels.length > 0 ? availableModels.join(", ") : "None";
|
|
2483
|
+
const validPatterns = config.models.allowed_patterns.length > 0 ? config.models.allowed_patterns.join(", ") : "None";
|
|
2484
|
+
const registrySources = !registryOverride || registryOverride === _ProviderRegistry.instance ? _ProviderRegistry.getLoadedConfigSources() : [];
|
|
2485
|
+
const sourceDetail = registrySources.length > 0 ? ` Registry sources: ${registrySources.join(", ")}.` : "";
|
|
2486
|
+
throw new Error(
|
|
2487
|
+
`Model '${trimmedModel}' is not available for provider '${providerId}'. Available models: ${validModels}. Allowed patterns: ${validPatterns}.${sourceDetail}`
|
|
2488
|
+
);
|
|
2489
|
+
}
|
|
2490
|
+
/**
|
|
2491
|
+
* Get bot identity configuration for cloud providers
|
|
2492
|
+
*
|
|
2493
|
+
* @param providerId - Provider identifier
|
|
2494
|
+
* @returns Bot identity config if provider is cloud-based, undefined otherwise
|
|
2495
|
+
*/
|
|
2496
|
+
static getBotIdentity(providerId) {
|
|
2497
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2498
|
+
return config.bot_identity;
|
|
2499
|
+
}
|
|
2500
|
+
/**
|
|
2501
|
+
* Get timeout for a specific provider
|
|
2502
|
+
*
|
|
2503
|
+
* @param providerId - Provider identifier
|
|
2504
|
+
* @returns Timeout in milliseconds
|
|
2505
|
+
*/
|
|
2506
|
+
static getTimeout(providerId) {
|
|
2507
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2508
|
+
return config.timeout_ms;
|
|
2509
|
+
}
|
|
2510
|
+
/**
|
|
2511
|
+
* Get retry configuration for a specific provider
|
|
2512
|
+
*
|
|
2513
|
+
* @param providerId - Provider identifier
|
|
2514
|
+
* @returns Retry configuration with defaults applied
|
|
2515
|
+
*/
|
|
2516
|
+
static getRetryConfig(providerId) {
|
|
2517
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2518
|
+
return config.retry || _ProviderRegistry.getDefaults().retry;
|
|
2519
|
+
}
|
|
2520
|
+
/**
|
|
2521
|
+
* Get circuit breaker configuration for a specific provider
|
|
2522
|
+
*
|
|
2523
|
+
* @param providerId - Provider identifier
|
|
2524
|
+
* @returns Circuit breaker configuration with defaults applied
|
|
2525
|
+
*/
|
|
2526
|
+
static getCircuitBreakerConfig(providerId) {
|
|
2527
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2528
|
+
return config.circuit_breaker || _ProviderRegistry.getDefaults().circuit_breaker;
|
|
2529
|
+
}
|
|
2530
|
+
/**
|
|
2531
|
+
* Get memory configuration for a specific provider
|
|
2532
|
+
*
|
|
2533
|
+
* @param providerId - Provider identifier
|
|
2534
|
+
* @returns Memory configuration
|
|
2535
|
+
*/
|
|
2536
|
+
static getMemoryConfig(providerId) {
|
|
2537
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2538
|
+
return config.memory;
|
|
2539
|
+
}
|
|
2540
|
+
/**
|
|
2541
|
+
* Get polling configuration for a specific provider
|
|
2542
|
+
*
|
|
2543
|
+
* @param providerId - Provider identifier
|
|
2544
|
+
* @returns Polling configuration if provider supports it, default otherwise
|
|
2545
|
+
*/
|
|
2546
|
+
static getPollingConfig(providerId) {
|
|
2547
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2548
|
+
return config.polling || _ProviderRegistry.getDefaults().polling;
|
|
2549
|
+
}
|
|
2550
|
+
/**
|
|
2551
|
+
* Get pricing configuration for a specific provider
|
|
2552
|
+
*
|
|
2553
|
+
* @param providerId - Provider identifier
|
|
2554
|
+
* @returns Pricing configuration if available, undefined otherwise
|
|
2555
|
+
*/
|
|
2556
|
+
static getProviderPricing(providerId) {
|
|
2557
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2558
|
+
return config.pricing;
|
|
2559
|
+
}
|
|
2560
|
+
/**
|
|
2561
|
+
* Get model pricing for a specific provider and model
|
|
2562
|
+
*
|
|
2563
|
+
* @param providerId - Provider identifier
|
|
2564
|
+
* @param modelId - Model identifier
|
|
2565
|
+
* @returns Model pricing if available, undefined otherwise
|
|
2566
|
+
*/
|
|
2567
|
+
static getModelPricing(providerId, modelId) {
|
|
2568
|
+
const pricing = _ProviderRegistry.getProviderPricing(providerId);
|
|
2569
|
+
if (!pricing || !pricing.models) return void 0;
|
|
2570
|
+
return pricing.models[modelId];
|
|
2571
|
+
}
|
|
2572
|
+
/**
|
|
2573
|
+
* Resolve provider ID from model name using allowed_patterns
|
|
2574
|
+
*
|
|
2575
|
+
* @param model - Model name (e.g., 'gemini-2.5-flash', 'sonnet-4-5')
|
|
2576
|
+
* @returns Provider ID if model matches a pattern, undefined otherwise
|
|
2577
|
+
*/
|
|
2578
|
+
static resolveProviderByModel(model) {
|
|
2579
|
+
if (!model) return void 0;
|
|
2580
|
+
const registry = _ProviderRegistry.getActiveRegistry();
|
|
2581
|
+
const isNonAuthoritativeOwnershipPattern = (pattern) => {
|
|
2582
|
+
const normalized = pattern.trim();
|
|
2583
|
+
return normalized === ".*" || normalized === "^.*$" || normalized === CURSOR_ID_SYNTAX_ADMISSION_PATTERN;
|
|
2584
|
+
};
|
|
2585
|
+
const matches = [];
|
|
2586
|
+
for (const [providerId, provider] of Object.entries(registry.providers)) {
|
|
2587
|
+
if (!provider.enabled) continue;
|
|
2588
|
+
const patterns = provider.models.allowed_patterns || [];
|
|
2589
|
+
let providerMatched = false;
|
|
2590
|
+
for (const pattern of patterns) {
|
|
2591
|
+
try {
|
|
2592
|
+
const regex = new RegExp(pattern, "i");
|
|
2593
|
+
if (regex.test(model)) {
|
|
2594
|
+
if (isNonAuthoritativeOwnershipPattern(pattern)) {
|
|
2595
|
+
continue;
|
|
2596
|
+
}
|
|
2597
|
+
providerMatched = true;
|
|
2598
|
+
break;
|
|
2599
|
+
}
|
|
2600
|
+
} catch (error) {
|
|
2601
|
+
emitWarning(
|
|
2602
|
+
"CFG-003",
|
|
2603
|
+
{
|
|
2604
|
+
taskId: "provider-registry",
|
|
2605
|
+
subsystem: "config",
|
|
2606
|
+
executionPhase: "setup"
|
|
2607
|
+
},
|
|
2608
|
+
{
|
|
2609
|
+
severity: "WARN" /* WARN */,
|
|
2610
|
+
metadata: {
|
|
2611
|
+
providerId,
|
|
2612
|
+
pattern,
|
|
2613
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2614
|
+
operation: "resolveProviderByModel"
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
);
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
if (providerMatched) {
|
|
2621
|
+
matches.push(providerId);
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
if (matches.length === 1) {
|
|
2625
|
+
return matches[0];
|
|
2626
|
+
}
|
|
2627
|
+
return void 0;
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* Get plugins for a specific provider
|
|
2631
|
+
*
|
|
2632
|
+
* @param providerId - Provider identifier
|
|
2633
|
+
* @returns Array of plugins, or empty array if none defined
|
|
2634
|
+
*/
|
|
2635
|
+
static getProviderPlugins(providerId) {
|
|
2636
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2637
|
+
return config.plugins || [];
|
|
2638
|
+
}
|
|
2639
|
+
/**
|
|
2640
|
+
* Get options for a specific provider
|
|
2641
|
+
*
|
|
2642
|
+
* @param providerId - Provider identifier
|
|
2643
|
+
* @returns Provider options, or empty object if none defined
|
|
2644
|
+
*/
|
|
2645
|
+
static getProviderOptions(providerId) {
|
|
2646
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2647
|
+
return config.options || {};
|
|
2648
|
+
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Get requirements for a specific provider
|
|
2651
|
+
*
|
|
2652
|
+
* @param providerId - Provider identifier
|
|
2653
|
+
* @returns Provider requirements with both unconditional and conditional deps
|
|
2654
|
+
*/
|
|
2655
|
+
static getProviderRequirements(providerId) {
|
|
2656
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2657
|
+
return {
|
|
2658
|
+
requires: config.requires || [],
|
|
2659
|
+
requires_if: config.requires_if || {}
|
|
2660
|
+
};
|
|
2661
|
+
}
|
|
2662
|
+
/**
|
|
2663
|
+
* Get a specific plugin by ID from a provider
|
|
2664
|
+
*
|
|
2665
|
+
* @param providerId - Provider identifier
|
|
2666
|
+
* @param pluginId - Plugin identifier
|
|
2667
|
+
* @returns Plugin configuration if found, undefined otherwise
|
|
2668
|
+
*/
|
|
2669
|
+
static getPlugin(providerId, pluginId) {
|
|
2670
|
+
const plugins = _ProviderRegistry.getProviderPlugins(providerId);
|
|
2671
|
+
return plugins.find((p) => p.id === pluginId);
|
|
2672
|
+
}
|
|
2673
|
+
/**
|
|
2674
|
+
* Get a specific option by key from a provider
|
|
2675
|
+
*
|
|
2676
|
+
* @param providerId - Provider identifier
|
|
2677
|
+
* @param optionKey - Option key
|
|
2678
|
+
* @returns Provider option if found, undefined otherwise
|
|
2679
|
+
*/
|
|
2680
|
+
static getOption(providerId, optionKey) {
|
|
2681
|
+
const options = _ProviderRegistry.getProviderOptions(providerId);
|
|
2682
|
+
return options[optionKey];
|
|
2683
|
+
}
|
|
2684
|
+
/**
|
|
2685
|
+
* Get the default model for a provider, from static registry config.
|
|
2686
|
+
* For runtime-observed defaults, use provider-specific discovery.
|
|
2687
|
+
*
|
|
2688
|
+
* @param providerId - Provider identifier
|
|
2689
|
+
* @returns Default model ID, or undefined if not configured
|
|
2690
|
+
*/
|
|
2691
|
+
static getDefaultModel(providerId, registryOverride) {
|
|
2692
|
+
const config = _ProviderRegistry.getProviderConfig(providerId, registryOverride);
|
|
2693
|
+
return config.models.default || void 0;
|
|
2694
|
+
}
|
|
2695
|
+
/**
|
|
2696
|
+
* Get a model assigned to a provider-specific role, if configured.
|
|
2697
|
+
*
|
|
2698
|
+
* Roles encode product intent such as "quality" or "fast" without assuming
|
|
2699
|
+
* the provider default is suitable for every outcome strategy.
|
|
2700
|
+
*
|
|
2701
|
+
* @param providerId - Provider identifier
|
|
2702
|
+
* @param role - Model role name
|
|
2703
|
+
* @returns Resolved model ID for the role, or undefined if the role is not configured
|
|
2704
|
+
*/
|
|
2705
|
+
static getModelForRole(providerId, role, registryOverride) {
|
|
2706
|
+
const trimmedRole = role.trim();
|
|
2707
|
+
if (!trimmedRole) return void 0;
|
|
2708
|
+
const config = _ProviderRegistry.getProviderConfig(providerId, registryOverride);
|
|
2709
|
+
const configuredModel = config.models.roles?.[trimmedRole];
|
|
2710
|
+
if (!configuredModel) return void 0;
|
|
2711
|
+
return _ProviderRegistry.resolveModel(providerId, configuredModel, registryOverride);
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* Resolve a reviewer model across all enabled providers, excluding specified providers.
|
|
2715
|
+
*
|
|
2716
|
+
* Implements the cross-provider review rule from the Wave 2 design record:
|
|
2717
|
+
* reviewer != orchestrator provider != executor provider (and any additional
|
|
2718
|
+
* mutation-owner providers the caller passes). Callers pass the provider IDs
|
|
2719
|
+
* already assigned to other stages so this method returns the first remaining
|
|
2720
|
+
* provider that has a model for a role in the role chain.
|
|
2721
|
+
*
|
|
2722
|
+
* Default role chain mirrors judge-tier-selector.ts: `['reviewer', 'quality']`.
|
|
2723
|
+
* Callers that honor a configured `roles.reviewer.modelRole` should pass a
|
|
2724
|
+
* chain starting with that role (then the defaults) so automatic selection
|
|
2725
|
+
* does not silently ignore the configured role.
|
|
2726
|
+
*
|
|
2727
|
+
* Candidate order: when `providerPreference` is provided, those ids are
|
|
2728
|
+
* tried first (skipping excluded / disabled / unknown entries); remaining
|
|
2729
|
+
* enabled providers are then appended in registry `order`. With no
|
|
2730
|
+
* preference, only registry order is used (dormant-compatible).
|
|
2731
|
+
*
|
|
2732
|
+
* Returns null when no qualifying provider is found. Pure and static — reads
|
|
2733
|
+
* only from the loaded registry and applies no side effects.
|
|
2734
|
+
*
|
|
2735
|
+
* @param excludeProviders - Provider IDs to skip (e.g. orchestrator + executor + mutation owners)
|
|
2736
|
+
* @param options.roleChain - Model-role fallback chain (default: reviewer, quality)
|
|
2737
|
+
* @param options.providerPreference - Preferred provider order for selection
|
|
2738
|
+
* @returns Provider + resolved model + winning role, or null if none qualify
|
|
2739
|
+
*/
|
|
2740
|
+
static resolveReviewerModel(excludeProviders, options = {}, registryOverride) {
|
|
2741
|
+
const excludeSet = new Set(
|
|
2742
|
+
excludeProviders.map((p) => p.trim().toLowerCase()).filter((p) => p.length > 0)
|
|
2743
|
+
);
|
|
2744
|
+
const roleChain = options.roleChain && options.roleChain.length > 0 ? options.roleChain.map((r) => r.trim()).filter((r) => r.length > 0) : ["reviewer", "quality"];
|
|
2745
|
+
if (roleChain.length === 0) {
|
|
2746
|
+
return null;
|
|
2747
|
+
}
|
|
2748
|
+
const enabled = _ProviderRegistry.getEnabledProviders(registryOverride);
|
|
2749
|
+
const enabledById = new Map(enabled.map((p) => [p.id.toLowerCase(), p]));
|
|
2750
|
+
const ordered = [];
|
|
2751
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2752
|
+
for (const pref of options.providerPreference ?? []) {
|
|
2753
|
+
const key = pref.trim().toLowerCase();
|
|
2754
|
+
if (!key || seen.has(key) || excludeSet.has(key)) continue;
|
|
2755
|
+
const match = enabledById.get(key);
|
|
2756
|
+
if (match) {
|
|
2757
|
+
ordered.push(match);
|
|
2758
|
+
seen.add(key);
|
|
2759
|
+
}
|
|
2760
|
+
}
|
|
2761
|
+
for (const providerConfig of enabled) {
|
|
2762
|
+
const key = providerConfig.id.toLowerCase();
|
|
2763
|
+
if (seen.has(key) || excludeSet.has(key)) continue;
|
|
2764
|
+
ordered.push(providerConfig);
|
|
2765
|
+
seen.add(key);
|
|
2766
|
+
}
|
|
2767
|
+
for (const providerConfig of ordered) {
|
|
2768
|
+
const pid = providerConfig.id;
|
|
2769
|
+
for (const role of roleChain) {
|
|
2770
|
+
const model = _ProviderRegistry.getModelForRole(pid, role, registryOverride);
|
|
2771
|
+
if (model) {
|
|
2772
|
+
return { provider: pid, model, role };
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
return null;
|
|
2777
|
+
}
|
|
2778
|
+
/**
|
|
2779
|
+
* Get the list of available models for a provider, from static registry config.
|
|
2780
|
+
* `getDiscoveredModels()` currently returns this same static inventory.
|
|
2781
|
+
* For observation-backed IDs, call `getCachedProviderModelIds` from
|
|
2782
|
+
* `src/core/providers/model-discovery-cache.ts`.
|
|
2783
|
+
*
|
|
2784
|
+
* @param providerId - Provider identifier
|
|
2785
|
+
* @returns Array of available model IDs from the static registry
|
|
2786
|
+
*/
|
|
2787
|
+
static getAvailableModels(providerId) {
|
|
2788
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2789
|
+
return config.models.available.map((m) => m.id);
|
|
2790
|
+
}
|
|
2791
|
+
/**
|
|
2792
|
+
* Get static model mappings for a provider (logical name → native CLI ID).
|
|
2793
|
+
* For Cursor, also check getCachedCanonicalMappings() from
|
|
2794
|
+
* src/core/providers/cursor/model-discovery.ts for discovery-fed mappings.
|
|
2795
|
+
*
|
|
2796
|
+
* @param providerId - Provider identifier
|
|
2797
|
+
* @returns Record mapping logical model names to native CLI IDs
|
|
2798
|
+
*/
|
|
2799
|
+
static getMappings(providerId) {
|
|
2800
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2801
|
+
return cloneProviderRegistryValue(config.models.mappings);
|
|
2802
|
+
}
|
|
2803
|
+
/**
|
|
2804
|
+
* Return the static available-model list from this registry.
|
|
2805
|
+
*
|
|
2806
|
+
* Despite the name, this is not live discovery and does not read an
|
|
2807
|
+
* observation cache. It is equivalent to `getAvailableModels()`.
|
|
2808
|
+
*
|
|
2809
|
+
* Callers that need observation-backed IDs should import the cache reader:
|
|
2810
|
+
*
|
|
2811
|
+
* import { getCachedProviderModelIds } from
|
|
2812
|
+
* '../providers/model-discovery-cache.js';
|
|
2813
|
+
* const ids = getCachedProviderModelIds(providerId);
|
|
2814
|
+
*
|
|
2815
|
+
* That reader returns local cache evidence only (empty when none) and does
|
|
2816
|
+
* not fall back to this registry.
|
|
2817
|
+
*
|
|
2818
|
+
* @param providerId - Provider identifier
|
|
2819
|
+
* @returns Array of model IDs from the static registry
|
|
2820
|
+
*/
|
|
2821
|
+
static getDiscoveredModels(providerId) {
|
|
2822
|
+
const normalized = normalizeProviderConfigId(providerId);
|
|
2823
|
+
return _ProviderRegistry.getAvailableModels(normalized);
|
|
2824
|
+
}
|
|
2825
|
+
/**
|
|
2826
|
+
* Read a single capability flag for a provider.
|
|
2827
|
+
*
|
|
2828
|
+
* Returns the boolean value when explicitly set in providers.yaml, or
|
|
2829
|
+
* `undefined` when the flag is absent (caller must decide the default).
|
|
2830
|
+
*
|
|
2831
|
+
* @param providerId - Provider identifier
|
|
2832
|
+
* @param name - Capability key (e.g. 'supports_api_judge')
|
|
2833
|
+
* @returns boolean if set, undefined if not declared
|
|
2834
|
+
*/
|
|
2835
|
+
static getCapability(providerId, name) {
|
|
2836
|
+
const config = _ProviderRegistry.getProviderConfig(providerId);
|
|
2837
|
+
const value = config.capabilities[name];
|
|
2838
|
+
return typeof value === "boolean" ? value : void 0;
|
|
2839
|
+
}
|
|
2840
|
+
};
|
|
2841
|
+
function loadProviderRegistry(configPath) {
|
|
2842
|
+
return ProviderRegistry.load(configPath);
|
|
2843
|
+
}
|
|
2844
|
+
function getProviderConfig(providerId, registryOverride) {
|
|
2845
|
+
return ProviderRegistry.getProviderConfig(providerId, registryOverride);
|
|
2846
|
+
}
|
|
2847
|
+
function getCapability(providerId, name) {
|
|
2848
|
+
return ProviderRegistry.getCapability(providerId, name);
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2851
|
+
export {
|
|
2852
|
+
PROVIDER_CATALOG_SHA256,
|
|
2853
|
+
REFRESH_OVERLAY_SCHEMA_VERSION,
|
|
2854
|
+
OverlayModelAvailableEntrySchema,
|
|
2855
|
+
OverlayPricingRowSchema,
|
|
2856
|
+
getRefreshOverlayOperatorNotice,
|
|
2857
|
+
emptyRefreshOverlay,
|
|
2858
|
+
serializeRefreshOverlay,
|
|
2859
|
+
resolveRefreshOverlayDisposition,
|
|
2860
|
+
loadRefreshOverlayFile,
|
|
2861
|
+
fingerprintEnvironment,
|
|
2862
|
+
fingerprintFile,
|
|
2863
|
+
fingerprintFiles,
|
|
2864
|
+
combineCacheFingerprints,
|
|
2865
|
+
InvalidExplicitConfigError,
|
|
2866
|
+
isInvalidExplicitConfigError,
|
|
2867
|
+
isConfigValidityError,
|
|
2868
|
+
rethrowConfigValidityError,
|
|
2869
|
+
isRecognizedEnvVar,
|
|
2870
|
+
getEnvVarEntry,
|
|
2871
|
+
validateEnvironmentVars,
|
|
2872
|
+
isTrustedProjectRoot,
|
|
2873
|
+
formatProjectTrustInstruction,
|
|
2874
|
+
registerProviderRegistryReloadInvalidator,
|
|
2875
|
+
getConfiguredProviderRegistryPaths,
|
|
2876
|
+
getProviderRegistryInputPaths,
|
|
2877
|
+
RetryConfigSchema,
|
|
2878
|
+
CircuitBreakerConfigSchema,
|
|
2879
|
+
RateLimitEntrySchema,
|
|
2880
|
+
RateLimitsConfigSchema,
|
|
2881
|
+
MemoryConfigSchema,
|
|
2882
|
+
PollingConfigSchema,
|
|
2883
|
+
CLIConfigSchema,
|
|
2884
|
+
AuthConfigSchema,
|
|
2885
|
+
TemplatedAuthConfigSchema,
|
|
2886
|
+
ProbeExpectationSchema,
|
|
2887
|
+
CommandProbeSchema,
|
|
2888
|
+
ModelsDiscoverySchema,
|
|
2889
|
+
ModelInfoSchema,
|
|
2890
|
+
ModelAccessClassSchema,
|
|
2891
|
+
ModelAccessConfigSchema,
|
|
2892
|
+
ModelsConfigSchema,
|
|
2893
|
+
TemplatedModelsConfigSchema,
|
|
2894
|
+
CapabilitiesConfigSchema,
|
|
2895
|
+
TemplatedCapabilitiesConfigSchema,
|
|
2896
|
+
BotIdentityConfigSchema,
|
|
2897
|
+
EnvConfigSchema,
|
|
2898
|
+
ModelPricingSchema,
|
|
2899
|
+
ToolPricingSchema,
|
|
2900
|
+
SubscriptionPricingSchema,
|
|
2901
|
+
InfrastructurePricingSchema,
|
|
2902
|
+
ProviderPricingSchema,
|
|
2903
|
+
RefreshStrategyConfigSchema,
|
|
2904
|
+
DefaultPricingSchema,
|
|
2905
|
+
ConcurrencyConfigSchema,
|
|
2906
|
+
RouteConfigSchema,
|
|
2907
|
+
WorkspaceEditsConfigSchema,
|
|
2908
|
+
GenerationConfigSchema,
|
|
2909
|
+
TaskSettingsSchema,
|
|
2910
|
+
PluginVerifySchema,
|
|
2911
|
+
PluginConfigureStepSchema,
|
|
2912
|
+
RequirementSchema,
|
|
2913
|
+
PluginSchema,
|
|
2914
|
+
ProviderOptionSchema,
|
|
2915
|
+
ProviderOptionsSchema,
|
|
2916
|
+
ConditionalRequiresSchema,
|
|
2917
|
+
ProviderRequiresSchema,
|
|
2918
|
+
ApiConfigSchema,
|
|
2919
|
+
TemplatedCLIExecutionSchema,
|
|
2920
|
+
NativeProviderConfigSchema,
|
|
2921
|
+
TemplatedProviderConfigSchema,
|
|
2922
|
+
ProviderConfigSchema,
|
|
2923
|
+
DefaultsConfigSchema,
|
|
2924
|
+
MetadataConfigSchema,
|
|
2925
|
+
ProviderRegistryConfigSchema,
|
|
2926
|
+
ProviderRegistry,
|
|
2927
|
+
loadProviderRegistry,
|
|
2928
|
+
getProviderConfig,
|
|
2929
|
+
getCapability
|
|
2930
|
+
};
|
|
2931
|
+
//# sourceMappingURL=chunk-AT4TNPWW.js.map
|