modestbench 0.0.3 → 0.2.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 (394) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +39 -31
  3. package/dist/bootstrap.cjs +10 -12
  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 -7
  8. package/dist/bootstrap.js.map +1 -1
  9. package/dist/cli/commands/history.cjs +108 -265
  10. package/dist/cli/commands/history.cjs.map +1 -1
  11. package/dist/cli/commands/history.d.cts +75 -12
  12. package/dist/cli/commands/history.d.cts.map +1 -1
  13. package/dist/cli/commands/history.d.ts +75 -12
  14. package/dist/cli/commands/history.d.ts.map +1 -1
  15. package/dist/cli/commands/history.js +105 -267
  16. package/dist/cli/commands/history.js.map +1 -1
  17. package/dist/cli/commands/init.cjs +5 -4
  18. package/dist/cli/commands/init.cjs.map +1 -1
  19. package/dist/cli/commands/init.d.cts.map +1 -1
  20. package/dist/cli/commands/init.d.ts.map +1 -1
  21. package/dist/cli/commands/init.js +5 -4
  22. package/dist/cli/commands/init.js.map +1 -1
  23. package/dist/cli/commands/run.cjs +32 -9
  24. package/dist/cli/commands/run.cjs.map +1 -1
  25. package/dist/cli/commands/run.d.cts +1 -0
  26. package/dist/cli/commands/run.d.cts.map +1 -1
  27. package/dist/cli/commands/run.d.ts +1 -0
  28. package/dist/cli/commands/run.d.ts.map +1 -1
  29. package/dist/cli/commands/run.js +32 -9
  30. package/dist/cli/commands/run.js.map +1 -1
  31. package/dist/cli/index.cjs +336 -103
  32. package/dist/cli/index.cjs.map +1 -1
  33. package/dist/cli/index.d.cts +1 -2
  34. package/dist/cli/index.d.cts.map +1 -1
  35. package/dist/cli/index.d.ts +1 -2
  36. package/dist/cli/index.d.ts.map +1 -1
  37. package/dist/cli/index.js +332 -99
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/constants.cjs +53 -1
  40. package/dist/constants.cjs.map +1 -1
  41. package/dist/constants.d.cts +36 -0
  42. package/dist/constants.d.cts.map +1 -1
  43. package/dist/constants.d.ts +36 -0
  44. package/dist/constants.d.ts.map +1 -1
  45. package/dist/constants.js +52 -0
  46. package/dist/constants.js.map +1 -1
  47. package/dist/core/engine.cjs +23 -43
  48. package/dist/core/engine.cjs.map +1 -1
  49. package/dist/core/engine.d.cts +4 -3
  50. package/dist/core/engine.d.cts.map +1 -1
  51. package/dist/core/engine.d.ts +4 -3
  52. package/dist/core/engine.d.ts.map +1 -1
  53. package/dist/core/engine.js +23 -43
  54. package/dist/core/engine.js.map +1 -1
  55. package/dist/core/engines/accurate-engine.cjs +2 -1
  56. package/dist/core/engines/accurate-engine.cjs.map +1 -1
  57. package/dist/core/engines/accurate-engine.d.cts.map +1 -1
  58. package/dist/core/engines/accurate-engine.d.ts.map +1 -1
  59. package/dist/core/engines/accurate-engine.js +2 -1
  60. package/dist/core/engines/accurate-engine.js.map +1 -1
  61. package/dist/core/engines/tinybench-engine.cjs +6 -5
  62. package/dist/core/engines/tinybench-engine.cjs.map +1 -1
  63. package/dist/core/engines/tinybench-engine.d.cts.map +1 -1
  64. package/dist/core/engines/tinybench-engine.d.ts.map +1 -1
  65. package/dist/core/engines/tinybench-engine.js +6 -5
  66. package/dist/core/engines/tinybench-engine.js.map +1 -1
  67. package/dist/core/output-path-resolver.cjs +34 -0
  68. package/dist/core/output-path-resolver.cjs.map +1 -0
  69. package/dist/core/output-path-resolver.d.cts +10 -0
  70. package/dist/core/output-path-resolver.d.cts.map +1 -0
  71. package/dist/core/output-path-resolver.d.ts +10 -0
  72. package/dist/core/output-path-resolver.d.ts.map +1 -0
  73. package/dist/core/output-path-resolver.js +30 -0
  74. package/dist/core/output-path-resolver.js.map +1 -0
  75. package/dist/errors/base.cjs +130 -0
  76. package/dist/errors/base.cjs.map +1 -0
  77. package/dist/errors/base.d.cts +97 -0
  78. package/dist/errors/base.d.cts.map +1 -0
  79. package/dist/errors/base.d.ts +97 -0
  80. package/dist/errors/base.d.ts.map +1 -0
  81. package/dist/errors/base.js +124 -0
  82. package/dist/errors/base.js.map +1 -0
  83. package/dist/errors/cli.cjs +58 -0
  84. package/dist/errors/cli.cjs.map +1 -0
  85. package/dist/errors/cli.d.cts +44 -0
  86. package/dist/errors/cli.d.cts.map +1 -0
  87. package/dist/errors/cli.d.ts +44 -0
  88. package/dist/errors/cli.d.ts.map +1 -0
  89. package/dist/errors/cli.js +52 -0
  90. package/dist/errors/cli.js.map +1 -0
  91. package/dist/errors/configuration.cjs +48 -0
  92. package/dist/errors/configuration.cjs.map +1 -0
  93. package/dist/errors/configuration.d.cts +41 -0
  94. package/dist/errors/configuration.d.cts.map +1 -0
  95. package/dist/errors/configuration.d.ts +41 -0
  96. package/dist/errors/configuration.d.ts.map +1 -0
  97. package/dist/errors/configuration.js +41 -0
  98. package/dist/errors/configuration.js.map +1 -0
  99. package/dist/errors/execution.cjs +65 -0
  100. package/dist/errors/execution.cjs.map +1 -0
  101. package/dist/errors/execution.d.cts +56 -0
  102. package/dist/errors/execution.d.cts.map +1 -0
  103. package/dist/errors/execution.d.ts +56 -0
  104. package/dist/errors/execution.d.ts.map +1 -0
  105. package/dist/errors/execution.js +56 -0
  106. package/dist/errors/execution.js.map +1 -0
  107. package/dist/errors/file.cjs +56 -0
  108. package/dist/errors/file.cjs.map +1 -0
  109. package/dist/errors/file.d.cts +48 -0
  110. package/dist/errors/file.d.cts.map +1 -0
  111. package/dist/errors/file.d.ts +48 -0
  112. package/dist/errors/file.d.ts.map +1 -0
  113. package/dist/errors/file.js +48 -0
  114. package/dist/errors/file.js.map +1 -0
  115. package/dist/errors/index.cjs +59 -0
  116. package/dist/errors/index.cjs.map +1 -0
  117. package/dist/errors/index.d.cts +16 -0
  118. package/dist/errors/index.d.cts.map +1 -0
  119. package/dist/errors/index.d.ts +16 -0
  120. package/dist/errors/index.d.ts.map +1 -0
  121. package/dist/errors/index.js +24 -0
  122. package/dist/errors/index.js.map +1 -0
  123. package/dist/errors/reporter.cjs +38 -0
  124. package/dist/errors/reporter.cjs.map +1 -0
  125. package/dist/errors/reporter.d.cts +32 -0
  126. package/dist/errors/reporter.d.cts.map +1 -0
  127. package/dist/errors/reporter.d.ts +32 -0
  128. package/dist/errors/reporter.d.ts.map +1 -0
  129. package/dist/errors/reporter.js +32 -0
  130. package/dist/errors/reporter.js.map +1 -0
  131. package/dist/errors/storage.cjs +55 -0
  132. package/dist/errors/storage.cjs.map +1 -0
  133. package/dist/errors/storage.d.cts +47 -0
  134. package/dist/errors/storage.d.cts.map +1 -0
  135. package/dist/errors/storage.d.ts +47 -0
  136. package/dist/errors/storage.d.ts.map +1 -0
  137. package/dist/errors/storage.js +47 -0
  138. package/dist/errors/storage.js.map +1 -0
  139. package/dist/errors/validation.cjs +38 -0
  140. package/dist/errors/validation.cjs.map +1 -0
  141. package/dist/errors/validation.d.cts +32 -0
  142. package/dist/errors/validation.d.cts.map +1 -0
  143. package/dist/errors/validation.d.ts +32 -0
  144. package/dist/errors/validation.d.ts.map +1 -0
  145. package/dist/errors/validation.js +32 -0
  146. package/dist/errors/validation.js.map +1 -0
  147. package/dist/formatters/history/base.cjs +9 -0
  148. package/dist/formatters/history/base.cjs.map +1 -0
  149. package/dist/formatters/history/base.d.cts +26 -0
  150. package/dist/formatters/history/base.d.cts.map +1 -0
  151. package/dist/formatters/history/base.d.ts +26 -0
  152. package/dist/formatters/history/base.d.ts.map +1 -0
  153. package/dist/formatters/history/base.js +8 -0
  154. package/dist/formatters/history/base.js.map +1 -0
  155. package/dist/formatters/history/compare.cjs +127 -0
  156. package/dist/formatters/history/compare.cjs.map +1 -0
  157. package/dist/formatters/history/compare.d.cts +21 -0
  158. package/dist/formatters/history/compare.d.cts.map +1 -0
  159. package/dist/formatters/history/compare.d.ts +21 -0
  160. package/dist/formatters/history/compare.d.ts.map +1 -0
  161. package/dist/formatters/history/compare.js +123 -0
  162. package/dist/formatters/history/compare.js.map +1 -0
  163. package/dist/formatters/history/list.cjs +74 -0
  164. package/dist/formatters/history/list.cjs.map +1 -0
  165. package/dist/formatters/history/list.d.cts +25 -0
  166. package/dist/formatters/history/list.d.cts.map +1 -0
  167. package/dist/formatters/history/list.d.ts +25 -0
  168. package/dist/formatters/history/list.d.ts.map +1 -0
  169. package/dist/formatters/history/list.js +70 -0
  170. package/dist/formatters/history/list.js.map +1 -0
  171. package/dist/formatters/history/show.cjs +98 -0
  172. package/dist/formatters/history/show.cjs.map +1 -0
  173. package/dist/formatters/history/show.d.cts +21 -0
  174. package/dist/formatters/history/show.d.cts.map +1 -0
  175. package/dist/formatters/history/show.d.ts +21 -0
  176. package/dist/formatters/history/show.d.ts.map +1 -0
  177. package/dist/formatters/history/show.js +94 -0
  178. package/dist/formatters/history/show.js.map +1 -0
  179. package/dist/formatters/history/trends.cjs +194 -0
  180. package/dist/formatters/history/trends.cjs.map +1 -0
  181. package/dist/formatters/history/trends.d.cts +22 -0
  182. package/dist/formatters/history/trends.d.cts.map +1 -0
  183. package/dist/formatters/history/trends.d.ts +22 -0
  184. package/dist/formatters/history/trends.d.ts.map +1 -0
  185. package/dist/formatters/history/trends.js +190 -0
  186. package/dist/formatters/history/trends.js.map +1 -0
  187. package/dist/formatters/history/visualization.cjs +79 -0
  188. package/dist/formatters/history/visualization.cjs.map +1 -0
  189. package/dist/formatters/history/visualization.d.cts +24 -0
  190. package/dist/formatters/history/visualization.d.cts.map +1 -0
  191. package/dist/formatters/history/visualization.d.ts +24 -0
  192. package/dist/formatters/history/visualization.d.ts.map +1 -0
  193. package/dist/formatters/history/visualization.js +74 -0
  194. package/dist/formatters/history/visualization.js.map +1 -0
  195. package/dist/index.cjs +17 -20
  196. package/dist/index.cjs.map +1 -1
  197. package/dist/index.d.cts +6 -6
  198. package/dist/index.d.cts.map +1 -1
  199. package/dist/index.d.ts +6 -6
  200. package/dist/index.d.ts.map +1 -1
  201. package/dist/index.js +9 -11
  202. package/dist/index.js.map +1 -1
  203. package/dist/reporters/csv.cjs +5 -4
  204. package/dist/reporters/csv.cjs.map +1 -1
  205. package/dist/reporters/csv.d.cts +1 -1
  206. package/dist/reporters/csv.d.cts.map +1 -1
  207. package/dist/reporters/csv.d.ts +1 -1
  208. package/dist/reporters/csv.d.ts.map +1 -1
  209. package/dist/reporters/csv.js +4 -3
  210. package/dist/reporters/csv.js.map +1 -1
  211. package/dist/reporters/human.cjs +24 -62
  212. package/dist/reporters/human.cjs.map +1 -1
  213. package/dist/reporters/human.d.cts +1 -1
  214. package/dist/reporters/human.d.cts.map +1 -1
  215. package/dist/reporters/human.d.ts +1 -1
  216. package/dist/reporters/human.d.ts.map +1 -1
  217. package/dist/reporters/human.js +3 -41
  218. package/dist/reporters/human.js.map +1 -1
  219. package/dist/reporters/json.cjs +5 -4
  220. package/dist/reporters/json.cjs.map +1 -1
  221. package/dist/reporters/json.d.cts +1 -1
  222. package/dist/reporters/json.d.cts.map +1 -1
  223. package/dist/reporters/json.d.ts +1 -1
  224. package/dist/reporters/json.d.ts.map +1 -1
  225. package/dist/reporters/json.js +4 -3
  226. package/dist/reporters/json.js.map +1 -1
  227. package/dist/reporters/simple.cjs +3 -3
  228. package/dist/reporters/simple.cjs.map +1 -1
  229. package/dist/reporters/simple.d.cts +1 -1
  230. package/dist/reporters/simple.d.cts.map +1 -1
  231. package/dist/reporters/simple.d.ts +1 -1
  232. package/dist/reporters/simple.d.ts.map +1 -1
  233. package/dist/reporters/simple.js +2 -2
  234. package/dist/reporters/simple.js.map +1 -1
  235. package/dist/{config/manager.cjs → services/config-manager.cjs} +10 -4
  236. package/dist/services/config-manager.cjs.map +1 -0
  237. package/dist/{config/manager.d.cts → services/config-manager.d.cts} +1 -1
  238. package/dist/services/config-manager.d.cts.map +1 -0
  239. package/dist/{config/manager.d.ts → services/config-manager.d.ts} +1 -1
  240. package/dist/services/config-manager.d.ts.map +1 -0
  241. package/dist/{config/manager.js → services/config-manager.js} +10 -4
  242. package/dist/services/config-manager.js.map +1 -0
  243. package/dist/{core/loader.cjs → services/file-loader.cjs} +18 -7
  244. package/dist/services/file-loader.cjs.map +1 -0
  245. package/dist/{core/loader.d.cts → services/file-loader.d.cts} +1 -1
  246. package/dist/services/file-loader.d.cts.map +1 -0
  247. package/dist/{core/loader.d.ts → services/file-loader.d.ts} +1 -1
  248. package/dist/services/file-loader.d.ts.map +1 -0
  249. package/dist/{core/loader.js → services/file-loader.js} +18 -7
  250. package/dist/services/file-loader.js.map +1 -0
  251. package/dist/services/history/comparison.cjs +124 -0
  252. package/dist/services/history/comparison.cjs.map +1 -0
  253. package/dist/services/history/comparison.d.cts +18 -0
  254. package/dist/services/history/comparison.d.cts.map +1 -0
  255. package/dist/services/history/comparison.d.ts +18 -0
  256. package/dist/services/history/comparison.d.ts.map +1 -0
  257. package/dist/services/history/comparison.js +120 -0
  258. package/dist/services/history/comparison.js.map +1 -0
  259. package/dist/services/history/models.cjs +9 -0
  260. package/dist/services/history/models.cjs.map +1 -0
  261. package/dist/services/history/models.d.cts +139 -0
  262. package/dist/services/history/models.d.cts.map +1 -0
  263. package/dist/services/history/models.d.ts +139 -0
  264. package/dist/services/history/models.d.ts.map +1 -0
  265. package/dist/services/history/models.js +8 -0
  266. package/dist/services/history/models.js.map +1 -0
  267. package/dist/services/history/query.cjs +97 -0
  268. package/dist/services/history/query.cjs.map +1 -0
  269. package/dist/services/history/query.d.cts +38 -0
  270. package/dist/services/history/query.d.cts.map +1 -0
  271. package/dist/services/history/query.d.ts +38 -0
  272. package/dist/services/history/query.d.ts.map +1 -0
  273. package/dist/services/history/query.js +92 -0
  274. package/dist/services/history/query.js.map +1 -0
  275. package/dist/services/history/trend-analysis.cjs +187 -0
  276. package/dist/services/history/trend-analysis.cjs.map +1 -0
  277. package/dist/services/history/trend-analysis.d.cts +34 -0
  278. package/dist/services/history/trend-analysis.d.cts.map +1 -0
  279. package/dist/services/history/trend-analysis.d.ts +34 -0
  280. package/dist/services/history/trend-analysis.d.ts.map +1 -0
  281. package/dist/services/history/trend-analysis.js +179 -0
  282. package/dist/services/history/trend-analysis.js.map +1 -0
  283. package/dist/{storage/history.cjs → services/history-storage.cjs} +33 -12
  284. package/dist/services/history-storage.cjs.map +1 -0
  285. package/dist/{storage/history.d.cts → services/history-storage.d.cts} +1 -1
  286. package/dist/services/history-storage.d.cts.map +1 -0
  287. package/dist/{storage/history.d.ts → services/history-storage.d.ts} +1 -1
  288. package/dist/services/history-storage.d.ts.map +1 -0
  289. package/dist/{storage/history.js → services/history-storage.js} +33 -12
  290. package/dist/services/history-storage.js.map +1 -0
  291. package/dist/{progress/manager.cjs → services/progress-manager.cjs} +1 -1
  292. package/dist/services/progress-manager.cjs.map +1 -0
  293. package/dist/{progress/manager.d.cts → services/progress-manager.d.cts} +1 -1
  294. package/dist/services/progress-manager.d.cts.map +1 -0
  295. package/dist/{progress/manager.d.ts → services/progress-manager.d.ts} +1 -1
  296. package/dist/services/progress-manager.d.ts.map +1 -0
  297. package/dist/{progress/manager.js → services/progress-manager.js} +1 -1
  298. package/dist/services/progress-manager.js.map +1 -0
  299. package/dist/{reporters/registry.cjs → services/reporter-registry.cjs} +4 -3
  300. package/dist/services/reporter-registry.cjs.map +1 -0
  301. package/dist/{reporters/registry.d.cts → services/reporter-registry.d.cts} +1 -1
  302. package/dist/services/reporter-registry.d.cts.map +1 -0
  303. package/dist/{reporters/registry.d.ts → services/reporter-registry.d.ts} +1 -1
  304. package/dist/services/reporter-registry.d.ts.map +1 -0
  305. package/dist/{reporters/registry.js → services/reporter-registry.js} +4 -3
  306. package/dist/services/reporter-registry.js.map +1 -0
  307. package/dist/types/cli.d.cts +3 -0
  308. package/dist/types/cli.d.cts.map +1 -1
  309. package/dist/types/cli.d.ts +3 -0
  310. package/dist/types/cli.d.ts.map +1 -1
  311. package/dist/types/interfaces.d.cts +1 -34
  312. package/dist/types/interfaces.d.cts.map +1 -1
  313. package/dist/types/interfaces.d.ts +1 -34
  314. package/dist/types/interfaces.d.ts.map +1 -1
  315. package/dist/utils/ansi.cjs +61 -0
  316. package/dist/utils/ansi.cjs.map +1 -0
  317. package/dist/utils/ansi.d.cts +53 -0
  318. package/dist/utils/ansi.d.cts.map +1 -0
  319. package/dist/utils/ansi.d.ts +53 -0
  320. package/dist/utils/ansi.d.ts.map +1 -0
  321. package/dist/utils/ansi.js +57 -0
  322. package/dist/utils/ansi.js.map +1 -0
  323. package/package.json +10 -8
  324. package/src/bootstrap.ts +5 -7
  325. package/src/cli/commands/history.ts +195 -341
  326. package/src/cli/commands/init.ts +14 -4
  327. package/src/cli/commands/run.ts +52 -7
  328. package/src/cli/index.ts +393 -119
  329. package/src/constants.ts +60 -0
  330. package/src/core/engine.ts +40 -48
  331. package/src/core/engines/accurate-engine.ts +4 -1
  332. package/src/core/engines/tinybench-engine.ts +12 -5
  333. package/src/core/output-path-resolver.ts +38 -0
  334. package/src/errors/base.ts +152 -0
  335. package/src/errors/cli.ts +59 -0
  336. package/src/errors/configuration.ts +45 -0
  337. package/src/errors/execution.ts +62 -0
  338. package/src/errors/file.ts +53 -0
  339. package/src/errors/index.ts +71 -0
  340. package/src/errors/reporter.ts +35 -0
  341. package/src/errors/storage.ts +52 -0
  342. package/src/errors/validation.ts +35 -0
  343. package/src/formatters/history/base.ts +28 -0
  344. package/src/formatters/history/compare.ts +186 -0
  345. package/src/formatters/history/list.ts +101 -0
  346. package/src/formatters/history/show.ts +155 -0
  347. package/src/formatters/history/trends.ts +281 -0
  348. package/src/formatters/history/visualization.ts +93 -0
  349. package/src/index.ts +10 -14
  350. package/src/reporters/csv.ts +5 -3
  351. package/src/reporters/human.ts +3 -43
  352. package/src/reporters/json.ts +5 -3
  353. package/src/reporters/simple.ts +2 -2
  354. package/src/{config/manager.ts → services/config-manager.ts} +13 -3
  355. package/src/{core/loader.ts → services/file-loader.ts} +28 -6
  356. package/src/services/history/comparison.ts +130 -0
  357. package/src/services/history/models.ts +148 -0
  358. package/src/services/history/query.ts +116 -0
  359. package/src/services/history/trend-analysis.ts +238 -0
  360. package/src/{storage/history.ts → services/history-storage.ts} +58 -11
  361. package/src/{reporters/registry.ts → services/reporter-registry.ts} +9 -2
  362. package/src/types/cli.ts +3 -0
  363. package/src/types/interfaces.ts +0 -43
  364. package/src/utils/ansi.ts +59 -0
  365. package/dist/config/manager.cjs.map +0 -1
  366. package/dist/config/manager.d.cts.map +0 -1
  367. package/dist/config/manager.d.ts.map +0 -1
  368. package/dist/config/manager.js.map +0 -1
  369. package/dist/core/error-manager.cjs +0 -303
  370. package/dist/core/error-manager.cjs.map +0 -1
  371. package/dist/core/error-manager.d.cts +0 -77
  372. package/dist/core/error-manager.d.cts.map +0 -1
  373. package/dist/core/error-manager.d.ts +0 -77
  374. package/dist/core/error-manager.d.ts.map +0 -1
  375. package/dist/core/error-manager.js +0 -299
  376. package/dist/core/error-manager.js.map +0 -1
  377. package/dist/core/loader.cjs.map +0 -1
  378. package/dist/core/loader.d.cts.map +0 -1
  379. package/dist/core/loader.d.ts.map +0 -1
  380. package/dist/core/loader.js.map +0 -1
  381. package/dist/progress/manager.cjs.map +0 -1
  382. package/dist/progress/manager.d.cts.map +0 -1
  383. package/dist/progress/manager.d.ts.map +0 -1
  384. package/dist/progress/manager.js.map +0 -1
  385. package/dist/reporters/registry.cjs.map +0 -1
  386. package/dist/reporters/registry.d.cts.map +0 -1
  387. package/dist/reporters/registry.d.ts.map +0 -1
  388. package/dist/reporters/registry.js.map +0 -1
  389. package/dist/storage/history.cjs.map +0 -1
  390. package/dist/storage/history.d.cts.map +0 -1
  391. package/dist/storage/history.d.ts.map +0 -1
  392. package/dist/storage/history.js.map +0 -1
  393. package/src/core/error-manager.ts +0 -372
  394. /package/src/{progress/manager.ts → services/progress-manager.ts} +0 -0
