modestbench 0.9.1 → 0.9.2

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 (151) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cli/builder.cjs +259 -0
  3. package/dist/cli/builder.cjs.map +1 -0
  4. package/dist/cli/builder.d.cts +37 -0
  5. package/dist/cli/builder.d.cts.map +1 -0
  6. package/dist/cli/builder.d.ts +37 -0
  7. package/dist/cli/builder.d.ts.map +1 -0
  8. package/dist/cli/builder.js +255 -0
  9. package/dist/cli/builder.js.map +1 -0
  10. package/dist/cli/commands/baseline.cjs +4 -33
  11. package/dist/cli/commands/baseline.cjs.map +1 -1
  12. package/dist/cli/commands/baseline.d.cts.map +1 -1
  13. package/dist/cli/commands/baseline.d.ts.map +1 -1
  14. package/dist/cli/commands/baseline.js +2 -31
  15. package/dist/cli/commands/baseline.js.map +1 -1
  16. package/dist/cli/commands/history.cjs +2 -14
  17. package/dist/cli/commands/history.cjs.map +1 -1
  18. package/dist/cli/commands/history.d.cts.map +1 -1
  19. package/dist/cli/commands/history.d.ts.map +1 -1
  20. package/dist/cli/commands/history.js +1 -13
  21. package/dist/cli/commands/history.js.map +1 -1
  22. package/dist/cli/context.cjs +60 -0
  23. package/dist/cli/context.cjs.map +1 -0
  24. package/dist/cli/context.d.cts +28 -0
  25. package/dist/cli/context.d.cts.map +1 -0
  26. package/dist/cli/context.d.ts +28 -0
  27. package/dist/cli/context.d.ts.map +1 -0
  28. package/dist/cli/context.js +56 -0
  29. package/dist/cli/context.js.map +1 -0
  30. package/dist/cli/handlers.cjs +74 -0
  31. package/dist/cli/handlers.cjs.map +1 -0
  32. package/dist/cli/handlers.d.cts +13 -0
  33. package/dist/cli/handlers.d.cts.map +1 -0
  34. package/dist/cli/handlers.d.ts +13 -0
  35. package/dist/cli/handlers.d.ts.map +1 -0
  36. package/dist/cli/handlers.js +70 -0
  37. package/dist/cli/handlers.js.map +1 -0
  38. package/dist/cli/index.cjs +12 -724
  39. package/dist/cli/index.cjs.map +1 -1
  40. package/dist/cli/index.d.cts +4 -39
  41. package/dist/cli/index.d.cts.map +1 -1
  42. package/dist/cli/index.d.ts +4 -39
  43. package/dist/cli/index.d.ts.map +1 -1
  44. package/dist/cli/index.js +9 -722
  45. package/dist/cli/index.js.map +1 -1
  46. package/dist/cli/parsers/analyze.cjs +54 -0
  47. package/dist/cli/parsers/analyze.cjs.map +1 -0
  48. package/dist/cli/parsers/analyze.d.cts +37 -0
  49. package/dist/cli/parsers/analyze.d.cts.map +1 -0
  50. package/dist/cli/parsers/analyze.d.ts +37 -0
  51. package/dist/cli/parsers/analyze.d.ts.map +1 -0
  52. package/dist/cli/parsers/analyze.js +51 -0
  53. package/dist/cli/parsers/analyze.js.map +1 -0
  54. package/dist/cli/parsers/baseline.cjs +75 -0
  55. package/dist/cli/parsers/baseline.cjs.map +1 -0
  56. package/dist/cli/parsers/baseline.d.cts +59 -0
  57. package/dist/cli/parsers/baseline.d.cts.map +1 -0
  58. package/dist/cli/parsers/baseline.d.ts +59 -0
  59. package/dist/cli/parsers/baseline.d.ts.map +1 -0
  60. package/dist/cli/parsers/baseline.js +72 -0
  61. package/dist/cli/parsers/baseline.js.map +1 -0
  62. package/dist/cli/parsers/global.cjs +49 -0
  63. package/dist/cli/parsers/global.cjs.map +1 -0
  64. package/dist/cli/parsers/global.d.cts +45 -0
  65. package/dist/cli/parsers/global.d.cts.map +1 -0
  66. package/dist/cli/parsers/global.d.ts +45 -0
  67. package/dist/cli/parsers/global.d.ts.map +1 -0
  68. package/dist/cli/parsers/global.js +46 -0
  69. package/dist/cli/parsers/global.js.map +1 -0
  70. package/dist/cli/parsers/history.cjs +138 -0
  71. package/dist/cli/parsers/history.cjs.map +1 -0
  72. package/dist/cli/parsers/history.d.cts +108 -0
  73. package/dist/cli/parsers/history.d.cts.map +1 -0
  74. package/dist/cli/parsers/history.d.ts +108 -0
  75. package/dist/cli/parsers/history.d.ts.map +1 -0
  76. package/dist/cli/parsers/history.js +135 -0
  77. package/dist/cli/parsers/history.js.map +1 -0
  78. package/dist/cli/parsers/index.cjs +35 -0
  79. package/dist/cli/parsers/index.cjs.map +1 -0
  80. package/dist/cli/parsers/index.d.cts +15 -0
  81. package/dist/cli/parsers/index.d.cts.map +1 -0
  82. package/dist/cli/parsers/index.d.ts +15 -0
  83. package/dist/cli/parsers/index.d.ts.map +1 -0
  84. package/dist/cli/parsers/index.js +15 -0
  85. package/dist/cli/parsers/index.js.map +1 -0
  86. package/dist/cli/parsers/init.cjs +39 -0
  87. package/dist/cli/parsers/init.cjs.map +1 -0
  88. package/dist/cli/parsers/init.d.cts +32 -0
  89. package/dist/cli/parsers/init.d.cts.map +1 -0
  90. package/dist/cli/parsers/init.d.ts +32 -0
  91. package/dist/cli/parsers/init.d.ts.map +1 -0
  92. package/dist/cli/parsers/init.js +36 -0
  93. package/dist/cli/parsers/init.js.map +1 -0
  94. package/dist/cli/parsers/run.cjs +99 -0
  95. package/dist/cli/parsers/run.cjs.map +1 -0
  96. package/dist/cli/parsers/run.d.cts +62 -0
  97. package/dist/cli/parsers/run.d.cts.map +1 -0
  98. package/dist/cli/parsers/run.d.ts +62 -0
  99. package/dist/cli/parsers/run.d.ts.map +1 -0
  100. package/dist/cli/parsers/run.js +96 -0
  101. package/dist/cli/parsers/run.js.map +1 -0
  102. package/dist/cli/parsers/test.cjs +42 -0
  103. package/dist/cli/parsers/test.cjs.map +1 -0
  104. package/dist/cli/parsers/test.d.cts +31 -0
  105. package/dist/cli/parsers/test.d.cts.map +1 -0
  106. package/dist/cli/parsers/test.d.ts +31 -0
  107. package/dist/cli/parsers/test.d.ts.map +1 -0
  108. package/dist/cli/parsers/test.js +39 -0
  109. package/dist/cli/parsers/test.js.map +1 -0
  110. package/dist/cli/theme.cjs +35 -0
  111. package/dist/cli/theme.cjs.map +1 -0
  112. package/dist/cli/theme.d.cts +31 -0
  113. package/dist/cli/theme.d.cts.map +1 -0
  114. package/dist/cli/theme.d.ts +31 -0
  115. package/dist/cli/theme.d.ts.map +1 -0
  116. package/dist/cli/theme.js +32 -0
  117. package/dist/cli/theme.js.map +1 -0
  118. package/dist/errors/base.cjs +3 -12
  119. package/dist/errors/base.cjs.map +1 -1
  120. package/dist/errors/base.d.cts +0 -7
  121. package/dist/errors/base.d.cts.map +1 -1
  122. package/dist/errors/base.d.ts +0 -7
  123. package/dist/errors/base.d.ts.map +1 -1
  124. package/dist/errors/base.js +1 -9
  125. package/dist/errors/base.js.map +1 -1
  126. package/dist/services/profiler/profile-runner.cjs +11 -0
  127. package/dist/services/profiler/profile-runner.cjs.map +1 -1
  128. package/dist/services/profiler/profile-runner.d.cts +2 -0
  129. package/dist/services/profiler/profile-runner.d.cts.map +1 -1
  130. package/dist/services/profiler/profile-runner.d.ts +2 -0
  131. package/dist/services/profiler/profile-runner.d.ts.map +1 -1
  132. package/dist/services/profiler/profile-runner.js +11 -0
  133. package/dist/services/profiler/profile-runner.js.map +1 -1
  134. package/package.json +1 -1
  135. package/src/cli/builder.ts +387 -0
  136. package/src/cli/commands/baseline.ts +7 -33
  137. package/src/cli/commands/history.ts +1 -16
  138. package/src/cli/context.ts +117 -0
  139. package/src/cli/handlers.ts +76 -0
  140. package/src/cli/index.ts +10 -1012
  141. package/src/cli/parsers/analyze.ts +61 -0
  142. package/src/cli/parsers/baseline.ts +92 -0
  143. package/src/cli/parsers/global.ts +51 -0
  144. package/src/cli/parsers/history.ts +168 -0
  145. package/src/cli/parsers/index.ts +28 -0
  146. package/src/cli/parsers/init.ts +45 -0
  147. package/src/cli/parsers/run.ts +118 -0
  148. package/src/cli/parsers/test.ts +46 -0
  149. package/src/cli/theme.ts +33 -0
  150. package/src/errors/base.ts +1 -10
  151. package/src/services/profiler/profile-runner.ts +15 -0
