modestbench 0.1.0 → 0.3.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 (484) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +162 -57
  3. package/dist/bootstrap.cjs +10 -10
  4. package/dist/bootstrap.cjs.map +1 -1
  5. package/dist/bootstrap.d.cts.map +1 -1
  6. package/dist/bootstrap.d.ts.map +1 -1
  7. package/dist/bootstrap.js +5 -5
  8. package/dist/bootstrap.js.map +1 -1
  9. package/dist/cli/commands/analyze.cjs +60 -0
  10. package/dist/cli/commands/analyze.cjs.map +1 -0
  11. package/dist/cli/commands/analyze.d.cts +35 -0
  12. package/dist/cli/commands/analyze.d.cts.map +1 -0
  13. package/dist/cli/commands/analyze.d.ts +35 -0
  14. package/dist/cli/commands/analyze.d.ts.map +1 -0
  15. package/dist/cli/commands/analyze.js +56 -0
  16. package/dist/cli/commands/analyze.js.map +1 -0
  17. package/dist/cli/commands/baseline.cjs +404 -0
  18. package/dist/cli/commands/baseline.cjs.map +1 -0
  19. package/dist/cli/commands/baseline.d.cts +72 -0
  20. package/dist/cli/commands/baseline.d.cts.map +1 -0
  21. package/dist/cli/commands/baseline.d.ts +72 -0
  22. package/dist/cli/commands/baseline.d.ts.map +1 -0
  23. package/dist/cli/commands/baseline.js +396 -0
  24. package/dist/cli/commands/baseline.js.map +1 -0
  25. package/dist/cli/commands/history.cjs +108 -266
  26. package/dist/cli/commands/history.cjs.map +1 -1
  27. package/dist/cli/commands/history.d.cts +75 -12
  28. package/dist/cli/commands/history.d.cts.map +1 -1
  29. package/dist/cli/commands/history.d.ts +75 -12
  30. package/dist/cli/commands/history.d.ts.map +1 -1
  31. package/dist/cli/commands/history.js +105 -268
  32. package/dist/cli/commands/history.js.map +1 -1
  33. package/dist/cli/commands/init.cjs +88 -155
  34. package/dist/cli/commands/init.cjs.map +1 -1
  35. package/dist/cli/commands/init.d.cts +4 -4
  36. package/dist/cli/commands/init.d.cts.map +1 -1
  37. package/dist/cli/commands/init.d.ts +4 -4
  38. package/dist/cli/commands/init.d.ts.map +1 -1
  39. package/dist/cli/commands/init.js +88 -155
  40. package/dist/cli/commands/init.js.map +1 -1
  41. package/dist/cli/commands/run.cjs +143 -112
  42. package/dist/cli/commands/run.cjs.map +1 -1
  43. package/dist/cli/commands/run.d.cts +17 -3
  44. package/dist/cli/commands/run.d.cts.map +1 -1
  45. package/dist/cli/commands/run.d.ts +17 -3
  46. package/dist/cli/commands/run.d.ts.map +1 -1
  47. package/dist/cli/commands/run.js +142 -78
  48. package/dist/cli/commands/run.js.map +1 -1
  49. package/dist/cli/index.cjs +671 -266
  50. package/dist/cli/index.cjs.map +1 -1
  51. package/dist/cli/index.d.cts +4 -16
  52. package/dist/cli/index.d.cts.map +1 -1
  53. package/dist/cli/index.d.ts +4 -16
  54. package/dist/cli/index.d.ts.map +1 -1
  55. package/dist/cli/index.js +664 -259
  56. package/dist/cli/index.js.map +1 -1
  57. package/dist/config/budget-schema.cjs +172 -0
  58. package/dist/config/budget-schema.cjs.map +1 -0
  59. package/dist/config/budget-schema.d.cts +59 -0
  60. package/dist/config/budget-schema.d.cts.map +1 -0
  61. package/dist/config/budget-schema.d.ts +59 -0
  62. package/dist/config/budget-schema.d.ts.map +1 -0
  63. package/dist/config/budget-schema.js +166 -0
  64. package/dist/config/budget-schema.js.map +1 -0
  65. package/dist/config/schema.cjs +182 -2
  66. package/dist/config/schema.cjs.map +1 -1
  67. package/dist/config/schema.d.cts +122 -3
  68. package/dist/config/schema.d.cts.map +1 -1
  69. package/dist/config/schema.d.ts +122 -3
  70. package/dist/config/schema.d.ts.map +1 -1
  71. package/dist/config/schema.js +180 -1
  72. package/dist/config/schema.js.map +1 -1
  73. package/dist/constants.cjs +45 -2
  74. package/dist/constants.cjs.map +1 -1
  75. package/dist/constants.d.cts +41 -0
  76. package/dist/constants.d.cts.map +1 -1
  77. package/dist/constants.d.ts +41 -0
  78. package/dist/constants.d.ts.map +1 -1
  79. package/dist/constants.js +44 -1
  80. package/dist/constants.js.map +1 -1
  81. package/dist/core/engine.cjs +104 -15
  82. package/dist/core/engine.cjs.map +1 -1
  83. package/dist/core/engine.d.cts +7 -4
  84. package/dist/core/engine.d.cts.map +1 -1
  85. package/dist/core/engine.d.ts +7 -4
  86. package/dist/core/engine.d.ts.map +1 -1
  87. package/dist/core/engine.js +105 -16
  88. package/dist/core/engine.js.map +1 -1
  89. package/dist/core/output-path-resolver.cjs +41 -0
  90. package/dist/core/output-path-resolver.cjs.map +1 -0
  91. package/dist/core/output-path-resolver.d.cts +10 -0
  92. package/dist/core/output-path-resolver.d.cts.map +1 -0
  93. package/dist/core/output-path-resolver.d.ts +10 -0
  94. package/dist/core/output-path-resolver.d.ts.map +1 -0
  95. package/dist/core/output-path-resolver.js +37 -0
  96. package/dist/core/output-path-resolver.js.map +1 -0
  97. package/dist/errors/base.cjs +12 -3
  98. package/dist/errors/base.cjs.map +1 -1
  99. package/dist/errors/base.d.cts +7 -0
  100. package/dist/errors/base.d.cts.map +1 -1
  101. package/dist/errors/base.d.ts +7 -0
  102. package/dist/errors/base.d.ts.map +1 -1
  103. package/dist/errors/base.js +10 -2
  104. package/dist/errors/base.js.map +1 -1
  105. package/dist/errors/budget.cjs +37 -0
  106. package/dist/errors/budget.cjs.map +1 -0
  107. package/dist/errors/budget.d.cts +31 -0
  108. package/dist/errors/budget.d.cts.map +1 -0
  109. package/dist/errors/budget.d.ts +31 -0
  110. package/dist/errors/budget.d.ts.map +1 -0
  111. package/dist/errors/budget.js +33 -0
  112. package/dist/errors/budget.js.map +1 -0
  113. package/dist/errors/index.cjs +4 -1
  114. package/dist/errors/index.cjs.map +1 -1
  115. package/dist/errors/index.d.cts +1 -0
  116. package/dist/errors/index.d.cts.map +1 -1
  117. package/dist/errors/index.d.ts +1 -0
  118. package/dist/errors/index.d.ts.map +1 -1
  119. package/dist/errors/index.js +2 -0
  120. package/dist/errors/index.js.map +1 -1
  121. package/dist/formatters/history/base.cjs +9 -0
  122. package/dist/formatters/history/base.cjs.map +1 -0
  123. package/dist/formatters/history/base.d.cts +26 -0
  124. package/dist/formatters/history/base.d.cts.map +1 -0
  125. package/dist/formatters/history/base.d.ts +26 -0
  126. package/dist/formatters/history/base.d.ts.map +1 -0
  127. package/dist/formatters/history/base.js +8 -0
  128. package/dist/formatters/history/base.js.map +1 -0
  129. package/dist/formatters/history/compare.cjs +127 -0
  130. package/dist/formatters/history/compare.cjs.map +1 -0
  131. package/dist/formatters/history/compare.d.cts +21 -0
  132. package/dist/formatters/history/compare.d.cts.map +1 -0
  133. package/dist/formatters/history/compare.d.ts +21 -0
  134. package/dist/formatters/history/compare.d.ts.map +1 -0
  135. package/dist/formatters/history/compare.js +123 -0
  136. package/dist/formatters/history/compare.js.map +1 -0
  137. package/dist/formatters/history/list.cjs +74 -0
  138. package/dist/formatters/history/list.cjs.map +1 -0
  139. package/dist/formatters/history/list.d.cts +25 -0
  140. package/dist/formatters/history/list.d.cts.map +1 -0
  141. package/dist/formatters/history/list.d.ts +25 -0
  142. package/dist/formatters/history/list.d.ts.map +1 -0
  143. package/dist/formatters/history/list.js +70 -0
  144. package/dist/formatters/history/list.js.map +1 -0
  145. package/dist/formatters/history/show.cjs +98 -0
  146. package/dist/formatters/history/show.cjs.map +1 -0
  147. package/dist/formatters/history/show.d.cts +21 -0
  148. package/dist/formatters/history/show.d.cts.map +1 -0
  149. package/dist/formatters/history/show.d.ts +21 -0
  150. package/dist/formatters/history/show.d.ts.map +1 -0
  151. package/dist/formatters/history/show.js +94 -0
  152. package/dist/formatters/history/show.js.map +1 -0
  153. package/dist/formatters/history/trends.cjs +194 -0
  154. package/dist/formatters/history/trends.cjs.map +1 -0
  155. package/dist/formatters/history/trends.d.cts +22 -0
  156. package/dist/formatters/history/trends.d.cts.map +1 -0
  157. package/dist/formatters/history/trends.d.ts +22 -0
  158. package/dist/formatters/history/trends.d.ts.map +1 -0
  159. package/dist/formatters/history/trends.js +190 -0
  160. package/dist/formatters/history/trends.js.map +1 -0
  161. package/dist/formatters/history/visualization.cjs +79 -0
  162. package/dist/formatters/history/visualization.cjs.map +1 -0
  163. package/dist/formatters/history/visualization.d.cts +24 -0
  164. package/dist/formatters/history/visualization.d.cts.map +1 -0
  165. package/dist/formatters/history/visualization.d.ts +24 -0
  166. package/dist/formatters/history/visualization.d.ts.map +1 -0
  167. package/dist/formatters/history/visualization.js +74 -0
  168. package/dist/formatters/history/visualization.js.map +1 -0
  169. package/dist/index.cjs +27 -17
  170. package/dist/index.cjs.map +1 -1
  171. package/dist/index.d.cts +10 -5
  172. package/dist/index.d.cts.map +1 -1
  173. package/dist/index.d.ts +10 -5
  174. package/dist/index.d.ts.map +1 -1
  175. package/dist/index.js +14 -9
  176. package/dist/index.js.map +1 -1
  177. package/dist/reporters/csv.cjs +39 -19
  178. package/dist/reporters/csv.cjs.map +1 -1
  179. package/dist/reporters/csv.d.cts +4 -7
  180. package/dist/reporters/csv.d.cts.map +1 -1
  181. package/dist/reporters/csv.d.ts +4 -7
  182. package/dist/reporters/csv.d.ts.map +1 -1
  183. package/dist/reporters/csv.js +38 -18
  184. package/dist/reporters/csv.js.map +1 -1
  185. package/dist/reporters/human.cjs +87 -99
  186. package/dist/reporters/human.cjs.map +1 -1
  187. package/dist/reporters/human.d.cts +15 -14
  188. package/dist/reporters/human.d.cts.map +1 -1
  189. package/dist/reporters/human.d.ts +15 -14
  190. package/dist/reporters/human.d.ts.map +1 -1
  191. package/dist/reporters/human.js +68 -80
  192. package/dist/reporters/human.js.map +1 -1
  193. package/dist/reporters/json.cjs +25 -50
  194. package/dist/reporters/json.cjs.map +1 -1
  195. package/dist/reporters/json.d.cts +3 -29
  196. package/dist/reporters/json.d.cts.map +1 -1
  197. package/dist/reporters/json.d.ts +3 -29
  198. package/dist/reporters/json.d.ts.map +1 -1
  199. package/dist/reporters/json.js +26 -51
  200. package/dist/reporters/json.js.map +1 -1
  201. package/dist/reporters/profile-human.cjs +149 -0
  202. package/dist/reporters/profile-human.cjs.map +1 -0
  203. package/dist/reporters/profile-human.d.cts +44 -0
  204. package/dist/reporters/profile-human.d.cts.map +1 -0
  205. package/dist/reporters/profile-human.d.ts +44 -0
  206. package/dist/reporters/profile-human.d.ts.map +1 -0
  207. package/dist/reporters/profile-human.js +142 -0
  208. package/dist/reporters/profile-human.js.map +1 -0
  209. package/dist/reporters/simple.cjs +66 -46
  210. package/dist/reporters/simple.cjs.map +1 -1
  211. package/dist/reporters/simple.d.cts +15 -15
  212. package/dist/reporters/simple.d.cts.map +1 -1
  213. package/dist/reporters/simple.d.ts +15 -15
  214. package/dist/reporters/simple.d.ts.map +1 -1
  215. package/dist/reporters/simple.js +65 -45
  216. package/dist/reporters/simple.js.map +1 -1
  217. package/dist/schema/modestbench-config.schema.json +153 -0
  218. package/dist/services/baseline-storage.cjs +151 -0
  219. package/dist/services/baseline-storage.cjs.map +1 -0
  220. package/dist/services/baseline-storage.d.cts +55 -0
  221. package/dist/services/baseline-storage.d.cts.map +1 -0
  222. package/dist/services/baseline-storage.d.ts +55 -0
  223. package/dist/services/baseline-storage.d.ts.map +1 -0
  224. package/dist/services/baseline-storage.js +147 -0
  225. package/dist/services/baseline-storage.js.map +1 -0
  226. package/dist/services/budget-evaluator.cjs +146 -0
  227. package/dist/services/budget-evaluator.cjs.map +1 -0
  228. package/dist/services/budget-evaluator.d.cts +29 -0
  229. package/dist/services/budget-evaluator.d.cts.map +1 -0
  230. package/dist/services/budget-evaluator.d.ts +29 -0
  231. package/dist/services/budget-evaluator.d.ts.map +1 -0
  232. package/dist/services/budget-evaluator.js +142 -0
  233. package/dist/services/budget-evaluator.js.map +1 -0
  234. package/dist/{config/manager.cjs → services/config-manager.cjs} +25 -11
  235. package/dist/services/config-manager.cjs.map +1 -0
  236. package/dist/{config/manager.d.cts → services/config-manager.d.cts} +7 -2
  237. package/dist/services/config-manager.d.cts.map +1 -0
  238. package/dist/{config/manager.d.ts → services/config-manager.d.ts} +7 -2
  239. package/dist/services/config-manager.d.ts.map +1 -0
  240. package/dist/{config/manager.js → services/config-manager.js} +25 -11
  241. package/dist/services/config-manager.js.map +1 -0
  242. package/dist/{core/loader.cjs → services/file-loader.cjs} +5 -8
  243. package/dist/services/file-loader.cjs.map +1 -0
  244. package/dist/{core/loader.d.cts → services/file-loader.d.cts} +1 -1
  245. package/dist/services/file-loader.d.cts.map +1 -0
  246. package/dist/{core/loader.d.ts → services/file-loader.d.ts} +1 -1
  247. package/dist/services/file-loader.d.ts.map +1 -0
  248. package/dist/{core/loader.js → services/file-loader.js} +5 -8
  249. package/dist/services/file-loader.js.map +1 -0
  250. package/dist/services/history/comparison.cjs +124 -0
  251. package/dist/services/history/comparison.cjs.map +1 -0
  252. package/dist/services/history/comparison.d.cts +18 -0
  253. package/dist/services/history/comparison.d.cts.map +1 -0
  254. package/dist/services/history/comparison.d.ts +18 -0
  255. package/dist/services/history/comparison.d.ts.map +1 -0
  256. package/dist/services/history/comparison.js +120 -0
  257. package/dist/services/history/comparison.js.map +1 -0
  258. package/dist/services/history/models.cjs +9 -0
  259. package/dist/services/history/models.cjs.map +1 -0
  260. package/dist/services/history/models.d.cts +139 -0
  261. package/dist/services/history/models.d.cts.map +1 -0
  262. package/dist/services/history/models.d.ts +139 -0
  263. package/dist/services/history/models.d.ts.map +1 -0
  264. package/dist/services/history/models.js +8 -0
  265. package/dist/services/history/models.js.map +1 -0
  266. package/dist/services/history/query.cjs +97 -0
  267. package/dist/services/history/query.cjs.map +1 -0
  268. package/dist/services/history/query.d.cts +38 -0
  269. package/dist/services/history/query.d.cts.map +1 -0
  270. package/dist/services/history/query.d.ts +38 -0
  271. package/dist/services/history/query.d.ts.map +1 -0
  272. package/dist/services/history/query.js +92 -0
  273. package/dist/services/history/query.js.map +1 -0
  274. package/dist/services/history/trend-analysis.cjs +187 -0
  275. package/dist/services/history/trend-analysis.cjs.map +1 -0
  276. package/dist/services/history/trend-analysis.d.cts +34 -0
  277. package/dist/services/history/trend-analysis.d.cts.map +1 -0
  278. package/dist/services/history/trend-analysis.d.ts +34 -0
  279. package/dist/services/history/trend-analysis.d.ts.map +1 -0
  280. package/dist/services/history/trend-analysis.js +179 -0
  281. package/dist/services/history/trend-analysis.js.map +1 -0
  282. package/dist/{storage/history.cjs → services/history-storage.cjs} +1 -1
  283. package/dist/services/history-storage.cjs.map +1 -0
  284. package/dist/{storage/history.d.cts → services/history-storage.d.cts} +1 -1
  285. package/dist/services/history-storage.d.cts.map +1 -0
  286. package/dist/{storage/history.d.ts → services/history-storage.d.ts} +1 -1
  287. package/dist/services/history-storage.d.ts.map +1 -0
  288. package/dist/{storage/history.js → services/history-storage.js} +1 -1
  289. package/dist/services/history-storage.js.map +1 -0
  290. package/dist/services/profiler/profile-filter.cjs +113 -0
  291. package/dist/services/profiler/profile-filter.cjs.map +1 -0
  292. package/dist/services/profiler/profile-filter.d.cts +20 -0
  293. package/dist/services/profiler/profile-filter.d.cts.map +1 -0
  294. package/dist/services/profiler/profile-filter.d.ts +20 -0
  295. package/dist/services/profiler/profile-filter.d.ts.map +1 -0
  296. package/dist/services/profiler/profile-filter.js +109 -0
  297. package/dist/services/profiler/profile-filter.js.map +1 -0
  298. package/dist/services/profiler/profile-parser.cjs +139 -0
  299. package/dist/services/profiler/profile-parser.cjs.map +1 -0
  300. package/dist/services/profiler/profile-parser.d.cts +18 -0
  301. package/dist/services/profiler/profile-parser.d.cts.map +1 -0
  302. package/dist/services/profiler/profile-parser.d.ts +18 -0
  303. package/dist/services/profiler/profile-parser.d.ts.map +1 -0
  304. package/dist/services/profiler/profile-parser.js +132 -0
  305. package/dist/services/profiler/profile-parser.js.map +1 -0
  306. package/dist/services/profiler/profile-runner.cjs +90 -0
  307. package/dist/services/profiler/profile-runner.cjs.map +1 -0
  308. package/dist/services/profiler/profile-runner.d.cts +29 -0
  309. package/dist/services/profiler/profile-runner.d.cts.map +1 -0
  310. package/dist/services/profiler/profile-runner.d.ts +29 -0
  311. package/dist/services/profiler/profile-runner.d.ts.map +1 -0
  312. package/dist/services/profiler/profile-runner.js +86 -0
  313. package/dist/services/profiler/profile-runner.js.map +1 -0
  314. package/dist/{progress/manager.cjs → services/progress-manager.cjs} +1 -1
  315. package/dist/services/progress-manager.cjs.map +1 -0
  316. package/dist/{progress/manager.d.cts → services/progress-manager.d.cts} +1 -1
  317. package/dist/services/progress-manager.d.cts.map +1 -0
  318. package/dist/{progress/manager.d.ts → services/progress-manager.d.ts} +1 -1
  319. package/dist/services/progress-manager.d.ts.map +1 -0
  320. package/dist/{progress/manager.js → services/progress-manager.js} +1 -1
  321. package/dist/services/progress-manager.js.map +1 -0
  322. package/dist/{reporters/registry.cjs → services/reporter-registry.cjs} +19 -25
  323. package/dist/services/reporter-registry.cjs.map +1 -0
  324. package/dist/{reporters/registry.d.cts → services/reporter-registry.d.cts} +19 -41
  325. package/dist/services/reporter-registry.d.cts.map +1 -0
  326. package/dist/{reporters/registry.d.ts → services/reporter-registry.d.ts} +19 -41
  327. package/dist/services/reporter-registry.d.ts.map +1 -0
  328. package/dist/{reporters/registry.js → services/reporter-registry.js} +19 -25
  329. package/dist/services/reporter-registry.js.map +1 -0
  330. package/dist/types/budgets.cjs +8 -0
  331. package/dist/types/budgets.cjs.map +1 -0
  332. package/dist/types/budgets.d.cts +149 -0
  333. package/dist/types/budgets.d.cts.map +1 -0
  334. package/dist/types/budgets.d.ts +149 -0
  335. package/dist/types/budgets.d.ts.map +1 -0
  336. package/dist/types/budgets.js +7 -0
  337. package/dist/types/budgets.js.map +1 -0
  338. package/dist/types/cli.cjs +2 -11
  339. package/dist/types/cli.cjs.map +1 -1
  340. package/dist/types/cli.d.cts +3 -224
  341. package/dist/types/cli.d.cts.map +1 -1
  342. package/dist/types/cli.d.ts +3 -224
  343. package/dist/types/cli.d.ts.map +1 -1
  344. package/dist/types/cli.js +2 -11
  345. package/dist/types/cli.js.map +1 -1
  346. package/dist/types/core.cjs +6 -1
  347. package/dist/types/core.cjs.map +1 -1
  348. package/dist/types/core.d.cts +13 -2
  349. package/dist/types/core.d.cts.map +1 -1
  350. package/dist/types/core.d.ts +13 -2
  351. package/dist/types/core.d.ts.map +1 -1
  352. package/dist/types/core.js +2 -1
  353. package/dist/types/core.js.map +1 -1
  354. package/dist/types/index.cjs +5 -0
  355. package/dist/types/index.cjs.map +1 -1
  356. package/dist/types/index.d.cts +2 -0
  357. package/dist/types/index.d.cts.map +1 -1
  358. package/dist/types/index.d.ts +2 -0
  359. package/dist/types/index.d.ts.map +1 -1
  360. package/dist/types/index.js +2 -0
  361. package/dist/types/index.js.map +1 -1
  362. package/dist/types/interfaces.d.cts +15 -8
  363. package/dist/types/interfaces.d.cts.map +1 -1
  364. package/dist/types/interfaces.d.ts +15 -8
  365. package/dist/types/interfaces.d.ts.map +1 -1
  366. package/dist/types/profiler.cjs +11 -0
  367. package/dist/types/profiler.cjs.map +1 -0
  368. package/dist/types/profiler.d.cts +100 -0
  369. package/dist/types/profiler.d.cts.map +1 -0
  370. package/dist/types/profiler.d.ts +100 -0
  371. package/dist/types/profiler.d.ts.map +1 -0
  372. package/dist/types/profiler.js +10 -0
  373. package/dist/types/profiler.js.map +1 -0
  374. package/dist/types/utility.cjs.map +1 -1
  375. package/dist/types/utility.d.cts +0 -8
  376. package/dist/types/utility.d.cts.map +1 -1
  377. package/dist/types/utility.d.ts +0 -8
  378. package/dist/types/utility.d.ts.map +1 -1
  379. package/dist/types/utility.js.map +1 -1
  380. package/dist/utils/ansi.cjs +61 -0
  381. package/dist/utils/ansi.cjs.map +1 -0
  382. package/dist/utils/ansi.d.cts +53 -0
  383. package/dist/utils/ansi.d.cts.map +1 -0
  384. package/dist/utils/ansi.d.ts +53 -0
  385. package/dist/utils/ansi.d.ts.map +1 -0
  386. package/dist/utils/ansi.js +57 -0
  387. package/dist/utils/ansi.js.map +1 -0
  388. package/dist/utils/identifiers.cjs +32 -0
  389. package/dist/utils/identifiers.cjs.map +1 -0
  390. package/dist/utils/identifiers.d.cts +32 -0
  391. package/dist/utils/identifiers.d.cts.map +1 -0
  392. package/dist/utils/identifiers.d.ts +32 -0
  393. package/dist/utils/identifiers.d.ts.map +1 -0
  394. package/dist/utils/identifiers.js +27 -0
  395. package/dist/utils/identifiers.js.map +1 -0
  396. package/dist/utils/package.cjs +40 -0
  397. package/dist/utils/package.cjs.map +1 -0
  398. package/dist/utils/package.d.cts +15 -0
  399. package/dist/utils/package.d.cts.map +1 -0
  400. package/dist/utils/package.d.ts +15 -0
  401. package/dist/utils/package.d.ts.map +1 -0
  402. package/dist/utils/package.js +33 -0
  403. package/dist/utils/package.js.map +1 -0
  404. package/dist/utils/type-guards.cjs +48 -0
  405. package/dist/utils/type-guards.cjs.map +1 -0
  406. package/dist/utils/type-guards.d.cts +22 -0
  407. package/dist/utils/type-guards.d.cts.map +1 -0
  408. package/dist/utils/type-guards.d.ts +22 -0
  409. package/dist/utils/type-guards.d.ts.map +1 -0
  410. package/dist/utils/type-guards.js +43 -0
  411. package/dist/utils/type-guards.js.map +1 -0
  412. package/package.json +14 -13
  413. package/src/bootstrap.ts +5 -5
  414. package/src/cli/commands/analyze.ts +101 -0
  415. package/src/cli/commands/baseline.ts +577 -0
  416. package/src/cli/commands/history.ts +194 -342
  417. package/src/cli/commands/init.ts +105 -183
  418. package/src/cli/commands/run.ts +186 -88
  419. package/src/cli/index.ts +731 -234
  420. package/src/config/budget-schema.ts +189 -0
  421. package/src/config/schema.ts +260 -1
  422. package/src/constants.ts +53 -1
  423. package/src/core/engine.ts +153 -14
  424. package/src/core/output-path-resolver.ts +46 -0
  425. package/src/errors/base.ts +11 -2
  426. package/src/errors/budget.ts +38 -0
  427. package/src/errors/index.ts +3 -0
  428. package/src/formatters/history/base.ts +28 -0
  429. package/src/formatters/history/compare.ts +186 -0
  430. package/src/formatters/history/list.ts +101 -0
  431. package/src/formatters/history/show.ts +155 -0
  432. package/src/formatters/history/trends.ts +281 -0
  433. package/src/formatters/history/visualization.ts +93 -0
  434. package/src/index.ts +17 -12
  435. package/src/reporters/csv.ts +55 -26
  436. package/src/reporters/human.ts +90 -89
  437. package/src/reporters/json.ts +27 -72
  438. package/src/reporters/profile-human.ts +204 -0
  439. package/src/reporters/simple.ts +85 -54
  440. package/src/services/baseline-storage.ts +199 -0
  441. package/src/services/budget-evaluator.ts +182 -0
  442. package/src/{config/manager.ts → services/config-manager.ts} +24 -9
  443. package/src/{core/loader.ts → services/file-loader.ts} +4 -7
  444. package/src/services/history/comparison.ts +130 -0
  445. package/src/services/history/models.ts +148 -0
  446. package/src/services/history/query.ts +116 -0
  447. package/src/services/history/trend-analysis.ts +238 -0
  448. package/src/services/profiler/profile-filter.ts +143 -0
  449. package/src/services/profiler/profile-parser.ts +194 -0
  450. package/src/services/profiler/profile-runner.ts +121 -0
  451. package/src/{reporters/registry.ts → services/reporter-registry.ts} +46 -81
  452. package/src/types/budgets.ts +180 -0
  453. package/src/types/cli.ts +5 -235
  454. package/src/types/core.ts +50 -10
  455. package/src/types/index.ts +5 -0
  456. package/src/types/interfaces.ts +16 -6
  457. package/src/types/profiler.ts +132 -0
  458. package/src/types/utility.ts +0 -10
  459. package/src/utils/ansi.ts +59 -0
  460. package/src/utils/identifiers.ts +58 -0
  461. package/src/utils/package.ts +35 -0
  462. package/src/utils/type-guards.ts +51 -0
  463. package/dist/config/manager.cjs.map +0 -1
  464. package/dist/config/manager.d.cts.map +0 -1
  465. package/dist/config/manager.d.ts.map +0 -1
  466. package/dist/config/manager.js.map +0 -1
  467. package/dist/core/loader.cjs.map +0 -1
  468. package/dist/core/loader.d.cts.map +0 -1
  469. package/dist/core/loader.d.ts.map +0 -1
  470. package/dist/core/loader.js.map +0 -1
  471. package/dist/progress/manager.cjs.map +0 -1
  472. package/dist/progress/manager.d.cts.map +0 -1
  473. package/dist/progress/manager.d.ts.map +0 -1
  474. package/dist/progress/manager.js.map +0 -1
  475. package/dist/reporters/registry.cjs.map +0 -1
  476. package/dist/reporters/registry.d.cts.map +0 -1
  477. package/dist/reporters/registry.d.ts.map +0 -1
  478. package/dist/reporters/registry.js.map +0 -1
  479. package/dist/storage/history.cjs.map +0 -1
  480. package/dist/storage/history.d.cts.map +0 -1
  481. package/dist/storage/history.d.ts.map +0 -1
  482. package/dist/storage/history.js.map +0 -1
  483. /package/src/{storage/history.ts → services/history-storage.ts} +0 -0
  484. /package/src/{progress/manager.ts → services/progress-manager.ts} +0 -0
