@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.
Files changed (782) hide show
  1. package/.github/SECURITY.md +47 -0
  2. package/.nvmrc +1 -0
  3. package/.poetic/README.md +37 -0
  4. package/.poetic/providers/catalog.json +12051 -0
  5. package/.poetic/providers/pricing.json +1272 -0
  6. package/.poetic/providers/registry.json +3369 -0
  7. package/CHANGELOG.md +552 -0
  8. package/CODE_OF_CONDUCT.md +40 -0
  9. package/CONTRIBUTING.md +23 -0
  10. package/INSTALL.md +454 -0
  11. package/LICENSE +21 -0
  12. package/README.md +474 -0
  13. package/dist/BasicOptimizationCompetitionRunner-5H5TBYO4.js +153 -0
  14. package/dist/ExecutionTracker-UVONC4C6.js +16 -0
  15. package/dist/OptimizationConfig-7DFY2TST.js +17 -0
  16. package/dist/OptimizationEngine-JIMGP3LY.js +1597 -0
  17. package/dist/PromptStore-U6ZD3ZMQ.js +18 -0
  18. package/dist/actions-LUJPINLJ.js +322 -0
  19. package/dist/agent-ingest-3DJUJ7FU.js +53 -0
  20. package/dist/aggregator-DNCBINFO.js +12 -0
  21. package/dist/ai-judge-5QT5QJVU.js +156 -0
  22. package/dist/allowlist-grounding-RO6HKUFI.js +16 -0
  23. package/dist/allowlist-utils-23V7TJ3G.js +28 -0
  24. package/dist/anchored-turn-service-JULUCUIK.js +489 -0
  25. package/dist/api-transport-4TYTNLTJ.js +1087 -0
  26. package/dist/apply-completion-mode-AW2MOS3R.js +89 -0
  27. package/dist/artifact-migrator-23L45ISD.js +267 -0
  28. package/dist/ask-HWVV6QFR.js +135 -0
  29. package/dist/auth-5KEDKAPP.js +67 -0
  30. package/dist/auth-7TT3JINV.js +78 -0
  31. package/dist/auth-E6XUNZ5M.js +68 -0
  32. package/dist/auth-H3XDZE22.js +134 -0
  33. package/dist/auth-OC4E6633.js +71 -0
  34. package/dist/auth-S4CTX4GQ.js +44 -0
  35. package/dist/auth-YLH3S7EY.js +69 -0
  36. package/dist/auth-liveness-TDDEZY3T.js +46 -0
  37. package/dist/auto-optimizer-VPRWOWGU.js +80 -0
  38. package/dist/autoloop-cleanup-JOGKTLWA.js +109 -0
  39. package/dist/autoloop-evidence-gates-PCDALGVJ.js +38 -0
  40. package/dist/autoloop-gate-policy-Z7FVJVXV.js +175 -0
  41. package/dist/autoloop-helpers-2KTK43GL.js +22 -0
  42. package/dist/autoloop-ledger-W7QO62PX.js +96 -0
  43. package/dist/autoloop-ledger-subscriber-Z5RW5EIE.js +162 -0
  44. package/dist/autoloop-run-defaults-FERGRZGP.js +19 -0
  45. package/dist/autoloop-run-lock-CT2NWSV3.js +197 -0
  46. package/dist/autoloop-success-J2VKKBXQ.js +85 -0
  47. package/dist/autoloop-termination-summary-RN75F422.js +58 -0
  48. package/dist/autoloop-trajectory-XFIEXP5Z.js +282 -0
  49. package/dist/autoloop-wall-clock-T7ZVIQOC.js +12 -0
  50. package/dist/autonomous-loop-controller-PW4XVFGQ.js +4120 -0
  51. package/dist/backend-P3DAYRP7.js +29 -0
  52. package/dist/background-executor-CBN552V4.js +257 -0
  53. package/dist/backlog-execution-intent-U4XYPTV6.js +15 -0
  54. package/dist/backup-active-store-5WXG6SXT.js +17 -0
  55. package/dist/backup-telemetry-db-XGLXAA3N.js +254 -0
  56. package/dist/basic-competition-master-VCSBJVRN.js +344 -0
  57. package/dist/branch-archive-manager-RP6FP3ZC.js +254 -0
  58. package/dist/branch-cleanup-manager-RSHAI7YR.js +20 -0
  59. package/dist/build-gate-YHGRB4QB.js +71 -0
  60. package/dist/change-summary-WY7J5TOX.js +33 -0
  61. package/dist/chunk-23A26CSN.js +123 -0
  62. package/dist/chunk-27UTJD3M.js +265 -0
  63. package/dist/chunk-2A5CILN3.js +310 -0
  64. package/dist/chunk-2AQUWJPW.js +225 -0
  65. package/dist/chunk-2BZ53J6J.js +2344 -0
  66. package/dist/chunk-2DY5KNVM.js +276 -0
  67. package/dist/chunk-2EIA4RBE.js +659 -0
  68. package/dist/chunk-2IUXIGQD.js +1064 -0
  69. package/dist/chunk-2N42MS2Z.js +2193 -0
  70. package/dist/chunk-2QJ3H3L7.js +42 -0
  71. package/dist/chunk-2QLYTVYX.js +791 -0
  72. package/dist/chunk-2VSQMRCB.js +18 -0
  73. package/dist/chunk-2XQXYBM2.js +130 -0
  74. package/dist/chunk-2YFUIER7.js +426 -0
  75. package/dist/chunk-34CNP2HB.js +148 -0
  76. package/dist/chunk-35P3W3JX.js +456 -0
  77. package/dist/chunk-36PEBZAF.js +18 -0
  78. package/dist/chunk-3AOKYKA7.js +22 -0
  79. package/dist/chunk-3BCUNHKF.js +475 -0
  80. package/dist/chunk-3FLXLLB7.js +26 -0
  81. package/dist/chunk-3FOZ2VHV.js +100 -0
  82. package/dist/chunk-3G6FZCRF.js +106 -0
  83. package/dist/chunk-3M57DADF.js +44 -0
  84. package/dist/chunk-3S62LLWJ.js +543 -0
  85. package/dist/chunk-3ZPQLGV7.js +2904 -0
  86. package/dist/chunk-44N5WZZH.js +45 -0
  87. package/dist/chunk-45FPSA3B.js +125 -0
  88. package/dist/chunk-4BJ3O4RQ.js +929 -0
  89. package/dist/chunk-4BOP7T6L.js +2321 -0
  90. package/dist/chunk-4BTDUT2S.js +42 -0
  91. package/dist/chunk-4CSS7WVI.js +143 -0
  92. package/dist/chunk-4CUY7AFY.js +247 -0
  93. package/dist/chunk-4GSN5O5J.js +62 -0
  94. package/dist/chunk-4HN6DF7V.js +1027 -0
  95. package/dist/chunk-4IAPOG5V.js +415 -0
  96. package/dist/chunk-4IYIZQWV.js +48 -0
  97. package/dist/chunk-4NXPXE62.js +84 -0
  98. package/dist/chunk-4RCCF5BR.js +712 -0
  99. package/dist/chunk-4V7NAQ4R.js +19527 -0
  100. package/dist/chunk-4VJITV4P.js +445 -0
  101. package/dist/chunk-4YX7J6QL.js +1859 -0
  102. package/dist/chunk-527OBWQB.js +338 -0
  103. package/dist/chunk-5D4A7E3D.js +448 -0
  104. package/dist/chunk-5DLKYTQX.js +4003 -0
  105. package/dist/chunk-5EERLVZB.js +139 -0
  106. package/dist/chunk-5H72XE4H.js +256 -0
  107. package/dist/chunk-5HDP7XZG.js +91 -0
  108. package/dist/chunk-5LAMRH4X.js +969 -0
  109. package/dist/chunk-5LTN43AS.js +1972 -0
  110. package/dist/chunk-5RBHQYDB.js +2206 -0
  111. package/dist/chunk-5WCQRDRB.js +588 -0
  112. package/dist/chunk-5WRLK5KW.js +700 -0
  113. package/dist/chunk-5ZCXC23G.js +595 -0
  114. package/dist/chunk-6BM72ZMG.js +31 -0
  115. package/dist/chunk-6EDAJH2I.js +68 -0
  116. package/dist/chunk-6EQKFDBH.js +457 -0
  117. package/dist/chunk-6MFRHTRI.js +115 -0
  118. package/dist/chunk-6TZJRKNW.js +321 -0
  119. package/dist/chunk-6V7HGQFZ.js +20 -0
  120. package/dist/chunk-6VWVO2TU.js +3746 -0
  121. package/dist/chunk-6Y5TWI7H.js +146 -0
  122. package/dist/chunk-6Y5U7UFY.js +91 -0
  123. package/dist/chunk-6ZLAK3XG.js +14 -0
  124. package/dist/chunk-72XCRQED.js +34 -0
  125. package/dist/chunk-72YTZMAM.js +589 -0
  126. package/dist/chunk-73BBJOKA.js +263 -0
  127. package/dist/chunk-73NCTWKL.js +188 -0
  128. package/dist/chunk-77I6G4CO.js +1 -0
  129. package/dist/chunk-7DHRDWFS.js +3104 -0
  130. package/dist/chunk-7DNSNKJV.js +78 -0
  131. package/dist/chunk-7FMJVYBS.js +307 -0
  132. package/dist/chunk-7GDRQBQC.js +419 -0
  133. package/dist/chunk-7GPCEFUV.js +270 -0
  134. package/dist/chunk-7IL4A2PP.js +948 -0
  135. package/dist/chunk-7MMLMXO6.js +3679 -0
  136. package/dist/chunk-7QCZSLBH.js +1 -0
  137. package/dist/chunk-7R2WLDOS.js +62 -0
  138. package/dist/chunk-7T7RUJI7.js +949 -0
  139. package/dist/chunk-A2WKSVX7.js +43 -0
  140. package/dist/chunk-A3YGID55.js +133 -0
  141. package/dist/chunk-A722DEVA.js +14 -0
  142. package/dist/chunk-ACDIT7OP.js +1376 -0
  143. package/dist/chunk-ACKIPAOJ.js +302 -0
  144. package/dist/chunk-APPNGGN7.js +365 -0
  145. package/dist/chunk-APV6MK5E.js +137 -0
  146. package/dist/chunk-ASEP3M2W.js +968 -0
  147. package/dist/chunk-AT4TNPWW.js +2931 -0
  148. package/dist/chunk-ATVKCSGT.js +250 -0
  149. package/dist/chunk-AURFMVCD.js +899 -0
  150. package/dist/chunk-AX6GWE7V.js +47 -0
  151. package/dist/chunk-AY5EWJPF.js +385 -0
  152. package/dist/chunk-BAV2HJXS.js +194 -0
  153. package/dist/chunk-BBHRN366.js +89 -0
  154. package/dist/chunk-BBPSTTPA.js +1004 -0
  155. package/dist/chunk-BDATUDDJ.js +992 -0
  156. package/dist/chunk-BKE5PG5L.js +20414 -0
  157. package/dist/chunk-BLPHWMDK.js +797 -0
  158. package/dist/chunk-BSE4R6XD.js +322 -0
  159. package/dist/chunk-BXGMAU4A.js +396 -0
  160. package/dist/chunk-BXI4NXL3.js +507 -0
  161. package/dist/chunk-BZU2O43F.js +1125 -0
  162. package/dist/chunk-C3L6YQ7P.js +147 -0
  163. package/dist/chunk-C57KJOUQ.js +121 -0
  164. package/dist/chunk-CCV7BPSY.js +118 -0
  165. package/dist/chunk-CD7ISXA4.js +826 -0
  166. package/dist/chunk-CE5OZBYY.js +21 -0
  167. package/dist/chunk-CFBIG37O.js +154 -0
  168. package/dist/chunk-CJC6GZ46.js +457 -0
  169. package/dist/chunk-CKCDGXIV.js +408 -0
  170. package/dist/chunk-CKNX3TTP.js +10338 -0
  171. package/dist/chunk-CLKSETWE.js +10 -0
  172. package/dist/chunk-CP7H3HSP.js +1552 -0
  173. package/dist/chunk-CPLEWXNZ.js +66 -0
  174. package/dist/chunk-CQM3A35X.js +844 -0
  175. package/dist/chunk-CS6P76D3.js +103 -0
  176. package/dist/chunk-CTLUBNCW.js +622 -0
  177. package/dist/chunk-CUSRN6RJ.js +632 -0
  178. package/dist/chunk-D5EP5D2W.js +26 -0
  179. package/dist/chunk-D5RYINO7.js +412 -0
  180. package/dist/chunk-DBFS4HMH.js +751 -0
  181. package/dist/chunk-DC4ZYMXJ.js +115 -0
  182. package/dist/chunk-DCBZP442.js +9243 -0
  183. package/dist/chunk-DCYF7EKG.js +26 -0
  184. package/dist/chunk-DDMAFNUK.js +5351 -0
  185. package/dist/chunk-DF5SLDE4.js +966 -0
  186. package/dist/chunk-DJFW7SMX.js +348 -0
  187. package/dist/chunk-DQFLLBJW.js +121 -0
  188. package/dist/chunk-DSFM56OA.js +1203 -0
  189. package/dist/chunk-DTY4APYV.js +218 -0
  190. package/dist/chunk-DXH5JBRS.js +437 -0
  191. package/dist/chunk-E3NTPHEO.js +194 -0
  192. package/dist/chunk-E74LUIID.js +302 -0
  193. package/dist/chunk-EI57M5BI.js +194 -0
  194. package/dist/chunk-EJ4ZAWLV.js +305 -0
  195. package/dist/chunk-EJGCZGUF.js +1483 -0
  196. package/dist/chunk-EK2U3YEG.js +486 -0
  197. package/dist/chunk-ELMFYNV7.js +109 -0
  198. package/dist/chunk-ENRGKNR5.js +25 -0
  199. package/dist/chunk-ETYDXCK7.js +679 -0
  200. package/dist/chunk-EYRH3W74.js +239 -0
  201. package/dist/chunk-F23DIWNN.js +1024 -0
  202. package/dist/chunk-F5JO7HAS.js +94 -0
  203. package/dist/chunk-F7ER6ANO.js +174 -0
  204. package/dist/chunk-FATUVIIN.js +374 -0
  205. package/dist/chunk-FC23CTXV.js +322 -0
  206. package/dist/chunk-FD4ERYEG.js +22 -0
  207. package/dist/chunk-FH7WOJAE.js +79 -0
  208. package/dist/chunk-FHOWVDF5.js +1342 -0
  209. package/dist/chunk-FKAUPHMR.js +96 -0
  210. package/dist/chunk-FONNFJXA.js +137 -0
  211. package/dist/chunk-FQ7FSZRW.js +75 -0
  212. package/dist/chunk-FRG57FPM.js +240 -0
  213. package/dist/chunk-FUVP64ER.js +31 -0
  214. package/dist/chunk-FYOILAN5.js +6818 -0
  215. package/dist/chunk-G35UYQ6Z.js +69 -0
  216. package/dist/chunk-G36W2T2S.js +1143 -0
  217. package/dist/chunk-G3L2L5XZ.js +49 -0
  218. package/dist/chunk-G4THLFV3.js +148 -0
  219. package/dist/chunk-GAFJEYLK.js +29 -0
  220. package/dist/chunk-GFGYB2ZU.js +1689 -0
  221. package/dist/chunk-GG6KJYW6.js +85 -0
  222. package/dist/chunk-GHHFDU2U.js +55 -0
  223. package/dist/chunk-GHTZSQB7.js +57 -0
  224. package/dist/chunk-GK37ILCX.js +1231 -0
  225. package/dist/chunk-GKN3HMN4.js +2809 -0
  226. package/dist/chunk-GNVDBVJP.js +156 -0
  227. package/dist/chunk-GPEL3FBM.js +924 -0
  228. package/dist/chunk-GPSNGPZS.js +1604 -0
  229. package/dist/chunk-GSGD5E4C.js +30 -0
  230. package/dist/chunk-GSUQJJXQ.js +331 -0
  231. package/dist/chunk-GSV226X6.js +110 -0
  232. package/dist/chunk-H2AYQIHW.js +224 -0
  233. package/dist/chunk-H66DXFS5.js +1374 -0
  234. package/dist/chunk-H6G7QRMQ.js +35 -0
  235. package/dist/chunk-H7JAGHZT.js +59 -0
  236. package/dist/chunk-H7ZEFECA.js +316 -0
  237. package/dist/chunk-HAC6EHZZ.js +79 -0
  238. package/dist/chunk-HIO33P3G.js +19 -0
  239. package/dist/chunk-HMVQIPH3.js +547 -0
  240. package/dist/chunk-HOYBYAOA.js +257 -0
  241. package/dist/chunk-HX5P3CSP.js +1784 -0
  242. package/dist/chunk-I46EG2XQ.js +65 -0
  243. package/dist/chunk-I4NPDSCB.js +279 -0
  244. package/dist/chunk-I5WRT7ZR.js +514 -0
  245. package/dist/chunk-IC7I6YIJ.js +301 -0
  246. package/dist/chunk-IDCSOZVN.js +78 -0
  247. package/dist/chunk-IFCBYECK.js +112 -0
  248. package/dist/chunk-IFZCPEY2.js +66 -0
  249. package/dist/chunk-IKFP2KUR.js +48 -0
  250. package/dist/chunk-IRFBN336.js +878 -0
  251. package/dist/chunk-IUXNGKA6.js +152 -0
  252. package/dist/chunk-IV2RVAN7.js +1356 -0
  253. package/dist/chunk-IZYIQQ7X.js +53 -0
  254. package/dist/chunk-J3UUR7DE.js +210 -0
  255. package/dist/chunk-J54VUAY2.js +566 -0
  256. package/dist/chunk-J62KPGII.js +464 -0
  257. package/dist/chunk-J6P3FWWW.js +130 -0
  258. package/dist/chunk-JKBHJQMT.js +434 -0
  259. package/dist/chunk-JLS65NUQ.js +14 -0
  260. package/dist/chunk-JOSYEJKY.js +141 -0
  261. package/dist/chunk-JPKSXKNB.js +94 -0
  262. package/dist/chunk-JQNJB2BB.js +2440 -0
  263. package/dist/chunk-JRVNSWSQ.js +2626 -0
  264. package/dist/chunk-JSWMRQYG.js +28 -0
  265. package/dist/chunk-JZKNBBIB.js +152 -0
  266. package/dist/chunk-K54Y7MLK.js +160 -0
  267. package/dist/chunk-K65546RE.js +183 -0
  268. package/dist/chunk-KM3F7SYE.js +702 -0
  269. package/dist/chunk-KNDYMVWN.js +102 -0
  270. package/dist/chunk-KNT72VR6.js +132 -0
  271. package/dist/chunk-KP6YILMU.js +482 -0
  272. package/dist/chunk-KQEBSK3T.js +274 -0
  273. package/dist/chunk-KT6VHSPF.js +84 -0
  274. package/dist/chunk-KTMW65UX.js +14 -0
  275. package/dist/chunk-KZ5CJVBP.js +1813 -0
  276. package/dist/chunk-L4427KOE.js +26 -0
  277. package/dist/chunk-L6OM4A22.js +189 -0
  278. package/dist/chunk-L7E6XCRA.js +1042 -0
  279. package/dist/chunk-L7JZLXQL.js +173 -0
  280. package/dist/chunk-LAMKBTXX.js +40 -0
  281. package/dist/chunk-LDCF2MKN.js +132 -0
  282. package/dist/chunk-LEIIWPWQ.js +78 -0
  283. package/dist/chunk-LFTQVYBB.js +31 -0
  284. package/dist/chunk-LG3PDRTR.js +2872 -0
  285. package/dist/chunk-LGHII5ET.js +23 -0
  286. package/dist/chunk-LH5QY22X.js +1205 -0
  287. package/dist/chunk-LIVJ6266.js +438 -0
  288. package/dist/chunk-LKRAR3IH.js +276 -0
  289. package/dist/chunk-LO23NABI.js +3063 -0
  290. package/dist/chunk-LO3X5NLS.js +326 -0
  291. package/dist/chunk-LPITVM7M.js +339 -0
  292. package/dist/chunk-LR5IJIGV.js +810 -0
  293. package/dist/chunk-LRGMHROI.js +79 -0
  294. package/dist/chunk-LUVKFFWR.js +315 -0
  295. package/dist/chunk-LWCBNGH6.js +35 -0
  296. package/dist/chunk-LWTN3WRV.js +260 -0
  297. package/dist/chunk-M3HQYKQX.js +308 -0
  298. package/dist/chunk-M6GVSPEH.js +1016 -0
  299. package/dist/chunk-MF5HP6XV.js +221 -0
  300. package/dist/chunk-MHLCBZJB.js +328 -0
  301. package/dist/chunk-MN6PL4AN.js +120 -0
  302. package/dist/chunk-MOEY65Z6.js +5678 -0
  303. package/dist/chunk-MQ4WA34C.js +206 -0
  304. package/dist/chunk-MWHF5V7U.js +223 -0
  305. package/dist/chunk-MWHLBPNU.js +211 -0
  306. package/dist/chunk-MWK5UZQ3.js +1068 -0
  307. package/dist/chunk-MYLH2S4G.js +64 -0
  308. package/dist/chunk-MZ5WYKNA.js +28 -0
  309. package/dist/chunk-N4VTRA7K.js +131 -0
  310. package/dist/chunk-N5DX4JAK.js +12 -0
  311. package/dist/chunk-N65O4XTH.js +5011 -0
  312. package/dist/chunk-NEQUQHOX.js +223 -0
  313. package/dist/chunk-NGK6PEOG.js +25 -0
  314. package/dist/chunk-NJVD4PWE.js +1033 -0
  315. package/dist/chunk-NM6PMYY4.js +768 -0
  316. package/dist/chunk-NN4PJDHP.js +708 -0
  317. package/dist/chunk-NP2V3L7K.js +226 -0
  318. package/dist/chunk-NRLY536M.js +260 -0
  319. package/dist/chunk-NRNE225N.js +1270 -0
  320. package/dist/chunk-NS2K2GTP.js +605 -0
  321. package/dist/chunk-NS33V3IM.js +51 -0
  322. package/dist/chunk-NSHASMZZ.js +71 -0
  323. package/dist/chunk-NWOYOA6H.js +378 -0
  324. package/dist/chunk-NWRUSEXG.js +322 -0
  325. package/dist/chunk-NZGDAWIP.js +1905 -0
  326. package/dist/chunk-O47UOKU3.js +395 -0
  327. package/dist/chunk-O4G2W3ST.js +9831 -0
  328. package/dist/chunk-O6V4PNLO.js +63 -0
  329. package/dist/chunk-OA4GPILI.js +624 -0
  330. package/dist/chunk-OGMSYL6J.js +227 -0
  331. package/dist/chunk-OIS7J26S.js +319 -0
  332. package/dist/chunk-OMX5VL43.js +79 -0
  333. package/dist/chunk-ON3G73BU.js +264 -0
  334. package/dist/chunk-OPYFYTWQ.js +220 -0
  335. package/dist/chunk-OQ6K46CK.js +1734 -0
  336. package/dist/chunk-OYZYO7TV.js +47 -0
  337. package/dist/chunk-OZ4REHIN.js +4386 -0
  338. package/dist/chunk-P47VN5F4.js +282 -0
  339. package/dist/chunk-P5I4X7A7.js +353 -0
  340. package/dist/chunk-P6VQROCO.js +594 -0
  341. package/dist/chunk-P7CQGPLS.js +30 -0
  342. package/dist/chunk-PCAGC5MR.js +1763 -0
  343. package/dist/chunk-PFTQBXS6.js +5181 -0
  344. package/dist/chunk-PGSPX4SU.js +15 -0
  345. package/dist/chunk-PIKLF7BM.js +432 -0
  346. package/dist/chunk-PJWJ3SAV.js +22 -0
  347. package/dist/chunk-PKIFMV72.js +100 -0
  348. package/dist/chunk-PL37JDNA.js +189 -0
  349. package/dist/chunk-PTH5E5XO.js +195 -0
  350. package/dist/chunk-PW6AXLQC.js +4128 -0
  351. package/dist/chunk-PYITM4N2.js +79 -0
  352. package/dist/chunk-PZ5AY32C.js +10 -0
  353. package/dist/chunk-Q3RO7N35.js +45 -0
  354. package/dist/chunk-Q3WIC6GQ.js +2670 -0
  355. package/dist/chunk-Q5XIXSHX.js +271 -0
  356. package/dist/chunk-QGJDMEOV.js +34 -0
  357. package/dist/chunk-QNOB37UH.js +58 -0
  358. package/dist/chunk-QOCOVLUH.js +462 -0
  359. package/dist/chunk-QTCJ5CC5.js +172 -0
  360. package/dist/chunk-QVFV5IP2.js +232 -0
  361. package/dist/chunk-QVZMFDYG.js +29 -0
  362. package/dist/chunk-R35PEUKH.js +511 -0
  363. package/dist/chunk-R4UWBC35.js +200 -0
  364. package/dist/chunk-R6MLCREW.js +44 -0
  365. package/dist/chunk-R6W23LKN.js +254 -0
  366. package/dist/chunk-R7XDDX2A.js +4007 -0
  367. package/dist/chunk-RDFRCT64.js +168 -0
  368. package/dist/chunk-RE5VZDFQ.js +58 -0
  369. package/dist/chunk-RGROYC2G.js +638 -0
  370. package/dist/chunk-RGWHUI5E.js +68 -0
  371. package/dist/chunk-RHVG6UNL.js +205 -0
  372. package/dist/chunk-RI4EX2QE.js +18 -0
  373. package/dist/chunk-RJAAKDRX.js +17 -0
  374. package/dist/chunk-ROMHOSMQ.js +185 -0
  375. package/dist/chunk-RWREC3KJ.js +517 -0
  376. package/dist/chunk-RYNETRDJ.js +118 -0
  377. package/dist/chunk-RZY7RKM5.js +500 -0
  378. package/dist/chunk-S2MNWFAG.js +52 -0
  379. package/dist/chunk-S2VQCZO4.js +22 -0
  380. package/dist/chunk-S54MKU6V.js +117 -0
  381. package/dist/chunk-S5OIDFRM.js +302 -0
  382. package/dist/chunk-SCW4ZF6R.js +150 -0
  383. package/dist/chunk-SLS2N4PH.js +2213 -0
  384. package/dist/chunk-SNLBO4BF.js +247 -0
  385. package/dist/chunk-SP3LFU6B.js +60 -0
  386. package/dist/chunk-SQQTDDQA.js +537 -0
  387. package/dist/chunk-STV6LYYE.js +45 -0
  388. package/dist/chunk-SURZ2WFE.js +326 -0
  389. package/dist/chunk-SZ7DL357.js +1047 -0
  390. package/dist/chunk-T5E4NQCM.js +5742 -0
  391. package/dist/chunk-TAJPCXSB.js +13 -0
  392. package/dist/chunk-TAOOYK3P.js +358 -0
  393. package/dist/chunk-TDSEX5CF.js +24 -0
  394. package/dist/chunk-TFTGP7Z7.js +174 -0
  395. package/dist/chunk-TGON4N4O.js +197 -0
  396. package/dist/chunk-TGQZHDY2.js +2373 -0
  397. package/dist/chunk-TJJZ2OKV.js +6783 -0
  398. package/dist/chunk-TRSVUPCX.js +25 -0
  399. package/dist/chunk-TSXGRLPR.js +107 -0
  400. package/dist/chunk-U2S3YEX3.js +224 -0
  401. package/dist/chunk-U45RTRGY.js +818 -0
  402. package/dist/chunk-U6C3VVWS.js +13 -0
  403. package/dist/chunk-UDMS5AD3.js +307 -0
  404. package/dist/chunk-UGX7GI37.js +94 -0
  405. package/dist/chunk-UH3JJSHK.js +1 -0
  406. package/dist/chunk-UHRBTZYY.js +208 -0
  407. package/dist/chunk-UHT2KRG5.js +193 -0
  408. package/dist/chunk-UI2F6DJ5.js +118 -0
  409. package/dist/chunk-UMAKSB4Z.js +284 -0
  410. package/dist/chunk-UR2IBGIM.js +521 -0
  411. package/dist/chunk-UUH2RVKS.js +585 -0
  412. package/dist/chunk-UVJ4PJDK.js +4533 -0
  413. package/dist/chunk-V53UG2OT.js +9924 -0
  414. package/dist/chunk-V72RMBM4.js +48 -0
  415. package/dist/chunk-VBNCKCCI.js +16 -0
  416. package/dist/chunk-VNSYKC25.js +24 -0
  417. package/dist/chunk-VPHVFK4A.js +1984 -0
  418. package/dist/chunk-VTLNJQ44.js +133 -0
  419. package/dist/chunk-VTW7HP3R.js +100 -0
  420. package/dist/chunk-VVGEPBPS.js +218 -0
  421. package/dist/chunk-VVLLL7I4.js +166 -0
  422. package/dist/chunk-VX3UMWB7.js +483 -0
  423. package/dist/chunk-VXF4Q3FW.js +20 -0
  424. package/dist/chunk-W3JMT2YY.js +712 -0
  425. package/dist/chunk-WDUORIHF.js +877 -0
  426. package/dist/chunk-WDVTY4U6.js +148 -0
  427. package/dist/chunk-WIFZCHEG.js +12566 -0
  428. package/dist/chunk-WIRN3F75.js +736 -0
  429. package/dist/chunk-WMPU2UOV.js +82 -0
  430. package/dist/chunk-WTOKKE2V.js +784 -0
  431. package/dist/chunk-WX5IRLF6.js +740 -0
  432. package/dist/chunk-WZ6U3O7I.js +1581 -0
  433. package/dist/chunk-XAONGNST.js +57 -0
  434. package/dist/chunk-XB5YLCLB.js +13 -0
  435. package/dist/chunk-XEP5NQ5Y.js +688 -0
  436. package/dist/chunk-XGYF2QMZ.js +351 -0
  437. package/dist/chunk-XHEKQENB.js +255 -0
  438. package/dist/chunk-XNO4FM6X.js +1124 -0
  439. package/dist/chunk-XPHKYHO4.js +878 -0
  440. package/dist/chunk-XPK2I4NC.js +405 -0
  441. package/dist/chunk-XPU2XADL.js +2175 -0
  442. package/dist/chunk-XQD2B6BB.js +507 -0
  443. package/dist/chunk-XT2ZQVTC.js +558 -0
  444. package/dist/chunk-XTXJGGUV.js +351 -0
  445. package/dist/chunk-XUXVDPSZ.js +50 -0
  446. package/dist/chunk-XV7NZL4B.js +57 -0
  447. package/dist/chunk-XZE4XARH.js +563 -0
  448. package/dist/chunk-XZYR5EDO.js +152 -0
  449. package/dist/chunk-Y3J4JMTU.js +61 -0
  450. package/dist/chunk-Y55LZN5U.js +52 -0
  451. package/dist/chunk-Y5VN7DMP.js +112 -0
  452. package/dist/chunk-Y67VAHN4.js +459 -0
  453. package/dist/chunk-YAXSKEUH.js +3544 -0
  454. package/dist/chunk-YB3JD4E6.js +975 -0
  455. package/dist/chunk-YESZJFK6.js +220 -0
  456. package/dist/chunk-YGXKOBQQ.js +292 -0
  457. package/dist/chunk-YMX76IOS.js +31 -0
  458. package/dist/chunk-YOTXESEH.js +257 -0
  459. package/dist/chunk-YTYIEZQY.js +119 -0
  460. package/dist/chunk-YVORHQ2S.js +579 -0
  461. package/dist/chunk-Z2CUQDAR.js +3429 -0
  462. package/dist/chunk-Z2KYOFHS.js +7000 -0
  463. package/dist/chunk-Z6PC7QX6.js +161 -0
  464. package/dist/chunk-ZDTGECTN.js +235 -0
  465. package/dist/chunk-ZIPWI2LY.js +151 -0
  466. package/dist/chunk-ZSKKMTQJ.js +554 -0
  467. package/dist/chunk-ZTT5IVPY.js +1160 -0
  468. package/dist/chunk-ZX65UI5W.js +78 -0
  469. package/dist/chunk-ZYG7GGKO.js +218 -0
  470. package/dist/chunk-ZZZUL4OF.js +38 -0
  471. package/dist/cli-utils-IXL26KJT.js +40 -0
  472. package/dist/cli-validation-WLXWLUJL.js +111 -0
  473. package/dist/commit-utils-P7CRJF5N.js +202 -0
  474. package/dist/compete-config-resolver-R5ULXMYH.js +76 -0
  475. package/dist/compete-request-62JESVET.js +364 -0
  476. package/dist/compete-results-QEPG6FZX.js +208 -0
  477. package/dist/competition-outcome-tracker-R32OOZ43.js +38 -0
  478. package/dist/config-JCOKXOQT.js +166 -0
  479. package/dist/config-audit-EL3GHXS7.js +360 -0
  480. package/dist/config-explain-TNILDEVJ.js +12 -0
  481. package/dist/config-loader-VPFPFO4B.js +38 -0
  482. package/dist/config-manager-7T4E2BQO.js +67 -0
  483. package/dist/config-validator-KKOHOW7O.js +72 -0
  484. package/dist/cost-YC42XUF3.js +53 -0
  485. package/dist/coverage-orchestrator-CISNKJC2.js +772 -0
  486. package/dist/coverage-scanner-YVD62MLH.js +12 -0
  487. package/dist/createCompetitionRunner-LJG6ZQSO.js +46 -0
  488. package/dist/data-migration-state-VJK64DLT.js +31 -0
  489. package/dist/db-migrator-XSEIOGWY.js +34 -0
  490. package/dist/discovery-JGYGDD25.js +25 -0
  491. package/dist/doctor-GJOYE7AE.js +186 -0
  492. package/dist/domain-analyzer-AWF3RP6E.js +29 -0
  493. package/dist/ensure-initialized-744DIZEZ.js +52 -0
  494. package/dist/entry.js +940 -0
  495. package/dist/environment-YS45U5ZI.js +81 -0
  496. package/dist/error-parser-core-PPZ36A4S.js +50 -0
  497. package/dist/escalation-ladder-MKTCEGSA.js +130 -0
  498. package/dist/evaluation-context-KV4GZNN7.js +35 -0
  499. package/dist/evidence-plan-resolver-GBSYSAPX.js +85 -0
  500. package/dist/execution-data-writer-3ODTBDLH.js +53 -0
  501. package/dist/execution-policy-applier-ZHD3DCF3.js +31 -0
  502. package/dist/execution-preflight-Z4Y64V3I.js +209 -0
  503. package/dist/execution-roles-R3DPPMD3.js +66 -0
  504. package/dist/exit-code-error-Z4SW2DVK.js +14 -0
  505. package/dist/external-temp-cleanup-N2RZH4QP.js +311 -0
  506. package/dist/factory-XBN7DFIM.js +149 -0
  507. package/dist/file-utils-XIVR2ZMA.js +47 -0
  508. package/dist/flywheel-autoloop-executor-UILGOFFK.js +249 -0
  509. package/dist/flywheel-competition-executor-JOBEXTRB.js +259 -0
  510. package/dist/flywheel-executor-6JFLA6J5.js +369 -0
  511. package/dist/flywheel-git-isolation-UC5NIEVU.js +48 -0
  512. package/dist/flywheel-manifest-5UC4VBMA.js +108 -0
  513. package/dist/flywheel-model-defaults-7CVKP53V.js +27 -0
  514. package/dist/flywheel-preflight-XEY5SHM6.js +104 -0
  515. package/dist/flywheel-resume-7HELH7QS.js +23 -0
  516. package/dist/flywheel-safety-7U7DPOAP.js +28 -0
  517. package/dist/flywheel-scope-decision-ZHKF6ZIN.js +11 -0
  518. package/dist/get-telemetry-logger-DPVWWIYY.js +73 -0
  519. package/dist/git-worktree-IY6V6DUO.js +18 -0
  520. package/dist/github-pr-manager-4LXEKJTA.js +211 -0
  521. package/dist/guidance-profile-config-E7XJL2VP.js +117 -0
  522. package/dist/guidance-profile-renderer-QK2YMAAP.js +21 -0
  523. package/dist/index-query-4JEUKA44.js +31 -0
  524. package/dist/index.js +108661 -0
  525. package/dist/instructions-6BURLQJC.js +64 -0
  526. package/dist/invoke-provider-auth-GRUYP44M.js +223 -0
  527. package/dist/judge-scoring.json +80 -0
  528. package/dist/judge-test.js +555 -0
  529. package/dist/lab-mode-OTWVHN63.js +39 -0
  530. package/dist/lab-utils-BJRFLGK4.js +23 -0
  531. package/dist/linux-host-class-UY4KVLFD.js +29 -0
  532. package/dist/llm-judge-executor-F7Z3HO77.js +133 -0
  533. package/dist/local-executor-CEHWE2PL.js +223 -0
  534. package/dist/logger-33TR6EE5.js +72 -0
  535. package/dist/loop-spec-XTLQAVZ7.js +191 -0
  536. package/dist/manager-2HJG5CLT.js +25 -0
  537. package/dist/matrix-prompt-builder-6UDN5X3F.js +497 -0
  538. package/dist/matrix-result-parser-7W35EUOV.js +15 -0
  539. package/dist/metadata-HQ43NDEK.js +22 -0
  540. package/dist/model-invocations-db-QBO4Y7WZ.js +38 -0
  541. package/dist/monitor-XGYBG2DW.js +72 -0
  542. package/dist/next-PB5ZXZKB.js +90 -0
  543. package/dist/next-ZBDK725T.js +69 -0
  544. package/dist/optimization-config-resolver-O6WKR47U.js +75 -0
  545. package/dist/package-3YCWIQQ5.js +10 -0
  546. package/dist/parallel-orchestrator-NL7YJJU2.js +297 -0
  547. package/dist/parallel-worker.js +279 -0
  548. package/dist/parse-git-status-PIAF3OTP.js +10 -0
  549. package/dist/path-security-ETTH6TZL.js +39 -0
  550. package/dist/pattern-bank-UNJR5ADV.js +15 -0
  551. package/dist/plan-backlog-list-fast-VAGYBV3J.js +270 -0
  552. package/dist/plan-backlog-show-fast-SG2CZPW3.js +406 -0
  553. package/dist/plan-sprint-list-fast-LURAX47V.js +162 -0
  554. package/dist/plan-sprint-status-fast-FJAODCHD.js +208 -0
  555. package/dist/plan-task-status-fast-HNYBMQI4.js +349 -0
  556. package/dist/plan-to-flywheel-Z4U3GWPN.js +456 -0
  557. package/dist/planning-backlog-3CQ5QQBQ.js +319 -0
  558. package/dist/poetic-root-V5DNXEAE.js +17 -0
  559. package/dist/preflight-OPANWMME.js +12 -0
  560. package/dist/process-registry-PDZJPTAS.js +27 -0
  561. package/dist/process-scanner-C22SYXYD.js +22 -0
  562. package/dist/processes-KMQUD7HY.js +29 -0
  563. package/dist/processes-json-fast-IBDXZ6WW.js +135 -0
  564. package/dist/profile-SE5EVXAP.js +149 -0
  565. package/dist/prompts-WZZPGWBX.js +168 -0
  566. package/dist/protected-branches-RNTEX7ET.js +57 -0
  567. package/dist/provider-aware-resource-manager-QBTZJMNP.js +18 -0
  568. package/dist/provider-matrix-N5X57V3Y.js +154 -0
  569. package/dist/provider-matrix-renderer-MZDWKKID.js +139 -0
  570. package/dist/provider-output-forwarding-DERID3TP.js +30 -0
  571. package/dist/provider-registry-J5NRBJKI.js +128 -0
  572. package/dist/provider-temp-cleanup-KYGLF6YU.js +14 -0
  573. package/dist/prune-engine-Q6E2DXBN.js +451 -0
  574. package/dist/quality-gate-YRHMQAEI.js +70 -0
  575. package/dist/quickstart-FIRLKGJI.js +62 -0
  576. package/dist/readiness-VZTMSG6J.js +96 -0
  577. package/dist/registry-YODFY77A.js +153 -0
  578. package/dist/repair-helpers-TTV5FEF4.js +117 -0
  579. package/dist/repo-root-2IGD4H7X.js +22 -0
  580. package/dist/resolution-engine-D6TX6FRG.js +127 -0
  581. package/dist/resolve-provider-cli-O2P6XZBZ.js +35 -0
  582. package/dist/restore-telemetry-db-BQL6DTQF.js +360 -0
  583. package/dist/result-streamer-WEHW476R.js +19 -0
  584. package/dist/routing-events-DHPUZDDF.js +27 -0
  585. package/dist/routing-history-store-UWCEXAP3.js +46 -0
  586. package/dist/routing-planner-F5WQEUOM.js +160 -0
  587. package/dist/run-poetic-tui-J6LWRJUP.js +13517 -0
  588. package/dist/run-simulation.js +376 -0
  589. package/dist/runner-CS2TNGHA.js +1092 -0
  590. package/dist/runner-HHH7ZN2Z.js +1571 -0
  591. package/dist/safety-OCC4KJJR.js +64 -0
  592. package/dist/safety-stanza-7SV3HGG3.js +60 -0
  593. package/dist/sandbox-32QXJEMV.js +81 -0
  594. package/dist/sandbox-RSO7VP6V.js +94 -0
  595. package/dist/schema-extensions.sql +234 -0
  596. package/dist/security-2KI5XNDG.js +17 -0
  597. package/dist/setup-bb-plugin-QAQWZCV5.js +738 -0
  598. package/dist/setup-claude-code-P7BTTSPO.js +317 -0
  599. package/dist/setup-temp-cleanup-GASCWZ2I.js +20 -0
  600. package/dist/shared-utils-D6U6UREP.js +37 -0
  601. package/dist/simple-artifact-goal-OTXNGZY6.js +25 -0
  602. package/dist/sprint-UIXPYOXQ.js +338 -0
  603. package/dist/sprint-bridge-4BHMSC3M.js +68 -0
  604. package/dist/sprint-execution-service-2B7WHL5L.js +311 -0
  605. package/dist/sprint-manager-IDQUDNQI.js +91 -0
  606. package/dist/sqlite-wrapper-UDWCTNLJ.js +17 -0
  607. package/dist/stale-cleanup-orchestrator-XWXV7KCZ.js +62 -0
  608. package/dist/storage-access-F6ALDN4S.js +22 -0
  609. package/dist/synthesis-XD6EDVHF.js +185 -0
  610. package/dist/task-classifier-LNLXSHOM.js +494 -0
  611. package/dist/task-list-fast-PTMA4LUC.js +147 -0
  612. package/dist/task-manager-XAT7GOWB.js +93 -0
  613. package/dist/task-splitter-U7DJ7W6A.js +79 -0
  614. package/dist/task-type-detector-OLVOMXZO.js +21 -0
  615. package/dist/task-type-resolver-KKNQYSB4.js +42 -0
  616. package/dist/telemetry-5HWBBXLX.js +131 -0
  617. package/dist/telemetry-health-tracker-DMSSGBZ2.js +11 -0
  618. package/dist/telemetry-path-resolver-7ICSG276.js +28 -0
  619. package/dist/telemetry-reliability-XUOZNZZ6.js +125 -0
  620. package/dist/token-estimator-MEQUL3EJ.js +37 -0
  621. package/dist/transports-KNSSV2V4.js +255 -0
  622. package/dist/unified-cost-tracker-4TFRBVPR.js +35 -0
  623. package/dist/unified-state-cleanup-LJPF2BOW.js +276 -0
  624. package/dist/universal-cost-calculator-BAJV35GA.js +42 -0
  625. package/dist/user-agents-GHUGCSKN.js +22 -0
  626. package/dist/variant-delivery-state-KLRNG6XA.js +33 -0
  627. package/dist/variant-state-cleanup-MZGGLQAJ.js +280 -0
  628. package/dist/variant-success-PJXWE3ZV.js +12 -0
  629. package/dist/variant-worker-KUWKBLAH.js +4196 -0
  630. package/dist/variant-worker.js +24 -0
  631. package/dist/variants-JE2FSAQS.js +233 -0
  632. package/dist/verification-toolchains-V24UHW6Q.js +28 -0
  633. package/dist/verify-commands-H3DTCSGI.js +37 -0
  634. package/dist/warning-EGQGUUIO.js +12 -0
  635. package/dist/work-edge-RWEDWJZF.js +49 -0
  636. package/dist/work-item-writer-WHAVZXAY.js +19 -0
  637. package/dist/worker-7SA2VS2Y.js +1435 -0
  638. package/dist/worker.js +19 -0
  639. package/dist/worktree-metrics-3DFUYVYE.js +26 -0
  640. package/dist/writeback-VZKHYHSN.js +44 -0
  641. package/docs/CLI_REFERENCE.md +7042 -0
  642. package/docs/PROVIDER_SETUP.md +1570 -0
  643. package/docs/README.md +96 -0
  644. package/docs/TROUBLESHOOTING.md +2232 -0
  645. package/docs/getting-started/QUICK_START.md +294 -0
  646. package/docs/getting-started/README.md +188 -0
  647. package/docs/getting-started/SETUP.md +52 -0
  648. package/docs/reference/AGENT_CONTEXT.md +38 -0
  649. package/docs/reference/PROVIDER_RELEASE_TIERS.md +34 -0
  650. package/docs/reference/README.md +381 -0
  651. package/docs/reference/SECURITY.md +262 -0
  652. package/integrations/bb-plugin-poetic/README.md +362 -0
  653. package/integrations/bb-plugin-poetic/app.css +341 -0
  654. package/integrations/bb-plugin-poetic/app.tsx +5059 -0
  655. package/integrations/bb-plugin-poetic/package.json +45 -0
  656. package/integrations/bb-plugin-poetic/server.ts +444 -0
  657. package/integrations/bb-plugin-poetic/src/adapter.ts +3312 -0
  658. package/integrations/bb-plugin-poetic/src/backlog-authoring-model.ts +150 -0
  659. package/integrations/bb-plugin-poetic/src/backlog-authoring-schema.ts +355 -0
  660. package/integrations/bb-plugin-poetic/src/backlog-authoring-service.ts +419 -0
  661. package/integrations/bb-plugin-poetic/src/backlog-authoring-view.ts +1026 -0
  662. package/integrations/bb-plugin-poetic/src/competition-defaults-schema.ts +122 -0
  663. package/integrations/bb-plugin-poetic/src/competition-defaults-service.ts +105 -0
  664. package/integrations/bb-plugin-poetic/src/competition-defaults-view.ts +138 -0
  665. package/integrations/bb-plugin-poetic/src/contract.ts +615 -0
  666. package/integrations/bb-plugin-poetic/src/finalize-model.ts +205 -0
  667. package/integrations/bb-plugin-poetic/src/finalize-schema.ts +158 -0
  668. package/integrations/bb-plugin-poetic/src/finalize-service.ts +382 -0
  669. package/integrations/bb-plugin-poetic/src/finalize-view.ts +159 -0
  670. package/integrations/bb-plugin-poetic/src/judge-operations-readback.ts +303 -0
  671. package/integrations/bb-plugin-poetic/src/judge-operations-schema.ts +33 -0
  672. package/integrations/bb-plugin-poetic/src/judge-operations-view.ts +459 -0
  673. package/integrations/bb-plugin-poetic/src/model.ts +1302 -0
  674. package/integrations/bb-plugin-poetic/src/monitor-service.ts +233 -0
  675. package/integrations/bb-plugin-poetic/src/panel-read-ux.ts +97 -0
  676. package/integrations/bb-plugin-poetic/src/patch-preview-schema.ts +166 -0
  677. package/integrations/bb-plugin-poetic/src/patch-preview-service.ts +480 -0
  678. package/integrations/bb-plugin-poetic/src/patch-preview-view.ts +109 -0
  679. package/integrations/bb-plugin-poetic/src/planning-readback.ts +204 -0
  680. package/integrations/bb-plugin-poetic/src/planning-service.ts +594 -0
  681. package/integrations/bb-plugin-poetic/src/planning-workspace-schema.ts +95 -0
  682. package/integrations/bb-plugin-poetic/src/planning-workspace.ts +323 -0
  683. package/integrations/bb-plugin-poetic/src/poll-handoff.ts +136 -0
  684. package/integrations/bb-plugin-poetic/src/project-target-server.ts +21 -0
  685. package/integrations/bb-plugin-poetic/src/project-target.ts +45 -0
  686. package/integrations/bb-plugin-poetic/src/reference-index.ts +192 -0
  687. package/integrations/bb-plugin-poetic/src/repository-schema.ts +30 -0
  688. package/integrations/bb-plugin-poetic/src/result-explorer-view.ts +597 -0
  689. package/integrations/bb-plugin-poetic/src/result-readback-model.ts +163 -0
  690. package/integrations/bb-plugin-poetic/src/result-readback-schema.ts +319 -0
  691. package/integrations/bb-plugin-poetic/src/result-readback-service.ts +333 -0
  692. package/integrations/bb-plugin-poetic/src/run-page-view.ts +177 -0
  693. package/integrations/bb-plugin-poetic/src/setup-config-schema.ts +291 -0
  694. package/integrations/bb-plugin-poetic/src/setup-config-service.ts +590 -0
  695. package/integrations/bb-plugin-poetic/src/setup-config-view.ts +413 -0
  696. package/integrations/bb-plugin-poetic/src/sprint-close-model.ts +150 -0
  697. package/integrations/bb-plugin-poetic/src/sprint-close-schema.ts +136 -0
  698. package/integrations/bb-plugin-poetic/src/sprint-close-service.ts +341 -0
  699. package/integrations/bb-plugin-poetic/src/sprint-close-view.ts +116 -0
  700. package/integrations/bb-plugin-poetic/src/sprint-composition-model.ts +714 -0
  701. package/integrations/bb-plugin-poetic/src/sprint-composition-readback.ts +231 -0
  702. package/integrations/bb-plugin-poetic/src/sprint-composition-schema.ts +601 -0
  703. package/integrations/bb-plugin-poetic/src/sprint-composition-service.ts +775 -0
  704. package/integrations/bb-plugin-poetic/src/sprint-composition-view.ts +1221 -0
  705. package/integrations/bb-plugin-poetic/src/task-authoring-model.ts +567 -0
  706. package/integrations/bb-plugin-poetic/src/task-authoring-schema.ts +635 -0
  707. package/integrations/bb-plugin-poetic/src/task-authoring-service.ts +842 -0
  708. package/integrations/bb-plugin-poetic/src/task-authoring-view.ts +1227 -0
  709. package/integrations/bb-plugin-poetic/src/task-detail-readback.ts +56 -0
  710. package/integrations/bb-plugin-poetic/src/task-detail-schema.ts +144 -0
  711. package/integrations/bb-plugin-poetic/src/task-navigation.ts +446 -0
  712. package/integrations/bb-plugin-poetic/src/workbench-route.ts +74 -0
  713. package/integrations/bb-plugin-poetic/tests/host-contract.test.ts +773 -0
  714. package/integrations/bb-plugin-poetic/tsconfig.json +18 -0
  715. package/integrations/bb-plugin-poetic/types/PROVENANCE.json +52 -0
  716. package/integrations/bb-plugin-poetic/types/bb-plugin-sdk-app.d.ts +1444 -0
  717. package/integrations/bb-plugin-poetic/types/bb-plugin-sdk.d.ts +13030 -0
  718. package/integrations/bb-plugin-poetic/vitest.host.config.ts +71 -0
  719. package/npm-shrinkwrap.json +4950 -0
  720. package/package.json +331 -0
  721. package/schemas/README.md +80 -0
  722. package/schemas/config-v1.schema.json +136 -0
  723. package/schemas/execution-config.schema.json +47 -0
  724. package/schemas/judge-scoring.schema.json +370 -0
  725. package/schemas/poetic.config.schema.json +2214 -0
  726. package/schemas/provider-config.schema.json +203 -0
  727. package/schemas/telemetry-config.schema.json +79 -0
  728. package/schemas/user-preferences.schema.json +141 -0
  729. package/scripts/assert-node-runtime.mjs +140 -0
  730. package/scripts/preflight-native.mjs +49 -0
  731. package/scripts/preinstall-node-check.mjs +78 -0
  732. package/scripts/setup-git-hooks.mjs +24 -0
  733. package/scripts/sync.sh +2722 -0
  734. package/scripts/write-node-launcher.sh +108 -0
  735. package/src/resources/gemini/slash-packs/default/plan.toml +15 -0
  736. package/src/resources/gemini/slash-packs/default/summary.toml +16 -0
  737. package/src/resources/gemini/slash-packs/default/tests.toml +16 -0
  738. package/templates/.poetic/README.md +37 -0
  739. package/templates/.poetic/agents/README.md +296 -0
  740. package/templates/.poetic/agents/api-documenter.md +147 -0
  741. package/templates/.poetic/agents/backend-architect.md +31 -0
  742. package/templates/.poetic/agents/code-reviewer.md +157 -0
  743. package/templates/.poetic/agents/data-scientist.md +179 -0
  744. package/templates/.poetic/agents/database-optimizer.md +145 -0
  745. package/templates/.poetic/agents/debugger.md +31 -0
  746. package/templates/.poetic/agents/deployment-engineer.md +164 -0
  747. package/templates/.poetic/agents/devops-troubleshooter.md +139 -0
  748. package/templates/.poetic/agents/frontend-developer.md +150 -0
  749. package/templates/.poetic/agents/javascript-pro.md +36 -0
  750. package/templates/.poetic/agents/performance-engineer.md +151 -0
  751. package/templates/.poetic/agents/python-pro.md +137 -0
  752. package/templates/.poetic/agents/test-automator.md +147 -0
  753. package/templates/.poetic/agents/typescript-pro.md +34 -0
  754. package/templates/.poetic/config/poetic.config.jsonc +69 -0
  755. package/templates/.poetic/config/project-context.template.json +6 -0
  756. package/templates/.poetic/config/task-type-aliases.presets/kanban.yaml +14 -0
  757. package/templates/.poetic/config/task-type-aliases.presets/scrum.yaml +17 -0
  758. package/templates/.poetic/config/task-type-aliases.presets/xp.yaml +12 -0
  759. package/templates/.poetic/config/task-type-aliases.yaml +28 -0
  760. package/templates/.poetic/gitignore.template +55 -0
  761. package/templates/.poetic/task-types/analysis.yaml +40 -0
  762. package/templates/.poetic/task-types/architecture.yaml +38 -0
  763. package/templates/.poetic/task-types/doc.yaml +35 -0
  764. package/templates/.poetic/task-types/feature.yaml +23 -0
  765. package/templates/.poetic/task-types/general.yaml +6 -0
  766. package/templates/.poetic/task-types/security.yaml +39 -0
  767. package/templates/AGENTS.template.md +99 -0
  768. package/templates/CLAUDE.template.md +1 -0
  769. package/templates/GEMINI.template.md +1 -0
  770. package/templates/builtin-workflows/code-review.yaml +73 -0
  771. package/templates/builtin-workflows/compete-streak.yaml +78 -0
  772. package/templates/builtin-workflows/hello-verify.yaml +10 -0
  773. package/templates/builtin-workflows/judge-regression.yaml +114 -0
  774. package/templates/builtin-workflows/skills/code-review/SKILL.md +60 -0
  775. package/templates/builtin-workflows/skills/hello-verify/SKILL.md +6 -0
  776. package/templates/guard-kit/GUARD_SETUP.md.template +255 -0
  777. package/templates/guard-kit/check.mjs.template +777 -0
  778. package/templates/guard-kit/config.json.template +6 -0
  779. package/templates/guard-kit/poetic-guard.yml.template +189 -0
  780. package/templates/profiles/README.md +56 -0
  781. package/templates/profiles/frontier-claude.json +27 -0
  782. package/templates/profiles/frontier-codex.json +26 -0