@@ -3,651 +3,29 @@
3
3
  /**
4
4
  * ModestBench CLI Entry Point
5
5
  *
6
- * Command-line interface using bargs for command parsing and routing. Provides
7
- * global options, help generation, and dependency injection setup.
6
+ * Command-line interface using bargs for command parsing and routing. This
7
+ * module provides the main entry points and re-exports key types.
8
8
  *
9
9
  * @packageDocumentation
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.main = exports.cli = void 0;
12
+ exports.main = exports.cli = exports.createCliContext = void 0;
13
13
  const bargs_1 = require("@boneskull/bargs");
14
14
  const node_fs_1 = require("node:fs");
15
15
  const node_url_1 = require("node:url");
16
- const bootstrap_js_1 = require("../bootstrap.cjs");
17
16
  const constants_js_1 = require("../constants.cjs");
18
- const index_js_1 = require("../core/engines/index.cjs");
19
- const base_js_1 = require("../errors/base.cjs");
20
- const index_js_2 = require("../errors/index.cjs");
21
- const index_js_3 = require("../reporters/index.cjs");
22
- // Import commands
23
- const analyze_js_1 = require("./commands/analyze.cjs");
24
- const baseline_js_1 = require("./commands/baseline.cjs");
25
- const history_js_1 = require("./commands/history.cjs");
26
- const init_js_1 = require("./commands/init.cjs");
27
- const run_js_1 = require("./commands/run.cjs");
28
- const test_js_1 = require("./commands/test.cjs");
29
- // ============================================================================
30
- // Global Options Parser
31
- // ============================================================================
32
- const globalOptions = bargs_1.opt.options({
33
- config: bargs_1.opt.string({
34
- aliases: ['c'],
35
- description: 'Path to configuration file',
36
- }),
37
- cwd: bargs_1.opt.string({
38
- description: 'Working directory',
39
- }),
40
- json: bargs_1.opt.boolean({
41
- description: 'Output results in JSON format',
42
- }),
43
- 'no-color': bargs_1.opt.boolean({
44
- description: 'Disable colored output',
45
- }),
46
- progress: bargs_1.opt.boolean({
47
- description: 'Show animated progress bar',
48
- }),
49
- verbose: bargs_1.opt.boolean({
50
- aliases: ['v'],
51
- description: 'Enable verbose output',
52
- }),
53
- });
54
- // ============================================================================
55
- // History Command Parsers
56
- // ============================================================================
57
- const historyListParser = bargs_1.opt.options({
58
- format: bargs_1.opt.enum(['human', 'json', 'csv'], {
59
- description: 'Output format',
60
- }),
61
- limit: bargs_1.opt.number({
62
- description: 'Maximum number of results',
63
- }),
64
- pattern: bargs_1.opt.string({
65
- description: 'Filter by benchmark name pattern',
66
- }),
67
- since: bargs_1.opt.string({
68
- description: 'Show runs since date (ISO 8601 or relative like "1 week ago")',
69
- }),
70
- tag: bargs_1.opt.array('string', {
71
- aliases: ['t'],
72
- description: 'Filter by tags',
73
- }),
74
- until: bargs_1.opt.string({
75
- description: 'Show runs until date (ISO 8601 or relative like "1 day ago")',
76
- }),
77
- });
78
- const historyShowParser = (0, bargs_1.merge)(bargs_1.opt.options({
79
- format: bargs_1.opt.enum(['human', 'json', 'csv'], {
80
- description: 'Output format',
81
- }),
82
- }), bargs_1.pos.positionals(bargs_1.pos.string({
83
- description: 'ID of the benchmark run to show',
84
- name: 'run-id',
85
- required: true,
86
- })));
87
- const historyCompareParser = (0, bargs_1.merge)(bargs_1.opt.options({
88
- format: bargs_1.opt.enum(['human', 'json'], {
89
- description: 'Output format',
90
- }),
91
- }), bargs_1.pos.positionals(bargs_1.pos.string({
92
- description: 'ID of the first benchmark run',
93
- name: 'run-id1',
94
- required: true,
95
- }), bargs_1.pos.string({
96
- description: 'ID of the second benchmark run',
97
- name: 'run-id2',
98
- required: true,
99
- })));
100
- const historyTrendsParser = (0, bargs_1.merge)(bargs_1.opt.options({
101
- all: bargs_1.opt.boolean({
102
- aliases: ['a'],
103
- description: 'Analyze all runs (ignore limit)',
104
- }),
105
- format: bargs_1.opt.enum(['human', 'json'], {
106
- description: 'Output format',
107
- }),
108
- limit: bargs_1.opt.number({
109
- description: 'Maximum number of runs to analyze',
110
- }),
111
- since: bargs_1.opt.string({
112
- description: 'Show trends since date (ISO 8601 or relative like "1 week ago")',
113
- }),
114
- tag: bargs_1.opt.array('string', {
115
- aliases: ['t'],
116
- description: 'Filter by tags',
117
- }),
118
- until: bargs_1.opt.string({
119
- description: 'Show trends until date (ISO 8601 or relative like "1 day ago")',
120
- }),
121
- }), bargs_1.pos.positionals(bargs_1.pos.string({
122
- description: 'Filter by benchmark name pattern',
123
- name: 'pattern',
124
- })));
125
- const historyCleanParser = (0, bargs_1.map)(bargs_1.opt.options({
126
- 'max-age': bargs_1.opt.number({
127
- description: 'Remove runs older than this many days',
128
- }),
129
- 'max-runs': bargs_1.opt.number({
130
- description: 'Keep only this many most recent runs',
131
- }),
132
- 'max-size': bargs_1.opt.number({
133
- description: 'Keep history under this size in bytes',
134
- }),
135
- yes: bargs_1.opt.boolean({
136
- aliases: ['y'],
137
- description: 'Confirm cleanup without prompting',
138
- }),
139
- }), ({ positionals, values }) => {
140
- if (!values['max-age'] && !values['max-runs'] && !values['max-size']) {
141
- throw new Error('At least one cleanup criterion must be specified (--max-age, --max-runs, or --max-size)');
142
- }
143
- return { positionals, values };
144
- });
145
- const historyExportParser = bargs_1.opt.options({
146
- format: bargs_1.opt.enum(['json', 'csv'], {
147
- description: 'Export format',
148
- }),
149
- output: bargs_1.opt.string({
150
- aliases: ['o'],
151
- description: 'Output file path',
152
- required: true,
153
- }),
154
- since: bargs_1.opt.string({
155
- description: 'Export runs since date',
156
- }),
157
- until: bargs_1.opt.string({
158
- description: 'Export runs until date',
159
- }),
160
- });
161
- // ============================================================================
162
- // Baseline Command Parsers
163
- // ============================================================================
164
- const baselineSetParser = (0, bargs_1.merge)(bargs_1.opt.options({
165
- branch: bargs_1.opt.string({
166
- description: 'Git branch name',
167
- }),
168
- commit: bargs_1.opt.string({
169
- description: 'Git commit SHA (40 characters)',
170
- }),
171
- default: bargs_1.opt.boolean({
172
- description: 'Set as default baseline',
173
- }),
174
- 'run-id': bargs_1.opt.string({
175
- description: 'Specific run ID to save (default: most recent)',
176
- }),
177
- }), bargs_1.pos.positionals(bargs_1.pos.string({
178
- description: 'Name for the baseline',
179
- name: 'name',
180
- required: true,
181
- })));
182
- const baselineListParser = bargs_1.opt.options({
183
- format: bargs_1.opt.enum(['human', 'json'], {
184
- description: 'Output format',
185
- }),
186
- });
187
- const baselineShowParser = (0, bargs_1.merge)(bargs_1.opt.options({
188
- format: bargs_1.opt.enum(['human', 'json'], {
189
- description: 'Output format',
190
- }),
191
- }), bargs_1.pos.positionals(bargs_1.pos.string({
192
- description: 'Baseline name to show',
193
- name: 'name',
194
- required: true,
195
- })));
196
- const baselineDeleteParser = bargs_1.pos.positionals(bargs_1.pos.string({
197
- description: 'Baseline name to delete',
198
- name: 'name',
199
- required: true,
200
- }));
201
- const baselineAnalyzeParser = bargs_1.opt.options({
202
- confidence: bargs_1.opt.number({
203
- description: 'Confidence level (0.5-0.999, default 0.95)',
204
- }),
205
- runs: bargs_1.opt.number({
206
- description: 'Number of recent runs to analyze',
207
- }),
208
- });
209
- // ============================================================================
210
- // Run Command Parser
211
- // ============================================================================
212
- const runParserBase = (0, bargs_1.merge)(bargs_1.opt.options({
213
- bail: bargs_1.opt.boolean({
214
- aliases: ['b'],
215
- description: 'Stop on first failure',
216
- }),
217
- engine: bargs_1.opt.enum([constants_js_1.Engines.TINYBENCH, constants_js_1.Engines.ACCURATE], {
218
- aliases: ['e'],
219
- description: 'Benchmark engine: tinybench (default) or accurate (requires --allow-natives-syntax)',
220
- }),
221
- exclude: bargs_1.opt.array('string', {
222
- aliases: ['X'],
223
- description: 'Exclude patterns',
224
- }),
225
- 'exclude-tag': bargs_1.opt.array('string', {
226
- aliases: ['T'],
227
- description: 'Exclude benchmarks with any of these tags',
228
- }),
229
- iterations: bargs_1.opt.number({
230
- aliases: ['i'],
231
- description: 'Number of iterations per benchmark',
232
- }),
233
- 'json-pretty': bargs_1.opt.boolean({
234
- description: 'Pretty-print JSON output (only affects json reporter)',
235
- }),
236
- 'limit-by': bargs_1.opt.enum(['time', 'iterations', 'any', 'all'], {
237
- aliases: ['l', 'limit'],
238
- description: 'How to limit benchmarks: time (time budget), iterations (sample count), any (either threshold), all (both thresholds)',
239
- }),
240
- output: bargs_1.opt.string({
241
- aliases: ['o'],
242
- description: 'Output directory for reports',
243
- }),
244
- 'output-file': bargs_1.opt.string({
245
- aliases: ['of', 'file'],
246
- description: 'Custom filename for reporter output (use with single reporter only)',
247
- }),
248
- quiet: bargs_1.opt.boolean({
249
- aliases: ['q'],
250
- description: 'Minimal output',
251
- }),
252
- reporter: bargs_1.opt.array([
253
- constants_js_1.Reporters.HUMAN,
254
- constants_js_1.Reporters.JSON,
255
- constants_js_1.Reporters.CSV,
256
- constants_js_1.Reporters.NYAN,
257
- constants_js_1.Reporters.SIMPLE,
258
- ], {
259
- aliases: ['r'],
260
- default: [constants_js_1.DEFAULT_REPORTER],
261
- description: 'Output reporters to use (human,json,csv)',
262
- }),
263
- tag: bargs_1.opt.array('string', {
264
- description: 'Include only benchmarks with any of these tags',
265
- }),
266
- time: bargs_1.opt.number({
267
- aliases: ['t'],
268
- description: 'Time budget per benchmark in milliseconds',
269
- }),
270
- timeout: bargs_1.opt.number({
271
- description: 'Timeout per benchmark in milliseconds',
272
- }),
273
- warmup: bargs_1.opt.number({
274
- aliases: ['w', 'warm'],
275
- description: 'Number of warmup iterations',
276
- }),
277
- }), bargs_1.pos.positionals(bargs_1.pos.variadic('string', {
278
- description: 'File paths, directory paths, or glob patterns for benchmark files',
279
- name: 'pattern',
280
- })));
281
- // Add validation via map()
282
- const runParser = (0, bargs_1.map)(runParserBase, ({ positionals, values }) => {
283
- if (values.reporter && values.reporter.length > 1 && values['output-file']) {
284
- throw new Error('--output-file can only be used with a single reporter. Use --output <dir> for multiple reporters.');
285
- }
286
- return { positionals, values };
287
- });
288
- // ============================================================================
289
- // Init Command Parser
290
- // ============================================================================
291
- const initParser = (0, bargs_1.merge)(bargs_1.opt.options({
292
- 'config-type': bargs_1.opt.enum(['json', 'yaml', 'js', 'ts'], {
293
- description: 'Configuration file format',
294
- }),
295
- examples: bargs_1.opt.boolean({
296
- description: 'Include example benchmark files',
297
- }),
298
- force: bargs_1.opt.boolean({
299
- description: 'Overwrite existing files',
300
- }),
301
- quiet: bargs_1.opt.boolean({
302
- aliases: ['q'],
303
- description: 'Minimal output',
304
- }),
305
- yes: bargs_1.opt.boolean({
306
- aliases: ['y'],
307
- description: 'Accept all prompts automatically',
308
- }),
309
- }), bargs_1.pos.positionals(bargs_1.pos.enum(['basic', 'advanced', 'library'], {
310
- description: 'Type of project to initialize',
311
- name: 'type',
312
- })));
313
- // ============================================================================
314
- // Analyze Command Parser
315
- // ============================================================================
316
- const analyzeParserBase = (0, bargs_1.merge)(bargs_1.opt.options({
317
- 'filter-file': bargs_1.opt.string({
318
- description: 'Filter functions by file glob pattern',
319
- }),
320
- 'group-by-file': bargs_1.opt.boolean({
321
- description: 'Group results by file',
322
- }),
323
- input: bargs_1.opt.string({
324
- aliases: ['i'],
325
- description: 'Path to existing *.cpuprofile file',
326
- }),
327
- 'min-percent': bargs_1.opt.number({
328
- aliases: ['m', 'min'],
329
- default: 0.5,
330
- description: 'Minimum execution percentage to show',
331
- }),
332
- top: bargs_1.opt.number({
333
- aliases: ['n'],
334
- default: 25,
335
- description: 'Number of top functions to show',
336
- }),
337
- }), bargs_1.pos.positionals(bargs_1.pos.string({
338
- description: 'Command to analyze (e.g., "npm test")',
339
- name: 'command',
340
- })));
341
- // Add validation
342
- const analyzeParser = (0, bargs_1.map)(analyzeParserBase, ({ positionals, values }) => {
343
- const [command] = positionals;
344
- if (!command && !values.input) {
345
- throw new Error('Either [command] or --input must be provided');
346
- }
347
- return { positionals, values };
348
- });
349
- // ============================================================================
350
- // Test Command Parser
351
- // ============================================================================
352
- const testParser = (0, bargs_1.merge)(bargs_1.opt.options({
353
- bail: bargs_1.opt.boolean({
354
- aliases: ['b'],
355
- description: 'Stop on first failure',
356
- }),
357
- iterations: bargs_1.opt.number({
358
- aliases: ['i'],
359
- default: 100,
360
- description: 'Number of iterations per test',
361
- }),
362
- quiet: bargs_1.opt.boolean({
363
- aliases: ['q'],
364
- description: 'Minimal output',
365
- }),
366
- warmup: bargs_1.opt.number({
367
- aliases: ['w'],
368
- default: 5,
369
- description: 'Number of warmup iterations',
370
- }),
371
- }), bargs_1.pos.positionals(bargs_1.pos.enum(['ava', 'jest', 'mocha', 'node-test'], {
372
- description: 'Test framework to use',
373
- name: 'framework',
374
- required: true,
375
- }), bargs_1.pos.variadic('string', {
376
- description: 'Test file paths or glob patterns',
377
- name: 'files',
378
- })));
379
- // ============================================================================
380
- // Subcommand-specific options
381
- // ============================================================================
382
- /**
383
- * Additional global options for history and baseline subcommands
384
- */
385
- const quietOption = bargs_1.opt.options({
386
- quiet: bargs_1.opt.boolean({
387
- description: 'Minimal output',
388
- }),
389
- });
390
- // ============================================================================
391
- // Main CLI Builder
392
- // ============================================================================
393
- /**
394
- * Synthwave-inspired theme for CLI help output
395
- *
396
- * Matches the retro aesthetic used in modestbench reporters
397
- */
398
- const synthwaveTheme = {
399
- colors: {
400
- command: bargs_1.ansi.brightMagenta,
401
- defaultText: bargs_1.ansi.dim,
402
- defaultValue: bargs_1.ansi.brightYellow,
403
- description: bargs_1.ansi.brightWhite,
404
- epilog: bargs_1.ansi.brightWhite,
405
- example: bargs_1.ansi.cyan,
406
- flag: bargs_1.ansi.brightCyan,
407
- positional: bargs_1.ansi.brightMagenta,
408
- scriptName: bargs_1.ansi.brightCyan + bargs_1.ansi.bold,
409
- sectionHeader: bargs_1.ansi.magenta + bargs_1.ansi.bold,
410
- type: bargs_1.ansi.brightWhite + bargs_1.ansi.dim,
411
- url: bargs_1.ansi.brightCyan + bargs_1.ansi.underline,
412
- usage: bargs_1.ansi.white,
413
- },
414
- };
415
- const createCli = (abortController) => {
416
- return (0, bargs_1.bargs)('modestbench', {
417
- description: 'A modern benchmark runner for Node.js',
418
- theme: synthwaveTheme,
419
- })
420
- .globals(globalOptions)
421
- .command('run', runParser, async ({ positionals, values }) => {
422
- const [pattern] = positionals;
423
- const context = await createCliContext(values, abortController, values.engine);
424
- const exitCode = await (0, run_js_1.handleRunCommand)(context, {
425
- bail: values.bail,
426
- config: values.config,
427
- cwd: values.cwd,
428
- engine: values.engine,
429
- exclude: values.exclude,
430
- excludeTags: values['exclude-tag'],
431
- iterations: values.iterations,
432
- json: values.json,
433
- jsonPretty: values['json-pretty'],
434
- noColor: values['no-color'],
435
- outputDir: values.output,
436
- outputFile: values['output-file'],
437
- pattern,
438
- progress: values.progress,
439
- quiet: values.quiet,
440
- reporters: values.reporter,
441
- tags: values.tag,
442
- time: values.time,
443
- timeout: values.timeout,
444
- verbose: values.verbose,
445
- warmup: values.warmup,
446
- });
447
- process.exit(exitCode);
448
- }, 'Run benchmark files')
449
- .command('history', (history) => history
450
- .globals(quietOption)
451
- .command('list', historyListParser, async ({ values }) => {
452
- const context = await createCliContext(values, abortController);
453
- const exitCode = await (0, history_js_1.handleListCommand)(context, {
454
- cwd: values.cwd,
455
- format: values.format,
456
- limit: values.limit,
457
- pattern: values.pattern,
458
- since: values.since,
459
- tags: values.tag,
460
- until: values.until,
461
- verbose: values.verbose,
462
- });
463
- process.exit(exitCode);
464
- }, 'List recent benchmark runs')
465
- .command('show', historyShowParser, async ({ positionals, values }) => {
466
- const [runId] = positionals;
467
- const context = await createCliContext(values, abortController);
468
- const exitCode = await (0, history_js_1.handleShowCommand)(context, {
469
- cwd: values.cwd,
470
- format: values.format,
471
- runId,
472
- verbose: values.verbose,
473
- });
474
- process.exit(exitCode);
475
- }, 'Show detailed results for a specific run')
476
- .command('compare', historyCompareParser, async ({ positionals, values }) => {
477
- const [runId1, runId2] = positionals;
478
- const context = await createCliContext(values, abortController);
479
- const exitCode = await (0, history_js_1.handleCompareCommand)(context, {
480
- cwd: values.cwd,
481
- format: values.format,
482
- runId1,
483
- runId2,
484
- verbose: values.verbose,
485
- });
486
- process.exit(exitCode);
487
- }, 'Compare two benchmark runs')
488
- .command('trends', historyTrendsParser, async ({ positionals, values }) => {
489
- const [pattern] = positionals;
490
- const context = await createCliContext(values, abortController);
491
- const exitCode = await (0, history_js_1.handleTrendsCommand)(context, {
492
- all: values.all,
493
- cwd: values.cwd,
494
- format: values.format,
495
- limit: values.limit,
496
- pattern,
497
- since: values.since,
498
- tags: values.tag,
499
- until: values.until,
500
- verbose: values.verbose,
501
- });
502
- process.exit(exitCode);
503
- }, 'Show performance trends over time')
504
- .command('clean', historyCleanParser, async ({ values }) => {
505
- const context = await createCliContext(values, abortController);
506
- const exitCode = await (0, history_js_1.handleCleanCommand)(context, {
507
- confirm: values.yes,
508
- cwd: values.cwd,
509
- maxAge: values['max-age'],
510
- maxRuns: values['max-runs'],
511
- maxSize: values['max-size'],
512
- quiet: values.quiet,
513
- verbose: values.verbose,
514
- });
515
- process.exit(exitCode);
516
- }, 'Clean up old benchmark history')
517
- .command('export', historyExportParser, async ({ values }) => {
518
- const context = await createCliContext(values, abortController);
519
- const exitCode = await (0, history_js_1.handleExportCommand)(context, {
520
- cwd: values.cwd,
521
- format: values.format,
522
- outputPath: values.output,
523
- quiet: Boolean(values.quiet),
524
- since: values.since,
525
- until: values.until,
526
- verbose: values.verbose,
527
- });
528
- process.exitCode = exitCode;
529
- }, 'Export benchmark history to a file'), 'View and manage benchmark history')
530
- .command('baseline', (baseline) => baseline
531
- .globals(quietOption)
532
- .command('set', baselineSetParser, async ({ positionals, values }) => {
533
- const [name] = positionals;
534
- const context = await createCliContext(values, abortController);
535
- const exitCode = await (0, baseline_js_1.handleSetCommand)(context, {
536
- branch: values.branch,
537
- commit: values.commit,
538
- cwd: values.cwd,
539
- default: values.default,
540
- name,
541
- quiet: Boolean(values.quiet),
542
- runId: values['run-id'],
543
- verbose: values.verbose,
544
- });
545
- process.exit(exitCode);
546
- }, 'Save a benchmark run as a baseline')
547
- .command('list', baselineListParser, async ({ values }) => {
548
- const context = await createCliContext(values, abortController);
549
- const exitCode = await (0, baseline_js_1.handleListCommand)(context, {
550
- cwd: values.cwd,
551
- format: values.format,
552
- quiet: Boolean(values.quiet),
553
- verbose: values.verbose,
554
- });
555
- process.exit(exitCode);
556
- }, 'List all saved baselines')
557
- .command('show', baselineShowParser, async ({ positionals, values }) => {
558
- const [name] = positionals;
559
- const context = await createCliContext(values, abortController);
560
- const exitCode = await (0, baseline_js_1.handleShowCommand)(context, {
561
- cwd: values.cwd,
562
- format: values.format,
563
- name,
564
- quiet: Boolean(values.quiet),
565
- verbose: values.verbose,
566
- });
567
- process.exit(exitCode);
568
- }, 'Show baseline details')
569
- .command('delete', baselineDeleteParser, async ({ positionals, values }) => {
570
- const [name] = positionals;
571
- const context = await createCliContext(values, abortController);
572
- const exitCode = await (0, baseline_js_1.handleDeleteCommand)(context, {
573
- cwd: values.cwd,
574
- name,
575
- quiet: Boolean(values.quiet),
576
- verbose: values.verbose,
577
- });
578
- process.exit(exitCode);
579
- }, 'Delete a baseline')
580
- .command('analyze', baselineAnalyzeParser, async ({ values }) => {
581
- const context = await createCliContext(values, abortController);
582
- const exitCode = await (0, baseline_js_1.handleAnalyzeCommand)(context, {
583
- confidence: values.confidence,
584
- cwd: values.cwd,
585
- quiet: Boolean(values.quiet),
586
- runs: values.runs,
587
- verbose: values.verbose,
588
- });
589
- process.exit(exitCode);
590
- }, 'Analyze history and suggest performance budgets'), 'Manage performance baselines')
591
- .command('init', initParser, async ({ positionals, values }) => {
592
- const [type] = positionals;
593
- const context = await createCliContext(values, abortController);
594
- const exitCode = await (0, init_js_1.handleInitCommand)(context, {
595
- configType: values['config-type'],
596
- cwd: values.cwd,
597
- examples: values.examples,
598
- force: values.force,
599
- quiet: values.quiet,
600
- type,
601
- verbose: values.verbose,
602
- yes: values.yes,
603
- });
604
- process.exitCode = exitCode;
605
- }, 'Initialize a new benchmark project')
606
- .command('analyze', analyzeParser, async ({ positionals, values }) => {
607
- const [command] = positionals;
608
- // Context not needed for analyze command currently
609
- const context = {};
610
- const options = {
611
- color: !values['no-color'],
612
- command,
613
- cwd: values.cwd || process.cwd(),
614
- filterFile: values['filter-file'],
615
- groupByFile: values['group-by-file'],
616
- input: values.input,
617
- minPercent: values['min-percent'],
618
- top: values.top,
619
- };
620
- process.exitCode = await (0, analyze_js_1.handleAnalyzeCommand)(context, options);
621
- }, {
622
- aliases: ['profile'],
623
- description: 'Analyze code execution and identify benchmark candidates',
624
- })
625
- .command('test', testParser, async ({ positionals, values }) => {
626
- const [framework, files] = positionals;
627
- const context = await createCliContext(values, abortController);
628
- const options = {
629
- bail: values.bail,
630
- cwd: values.cwd,
631
- framework,
632
- iterations: values.iterations,
633
- json: values.json,
634
- noColor: values['no-color'],
635
- pattern: files,
636
- quiet: values.quiet,
637
- verbose: values.verbose,
638
- warmup: values.warmup,
639
- };
640
- const exitCode = await (0, test_js_1.handleTestCommand)(context, options);
641
- process.exit(exitCode);
642
- }, 'Run test files as benchmarks')
643
- .defaultCommand('run');
644
- };
17
+ const index_js_1 = require("../errors/index.cjs");
18
+ const builder_js_1 = require("./builder.cjs");
19
+ const handlers_js_1 = require("./handlers.cjs");
20
+ // Re-export types and utilities for external use
21
+ var context_js_1 = require("./context.cjs");
22
+ Object.defineProperty(exports, "createCliContext", { enumerable: true, get: function () { return context_js_1.createCliContext; } });
645
23
  /**
646
24
  * Initialize and run the CLI
647
25
  */