@@ -11,20 +11,24 @@ import { dirname } from 'node:path';
11
11
 
12
12
  import type {
13
13
  BenchmarkRun,
14
- FileResult,
15
- ProgressState,
16
- SuiteResult,
14
+ BudgetResult,
15
+ BudgetSummary,
16
+ TaskId,
17
17
  TaskResult,
18
18
  } from '../types/index.js';
19
19
 
20
20
  import { ReporterOutputError } from '../errors/index.js';
21
- import { BaseReporter } from './registry.js';
21
+ import { BaseReporter } from '../services/reporter-registry.js';
22
+ import { createTaskId } from '../types/index.js';
22
23
 
23
24
  /**
24
25
  * CSV column definitions for task results
25
26
  */
26
27
  interface CsvRow {
27
28
  readonly arch: string;
29
+ /** Budget passed: 1 (pass), 0 (fail), undefined (no budget) */
30
+ readonly budgetPassed?: number | undefined;
31
+ readonly budgetViolations?: string | undefined;
28
32
  readonly ciProvider?: string | undefined;
29
33
  readonly cpuCores: number;
30
34
  readonly cpuModel: string;
@@ -54,6 +58,8 @@ interface CsvRow {
54
58
  * CSV reporter for structured tabular output
55
59
  */
56
60
  export class CsvReporter extends BaseReporter {
61
+ private budgetResults: Map<TaskId, BudgetResult> = new Map();
62
+
57
63
  private currentFile = '';
58
64
 
59
65
  private currentRun?: BenchmarkRun;
@@ -68,8 +74,6 @@ export class CsvReporter extends BaseReporter {
68
74
 
69
75
  private readonly outputPath?: string | undefined;
70
76
 
71
- private readonly quiet: boolean;
72
-
73
77
  private readonly quote: string;
74
78
 
75
79
  private rows: CsvRow[] = [];
@@ -92,7 +96,6 @@ export class CsvReporter extends BaseReporter {
92
96
  this.includeMetadata = options.includeMetadata ?? true;
93
97
  this.delimiter = options.delimiter ?? ',';
94
98
  this.quote = options.quote ?? '"';
95
- this.quiet = options.quiet ?? false;
96
99
  }
97
100
 
98
101
  /**
@@ -137,6 +140,31 @@ export class CsvReporter extends BaseReporter {
137
140
  return this.includeMetadata;
138
141
  }
139
142
 
143
+ onBudgetResult(summary: BudgetSummary): void {
144
+ // Store budget results indexed by taskId
145
+ for (const result of summary.results) {
146
+ this.budgetResults.set(result.taskId, result);
147
+ }
148
+
149
+ // Update existing rows with budget data (since onTaskResult is called before onBudgetResult)
150
+ for (const row of this.rows) {
151
+ // row.file is already relative to cwd
152
+ const taskId = createTaskId(row.file, row.suite, row.task);
153
+ const budgetResult = this.budgetResults.get(taskId);
154
+ if (budgetResult) {
155
+ // Need to cast to mutable to update readonly properties
156
+ const mutableRow = row as {
157
+ budgetPassed?: number;
158
+ budgetViolations?: string;
159
+ };
160
+ mutableRow.budgetPassed = budgetResult.passed ? 1 : 0;
161
+ mutableRow.budgetViolations = budgetResult.violations
162
+ .map((v) => v.type)
163
+ .join('; ');
164
+ }
165
+ }
166
+ }
167
+
140
168
  async onEnd(_run: BenchmarkRun): Promise<void> {
141
169
  const csvContent = this.generateCsv();
142
170
 
@@ -151,27 +179,15 @@ export class CsvReporter extends BaseReporter {
151
179
  console.error('CSV Reporter Error:', error.message);
152
180
  }
153
181
 
154
- onFileEnd(_result: FileResult): void {
155
- // No-op for CSV reporter
156
- }
157
-
158
182
  onFileStart(file: string): void {
159
183
  this.currentFile = file;
160
184
  }
161
185
 
162
- onProgress(_state: ProgressState): void {
163
- // No-op for CSV reporter
164
- }
165
-
166
186
  onStart(run: BenchmarkRun): void {
167
187
  this.currentRun = run;
168
188
  this.rows = [];
169
189
  }
170
190
 
171
- onSuiteEnd(_result: SuiteResult): void {
172
- // No-op for CSV reporter
173
- }
174
-
175
191
  onSuiteStart(suite: string): void {
176
192
  this.currentSuite = suite;
177
193
  }
@@ -181,8 +197,21 @@ export class CsvReporter extends BaseReporter {
181
197
  return;
182
198
  }
183
199
 
200
+ // Look up budget result for this task
201
+ // this.currentFile is already relative to cwd (comes from engine)
202
+ const taskId = createTaskId(
203
+ this.currentFile,
204
+ this.currentSuite,
205
+ result.name,
206
+ );
207
+ const budgetResult = this.budgetResults.get(taskId);
208
+
184
209
  const row: CsvRow = {
185
210
  arch: this.currentRun.environment.arch,
211
+ budgetPassed: budgetResult ? (budgetResult.passed ? 1 : 0) : undefined,
212
+ budgetViolations: budgetResult
213
+ ? budgetResult.violations.map((v) => v.type).join('; ')
214
+ : undefined,
186
215
  ciProvider: this.currentRun.ci?.provider,
187
216
  cpuCores: this.currentRun.environment.cpu.cores,
188
217
  cpuModel: this.currentRun.environment.cpu.model,
@@ -211,10 +240,6 @@ export class CsvReporter extends BaseReporter {
211
240
  this.rows.push(row);
212
241
  }
213
242
 
214
- onTaskStart(_task: string): void {
215
- // No-op for CSV reporter
216
- }
217
-
218
243
  /**
219
244
  * Escape a field value for CSV format
220
245
  */
@@ -277,6 +302,8 @@ export class CsvReporter extends BaseReporter {
277
302
  'p95',
278
303
  'p99',
279
304
  'error',
305
+ 'budgetPassed',
306
+ 'budgetViolations',
280
307
  'timestamp',
281
308
  ];
282
309
 
@@ -302,9 +329,9 @@ export class CsvReporter extends BaseReporter {
302
329
  */
303
330
  private generateRow(row: CsvRow): string {
304
331
  const values = [
305
- row.file || '',
306
- row.suite || '',
307
- row.task || '',
332
+ row.file,
333
+ row.suite,
334
+ row.task,
308
335
  (row.mean ?? 0).toString(),
309
336
  (row.stdDev ?? 0).toString(),
310
337
  (row.min ?? 0).toString(),
@@ -316,6 +343,8 @@ export class CsvReporter extends BaseReporter {
316
343
  (row.p95 ?? 0).toString(),
317
344
  (row.p99 ?? 0).toString(),
318
345
  row.error || '',
346
+ row.budgetPassed !== undefined ? row.budgetPassed.toString() : '',
347
+ row.budgetViolations || '',
319
348
  row.timestamp || '',
320
349
  ];
321
350
 
@@ -9,54 +9,15 @@ import path from 'node:path';
9
9
 
10
10
  import type {
11
11
  BenchmarkRun,
12
+ BudgetSummary,
12
13
  FileResult,
13
14
  ProgressState,
14
15
  SuiteResult,
15
16
  TaskResult,
16
17
  } from '../types/index.js';
17
18
 
18
- import { BaseReporter } from './registry.js';
19
-
20
- /**
21
- * ANSI color codes for terminal output
22
- */
23
- const colors = {
24
- bold: '\x1b[1m',
25
- brightBlue: '\x1b[94m',
26
- brightCyan: '\x1b[96m',
27
- brightMagenta: '\x1b[95m',
28
- brightRed: '\x1b[91m',
29
- brightWhite: '\x1b[97m',
30
- cyan: '\x1b[36m',
31
- dim: '\x1b[2m',
32
- gray: '\x1b[90m',
33
- green: '\x1b[32m',
34
- magenta: '\x1b[35m',
35
- red: '\x1b[31m',
36
- reset: '\x1b[0m',
37
- underline: '\x1b[4m',
38
- white: '\x1b[37m',
39
- } as const;
40
-
41
- /**
42
- * CP437-inspired ANSI art characters
43
- */
44
- const ansiChars = {
45
- approx: '≈',
46
- // Block elements for gradients
47
- block: {
48
- dark: '▓',
49
- full: '█',
50
- light: '░',
51
- medium: '▒',
52
- },
53
- bullet: '•',
54
- // Symbols
55
- checkmark: '√',
56
- cross: '×',
57
- plusMinus: '±',
58
- smallSquare: '▪',
59
- } as const;
19
+ import { BaseReporter } from '../services/reporter-registry.js';
20
+ import { ansiChars, colors } from '../utils/ansi.js';
60
21
 
61
22
  /**
62
23
  * Human-readable console reporter with colorized output
@@ -111,6 +72,84 @@ export class HumanReporter extends BaseReporter {
111
72
  this.showProgress = options.progress ?? true;
112
73
  }
113
74
 
75
+ /**
76
+ * Format bytes in human-readable format
77
+ */
78
+ private static formatBytes(this: void, bytes: number): string {
79
+ const units = ['B', 'KB', 'MB', 'GB', 'TB'];
80
+ let size = bytes;
81
+ let unitIndex = 0;
82
+
83
+ while (size >= 1024 && unitIndex < units.length - 1) {
84
+ size /= 1024;
85
+ unitIndex++;
86
+ }
87
+
88
+ return `${size.toFixed(1)} ${units[unitIndex]}`;
89
+ }
90
+
91
+ /**
92
+ * Format file path - show relative path if within CWD, otherwise absolute
93
+ */
94
+ private static formatPath(this: void, filePath: string): string {
95
+ const cwd = process.cwd();
96
+ const absolutePath = path.resolve(filePath);
97
+
98
+ // Check if the file is within the current working directory
99
+ if (absolutePath.startsWith(cwd + path.sep) || absolutePath === cwd) {
100
+ return path.relative(cwd, absolutePath);
101
+ }
102
+
103
+ return absolutePath;
104
+ }
105
+
106
+ /**
107
+ * Simple pluralization helper
108
+ */
109
+ private static pluralize(this: void, str: string, count: number): string {
110
+ return count === 1 ? str : `${str}s`;
111
+ }
112
+
113
+ onBudgetResult(summary: BudgetSummary): void {
114
+ if (summary.total === 0 || this.quiet) {
115
+ return;
116
+ }
117
+
118
+ this.clearProgress();
119
+
120
+ this.printLine();
121
+ const budgetHeader = `${this.colorize('magenta', ansiChars.block.full.repeat(2))} ${this.colorize('brightWhite', this.colorize('bold', 'Performance Budgets'))}`;
122
+ this.printLine(budgetHeader);
123
+ this.printLine();
124
+
125
+ for (const result of summary.results) {
126
+ const icon = result.passed ? ansiChars.checkmark : ansiChars.cross;
127
+ const iconColor = result.passed ? 'brightCyan' : 'brightRed';
128
+
129
+ this.printLine(
130
+ ` ${this.colorize(iconColor, icon)} ${this.colorize('white', result.taskId)}`,
131
+ );
132
+
133
+ if (!result.passed && result.violations.length > 0) {
134
+ for (const violation of result.violations) {
135
+ this.printLine(
136
+ ` ${this.colorize('brightRed', violation.message)}`,
137
+ );
138
+ }
139
+ }
140
+ }
141
+
142
+ this.printLine();
143
+
144
+ const statusText =
145
+ summary.failed === 0
146
+ ? `${this.colorize('brightCyan', ansiChars.checkmark)} All ${summary.total} budget(s) passed`
147
+ : `${this.colorize('brightRed', ansiChars.cross)} ${summary.failed} of ${summary.total} budget(s) failed`;
148
+
149
+ this.printLine(` ${statusText}`);
150
+ this.printLine();
151
+ }
152
+
114
153
  onEnd(run: BenchmarkRun): void {
115
154
  if (this.quiet) {
116
155
  return;
@@ -161,7 +200,7 @@ export class HumanReporter extends BaseReporter {
161
200
  );
162
201
  }
163
202
  this.printLine(
164
- `${this.colorize('cyan', ansiChars.approx + ' Duration:')} ${this.colorize('brightWhite', this.formatDuration(duration * 1000000))}`,
203
+ `${this.colorize('cyan', ansiChars.approx + ' Duration:')} ${this.colorize('brightWhite', BaseReporter.formatDuration(duration * 1000000))}`,
165
204
  );
166
205
  this.printLine();
167
206
 
@@ -175,7 +214,7 @@ export class HumanReporter extends BaseReporter {
175
214
  this.printLine();
176
215
 
177
216
  for (const failure of this.failures) {
178
- const displayPath = this.formatPath(failure.file);
217
+ const displayPath = HumanReporter.formatPath(failure.file);
179
218
  this.printLine(
180
219
  ` ${this.colorize('dim', displayPath)} ${this.colorize('dim', '›')} ${this.colorize('white', failure.suite)} ${this.colorize('dim', '›')} ${this.colorize('brightWhite', failure.task)}`,
181
220
  );
@@ -229,7 +268,7 @@ export class HumanReporter extends BaseReporter {
229
268
  );
230
269
  } else {
231
270
  this.printLine(
232
- ` ${this.colorize('magenta', ansiChars.checkmark)} ${totalPassed > 1 ? this.colorize('brightMagenta', 'All ') : ''}${this.colorize('bold', this.colorize('brightMagenta', `${totalPassed}`))} ${this.colorize('brightMagenta', `${this.pluralize('task', totalPassed)} passed`)}`,
271
+ ` ${this.colorize('magenta', ansiChars.checkmark)} ${totalPassed > 1 ? this.colorize('brightMagenta', 'All ') : ''}${this.colorize('bold', this.colorize('brightMagenta', `${totalPassed}`))} ${this.colorize('brightMagenta', `${HumanReporter.pluralize('task', totalPassed)} passed`)}`,
233
272
  );
234
273
  }
235
274
 
@@ -243,7 +282,7 @@ export class HumanReporter extends BaseReporter {
243
282
  return;
244
283
  }
245
284
 
246
- const displayPath = this.formatPath(file);
285
+ const displayPath = HumanReporter.formatPath(file);
247
286
  const fileMarker = `${colors.magenta}${ansiChars.block.dark}${ansiChars.block.dark}${colors.reset}`;
248
287
  this.printLine(
249
288
  `${fileMarker} ${colors.underline}${this.colorize('brightMagenta', this.colorize('bold', displayPath))}${colors.reset}`,
@@ -318,7 +357,7 @@ export class HumanReporter extends BaseReporter {
318
357
  \x1b[48;5;0m \x1b[48;5;14m \x1b[38;5;30;48;5;38m▄\x1b[38;5;14;48;5;14m▄\x1b[48;5;14m \x1b[38;5;45;48;5;14m▄\x1b[38;5;89;48;5;14m▄\x1b[38;5;89;48;5;89m▄\x1b[38;5;14;48;5;31m▄\x1b[48;5;14m \x1b[38;5;37;48;5;89m▄\x1b[48;5;198m \x1b[38;5;198;48;5;198m▄\x1b[38;5;31;48;5;14m▄\x1b[48;5;14m \x1b[48;5;0m \x1b[m \x1b[2mnode.js:\x1b[m \x1b[36m${run.environment.nodeVersion} \x1b[m
319
358
  \x1b[48;5;0m \x1b[48;5;14m \x1b[38;5;44;48;5;31m▄\x1b[48;5;14m \x1b[38;5;126;48;5;38m▄\x1b[38;5;198;48;5;237m▄\x1b[38;5;237;48;5;37m▄\x1b[48;5;14m \x1b[38;5;14;48;5;14m▄\x1b[38;5;162;48;5;198m▄▄\x1b[38;5;53;48;5;240m▄\x1b[48;5;14m \x1b[48;5;0m \x1b[m \x1b[2mplatform:\x1b[m \x1b[36m${run.environment.platform} ${run.environment.arch} \x1b[m
320
359
  \x1b[48;5;0m \x1b[38;5;45;48;5;14m▄\x1b[48;5;14m \x1b[38;5;14;48;5;37m▄\x1b[38;5;14;48;5;5m▄\x1b[38;5;14;48;5;44m▄\x1b[48;5;14m \x1b[38;5;45;48;5;14m▄\x1b[48;5;0m \x1b[m \x1b[2mcpu:\x1b[m \x1b[36m${run.environment.cpu.model} \x1b[2m(\x1b[m\x1b[36m${run.environment.cpu.cores} cores\x1b[2m) \x1b[m
321
- \x1b[49;38;5;0m▀▀\x1b[38;5;0;48;5;6m▄\x1b[38;5;232;48;5;14m▄\x1b[38;5;38;48;5;14m▄\x1b[48;5;14m \x1b[38;5;30;48;5;14m▄\x1b[38;5;0;48;5;14m▄\x1b[38;5;0;48;5;23m▄\x1b[49;38;5;0m▀▀\x1b[m \x1b[2mmem:\x1b[m \x1b[36m${this.formatBytes(run.environment.memory.total)} \x1b[m
360
+ \x1b[49;38;5;0m▀▀\x1b[38;5;0;48;5;6m▄\x1b[38;5;232;48;5;14m▄\x1b[38;5;38;48;5;14m▄\x1b[48;5;14m \x1b[38;5;30;48;5;14m▄\x1b[38;5;0;48;5;14m▄\x1b[38;5;0;48;5;23m▄\x1b[49;38;5;0m▀▀\x1b[m \x1b[2mmem:\x1b[m \x1b[36m${HumanReporter.formatBytes(run.environment.memory.total)} \x1b[m
322
361
  \x1b[49m \x1b[49;38;5;0m▀\x1b[38;5;0;48;5;236m▄\x1b[38;5;0;48;5;45m▄\x1b[38;5;23;48;5;14m▄\x1b[48;5;14m \x1b[38;5;236;48;5;14m▄\x1b[38;5;0;48;5;44m▄\x1b[38;5;0;48;5;232m▄\x1b[49;38;5;0m▀\x1b[49m \x1b[m
323
362
  \x1b[49m \x1b[49;38;5;0m▀▀\x1b[38;5;0;48;5;37m▄\x1b[38;5;0;48;5;14m▄\x1b[38;5;0;48;5;30m▄\x1b[49;38;5;0m▀▀\x1b[49m \x1b[m
324
363
  `;
@@ -373,7 +412,7 @@ export class HumanReporter extends BaseReporter {
373
412
  );
374
413
  } else {
375
414
  this.printLine(
376
- ` ${this.colorize('magenta', ansiChars.checkmark)} ${this.colorize('bold', this.colorize('brightWhite', `${passed}`))} ${this.colorize('brightWhite', `${this.pluralize('task', passed)} passed`)}`,
415
+ ` ${this.colorize('magenta', ansiChars.checkmark)} ${this.colorize('bold', this.colorize('brightWhite', `${passed}`))} ${this.colorize('brightWhite', `${HumanReporter.pluralize('task', passed)} passed`)}`,
377
416
  );
378
417
  }
379
418
  this.printLine();
@@ -454,37 +493,6 @@ export class HumanReporter extends BaseReporter {
454
493
  return `${colors[color]}${text}${colors.reset}`;
455
494
  }
456
495
 
457
- /**
458
- * Format bytes in human-readable format
459
- */
460
- private formatBytes(bytes: number): string {
461
- const units = ['B', 'KB', 'MB', 'GB', 'TB'];
462
- let size = bytes;
463
- let unitIndex = 0;
464
-
465
- while (size >= 1024 && unitIndex < units.length - 1) {
466
- size /= 1024;
467
- unitIndex++;
468
- }
469
-
470
- return `${size.toFixed(1)} ${units[unitIndex]}`;
471
- }
472
-
473
- /**
474
- * Format file path - show relative path if within CWD, otherwise absolute
475
- */
476
- private formatPath(filePath: string): string {
477
- const cwd = process.cwd();
478
- const absolutePath = path.resolve(filePath);
479
-
480
- // Check if the file is within the current working directory
481
- if (absolutePath.startsWith(cwd + path.sep) || absolutePath === cwd) {
482
- return path.relative(cwd, absolutePath);
483
- }
484
-
485
- return absolutePath;
486
- }
487
-
488
496
  /**
489
497
  * Format duration in human-readable format for progress display
490
498
  */
@@ -511,13 +519,6 @@ export class HumanReporter extends BaseReporter {
511
519
  return str.replace(/\x1b\[[0-9;]*m/g, '').length;
512
520
  }
513
521
 
514
- /**
515
- * Simple pluralization helper
516
- */
517
- private pluralize(str: string, count: number): string {
518
- return count === 1 ? str : `${str}s`;
519
- }
520
-
521
522
  /**
522
523
  * Print all task results in a suite with aligned columns
523
524
  */
@@ -574,9 +575,9 @@ export class HumanReporter extends BaseReporter {
574
575
  };
575
576
  }
576
577
 
577
- const duration = this.formatDuration(result.mean); // already in nanoseconds
578
- const opsPerSec = this.formatOpsPerSecond(result.opsPerSecond);
579
- const rme = this.formatPercentage(result.marginOfError * 100);
578
+ const duration = BaseReporter.formatDuration(result.mean); // already in nanoseconds
579
+ const opsPerSec = BaseReporter.formatOpsPerSecond(result.opsPerSecond);
580
+ const rme = BaseReporter.formatPercentage(result.marginOfError * 100);
580
581
 
581
582
  return {
582
583
  durationLen: this.getVisibleLength(duration),
@@ -5,19 +5,14 @@
5
5
  * processing, CI/CD integration, and data analysis.
6
6
  */
7
7
 
8
- import { mkdirSync, writeFileSync } from 'node:fs';
9
- import { dirname } from 'node:path';
8
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
9
+ import { dirname, join } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
10
11
 
11
- import type {
12
- BenchmarkRun,
13
- FileResult,
14
- ProgressState,
15
- SuiteResult,
16
- TaskResult,
17
- } from '../types/index.js';
12
+ import type { BenchmarkRun, TaskResult } from '../types/index.js';
18
13
 
19
14
  import { ReporterOutputError } from '../errors/index.js';
20
- import { BaseReporter } from './registry.js';
15
+ import { BaseReporter } from '../services/reporter-registry.js';
21
16
 
22
17
  /**
23
18
  * JSON output structure for benchmark results
@@ -40,12 +35,30 @@ interface JsonOutput {
40
35
  };
41
36
  }
42
37
 
38
+ /**
39
+ * Cache the package version at module load time
40
+ *
41
+ * NOTE: This relies on package.json being at the same relative path from both
42
+ * src/ and dist/ directories (../../package.json). If the build output
43
+ * structure changes, this will break.
44
+ */
45
+ const cachedPackageVersion = (() => {
46
+ try {
47
+ const __dirname = dirname(fileURLToPath(import.meta.url));
48
+ const pkgPath = join(__dirname, '..', '..', 'package.json');
49
+ const pkgContent = readFileSync(pkgPath, 'utf8');
50
+ const pkg = JSON.parse(pkgContent) as { version: string };
51
+ return pkg.version;
52
+ } catch {
53
+ // Fallback if package.json cannot be read (shouldn't happen in normal use)
54
+ return 'unknown';
55
+ }
56
+ })();
57
+
43
58
  /**
44
59
  * JSON reporter for structured output
45
60
  */
46
61
  export class JsonReporter extends BaseReporter {
47
- private currentRun?: BenchmarkRun;
48
-
49
62
  private readonly includeMetadata: boolean;
50
63
 
51
64
  private readonly includeStatistics: boolean;
@@ -54,8 +67,6 @@ export class JsonReporter extends BaseReporter {
54
67
 
55
68
  private readonly prettyPrint: boolean;
56
69
 
57
- private readonly quiet: boolean;
58
-
59
70
  private statistics: {
60
71
  fastestTask?: TaskResult;
61
72
  slowestTask?: TaskResult;
@@ -74,8 +85,6 @@ export class JsonReporter extends BaseReporter {
74
85
  includeStatistics?: boolean;
75
86
  outputPath?: string;
76
87
  prettyPrint?: boolean;
77
- quiet?: boolean;
78
- verbose?: boolean;
79
88
  } = {},
80
89
  ) {
81
90
  super('json', options);
@@ -84,35 +93,6 @@ export class JsonReporter extends BaseReporter {
84
93
  this.prettyPrint = options.prettyPrint ?? true;
85
94
  this.includeStatistics = options.includeStatistics ?? true;
86
95
  this.includeMetadata = options.includeMetadata ?? true;
87
- this.quiet = options.quiet ?? false;
88
- }
89
-
90
- /**
91
- * Check if statistics are included
92
- */
93
- areStatisticsIncluded(): boolean {
94
- return this.includeStatistics;
95
- }
96
-
97
- /**
98
- * Get the output path (if configured)
99
- */
100
- getOutputPath(): string | undefined {
101
- return this.outputPath;
102
- }
103
-
104
- /**
105
- * Check if metadata is included
106
- */
107
- isMetadataIncluded(): boolean {
108
- return this.includeMetadata;
109
- }
110
-
111
- /**
112
- * Check if pretty printing is enabled
113
- */
114
- isPrettyPrintEnabled(): boolean {
115
- return this.prettyPrint;
116
96
  }
117
97
 
118
98
  async onEnd(run: BenchmarkRun): Promise<void> {
@@ -131,41 +111,16 @@ export class JsonReporter extends BaseReporter {
131
111
  console.error('JSON Reporter Error:', error.message);
132
112
  }
133
113
 
134
- onFileEnd(_result: FileResult): void {
135
- // No-op for JSON reporter
136
- }
137
-
138
- onFileStart(_file: string): void {
139
- // No-op for JSON reporter
140
- }
141
-
142
- onProgress(_state: ProgressState): void {
143
- // No-op for JSON reporter - we don't output progress in JSON format
144
- }
145
-
146
- onStart(run: BenchmarkRun): void {
147
- this.currentRun = run;
114
+ onStart(_run: BenchmarkRun): void {
148
115
  this.resetStatistics();
149
116
  }
150
117
 
151
- onSuiteEnd(_result: SuiteResult): void {
152
- // No-op for JSON reporter
153
- }
154
-
155
- onSuiteStart(_suite: string): void {
156
- // No-op for JSON reporter
157
- }
158
-
159
118
  onTaskResult(result: TaskResult): void {
160
119
  if (!result.error) {
161
120
  this.updateStatistics(result);
162
121
  }
163
122
  }
164
123
 
165
- onTaskStart(_task: string): void {
166
- // No-op for JSON reporter
167
- }
168
-
169
124
  /**
170
125
  * Build the complete JSON output structure
171
126
  */
@@ -174,7 +129,7 @@ export class JsonReporter extends BaseReporter {
174
129
  meta: {
175
130
  format: 'modestbench-json',
176
131
  timestamp: new Date().toISOString(),
177
- version: '0.1.0', // TODO: Get from package.json
132
+ version: cachedPackageVersion,
178
133
  },
179
134
  run: this.includeMetadata ? run : this.sanitizeRun(run),
180
135
  };