@@ -0,0 +1,2809 @@
1
+ import {
2
+ parseJsonWithContext
3
+ } from "./chunk-QVZMFDYG.js";
4
+ import {
5
+ sqlite_wrapper_default
6
+ } from "./chunk-45FPSA3B.js";
7
+ import {
8
+ applySqlitePragmas
9
+ } from "./chunk-QGJDMEOV.js";
10
+ import {
11
+ ProviderRegistry,
12
+ ProviderRegistryConfigSchema,
13
+ registerProviderRegistryReloadInvalidator
14
+ } from "./chunk-AT4TNPWW.js";
15
+ import {
16
+ getPackageRoot
17
+ } from "./chunk-XZE4XARH.js";
18
+ import {
19
+ emitWarning
20
+ } from "./chunk-EJGCZGUF.js";
21
+
22
+ // src/telemetry/model-invocations-db.ts
23
+ import { randomBytes } from "crypto";
24
+ import path3 from "path";
25
+
26
+ // src/telemetry/cost-precedence.ts
27
+ var SNAPSHOT_FIRST_COST_CENTS_SQL = `
28
+ CASE
29
+ WHEN e.cost_snapshot IS NOT NULL AND json_valid(e.cost_snapshot) THEN
30
+ COALESCE(
31
+ -- REAL (not INTEGER): snapshot costs carry sub-cent precision; an
32
+ -- integer cast truncates small invocations (< 1 cent) to zero.
33
+ CAST(json_extract(e.cost_snapshot, '$.totalCostCents') AS REAL),
34
+ e.computed_cost_cents
35
+ )
36
+ ELSE e.computed_cost_cents
37
+ END
38
+ `;
39
+ function resolveSnapshotFirstCostCents(input) {
40
+ const snapshotCost = input.costSnapshot?.totalCostCents;
41
+ if (typeof snapshotCost === "number" && Number.isFinite(snapshotCost)) {
42
+ return snapshotCost;
43
+ }
44
+ const computedCost = input.computedCostCents;
45
+ return typeof computedCost === "number" && Number.isFinite(computedCost) ? computedCost : null;
46
+ }
47
+ function finiteNumberOrZero(value) {
48
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
49
+ }
50
+ function resolveSnapshotFirstCostSnapshot(input) {
51
+ const totalCostCents = resolveSnapshotFirstCostCents(input);
52
+ if (totalCostCents === null) {
53
+ return null;
54
+ }
55
+ const snapshot = input.costSnapshot;
56
+ return {
57
+ inputCostCents: finiteNumberOrZero(snapshot?.inputCostCents),
58
+ outputCostCents: finiteNumberOrZero(snapshot?.outputCostCents),
59
+ cacheCostCents: finiteNumberOrZero(snapshot?.cacheCostCents),
60
+ toolCostCents: finiteNumberOrZero(snapshot?.toolCostCents),
61
+ infrastructureCostCents: finiteNumberOrZero(snapshot?.infrastructureCostCents),
62
+ totalCostCents,
63
+ currency: typeof snapshot?.currency === "string" && snapshot.currency ? snapshot.currency : "USD"
64
+ };
65
+ }
66
+
67
+ // src/telemetry/invocation-cost-enrichment.ts
68
+ import fs2 from "fs";
69
+ import path2 from "path";
70
+ import yaml2 from "js-yaml";
71
+
72
+ // src/core/config/model-registry.ts
73
+ import * as crypto from "crypto";
74
+ import * as fs from "fs";
75
+ import * as path from "path";
76
+ import yaml from "js-yaml";
77
+ import { z } from "zod";
78
+ var BillingModeSchema = z.enum(["metered", "flat_rate", "non_metered"]);
79
+ var CostSchemaZ = z.object({
80
+ prompt_per_1k: z.number().min(0).optional(),
81
+ completion_per_1k: z.number().min(0).optional(),
82
+ extra_fees: z.record(z.string(), z.number()).optional(),
83
+ billing_mode: BillingModeSchema.optional(),
84
+ billing_source: z.string().optional(),
85
+ pricing_source: z.string().optional(),
86
+ pricing_confidence: z.enum(["high", "medium", "low"]).optional(),
87
+ flat_rate_per_seat_month: z.number().min(0).optional(),
88
+ notes: z.string().optional()
89
+ }).superRefine((value, ctx) => {
90
+ const billingMode = value.billing_mode ?? "metered";
91
+ if (billingMode === "metered") {
92
+ if (typeof value.prompt_per_1k !== "number") {
93
+ ctx.addIssue({
94
+ code: z.ZodIssueCode.custom,
95
+ message: "Metered billing requires prompt_per_1k",
96
+ path: ["prompt_per_1k"]
97
+ });
98
+ }
99
+ if (typeof value.completion_per_1k !== "number") {
100
+ ctx.addIssue({
101
+ code: z.ZodIssueCode.custom,
102
+ message: "Metered billing requires completion_per_1k",
103
+ path: ["completion_per_1k"]
104
+ });
105
+ }
106
+ }
107
+ });
108
+ var ModelDefZ = z.object({
109
+ id: z.string().min(1),
110
+ display_name: z.string().min(1),
111
+ capabilities: z.array(z.string()),
112
+ costSchema: CostSchemaZ.optional()
113
+ });
114
+ var ProviderFrontmatterZ = z.object({
115
+ id: z.string().min(1),
116
+ display_name: z.string().min(1),
117
+ models: z.array(ModelDefZ).min(1, "At least one model is required"),
118
+ auth_hint: z.string().optional()
119
+ });
120
+ var IGNORED_PROVIDER_FILES = /* @__PURE__ */ new Set(["valid-provider.md", "minimal-provider.md"]);
121
+ function parseFrontmatter(content) {
122
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);
123
+ if (!match) {
124
+ throw new Error("Invalid frontmatter: must start with --- and have --- separator");
125
+ }
126
+ const [, yamlStr, markdown] = match;
127
+ const data = yaml.load(yamlStr);
128
+ return { data, content: markdown || "" };
129
+ }
130
+ function loadProviderFile(filePath) {
131
+ const content = fs.readFileSync(filePath, "utf-8");
132
+ const { data } = parseFrontmatter(content);
133
+ const normalized = normalizeProviderFrontmatter(data, filePath);
134
+ const frontmatter = ProviderFrontmatterZ.parse(normalized);
135
+ return {
136
+ providerId: frontmatter.id,
137
+ displayName: frontmatter.display_name,
138
+ models: frontmatter.models.map((m) => ({
139
+ modelId: m.id,
140
+ displayName: m.display_name,
141
+ capabilities: m.capabilities,
142
+ costSchema: m.costSchema
143
+ })),
144
+ authHint: frontmatter.auth_hint
145
+ };
146
+ }
147
+ function computeRegistryVersion(registry) {
148
+ const sortedProviders = [...registry.providers].sort((a, b) => a.providerId.localeCompare(b.providerId)).map((provider) => ({
149
+ authHint: provider.authHint,
150
+ displayName: provider.displayName,
151
+ models: [...provider.models || []].sort((a, b) => a.modelId.localeCompare(b.modelId)).map((model) => ({
152
+ capabilities: [...model.capabilities].sort(),
153
+ costSchema: model.costSchema,
154
+ displayName: model.displayName,
155
+ modelId: model.modelId
156
+ })),
157
+ providerId: provider.providerId
158
+ }));
159
+ const canonical = JSON.stringify(sortedProviders);
160
+ return crypto.createHash("sha256").update(canonical).digest("hex");
161
+ }
162
+ function loadProviderDirectory(providerDir) {
163
+ if (!fs.existsSync(providerDir)) {
164
+ throw new Error(`Providers directory not found: ${providerDir}`);
165
+ }
166
+ const providerMap = /* @__PURE__ */ new Map();
167
+ const files = fs.readdirSync(providerDir).filter((f) => f.endsWith(".md") && !IGNORED_PROVIDER_FILES.has(f));
168
+ if (files.length === 0) {
169
+ throw new Error(`No provider manifests found in ${providerDir}`);
170
+ }
171
+ for (const file of files) {
172
+ try {
173
+ const provider = loadProviderFile(path.join(providerDir, file));
174
+ providerMap.set(provider.providerId, provider);
175
+ } catch (error) {
176
+ throw new Error(
177
+ `Failed to load provider ${file}: ${error instanceof Error ? error.message : String(error)}`
178
+ );
179
+ }
180
+ }
181
+ return Array.from(providerMap.values());
182
+ }
183
+ function normalizeProviderFrontmatter(data, filePath) {
184
+ const providerId = getFirstString(data, ["id", "provider_id"]);
185
+ if (!providerId) {
186
+ throw new Error(`Provider manifest ${filePath} is missing required id/provider_id field`);
187
+ }
188
+ const displayName = getFirstString(data, ["display_name", "name"]) ?? providerId;
189
+ const authHint = getFirstString(data, ["auth_hint", "auth", "authHint"]);
190
+ const rawModels = Array.isArray(data.models) ? data.models : [];
191
+ const models = rawModels.map((model, index) => normalizeModel(model, filePath, index));
192
+ return {
193
+ id: providerId,
194
+ display_name: displayName,
195
+ auth_hint: authHint,
196
+ models
197
+ };
198
+ }
199
+ function normalizeModel(model, filePath, index) {
200
+ if (!model || typeof model !== "object") {
201
+ throw new Error(`Model entry at index ${index} in ${filePath} must be an object`);
202
+ }
203
+ const id = getFirstString(model, ["id", "model_id"]);
204
+ if (!id) {
205
+ throw new Error(
206
+ `Model entry at index ${index} in ${filePath} is missing required id/model_id field`
207
+ );
208
+ }
209
+ const displayName = getFirstString(model, ["display_name", "name"]) ?? id;
210
+ const capabilitiesRaw = Array.isArray(model.capabilities) ? model.capabilities : [];
211
+ const capabilities = capabilitiesRaw.map((capability) => String(capability));
212
+ const costSchema = normalizeCostSchema(
213
+ model.costSchema,
214
+ model.cost
215
+ );
216
+ return {
217
+ id,
218
+ display_name: displayName,
219
+ capabilities,
220
+ costSchema
221
+ };
222
+ }
223
+ function normalizeCostSchema(costSchema, legacyCost) {
224
+ const normalized = {};
225
+ if (costSchema && typeof costSchema === "object") {
226
+ const prompt = parseCurrency(
227
+ costSchema.prompt_per_1k ?? costSchema.promptPer1k
228
+ );
229
+ const completion = parseCurrency(
230
+ costSchema.completion_per_1k ?? costSchema.completionPer1k
231
+ );
232
+ const extraFees = parseExtraFees(
233
+ costSchema.extra_fees ?? costSchema.extraFees
234
+ );
235
+ const billingMode = parseBillingMode(
236
+ costSchema.billing_mode ?? costSchema.billingMode ?? costSchema.pricing_mode
237
+ );
238
+ const flatRate = parseCurrency(
239
+ costSchema.flat_rate_per_seat_month ?? costSchema.flat_rate ?? costSchema.seat_price
240
+ );
241
+ const billingSource = parseOptionalString(
242
+ costSchema.billing_source ?? costSchema.billingSource
243
+ );
244
+ const pricingSource = parseOptionalString(
245
+ costSchema.pricing_source ?? costSchema.pricingSource
246
+ );
247
+ const pricingConfidence = parsePricingConfidence(
248
+ costSchema.pricing_confidence ?? costSchema.pricingConfidence
249
+ );
250
+ const notes = parseOptionalString(
251
+ costSchema.notes ?? costSchema.description
252
+ );
253
+ if (prompt !== void 0) {
254
+ normalized.prompt_per_1k = prompt;
255
+ }
256
+ if (completion !== void 0) {
257
+ normalized.completion_per_1k = completion;
258
+ }
259
+ if (extraFees) {
260
+ normalized.extra_fees = extraFees;
261
+ }
262
+ if (billingMode) {
263
+ normalized.billing_mode = billingMode;
264
+ }
265
+ if (flatRate !== void 0) {
266
+ normalized.flat_rate_per_seat_month = flatRate;
267
+ }
268
+ if (billingSource) {
269
+ normalized.billing_source = billingSource;
270
+ }
271
+ if (pricingSource) {
272
+ normalized.pricing_source = pricingSource;
273
+ }
274
+ if (pricingConfidence) {
275
+ normalized.pricing_confidence = pricingConfidence;
276
+ }
277
+ if (notes) {
278
+ normalized.notes = notes;
279
+ }
280
+ }
281
+ if (legacyCost && typeof legacyCost === "object") {
282
+ const prompt = parseCurrency(
283
+ legacyCost.prompt_per_1k_tokens ?? legacyCost.prompt_per_1k ?? legacyCost.promptPer1k
284
+ );
285
+ const completion = parseCurrency(
286
+ legacyCost.completion_per_1k_tokens ?? legacyCost.completion_per_1k ?? legacyCost.completionPer1k
287
+ );
288
+ const extraFees = {};
289
+ const cacheRead = parseCurrency(
290
+ legacyCost.cache_read_per_1k_tokens ?? legacyCost.cache_read_per_1k
291
+ );
292
+ const cacheWrite = parseCurrency(
293
+ legacyCost.cache_write_per_1k_tokens ?? legacyCost.cache_write_per_1k
294
+ );
295
+ if (cacheRead !== void 0) {
296
+ extraFees.cacheReadPer1k = cacheRead;
297
+ }
298
+ if (cacheWrite !== void 0) {
299
+ extraFees.cacheWritePer1k = cacheWrite;
300
+ }
301
+ if (prompt !== void 0 && normalized.prompt_per_1k === void 0) {
302
+ normalized.prompt_per_1k = prompt;
303
+ }
304
+ if (completion !== void 0 && normalized.completion_per_1k === void 0) {
305
+ normalized.completion_per_1k = completion;
306
+ }
307
+ const normalizedExtraFees = Object.keys(extraFees).length > 0 ? extraFees : void 0;
308
+ if (normalizedExtraFees && !normalized.extra_fees) {
309
+ normalized.extra_fees = normalizedExtraFees;
310
+ }
311
+ }
312
+ if (Object.keys(normalized).length === 0) {
313
+ return void 0;
314
+ }
315
+ if (!normalized.billing_mode) {
316
+ normalized.billing_mode = "metered";
317
+ }
318
+ if (normalized.billing_mode === "metered" && (typeof normalized.prompt_per_1k !== "number" || typeof normalized.completion_per_1k !== "number")) {
319
+ return void 0;
320
+ }
321
+ return normalized;
322
+ }
323
+ function parseCurrency(value) {
324
+ if (typeof value === "number") {
325
+ return value;
326
+ }
327
+ if (typeof value === "string" && value.trim() !== "") {
328
+ const parsed = Number(value);
329
+ return Number.isFinite(parsed) ? parsed : void 0;
330
+ }
331
+ return void 0;
332
+ }
333
+ function parseExtraFees(value) {
334
+ if (!value || typeof value !== "object") {
335
+ return void 0;
336
+ }
337
+ const entries = {};
338
+ for (const [key, raw] of Object.entries(value)) {
339
+ const parsed = parseCurrency(raw);
340
+ if (parsed !== void 0) {
341
+ entries[key] = parsed;
342
+ }
343
+ }
344
+ return Object.keys(entries).length > 0 ? entries : void 0;
345
+ }
346
+ function parseBillingMode(value) {
347
+ if (typeof value !== "string") {
348
+ return void 0;
349
+ }
350
+ const normalized = value.trim().toLowerCase();
351
+ if (!normalized) {
352
+ return void 0;
353
+ }
354
+ if (["flat", "flat_rate", "flat-rate", "seat", "seat_licensed"].includes(normalized)) {
355
+ return "flat_rate";
356
+ }
357
+ if (["non_metered", "non-metered", "unmetered", "license"].includes(normalized)) {
358
+ return "non_metered";
359
+ }
360
+ if (["metered", "per_token", "per-token"].includes(normalized)) {
361
+ return "metered";
362
+ }
363
+ return void 0;
364
+ }
365
+ function parsePricingConfidence(value) {
366
+ if (typeof value !== "string") {
367
+ return void 0;
368
+ }
369
+ const normalized = value.trim().toLowerCase();
370
+ if (normalized === "high" || normalized === "medium" || normalized === "low") {
371
+ return normalized;
372
+ }
373
+ return void 0;
374
+ }
375
+ function parseOptionalString(value) {
376
+ if (typeof value === "string") {
377
+ const trimmed = value.trim();
378
+ return trimmed.length > 0 ? trimmed : void 0;
379
+ }
380
+ return void 0;
381
+ }
382
+ function getFirstString(source, keys) {
383
+ if (!source || typeof source !== "object") {
384
+ return void 0;
385
+ }
386
+ for (const key of keys) {
387
+ const value = source[key];
388
+ if (typeof value === "string" && value.trim() !== "") {
389
+ return value.trim();
390
+ }
391
+ }
392
+ return void 0;
393
+ }
394
+ function buildRegistry(providers) {
395
+ const sorted = [...providers].sort((a, b) => a.providerId.localeCompare(b.providerId));
396
+ const registry = {
397
+ providers: sorted,
398
+ registryVersion: ""
399
+ // Placeholder, will be computed
400
+ };
401
+ const versionData = { ...registry, registryVersion: "" };
402
+ registry.registryVersion = computeRegistryVersion(versionData);
403
+ return registry;
404
+ }
405
+ function saveRegistry(registry, filePath) {
406
+ const dir = path.dirname(filePath);
407
+ if (!fs.existsSync(dir)) {
408
+ fs.mkdirSync(dir, { recursive: true });
409
+ }
410
+ const tempPath = path.join(dir, `${path.basename(filePath)}.tmp-${process.pid}-${Date.now()}`);
411
+ fs.writeFileSync(tempPath, JSON.stringify(registry, null, 2));
412
+ fs.renameSync(tempPath, filePath);
413
+ }
414
+ function loadRegistry(filePath) {
415
+ const content = fs.readFileSync(filePath, "utf-8");
416
+ return parseJsonWithContext(content, `model registry: ${filePath}`);
417
+ }
418
+
419
+ // src/telemetry/worker.ts
420
+ function resolveRegistryModelCandidates(providerId, modelId) {
421
+ const trimmed = modelId.trim();
422
+ if (trimmed.length === 0) {
423
+ return [];
424
+ }
425
+ const candidates = /* @__PURE__ */ new Set([trimmed]);
426
+ let mappings = {};
427
+ try {
428
+ mappings = ProviderRegistry.getMappings(providerId);
429
+ } catch {
430
+ mappings = {};
431
+ }
432
+ const directMapped = mappings[trimmed];
433
+ if (directMapped) {
434
+ candidates.add(directMapped);
435
+ } else {
436
+ const lowered = trimmed.toLowerCase();
437
+ for (const [alias, target] of Object.entries(mappings)) {
438
+ if (alias.toLowerCase() === lowered && target) {
439
+ candidates.add(target);
440
+ break;
441
+ }
442
+ }
443
+ }
444
+ return Array.from(candidates);
445
+ }
446
+ function roundCostCents(value) {
447
+ return Math.round(value * 1e6) / 1e6;
448
+ }
449
+ function findRegistryModel(provider, modelId) {
450
+ const candidates = resolveRegistryModelCandidates(provider.providerId, modelId);
451
+ for (const candidate of candidates) {
452
+ const model = provider.models.find((entry) => entry.modelId === candidate);
453
+ if (model) {
454
+ return { model, resolvedModelId: candidate };
455
+ }
456
+ }
457
+ return null;
458
+ }
459
+ function optionalAttributionId(value) {
460
+ if (typeof value !== "string") return null;
461
+ const trimmed = value.trim();
462
+ return trimmed.length > 0 ? trimmed : null;
463
+ }
464
+ function findProviderAndModel(registry, providerId, modelId) {
465
+ const provider = registry.providers.find((p) => p.providerId === providerId);
466
+ if (!provider) return null;
467
+ const resolvedModel = findRegistryModel(provider, modelId);
468
+ if (!resolvedModel) return null;
469
+ return { provider, ...resolvedModel };
470
+ }
471
+ function collectRegistrySnapshotsForEnrichment(db, preferredRegistryVersion) {
472
+ const ordered = [];
473
+ const seen = /* @__PURE__ */ new Set();
474
+ const preferred = db.getRegistrySnapshot(preferredRegistryVersion);
475
+ if (preferred) {
476
+ ordered.push(preferred);
477
+ seen.add(preferred.registryVersion);
478
+ }
479
+ for (const snapshot of db.getRegistrySnapshots()) {
480
+ if (seen.has(snapshot.registryVersion)) continue;
481
+ ordered.push(snapshot);
482
+ seen.add(snapshot.registryVersion);
483
+ }
484
+ return ordered;
485
+ }
486
+ var TelemetryWorker = class _TelemetryWorker {
487
+ constructor(db, options = {}) {
488
+ this.db = db;
489
+ this.options = options;
490
+ }
491
+ db;
492
+ options;
493
+ warn(message) {
494
+ if (this.options.diagnostics === "silent") return;
495
+ console.warn(message);
496
+ }
497
+ error(message, detail) {
498
+ if (this.options.diagnostics === "silent") return;
499
+ console.error(message, detail);
500
+ }
501
+ static interpolatePercentile(sortedValues, percentile) {
502
+ if (sortedValues.length === 0) {
503
+ return 0;
504
+ }
505
+ const clampedPercentile = Math.min(1, Math.max(0, percentile));
506
+ const rank = (sortedValues.length - 1) * clampedPercentile;
507
+ const lowerIndex = Math.floor(rank);
508
+ const upperIndex = Math.ceil(rank);
509
+ const lower = sortedValues[lowerIndex] ?? 0;
510
+ const upper = sortedValues[upperIndex] ?? lower;
511
+ if (lowerIndex === upperIndex) {
512
+ return lower;
513
+ }
514
+ const weight = rank - lowerIndex;
515
+ return lower + (upper - lower) * weight;
516
+ }
517
+ /**
518
+ * Enrich unenriched invocations with cost data
519
+ * Returns number of rows enriched
520
+ */
521
+ async enrichInvocations(overrides) {
522
+ const unenriched = this.db.getUnenrichedInvocations(1e3);
523
+ let enrichedCount = 0;
524
+ for (const invocation of unenriched) {
525
+ try {
526
+ const snapshots = collectRegistrySnapshotsForEnrichment(
527
+ this.db,
528
+ invocation.registryVersion
529
+ );
530
+ if (snapshots.length === 0) {
531
+ this.warn(`Registry snapshot not found for version ${invocation.registryVersion}`);
532
+ continue;
533
+ }
534
+ let resolved = null;
535
+ let providerSeen = false;
536
+ for (const snapshot of snapshots) {
537
+ const registry = parseJsonWithContext(
538
+ snapshot.jsonBlob,
539
+ "Model registry snapshot"
540
+ );
541
+ if (registry.providers.some((p) => p.providerId === invocation.providerId)) {
542
+ providerSeen = true;
543
+ }
544
+ const candidate = findProviderAndModel(
545
+ registry,
546
+ invocation.providerId,
547
+ invocation.modelId
548
+ );
549
+ if (candidate) {
550
+ resolved = candidate;
551
+ break;
552
+ }
553
+ }
554
+ if (!resolved) {
555
+ if (!providerSeen) {
556
+ this.warn(`Provider ${invocation.providerId} not found in registry`);
557
+ } else {
558
+ this.warn(
559
+ `Model ${invocation.modelId} not found for provider ${invocation.providerId}`
560
+ );
561
+ }
562
+ continue;
563
+ }
564
+ const { model, resolvedModelId } = resolved;
565
+ let pricingSource = model.costSchema?.pricing_source ?? "frontmatter";
566
+ let pricingConfidence = model.costSchema?.pricing_confidence;
567
+ let billingSource = model.costSchema?.billing_source;
568
+ let promptPer1k = model.costSchema?.prompt_per_1k ?? 0;
569
+ let completionPer1k = model.costSchema?.completion_per_1k ?? 0;
570
+ let extraFees = model.costSchema?.extra_fees ?? {};
571
+ let billingMode = model.costSchema?.billing_mode ?? "metered";
572
+ const overrideKey = `${invocation.providerId}:${invocation.modelId}`;
573
+ const resolvedOverrideKey = `${invocation.providerId}:${resolvedModelId}`;
574
+ const override = overrides?.[overrideKey] ?? (resolvedOverrideKey !== overrideKey ? overrides?.[resolvedOverrideKey] : void 0);
575
+ if (override) {
576
+ pricingSource = `override:${overrides?.[overrideKey] ? overrideKey : resolvedOverrideKey}`;
577
+ promptPer1k = override.promptPer1k;
578
+ completionPer1k = override.completionPer1k;
579
+ extraFees = override.extraFees ?? {};
580
+ billingMode = "metered";
581
+ pricingConfidence = void 0;
582
+ billingSource = void 0;
583
+ }
584
+ const tokensIn = invocation.tokensIn ?? 0;
585
+ const tokensOut = invocation.tokensOut ?? 0;
586
+ let costCents = null;
587
+ if (billingMode === "metered") {
588
+ costCents = roundCostCents(
589
+ tokensIn / 1e3 * promptPer1k * 100 + tokensOut / 1e3 * completionPer1k * 100 + Object.values(extraFees).reduce(
590
+ (sum, fee) => sum + (typeof fee === "number" ? fee * 100 : 0),
591
+ 0
592
+ )
593
+ );
594
+ } else if (!model.costSchema?.pricing_source && !override) {
595
+ pricingSource = `non_metered:${billingMode}`;
596
+ }
597
+ const originalModelId = typeof invocation.requestedModelId === "string" && invocation.requestedModelId.trim().length > 0 ? invocation.requestedModelId : invocation.modelId;
598
+ const usageData = JSON.stringify({
599
+ inputTokens: tokensIn,
600
+ outputTokens: tokensOut,
601
+ originalModelId,
602
+ canonicalModelId: resolvedModelId
603
+ });
604
+ const inputCostCents = billingMode === "metered" ? roundCostCents(tokensIn / 1e3 * promptPer1k * 100) : 0;
605
+ const outputCostCents = billingMode === "metered" ? roundCostCents(tokensOut / 1e3 * completionPer1k * 100) : 0;
606
+ const costSnapshot = JSON.stringify({
607
+ inputCostCents,
608
+ outputCostCents,
609
+ cacheCostCents: 0,
610
+ toolCostCents: 0,
611
+ infrastructureCostCents: 0,
612
+ totalCostCents: costCents ?? 0,
613
+ currency: "USD",
614
+ pricingSource,
615
+ ...pricingConfidence ? { pricingConfidence } : {},
616
+ billingMode,
617
+ ...billingSource ? { billingSource } : {},
618
+ originalModelId,
619
+ canonicalModelId: resolvedModelId,
620
+ pricingVersion: invocation.registryVersion
621
+ });
622
+ const taskId = optionalAttributionId(invocation.taskId);
623
+ const competitionId = optionalAttributionId(invocation.competitionId) ?? taskId;
624
+ const variantId = optionalAttributionId(invocation.variantId);
625
+ const enrichedId = generateInvocationId();
626
+ const enriched = {
627
+ id: enrichedId,
628
+ invocationId: invocation.id,
629
+ computedCostCents: costCents,
630
+ pricingSource,
631
+ enrichedAt: Date.now(),
632
+ billingMode,
633
+ usageData,
634
+ costSnapshot,
635
+ pricingVersion: invocation.registryVersion,
636
+ taskId,
637
+ competitionId,
638
+ variantId
639
+ };
640
+ this.db.insertEnrichedInvocation(enriched);
641
+ enrichedCount++;
642
+ } catch (error) {
643
+ this.error(
644
+ `Failed to enrich invocation ${invocation.id}:`,
645
+ error instanceof Error ? error.message : String(error)
646
+ );
647
+ }
648
+ }
649
+ return enrichedCount;
650
+ }
651
+ /**
652
+ * Aggregate enriched invocations into hourly buckets
653
+ * Returns number of aggregates updated
654
+ */
655
+ aggregateHourly() {
656
+ const rows = this.db.db.prepare(
657
+ `
658
+ SELECT
659
+ i.provider_id AS provider_id,
660
+ i.model_id AS model_id,
661
+ CAST(i.timestamp / 3600000 AS INTEGER) * 3600000 AS bucket_start,
662
+ i.tokens_in AS tokens_in,
663
+ i.tokens_out AS tokens_out,
664
+ i.total_time_ms AS total_time_ms,
665
+ i.status AS status,
666
+ e.billing_mode AS billing_mode,
667
+ e.computed_cost_cents AS computed_cost_cents
668
+ FROM model_invocations i
669
+ LEFT JOIN enriched_invocations e ON i.id = e.invocation_id
670
+ `
671
+ ).all();
672
+ const buckets = /* @__PURE__ */ new Map();
673
+ for (const row of rows) {
674
+ const key = `${row.provider_id}\0${row.model_id}\0${row.bucket_start}`;
675
+ let acc = buckets.get(key);
676
+ if (!acc) {
677
+ acc = {
678
+ providerId: row.provider_id,
679
+ modelId: row.model_id,
680
+ bucketStart: row.bucket_start,
681
+ totalInvocations: 0,
682
+ totalTokensIn: 0,
683
+ totalTokensOut: 0,
684
+ errorCount: 0,
685
+ timings: [],
686
+ costSum: 0,
687
+ costCount: 0
688
+ };
689
+ buckets.set(key, acc);
690
+ }
691
+ acc.totalInvocations += 1;
692
+ if (typeof row.tokens_in === "number") {
693
+ acc.totalTokensIn += row.tokens_in;
694
+ }
695
+ if (typeof row.tokens_out === "number") {
696
+ acc.totalTokensOut += row.tokens_out;
697
+ }
698
+ if (row.status !== "success") {
699
+ acc.errorCount += 1;
700
+ }
701
+ if (typeof row.total_time_ms === "number" && Number.isFinite(row.total_time_ms)) {
702
+ acc.timings.push(row.total_time_ms);
703
+ }
704
+ const billingQualifies = row.billing_mode === null || row.billing_mode === "metered";
705
+ if (billingQualifies && typeof row.computed_cost_cents === "number") {
706
+ acc.costSum += row.computed_cost_cents;
707
+ acc.costCount += 1;
708
+ }
709
+ }
710
+ let aggregatedCount = 0;
711
+ for (const acc of buckets.values()) {
712
+ const sortedTimings = acc.timings.slice().sort((a, b) => a - b);
713
+ const p95LatencyMs = _TelemetryWorker.interpolatePercentile(sortedTimings, 0.95);
714
+ const avgCostCents = acc.costCount > 0 ? acc.costSum / acc.costCount : 0;
715
+ const errorRate = acc.errorCount * 100 / acc.totalInvocations;
716
+ const aggregate = {
717
+ bucketStart: acc.bucketStart,
718
+ providerId: acc.providerId,
719
+ modelId: acc.modelId,
720
+ totalInvocations: acc.totalInvocations,
721
+ totalTokensIn: acc.totalTokensIn,
722
+ totalTokensOut: acc.totalTokensOut,
723
+ avgCostCents,
724
+ p95LatencyMs,
725
+ errorRate
726
+ };
727
+ this.db.upsertHourlyAggregate(aggregate);
728
+ aggregatedCount++;
729
+ }
730
+ return aggregatedCount;
731
+ }
732
+ /**
733
+ * Aggregate enriched invocations into daily cost buckets.
734
+ * Returns number of daily aggregate rows upserted.
735
+ */
736
+ aggregateDaily() {
737
+ return this.db.backfillDailyCostAggregations();
738
+ }
739
+ /**
740
+ * Run full enrichment and aggregation cycle
741
+ */
742
+ async runCycle(overrides) {
743
+ const enrichedCount = await this.enrichInvocations(overrides);
744
+ const aggregatedCount = this.aggregateHourly();
745
+ const dailyAggregatedCount = this.aggregateDaily();
746
+ return { enrichedCount, aggregatedCount, dailyAggregatedCount };
747
+ }
748
+ };
749
+
750
+ // src/telemetry/invocation-cost-enrichment.ts
751
+ var PENDING_ENRICHMENT_HINT = "Invocations exist in this window but cost enrichment is pending or incomplete.";
752
+ var NO_INVOCATIONS_HINT = "No model invocations recorded in this window.";
753
+ var ZERO_USAGE_HINT = "Invocations were recorded but reported zero token usage; per-token cost is $0.";
754
+ function resolveProvidersDirectory(cwd = process.cwd()) {
755
+ const packageRoot = getPackageRoot();
756
+ const artifactsDir = path2.join(cwd, ".poetic", "providers");
757
+ if (fs2.existsSync(path2.join(artifactsDir, "registry.json"))) {
758
+ return artifactsDir;
759
+ }
760
+ const candidates = [
761
+ path2.join(cwd, "providers"),
762
+ path2.join(cwd, ".poetic", "config"),
763
+ path2.join(packageRoot, ".poetic", "providers"),
764
+ path2.join(packageRoot, "providers"),
765
+ path2.join(packageRoot, ".poetic", "config")
766
+ ];
767
+ for (const candidate of candidates) {
768
+ if (!fs2.existsSync(candidate)) continue;
769
+ if (fs2.existsSync(path2.join(candidate, "registry.json")) || fs2.existsSync(path2.join(candidate, "providers.yaml")) || fs2.readdirSync(candidate, { withFileTypes: true }).some((entry) => entry.name.endsWith(".md"))) {
770
+ return candidate;
771
+ }
772
+ }
773
+ return null;
774
+ }
775
+ function per1kCost(modelPricing, input) {
776
+ if (!modelPricing) return void 0;
777
+ const per1k = input ? modelPricing.input_per_1k_tokens : modelPricing.output_per_1k_tokens;
778
+ if (typeof per1k === "number") return per1k;
779
+ const per1m = input ? modelPricing.input_per_1m_tokens : modelPricing.output_per_1m_tokens;
780
+ return typeof per1m === "number" ? per1m / 1e3 : void 0;
781
+ }
782
+ function stringMeta(value) {
783
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
784
+ }
785
+ function confidenceMeta(value) {
786
+ const raw = stringMeta(value)?.toLowerCase();
787
+ return raw === "high" || raw === "medium" || raw === "low" ? raw : void 0;
788
+ }
789
+ function pricingMetadata(pricing) {
790
+ const meta = pricing?._meta && typeof pricing._meta === "object" ? pricing._meta : {};
791
+ return {
792
+ ...stringMeta(meta.pricing_source) ? { pricing_source: stringMeta(meta.pricing_source) } : {},
793
+ ...confidenceMeta(meta.pricing_confidence) ? { pricing_confidence: confidenceMeta(meta.pricing_confidence) } : {},
794
+ ...stringMeta(meta.billing_source) ? { billing_source: stringMeta(meta.billing_source) } : {}
795
+ };
796
+ }
797
+ function buildRegistryFromProvidersYaml(filePath) {
798
+ const parsed = ProviderRegistryConfigSchema.parse(yaml2.load(fs2.readFileSync(filePath, "utf-8")));
799
+ const providers = Object.entries(parsed.providers).map(
800
+ ([providerId, provider]) => ({
801
+ providerId,
802
+ displayName: provider.display_name,
803
+ models: provider.models.available.map((model) => {
804
+ const pricing = provider.pricing?.models?.[model.id];
805
+ const inputPer1k = per1kCost(pricing, true);
806
+ const outputPer1k = per1kCost(pricing, false);
807
+ const metadata = pricingMetadata(pricing);
808
+ return {
809
+ modelId: model.id,
810
+ displayName: model.display_name,
811
+ capabilities: model.capabilities,
812
+ ...pricing?.non_metered ? {
813
+ costSchema: {
814
+ billing_mode: "non_metered",
815
+ ...metadata,
816
+ notes: pricing.notes
817
+ }
818
+ } : inputPer1k !== void 0 || outputPer1k !== void 0 ? {
819
+ costSchema: {
820
+ prompt_per_1k: inputPer1k ?? 0,
821
+ completion_per_1k: outputPer1k ?? 0,
822
+ billing_mode: "metered",
823
+ ...metadata,
824
+ notes: pricing?.notes
825
+ }
826
+ } : {}
827
+ };
828
+ })
829
+ })
830
+ );
831
+ return buildRegistry(providers);
832
+ }
833
+ function loadBundledRegistry(providersDir) {
834
+ const registryJsonPath = path2.join(providersDir, "registry.json");
835
+ if (fs2.existsSync(registryJsonPath)) {
836
+ return loadRegistry(registryJsonPath);
837
+ }
838
+ const providersYamlPath = path2.join(providersDir, "providers.yaml");
839
+ if (fs2.existsSync(providersYamlPath)) {
840
+ return buildRegistryFromProvidersYaml(providersYamlPath);
841
+ }
842
+ return buildRegistry(loadProviderDirectory(providersDir));
843
+ }
844
+ function ensureRegistrySnapshot(db) {
845
+ const providersDir = resolveProvidersDirectory();
846
+ const existingSnapshot = db.getLatestRegistrySnapshot();
847
+ if (!providersDir) {
848
+ return Boolean(existingSnapshot);
849
+ }
850
+ try {
851
+ const registry = loadBundledRegistry(providersDir);
852
+ db.insertRegistrySnapshot({
853
+ registryVersion: registry.registryVersion,
854
+ createdAt: Date.now(),
855
+ jsonBlob: JSON.stringify(registry)
856
+ });
857
+ return true;
858
+ } catch {
859
+ return Boolean(existingSnapshot);
860
+ }
861
+ }
862
+ function ensureRegistrySnapshotForPendingEnrichment(db, options) {
863
+ const existingSnapshot = db.getLatestRegistrySnapshot();
864
+ if (options.refreshRegistrySnapshot === false && existingSnapshot) {
865
+ return true;
866
+ }
867
+ return ensureRegistrySnapshot(db);
868
+ }
869
+ async function ensurePendingInvocationCostEnrichment(db, options = {}) {
870
+ const pendingCount = db.countUnenrichedInvocations();
871
+ if (pendingCount === 0) {
872
+ return { enrichedCount: 0, registrySnapshotEnsured: Boolean(db.getLatestRegistrySnapshot()) };
873
+ }
874
+ const registrySnapshotEnsured = ensureRegistrySnapshotForPendingEnrichment(db, options);
875
+ if (!registrySnapshotEnsured) {
876
+ return { enrichedCount: 0, registrySnapshotEnsured: false };
877
+ }
878
+ const worker = new TelemetryWorker(db, { diagnostics: "silent" });
879
+ const enrichedCount = options.aggregate === false ? await worker.enrichInvocations() : (await worker.runCycle()).enrichedCount;
880
+ return {
881
+ enrichedCount,
882
+ registrySnapshotEnsured: true
883
+ };
884
+ }
885
+ function summarizeInvocationCostVisibility(db, startTimestampMs) {
886
+ const rawInvocationCount = db.countRawInvocationsSince(startTimestampMs);
887
+ const enrichedInvocationCount = db.countEnrichedInvocationsSince(startTimestampMs);
888
+ const pendingEnrichmentCount = Math.max(0, rawInvocationCount - enrichedInvocationCount);
889
+ if (rawInvocationCount === 0) {
890
+ return {
891
+ rawInvocationCount,
892
+ enrichedInvocationCount,
893
+ pendingEnrichmentCount,
894
+ visibility: "no_invocations",
895
+ hint: NO_INVOCATIONS_HINT
896
+ };
897
+ }
898
+ if (pendingEnrichmentCount > 0) {
899
+ return {
900
+ rawInvocationCount,
901
+ enrichedInvocationCount,
902
+ pendingEnrichmentCount,
903
+ visibility: "pending_enrichment",
904
+ hint: PENDING_ENRICHMENT_HINT
905
+ };
906
+ }
907
+ const hasTokenUsage = db.hasTokenUsageSince(startTimestampMs);
908
+ if (!hasTokenUsage) {
909
+ return {
910
+ rawInvocationCount,
911
+ enrichedInvocationCount,
912
+ pendingEnrichmentCount,
913
+ visibility: "zero_usage",
914
+ hint: ZERO_USAGE_HINT
915
+ };
916
+ }
917
+ return {
918
+ rawInvocationCount,
919
+ enrichedInvocationCount,
920
+ pendingEnrichmentCount,
921
+ visibility: "enriched"
922
+ };
923
+ }
924
+ function resolveInvocationRegistryVersion(db) {
925
+ return db.getLatestRegistryVersion() ?? "v1";
926
+ }
927
+
928
+ // src/telemetry/cost-projection.ts
929
+ function availableCostAmount(amount, unit, source, detail) {
930
+ return {
931
+ amount,
932
+ unit,
933
+ status: "available",
934
+ source,
935
+ ...detail ? { detail } : {}
936
+ };
937
+ }
938
+ function unavailableCostAmount(unit, source, detail) {
939
+ return {
940
+ amount: null,
941
+ unit,
942
+ status: "unavailable",
943
+ source,
944
+ ...detail ? { detail } : {}
945
+ };
946
+ }
947
+ function errorCostAmount(unit, source, error, detail) {
948
+ return {
949
+ amount: null,
950
+ unit,
951
+ status: "error",
952
+ source,
953
+ error,
954
+ ...detail ? { detail } : {}
955
+ };
956
+ }
957
+ function isAvailableCostAmount(value) {
958
+ return value.status === "available";
959
+ }
960
+ function costAmountOrNull(value) {
961
+ return value.status === "available" ? value.amount : null;
962
+ }
963
+ var PENDING_HINT = "Invocations exist in this window but cost enrichment is pending; totals may under-report until enrichment completes.";
964
+ var FAILED_HINT = "Invocations exist in this window but cost enrichment could not run (no pricing snapshot available); showing raw counts only.";
965
+ var RAW_ZERO_USAGE_HINT = "Invocations were recorded but reported zero token usage; per-token cost is $0.";
966
+ var NO_INVOCATIONS_HINT2 = "No model invocations recorded in this window.";
967
+ function mapVisibilityToState(summary, attempt) {
968
+ switch (summary.visibility) {
969
+ case "enriched":
970
+ return "enriched";
971
+ case "zero_usage":
972
+ return "raw";
973
+ case "no_invocations":
974
+ return "enriched";
975
+ case "pending_enrichment":
976
+ if (attempt && attempt.registrySnapshotEnsured === false) {
977
+ return "failed";
978
+ }
979
+ return "pending";
980
+ }
981
+ }
982
+ function resolveHint(state, summary) {
983
+ switch (state) {
984
+ case "pending":
985
+ return PENDING_HINT;
986
+ case "failed":
987
+ return FAILED_HINT;
988
+ case "raw":
989
+ return summary.visibility === "zero_usage" ? RAW_ZERO_USAGE_HINT : summary.hint;
990
+ case "enriched":
991
+ return summary.rawInvocationCount === 0 ? NO_INVOCATIONS_HINT2 : void 0;
992
+ }
993
+ }
994
+ function projectCostVisibility(db, startTimestampMs, attempt) {
995
+ const summary = summarizeInvocationCostVisibility(db, startTimestampMs);
996
+ return fromVisibilitySummary(summary, attempt);
997
+ }
998
+ function fromVisibilitySummary(summary, attempt) {
999
+ const state = mapVisibilityToState(summary, attempt);
1000
+ const totalsMayUnderReport = state === "pending" || state === "failed";
1001
+ const hint = resolveHint(state, summary);
1002
+ return {
1003
+ rawInvocationCount: summary.rawInvocationCount,
1004
+ enrichedInvocationCount: summary.enrichedInvocationCount,
1005
+ pendingEnrichmentCount: summary.pendingEnrichmentCount,
1006
+ state,
1007
+ visibility: summary.visibility,
1008
+ totalsMayUnderReport,
1009
+ ...hint ? { hint } : {}
1010
+ };
1011
+ }
1012
+ function formatCostProjectionNotice(projection) {
1013
+ if (projection.state === "enriched" && projection.rawInvocationCount === 0) {
1014
+ return NO_INVOCATIONS_HINT2;
1015
+ }
1016
+ if (projection.state === "enriched") {
1017
+ return void 0;
1018
+ }
1019
+ const counts = projection.pendingEnrichmentCount > 0 ? ` (${projection.pendingEnrichmentCount} pending of ${projection.rawInvocationCount} raw)` : projection.rawInvocationCount > 0 ? ` (${projection.rawInvocationCount} raw)` : "";
1020
+ return `${projection.hint ?? ""}${counts}`.trim() || void 0;
1021
+ }
1022
+
1023
+ // src/telemetry/invocation-quality.ts
1024
+ var SAFE_SQL_ALIAS = /^[A-Za-z_][A-Za-z0-9_]*$/u;
1025
+ function invocationProvenanceClauses(alias) {
1026
+ const prefix = sqlPrefix(alias);
1027
+ return [
1028
+ `${prefix}provider_id <> 'unknown'`,
1029
+ `(${prefix}execution_source IS NULL OR ${prefix}execution_source = 'live')`
1030
+ ];
1031
+ }
1032
+ function invocationMetricQualityClauses(alias) {
1033
+ const prefix = sqlPrefix(alias);
1034
+ return [
1035
+ `NOT (${prefix}total_time_ms IS NOT NULL AND ${prefix}total_time_ms < 1000 AND ${prefix}tokens_out IS NULL)`,
1036
+ `NOT (
1037
+ ${prefix}tokens_out IS NOT NULL
1038
+ AND ${prefix}tokens_out > 0
1039
+ AND ${prefix}time_first_token_ms IS NOT NULL
1040
+ AND ${prefix}time_last_token_ms IS NOT NULL
1041
+ AND ${prefix}time_last_token_ms > ${prefix}time_first_token_ms
1042
+ AND ((${prefix}tokens_out * 1000.0) / (${prefix}time_last_token_ms - ${prefix}time_first_token_ms)) > 1000
1043
+ )`
1044
+ ];
1045
+ }
1046
+ function invocationAnalyticsQualityClauses(alias) {
1047
+ return [...invocationProvenanceClauses(alias), ...invocationMetricQualityClauses(alias)];
1048
+ }
1049
+ function invocationProvenanceWhereSql(alias) {
1050
+ return clausesToAndSql(invocationProvenanceClauses(alias));
1051
+ }
1052
+ function invocationAnalyticsQualityWhereSql(alias) {
1053
+ return clausesToAndSql(invocationAnalyticsQualityClauses(alias));
1054
+ }
1055
+ function isInvocationMetricQualityRow(row) {
1056
+ if (row.total_time_ms !== null && row.total_time_ms !== void 0 && row.total_time_ms < 1e3) {
1057
+ if (row.tokens_out === null || row.tokens_out === void 0) return false;
1058
+ }
1059
+ const tokensOut = row.tokens_out;
1060
+ const firstTokenMs = row.time_first_token_ms;
1061
+ const lastTokenMs = row.time_last_token_ms;
1062
+ if (typeof tokensOut === "number" && tokensOut > 0 && typeof firstTokenMs === "number" && typeof lastTokenMs === "number" && lastTokenMs > firstTokenMs) {
1063
+ const decodeTokensPerSecond = tokensOut * 1e3 / (lastTokenMs - firstTokenMs);
1064
+ if (decodeTokensPerSecond > 1e3) return false;
1065
+ }
1066
+ return true;
1067
+ }
1068
+ function clausesToAndSql(clauses) {
1069
+ if (clauses.length === 0) return "";
1070
+ return clauses.map((clause) => `AND ${clause}`).join("\n");
1071
+ }
1072
+ function sqlPrefix(alias) {
1073
+ if (alias === void 0) return "";
1074
+ if (!SAFE_SQL_ALIAS.test(alias)) {
1075
+ throw new Error(`Invalid SQL alias: ${alias}`);
1076
+ }
1077
+ return `${alias}.`;
1078
+ }
1079
+
1080
+ // src/telemetry/model-invocations-db.ts
1081
+ var ENRICHED_INVOCATIONS_SOURCE = "enriched_invocations";
1082
+ var ALLOWED_TABLE_NAMES = [
1083
+ "model_invocations",
1084
+ "registry_snapshots",
1085
+ "enriched_invocations",
1086
+ "aggregates_hourly",
1087
+ "cost_aggregations_daily"
1088
+ ];
1089
+ var SAFE_SQL_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/u;
1090
+ var SAFE_COLUMN_DEFINITION = /^(TEXT|INTEGER|REAL|BLOB|NUMERIC)$/iu;
1091
+ function validateTableName(tableName) {
1092
+ if (!ALLOWED_TABLE_NAMES.includes(tableName)) {
1093
+ throw new Error(
1094
+ `Invalid table name: "${tableName}". Only the following tables are allowed: ${ALLOWED_TABLE_NAMES.join(", ")}`
1095
+ );
1096
+ }
1097
+ return tableName;
1098
+ }
1099
+ function validateSqlIdentifier(value, label) {
1100
+ if (!SAFE_SQL_IDENTIFIER.test(value)) {
1101
+ throw new Error(`Invalid SQL ${label}: ${value}`);
1102
+ }
1103
+ return value;
1104
+ }
1105
+ function validateColumnDefinition(value) {
1106
+ if (!SAFE_COLUMN_DEFINITION.test(value)) {
1107
+ throw new Error(`Invalid SQL column definition: ${value}`);
1108
+ }
1109
+ return value;
1110
+ }
1111
+ function snakeToCamel(str) {
1112
+ return str.replace(/_([a-z])/g, (_match, letter) => letter.toUpperCase());
1113
+ }
1114
+ function convertRowToCamelCase(row) {
1115
+ if (!row) return null;
1116
+ const result = {};
1117
+ for (const key in row) {
1118
+ result[snakeToCamel(key)] = row[key];
1119
+ }
1120
+ return result;
1121
+ }
1122
+ var DAY_MS = 24 * 60 * 60 * 1e3;
1123
+ function utcDateStartMs(date) {
1124
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/u.exec(date);
1125
+ if (!match) {
1126
+ throw new Error(`Invalid date (expected YYYY-MM-DD): ${date}`);
1127
+ }
1128
+ const year = Number(match[1]);
1129
+ const month = Number(match[2]);
1130
+ const day = Number(match[3]);
1131
+ const ms = Date.UTC(year, month - 1, day);
1132
+ const check = new Date(ms);
1133
+ if (check.getUTCFullYear() !== year || check.getUTCMonth() !== month - 1 || check.getUTCDate() !== day) {
1134
+ throw new Error(`Invalid calendar date: ${date}`);
1135
+ }
1136
+ return ms;
1137
+ }
1138
+ var compatibleModelIndexByProvider = /* @__PURE__ */ new Map();
1139
+ registerProviderRegistryReloadInvalidator(() => {
1140
+ compatibleModelIndexByProvider.clear();
1141
+ });
1142
+ function addAlternate(index, alternate, modelId) {
1143
+ if (typeof alternate !== "string") return;
1144
+ const trimmed = alternate.trim();
1145
+ if (trimmed.length === 0) return;
1146
+ let owners = index.alternateToModels.get(trimmed);
1147
+ if (!owners) {
1148
+ owners = /* @__PURE__ */ new Set();
1149
+ index.alternateToModels.set(trimmed, owners);
1150
+ }
1151
+ owners.add(modelId);
1152
+ }
1153
+ function buildCompatibleModelIndex(providerId) {
1154
+ try {
1155
+ const config = ProviderRegistry.getProviderConfig(providerId);
1156
+ const index = {
1157
+ modelIds: /* @__PURE__ */ new Set(),
1158
+ alternateToModels: /* @__PURE__ */ new Map()
1159
+ };
1160
+ for (const model of config.models.available) {
1161
+ index.modelIds.add(model.id);
1162
+ addAlternate(index, model.id, model.id);
1163
+ addAlternate(index, model.full_name, model.id);
1164
+ addAlternate(index, model.canonical_id, model.id);
1165
+ addAlternate(index, model.routing_id, model.id);
1166
+ const bedrock = model.bedrock;
1167
+ if (bedrock) {
1168
+ addAlternate(index, bedrock.base_model_id, model.id);
1169
+ addAlternate(index, bedrock.global, model.id);
1170
+ addAlternate(index, bedrock.us, model.id);
1171
+ addAlternate(index, bedrock.eu, model.id);
1172
+ addAlternate(index, bedrock.jp, model.id);
1173
+ addAlternate(index, bedrock.apac, model.id);
1174
+ }
1175
+ }
1176
+ return index;
1177
+ } catch {
1178
+ return null;
1179
+ }
1180
+ }
1181
+ function getCompatibleModelIndex(providerId) {
1182
+ const trimmedProvider = providerId.trim();
1183
+ if (trimmedProvider.length === 0) return null;
1184
+ if (compatibleModelIndexByProvider.has(trimmedProvider)) {
1185
+ return compatibleModelIndexByProvider.get(trimmedProvider) ?? null;
1186
+ }
1187
+ const index = buildCompatibleModelIndex(trimmedProvider);
1188
+ compatibleModelIndexByProvider.set(trimmedProvider, index);
1189
+ return index;
1190
+ }
1191
+ function lookupCompatibleModelId(index, candidate) {
1192
+ if (index.modelIds.has(candidate)) {
1193
+ return candidate;
1194
+ }
1195
+ const owners = index.alternateToModels.get(candidate);
1196
+ if (owners && owners.size === 1) {
1197
+ return owners.values().next().value;
1198
+ }
1199
+ return null;
1200
+ }
1201
+ function stripOneTrailingContextSelector(modelId) {
1202
+ const match = modelId.match(/^(.*)(\[[^\]]+\])\s*$/u);
1203
+ if (!match || match[1] === void 0 || match[2] === void 0) {
1204
+ return null;
1205
+ }
1206
+ const base = match[1].trim();
1207
+ if (base.length === 0) {
1208
+ return null;
1209
+ }
1210
+ return base;
1211
+ }
1212
+ function resolveCompatibleInvocationModelId(providerId, modelId) {
1213
+ const trimmedModel = typeof modelId === "string" ? modelId.trim() : "";
1214
+ if (trimmedModel.length === 0) return modelId;
1215
+ const index = getCompatibleModelIndex(providerId);
1216
+ if (!index) return modelId;
1217
+ const direct = lookupCompatibleModelId(index, trimmedModel);
1218
+ if (direct !== null) {
1219
+ return direct;
1220
+ }
1221
+ const baseWithoutSelector = stripOneTrailingContextSelector(trimmedModel);
1222
+ if (baseWithoutSelector !== null && baseWithoutSelector !== trimmedModel) {
1223
+ const fromBase = lookupCompatibleModelId(index, baseWithoutSelector);
1224
+ if (fromBase !== null) {
1225
+ return fromBase;
1226
+ }
1227
+ }
1228
+ return modelId;
1229
+ }
1230
+ function invocationModelMatchesSameModel(providerId, storedModelId, filterModelId) {
1231
+ if (storedModelId === filterModelId) return true;
1232
+ const storedNorm = resolveCompatibleInvocationModelId(providerId, storedModelId);
1233
+ const filterNorm = resolveCompatibleInvocationModelId(providerId, filterModelId);
1234
+ return storedNorm === filterNorm;
1235
+ }
1236
+ var ModelInvocationsDB = class {
1237
+ // Exposed for worker access - ideally should add public query methods instead
1238
+ db;
1239
+ // Database instance type (better-sqlite3 or in-memory shim)
1240
+ dbPath;
1241
+ constructor(dbPath) {
1242
+ if (!sqlite_wrapper_default) {
1243
+ throw new Error("Database implementation not available");
1244
+ }
1245
+ this.dbPath = dbPath;
1246
+ this.db = new sqlite_wrapper_default(dbPath);
1247
+ this.initializeSchema();
1248
+ }
1249
+ /**
1250
+ * Initialize database schema with all required tables
1251
+ */
1252
+ initializeSchema() {
1253
+ applySqlitePragmas(this.db, { foreignKeys: true });
1254
+ this.db.exec(`
1255
+ -- Model invocations table
1256
+ CREATE TABLE IF NOT EXISTS model_invocations (
1257
+ id TEXT PRIMARY KEY,
1258
+ timestamp INTEGER NOT NULL,
1259
+ parent_workflow_id TEXT,
1260
+ provider_id TEXT NOT NULL,
1261
+ model_id TEXT NOT NULL,
1262
+ registry_version TEXT NOT NULL,
1263
+ tokens_in INTEGER,
1264
+ tokens_out INTEGER,
1265
+ time_request_sent_ms INTEGER NOT NULL,
1266
+ time_first_token_ms INTEGER,
1267
+ time_last_token_ms INTEGER,
1268
+ time_to_first_token_ms INTEGER,
1269
+ total_time_ms INTEGER,
1270
+ status TEXT NOT NULL,
1271
+ error_code TEXT,
1272
+ request_size_bytes INTEGER,
1273
+ agent_role TEXT,
1274
+ copilot_subcommand TEXT,
1275
+ execution_source TEXT,
1276
+ requested_model_id TEXT,
1277
+ execution_model_id TEXT,
1278
+ reported_model_id TEXT,
1279
+ backend TEXT,
1280
+ scope TEXT,
1281
+ context_selector TEXT,
1282
+ resolution_source TEXT,
1283
+ task_id TEXT,
1284
+ competition_id TEXT,
1285
+ variant_id TEXT
1286
+ );
1287
+
1288
+ CREATE INDEX IF NOT EXISTS idx_model_invocations_timestamp
1289
+ ON model_invocations(timestamp);
1290
+ CREATE INDEX IF NOT EXISTS idx_model_invocations_provider_model
1291
+ ON model_invocations(provider_id, model_id);
1292
+ CREATE INDEX IF NOT EXISTS idx_model_invocations_registry_version
1293
+ ON model_invocations(registry_version);
1294
+ CREATE INDEX IF NOT EXISTS idx_model_invocations_agent_role
1295
+ ON model_invocations(agent_role);
1296
+ -- Partial index for speed/latency analytics, which filter on
1297
+ -- status='success' (+ optional timestamp/provider/model) and order by
1298
+ -- timestamp. A PARTIAL index keyed only to successful rows is used
1299
+ -- instead of the full composite (status, timestamp, provider_id,
1300
+ -- model_id) deliberately: the full composite would add per-INSERT write
1301
+ -- cost on the hot invocation-write path for every row, whereas success
1302
+ -- rows are the only ones these read paths target. Validate that the
1303
+ -- speed query actually uses this index with EXPLAIN QUERY PLAN. Created
1304
+ -- idempotently like the other indexes above (no SCHEMA_VERSION bump).
1305
+ CREATE INDEX IF NOT EXISTS idx_model_invocations_success_speed
1306
+ ON model_invocations(timestamp DESC, provider_id, model_id)
1307
+ WHERE status = 'success';
1308
+
1309
+ -- Registry snapshots table
1310
+ CREATE TABLE IF NOT EXISTS registry_snapshots (
1311
+ registry_version TEXT PRIMARY KEY,
1312
+ created_at INTEGER NOT NULL,
1313
+ json_blob TEXT NOT NULL
1314
+ );
1315
+
1316
+ -- Enriched invocations table (hybrid storage: tokens + cost snapshot)
1317
+ CREATE TABLE IF NOT EXISTS enriched_invocations (
1318
+ id TEXT PRIMARY KEY,
1319
+ invocation_id TEXT NOT NULL UNIQUE,
1320
+ computed_cost_cents INTEGER,
1321
+ pricing_source TEXT NOT NULL,
1322
+ enriched_at INTEGER NOT NULL,
1323
+ billing_mode TEXT,
1324
+
1325
+ -- Hybrid Storage: Raw usage data (JSON) - immutable source of truth
1326
+ usage_data TEXT,
1327
+
1328
+ -- Hybrid Storage: Cost snapshot (JSON) - historical accuracy
1329
+ cost_snapshot TEXT,
1330
+
1331
+ -- Hybrid Storage: Pricing metadata for recalculation
1332
+ pricing_version TEXT,
1333
+
1334
+ -- Hybrid Storage: Context for cost attribution
1335
+ task_id TEXT,
1336
+ competition_id TEXT,
1337
+ variant_id TEXT,
1338
+
1339
+ FOREIGN KEY (invocation_id) REFERENCES model_invocations(id)
1340
+ );
1341
+
1342
+ CREATE INDEX IF NOT EXISTS idx_enriched_invocations_invocation_id
1343
+ ON enriched_invocations(invocation_id);
1344
+ CREATE INDEX IF NOT EXISTS idx_enriched_invocations_task_id
1345
+ ON enriched_invocations(task_id);
1346
+ CREATE INDEX IF NOT EXISTS idx_enriched_invocations_competition_id
1347
+ ON enriched_invocations(competition_id);
1348
+
1349
+ -- Hourly aggregates table
1350
+ CREATE TABLE IF NOT EXISTS aggregates_hourly (
1351
+ bucket_start INTEGER NOT NULL,
1352
+ provider_id TEXT NOT NULL,
1353
+ model_id TEXT NOT NULL,
1354
+ total_invocations INTEGER NOT NULL,
1355
+ total_tokens_in INTEGER NOT NULL,
1356
+ total_tokens_out INTEGER NOT NULL,
1357
+ avg_cost_cents REAL NOT NULL,
1358
+ p95_latency_ms INTEGER NOT NULL,
1359
+ error_rate REAL NOT NULL,
1360
+ PRIMARY KEY (bucket_start, provider_id, model_id)
1361
+ );
1362
+
1363
+ -- Daily cost aggregates table (queried by getDailyCostAggregations)
1364
+ CREATE TABLE IF NOT EXISTS cost_aggregations_daily (
1365
+ date TEXT NOT NULL,
1366
+ provider TEXT NOT NULL,
1367
+ model TEXT NOT NULL,
1368
+ execution_count INTEGER NOT NULL DEFAULT 0,
1369
+ total_cost_usd REAL NOT NULL DEFAULT 0,
1370
+ total_input_tokens INTEGER NOT NULL DEFAULT 0,
1371
+ total_output_tokens INTEGER NOT NULL DEFAULT 0,
1372
+ avg_cost_per_execution REAL NOT NULL DEFAULT 0,
1373
+ PRIMARY KEY (date, provider, model)
1374
+ );
1375
+ CREATE INDEX IF NOT EXISTS idx_cost_aggregations_daily_date
1376
+ ON cost_aggregations_daily(date);
1377
+ `);
1378
+ this.ensureColumn("model_invocations", "copilot_subcommand", "TEXT");
1379
+ this.ensureColumn("model_invocations", "execution_source", "TEXT");
1380
+ this.ensureColumn("model_invocations", "requested_model_id", "TEXT");
1381
+ this.ensureColumn("model_invocations", "execution_model_id", "TEXT");
1382
+ this.ensureColumn("model_invocations", "reported_model_id", "TEXT");
1383
+ this.ensureColumn("model_invocations", "backend", "TEXT");
1384
+ this.ensureColumn("model_invocations", "scope", "TEXT");
1385
+ this.ensureColumn("model_invocations", "context_selector", "TEXT");
1386
+ this.ensureColumn("model_invocations", "resolution_source", "TEXT");
1387
+ this.ensureColumn("model_invocations", "task_id", "TEXT");
1388
+ this.ensureColumn("model_invocations", "competition_id", "TEXT");
1389
+ this.ensureColumn("model_invocations", "variant_id", "TEXT");
1390
+ this.ensureColumn("enriched_invocations", "billing_mode", "TEXT");
1391
+ this.ensureColumn("enriched_invocations", "usage_data", "TEXT");
1392
+ this.ensureColumn("enriched_invocations", "cost_snapshot", "TEXT");
1393
+ this.ensureColumn("enriched_invocations", "pricing_version", "TEXT");
1394
+ this.ensureColumn("enriched_invocations", "task_id", "TEXT");
1395
+ this.ensureColumn("enriched_invocations", "competition_id", "TEXT");
1396
+ this.ensureColumn("enriched_invocations", "variant_id", "TEXT");
1397
+ }
1398
+ /**
1399
+ * Ensures a column exists in a table, adding it if necessary.
1400
+ * Security: Table name is validated against whitelist to prevent SQL injection (CWE-89).
1401
+ * Column name and definition are parameterized through prepared statements where possible.
1402
+ *
1403
+ * @param table - The table name (must be in ALLOWED_TABLE_NAMES)
1404
+ * @param column - The column name to ensure exists
1405
+ * @param definition - The SQL column definition (e.g., 'TEXT', 'INTEGER NOT NULL')
1406
+ * @throws {Error} If the table name is not in the whitelist
1407
+ */
1408
+ ensureColumn(table, column, definition) {
1409
+ const validatedTable = validateTableName(table);
1410
+ const validatedColumn = validateSqlIdentifier(column, "column name");
1411
+ const validatedDefinition = validateColumnDefinition(definition);
1412
+ try {
1413
+ const infoStmt = this.db.prepare(`PRAGMA table_info(${validatedTable})`);
1414
+ const columns = infoStmt.all() ?? [];
1415
+ const hasColumn = columns.some((col) => col.name === validatedColumn);
1416
+ if (!hasColumn) {
1417
+ this.db.exec(
1418
+ `ALTER TABLE ${validatedTable} ADD COLUMN ${validatedColumn} ${validatedDefinition}`
1419
+ );
1420
+ }
1421
+ } catch (error) {
1422
+ if (!error || !(error instanceof Error) || !error.message.includes("Invalid table name")) {
1423
+ emitWarning(
1424
+ "WS-003",
1425
+ {
1426
+ taskId: "system",
1427
+ subsystem: "telemetry",
1428
+ executionPhase: "setup"
1429
+ },
1430
+ {
1431
+ severity: "WARN" /* WARN */,
1432
+ metadata: {
1433
+ operation: "ensure_column",
1434
+ table,
1435
+ column,
1436
+ error: error instanceof Error ? error.message : String(error)
1437
+ }
1438
+ }
1439
+ );
1440
+ } else {
1441
+ throw error;
1442
+ }
1443
+ }
1444
+ }
1445
+ /**
1446
+ * Insert a model invocation record
1447
+ */
1448
+ insertInvocation(invocation) {
1449
+ const stmt = this.db.prepare(`
1450
+ INSERT INTO model_invocations (
1451
+ id, timestamp, parent_workflow_id, provider_id, model_id,
1452
+ registry_version, tokens_in, tokens_out, time_request_sent_ms,
1453
+ time_first_token_ms, time_last_token_ms, time_to_first_token_ms,
1454
+ total_time_ms, status, error_code, request_size_bytes, agent_role,
1455
+ copilot_subcommand, execution_source,
1456
+ requested_model_id, execution_model_id, reported_model_id,
1457
+ backend, scope, context_selector, resolution_source,
1458
+ task_id, competition_id, variant_id
1459
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1460
+ `);
1461
+ stmt.run(
1462
+ invocation.id,
1463
+ invocation.timestamp,
1464
+ invocation.parentWorkflowId ?? null,
1465
+ invocation.providerId,
1466
+ invocation.modelId,
1467
+ invocation.registryVersion,
1468
+ invocation.tokensIn ?? null,
1469
+ invocation.tokensOut ?? null,
1470
+ invocation.timeRequestSentMs,
1471
+ invocation.timeFirstTokenMs ?? null,
1472
+ invocation.timeLastTokenMs ?? null,
1473
+ invocation.timeToFirstTokenMs ?? null,
1474
+ invocation.totalTimeMs ?? null,
1475
+ invocation.status,
1476
+ invocation.errorCode ?? null,
1477
+ invocation.requestSizeBytes ?? null,
1478
+ invocation.agentRole ?? null,
1479
+ invocation.copilotSubcommand ?? null,
1480
+ invocation.executionSource ?? null,
1481
+ invocation.requestedModelId ?? null,
1482
+ invocation.executionModelId ?? null,
1483
+ invocation.reportedModelId ?? null,
1484
+ invocation.backend ?? null,
1485
+ invocation.scope ?? null,
1486
+ invocation.contextSelector ?? null,
1487
+ invocation.resolutionSource ?? null,
1488
+ invocation.taskId ?? null,
1489
+ invocation.competitionId ?? invocation.taskId ?? null,
1490
+ invocation.variantId ?? null
1491
+ );
1492
+ }
1493
+ /**
1494
+ * Get a model invocation by ID
1495
+ */
1496
+ getInvocation(id) {
1497
+ const stmt = this.db.prepare(`
1498
+ SELECT * FROM model_invocations WHERE id = ?
1499
+ `);
1500
+ const row = stmt.get(id);
1501
+ return row ? convertRowToCamelCase(row) : null;
1502
+ }
1503
+ /**
1504
+ * Insert a registry snapshot
1505
+ */
1506
+ insertRegistrySnapshot(snapshot) {
1507
+ const stmt = this.db.prepare(`
1508
+ INSERT OR REPLACE INTO registry_snapshots (registry_version, created_at, json_blob)
1509
+ VALUES (?, ?, ?)
1510
+ `);
1511
+ stmt.run(snapshot.registryVersion, snapshot.createdAt, snapshot.jsonBlob);
1512
+ }
1513
+ /**
1514
+ * Get the most recently persisted registry snapshot, if any.
1515
+ */
1516
+ getLatestRegistrySnapshot() {
1517
+ const snapshots = this.getRegistrySnapshots(1);
1518
+ return snapshots[0] ?? null;
1519
+ }
1520
+ /**
1521
+ * List registry snapshots newest-first.
1522
+ *
1523
+ * Used by enrichment when an invocation's stamped registry_version is a
1524
+ * placeholder / stale id: prefer the exact version when present, then walk
1525
+ * other persisted snapshots so known providers still price.
1526
+ */
1527
+ getRegistrySnapshots(limit) {
1528
+ const boundedLimit = typeof limit === "number" && Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : void 0;
1529
+ const stmt = this.db.prepare(
1530
+ boundedLimit !== void 0 ? `
1531
+ SELECT * FROM registry_snapshots
1532
+ ORDER BY created_at DESC
1533
+ LIMIT ?
1534
+ ` : `
1535
+ SELECT * FROM registry_snapshots
1536
+ ORDER BY created_at DESC
1537
+ `
1538
+ );
1539
+ const rows = (boundedLimit !== void 0 ? stmt.all(boundedLimit) : stmt.all()) ?? [];
1540
+ return rows.map(
1541
+ (row) => convertRowToCamelCase(row)
1542
+ ).filter((snapshot) => snapshot !== null);
1543
+ }
1544
+ /**
1545
+ * Get the most recently persisted registry version, if any.
1546
+ */
1547
+ getLatestRegistryVersion() {
1548
+ return this.getLatestRegistrySnapshot()?.registryVersion ?? null;
1549
+ }
1550
+ /**
1551
+ * Get a registry snapshot by version
1552
+ */
1553
+ getRegistrySnapshot(registryVersion) {
1554
+ const stmt = this.db.prepare(`
1555
+ SELECT * FROM registry_snapshots WHERE registry_version = ?
1556
+ `);
1557
+ const row = stmt.get(registryVersion);
1558
+ return row ? convertRowToCamelCase(row) : null;
1559
+ }
1560
+ /**
1561
+ * Insert an enriched invocation record
1562
+ */
1563
+ insertEnrichedInvocation(enriched) {
1564
+ const stmt = this.db.prepare(`
1565
+ INSERT OR REPLACE INTO enriched_invocations (
1566
+ id, invocation_id, computed_cost_cents, pricing_source, enriched_at, billing_mode,
1567
+ usage_data, cost_snapshot, pricing_version, task_id, competition_id, variant_id
1568
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1569
+ `);
1570
+ stmt.run(
1571
+ enriched.id,
1572
+ enriched.invocationId,
1573
+ enriched.computedCostCents ?? null,
1574
+ enriched.pricingSource,
1575
+ enriched.enrichedAt,
1576
+ enriched.billingMode ?? null,
1577
+ enriched.usageData ?? null,
1578
+ enriched.costSnapshot ?? null,
1579
+ enriched.pricingVersion ?? null,
1580
+ enriched.taskId ?? null,
1581
+ enriched.competitionId ?? null,
1582
+ enriched.variantId ?? null
1583
+ );
1584
+ }
1585
+ /**
1586
+ * Execute related telemetry writes atomically when the SQLite driver supports it.
1587
+ */
1588
+ transaction(operation) {
1589
+ if (!this.db.transaction) {
1590
+ return operation();
1591
+ }
1592
+ return this.db.transaction(operation)();
1593
+ }
1594
+ /**
1595
+ * Get unenriched invocations
1596
+ */
1597
+ getUnenrichedInvocations(limit = 100) {
1598
+ const stmt = this.db.prepare(`
1599
+ SELECT i.* FROM model_invocations i
1600
+ LEFT JOIN enriched_invocations e ON i.id = e.invocation_id
1601
+ WHERE e.id IS NULL
1602
+ ORDER BY i.timestamp ASC
1603
+ LIMIT ?
1604
+ `);
1605
+ const rows = stmt.all(limit) ?? [];
1606
+ return rows.map(
1607
+ (row) => convertRowToCamelCase(row)
1608
+ ).filter((x) => x !== null);
1609
+ }
1610
+ /**
1611
+ * Upsert hourly aggregate
1612
+ */
1613
+ upsertHourlyAggregate(aggregate) {
1614
+ const stmt = this.db.prepare(`
1615
+ INSERT OR REPLACE INTO aggregates_hourly (
1616
+ bucket_start, provider_id, model_id, total_invocations,
1617
+ total_tokens_in, total_tokens_out, avg_cost_cents,
1618
+ p95_latency_ms, error_rate
1619
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
1620
+ `);
1621
+ stmt.run(
1622
+ aggregate.bucketStart,
1623
+ aggregate.providerId,
1624
+ aggregate.modelId,
1625
+ aggregate.totalInvocations,
1626
+ aggregate.totalTokensIn,
1627
+ aggregate.totalTokensOut,
1628
+ aggregate.avgCostCents,
1629
+ aggregate.p95LatencyMs,
1630
+ aggregate.errorRate
1631
+ );
1632
+ }
1633
+ /**
1634
+ * Get hourly aggregates for a time range
1635
+ */
1636
+ getHourlyAggregates(providerId, modelId, startBucket, endBucket) {
1637
+ const stmt = this.db.prepare(`
1638
+ SELECT * FROM aggregates_hourly
1639
+ WHERE provider_id = ? AND model_id = ?
1640
+ AND bucket_start >= ? AND bucket_start <= ?
1641
+ ORDER BY bucket_start ASC
1642
+ `);
1643
+ const rows = stmt.all(providerId, modelId, startBucket, endBucket) ?? [];
1644
+ return rows.map(
1645
+ (row) => convertRowToCamelCase(row)
1646
+ ).filter((x) => x !== null);
1647
+ }
1648
+ /**
1649
+ * Get cost breakdown by agent role for swarm executions
1650
+ * Returns aggregated cost metrics grouped by agent role
1651
+ */
1652
+ getRoleCostBreakdown(startTimestamp, endTimestamp) {
1653
+ let query = `
1654
+ SELECT
1655
+ i.agent_role as agent_role,
1656
+ COUNT(*) as total_invocations,
1657
+ COALESCE(SUM(i.tokens_in), 0) as total_tokens_in,
1658
+ COALESCE(SUM(i.tokens_out), 0) as total_tokens_out,
1659
+ COALESCE(AVG(CASE WHEN e.billing_mode IS NULL OR e.billing_mode = 'metered' THEN e.computed_cost_cents END), 0) as avg_cost_cents
1660
+ FROM model_invocations i
1661
+ LEFT JOIN enriched_invocations e ON i.id = e.invocation_id
1662
+ WHERE i.agent_role IS NOT NULL
1663
+ `;
1664
+ const params = [];
1665
+ if (startTimestamp !== void 0) {
1666
+ query += " AND i.timestamp >= ?";
1667
+ params.push(startTimestamp);
1668
+ }
1669
+ if (endTimestamp !== void 0) {
1670
+ query += " AND i.timestamp <= ?";
1671
+ params.push(endTimestamp);
1672
+ }
1673
+ query += `
1674
+ GROUP BY i.agent_role
1675
+ ORDER BY avg_cost_cents DESC
1676
+ `;
1677
+ const stmt = this.db.prepare(query);
1678
+ const rows = params.length > 0 ? stmt.all(...params) : stmt.all();
1679
+ return (rows ?? []).map(
1680
+ (row) => convertRowToCamelCase(row)
1681
+ ).filter(
1682
+ (x) => x !== null
1683
+ );
1684
+ }
1685
+ /**
1686
+ * Return TTFT and token-throughput statistics grouped by provider/model.
1687
+ *
1688
+ * Only streaming invocations (status='success', time_to_first_token_ms IS NOT NULL)
1689
+ * are included. Rows with total_time_ms <= 0 or null tokens_out are excluded from
1690
+ * the tokens/sec calculation to avoid divide-by-zero and noise.
1691
+ *
1692
+ * Percentiles are computed in JS from a sorted slice, so they are exact for the
1693
+ * dataset (not approximations). Safe to call on an empty or partially-populated DB.
1694
+ *
1695
+ * @param limit - Max provider/model groups to return, ordered by invocation count desc.
1696
+ */
1697
+ getTtftReport(limit = 20, options = {}) {
1698
+ let rows;
1699
+ try {
1700
+ const stmt = this.db.prepare(`
1701
+ SELECT
1702
+ provider_id,
1703
+ model_id,
1704
+ time_to_first_token_ms,
1705
+ tokens_out,
1706
+ total_time_ms
1707
+ FROM model_invocations
1708
+ WHERE time_to_first_token_ms IS NOT NULL
1709
+ AND status = 'success'
1710
+ ${options.includeRaw ? "" : invocationAnalyticsQualityWhereSql()}
1711
+ ORDER BY provider_id, model_id, time_to_first_token_ms ASC
1712
+ `);
1713
+ rows = stmt.all();
1714
+ } catch {
1715
+ return [];
1716
+ }
1717
+ if (rows.length === 0) return [];
1718
+ const groups = /* @__PURE__ */ new Map();
1719
+ for (const row of rows) {
1720
+ const compatibleModelId = resolveCompatibleInvocationModelId(row.provider_id, row.model_id);
1721
+ const key = `${row.provider_id}\0${compatibleModelId}`;
1722
+ let group = groups.get(key);
1723
+ if (!group) {
1724
+ group = { providerId: row.provider_id, modelId: compatibleModelId, rows: [] };
1725
+ groups.set(key, group);
1726
+ }
1727
+ group.rows.push(row);
1728
+ }
1729
+ const result = [];
1730
+ for (const group of groups.values()) {
1731
+ const groupRows = group.rows;
1732
+ const ttfts = groupRows.map((r) => r.time_to_first_token_ms).sort((a, b) => a - b);
1733
+ const n = ttfts.length;
1734
+ if (n === 0) continue;
1735
+ const p50 = ttfts[Math.min(Math.floor(n * 0.5), n - 1)] ?? null;
1736
+ const p95 = ttfts[Math.min(Math.floor(n * 0.95), n - 1)] ?? null;
1737
+ const avgTtft = Math.round(ttfts.reduce((s, v) => s + v, 0) / n);
1738
+ const tokensSecs = groupRows.filter(
1739
+ (r) => r.total_time_ms !== null && r.total_time_ms > 0 && r.tokens_out !== null && r.tokens_out > 0
1740
+ ).map((r) => r.tokens_out * 1e3 / r.total_time_ms);
1741
+ const avgTokensPerSec = tokensSecs.length > 0 ? Math.round(tokensSecs.reduce((s, v) => s + v, 0) / tokensSecs.length * 100) / 100 : null;
1742
+ result.push({
1743
+ providerId: group.providerId,
1744
+ modelId: group.modelId,
1745
+ streamingInvocations: n,
1746
+ p50TtftMs: p50,
1747
+ p95TtftMs: p95,
1748
+ avgTtftMs: avgTtft,
1749
+ avgTokensPerSec
1750
+ });
1751
+ }
1752
+ result.sort((a, b) => b.streamingInvocations - a.streamingInvocations);
1753
+ return result.slice(0, limit);
1754
+ }
1755
+ /**
1756
+ * Close database connection
1757
+ */
1758
+ close() {
1759
+ this.db.close();
1760
+ }
1761
+ /**
1762
+ * Backfill daily cost aggregates from model_invocations (optional enrichment).
1763
+ * Idempotent via INSERT OR REPLACE; safe to call before reads or in worker cycles.
1764
+ *
1765
+ * Source universe is every matching model_invocations row; enrichment is optional
1766
+ * via LEFT JOIN. Numeric cost totals are stored only for fully priced groups;
1767
+ * incomplete groups store 0 cost so partial known-member sums are never
1768
+ * persisted as totals. Coverage status for reads is derived by
1769
+ * {@link getDailyCostAggregations}.
1770
+ *
1771
+ * @returns Number of aggregate rows upserted, or 0 on failure (worker-compatible).
1772
+ */
1773
+ backfillDailyCostAggregations(startDate, endDate) {
1774
+ const result = this.tryBackfillDailyCostAggregations(startDate, endDate);
1775
+ return result.ok ? result.changes : 0;
1776
+ }
1777
+ /**
1778
+ * Internal backfill with explicit success/failure (does not launder errors to "0 changes").
1779
+ */
1780
+ tryBackfillDailyCostAggregations(startDate, endDate) {
1781
+ const params = [];
1782
+ let whereClause = "WHERE 1=1";
1783
+ if (startDate) {
1784
+ whereClause += " AND i.timestamp >= ?";
1785
+ params.push(utcDateStartMs(startDate));
1786
+ }
1787
+ if (endDate) {
1788
+ whereClause += " AND i.timestamp < ?";
1789
+ params.push(utcDateStartMs(endDate) + DAY_MS);
1790
+ }
1791
+ try {
1792
+ const stmt = this.db.prepare(`
1793
+ INSERT OR REPLACE INTO cost_aggregations_daily (
1794
+ date,
1795
+ provider,
1796
+ model,
1797
+ execution_count,
1798
+ total_cost_usd,
1799
+ total_input_tokens,
1800
+ total_output_tokens,
1801
+ avg_cost_per_execution
1802
+ )
1803
+ SELECT
1804
+ date(i.timestamp / 1000, 'unixepoch') as date,
1805
+ i.provider_id as provider,
1806
+ i.model_id as model,
1807
+ COUNT(*) as execution_count,
1808
+ CASE
1809
+ WHEN COUNT(*) > 0
1810
+ AND COUNT(*) = SUM(
1811
+ CASE WHEN (${SNAPSHOT_FIRST_COST_CENTS_SQL}) IS NOT NULL THEN 1 ELSE 0 END
1812
+ )
1813
+ THEN COALESCE(SUM((${SNAPSHOT_FIRST_COST_CENTS_SQL})), 0) / 100.0
1814
+ ELSE 0
1815
+ END as total_cost_usd,
1816
+ COALESCE(SUM(i.tokens_in), 0) as total_input_tokens,
1817
+ COALESCE(SUM(i.tokens_out), 0) as total_output_tokens,
1818
+ CASE
1819
+ WHEN COUNT(*) > 0
1820
+ AND COUNT(*) = SUM(
1821
+ CASE WHEN (${SNAPSHOT_FIRST_COST_CENTS_SQL}) IS NOT NULL THEN 1 ELSE 0 END
1822
+ )
1823
+ THEN COALESCE(SUM((${SNAPSHOT_FIRST_COST_CENTS_SQL})), 0) / 100.0 / COUNT(*)
1824
+ ELSE 0
1825
+ END as avg_cost_per_execution
1826
+ FROM model_invocations i
1827
+ LEFT JOIN enriched_invocations e ON e.invocation_id = i.id
1828
+ ${whereClause}
1829
+ GROUP BY date, provider, model
1830
+ `);
1831
+ const result = params.length > 0 ? stmt.run(...params) : stmt.run();
1832
+ return { ok: true, changes: result.changes ?? 0 };
1833
+ } catch (error) {
1834
+ const message = error instanceof Error ? error.message : String(error);
1835
+ emitWarning(
1836
+ "WS-003",
1837
+ {
1838
+ taskId: "system",
1839
+ subsystem: "telemetry",
1840
+ executionPhase: "execution"
1841
+ },
1842
+ {
1843
+ severity: "WARN" /* WARN */,
1844
+ metadata: {
1845
+ operation: "backfill_daily_cost_aggregations",
1846
+ error: message,
1847
+ startDate,
1848
+ endDate
1849
+ }
1850
+ }
1851
+ );
1852
+ return { ok: false, error: message };
1853
+ }
1854
+ }
1855
+ /**
1856
+ * Get daily cost aggregations for a specified date range.
1857
+ *
1858
+ * Status-bearing: numeric totals/averages exist only when every included
1859
+ * invocation has authoritative snapshot-first cost evidence. Mixed or
1860
+ * all-unpriced evidence is `incomplete` (counts retained, costs null).
1861
+ * Query/backfill failure is `error` (no totals). Empty complete means no data.
1862
+ *
1863
+ * Source universe is every matching model_invocations row (optional enrichment
1864
+ * via LEFT JOIN). Live and legacy tables are composed at the storage-native
1865
+ * date+provider+model key first: live replaces only its exact native key;
1866
+ * legacy-only native keys remain. Only then are merged native rows aggregated
1867
+ * to the requested date/provider/model grouping. A group total is numeric only
1868
+ * when every constituent native row is complete (no partial subtotals).
1869
+ * Ordering is preserved (date DESC, then provider/model ASC when grouped).
1870
+ */
1871
+ getDailyCostAggregations(startDate, endDate, groupBy) {
1872
+ const backfill = this.tryBackfillDailyCostAggregations(startDate, endDate);
1873
+ if (!backfill.ok) {
1874
+ return {
1875
+ status: "error",
1876
+ rows: [],
1877
+ executionCount: 0,
1878
+ pricedCount: 0,
1879
+ error: backfill.error,
1880
+ detail: "backfill_daily_cost_aggregations failed"
1881
+ };
1882
+ }
1883
+ try {
1884
+ const liveNative = this.queryLiveDailyCostCoverage(startDate, endDate);
1885
+ const legacyNative = this.queryPreseededDailyCostAggregationsNative(startDate, endDate);
1886
+ if (liveNative.length === 0) {
1887
+ const rows2 = this.aggregateNativeDailyCostRows(legacyNative, groupBy);
1888
+ return this.buildDailyCostResultFromRows(rows2);
1889
+ }
1890
+ if (legacyNative.length === 0) {
1891
+ const rows2 = this.aggregateNativeDailyCostRows(
1892
+ this.buildDailyCostRowsFromLive(liveNative),
1893
+ groupBy
1894
+ );
1895
+ return this.buildDailyCostResultFromRows(rows2);
1896
+ }
1897
+ const mergedNative = this.mergeLiveAndLegacyAtNativeKey(liveNative, legacyNative);
1898
+ const rows = this.aggregateNativeDailyCostRows(mergedNative, groupBy);
1899
+ return this.buildDailyCostResultFromRows(rows);
1900
+ } catch (error) {
1901
+ const message = error instanceof Error ? error.message : String(error);
1902
+ emitWarning(
1903
+ "WS-003",
1904
+ {
1905
+ taskId: "system",
1906
+ subsystem: "telemetry",
1907
+ executionPhase: "execution"
1908
+ },
1909
+ {
1910
+ severity: "WARN" /* WARN */,
1911
+ metadata: {
1912
+ operation: "query_daily_cost_aggregations",
1913
+ error: message,
1914
+ startDate,
1915
+ endDate
1916
+ }
1917
+ }
1918
+ );
1919
+ return {
1920
+ status: "error",
1921
+ rows: [],
1922
+ executionCount: 0,
1923
+ pricedCount: 0,
1924
+ error: message,
1925
+ detail: "query_daily_cost_aggregations failed"
1926
+ };
1927
+ }
1928
+ }
1929
+ /**
1930
+ * Storage-native merge identity: date + provider + model.
1931
+ */
1932
+ nativeDailyCostKey(row) {
1933
+ return `${row.date}\0${row.provider ?? ""}\0${row.model ?? ""}`;
1934
+ }
1935
+ /**
1936
+ * Stable key for daily aggregation under the requested grouping.
1937
+ */
1938
+ dailyCostAggregationKey(row, groupBy) {
1939
+ if (groupBy === "provider") {
1940
+ return `${row.date}\0${row.provider ?? ""}`;
1941
+ }
1942
+ if (groupBy === "model") {
1943
+ return `${row.date}\0${row.model ?? ""}`;
1944
+ }
1945
+ return row.date;
1946
+ }
1947
+ /**
1948
+ * Ordering: date DESC, then provider/model ASC when grouped (matches SQL ORDER BY).
1949
+ * At native resolution, order by date DESC, provider ASC, model ASC.
1950
+ */
1951
+ compareDailyCostAggregationRows(a, b, groupBy) {
1952
+ if (a.date !== b.date) {
1953
+ return a.date < b.date ? 1 : -1;
1954
+ }
1955
+ if (groupBy === "provider" || groupBy === "native") {
1956
+ const ap = a.provider ?? "";
1957
+ const bp = b.provider ?? "";
1958
+ if (ap !== bp) {
1959
+ return ap < bp ? -1 : 1;
1960
+ }
1961
+ }
1962
+ if (groupBy === "model" || groupBy === "native") {
1963
+ const am = a.model ?? "";
1964
+ const bm = b.model ?? "";
1965
+ if (am !== bm) {
1966
+ return am < bm ? -1 : 1;
1967
+ }
1968
+ }
1969
+ return 0;
1970
+ }
1971
+ /**
1972
+ * Live coverage at native date+provider+model resolution.
1973
+ * Source universe: model_invocations; enrichment optional via LEFT JOIN.
1974
+ */
1975
+ queryLiveDailyCostCoverage(startDate, endDate) {
1976
+ const params = [];
1977
+ let whereClause = "WHERE 1=1";
1978
+ if (startDate) {
1979
+ whereClause += " AND i.timestamp >= ?";
1980
+ params.push(utcDateStartMs(startDate));
1981
+ }
1982
+ if (endDate) {
1983
+ whereClause += " AND i.timestamp < ?";
1984
+ params.push(utcDateStartMs(endDate) + DAY_MS);
1985
+ }
1986
+ const query = `
1987
+ SELECT
1988
+ date(i.timestamp / 1000, 'unixepoch') as date,
1989
+ i.provider_id as provider,
1990
+ i.model_id as model,
1991
+ COUNT(*) as execution_count,
1992
+ SUM(
1993
+ CASE WHEN (${SNAPSHOT_FIRST_COST_CENTS_SQL}) IS NOT NULL THEN 1 ELSE 0 END
1994
+ ) as priced_count,
1995
+ SUM((${SNAPSHOT_FIRST_COST_CENTS_SQL})) as total_cost_cents,
1996
+ COALESCE(SUM(i.tokens_in), 0) as total_input_tokens,
1997
+ COALESCE(SUM(i.tokens_out), 0) as total_output_tokens
1998
+ FROM model_invocations i
1999
+ LEFT JOIN enriched_invocations e ON e.invocation_id = i.id
2000
+ ${whereClause}
2001
+ GROUP BY date, i.provider_id, i.model_id
2002
+ ORDER BY date DESC, provider ASC, model ASC
2003
+ `;
2004
+ const stmt = this.db.prepare(query);
2005
+ const rows = params.length > 0 ? stmt.all(...params) : stmt.all();
2006
+ return rows.map((row) => this.normalizeLiveDailyCostCoverageRow(row));
2007
+ }
2008
+ normalizeLiveDailyCostCoverageRow(row) {
2009
+ if (row === null || typeof row !== "object") {
2010
+ return {
2011
+ date: "",
2012
+ provider: "",
2013
+ model: "",
2014
+ execution_count: 0,
2015
+ priced_count: 0,
2016
+ total_cost_cents: null,
2017
+ total_input_tokens: 0,
2018
+ total_output_tokens: 0
2019
+ };
2020
+ }
2021
+ const dateValue = Reflect.get(row, "date");
2022
+ const providerValue = Reflect.get(row, "provider");
2023
+ const modelValue = Reflect.get(row, "model");
2024
+ const totalCostCentsValue = Reflect.get(row, "total_cost_cents");
2025
+ const totalCostCents = totalCostCentsValue === null || totalCostCentsValue === void 0 ? null : Number(totalCostCentsValue);
2026
+ return {
2027
+ date: typeof dateValue === "string" ? dateValue : String(dateValue ?? ""),
2028
+ provider: typeof providerValue === "string" ? providerValue : String(providerValue ?? ""),
2029
+ model: typeof modelValue === "string" ? modelValue : String(modelValue ?? ""),
2030
+ execution_count: Number(Reflect.get(row, "execution_count")) || 0,
2031
+ priced_count: Number(Reflect.get(row, "priced_count")) || 0,
2032
+ total_cost_cents: totalCostCents === null || Number.isNaN(totalCostCents) ? null : totalCostCents,
2033
+ total_input_tokens: Number(Reflect.get(row, "total_input_tokens")) || 0,
2034
+ total_output_tokens: Number(Reflect.get(row, "total_output_tokens")) || 0
2035
+ };
2036
+ }
2037
+ buildDailyCostRowsFromLive(live) {
2038
+ return live.map((row) => {
2039
+ const execCount = Number(row.execution_count) || 0;
2040
+ const priced = Number(row.priced_count) || 0;
2041
+ const rowComplete = execCount > 0 && priced === execCount;
2042
+ const totalCost = rowComplete ? (Number(row.total_cost_cents) || 0) / 100 : null;
2043
+ const avgCostPerExecution = rowComplete && execCount > 0 && totalCost !== null ? totalCost / execCount : null;
2044
+ return {
2045
+ date: row.date,
2046
+ provider: row.provider,
2047
+ model: row.model,
2048
+ executionCount: execCount,
2049
+ pricedCount: priced,
2050
+ totalTokensIn: Number(row.total_input_tokens) || 0,
2051
+ totalTokensOut: Number(row.total_output_tokens) || 0,
2052
+ totalCost,
2053
+ avgCostPerExecution,
2054
+ status: rowComplete ? "complete" : "incomplete"
2055
+ };
2056
+ });
2057
+ }
2058
+ buildDailyCostResultFromRows(rows) {
2059
+ let executionCount = 0;
2060
+ let pricedCount = 0;
2061
+ let anyIncomplete = false;
2062
+ for (const row of rows) {
2063
+ executionCount += row.executionCount;
2064
+ pricedCount += row.pricedCount;
2065
+ if (row.status === "incomplete") {
2066
+ anyIncomplete = true;
2067
+ }
2068
+ }
2069
+ return {
2070
+ status: anyIncomplete ? "incomplete" : "complete",
2071
+ rows,
2072
+ executionCount,
2073
+ pricedCount,
2074
+ ...anyIncomplete ? { detail: `incomplete cost evidence (${pricedCount}/${executionCount} priced)` } : {}
2075
+ };
2076
+ }
2077
+ /**
2078
+ * Compose live and legacy rows at storage-native date+provider+model keys.
2079
+ * Live is authoritative for its exact native key only; legacy-only keys remain.
2080
+ */
2081
+ mergeLiveAndLegacyAtNativeKey(live, legacyRows) {
2082
+ const liveRows = this.buildDailyCostRowsFromLive(live);
2083
+ const liveKeys = new Set(liveRows.map((row) => this.nativeDailyCostKey(row)));
2084
+ const legacyOnly = legacyRows.filter((row) => !liveKeys.has(this.nativeDailyCostKey(row)));
2085
+ return [...liveRows, ...legacyOnly];
2086
+ }
2087
+ /**
2088
+ * Aggregate storage-native rows to the requested date/provider/model grouping.
2089
+ * A group total/average is numeric only when every constituent native row is
2090
+ * complete; partial subtotals are never exposed.
2091
+ */
2092
+ aggregateNativeDailyCostRows(nativeRows, groupBy) {
2093
+ const groups = /* @__PURE__ */ new Map();
2094
+ for (const row of nativeRows) {
2095
+ const key = this.dailyCostAggregationKey(row, groupBy);
2096
+ let group = groups.get(key);
2097
+ if (!group) {
2098
+ group = {
2099
+ date: row.date,
2100
+ ...groupBy === "provider" ? { provider: row.provider } : {},
2101
+ ...groupBy === "model" ? { model: row.model } : {},
2102
+ members: []
2103
+ };
2104
+ groups.set(key, group);
2105
+ }
2106
+ group.members.push(row);
2107
+ }
2108
+ const aggregated = [];
2109
+ for (const group of groups.values()) {
2110
+ let executionCount = 0;
2111
+ let pricedCount = 0;
2112
+ let totalTokensIn = 0;
2113
+ let totalTokensOut = 0;
2114
+ let allComplete = true;
2115
+ let totalCostSum = 0;
2116
+ for (const member of group.members) {
2117
+ executionCount += member.executionCount;
2118
+ pricedCount += member.pricedCount;
2119
+ totalTokensIn += member.totalTokensIn;
2120
+ totalTokensOut += member.totalTokensOut;
2121
+ if (member.status !== "complete" || member.totalCost === null) {
2122
+ allComplete = false;
2123
+ } else {
2124
+ totalCostSum += member.totalCost;
2125
+ }
2126
+ }
2127
+ const complete = allComplete && executionCount > 0;
2128
+ const totalCost = complete ? totalCostSum : null;
2129
+ const avgCostPerExecution = complete && executionCount > 0 && totalCost !== null ? totalCost / executionCount : null;
2130
+ aggregated.push({
2131
+ date: group.date,
2132
+ provider: group.provider,
2133
+ model: group.model,
2134
+ executionCount,
2135
+ pricedCount,
2136
+ totalTokensIn,
2137
+ totalTokensOut,
2138
+ totalCost,
2139
+ avgCostPerExecution,
2140
+ status: complete ? "complete" : "incomplete"
2141
+ });
2142
+ }
2143
+ return aggregated.sort((a, b) => this.compareDailyCostAggregationRows(a, b, groupBy));
2144
+ }
2145
+ /**
2146
+ * Pre-seeded cost_aggregations_daily fixtures at storage-native resolution
2147
+ * (date, provider, model). Treated as complete; pricedCount equals
2148
+ * executionCount. Callers that also have live coverage must merge at the
2149
+ * native key so live remains authoritative for exact collisions only.
2150
+ */
2151
+ queryPreseededDailyCostAggregationsNative(startDate, endDate) {
2152
+ const params = [];
2153
+ let whereClause = " WHERE 1=1";
2154
+ if (startDate) {
2155
+ whereClause += " AND date >= ?";
2156
+ params.push(startDate);
2157
+ }
2158
+ if (endDate) {
2159
+ whereClause += " AND date <= ?";
2160
+ params.push(endDate);
2161
+ }
2162
+ const query = `
2163
+ SELECT
2164
+ date,
2165
+ provider,
2166
+ model,
2167
+ execution_count,
2168
+ total_cost_usd,
2169
+ total_input_tokens,
2170
+ total_output_tokens,
2171
+ avg_cost_per_execution
2172
+ FROM cost_aggregations_daily
2173
+ ${whereClause}
2174
+ ORDER BY date DESC, provider ASC, model ASC
2175
+ `;
2176
+ const stmt = this.db.prepare(query);
2177
+ const rawRows = params.length > 0 ? stmt.all(...params) : stmt.all();
2178
+ return rawRows.map((raw) => this.normalizePreseededDailyCostAggregateRow(raw));
2179
+ }
2180
+ normalizePreseededDailyCostAggregateRow(raw) {
2181
+ if (raw === null || typeof raw !== "object") {
2182
+ return {
2183
+ date: "",
2184
+ executionCount: 0,
2185
+ pricedCount: 0,
2186
+ totalTokensIn: 0,
2187
+ totalTokensOut: 0,
2188
+ totalCost: 0,
2189
+ avgCostPerExecution: 0,
2190
+ status: "complete"
2191
+ };
2192
+ }
2193
+ const dateValue = Reflect.get(raw, "date");
2194
+ const providerValue = Reflect.get(raw, "provider");
2195
+ const modelValue = Reflect.get(raw, "model");
2196
+ const avgValue = Reflect.get(raw, "avg_cost_per_execution");
2197
+ const execCount = Number(Reflect.get(raw, "execution_count")) || 0;
2198
+ const totalCost = Number(Reflect.get(raw, "total_cost_usd")) || 0;
2199
+ const avgFromRow = avgValue === null || avgValue === void 0 ? null : Number(avgValue);
2200
+ const avgCostPerExecution = avgFromRow !== null && !Number.isNaN(avgFromRow) ? avgFromRow : execCount > 0 ? totalCost / execCount : 0;
2201
+ const provider = typeof providerValue === "string" ? providerValue : void 0;
2202
+ const model = typeof modelValue === "string" ? modelValue : void 0;
2203
+ return {
2204
+ date: typeof dateValue === "string" ? dateValue : String(dateValue ?? ""),
2205
+ ...provider !== void 0 ? { provider } : {},
2206
+ ...model !== void 0 ? { model } : {},
2207
+ executionCount: execCount,
2208
+ pricedCount: execCount,
2209
+ totalTokensIn: Number(Reflect.get(raw, "total_input_tokens")) || 0,
2210
+ totalTokensOut: Number(Reflect.get(raw, "total_output_tokens")) || 0,
2211
+ totalCost,
2212
+ avgCostPerExecution,
2213
+ status: "complete"
2214
+ };
2215
+ }
2216
+ /**
2217
+ * Determine if telemetry contains non-metered billing records
2218
+ */
2219
+ hasNonMeteredBilling() {
2220
+ try {
2221
+ const stmt = this.db.prepare(`
2222
+ SELECT 1 FROM enriched_invocations
2223
+ WHERE billing_mode IS NOT NULL AND billing_mode != 'metered'
2224
+ LIMIT 1
2225
+ `);
2226
+ const row = stmt.get();
2227
+ return Boolean(row);
2228
+ } catch (error) {
2229
+ emitWarning(
2230
+ "WS-003",
2231
+ {
2232
+ taskId: "system",
2233
+ subsystem: "telemetry",
2234
+ executionPhase: "execution"
2235
+ },
2236
+ {
2237
+ severity: "WARN" /* WARN */,
2238
+ metadata: {
2239
+ operation: "query_non_metered_billing",
2240
+ error: error instanceof Error ? error.message : String(error)
2241
+ }
2242
+ }
2243
+ );
2244
+ return false;
2245
+ }
2246
+ }
2247
+ // ============================================================================
2248
+ // HYBRID STORAGE: Cost Tracking with Tokens + Snapshot
2249
+ // ============================================================================
2250
+ /**
2251
+ * Record an execution cost with hybrid storage (tokens + cost snapshot)
2252
+ * Stores both raw usage data (immutable) and cost snapshot (historical accuracy)
2253
+ */
2254
+ recordExecutionCost(record) {
2255
+ const stmt = this.db.prepare(`
2256
+ INSERT OR REPLACE INTO enriched_invocations (
2257
+ id,
2258
+ invocation_id,
2259
+ computed_cost_cents,
2260
+ pricing_source,
2261
+ enriched_at,
2262
+ billing_mode,
2263
+ usage_data,
2264
+ cost_snapshot,
2265
+ pricing_version,
2266
+ task_id,
2267
+ competition_id,
2268
+ variant_id
2269
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2270
+ `);
2271
+ const enrichedId = `enrich_${Date.now()}_${randomBytes(8).toString("hex")}`;
2272
+ const enrichedAt = record.timestamp.getTime();
2273
+ stmt.run(
2274
+ enrichedId,
2275
+ record.executionId,
2276
+ record.costSnapshot.totalCostCents,
2277
+ record.pricingSource,
2278
+ enrichedAt,
2279
+ "metered",
2280
+ // Default to metered for new records
2281
+ JSON.stringify(record.usage),
2282
+ JSON.stringify(record.costSnapshot),
2283
+ record.pricingVersion,
2284
+ record.taskId ?? null,
2285
+ record.competitionId ?? null,
2286
+ record.variantId ?? null
2287
+ );
2288
+ }
2289
+ /**
2290
+ * Get execution cost record by execution ID
2291
+ * Reconstructs full ExecutionCostRecord from hybrid storage
2292
+ */
2293
+ getExecutionCost(executionId) {
2294
+ const stmt = this.db.prepare(`
2295
+ SELECT
2296
+ e.invocation_id,
2297
+ i.timestamp,
2298
+ i.provider_id,
2299
+ i.model_id,
2300
+ e.usage_data,
2301
+ e.cost_snapshot,
2302
+ e.computed_cost_cents,
2303
+ e.pricing_version,
2304
+ e.pricing_source,
2305
+ e.task_id,
2306
+ e.competition_id,
2307
+ i.agent_role,
2308
+ e.variant_id
2309
+ FROM enriched_invocations e
2310
+ JOIN model_invocations i ON e.invocation_id = i.id
2311
+ WHERE e.invocation_id = ?
2312
+ `);
2313
+ const row = stmt.get(executionId);
2314
+ if (!row) {
2315
+ return null;
2316
+ }
2317
+ const usage = row.usage_data ? parseJsonWithContext(row.usage_data, "Execution usage data") : null;
2318
+ const costSnapshot = row.cost_snapshot ? parseJsonWithContext(row.cost_snapshot, "Cost snapshot") : null;
2319
+ const resolvedCostSnapshot = resolveSnapshotFirstCostSnapshot({
2320
+ costSnapshot,
2321
+ computedCostCents: row.computed_cost_cents
2322
+ });
2323
+ if (!usage || !resolvedCostSnapshot) {
2324
+ return null;
2325
+ }
2326
+ return {
2327
+ executionId: row.invocation_id,
2328
+ timestamp: new Date(row.timestamp),
2329
+ provider: row.provider_id,
2330
+ model: row.model_id,
2331
+ usage,
2332
+ pricingVersion: row.pricing_version || "unknown",
2333
+ pricingSource: row.pricing_source || "xml",
2334
+ costSnapshot: resolvedCostSnapshot,
2335
+ computedCostCents: row.computed_cost_cents ?? void 0,
2336
+ taskId: row.task_id ?? void 0,
2337
+ competitionId: row.competition_id ?? void 0,
2338
+ agentRole: row.agent_role ?? void 0,
2339
+ variantId: row.variant_id ?? void 0
2340
+ };
2341
+ }
2342
+ /**
2343
+ * Recalculate cost for an execution using current pricing
2344
+ * Requires calculator function to be passed in to avoid circular dependency
2345
+ *
2346
+ * @param executionId - Execution ID to recalculate
2347
+ * @param calculateCost - Cost calculation function (provider, model, usage) => cost in cents
2348
+ * @returns New cost in cents, or null if execution not found or missing usage data
2349
+ */
2350
+ recalculateCost(executionId, calculateCost) {
2351
+ const record = this.getExecutionCost(executionId);
2352
+ if (!record) {
2353
+ return null;
2354
+ }
2355
+ try {
2356
+ const newCostCents = calculateCost(record.provider, record.model, record.usage);
2357
+ return newCostCents;
2358
+ } catch (error) {
2359
+ emitWarning(
2360
+ "WS-003",
2361
+ {
2362
+ taskId: "system",
2363
+ subsystem: "telemetry",
2364
+ executionPhase: "execution"
2365
+ },
2366
+ {
2367
+ severity: "WARN" /* WARN */,
2368
+ metadata: {
2369
+ operation: "recalculate_cost",
2370
+ executionId,
2371
+ error: error instanceof Error ? error.message : String(error)
2372
+ }
2373
+ }
2374
+ );
2375
+ return null;
2376
+ }
2377
+ }
2378
+ /**
2379
+ * Get all execution costs for a task
2380
+ */
2381
+ getTaskExecutionCosts(taskId) {
2382
+ const stmt = this.db.prepare(`
2383
+ SELECT
2384
+ e.invocation_id,
2385
+ i.timestamp,
2386
+ i.provider_id,
2387
+ i.model_id,
2388
+ e.usage_data,
2389
+ e.cost_snapshot,
2390
+ e.computed_cost_cents,
2391
+ e.pricing_version,
2392
+ e.pricing_source,
2393
+ e.task_id,
2394
+ e.competition_id,
2395
+ i.agent_role,
2396
+ e.variant_id
2397
+ FROM enriched_invocations e
2398
+ JOIN model_invocations i ON e.invocation_id = i.id
2399
+ WHERE e.task_id = ?
2400
+ ORDER BY i.timestamp ASC
2401
+ `);
2402
+ const rows = stmt.all(taskId);
2403
+ const mappedRecords = rows.map((row) => {
2404
+ const usage = row.usage_data ? parseJsonWithContext(row.usage_data, "Execution usage data") : null;
2405
+ const costSnapshot = row.cost_snapshot ? parseJsonWithContext(row.cost_snapshot, "Cost snapshot") : null;
2406
+ const resolvedCostSnapshot = resolveSnapshotFirstCostSnapshot({
2407
+ costSnapshot,
2408
+ computedCostCents: row.computed_cost_cents
2409
+ });
2410
+ if (!usage || !resolvedCostSnapshot) {
2411
+ return null;
2412
+ }
2413
+ return {
2414
+ executionId: row.invocation_id,
2415
+ timestamp: new Date(row.timestamp),
2416
+ provider: row.provider_id,
2417
+ model: row.model_id,
2418
+ usage,
2419
+ pricingVersion: row.pricing_version || "unknown",
2420
+ pricingSource: row.pricing_source || "xml",
2421
+ costSnapshot: resolvedCostSnapshot,
2422
+ computedCostCents: row.computed_cost_cents ?? void 0,
2423
+ taskId: row.task_id ?? void 0,
2424
+ competitionId: row.competition_id ?? void 0,
2425
+ agentRole: row.agent_role ?? void 0,
2426
+ variantId: row.variant_id ?? void 0
2427
+ };
2428
+ });
2429
+ return mappedRecords.filter((record) => record !== null);
2430
+ }
2431
+ /**
2432
+ * Get all execution costs for a competition
2433
+ */
2434
+ getCompetitionExecutionCosts(competitionId) {
2435
+ const stmt = this.db.prepare(`
2436
+ SELECT
2437
+ e.invocation_id,
2438
+ i.timestamp,
2439
+ i.provider_id,
2440
+ i.model_id,
2441
+ e.usage_data,
2442
+ e.cost_snapshot,
2443
+ e.computed_cost_cents,
2444
+ e.pricing_version,
2445
+ e.pricing_source,
2446
+ e.task_id,
2447
+ e.competition_id,
2448
+ i.agent_role,
2449
+ e.variant_id
2450
+ FROM enriched_invocations e
2451
+ JOIN model_invocations i ON e.invocation_id = i.id
2452
+ WHERE e.competition_id = ?
2453
+ ORDER BY i.timestamp ASC
2454
+ `);
2455
+ const rows = stmt.all(competitionId);
2456
+ const mappedRecords = rows.map((row) => {
2457
+ const usage = row.usage_data ? parseJsonWithContext(row.usage_data, "Execution usage data") : null;
2458
+ const costSnapshot = row.cost_snapshot ? parseJsonWithContext(row.cost_snapshot, "Cost snapshot") : null;
2459
+ const resolvedCostSnapshot = resolveSnapshotFirstCostSnapshot({
2460
+ costSnapshot,
2461
+ computedCostCents: row.computed_cost_cents
2462
+ });
2463
+ if (!usage || !resolvedCostSnapshot) {
2464
+ return null;
2465
+ }
2466
+ return {
2467
+ executionId: row.invocation_id,
2468
+ timestamp: new Date(row.timestamp),
2469
+ provider: row.provider_id,
2470
+ model: row.model_id,
2471
+ usage,
2472
+ pricingVersion: row.pricing_version || "unknown",
2473
+ pricingSource: row.pricing_source || "xml",
2474
+ costSnapshot: resolvedCostSnapshot,
2475
+ computedCostCents: row.computed_cost_cents ?? void 0,
2476
+ taskId: row.task_id ?? void 0,
2477
+ competitionId: row.competition_id ?? void 0,
2478
+ agentRole: row.agent_role ?? void 0,
2479
+ variantId: row.variant_id ?? void 0
2480
+ };
2481
+ });
2482
+ return mappedRecords.filter((record) => record !== null);
2483
+ }
2484
+ /**
2485
+ * Count invocations that have not yet been enriched with cost data.
2486
+ */
2487
+ countUnenrichedInvocations() {
2488
+ const stmt = this.db.prepare(`
2489
+ SELECT COUNT(*) as count
2490
+ FROM model_invocations i
2491
+ LEFT JOIN enriched_invocations e ON i.id = e.invocation_id
2492
+ WHERE e.id IS NULL
2493
+ `);
2494
+ const row = stmt.get();
2495
+ return row?.count ?? 0;
2496
+ }
2497
+ /**
2498
+ * Count enriched invocations since a given timestamp.
2499
+ */
2500
+ countEnrichedInvocationsSince(startTimestampMs) {
2501
+ const stmt = this.db.prepare(`
2502
+ SELECT COUNT(*) as count
2503
+ FROM enriched_invocations e
2504
+ JOIN model_invocations i ON e.invocation_id = i.id
2505
+ WHERE i.timestamp >= ?
2506
+ `);
2507
+ const row = stmt.get(startTimestampMs);
2508
+ return row?.count ?? 0;
2509
+ }
2510
+ /**
2511
+ * Whether any invocation in the window reported non-zero token usage.
2512
+ */
2513
+ hasTokenUsageSince(startTimestampMs) {
2514
+ const stmt = this.db.prepare(`
2515
+ SELECT 1
2516
+ FROM model_invocations
2517
+ WHERE timestamp >= ?
2518
+ AND (
2519
+ COALESCE(tokens_in, 0) > 0
2520
+ OR COALESCE(tokens_out, 0) > 0
2521
+ )
2522
+ LIMIT 1
2523
+ `);
2524
+ return Boolean(stmt.get(startTimestampMs));
2525
+ }
2526
+ /**
2527
+ * Count raw model invocations since a given timestamp (before cost enrichment).
2528
+ */
2529
+ countRawInvocationsSince(startTimestampMs) {
2530
+ const stmt = this.db.prepare(`
2531
+ SELECT COUNT(*) as count
2532
+ FROM model_invocations
2533
+ WHERE timestamp >= ?
2534
+ `);
2535
+ const row = stmt.get(startTimestampMs);
2536
+ return row?.count ?? 0;
2537
+ }
2538
+ /**
2539
+ * Get execution costs since a given timestamp
2540
+ */
2541
+ getExecutionCostsSince(startTimestampMs) {
2542
+ const stmt = this.db.prepare(`
2543
+ SELECT
2544
+ e.invocation_id,
2545
+ i.timestamp,
2546
+ i.provider_id,
2547
+ i.model_id,
2548
+ i.tokens_in,
2549
+ i.tokens_out,
2550
+ e.usage_data,
2551
+ e.cost_snapshot,
2552
+ e.computed_cost_cents,
2553
+ e.pricing_version,
2554
+ e.pricing_source,
2555
+ e.task_id,
2556
+ e.competition_id,
2557
+ i.agent_role,
2558
+ e.variant_id
2559
+ FROM enriched_invocations e
2560
+ JOIN model_invocations i ON e.invocation_id = i.id
2561
+ WHERE i.timestamp >= ?
2562
+ ORDER BY i.timestamp ASC
2563
+ `);
2564
+ const rows = stmt.all(startTimestampMs);
2565
+ const mappedRecords = rows.map((row) => {
2566
+ const usage = row.usage_data ? parseJsonWithContext(row.usage_data, "Execution usage data") : {
2567
+ inputTokens: row.tokens_in ?? 0,
2568
+ outputTokens: row.tokens_out ?? 0
2569
+ };
2570
+ const costSnapshot = row.cost_snapshot ? parseJsonWithContext(row.cost_snapshot, "Cost snapshot") : null;
2571
+ const resolvedCostSnapshot = resolveSnapshotFirstCostSnapshot({
2572
+ costSnapshot,
2573
+ computedCostCents: row.computed_cost_cents
2574
+ });
2575
+ if (!resolvedCostSnapshot) {
2576
+ return null;
2577
+ }
2578
+ return {
2579
+ executionId: row.invocation_id,
2580
+ timestamp: new Date(row.timestamp),
2581
+ provider: row.provider_id,
2582
+ model: row.model_id,
2583
+ usage,
2584
+ pricingVersion: row.pricing_version || "unknown",
2585
+ pricingSource: row.pricing_source || "xml",
2586
+ costSnapshot: resolvedCostSnapshot,
2587
+ computedCostCents: row.computed_cost_cents ?? void 0,
2588
+ taskId: row.task_id ?? void 0,
2589
+ competitionId: row.competition_id ?? void 0,
2590
+ agentRole: row.agent_role ?? void 0,
2591
+ variantId: row.variant_id ?? void 0
2592
+ };
2593
+ });
2594
+ return mappedRecords.filter((record) => record !== null);
2595
+ }
2596
+ /**
2597
+ * Get total cost for a task from cost snapshots.
2598
+ *
2599
+ * Returns a status-bearing amount in cents (as stored on enriched rows).
2600
+ * Known zero is valid only when priced rows exist and sum to 0.
2601
+ * Empty match set, all-null evidence, and query failures do not collapse to bare 0.
2602
+ */
2603
+ getTaskTotalCost(taskId) {
2604
+ try {
2605
+ const stmt = this.db.prepare(`
2606
+ SELECT
2607
+ ${SNAPSHOT_FIRST_COST_CENTS_SQL} AS cost_cents
2608
+ FROM enriched_invocations e
2609
+ WHERE e.task_id = ?
2610
+ `);
2611
+ const rows = stmt.all(taskId);
2612
+ if (rows.length === 0) {
2613
+ return unavailableCostAmount(
2614
+ "cents",
2615
+ ENRICHED_INVOCATIONS_SOURCE,
2616
+ `no enriched cost rows for task=${taskId}`
2617
+ );
2618
+ }
2619
+ let totalCents = 0;
2620
+ let pricedCount = 0;
2621
+ for (const row of rows) {
2622
+ if (row.cost_cents === null || row.cost_cents === void 0) {
2623
+ continue;
2624
+ }
2625
+ if (!Number.isFinite(row.cost_cents)) {
2626
+ return unavailableCostAmount(
2627
+ "cents",
2628
+ ENRICHED_INVOCATIONS_SOURCE,
2629
+ `non-finite cost evidence for task=${taskId}`
2630
+ );
2631
+ }
2632
+ pricedCount += 1;
2633
+ totalCents += row.cost_cents;
2634
+ }
2635
+ if (pricedCount === 0) {
2636
+ return unavailableCostAmount(
2637
+ "cents",
2638
+ ENRICHED_INVOCATIONS_SOURCE,
2639
+ `null or missing cost evidence for task=${taskId}`
2640
+ );
2641
+ }
2642
+ if (pricedCount < rows.length) {
2643
+ return unavailableCostAmount(
2644
+ "cents",
2645
+ ENRICHED_INVOCATIONS_SOURCE,
2646
+ `partial cost evidence for task=${taskId} (${pricedCount}/${rows.length} priced)`
2647
+ );
2648
+ }
2649
+ return availableCostAmount(totalCents, "cents", ENRICHED_INVOCATIONS_SOURCE);
2650
+ } catch (error) {
2651
+ const message = error instanceof Error ? error.message : String(error);
2652
+ return errorCostAmount(
2653
+ "cents",
2654
+ ENRICHED_INVOCATIONS_SOURCE,
2655
+ message,
2656
+ `query failure for task=${taskId}`
2657
+ );
2658
+ }
2659
+ }
2660
+ /**
2661
+ * Get cost breakdown by provider for a competition.
2662
+ *
2663
+ * Status-bearing (C11): empty match set, null/partial evidence, and query
2664
+ * failures never collapse to an empty map or bare numeric zero. Known zero is
2665
+ * returned only when priced rows exist and sum to 0. Zero-valued providers are
2666
+ * retained rather than omitted.
2667
+ */
2668
+ getCompetitionCostBreakdown(competitionId) {
2669
+ try {
2670
+ const stmt = this.db.prepare(`
2671
+ SELECT
2672
+ i.provider_id,
2673
+ SUM(${SNAPSHOT_FIRST_COST_CENTS_SQL}) as total_cost_cents,
2674
+ COUNT(*) as row_count,
2675
+ SUM(CASE WHEN ${SNAPSHOT_FIRST_COST_CENTS_SQL} IS NOT NULL THEN 1 ELSE 0 END) as priced_count
2676
+ FROM enriched_invocations e
2677
+ JOIN model_invocations i ON e.invocation_id = i.id
2678
+ WHERE e.competition_id = ?
2679
+ GROUP BY i.provider_id
2680
+ `);
2681
+ const rows = stmt.all(competitionId);
2682
+ if (rows.length === 0) {
2683
+ const total2 = unavailableCostAmount(
2684
+ "cents",
2685
+ ENRICHED_INVOCATIONS_SOURCE,
2686
+ `no enriched cost rows for competition=${competitionId}`
2687
+ );
2688
+ return {
2689
+ status: "unavailable",
2690
+ byProvider: {},
2691
+ total: total2,
2692
+ source: ENRICHED_INVOCATIONS_SOURCE,
2693
+ detail: total2.detail
2694
+ };
2695
+ }
2696
+ const byProvider = {};
2697
+ let allAvailable = true;
2698
+ let totalCents = 0;
2699
+ const partialDetails = [];
2700
+ for (const row of rows) {
2701
+ const rowCount = row.row_count ?? 0;
2702
+ const pricedCount = row.priced_count ?? 0;
2703
+ const totalCostCents = row.total_cost_cents;
2704
+ if (rowCount === 0) {
2705
+ byProvider[row.provider_id] = unavailableCostAmount(
2706
+ "cents",
2707
+ ENRICHED_INVOCATIONS_SOURCE,
2708
+ `no rows for provider=${row.provider_id} competition=${competitionId}`
2709
+ );
2710
+ allAvailable = false;
2711
+ continue;
2712
+ }
2713
+ if (pricedCount === 0 || totalCostCents === null || totalCostCents === void 0) {
2714
+ byProvider[row.provider_id] = unavailableCostAmount(
2715
+ "cents",
2716
+ ENRICHED_INVOCATIONS_SOURCE,
2717
+ `null or missing cost evidence for provider=${row.provider_id} competition=${competitionId}`
2718
+ );
2719
+ allAvailable = false;
2720
+ partialDetails.push(`${row.provider_id}:null`);
2721
+ continue;
2722
+ }
2723
+ if (pricedCount < rowCount) {
2724
+ byProvider[row.provider_id] = unavailableCostAmount(
2725
+ "cents",
2726
+ ENRICHED_INVOCATIONS_SOURCE,
2727
+ `partial cost evidence for provider=${row.provider_id} competition=${competitionId} (${pricedCount}/${rowCount} priced)`
2728
+ );
2729
+ allAvailable = false;
2730
+ partialDetails.push(`${row.provider_id}:${pricedCount}/${rowCount}`);
2731
+ continue;
2732
+ }
2733
+ byProvider[row.provider_id] = availableCostAmount(
2734
+ totalCostCents,
2735
+ "cents",
2736
+ ENRICHED_INVOCATIONS_SOURCE
2737
+ );
2738
+ totalCents += totalCostCents;
2739
+ }
2740
+ if (!allAvailable) {
2741
+ const detail = partialDetails.length > 0 ? `partial or null cost evidence for competition=${competitionId} (${partialDetails.join(", ")})` : `incomplete cost evidence for competition=${competitionId}`;
2742
+ const total2 = unavailableCostAmount("cents", ENRICHED_INVOCATIONS_SOURCE, detail);
2743
+ return {
2744
+ status: "unavailable",
2745
+ byProvider,
2746
+ total: total2,
2747
+ source: ENRICHED_INVOCATIONS_SOURCE,
2748
+ detail
2749
+ };
2750
+ }
2751
+ const total = availableCostAmount(totalCents, "cents", ENRICHED_INVOCATIONS_SOURCE);
2752
+ return {
2753
+ status: "available",
2754
+ byProvider,
2755
+ total,
2756
+ source: ENRICHED_INVOCATIONS_SOURCE
2757
+ };
2758
+ } catch (error) {
2759
+ const message = error instanceof Error ? error.message : String(error);
2760
+ const total = errorCostAmount(
2761
+ "cents",
2762
+ ENRICHED_INVOCATIONS_SOURCE,
2763
+ message,
2764
+ `query failure for competition=${competitionId}`
2765
+ );
2766
+ return {
2767
+ status: "error",
2768
+ byProvider: {},
2769
+ total,
2770
+ source: ENRICHED_INVOCATIONS_SOURCE,
2771
+ error: message,
2772
+ detail: total.detail
2773
+ };
2774
+ }
2775
+ }
2776
+ };
2777
+ function generateInvocationId() {
2778
+ return `inv_${Date.now()}_${randomBytes(8).toString("hex")}`;
2779
+ }
2780
+ function resolveInvocationsDbPath(poeticDir) {
2781
+ return path3.join(poeticDir, "telemetry", "invocations.db");
2782
+ }
2783
+
2784
+ export {
2785
+ loadProviderDirectory,
2786
+ buildRegistry,
2787
+ saveRegistry,
2788
+ SNAPSHOT_FIRST_COST_CENTS_SQL,
2789
+ ensurePendingInvocationCostEnrichment,
2790
+ summarizeInvocationCostVisibility,
2791
+ resolveInvocationRegistryVersion,
2792
+ availableCostAmount,
2793
+ unavailableCostAmount,
2794
+ errorCostAmount,
2795
+ isAvailableCostAmount,
2796
+ costAmountOrNull,
2797
+ projectCostVisibility,
2798
+ fromVisibilitySummary,
2799
+ formatCostProjectionNotice,
2800
+ invocationAnalyticsQualityClauses,
2801
+ invocationProvenanceWhereSql,
2802
+ isInvocationMetricQualityRow,
2803
+ resolveCompatibleInvocationModelId,
2804
+ invocationModelMatchesSameModel,
2805
+ ModelInvocationsDB,
2806
+ generateInvocationId,
2807
+ resolveInvocationsDbPath
2808
+ };
2809
+ //# sourceMappingURL=chunk-GKN3HMN4.js.map