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
@@ -10,31 +10,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
10
10
  return (mod && mod.__esModule) ? mod : { "default": mod };
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.main = exports.cli = exports.ExitCodes = void 0;
13
+ exports.main = exports.cli = void 0;
14
14
  const node_fs_1 = require("node:fs");
15
15
  const node_url_1 = require("node:url");
16
16
  const yargs_1 = __importDefault(require("yargs"));
17
17
  const helpers_1 = require("yargs/helpers");
18
18
  const bootstrap_js_1 = require("../bootstrap.cjs");
19
+ const constants_js_1 = require("../constants.cjs");
19
20
  const index_js_1 = require("../core/engines/index.cjs");
21
+ const base_js_1 = require("../errors/base.cjs");
20
22
  const index_js_2 = require("../errors/index.cjs");
21
23
  const index_js_3 = require("../reporters/index.cjs");
22
24
  // Import commands
25
+ const analyze_js_1 = require("./commands/analyze.cjs");
26
+ const baseline_js_1 = require("./commands/baseline.cjs");
23
27
  const history_js_1 = require("./commands/history.cjs");
24
28
  const init_js_1 = require("./commands/init.cjs");
25
29
  const run_js_1 = require("./commands/run.cjs");
26
- /**
27
- * Exit codes for the CLI
28
- */
29
- exports.ExitCodes = {
30
- BENCHMARK_FAILURES: 1,
31
- CONFIG_ERROR: 2,
32
- DISCOVERY_ERROR: 3,
33
- RUNTIME_ERROR: 5,
34
- SUCCESS: 0,
35
- UNKNOWN_ERROR: 99,
36
- VALIDATION_ERROR: 4,
37
- };
38
30
  /**
39
31
  * Initialize and run the CLI
40
32
  */
@@ -43,7 +35,7 @@ const cli = (argv) => {
43
35
  setupSignalHandlers(abortController);
44
36
  (0, exports.main)(argv, abortController).catch((error) => {
45
37
  console.error('CLI error:', error);
46
- process.exit(exports.ExitCodes.UNKNOWN_ERROR);
38
+ process.exit(constants_js_1.ExitCodes.UNKNOWN_ERROR);
47
39
  });
48
40
  };
49
41
  exports.cli = cli;
