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
@@ -5,70 +5,94 @@
5
5
  * comparing, and cleaning historical data.
6
6
  */
7
7
 
8
- import type { HistoryQuery, RetentionPolicy } from '../../types/index.js';
8
+ import type {
9
+ HistoryQuery,
10
+ HistoryStorage,
11
+ RetentionPolicy,
12
+ } from '../../types/index.js';
9
13
  import type { CliContext } from '../index.js';
10
14
 
15
+ import { HistoryCompareFormatter } from '../../formatters/history/compare.js';
16
+ import { HistoryListFormatter } from '../../formatters/history/list.js';
17
+ import { HistoryShowFormatter } from '../../formatters/history/show.js';
18
+ import { HistoryTrendsFormatter } from '../../formatters/history/trends.js';
19
+ import { ComparisonService } from '../../services/history/comparison.js';
20
+ import {
21
+ HistoryQueryService,
22
+ parseDate,
23
+ } from '../../services/history/query.js';
24
+ import { TrendAnalysisService } from '../../services/history/trend-analysis.js';
25
+
11
26
  /**
12
- * History command options interface
27
+ * Base options shared by all history subcommands
13
28
  */
14
- interface HistoryOptions {
15
- args?: string[] | undefined; // Additional arguments after subcommand
16
- confirm?: boolean | undefined;
29
+ interface BaseHistoryOptions {
17
30
  cwd: string;
18
- format?: 'csv' | 'human' | 'json' | undefined;
19
- limit?: number | undefined;
31
+ quiet?: boolean | undefined;
32
+ verbose?: boolean | undefined;
33
+ }
34
+
35
+ /**
36
+ * Options for history clean command
37
+ */
38
+ interface HistoryCleanOptions extends BaseHistoryOptions {
39
+ confirm?: boolean | undefined;
20
40
  maxAge?: number | undefined;
21
41
  maxRuns?: number | undefined;
22
42
  maxSize?: number | undefined;
23
- outputDir?: string | undefined;
43
+ }
44
+
45
+ /**
46
+ * Options for history compare command
47
+ */
48
+ interface HistoryCompareOptions extends BaseHistoryOptions {
49
+ format?: 'human' | 'json' | undefined;
50
+ runId1: string;
51
+ runId2: string;
52
+ }
53
+
54
+ /**
55
+ * Options for history export command
56
+ */
57
+ interface HistoryExportOptions extends BaseHistoryOptions {
58
+ format?: 'csv' | 'json' | undefined;
59
+ outputPath: string;
60
+ since?: string | undefined;
61
+ until?: string | undefined;
62
+ }
63
+
64
+ /**
65
+ * Options for history list command
66
+ */
67
+ interface HistoryListOptions extends BaseHistoryOptions {
68
+ format?: 'csv' | 'human' | 'json' | undefined;
69
+ limit?: number | undefined;
24
70
  pattern?: string | undefined;
25
- quiet?: boolean | undefined;
26
71
  since?: string | undefined;
27
- subcommand: 'clean' | 'compare' | 'export' | 'list' | 'show' | 'trends';
28
72
  tags?: string[] | undefined;
29
73
  until?: string | undefined;
30
- verbose?: boolean | undefined;
31
74
  }
32
75
 
33
76
  /**
34
- * Handle history command
77
+ * Options for history show command
35
78
  */
36
- export const handleHistoryCommand = async (
37
- context: CliContext,
38
- options: HistoryOptions,
39
- ): Promise<number> => {
40
- try {
41
- // Get the subcommand
42
- const subcommand = options.subcommand;
43
-
44
- switch (subcommand) {
45
- case 'clean':
46
- return await handleCleanCommand(context, options);
47
- case 'compare':
48
- return await handleCompareCommand(context, options);
49
- case 'export':
50
- return await handleExportCommand(context, options);
51
- case 'list':
52
- return await handleListCommand(context, options);
53
- case 'show':
54
- return await handleShowCommand(context, options);
55
- case 'trends':
56
- return await handleTrendsCommand(context, options);
57
- default:
58
- console.error(`Unknown history subcommand: ${subcommand || '(none)'}`);
59
- console.error(
60
- 'Available subcommands: list, show, compare, trends, clean, export',
61
- );
62
- return 2; // Config error
63
- }
64
- } catch (error) {
65
- console.error(
66
- 'History command failed:',
67
- error instanceof Error ? error.message : String(error),
68
- );
69
- return 2; // Configuration/runtime errors
70
- }
71
- };
79
+ interface HistoryShowOptions extends BaseHistoryOptions {
80
+ format?: 'csv' | 'human' | 'json' | undefined;
81
+ runId: string;
82
+ }
83
+
84
+ /**
85
+ * Options for history trends command
86
+ */
87
+ interface HistoryTrendsOptions extends BaseHistoryOptions {
88
+ all?: boolean | undefined;
89
+ format?: 'human' | 'json' | undefined;
90
+ limit?: number | undefined;
91
+ pattern?: string | undefined;
92
+ since?: string | undefined;
93
+ tags?: string[] | undefined;
94
+ until?: string | undefined;
95
+ }
72
96
 
73
97
  /**
74
98
  * Format bytes in human-readable format
@@ -86,12 +110,38 @@ const formatBytes = (bytes: number): string => {
86
110
  return `${size.toFixed(1)} ${units[unitIndex]}`;
87
111
  };
88
112
 
113
+ /**
114
+ * Resolve a partial run ID to a full ID by checking prefix match
115
+ *
116
+ * Supports Git-style partial ID matching (e.g., "k3m" matches "k3m9x2p")
117
+ */
118
+ const resolveRunId = async (
119
+ storage: HistoryStorage,
120
+ partialId: string,
121
+ ): Promise<null | string> => {
122
+ // First try exact match
123
+ const exactRun = await storage.loadRun(partialId);
124
+ if (exactRun) {
125
+ return partialId;
126
+ }
127
+
128
+ // Query all runs to find a prefix match
129
+ const allRuns = await storage.queryRuns({});
130
+
131
+ const prefixMatch = allRuns.find((run) => run.id.startsWith(partialId));
132
+ if (prefixMatch) {
133
+ return prefixMatch.id;
134
+ }
135
+
136
+ return null;
137
+ };
138
+
89
139
  /**
90
140
  * Handle the clean subcommand
91
141
  */
92
- const handleCleanCommand = async (
142
+ export const handleCleanCommand = async (
93
143
  context: CliContext,
94
- options: HistoryOptions,
144
+ options: HistoryCleanOptions,
95
145
  ): Promise<number> => {
96
146
  try {
97
147
  // Build retention policy from arguments
@@ -158,69 +208,38 @@ const handleCleanCommand = async (
158
208
  /**
159
209
  * Handle the compare subcommand
160
210
  */
161
- const handleCompareCommand = async (
211
+ export const handleCompareCommand = async (
162
212
  context: CliContext,
163
- options: HistoryOptions,
213
+ options: HistoryCompareOptions,
164
214
  ): Promise<number> => {
165
215
  try {
166
- // For compare command, IDs come from args after the subcommand
167
- const id1 = options.args?.[0];
168
- const id2 = options.args?.[1];
169
-
170
- if (!id1 || !id2) {
171
- console.error('Two run IDs are required for compare command');
172
- console.error('Usage: modestbench history compare <run-id1> <run-id2>');
173
- return 2;
174
- }
175
-
176
216
  const [run1, run2] = await Promise.all([
177
- context.historyStorage.loadRun(id1),
178
- context.historyStorage.loadRun(id2),
217
+ context.historyStorage.loadRun(options.runId1),
218
+ context.historyStorage.loadRun(options.runId2),
179
219
  ]);
180
220
 
181
221
  if (!run1) {
182
- console.error(`Run not found: ${id1}`);
222
+ console.error(`Run not found: ${options.runId1}`);
183
223
  return 1;
184
224
  }
185
225
 
186
226
  if (!run2) {
187
- console.error(`Run not found: ${id2}`);
227
+ console.error(`Run not found: ${options.runId2}`);
188
228
  return 1;
189
229
  }
190
230
 
191
- if (options.format === 'json') {
192
- const comparison = {
193
- run1: { id: run1.id, summary: run1.summary },
194
- run2: { id: run2.id, summary: run2.summary },
195
- // TODO: Add detailed comparison logic
196
- };
197
- console.log(JSON.stringify(comparison, null, 2));
198
- } else {
199
- // Human format comparison
200
- console.log(`Comparing runs:`);
201
- console.log(` Run 1: ${run1.id} (${run1.startTime.toLocaleString()})`);
202
- console.log(` Run 2: ${run2.id} (${run2.startTime.toLocaleString()})`);
203
- console.log();
231
+ // Compare using service
232
+ const comparisonService = new ComparisonService();
233
+ const result = comparisonService.compareRuns(run1, run2);
204
234
 
205
- console.log('Summary comparison:');
206
- console.log(
207
- ` Files: ${run1.summary.totalFiles} vs ${run2.summary.totalFiles}`,
208
- );
209
- console.log(
210
- ` Tasks: ${run1.summary.totalTasks} vs ${run2.summary.totalTasks}`,
211
- );
212
- console.log(
213
- ` Passed: ${run1.summary.passedTasks} vs ${run2.summary.passedTasks}`,
214
- );
215
- console.log(
216
- ` Failed: ${run1.summary.failedTasks} vs ${run2.summary.failedTasks}`,
217
- );
218
-
219
- // TODO: Add detailed performance comparison
220
- console.log();
221
- console.log('Note: Detailed performance comparison not yet implemented.');
222
- }
235
+ // Format output
236
+ const formatter = new HistoryCompareFormatter();
237
+ const output =
238
+ options.format === 'json'
239
+ ? formatter.formatJson(result)
240
+ : formatter.formatHuman(result);
223
241
 
242
+ console.log(output);
224
243
  return 0;
225
244
  } catch (error) {
226
245
  console.error(
@@ -234,9 +253,9 @@ const handleCompareCommand = async (
234
253
  /**
235
254
  * Handle the export subcommand
236
255
  */
237
- const handleExportCommand = async (
256
+ export const handleExportCommand = async (
238
257
  context: CliContext,
239
- options: HistoryOptions,
258
+ options: HistoryExportOptions,
240
259
  ): Promise<number> => {
241
260
  try {
242
261
  const format = options.format || 'json';
@@ -247,21 +266,13 @@ const handleExportCommand = async (
247
266
  ...(options.until && { until: parseDate(options.until) }),
248
267
  } as Partial<HistoryQuery>;
249
268
 
250
- const exportData = await context.historyStorage.export(
251
- format as 'csv' | 'json',
252
- query,
253
- );
269
+ const exportData = await context.historyStorage.export(format, query);
254
270
 
255
- if (options.outputDir) {
256
- // Write to file
257
- const fs = await import('node:fs/promises');
258
- await fs.writeFile(options.outputDir, exportData, 'utf8');
259
- if (!options.quiet) {
260
- console.log(`Exported history to ${options.outputDir}`);
261
- }
262
- } else {
263
- // Write to stdout
264
- console.log(exportData);
271
+ // Write to file
272
+ const fs = await import('node:fs/promises');
273
+ await fs.writeFile(options.outputPath, exportData, 'utf8');
274
+ if (!options.quiet) {
275
+ console.log(`Exported history to ${options.outputPath}`);
265
276
  }
266
277
 
267
278
  return 0;
@@ -277,110 +288,39 @@ const handleExportCommand = async (
277
288
  /**
278
289
  * Handle the list subcommand
279
290
  */
280
- const handleListCommand = async (
291
+ export const handleListCommand = async (
281
292
  context: CliContext,
282
- options: HistoryOptions,
293
+ options: HistoryListOptions,
283
294
  ): Promise<number> => {
284
295
  try {
285
- // Build query from command line arguments
286
- let parsedSince: Date | undefined;
287
- let parsedUntil: Date | undefined;
288
-
289
- if (options.since) {
290
- try {
291
- parsedSince = parseDate(options.since);
292
- } catch (error) {
293
- console.error(
294
- 'Invalid since date:',
295
- error instanceof Error ? error.message : String(error),
296
- );
297
- return 2; // Invalid date format
298
- }
299
- }
300
-
301
- if (options.until) {
302
- try {
303
- parsedUntil = parseDate(options.until);
304
- } catch (error) {
305
- console.error(
306
- 'Invalid until date:',
307
- error instanceof Error ? error.message : String(error),
308
- );
309
- return 2; // Invalid date format
310
- }
311
- }
312
-
313
- const query = {
314
- ...(parsedSince && { since: parsedSince }),
315
- ...(parsedUntil && { until: parsedUntil }),
316
- ...(options.pattern && { pattern: options.pattern }),
317
- ...(options.tags && options.tags.length > 0 && { tags: options.tags }),
318
- ...(options.limit && { limit: options.limit }),
319
- } as Partial<HistoryQuery>;
296
+ // Query runs using service
297
+ const queryService = new HistoryQueryService(context.historyStorage);
298
+ const runs = await queryService.queryWithDateParsing(options);
299
+
300
+ // Transform to result format
301
+ const result = {
302
+ runs: runs.map((run) => ({
303
+ duration: run.duration,
304
+ id: run.id,
305
+ startTime: run.startTime,
306
+ summary: run.summary,
307
+ })),
308
+ totalCount: runs.length,
309
+ };
310
+
311
+ // Format output
312
+ const formatter = new HistoryListFormatter();
313
+ let output: string;
320
314
 
321
- // Query historical runs
322
- const runs = await context.historyStorage.queryRuns(query);
323
-
324
- // Display results based on format
325
315
  if (options.format === 'json') {
326
- if (runs.length === 0) {
327
- console.log('[]'); // Empty JSON array for no data
328
- } else {
329
- console.log(
330
- JSON.stringify(
331
- runs.map((run) => ({
332
- duration: run.duration,
333
- failed: run.summary.failedTasks,
334
- files: run.summary.totalFiles,
335
- id: run.id,
336
- passed: run.summary.passedTasks,
337
- startTime: run.startTime,
338
- tasks: run.summary.totalTasks,
339
- })),
340
- null,
341
- 2,
342
- ),
343
- );
344
- }
316
+ output = formatter.formatJson(result);
345
317
  } else if (options.format === 'csv') {
346
- console.log('id,startTime,duration,files,tasks,passed,failed');
347
- if (runs.length > 0) {
348
- for (const run of runs) {
349
- console.log(
350
- `${run.id},${run.startTime.toISOString()},${run.duration},${run.summary.totalFiles},${run.summary.totalTasks},${run.summary.passedTasks},${run.summary.failedTasks}`,
351
- );
352
- }
353
- }
354
- // For CSV, no additional message needed - header is sufficient
318
+ output = formatter.formatCsv(result);
355
319
  } else {
356
- // Human format
357
- if (runs.length === 0) {
358
- if (!options.quiet) {
359
- console.log('No historical data found matching criteria.');
360
- }
361
- } else {
362
- console.log('Recent benchmark runs:');
363
- console.log();
364
-
365
- for (const run of runs) {
366
- const dateStr = run.startTime.toLocaleString();
367
- const durationStr = `${(run.duration / 1000).toFixed(1)}s`;
368
- const statusStr =
369
- run.summary.failedTasks > 0
370
- ? `${run.summary.passedTasks} passed, ${run.summary.failedTasks} failed`
371
- : `${run.summary.passedTasks} passed`;
372
-
373
- console.log(
374
- ` ${run.id.substring(0, 8)} - ${dateStr} (${durationStr})`,
375
- );
376
- console.log(
377
- ` ${run.summary.totalFiles} files, ${run.summary.totalTasks} tasks: ${statusStr}`,
378
- );
379
- console.log();
380
- }
381
- }
320
+ output = formatter.formatHuman(result);
382
321
  }
383
322
 
323
+ console.log(output);
384
324
  return 0;
385
325
  } catch (error) {
386
326
  console.error(
@@ -394,68 +334,34 @@ const handleListCommand = async (
394
334
  /**
395
335
  * Handle the show subcommand
396
336
  */
397
- const handleShowCommand = async (
337
+ export const handleShowCommand = async (
398
338
  context: CliContext,
399
- options: HistoryOptions,
339
+ options: HistoryShowOptions,
400
340
  ): Promise<number> => {
401
341
  try {
402
- // For show command, ID comes from the args after the subcommand
403
- const runId = options.args?.[0];
342
+ // Resolve partial ID to full ID
343
+ const fullRunId = await resolveRunId(context.historyStorage, options.runId);
404
344
 
405
- if (!runId) {
406
- console.error('Run ID is required for show command');
407
- console.error('Usage: modestbench history show <run-id>');
408
- return 2;
345
+ if (!fullRunId) {
346
+ console.error(`Run not found: ${options.runId}`);
347
+ return 1;
409
348
  }
410
349
 
411
- const run = await context.historyStorage.loadRun(runId);
350
+ const run = await context.historyStorage.loadRun(fullRunId);
412
351
 
413
352
  if (!run) {
414
- console.error(`Run not found: ${runId}`);
353
+ console.error(`Run not found: ${options.runId}`);
415
354
  return 1;
416
355
  }
417
356
 
418
- if (options.format === 'json') {
419
- console.log(JSON.stringify(run, null, 2));
420
- } else {
421
- // Human format
422
- console.log(`Benchmark Run: ${run.id}`);
423
- console.log(`Date: ${run.startTime.toLocaleString()}`);
424
- console.log(`Duration: ${(run.duration / 1000).toFixed(1)}s`);
425
- console.log(
426
- `Environment: Node.js ${run.environment.nodeVersion} on ${run.environment.platform}`,
427
- );
428
-
429
- if (run.git) {
430
- console.log(`Git: ${run.git.branch}@${run.git.commit.substring(0, 8)}`);
431
- }
432
-
433
- console.log();
434
- console.log('Summary:');
435
- console.log(` Files: ${run.summary.totalFiles}`);
436
- console.log(` Suites: ${run.summary.totalSuites}`);
437
- console.log(` Tasks: ${run.summary.totalTasks}`);
438
- console.log(` Passed: ${run.summary.passedTasks}`);
439
- console.log(` Failed: ${run.summary.failedTasks}`);
440
-
441
- // TODO: Show detailed file/suite/task results
442
- console.log();
443
- console.log('Detailed results:');
444
- for (const file of run.files) {
445
- console.log(` 📁 ${file.filePath}`);
446
- for (const suite of file.suites) {
447
- console.log(` 📊 ${suite.name}`);
448
- for (const task of suite.tasks) {
449
- const status = task.error ? '❌' : '✅';
450
- const timing = task.error
451
- ? 'failed'
452
- : `${(task.mean / 1000000).toFixed(2)}ms`;
453
- console.log(` ${status} ${task.name} - ${timing}`);
454
- }
455
- }
456
- }
457
- }
357
+ // Format output
358
+ const formatter = new HistoryShowFormatter();
359
+ const output =
360
+ options.format === 'json'
361
+ ? formatter.formatJson(run)
362
+ : formatter.formatHuman(run);
458
363
 
364
+ console.log(output);
459
365
  return 0;
460
366
  } catch (error) {
461
367
  console.error(
@@ -469,101 +375,49 @@ const handleShowCommand = async (
469
375
  /**
470
376
  * Handle the trends subcommand
471
377
  */
472
- const handleTrendsCommand = async (
378
+ export const handleTrendsCommand = async (
473
379
  context: CliContext,
474
- options: HistoryOptions,
380
+ options: HistoryTrendsOptions,
475
381
  ): Promise<number> => {
476
382
  try {
477
- // Build query from command line arguments (same as list command)
478
- let parsedSince: Date | undefined;
479
- let parsedUntil: Date | undefined;
480
-
481
- if (options.since) {
482
- try {
483
- parsedSince = parseDate(options.since);
484
- } catch (error) {
485
- console.error(
486
- 'Invalid since date:',
487
- error instanceof Error ? error.message : String(error),
488
- );
489
- return 2; // Invalid date format
490
- }
491
- }
492
-
493
- if (options.until) {
494
- try {
495
- parsedUntil = parseDate(options.until);
496
- } catch (error) {
497
- console.error(
498
- 'Invalid until date:',
499
- error instanceof Error ? error.message : String(error),
500
- );
501
- return 2; // Invalid date format
502
- }
503
- }
504
-
505
- // Get pattern from args or explicit pattern option
506
- const pattern = options.args?.[0] || options.pattern;
507
-
508
- const query = {
509
- ...(parsedSince && { since: parsedSince }),
510
- ...(parsedUntil && { until: parsedUntil }),
511
- ...(pattern && { pattern }),
512
- ...(options.tags && options.tags.length > 0 && { tags: options.tags }),
513
- ...(options.limit && { limit: options.limit }),
514
- } as Partial<HistoryQuery>;
515
-
516
- // Query historical runs
517
- const runs = await context.historyStorage.queryRuns(query);
383
+ // Query runs using service
384
+ const queryService = new HistoryQueryService(context.historyStorage);
385
+ const runs = await queryService.queryWithDateParsing({
386
+ limit: options.all ? undefined : options.limit,
387
+ pattern: options.pattern,
388
+ since: options.since,
389
+ tags: options.tags,
390
+ until: options.until,
391
+ });
518
392
 
519
393
  if (runs.length === 0) {
520
394
  if (!options.quiet) {
521
395
  console.log('No historical data found matching criteria');
522
396
  }
523
- return 0; // Success - no data is not an error
397
+ return 0;
524
398
  }
525
399
 
526
- if (options.format === 'json') {
527
- // TODO: Generate trends data in JSON format
528
- const trendsData = {
529
- runs: runs.length,
530
- timespan: {
531
- end: runs[0]?.startTime,
532
- start: runs[runs.length - 1]?.startTime,
533
- },
534
- // TODO: Add actual trend calculations
535
- };
536
- console.log(JSON.stringify(trendsData, null, 2));
537
- } else {
538
- // Human format trends
539
- if (!options.quiet) {
540
- console.log(`Performance trends for ${runs.length} runs:`);
541
- console.log(
542
- `Time range: ${runs[runs.length - 1]?.startTime} to ${runs[0]?.startTime}`,
543
- );
544
- // TODO: Add trend analysis and visualization
545
- console.log('(Trend analysis not yet implemented)');
546
- }
400
+ // Analyze trends using service
401
+ const analysisService = new TrendAnalysisService();
402
+ const result = analysisService.analyzeTrends(runs);
403
+
404
+ // Format output
405
+ const formatter = new HistoryTrendsFormatter();
406
+ const output =
407
+ options.format === 'json'
408
+ ? formatter.formatJson(result)
409
+ : formatter.formatHuman(result);
410
+
411
+ if (!options.quiet || options.format !== 'human') {
412
+ console.log(output);
547
413
  }
548
414
 
549
- return 0; // Success
415
+ return 0;
550
416
  } catch (error) {
551
- console.error('Error showing trends:', error);
552
- return 3; // Runtime error
553
- }
554
- };
555
-
556
- /**
557
- * Parse date string (ISO 8601 or relative)
558
- */
559
- const parseDate = (dateStr: string): Date => {
560
- // Try parsing as ISO 8601 first
561
- const isoDate = new Date(dateStr);
562
- if (!isNaN(isoDate.getTime())) {
563
- return isoDate;
417
+ console.error(
418
+ 'Failed to show trends:',
419
+ error instanceof Error ? error.message : String(error),
420
+ );
421
+ return 5;
564
422
  }
565
-
566
- // TODO: Parse relative dates like "1 week ago", "3 days ago", etc.
567
- // For now, throw error for invalid dates
568
- throw new Error(`Invalid date format: "${dateStr}"`);
569
423
  };