@@ -0,0 +1,71 @@
1
+ /**
2
+ * ModestBench Error Classes
3
+ *
4
+ * Custom error classes for structured error handling throughout ModestBench.
5
+ * All errors extend ModestBenchError and include error codes and documentation
6
+ * URLs.
7
+ */
8
+
9
+ // Base error classes and utilities
10
+ export {
11
+ isModestBenchError,
12
+ ModestBenchAggregateError,
13
+ ModestBenchError,
14
+ } from './base.js';
15
+
16
+ // CLI errors
17
+ export {
18
+ InvalidArgumentError,
19
+ InvalidDateFormatError,
20
+ UnknownError,
21
+ } from './cli.js';
22
+
23
+ // Configuration errors
24
+ export {
25
+ ConfigLoadError,
26
+ ConfigNotFoundError,
27
+ ConfigValidationError,
28
+ UnsupportedConfigFormatError,
29
+ } from './configuration.js';
30
+
31
+ // Execution errors
32
+ export {
33
+ BenchmarkExecutionError,
34
+ OperationTooFastError,
35
+ SetupError,
36
+ TaskExecutionError,
37
+ TeardownError,
38
+ TimeoutError,
39
+ } from './execution.js';
40
+
41
+ // File errors
42
+ export {
43
+ FileDiscoveryError,
44
+ FileLoadError,
45
+ FileNotFoundError,
46
+ FilePermissionError,
47
+ UnsupportedFileExtensionError,
48
+ } from './file.js';
49
+
50
+ // Reporter errors
51
+ export {
52
+ ReporterAlreadyRegisteredError,
53
+ ReporterOutputError,
54
+ UnknownReporterError,
55
+ } from './reporter.js';
56
+
57
+ // Storage errors
58
+ export {
59
+ StorageCorruptionError,
60
+ StorageError,
61
+ StorageIndexError,
62
+ StorageSpaceError,
63
+ UnsupportedExportFormatError,
64
+ } from './storage.js';
65
+
66
+ // Validation errors
67
+ export {
68
+ SchemaValidationError,
69
+ StructureValidationError,
70
+ TypeValidationError,
71
+ } from './validation.js';
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Reporter-related errors
3
+ *
4
+ * Errors that occur during reporter operations.
5
+ */
6
+
7
+ import { ModestBenchError } from './base.js';
8
+
9
+ /**
10
+ * Reporter already registered
11
+ *
12
+ * Thrown when attempting to register a reporter with a name that is already in
13
+ * use.
14
+ */
15
+ export class ReporterAlreadyRegisteredError extends ModestBenchError {
16
+ readonly code = 'ERR_MB_REPORTER_ALREADY_REGISTERED';
17
+ }
18
+
19
+ /**
20
+ * Reporter output failed
21
+ *
22
+ * Thrown when a reporter fails to write output.
23
+ */
24
+ export class ReporterOutputError extends ModestBenchError {
25
+ readonly code = 'ERR_MB_REPORTER_OUTPUT_FAILED';
26
+ }
27
+
28
+ /**
29
+ * Unknown reporter
30
+ *
31
+ * Thrown when attempting to use a reporter that is not registered.
32
+ */
33
+ export class UnknownReporterError extends ModestBenchError {
34
+ readonly code = 'ERR_MB_REPORTER_UNKNOWN';
35
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Storage-related errors
3
+ *
4
+ * Errors that occur during history storage operations.
5
+ */
6
+
7
+ import { ModestBenchError } from './base.js';
8
+
9
+ /**
10
+ * Storage data corruption
11
+ *
12
+ * Thrown when stored data is found to be corrupted or invalid.
13
+ */
14
+ export class StorageCorruptionError extends ModestBenchError {
15
+ readonly code = 'ERR_MB_STORAGE_CORRUPTION';
16
+ }
17
+
18
+ /**
19
+ * Storage operation failed
20
+ *
21
+ * Thrown when a general storage operation fails.
22
+ */
23
+ export class StorageError extends ModestBenchError {
24
+ readonly code = 'ERR_MB_STORAGE_FAILED';
25
+ }
26
+
27
+ /**
28
+ * Storage index corruption
29
+ *
30
+ * Thrown when the storage index is corrupted or cannot be read.
31
+ */
32
+ export class StorageIndexError extends ModestBenchError {
33
+ readonly code = 'ERR_MB_STORAGE_INDEX_CORRUPTION';
34
+ }
35
+
36
+ /**
37
+ * Insufficient storage space
38
+ *
39
+ * Thrown when there is insufficient disk space for storage operations.
40
+ */
41
+ export class StorageSpaceError extends ModestBenchError {
42
+ readonly code = 'ERR_MB_STORAGE_INSUFFICIENT_SPACE';
43
+ }
44
+
45
+ /**
46
+ * Unsupported export format
47
+ *
48
+ * Thrown when attempting to export data in an unsupported format.
49
+ */
50
+ export class UnsupportedExportFormatError extends ModestBenchError {
51
+ readonly code = 'ERR_MB_STORAGE_EXPORT_UNSUPPORTED';
52
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Validation-related errors
3
+ *
4
+ * Errors that occur during benchmark file structure and data validation.
5
+ */
6
+
7
+ import { ModestBenchError } from './base.js';
8
+
9
+ /**
10
+ * Schema validation failed
11
+ *
12
+ * Thrown when data fails to validate against a Zod schema or other schema
13
+ * validation.
14
+ */
15
+ export class SchemaValidationError extends ModestBenchError {
16
+ readonly code = 'ERR_MB_VALIDATION_SCHEMA_FAILED';
17
+ }
18
+
19
+ /**
20
+ * Invalid benchmark structure
21
+ *
22
+ * Thrown when a benchmark file has an invalid or unexpected structure.
23
+ */
24
+ export class StructureValidationError extends ModestBenchError {
25
+ readonly code = 'ERR_MB_VALIDATION_STRUCTURE_INVALID';
26
+ }
27
+
28
+ /**
29
+ * Type validation failed
30
+ *
31
+ * Thrown when data fails type validation checks.
32
+ */
33
+ export class TypeValidationError extends ModestBenchError {
34
+ readonly code = 'ERR_MB_VALIDATION_TYPE_FAILED';
35
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Base Formatter Interface
3
+ *
4
+ * Defines the contract for history command formatters. Each formatter
5
+ * transforms processed data into human-readable or machine-readable output.
6
+ */
7
+
8
+ /**
9
+ * Formatter interface for history command output
10
+ *
11
+ * @template TData - The data type this formatter accepts
12
+ */
13
+ export interface HistoryFormatter<TData> {
14
+ /**
15
+ * Format data as CSV (optional, not all commands support CSV)
16
+ */
17
+ formatCsv?(data: TData): string;
18
+
19
+ /**
20
+ * Format data for human-readable terminal output
21
+ */
22
+ formatHuman(data: TData): string;
23
+
24
+ /**
25
+ * Format data as JSON
26
+ */
27
+ formatJson(data: TData): string;
28
+ }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Compare Formatter
3
+ *
4
+ * Formats benchmark run comparison results in human and JSON formats.
5
+ */
6
+
7
+ import type { CompareResult } from '../../services/history/models.js';
8
+ import type { HistoryFormatter } from './base.js';
9
+
10
+ import { colorize } from '../../utils/ansi.js';
11
+ import { ansiChars } from '../../utils/ansi.js';
12
+
13
+ /**
14
+ * Formatter for history compare command
15
+ */
16
+ export class HistoryCompareFormatter
17
+ implements HistoryFormatter<CompareResult>
18
+ {
19
+ /**
20
+ * Format as human-readable comparison
21
+ */
22
+ formatHuman(data: CompareResult): string {
23
+ const lines: string[] = [];
24
+
25
+ lines.push(colorize('brightMagenta', colorize('bold', 'Comparing runs:')));
26
+ lines.push(
27
+ ` ${colorize('brightCyan', ansiChars.bullet)} ${colorize('brightWhite', colorize('bold', 'Run 1'))} ${colorize('dim', data.run1.id)} (${colorize('white', data.run1.startTime.toLocaleString())})`,
28
+ );
29
+ lines.push(
30
+ ` ${colorize('brightCyan', ansiChars.bullet)} ${colorize('brightWhite', colorize('bold', 'Run 2'))} ${colorize('dim', data.run2.id)} (${colorize('white', data.run2.startTime.toLocaleString())})`,
31
+ );
32
+ lines.push('');
33
+
34
+ lines.push(colorize('cyan', 'Summary comparison:'));
35
+ lines.push('');
36
+ lines.push(
37
+ ` ${colorize('dim', ansiChars.smallSquare)} Files: ${colorize('brightWhite', String(data.run1.summary.totalFiles))} vs ${colorize('brightWhite', String(data.run2.summary.totalFiles))}`,
38
+ );
39
+ lines.push(
40
+ ` ${colorize('dim', ansiChars.smallSquare)} Tasks: ${colorize('brightWhite', String(data.run1.summary.totalTasks))} vs ${colorize('brightWhite', String(data.run2.summary.totalTasks))}`,
41
+ );
42
+ lines.push(
43
+ ` ${colorize('dim', ansiChars.smallSquare)} Passed: ${colorize('brightCyan', String(data.run1.summary.passedTasks))} vs ${colorize('brightCyan', String(data.run2.summary.passedTasks))}`,
44
+ );
45
+ lines.push(
46
+ ` ${colorize('dim', ansiChars.smallSquare)} Failed: ${colorize('brightRed', colorize('bold', String(data.run1.summary.failedTasks)))} vs ${colorize('brightRed', colorize('bold', String(data.run2.summary.failedTasks)))}`,
47
+ );
48
+ lines.push('');
49
+
50
+ // Detailed task comparison
51
+ if (data.tasksInBoth.length > 0) {
52
+ lines.push(colorize('cyan', 'Task-by-task comparison:'));
53
+ lines.push('');
54
+
55
+ for (const comparison of data.tasksInBoth) {
56
+ const mean1 = comparison.run1!.mean / 1000000; // Convert to ms
57
+ const mean2 = comparison.run2!.mean / 1000000;
58
+ const changeSign = comparison.percentChange >= 0 ? '+' : '';
59
+ const changeStr = `${changeSign}${comparison.percentChange.toFixed(1)}%`;
60
+
61
+ lines.push(
62
+ ` ${colorize('brightWhite', `${comparison.suite} › ${comparison.task}`)}`,
63
+ );
64
+
65
+ // Mean - highlight higher (slower/worse) number
66
+ const meanHigher = mean2 > mean1;
67
+ const mean1Str = meanHigher
68
+ ? colorize('magenta', `${mean1.toFixed(3)}ms`)
69
+ : colorize('brightMagenta', `${mean1.toFixed(3)}ms`);
70
+ const mean2Str = meanHigher
71
+ ? colorize('brightMagenta', `${mean2.toFixed(3)}ms`)
72
+ : colorize('magenta', `${mean2.toFixed(3)}ms`);
73
+ lines.push(
74
+ ` ${colorize('dim', ansiChars.bullet)} ${colorize('white', 'Mean:')} ${mean1Str} ${colorize('dim', '→')} ${mean2Str} ${colorize('dim', `(${colorize('white', changeStr)}`)}`,
75
+ );
76
+
77
+ // Min - highlight higher number
78
+ const min1 = comparison.run1!.min / 1000000;
79
+ const min2 = comparison.run2!.min / 1000000;
80
+ const minHigher = min2 > min1;
81
+ const min1Str = minHigher
82
+ ? colorize('magenta', `${min1.toFixed(3)}ms`)
83
+ : colorize('brightMagenta', `${min1.toFixed(3)}ms`);
84
+ const min2Str = minHigher
85
+ ? colorize('brightMagenta', `${min2.toFixed(3)}ms`)
86
+ : colorize('magenta', `${min2.toFixed(3)}ms`);
87
+ lines.push(
88
+ ` ${colorize('dim', ansiChars.bullet)} ${colorize('white', 'Min:')} ${min1Str} ${colorize('dim', '→')} ${min2Str}`,
89
+ );
90
+
91
+ // Max - highlight higher number
92
+ const max1 = comparison.run1!.max / 1000000;
93
+ const max2 = comparison.run2!.max / 1000000;
94
+ const maxHigher = max2 > max1;
95
+ const max1Str = maxHigher
96
+ ? colorize('magenta', `${max1.toFixed(3)}ms`)
97
+ : colorize('brightMagenta', `${max1.toFixed(3)}ms`);
98
+ const max2Str = maxHigher
99
+ ? colorize('brightMagenta', `${max2.toFixed(3)}ms`)
100
+ : colorize('magenta', `${max2.toFixed(3)}ms`);
101
+ lines.push(
102
+ ` ${colorize('dim', ansiChars.bullet)} ${colorize('white', 'Max:')} ${max1Str} ${colorize('dim', '→')} ${max2Str}`,
103
+ );
104
+
105
+ // Iterations - highlight higher number
106
+ const iter1 = comparison.run1!.iterations;
107
+ const iter2 = comparison.run2!.iterations;
108
+ const iterHigher = iter2 > iter1;
109
+ const iter1Str = iterHigher
110
+ ? colorize('brightWhite', String(iter1))
111
+ : colorize('bold', colorize('brightWhite', String(iter1)));
112
+ const iter2Str = iterHigher
113
+ ? colorize('bold', colorize('brightWhite', String(iter2)))
114
+ : colorize('brightWhite', String(iter2));
115
+ lines.push(
116
+ ` ${colorize('dim', ansiChars.bullet)} ${colorize('white', 'Iterations:')} ${iter1Str} ${colorize('dim', 'vs')} ${iter2Str}`,
117
+ );
118
+
119
+ // CV (Coefficient of Variation) - shows measurement consistency
120
+ const cv1 = comparison.run1!.cv * 100;
121
+ const cv2 = comparison.run2!.cv * 100;
122
+ const cvHigher = cv2 > cv1;
123
+ const cv1Str = cvHigher
124
+ ? colorize('magenta', `${cv1.toFixed(2)}%`)
125
+ : colorize('brightMagenta', `${cv1.toFixed(2)}%`);
126
+ const cv2Str = cvHigher
127
+ ? colorize('brightMagenta', `${cv2.toFixed(2)}%`)
128
+ : colorize('magenta', `${cv2.toFixed(2)}%`);
129
+ lines.push(
130
+ ` ${colorize('dim', ansiChars.bullet)} ${colorize('white', 'CV:')} ${cv1Str} ${colorize('dim', '→')} ${cv2Str}`,
131
+ );
132
+
133
+ lines.push('');
134
+ }
135
+ }
136
+
137
+ if (data.tasksOnlyInRun1.length > 0) {
138
+ lines.push(
139
+ colorize(
140
+ 'cyan',
141
+ `Tasks only in run 1 (${data.tasksOnlyInRun1.length}):`,
142
+ ),
143
+ );
144
+ for (const task of data.tasksOnlyInRun1) {
145
+ lines.push(
146
+ ` ${colorize('dim', ansiChars.bullet)} ${colorize('brightWhite', `${task.suite} › ${task.task}`)}`,
147
+ );
148
+ }
149
+ lines.push('');
150
+ }
151
+
152
+ if (data.tasksOnlyInRun2.length > 0) {
153
+ lines.push(
154
+ colorize(
155
+ 'cyan',
156
+ `Tasks only in run 2 (${data.tasksOnlyInRun2.length}):`,
157
+ ),
158
+ );
159
+ for (const task of data.tasksOnlyInRun2) {
160
+ lines.push(
161
+ ` ${colorize('dim', ansiChars.bullet)} ${colorize('brightWhite', `${task.suite} › ${task.task}`)}`,
162
+ );
163
+ }
164
+ lines.push('');
165
+ }
166
+
167
+ return lines.join('\n');
168
+ }
169
+
170
+ /**
171
+ * Format as JSON
172
+ */
173
+ formatJson(data: CompareResult): string {
174
+ return JSON.stringify(
175
+ {
176
+ run1: data.run1,
177
+ run2: data.run2,
178
+ taskComparisons: data.tasksInBoth,
179
+ tasksOnlyInRun1: data.tasksOnlyInRun1,
180
+ tasksOnlyInRun2: data.tasksOnlyInRun2,
181
+ },
182
+ null,
183
+ 2,
184
+ );
185
+ }
186
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * List Formatter
3
+ *
4
+ * Formats historical run listings in human, JSON, and CSV formats.
5
+ */
6
+
7
+ import type { HistoryListResult } from '../../services/history/models.js';
8
+ import type { HistoryFormatter } from './base.js';
9
+
10
+ import { ansiChars, colorize } from '../../utils/ansi.js';
11
+
12
+ /**
13
+ * Formatter for history list command
14
+ */
15
+ export class HistoryListFormatter
16
+ implements HistoryFormatter<HistoryListResult>
17
+ {
18
+ /**
19
+ * Format as CSV
20
+ */
21
+ formatCsv(data: HistoryListResult): string {
22
+ const lines: string[] = ['id,startTime,duration,files,tasks,passed,failed'];
23
+
24
+ for (const run of data.runs) {
25
+ lines.push(
26
+ `${run.id},${run.startTime.toISOString()},${run.duration},${run.summary.totalFiles},${run.summary.totalTasks},${run.summary.passedTasks},${run.summary.failedTasks}`,
27
+ );
28
+ }
29
+
30
+ return lines.join('\n');
31
+ }
32
+
33
+ /**
34
+ * Format as human-readable list
35
+ */
36
+ formatHuman(data: HistoryListResult): string {
37
+ if (data.runs.length === 0) {
38
+ return colorize('dim', 'No historical data found matching criteria.');
39
+ }
40
+
41
+ const lines: string[] = [
42
+ colorize('brightMagenta', colorize('bold', '\nRecent Benchmark Runs')),
43
+ '',
44
+ ];
45
+
46
+ for (const run of data.runs) {
47
+ const dateStr = run.startTime.toLocaleString();
48
+ const durationStr = `${(run.duration / 1000).toFixed(1)}s`;
49
+
50
+ // Status with colors and symbols
51
+ const hasFailures = run.summary.failedTasks > 0;
52
+ const statusIcon = hasFailures
53
+ ? colorize('brightRed', ansiChars.cross)
54
+ : colorize('brightCyan', ansiChars.checkmark);
55
+
56
+ const passedStr = colorize(
57
+ 'brightCyan',
58
+ `${run.summary.passedTasks} passed`,
59
+ );
60
+ const statusStr = hasFailures
61
+ ? `${passedStr}, ${colorize('brightRed', `${run.summary.failedTasks} failed`)}`
62
+ : passedStr;
63
+
64
+ // Run ID in bright white and bold, date dimmed, duration in magenta
65
+ lines.push(
66
+ ` ${statusIcon} ${colorize('brightWhite', colorize('bold', run.id))} ${colorize('dim', ansiChars.bullet)} ${colorize('gray', dateStr)} ${colorize('dim', ansiChars.bullet)} ${colorize('brightMagenta', durationStr)}`,
67
+ );
68
+
69
+ // Files and tasks info
70
+ lines.push(
71
+ ` ${colorize('dim', `${run.summary.totalFiles} files, ${run.summary.totalTasks} tasks:`)} ${statusStr}`,
72
+ );
73
+ lines.push('');
74
+ }
75
+
76
+ return lines.join('\n');
77
+ }
78
+
79
+ /**
80
+ * Format as JSON array
81
+ */
82
+ formatJson(data: HistoryListResult): string {
83
+ if (data.runs.length === 0) {
84
+ return '[]';
85
+ }
86
+
87
+ return JSON.stringify(
88
+ data.runs.map((run) => ({
89
+ duration: run.duration,
90
+ failed: run.summary.failedTasks,
91
+ files: run.summary.totalFiles,
92
+ id: run.id,
93
+ passed: run.summary.passedTasks,
94
+ startTime: run.startTime,
95
+ tasks: run.summary.totalTasks,
96
+ })),
97
+ null,
98
+ 2,
99
+ );
100
+ }
101
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Show Formatter
3
+ *
4
+ * Formats detailed benchmark run display in human and JSON formats.
5
+ */
6
+
7
+ import { relative } from 'node:path';
8
+
9
+ import type { ShowResult } from '../../services/history/models.js';
10
+ import type { HistoryFormatter } from './base.js';
11
+
12
+ import { ansiChars, colorize } from '../../utils/ansi.js';
13
+
14
+ /**
15
+ * Formatter for history show command
16
+ */
17
+ export class HistoryShowFormatter implements HistoryFormatter<ShowResult> {
18
+ /**
19
+ * Format as human-readable detailed view
20
+ */
21
+ formatHuman(data: ShowResult): string {
22
+ const lines: string[] = [];
23
+
24
+ // Header with run ID
25
+ lines.push(
26
+ colorize(
27
+ 'cyan',
28
+ colorize(
29
+ 'bold',
30
+ `\nBenchmark Run: ${colorize('brightWhite', colorize('bold', data.id))}`,
31
+ ),
32
+ ),
33
+ );
34
+
35
+ // Run details (indented by 2 spaces)
36
+ lines.push(
37
+ ` ${colorize('brightCyan', ansiChars.bullet)} ${colorize('white', data.startTime.toLocaleString())}`,
38
+ );
39
+ lines.push(
40
+ ` ${colorize('brightCyan', ansiChars.bullet)} ${colorize('white', 'Duration:')} ${colorize('magenta', `${(data.duration / 1000).toFixed(1)}s`)}`,
41
+ );
42
+ lines.push(
43
+ ` ${colorize('brightCyan', ansiChars.bullet)} Node.js ${colorize('brightWhite', data.environment.nodeVersion)} on ${colorize('brightWhite', data.environment.platform)} (${colorize('brightWhite', data.environment.arch)})`,
44
+ );
45
+
46
+ // CPU and system info
47
+ lines.push(
48
+ ` ${colorize('brightCyan', ansiChars.bullet)} ${colorize('brightWhite', String(data.environment.cpu.cores))} cores @ ${colorize('brightWhite', `${data.environment.cpu.speed}MHz`)} on ${colorize('brightWhite', data.environment.cpu.model)}`,
49
+ );
50
+
51
+ if (data.git) {
52
+ lines.push(
53
+ ` ${colorize('brightCyan', ansiChars.bullet)} ${colorize('brightBlue', data.git.branch)}@${colorize('dim', data.git.commit.substring(0, 8))}`,
54
+ );
55
+ }
56
+
57
+ // Summary section
58
+ lines.push('');
59
+ lines.push(colorize('cyan', 'Summary'));
60
+ lines.push(
61
+ ` ${colorize('dim', ansiChars.smallSquare)} Files: ${colorize('brightWhite', String(data.summary.totalFiles))}`,
62
+ );
63
+ lines.push(
64
+ ` ${colorize('dim', ansiChars.smallSquare)} Suites: ${colorize('brightWhite', String(data.summary.totalSuites))}`,
65
+ );
66
+ lines.push(
67
+ ` ${colorize('dim', ansiChars.smallSquare)} Tasks: ${colorize('brightWhite', String(data.summary.totalTasks))}`,
68
+ );
69
+
70
+ lines.push(
71
+ ` ${colorize('dim', ansiChars.smallSquare)} Passed: ${colorize('brightCyan', String(data.summary.passedTasks))}`,
72
+ );
73
+
74
+ if (data.summary.failedTasks > 0) {
75
+ lines.push(
76
+ ` ${colorize('dim', ansiChars.smallSquare)} Failed: ${colorize('brightRed', colorize('bold', String(data.summary.failedTasks)))}`,
77
+ );
78
+ }
79
+
80
+ // Detailed results
81
+ lines.push('');
82
+ lines.push(colorize('cyan', 'Results'));
83
+ lines.push('');
84
+
85
+ for (const file of data.files) {
86
+ // Display filepath as relative if within cwd, otherwise absolute
87
+ const displayPath = relative(process.cwd(), file.filePath);
88
+ const finalPath = displayPath.startsWith('..')
89
+ ? file.filePath
90
+ : displayPath;
91
+
92
+ lines.push(
93
+ `${colorize('dim', ansiChars.bullet)} ${colorize('brightMagenta', colorize('bold', finalPath))}`,
94
+ );
95
+
96
+ for (const suite of file.suites) {
97
+ lines.push(
98
+ ` ${colorize('dim', ansiChars.bullet)} ${colorize('brightWhite', suite.name)}`,
99
+ );
100
+
101
+ for (const task of suite.tasks) {
102
+ const statusIcon = task.error
103
+ ? colorize('brightRed', ansiChars.cross)
104
+ : colorize('brightCyan', ansiChars.checkmark);
105
+
106
+ if (task.error) {
107
+ lines.push(
108
+ ` ${statusIcon} ${colorize('white', task.name)} ${colorize('dim', ansiChars.bullet)} ${colorize('brightRed', 'failed')}`,
109
+ );
110
+ } else {
111
+ const mean = formatTime(task.mean);
112
+ const opsStr = task.opsPerSecond.toLocaleString('en-US', {
113
+ maximumFractionDigits: 0,
114
+ });
115
+ const rmeStr = task.marginOfError.toFixed(2);
116
+
117
+ lines.push(
118
+ ` ${statusIcon} ${colorize('white', task.name)}: ${colorize('brightMagenta', mean)} ${colorize('dim', ansiChars.bullet)} ${colorize('brightBlue', `${ansiChars.plusMinus}${rmeStr}`)} ${colorize('dim', ansiChars.bullet)} ${colorize('magenta', opsStr)} ops/sec`,
119
+ );
120
+
121
+ if (task.iterations > 0) {
122
+ lines.push(
123
+ ` ${colorize('dim', `${task.iterations} iterations, cv: ${task.cv.toFixed(1)}%`)}`,
124
+ );
125
+ }
126
+ }
127
+ }
128
+ }
129
+
130
+ lines.push('');
131
+ }
132
+
133
+ return lines.join('\n');
134
+ }
135
+
136
+ /**
137
+ * Format as complete JSON
138
+ */
139
+ formatJson(data: ShowResult): string {
140
+ return JSON.stringify(data, null, 2);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Format nanoseconds as a human-readable time string
146
+ */
147
+ const formatTime = (ns: number): string => {
148
+ if (ns < 1000) {
149
+ return `${ns.toFixed(2)}ns`;
150
+ }
151
+ if (ns < 1000000) {
152
+ return `${(ns / 1000).toFixed(3)}µs`;
153
+ }
154
+ return `${(ns / 1000000).toFixed(3)}ms`;
155
+ };