648
26
  const cli = (argv) => {
649
27
  const abortController = new AbortController();
650
- setupSignalHandlers(abortController);
28
+ (0, handlers_js_1.setupSignalHandlers)(abortController);
651
29
  (0, exports.main)(argv, abortController).catch((error) => {
652
30
  console.error('CLI error:', error);
653
31
  process.exit(constants_js_1.ExitCodes.UNKNOWN_ERROR);
@@ -660,7 +38,7 @@ exports.cli = cli;
660
38
  const main = async (argv, abortController) => {
661
39
  const controller = abortController ?? new AbortController();
662
40
  try {
663
- const cliBuilder = createCli(controller);
41
+ const cliBuilder = (0, builder_js_1.createCli)(controller);
664
42
  await cliBuilder.parseAsync(argv);
665
43
  }
666
44
  catch (error) {
@@ -681,7 +59,7 @@ const main = async (argv, abortController) => {
681
59
  process.exit(constants_js_1.ExitCodes.CONFIG_ERROR);
682
60
  }
683
61
  // Handle ModestBench errors
684
- if ((0, index_js_2.isModestBenchError)(error)) {
62
+ if ((0, index_js_1.isModestBenchError)(error)) {
685
63
  console.error('Error:', error.message);
686
64
  if (process.env.DEBUG) {
687
65
  console.error(error.stack);
@@ -701,87 +79,6 @@ const main = async (argv, abortController) => {
701
79
  }
702
80
  };
703
81
  exports.main = main;
704
- /**
705
- * Create CLI context with dependency injection
706
- */
707
- const createCliContext = async (options, abortController, engineType = constants_js_1.DEFAULT_ENGINE) => {
708
- try {
709
- const dependencies = (0, bootstrap_js_1.bootstrap)();
710
- // Select engine based on type
711
- const engine = engineType === constants_js_1.Engines.ACCURATE
712
- ? new index_js_1.AccurateEngine(dependencies)
713
- : new index_js_1.TinybenchEngine(dependencies);
714
- // Register built-in reporters
715
- engine.registerReporter(constants_js_1.Reporters.HUMAN, new index_js_3.HumanReporter({
716
- color: !options['no-color'],
717
- verbose: options.verbose,
718
- }));
719
- engine.registerReporter('json', new index_js_3.JsonReporter({
720
- prettyPrint: false,
721
- }));
722
- engine.registerReporter('csv', new index_js_3.CsvReporter({
723
- includeHeaders: true,
724
- includeMetadata: true,
725
- }));
726
- engine.registerReporter('simple', new index_js_3.SimpleReporter({
727
- verbose: options.verbose,
728
- }));
729
- engine.registerReporter('nyan', new index_js_3.NyanReporter({
730
- color: !options['no-color'],
731
- }));
732
- return {
733
- abortController,
734
- configManager: engine.configManager,
735
- engine,
736
- historyStorage: engine.historyStorage,
737
- options,
738
- progressManager: engine.progressManager,
739
- reporterRegistry: engine.reporterRegistry,
740
- };
741
- }
742
- catch (error) {
743
- console.error('Failed to initialize ModestBench:', error instanceof Error ? error.message : String(error));
744
- process.exit(constants_js_1.ExitCodes.CONFIG_ERROR);
745
- }
746
- };
747
- /**
748
- * Handle process signals gracefully
749
- */
750
- const setupSignalHandlers = (abortController) => {
751
- let abortRequested = false;
752
- const handleSignal = (signal) => {
753
- if (abortRequested) {
754
- // Second signal, force exit
755
- console.log(`\nReceived ${signal} again, forcing exit...`);
756
- process.exit(computeExitCode(signal));
757
- }
758
- console.log(`\nReceived ${signal}, aborting benchmarks...`);
759
- abortRequested = true;
760
- abortController.abort();
761
- // Give a short grace period for cleanup, then exit
762
- setTimeout(() => {
763
- console.log('\nBenchmark aborted.');
764
- process.exit(computeExitCode(signal));
765
- }, constants_js_1.ABORT_TIMEOUT);
766
- };
767
- process
768
- .once('SIGINT', handleSignal)
769
- .once('SIGQUIT', handleSignal)
770
- .once('SIGTERM', handleSignal)
771
- .once('uncaughtException', (error) => {
772
- // Wrap non-ModestBench errors with UnknownError
773
- const wrappedError = (0, index_js_2.isModestBenchError)(error)
774
- ? error
775
- : new index_js_2.UnknownError(error.message, { cause: error });
776
- console.error(`${wrappedError}`);
777
- process.exit(constants_js_1.ExitCodes.RUNTIME_ERROR);
778
- })
779
- .once('unhandledRejection', (reason) => {
780
- const wrappedError = new index_js_2.UnknownError((0, base_js_1.isError)(reason) ? reason.message : String(reason), { cause: reason });
781
- console.error(`${wrappedError}`);
782
- process.exit(constants_js_1.ExitCodes.RUNTIME_ERROR);
783
- });
784
- };
785
82
  // Run CLI if this file is executed directly
786
83
  const scriptPath = (0, node_url_1.fileURLToPath)(require("url").pathToFileURL(__filename));
787
84
  const argPath = process.argv[1];
@@ -799,13 +96,4 @@ catch {
799
96
  (0, exports.cli)();
800
97
  }
801
98
  }
802
- /**
803
- * Compute the exit code based on the signal
804
- *
805
- * @param signal - The signal that caused the exit
806
- * @returns The exit code
807
- */
808
- const computeExitCode = (signal) => {
809
- return 128 + (signal === 'SIGINT' ? 2 : signal === 'SIGQUIT' ? 3 : 15);
810
- };
811
99
  //# sourceMappingURL=index.js.map