@@ -56,6 +48,7 @@ const main = async (argv, abortController) => {
56
48
  const cli = (0, yargs_1.default)(args);
57
49
  // Configure global options and commands
58
50
  await cli
51
+ .scriptName('modestbench')
59
52
  .option('config', {
60
53
  alias: 'c',
61
54
  description: 'Path to configuration file',
@@ -64,33 +57,34 @@ const main = async (argv, abortController) => {
64
57
  })
65
58
  .option('verbose', {
66
59
  alias: 'v',
67
- default: false,
60
+ defaultDescription: String(run_js_1.RUN_COMMAND_DEFAULTS.verbose),
68
61
  description: 'Enable verbose output',
69
62
  global: true,
70
63
  type: 'boolean',
71
64
  })
72
65
  .option('no-color', {
73
- default: false,
66
+ defaultDescription: 'false',
74
67
  description: 'Disable colored output',
75
68
  global: true,
76
69
  type: 'boolean',
77
70
  })
78
71
  .option('progress', {
79
- default: true,
72
+ defaultDescription: 'true',
80
73
  description: 'Show animated progress bar',
81
74
  global: true,
82
75
  type: 'boolean',
83
76
  })
84
77
  .option('json', {
85
- default: false,
78
+ defaultDescription: 'false',
86
79
  description: 'Output results in JSON format',
87
80
  global: true,
88
81
  type: 'boolean',
89
82
  })
90
83
  .option('cwd', {
91
- default: process.cwd(),
84
+ defaultDescription: '.',
92
85
  description: 'Working directory',
93
86
  global: true,
87
+ normalize: true,
94
88
  type: 'string',
95
89
  })
96
90
  .help()
@@ -98,130 +92,122 @@ const main = async (argv, abortController) => {
98
92
  .version()
99
93
  .alias('version', 'V')
100
94
  .strict()
101
- .demandCommand(1, 'You must specify a command')
95
+ .demandCommand(1)
102
96
  .recommendCommands()
103
97
  .completion()
104
98
  .wrap(Math.min(120, cli.terminalWidth()))
105
- .command(['$0 [pattern..]', 'run [pattern..]'], 'Run benchmark files', (yargs) => {
106
- return yargs
107
- .positional('pattern', {
108
- array: true,
109
- default: ['./bench/**/*.bench.{js,mjs,cjs,ts}'],
110
- describe: 'File paths, directory paths, or glob patterns for benchmark files',
111
- type: 'string',
112
- })
113
- .option('config', {
114
- alias: 'c',
115
- description: 'Path to configuration file',
116
- type: 'string',
117
- })
118
- .option('reporters', {
119
- alias: 'r',
120
- coerce: (value) => {
121
- // Handle comma-separated values
122
- if (Array.isArray(value)) {
123
- return value.flatMap((v) => v.split(',').map((s) => s.trim()));
124
- }
125
- return value.split(',').map((s) => s.trim());
126
- },
127
- default: ['human'],
128
- description: 'Output reporters to use (human,json,csv)',
129
- type: 'array',
130
- })
131
- .option('output', {
132
- alias: 'o',
133
- description: 'Output directory for reports',
134
- type: 'string',
135
- })
136
- .option('iterations', {
137
- alias: 'i',
138
- description: 'Number of iterations per benchmark',
139
- type: 'number',
140
- })
141
- .option('time', {
142
- alias: 't',
143
- description: 'Time budget per benchmark in milliseconds',
144
- type: 'number',
145
- })
146
- .option('warmup', {
147
- alias: 'w',
148
- description: 'Number of warmup iterations',
149
- type: 'number',
150
- })
151
- .option('limit-by', {
152
- choices: ['time', 'iterations', 'any', 'all'],
153
- description: 'How to limit benchmarks: time (time budget), iterations (sample count), any (either threshold), all (both thresholds)',
154
- type: 'string',
155
- })
156
- .option('bail', {
157
- alias: 'b',
158
- default: false,
159
- description: 'Stop on first failure',
160
- type: 'boolean',
161
- })
162
- .option('exclude', {
163
- coerce: (value) => {
164
- // Handle comma-separated values
165
- if (Array.isArray(value)) {
166
- return value.flatMap((v) => v.split(',').map((s) => s.trim()));
167
- }
168
- return value.split(',').map((s) => s.trim());
169
- },
170
- description: 'Exclude patterns (comma-separated)',
171
- type: 'array',
172
- })
173
- .option('timeout', {
174
- description: 'Timeout per benchmark in milliseconds',
175
- type: 'number',
176
- })
177
- .option('quiet', {
178
- alias: 'q',
179
- default: false,
180
- description: 'Minimal output',
181
- type: 'boolean',
182
- })
183
- .option('tags', {
184
- coerce: (value) => {
185
- // Handle comma-separated values
186
- if (Array.isArray(value)) {
187
- return value.flatMap((v) => v.split(',').map((s) => s.trim()));
188
- }
189
- return value.split(',').map((s) => s.trim());
190
- },
191
- description: 'Include only benchmarks with any of these tags',
192
- type: 'array',
193
- })
194
- .option('exclude-tags', {
195
- coerce: (value) => {
196
- // Handle comma-separated values
197
- if (Array.isArray(value)) {
198
- return value.flatMap((v) => v.split(',').map((s) => s.trim()));
199
- }
200
- return value.split(',').map((s) => s.trim());
201
- },
202
- description: 'Exclude benchmarks with any of these tags',
203
- type: 'array',
204
- })
205
- .option('engine', {
206
- alias: 'e',
207
- choices: ['tinybench', 'accurate'],
208
- default: 'tinybench',
209
- description: 'Benchmark engine: tinybench (default) or accurate (requires --allow-natives-syntax)',
210
- type: 'string',
211
- })
212
- .example([
213
- ['$0 run', 'Run benchmarks in current directory and bench/'],
214
- ['$0 run benchmarks/', 'Run all benchmarks in a directory'],
215
- ['$0 run src/perf/', 'Run benchmarks in specific directory'],
216
- ['$0 run "src/**/*.bench.js"', 'Run specific glob pattern'],
217
- ['$0 run file1.bench.js file2.bench.js', 'Run specific files'],
218
- ['$0 run benchmarks/ tests/perf/', 'Run multiple directories'],
219
- ['$0 run --reporters json,csv', 'Use multiple reporters'],
220
- ['$0 run --iterations 1000', 'Set iteration count'],
221
- ['$0 run --engine accurate', 'Use high-accuracy engine'],
222
- ['$0 run --bail', 'Stop on first failure'],
223
- ]);
224
- }, async (argv) => {
99
+ .command(['$0 [pattern..]', 'run [pattern..]'], 'Run benchmark files', (yargs) => yargs
100
+ .positional('pattern', {
101
+ array: true,
102
+ defaultDescription: '(auto-discovered from bench/ directory)',
103
+ describe: 'File paths, directory paths, or glob patterns for benchmark files',
104
+ type: 'string',
105
+ })
106
+ .option('config', {
107
+ alias: 'c',
108
+ description: 'Path to configuration file',
109
+ type: 'string',
110
+ })
111
+ .option('reporter', {
112
+ alias: 'r',
113
+ array: true,
114
+ choices: Object.values(constants_js_1.Reporters).sort(),
115
+ defaultDescription: constants_js_1.DEFAULT_REPORTER,
116
+ description: 'Output reporters to use (human,json,csv)',
117
+ type: 'string',
118
+ })
119
+ .option('output', {
120
+ alias: 'o',
121
+ description: 'Output directory for reports',
122
+ type: 'string',
123
+ })
124
+ .option('output-file', {
125
+ alias: ['of', 'file'],
126
+ description: 'Custom filename for reporter output (use with single reporter only)',
127
+ requiresArg: true,
128
+ type: 'string',
129
+ })
130
+ .option('iterations', {
131
+ alias: 'i',
132
+ description: 'Number of iterations per benchmark',
133
+ type: 'number',
134
+ })
135
+ .option('time', {
136
+ alias: 't',
137
+ description: 'Time budget per benchmark in milliseconds',
138
+ type: 'number',
139
+ })
140
+ .option('warmup', {
141
+ alias: ['w', 'warm'],
142
+ description: 'Number of warmup iterations',
143
+ type: 'number',
144
+ })
145
+ .option('limit-by', {
146
+ alias: ['l', 'limit'],
147
+ choices: ['time', 'iterations', 'any', 'all'],
148
+ description: 'How to limit benchmarks: time (time budget), iterations (sample count), any (either threshold), all (both thresholds)',
149
+ type: 'string',
150
+ })
151
+ .option('bail', {
152
+ alias: 'b',
153
+ defaultDescription: String(run_js_1.RUN_COMMAND_DEFAULTS.bail),
154
+ description: 'Stop on first failure',
155
+ type: 'boolean',
156
+ })
157
+ .option('exclude', {
158
+ alias: 'X',
159
+ array: true,
160
+ description: 'Exclude patterns (comma-separated)',
161
+ type: 'string',
162
+ })
163
+ .option('timeout', {
164
+ description: 'Timeout per benchmark in milliseconds',
165
+ type: 'number',
166
+ })
167
+ .option('quiet', {
168
+ alias: 'q',
169
+ defaultDescription: String(run_js_1.RUN_COMMAND_DEFAULTS.quiet),
170
+ description: 'Minimal output',
171
+ type: 'boolean',
172
+ })
173
+ .option('tag', {
174
+ array: true,
175
+ description: 'Include only benchmarks with any of these tags',
176
+ type: 'string',
177
+ })
178
+ .option('exclude-tag', {
179
+ alias: 'T',
180
+ array: true,
181
+ description: 'Exclude benchmarks with any of these tags',
182
+ type: 'string',
183
+ })
184
+ .option('engine', {
185
+ alias: 'e',
186
+ choices: Object.values(constants_js_1.Engines),
187
+ defaultDescription: constants_js_1.DEFAULT_ENGINE,
188
+ description: 'Benchmark engine: tinybench (default) or accurate (requires --allow-natives-syntax)',
189
+ type: 'string',
190
+ })
191
+ .example([
192
+ ['$0 run', 'Run benchmarks in current directory and bench/'],
193
+ ['$0 run benchmarks/', 'Run all benchmarks in a directory'],
194
+ ['$0 run src/perf/', 'Run benchmarks in specific directory'],
195
+ ['$0 run "src/**/*.bench.js"', 'Run specific glob pattern'],
196
+ ['$0 run file1.bench.js file2.bench.js', 'Run specific files'],
197
+ ['$0 run benchmarks/ tests/perf/', 'Run multiple directories'],
198
+ ['$0 run -r json -r csv', 'Use multiple reporters'],
199
+ ['$0 run --iterations 1000', 'Set iteration count'],
200
+ ['$0 run --engine accurate', 'Use high-accuracy engine'],
201
+ ['$0 run --bail', 'Stop on first failure'],
202
+ ])
203
+ .check((argv) => {
204
+ if (argv.reporter &&
205
+ argv.reporter.length > 1 &&
206
+ argv['output-file']) {
207
+ throw new Error('--output-file can only be used with a single reporter. Use --output <dir> for multiple reporters.');
208
+ }
209
+ return true;
210
+ }), async (argv) => {
225
211
  const context = await createCliContext(argv, abortController, argv.engine);
226
212
  const exitCode = await (0, run_js_1.handleRunCommand)(context, {
227
213
  bail: argv.bail,
@@ -229,16 +215,17 @@ const main = async (argv, abortController) => {
229
215
  cwd: argv.cwd,
230
216
  engine: argv.engine,
231
217
  exclude: argv.exclude,
232
- excludeTags: argv['exclude-tags'],
218
+ excludeTags: argv['exclude-tag'],
233
219
  iterations: argv.iterations,
234
220
  json: argv.json,
235
221
  noColor: argv.noColor,
236
222
  outputDir: argv.output,
223
+ outputFile: argv['output-file'],
237
224
  pattern: argv.pattern,
238
225
  progress: argv.progress,
239
226
  quiet: argv.quiet,
240
- reporters: argv.reporters,
241
- tags: argv.tags,
227
+ reporters: argv.reporter,
228
+ tags: argv.tag,
242
229
  time: argv.time,
243
230
  timeout: argv.timeout,
244
231
  verbose: argv.verbose,
@@ -246,137 +233,503 @@ const main = async (argv, abortController) => {
246
233
  });
247
234
  process.exit(exitCode);
248
235
  })
249
- .command('history <subcommand> [args..]', 'View and manage benchmark history', (yargs) => {
250
- return yargs
251
- .positional('subcommand', {
252
- choices: [
253
- 'list',
254
- 'show',
255
- 'compare',
256
- 'trends',
257
- 'clean',
258
- 'export',
259
- ],
260
- demandOption: true,
261
- describe: 'History subcommand',
262
- type: 'string',
263
- })
264
- .positional('args', {
265
- array: true,
266
- describe: 'Additional arguments for the subcommand',
267
- type: 'string',
268
- })
269
- .option('since', {
270
- description: 'Show runs since date (ISO 8601 or relative like "1 week ago")',
271
- type: 'string',
272
- })
273
- .option('until', {
274
- description: 'Show runs until date (ISO 8601 or relative like "1 day ago")',
275
- type: 'string',
276
- })
277
- .option('pattern', {
278
- description: 'Filter by benchmark name pattern',
279
- type: 'string',
280
- })
281
- .option('tags', {
282
- description: 'Filter by tags',
283
- type: 'array',
284
- })
285
- .option('limit', {
286
- default: 10,
287
- description: 'Maximum number of results',
288
- type: 'number',
289
- })
290
- .option('format', {
291
- choices: ['human', 'json', 'csv'],
292
- default: 'human',
293
- description: 'Output format',
294
- type: 'string',
295
- })
296
- .option('maxAge', {
297
- description: 'Maximum age in days for cleanup',
298
- type: 'number',
299
- })
300
- .option('maxRuns', {
301
- description: 'Maximum number of runs to keep',
302
- type: 'number',
303
- })
304
- .option('maxSize', {
305
- description: 'Maximum storage size in bytes',
306
- type: 'number',
307
- })
308
- .option('confirm', {
309
- default: false,
310
- description: 'Confirm cleanup operations',
311
- type: 'boolean',
312
- })
313
- .option('output', {
314
- description: 'Output file path',
315
- type: 'string',
316
- })
317
- .example([
318
- ['$0 history list', 'List recent benchmark runs'],
319
- ['$0 history show <run-id>', 'Show detailed results for run'],
320
- ['$0 history compare <run-id1> <run-id2>', 'Compare two runs'],
321
- ['$0 history trends [pattern]', 'Show performance trends'],
322
- ['$0 history clean --max-runs 50', 'Keep only latest 50 runs'],
323
- ['$0 history export --format csv', 'Export to CSV'],
324
- ]);
325
- }, async (argv) => {
236
+ .command('history', 'View and manage benchmark history', (yargs) => yargs
237
+ .command('list', 'List recent benchmark runs', (yargs) => yargs
238
+ .option('since', {
239
+ description: 'Show runs since date (ISO 8601 or relative like "1 week ago")',
240
+ type: 'string',
241
+ })
242
+ .option('until', {
243
+ description: 'Show runs until date (ISO 8601 or relative like "1 day ago")',
244
+ type: 'string',
245
+ })
246
+ .option('pattern', {
247
+ description: 'Filter by benchmark name pattern',
248
+ type: 'string',
249
+ })
250
+ .option('tag', {
251
+ alias: 't',
252
+ array: true,
253
+ description: 'Filter by tags (comma-separated)',
254
+ type: 'string',
255
+ })
256
+ .option('limit', {
257
+ defaultDescription: '10',
258
+ description: 'Maximum number of results',
259
+ type: 'number',
260
+ })
261
+ .option('format', {
262
+ choices: ['human', 'json', 'csv'],
263
+ defaultDescription: 'human',
264
+ description: 'Output format',
265
+ type: 'string',
266
+ })
267
+ .example([
268
+ ['$0 history list', 'List recent benchmark runs'],
269
+ [
270
+ '$0 history list --since "1 week ago"',
271
+ 'List runs from last week',
272
+ ],
273
+ ['$0 history list --limit 20', 'List 20 most recent runs'],
274
+ ['$0 history list --format json', 'List runs in JSON format'],
275
+ ]), async (argv) => {
326
276
  const context = await createCliContext(argv, abortController);
327
- const exitCode = await (0, history_js_1.handleHistoryCommand)(context, {
328
- args: argv.args,
329
- confirm: argv.confirm,
277
+ const exitCode = await (0, history_js_1.handleListCommand)(context, {
278
+ cwd: argv.cwd,
279
+ format: argv.format,
280
+ limit: argv.limit,
281
+ pattern: argv.pattern,
282
+ since: argv.since,
283
+ tags: argv.tag,
284
+ until: argv.until,
285
+ verbose: argv.verbose,
286
+ });
287
+ process.exit(exitCode);
288
+ })
289
+ .command('show <run-id>', 'Show detailed results for a specific run', (yargs) => yargs
290
+ .positional('run-id', {
291
+ demandOption: true,
292
+ describe: 'ID of the benchmark run to show',
293
+ type: 'string',
294
+ })
295
+ .option('format', {
296
+ choices: ['human', 'json', 'csv'],
297
+ defaultDescription: 'human',
298
+ description: 'Output format',
299
+ type: 'string',
300
+ })
301
+ .example([
302
+ [
303
+ '$0 history show abc123',
304
+ 'Show detailed results for run abc123',
305
+ ],
306
+ [
307
+ '$0 history show abc123 --format json',
308
+ 'Show run in JSON format',
309
+ ],
310
+ ]), async (argv) => {
311
+ const context = await createCliContext(argv, abortController);
312
+ const exitCode = await (0, history_js_1.handleShowCommand)(context, {
313
+ cwd: argv.cwd,
314
+ format: argv.format,
315
+ runId: argv['run-id'],
316
+ verbose: argv.verbose,
317
+ });
318
+ process.exit(exitCode);
319
+ })
320
+ .command('compare <run-id1> <run-id2>', 'Compare two benchmark runs', (yargs) => yargs
321
+ .positional('run-id1', {
322
+ demandOption: true,
323
+ describe: 'ID of the first benchmark run',
324
+ type: 'string',
325
+ })
326
+ .positional('run-id2', {
327
+ demandOption: true,
328
+ describe: 'ID of the second benchmark run',
329
+ type: 'string',
330
+ })
331
+ .option('format', {
332
+ choices: ['human', 'json'],
333
+ defaultDescription: 'human',
334
+ description: 'Output format',
335
+ type: 'string',
336
+ })
337
+ .example([
338
+ ['$0 history compare abc123 def456', 'Compare two runs'],
339
+ [
340
+ '$0 history compare abc123 def456 --format json',
341
+ 'Compare in JSON format',
342
+ ],
343
+ ]), async (argv) => {
344
+ const context = await createCliContext(argv, abortController);
345
+ const exitCode = await (0, history_js_1.handleCompareCommand)(context, {
346
+ cwd: argv.cwd,
347
+ format: argv.format,
348
+ runId1: argv['run-id1'],
349
+ runId2: argv['run-id2'],
350
+ verbose: argv.verbose,
351
+ });
352
+ process.exit(exitCode);
353
+ })
354
+ .command('trends [pattern]', 'Show performance trends over time', (yargs) => yargs
355
+ .positional('pattern', {
356
+ describe: 'Filter by benchmark name pattern',
357
+ type: 'string',
358
+ })
359
+ .option('since', {
360
+ description: 'Show trends since date (ISO 8601 or relative like "1 week ago")',
361
+ type: 'string',
362
+ })
363
+ .option('until', {
364
+ description: 'Show trends until date (ISO 8601 or relative like "1 day ago")',
365
+ type: 'string',
366
+ })
367
+ .option('tag', {
368
+ alias: 't',
369
+ array: true,
370
+ description: 'Filter by tags (comma-separated)',
371
+ type: 'string',
372
+ })
373
+ .option('limit', {
374
+ description: 'Maximum number of runs to analyze',
375
+ type: 'number',
376
+ })
377
+ .option('all', {
378
+ alias: 'a',
379
+ defaultDescription: 'false',
380
+ description: 'Analyze all runs (ignore limit)',
381
+ type: 'boolean',
382
+ })
383
+ .option('format', {
384
+ choices: ['human', 'json'],
385
+ defaultDescription: 'human',
386
+ description: 'Output format',
387
+ type: 'string',
388
+ })
389
+ .example([
390
+ [
391
+ '$0 history trends',
392
+ 'Show performance trends for all benchmarks',
393
+ ],
394
+ [
395
+ '$0 history trends --since "1 month ago"',
396
+ 'Show trends from last month',
397
+ ],
398
+ [
399
+ '$0 history trends "array-*"',
400
+ 'Show trends for array benchmarks',
401
+ ],
402
+ [
403
+ '$0 history trends --format json',
404
+ 'Output trends in JSON format',
405
+ ],
406
+ ]), async (argv) => {
407
+ const context = await createCliContext(argv, abortController);
408
+ const exitCode = await (0, history_js_1.handleTrendsCommand)(context, {
409
+ all: argv.all,
330
410
  cwd: argv.cwd,
331
411
  format: argv.format,
332
412
  limit: argv.limit,
333
- maxAge: argv.maxAge,
334
- maxRuns: argv.maxRuns,
335
- maxSize: argv.maxSize,
336
- outputDir: argv.output,
337
413
  pattern: argv.pattern,
338
- quiet: Boolean(argv.quiet),
339
414
  since: argv.since,
340
- subcommand: argv.subcommand,
341
- tags: argv.tags,
415
+ tags: argv.tag,
342
416
  until: argv.until,
343
417
  verbose: argv.verbose,
344
418
  });
345
419
  process.exit(exitCode);
420
+ })
421
+ .command('clean', 'Clean up old benchmark history', (yargs) => yargs
422
+ .option('max-age', {
423
+ description: 'Remove runs older than this many days',
424
+ type: 'number',
425
+ })
426
+ .option('max-runs', {
427
+ description: 'Keep only this many most recent runs',
428
+ type: 'number',
429
+ })
430
+ .option('max-size', {
431
+ description: 'Keep history under this size in bytes',
432
+ type: 'number',
433
+ })
434
+ .option('yes', {
435
+ alias: 'y',
436
+ description: 'Confirm cleanup without prompting',
437
+ type: 'boolean',
438
+ })
439
+ .option('quiet', {
440
+ default: false,
441
+ description: 'Minimal output',
442
+ type: 'boolean',
443
+ })
444
+ .check((argv) => {
445
+ if (!argv['max-age'] &&
446
+ !argv['max-runs'] &&
447
+ !argv['max-size']) {
448
+ throw new Error('At least one cleanup criterion must be specified (--max-age, --max-runs, or --max-size)');
449
+ }
450
+ return true;
451
+ })
452
+ .example([
453
+ [
454
+ '$0 history clean --max-runs 50 --yes',
455
+ 'Keep only latest 50 runs',
456
+ ],
457
+ [
458
+ '$0 history clean --max-age 30',
459
+ 'Preview removing runs older than 30 days',
460
+ ],
461
+ [
462
+ '$0 history clean --max-size 10485760',
463
+ 'Keep history under 10MB',
464
+ ],
465
+ ]), async (argv) => {
466
+ const context = await createCliContext(argv, abortController);
467
+ const exitCode = await (0, history_js_1.handleCleanCommand)(context, {
468
+ confirm: argv.yes,
469
+ cwd: argv.cwd,
470
+ maxAge: argv['max-age'],
471
+ maxRuns: argv['max-runs'],
472
+ maxSize: argv['max-size'],
473
+ quiet: argv.quiet,
474
+ verbose: argv.verbose,
475
+ });
476
+ process.exit(exitCode);
477
+ })
478
+ .command('export', 'Export benchmark history to a file', (yargs) => yargs
479
+ .option('format', {
480
+ choices: ['json', 'csv'],
481
+ defaultDescription: 'json',
482
+ description: 'Export format',
483
+ type: 'string',
484
+ })
485
+ .option('output', {
486
+ alias: 'o',
487
+ demandOption: true,
488
+ description: 'Output file path',
489
+ type: 'string',
490
+ })
491
+ .option('since', {
492
+ description: 'Export runs since date',
493
+ type: 'string',
494
+ })
495
+ .option('until', {
496
+ description: 'Export runs until date',
497
+ type: 'string',
498
+ })
499
+ .example([
500
+ [
501
+ '$0 history export -o history.json',
502
+ 'Export all history to JSON',
503
+ ],
504
+ [
505
+ '$0 history export -o history.csv --format csv',
506
+ 'Export to CSV',
507
+ ],
508
+ [
509
+ '$0 history export -o recent.json --since "1 week ago"',
510
+ 'Export recent runs',
511
+ ],
512
+ ]), async (argv) => {
513
+ const context = await createCliContext(argv, abortController);
514
+ const exitCode = await (0, history_js_1.handleExportCommand)(context, {
515
+ cwd: argv.cwd,
516
+ format: argv.format,
517
+ outputPath: argv.output,
518
+ quiet: Boolean(argv.quiet),
519
+ since: argv.since,
520
+ until: argv.until,
521
+ verbose: argv.verbose,
522
+ });
523
+ process.exitCode = exitCode;
524
+ })
525
+ .demandCommand(1, 'You must specify a history subcommand')
526
+ .strict()
527
+ .example([
528
+ ['$0 history list', 'List recent benchmark runs'],
529
+ ['$0 history show <run-id>', 'Show detailed results'],
530
+ ['$0 history compare <run-id1> <run-id2>', 'Compare two runs'],
531
+ ['$0 history trends', 'Show performance trends'],
532
+ ['$0 history clean --max-runs 50', 'Keep only latest 50 runs'],
533
+ ['$0 history export -o data.json', 'Export history'],
534
+ ]))
535
+ .command('baseline', 'Manage performance baselines', (yargs) => {
536
+ return yargs
537
+ .command('set <name>', 'Save a benchmark run as a baseline', (yargs) => {
538
+ return yargs
539
+ .positional('name', {
540
+ describe: 'Name for the baseline',
541
+ type: 'string',
542
+ })
543
+ .option('run-id', {
544
+ description: 'Specific run ID to save (default: most recent)',
545
+ type: 'string',
546
+ })
547
+ .option('commit', {
548
+ description: 'Git commit SHA (40 characters)',
549
+ type: 'string',
550
+ })
551
+ .option('branch', {
552
+ description: 'Git branch name',
553
+ type: 'string',
554
+ })
555
+ .option('default', {
556
+ defaultDescription: 'false',
557
+ description: 'Set as default baseline',
558
+ type: 'boolean',
559
+ })
560
+ .example([
561
+ [
562
+ '$0 baseline set production-v1.0',
563
+ 'Save most recent run as baseline',
564
+ ],
565
+ ['$0 baseline set v1.0 --default', 'Save and set as default'],
566
+ [
567
+ '$0 baseline set v1.0 --commit abc123...',
568
+ 'Save with commit info',
569
+ ],
570
+ ]);
571
+ }, async (argv) => {
572
+ const context = await createCliContext(argv, abortController);
573
+ const exitCode = await (0, baseline_js_1.handleSetCommand)(context, {
574
+ branch: argv.branch,
575
+ commit: argv.commit,
576
+ cwd: argv.cwd,
577
+ default: argv.default,
578
+ name: String(argv.name),
579
+ quiet: Boolean(argv.quiet),
580
+ runId: argv['run-id'],
581
+ verbose: argv.verbose,
582
+ });
583
+ process.exit(exitCode);
584
+ })
585
+ .command('list', 'List all saved baselines', (yargs) => {
586
+ return yargs
587
+ .option('format', {
588
+ choices: ['human', 'json'],
589
+ defaultDescription: 'human',
590
+ description: 'Output format',
591
+ type: 'string',
592
+ })
593
+ .example([
594
+ ['$0 baseline list', 'List all baselines'],
595
+ ['$0 baseline list --format json', 'List in JSON format'],
596
+ ]);
597
+ }, async (argv) => {
598
+ const context = await createCliContext(argv, abortController);
599
+ const exitCode = await (0, baseline_js_1.handleListCommand)(context, {
600
+ cwd: argv.cwd,
601
+ format: argv.format,
602
+ quiet: Boolean(argv.quiet),
603
+ verbose: argv.verbose,
604
+ });
605
+ process.exit(exitCode);
606
+ })
607
+ .command('show <name>', 'Show baseline details', (yargs) => {
608
+ return yargs
609
+ .positional('name', {
610
+ describe: 'Baseline name to show',
611
+ type: 'string',
612
+ })
613
+ .option('format', {
614
+ choices: ['human', 'json'],
615
+ defaultDescription: 'human',
616
+ description: 'Output format',
617
+ type: 'string',
618
+ })
619
+ .example([
620
+ ['$0 baseline show production-v1.0', 'Show baseline details'],
621
+ [
622
+ '$0 baseline show v1.0 --format json',
623
+ 'Show in JSON format',
624
+ ],
625
+ ]);
626
+ }, async (argv) => {
627
+ const context = await createCliContext(argv, abortController);
628
+ const exitCode = await (0, baseline_js_1.handleShowCommand)(context, {
629
+ cwd: argv.cwd,
630
+ format: argv.format,
631
+ name: String(argv.name),
632
+ quiet: Boolean(argv.quiet),
633
+ verbose: argv.verbose,
634
+ });
635
+ process.exit(exitCode);
636
+ })
637
+ .command('delete <name>', 'Delete a baseline', (yargs) => {
638
+ return yargs
639
+ .positional('name', {
640
+ describe: 'Baseline name to delete',
641
+ type: 'string',
642
+ })
643
+ .example([
644
+ ['$0 baseline delete old-baseline', 'Delete a baseline'],
645
+ ]);
646
+ }, async (argv) => {
647
+ const context = await createCliContext(argv, abortController);
648
+ const exitCode = await (0, baseline_js_1.handleDeleteCommand)(context, {
649
+ cwd: argv.cwd,
650
+ name: String(argv.name),
651
+ quiet: Boolean(argv.quiet),
652
+ verbose: argv.verbose,
653
+ });
654
+ process.exit(exitCode);
655
+ })
656
+ .command('analyze', 'Analyze history and suggest performance budgets', (yargs) => {
657
+ return yargs
658
+ .option('runs', {
659
+ defaultDescription: '10',
660
+ description: 'Number of recent runs to analyze',
661
+ type: 'number',
662
+ })
663
+ .option('confidence', {
664
+ defaultDescription: '0.95',
665
+ description: 'Confidence level (0.5-0.999, default 0.95)',
666
+ type: 'number',
667
+ })
668
+ .example([
669
+ [
670
+ '$0 baseline analyze',
671
+ 'Analyze last 10 runs with 95% confidence',
672
+ ],
673
+ ['$0 baseline analyze --runs 20', 'Analyze last 20 runs'],
674
+ [
675
+ '$0 baseline analyze --confidence 0.90',
676
+ 'Use 90% confidence level',
677
+ ],
678
+ ]);
679
+ }, async (argv) => {
680
+ const context = await createCliContext(argv, abortController);
681
+ const exitCode = await (0, baseline_js_1.handleAnalyzeCommand)(context, {
682
+ confidence: argv.confidence,
683
+ cwd: argv.cwd,
684
+ quiet: Boolean(argv.quiet),
685
+ runs: argv.runs,
686
+ verbose: argv.verbose,
687
+ });
688
+ process.exit(exitCode);
689
+ })
690
+ .demandCommand(1, 'You must specify a baseline subcommand')
691
+ .strict()
692
+ .example([
693
+ ['$0 baseline set production-v1.0', 'Save current run as baseline'],
694
+ ['$0 baseline list', 'List all baselines'],
695
+ ['$0 baseline show production-v1.0', 'Show baseline details'],
696
+ ['$0 baseline delete old-baseline', 'Delete a baseline'],
697
+ ['$0 baseline analyze', 'Suggest budgets from history'],
698
+ ]);
346
699
  })
347
700
  .command('init [type]', 'Initialize a new benchmark project', (yargs) => {
348
701
  return yargs
349
702
  .positional('type', {
350
703
  choices: ['basic', 'advanced', 'library'],
351
- default: 'basic',
704
+ defaultDescription: 'basic',
352
705
  describe: 'Type of project to initialize',
353
706
  type: 'string',
354
707
  })
355
708
  .option('examples', {
356
- default: true,
709
+ defaultDescription: 'true',
357
710
  description: 'Include example benchmark files',
358
711
  type: 'boolean',
359
712
  })
360
713
  .option('config-type', {
361
714
  choices: ['json', 'yaml', 'js', 'ts'],
362
- default: 'json',
715
+ defaultDescription: 'json',
363
716
  description: 'Configuration file format',
364
717
  type: 'string',
365
718
  })
366
719
  .option('force', {
367
- default: false,
720
+ defaultDescription: 'false',
368
721
  description: 'Overwrite existing files',
369
722
  type: 'boolean',
370
723
  })
371
724
  .option('yes', {
372
725
  alias: 'y',
373
- default: false,
726
+ defaultDescription: 'false',
374
727
  description: 'Accept all prompts automatically',
375
728
  type: 'boolean',
376
729
  })
377
730
  .option('quiet', {
378
731
  alias: 'q',
379
- default: false,
732
+ defaultDescription: 'false',
380
733
  description: 'Minimal output',
381
734
  type: 'boolean',
382
735
  })
@@ -398,33 +751,87 @@ const main = async (argv, abortController) => {
398
751
  cwd: argv.cwd,
399
752
  examples: argv.examples,
400
753
  force: argv.force,
401
- quiet: Boolean(argv.quiet),
754
+ quiet: argv.quiet,
402
755
  type: argv.type,
403
756
  verbose: argv.verbose,
404
757
  yes: argv.yes,
405
758
  });
406
- process.exit(exitCode);
759
+ process.exitCode = exitCode;
407
760
  })
408
- .fail((msg, err, yargsInstance) => {
761
+ .command(['analyze [command]', 'profile [command]'], 'Analyze code execution and identify benchmark candidates', (yargs) => {
762
+ return yargs
763
+ .positional('command', {
764
+ description: 'Command to analyze (e.g., "npm test")',
765
+ type: 'string',
766
+ })
767
+ .option('input', {
768
+ alias: 'i',
769
+ description: 'Path to existing *.cpuprofile file',
770
+ type: 'string',
771
+ })
772
+ .option('filter-file', {
773
+ description: 'Filter functions by file glob pattern',
774
+ type: 'string',
775
+ })
776
+ .option('min-percent', {
777
+ alias: ['m', 'min'],
778
+ default: 0.5,
779
+ description: 'Minimum execution percentage to show',
780
+ type: 'number',
781
+ })
782
+ .option('top', {
783
+ alias: 'n',
784
+ default: 25,
785
+ description: 'Number of top functions to show',
786
+ type: 'number',
787
+ })
788
+ .option('group-by-file', {
789
+ default: false,
790
+ description: 'Group results by file',
791
+ type: 'boolean',
792
+ })
793
+ .check((argv) => {
794
+ if (!argv.command && !argv.input) {
795
+ throw new Error('Either [command] or --input must be provided');
796
+ }
797
+ return true;
798
+ });
799
+ }, async (argv) => {
800
+ // Context not needed for analyze command currently
801
+ const context = {};
802
+ const options = {
803
+ color: !argv.noColor,
804
+ command: argv.command,
805
+ cwd: argv.cwd || process.cwd(),
806
+ filterFile: argv.filterFile,
807
+ groupByFile: argv.groupByFile,
808
+ input: argv.input,
809
+ minPercent: argv.minPercent,
810
+ top: argv.top,
811
+ };
812
+ process.exitCode = await (0, analyze_js_1.handleAnalyzeCommand)(context, options);
813
+ })
814
+ .fail((msg, err, yargs) => {
409
815
  if (err) {
410
816
  console.error('Error:', err.message);
411
817
  if (process.env.DEBUG) {
412
818
  console.error(err.stack);
413
819
  }
414
820
  // Show help for file discovery errors (similar to usage errors)
415
- if (err.name === 'FileDiscoveryError') {
821
+ if ((0, index_js_2.isModestBenchError)(err) &&
822
+ err.code === constants_js_1.ErrorCodes.FILE_DISCOVERY_FAILED) {
416
823
  console.error();
417
- yargsInstance.showHelp();
418
- process.exit(exports.ExitCodes.DISCOVERY_ERROR);
824
+ yargs.showHelp();
825
+ process.exit(constants_js_1.ExitCodes.DISCOVERY_ERROR);
419
826
  }
420
- process.exit(exports.ExitCodes.RUNTIME_ERROR);
827
+ process.exit(constants_js_1.ExitCodes.RUNTIME_ERROR);
421
828
  }
422
829
  else {
423
830
  // Show help for usage errors (unknown arguments, etc.)
424
831
  console.error(msg);
425
832
  console.error();
426
- yargsInstance.showHelp();
427
- process.exit(exports.ExitCodes.CONFIG_ERROR);
833
+ yargs.showHelp();
834
+ process.exit(constants_js_1.ExitCodes.CONFIG_ERROR);
428
835
  }
429
836
  })
430
837
  .parse();
@@ -434,22 +841,22 @@ const main = async (argv, abortController) => {
434
841
  if (process.env.DEBUG) {
435
842
  console.error(error);
436
843
  }
437
- process.exit(exports.ExitCodes.UNKNOWN_ERROR);
844
+ process.exit(constants_js_1.ExitCodes.UNKNOWN_ERROR);
438
845
  }
439
846
  };
440
847
  exports.main = main;
441
848
  /**
442
849
  * Create CLI context with dependency injection
443
850
  */
444
- const createCliContext = async (options, abortController, engineType = 'tinybench') => {
851
+ const createCliContext = async (options, abortController, engineType = constants_js_1.DEFAULT_ENGINE) => {
445
852
  try {
446
853
  const dependencies = (0, bootstrap_js_1.bootstrap)();
447
854
  // Select engine based on type
448
- const engine = engineType === 'accurate'
855
+ const engine = engineType === constants_js_1.Engines.ACCURATE
449
856
  ? new index_js_1.AccurateEngine(dependencies)
450
857
  : new index_js_1.TinybenchEngine(dependencies);
451
858
  // Register built-in reporters
452
- engine.registerReporter('human', new index_js_3.HumanReporter({
859
+ engine.registerReporter(constants_js_1.Reporters.HUMAN, new index_js_3.HumanReporter({
453
860
  color: !options.noColor,
454
861
  verbose: options.verbose,
455
862
  }));
@@ -475,7 +882,7 @@ const createCliContext = async (options, abortController, engineType = 'tinybenc
475
882
  }
476
883
  catch (error) {
477
884
  console.error('Failed to initialize ModestBench:', error instanceof Error ? error.message : String(error));
478
- process.exit(exports.ExitCodes.CONFIG_ERROR);
885
+ process.exit(constants_js_1.ExitCodes.CONFIG_ERROR);
479
886
  }
480
887
  };
481
888
  /**
@@ -496,26 +903,24 @@ const setupSignalHandlers = (abortController) => {
496
903
  setTimeout(() => {
497
904
  console.log('\nBenchmark aborted.');
498
905
  process.exit(computeExitCode(signal));
499
- }, 100);
906
+ }, constants_js_1.ABORT_TIMEOUT);
500
907
  };
501
- process.on('SIGINT', () => handleSignal('SIGINT'));
502
- process.on('SIGQUIT', () => handleSignal('SIGQUIT'));
503
- process.on('SIGTERM', () => handleSignal('SIGTERM'));
504
- process.once('uncaughtException', (error) => {
908
+ process
909
+ .once('SIGINT', handleSignal)
910
+ .once('SIGQUIT', handleSignal)
911
+ .once('SIGTERM', handleSignal)
912
+ .once('uncaughtException', (error) => {
505
913
  // Wrap non-ModestBench errors with UnknownError
506
914
  const wrappedError = (0, index_js_2.isModestBenchError)(error)
507
915
  ? error
508
- : new index_js_2.UnknownError(error instanceof Error ? error.message : String(error), { cause: error });
509
- console.error(wrappedError.toString());
510
- process.exit(exports.ExitCodes.RUNTIME_ERROR);
511
- });
512
- process.once('unhandledRejection', (reason) => {
513
- // Wrap non-ModestBench errors with UnknownError
514
- const wrappedError = (0, index_js_2.isModestBenchError)(reason)
515
- ? reason
516
- : new index_js_2.UnknownError(reason instanceof Error ? reason.message : String(reason), { cause: reason });
517
- console.error(wrappedError.toString());
518
- process.exit(exports.ExitCodes.RUNTIME_ERROR);
916
+ : new index_js_2.UnknownError(error.message, { cause: error });
917
+ console.error(`${wrappedError}`);
918
+ process.exit(constants_js_1.ExitCodes.RUNTIME_ERROR);
919
+ })
920
+ .once('unhandledRejection', (reason) => {
921
+ const wrappedError = new index_js_2.UnknownError((0, base_js_1.isError)(reason) ? reason.message : String(reason), { cause: reason });
922
+ console.error(`${wrappedError}`);
923
+ process.exit(constants_js_1.ExitCodes.RUNTIME_ERROR);
519
924
  });
520
925
  };
521
926
  // Run CLI if this file is executed directly