modestbench 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +131 -34
- package/dist/cli/commands/analyze.cjs +60 -0
- package/dist/cli/commands/analyze.cjs.map +1 -0
- package/dist/cli/commands/analyze.d.cts +35 -0
- package/dist/cli/commands/analyze.d.cts.map +1 -0
- package/dist/cli/commands/analyze.d.ts +35 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -0
- package/dist/cli/commands/analyze.js +56 -0
- package/dist/cli/commands/analyze.js.map +1 -0
- package/dist/cli/commands/baseline.cjs +404 -0
- package/dist/cli/commands/baseline.cjs.map +1 -0
- package/dist/cli/commands/baseline.d.cts +72 -0
- package/dist/cli/commands/baseline.d.cts.map +1 -0
- package/dist/cli/commands/baseline.d.ts +72 -0
- package/dist/cli/commands/baseline.d.ts.map +1 -0
- package/dist/cli/commands/baseline.js +396 -0
- package/dist/cli/commands/baseline.js.map +1 -0
- package/dist/cli/commands/history.d.cts +1 -1
- package/dist/cli/commands/history.d.cts.map +1 -1
- package/dist/cli/commands/history.d.ts +1 -1
- package/dist/cli/commands/history.d.ts.map +1 -1
- package/dist/cli/commands/init.cjs +88 -155
- package/dist/cli/commands/init.cjs.map +1 -1
- package/dist/cli/commands/init.d.cts +4 -4
- package/dist/cli/commands/init.d.cts.map +1 -1
- package/dist/cli/commands/init.d.ts +4 -4
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +88 -155
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/run.cjs +132 -114
- package/dist/cli/commands/run.cjs.map +1 -1
- package/dist/cli/commands/run.d.cts +16 -3
- package/dist/cli/commands/run.d.cts.map +1 -1
- package/dist/cli/commands/run.d.ts +16 -3
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +131 -80
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/index.cjs +583 -394
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +4 -16
- package/dist/cli/index.d.cts.map +1 -1
- package/dist/cli/index.d.ts +4 -16
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +575 -386
- package/dist/cli/index.js.map +1 -1
- package/dist/config/budget-schema.cjs +172 -0
- package/dist/config/budget-schema.cjs.map +1 -0
- package/dist/config/budget-schema.d.cts +59 -0
- package/dist/config/budget-schema.d.cts.map +1 -0
- package/dist/config/budget-schema.d.ts +59 -0
- package/dist/config/budget-schema.d.ts.map +1 -0
- package/dist/config/budget-schema.js +166 -0
- package/dist/config/budget-schema.js.map +1 -0
- package/dist/config/schema.cjs +182 -2
- package/dist/config/schema.cjs.map +1 -1
- package/dist/config/schema.d.cts +122 -3
- package/dist/config/schema.d.cts.map +1 -1
- package/dist/config/schema.d.ts +122 -3
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +180 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/constants.cjs +45 -2
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +41 -0
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.ts +41 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +44 -1
- package/dist/constants.js.map +1 -1
- package/dist/core/engine.cjs +103 -21
- package/dist/core/engine.cjs.map +1 -1
- package/dist/core/engine.d.cts +7 -7
- package/dist/core/engine.d.cts.map +1 -1
- package/dist/core/engine.d.ts +7 -7
- package/dist/core/engine.d.ts.map +1 -1
- package/dist/core/engine.js +104 -22
- package/dist/core/engine.js.map +1 -1
- package/dist/core/output-path-resolver.cjs +8 -1
- package/dist/core/output-path-resolver.cjs.map +1 -1
- package/dist/core/output-path-resolver.d.cts.map +1 -1
- package/dist/core/output-path-resolver.d.ts.map +1 -1
- package/dist/core/output-path-resolver.js +9 -2
- package/dist/core/output-path-resolver.js.map +1 -1
- package/dist/errors/base.cjs +12 -3
- package/dist/errors/base.cjs.map +1 -1
- package/dist/errors/base.d.cts +7 -0
- package/dist/errors/base.d.cts.map +1 -1
- package/dist/errors/base.d.ts +7 -0
- package/dist/errors/base.d.ts.map +1 -1
- package/dist/errors/base.js +10 -2
- package/dist/errors/base.js.map +1 -1
- package/dist/errors/budget.cjs +37 -0
- package/dist/errors/budget.cjs.map +1 -0
- package/dist/errors/budget.d.cts +31 -0
- package/dist/errors/budget.d.cts.map +1 -0
- package/dist/errors/budget.d.ts +31 -0
- package/dist/errors/budget.d.ts.map +1 -0
- package/dist/errors/budget.js +33 -0
- package/dist/errors/budget.js.map +1 -0
- package/dist/errors/index.cjs +4 -1
- package/dist/errors/index.cjs.map +1 -1
- package/dist/errors/index.d.cts +1 -0
- package/dist/errors/index.d.cts.map +1 -1
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -1
- package/dist/index.cjs +13 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/reporters/csv.cjs +37 -17
- package/dist/reporters/csv.cjs.map +1 -1
- package/dist/reporters/csv.d.cts +3 -6
- package/dist/reporters/csv.d.cts.map +1 -1
- package/dist/reporters/csv.d.ts +3 -6
- package/dist/reporters/csv.d.ts.map +1 -1
- package/dist/reporters/csv.js +37 -17
- package/dist/reporters/csv.js.map +1 -1
- package/dist/reporters/human.cjs +66 -40
- package/dist/reporters/human.cjs.map +1 -1
- package/dist/reporters/human.d.cts +14 -13
- package/dist/reporters/human.d.cts.map +1 -1
- package/dist/reporters/human.d.ts +14 -13
- package/dist/reporters/human.d.ts.map +1 -1
- package/dist/reporters/human.js +66 -40
- package/dist/reporters/human.js.map +1 -1
- package/dist/reporters/json.cjs +23 -48
- package/dist/reporters/json.cjs.map +1 -1
- package/dist/reporters/json.d.cts +2 -28
- package/dist/reporters/json.d.cts.map +1 -1
- package/dist/reporters/json.d.ts +2 -28
- package/dist/reporters/json.d.ts.map +1 -1
- package/dist/reporters/json.js +25 -50
- package/dist/reporters/json.js.map +1 -1
- package/dist/reporters/profile-human.cjs +149 -0
- package/dist/reporters/profile-human.cjs.map +1 -0
- package/dist/reporters/profile-human.d.cts +44 -0
- package/dist/reporters/profile-human.d.cts.map +1 -0
- package/dist/reporters/profile-human.d.ts +44 -0
- package/dist/reporters/profile-human.d.ts.map +1 -0
- package/dist/reporters/profile-human.js +142 -0
- package/dist/reporters/profile-human.js.map +1 -0
- package/dist/reporters/simple.cjs +64 -44
- package/dist/reporters/simple.cjs.map +1 -1
- package/dist/reporters/simple.d.cts +14 -14
- package/dist/reporters/simple.d.cts.map +1 -1
- package/dist/reporters/simple.d.ts +14 -14
- package/dist/reporters/simple.d.ts.map +1 -1
- package/dist/reporters/simple.js +64 -44
- package/dist/reporters/simple.js.map +1 -1
- package/dist/schema/modestbench-config.schema.json +153 -0
- package/dist/services/baseline-storage.cjs +151 -0
- package/dist/services/baseline-storage.cjs.map +1 -0
- package/dist/services/baseline-storage.d.cts +55 -0
- package/dist/services/baseline-storage.d.cts.map +1 -0
- package/dist/services/baseline-storage.d.ts +55 -0
- package/dist/services/baseline-storage.d.ts.map +1 -0
- package/dist/services/baseline-storage.js +147 -0
- package/dist/services/baseline-storage.js.map +1 -0
- package/dist/services/budget-evaluator.cjs +146 -0
- package/dist/services/budget-evaluator.cjs.map +1 -0
- package/dist/services/budget-evaluator.d.cts +29 -0
- package/dist/services/budget-evaluator.d.cts.map +1 -0
- package/dist/services/budget-evaluator.d.ts +29 -0
- package/dist/services/budget-evaluator.d.ts.map +1 -0
- package/dist/services/budget-evaluator.js +142 -0
- package/dist/services/budget-evaluator.js.map +1 -0
- package/dist/services/config-manager.cjs +23 -9
- package/dist/services/config-manager.cjs.map +1 -1
- package/dist/services/config-manager.d.cts +6 -1
- package/dist/services/config-manager.d.cts.map +1 -1
- package/dist/services/config-manager.d.ts +6 -1
- package/dist/services/config-manager.d.ts.map +1 -1
- package/dist/services/config-manager.js +23 -9
- package/dist/services/config-manager.js.map +1 -1
- package/dist/services/file-loader.cjs +3 -6
- package/dist/services/file-loader.cjs.map +1 -1
- package/dist/services/file-loader.d.cts.map +1 -1
- package/dist/services/file-loader.d.ts.map +1 -1
- package/dist/services/file-loader.js +3 -6
- package/dist/services/file-loader.js.map +1 -1
- package/dist/services/profiler/profile-filter.cjs +113 -0
- package/dist/services/profiler/profile-filter.cjs.map +1 -0
- package/dist/services/profiler/profile-filter.d.cts +20 -0
- package/dist/services/profiler/profile-filter.d.cts.map +1 -0
- package/dist/services/profiler/profile-filter.d.ts +20 -0
- package/dist/services/profiler/profile-filter.d.ts.map +1 -0
- package/dist/services/profiler/profile-filter.js +109 -0
- package/dist/services/profiler/profile-filter.js.map +1 -0
- package/dist/services/profiler/profile-parser.cjs +139 -0
- package/dist/services/profiler/profile-parser.cjs.map +1 -0
- package/dist/services/profiler/profile-parser.d.cts +18 -0
- package/dist/services/profiler/profile-parser.d.cts.map +1 -0
- package/dist/services/profiler/profile-parser.d.ts +18 -0
- package/dist/services/profiler/profile-parser.d.ts.map +1 -0
- package/dist/services/profiler/profile-parser.js +132 -0
- package/dist/services/profiler/profile-parser.js.map +1 -0
- package/dist/services/profiler/profile-runner.cjs +90 -0
- package/dist/services/profiler/profile-runner.cjs.map +1 -0
- package/dist/services/profiler/profile-runner.d.cts +29 -0
- package/dist/services/profiler/profile-runner.d.cts.map +1 -0
- package/dist/services/profiler/profile-runner.d.ts +29 -0
- package/dist/services/profiler/profile-runner.d.ts.map +1 -0
- package/dist/services/profiler/profile-runner.js +86 -0
- package/dist/services/profiler/profile-runner.js.map +1 -0
- package/dist/services/reporter-registry.cjs +18 -24
- package/dist/services/reporter-registry.cjs.map +1 -1
- package/dist/services/reporter-registry.d.cts +18 -40
- package/dist/services/reporter-registry.d.cts.map +1 -1
- package/dist/services/reporter-registry.d.ts +18 -40
- package/dist/services/reporter-registry.d.ts.map +1 -1
- package/dist/services/reporter-registry.js +18 -24
- package/dist/services/reporter-registry.js.map +1 -1
- package/dist/types/budgets.cjs +8 -0
- package/dist/types/budgets.cjs.map +1 -0
- package/dist/types/budgets.d.cts +149 -0
- package/dist/types/budgets.d.cts.map +1 -0
- package/dist/types/budgets.d.ts +149 -0
- package/dist/types/budgets.d.ts.map +1 -0
- package/dist/types/budgets.js +7 -0
- package/dist/types/budgets.js.map +1 -0
- package/dist/types/cli.cjs +2 -11
- package/dist/types/cli.cjs.map +1 -1
- package/dist/types/cli.d.cts +3 -227
- package/dist/types/cli.d.cts.map +1 -1
- package/dist/types/cli.d.ts +3 -227
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/cli.js +2 -11
- package/dist/types/cli.js.map +1 -1
- package/dist/types/core.cjs +6 -1
- package/dist/types/core.cjs.map +1 -1
- package/dist/types/core.d.cts +13 -2
- package/dist/types/core.d.cts.map +1 -1
- package/dist/types/core.d.ts +13 -2
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/core.js +2 -1
- package/dist/types/core.js.map +1 -1
- package/dist/types/index.cjs +5 -0
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +2 -0
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/interfaces.d.cts +15 -8
- package/dist/types/interfaces.d.cts.map +1 -1
- package/dist/types/interfaces.d.ts +15 -8
- package/dist/types/interfaces.d.ts.map +1 -1
- package/dist/types/profiler.cjs +11 -0
- package/dist/types/profiler.cjs.map +1 -0
- package/dist/types/profiler.d.cts +100 -0
- package/dist/types/profiler.d.cts.map +1 -0
- package/dist/types/profiler.d.ts +100 -0
- package/dist/types/profiler.d.ts.map +1 -0
- package/dist/types/profiler.js +10 -0
- package/dist/types/profiler.js.map +1 -0
- package/dist/types/utility.cjs.map +1 -1
- package/dist/types/utility.d.cts +0 -8
- package/dist/types/utility.d.cts.map +1 -1
- package/dist/types/utility.d.ts +0 -8
- package/dist/types/utility.d.ts.map +1 -1
- package/dist/types/utility.js.map +1 -1
- package/dist/utils/identifiers.cjs +32 -0
- package/dist/utils/identifiers.cjs.map +1 -0
- package/dist/utils/identifiers.d.cts +32 -0
- package/dist/utils/identifiers.d.cts.map +1 -0
- package/dist/utils/identifiers.d.ts +32 -0
- package/dist/utils/identifiers.d.ts.map +1 -0
- package/dist/utils/identifiers.js +27 -0
- package/dist/utils/identifiers.js.map +1 -0
- package/dist/utils/package.cjs +40 -0
- package/dist/utils/package.cjs.map +1 -0
- package/dist/utils/package.d.cts +15 -0
- package/dist/utils/package.d.cts.map +1 -0
- package/dist/utils/package.d.ts +15 -0
- package/dist/utils/package.d.ts.map +1 -0
- package/dist/utils/package.js +33 -0
- package/dist/utils/package.js.map +1 -0
- package/dist/utils/type-guards.cjs +48 -0
- package/dist/utils/type-guards.cjs.map +1 -0
- package/dist/utils/type-guards.d.cts +22 -0
- package/dist/utils/type-guards.d.cts.map +1 -0
- package/dist/utils/type-guards.d.ts +22 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +43 -0
- package/dist/utils/type-guards.js.map +1 -0
- package/package.json +10 -10
- package/src/cli/commands/analyze.ts +101 -0
- package/src/cli/commands/baseline.ts +577 -0
- package/src/cli/commands/history.ts +1 -1
- package/src/cli/commands/init.ts +105 -183
- package/src/cli/commands/run.ts +167 -98
- package/src/cli/index.ts +425 -183
- package/src/config/budget-schema.ts +189 -0
- package/src/config/schema.ts +260 -1
- package/src/constants.ts +53 -1
- package/src/core/engine.ts +151 -20
- package/src/core/output-path-resolver.ts +10 -2
- package/src/errors/base.ts +11 -2
- package/src/errors/budget.ts +38 -0
- package/src/errors/index.ts +3 -0
- package/src/index.ts +9 -0
- package/src/reporters/csv.ts +54 -25
- package/src/reporters/human.ts +88 -47
- package/src/reporters/json.ts +26 -71
- package/src/reporters/profile-human.ts +204 -0
- package/src/reporters/simple.ts +84 -53
- package/src/services/baseline-storage.ts +199 -0
- package/src/services/budget-evaluator.ts +182 -0
- package/src/services/config-manager.ts +23 -8
- package/src/services/file-loader.ts +3 -6
- package/src/services/profiler/profile-filter.ts +143 -0
- package/src/services/profiler/profile-parser.ts +194 -0
- package/src/services/profiler/profile-runner.ts +121 -0
- package/src/services/reporter-registry.ts +46 -81
- package/src/types/budgets.ts +180 -0
- package/src/types/cli.ts +5 -238
- package/src/types/core.ts +50 -10
- package/src/types/index.ts +5 -0
- package/src/types/interfaces.ts +16 -6
- package/src/types/profiler.ts +132 -0
- package/src/types/utility.ts +0 -10
- package/src/utils/identifiers.ts +58 -0
- package/src/utils/package.ts +35 -0
- package/src/utils/type-guards.ts +51 -0
package/src/cli/index.ts
CHANGED
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
* global options, help generation, and dependency injection setup.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { Argv } from 'yargs';
|
|
11
|
-
|
|
12
10
|
import { realpathSync } from 'node:fs';
|
|
13
11
|
import { fileURLToPath } from 'node:url';
|
|
14
12
|
import yargs from 'yargs';
|
|
@@ -17,13 +15,24 @@ import { hideBin } from 'yargs/helpers';
|
|
|
17
15
|
import type {
|
|
18
16
|
BenchmarkEngine,
|
|
19
17
|
ConfigurationManager,
|
|
18
|
+
Engine,
|
|
20
19
|
HistoryStorage,
|
|
21
20
|
ProgressManager,
|
|
22
21
|
ReporterRegistry,
|
|
23
22
|
} from '../types/index.js';
|
|
24
23
|
|
|
25
24
|
import { bootstrap } from '../bootstrap.js';
|
|
25
|
+
import {
|
|
26
|
+
ABORT_TIMEOUT,
|
|
27
|
+
DEFAULT_ENGINE,
|
|
28
|
+
DEFAULT_REPORTER,
|
|
29
|
+
Engines,
|
|
30
|
+
ErrorCodes,
|
|
31
|
+
ExitCodes,
|
|
32
|
+
Reporters,
|
|
33
|
+
} from '../constants.js';
|
|
26
34
|
import { AccurateEngine, TinybenchEngine } from '../core/engines/index.js';
|
|
35
|
+
import { isError } from '../errors/base.js';
|
|
27
36
|
import { isModestBenchError, UnknownError } from '../errors/index.js';
|
|
28
37
|
import {
|
|
29
38
|
CsvReporter,
|
|
@@ -32,6 +41,17 @@ import {
|
|
|
32
41
|
SimpleReporter,
|
|
33
42
|
} from '../reporters/index.js';
|
|
34
43
|
// Import commands
|
|
44
|
+
import {
|
|
45
|
+
handleAnalyzeCommand as analyzeCommand,
|
|
46
|
+
type AnalyzeOptions,
|
|
47
|
+
} from './commands/analyze.js';
|
|
48
|
+
import {
|
|
49
|
+
handleAnalyzeCommand as handleBaselineAnalyzeCommand,
|
|
50
|
+
handleDeleteCommand as handleBaselineDeleteCommand,
|
|
51
|
+
handleListCommand as handleBaselineListCommand,
|
|
52
|
+
handleSetCommand as handleBaselineSetCommand,
|
|
53
|
+
handleShowCommand as handleBaselineShowCommand,
|
|
54
|
+
} from './commands/baseline.js';
|
|
35
55
|
import {
|
|
36
56
|
handleCleanCommand,
|
|
37
57
|
handleCompareCommand,
|
|
@@ -41,7 +61,10 @@ import {
|
|
|
41
61
|
handleTrendsCommand,
|
|
42
62
|
} from './commands/history.js';
|
|
43
63
|
import { handleInitCommand as initCommand } from './commands/init.js';
|
|
44
|
-
import {
|
|
64
|
+
import {
|
|
65
|
+
RUN_COMMAND_DEFAULTS,
|
|
66
|
+
handleRunCommand as runCommand,
|
|
67
|
+
} from './commands/run.js';
|
|
45
68
|
|
|
46
69
|
/**
|
|
47
70
|
* CLI context with initialized services
|
|
@@ -63,28 +86,15 @@ interface GlobalOptions {
|
|
|
63
86
|
/** Configuration file path */
|
|
64
87
|
config?: string | undefined;
|
|
65
88
|
/** Working directory */
|
|
66
|
-
cwd
|
|
89
|
+
cwd?: string;
|
|
67
90
|
/** JSON output for machine parsing */
|
|
68
|
-
json
|
|
91
|
+
json?: boolean;
|
|
69
92
|
/** Disable colored output */
|
|
70
|
-
noColor
|
|
93
|
+
noColor?: boolean;
|
|
71
94
|
/** Enable verbose output */
|
|
72
|
-
verbose
|
|
95
|
+
verbose?: boolean;
|
|
73
96
|
}
|
|
74
97
|
|
|
75
|
-
/**
|
|
76
|
-
* Exit codes for the CLI
|
|
77
|
-
*/
|
|
78
|
-
export const ExitCodes = {
|
|
79
|
-
BENCHMARK_FAILURES: 1,
|
|
80
|
-
CONFIG_ERROR: 2,
|
|
81
|
-
DISCOVERY_ERROR: 3,
|
|
82
|
-
RUNTIME_ERROR: 5,
|
|
83
|
-
SUCCESS: 0,
|
|
84
|
-
UNKNOWN_ERROR: 99,
|
|
85
|
-
VALIDATION_ERROR: 4,
|
|
86
|
-
} as const;
|
|
87
|
-
|
|
88
98
|
/**
|
|
89
99
|
* Initialize and run the CLI
|
|
90
100
|
*/
|
|
@@ -110,6 +120,7 @@ export const main = async (
|
|
|
110
120
|
const cli = yargs(args);
|
|
111
121
|
|
|
112
122
|
// Configure global options and commands
|
|
123
|
+
|
|
113
124
|
await cli
|
|
114
125
|
.scriptName('modestbench')
|
|
115
126
|
.option('config', {
|
|
@@ -120,34 +131,34 @@ export const main = async (
|
|
|
120
131
|
})
|
|
121
132
|
.option('verbose', {
|
|
122
133
|
alias: 'v',
|
|
123
|
-
|
|
134
|
+
defaultDescription: String(RUN_COMMAND_DEFAULTS.verbose),
|
|
124
135
|
description: 'Enable verbose output',
|
|
125
136
|
global: true,
|
|
126
137
|
type: 'boolean',
|
|
127
138
|
})
|
|
128
139
|
.option('no-color', {
|
|
129
|
-
|
|
140
|
+
defaultDescription: 'false',
|
|
130
141
|
description: 'Disable colored output',
|
|
131
142
|
global: true,
|
|
132
143
|
type: 'boolean',
|
|
133
144
|
})
|
|
134
145
|
.option('progress', {
|
|
135
|
-
|
|
146
|
+
defaultDescription: 'true',
|
|
136
147
|
description: 'Show animated progress bar',
|
|
137
148
|
global: true,
|
|
138
149
|
type: 'boolean',
|
|
139
150
|
})
|
|
140
151
|
.option('json', {
|
|
141
|
-
|
|
152
|
+
defaultDescription: 'false',
|
|
142
153
|
description: 'Output results in JSON format',
|
|
143
154
|
global: true,
|
|
144
155
|
type: 'boolean',
|
|
145
156
|
})
|
|
146
157
|
.option('cwd', {
|
|
147
|
-
default: process.cwd(),
|
|
148
158
|
defaultDescription: '.',
|
|
149
159
|
description: 'Working directory',
|
|
150
160
|
global: true,
|
|
161
|
+
normalize: true,
|
|
151
162
|
type: 'string',
|
|
152
163
|
})
|
|
153
164
|
.help()
|
|
@@ -155,18 +166,18 @@ export const main = async (
|
|
|
155
166
|
.version()
|
|
156
167
|
.alias('version', 'V')
|
|
157
168
|
.strict()
|
|
158
|
-
.demandCommand(1
|
|
169
|
+
.demandCommand(1)
|
|
159
170
|
.recommendCommands()
|
|
160
171
|
.completion()
|
|
161
172
|
.wrap(Math.min(120, cli.terminalWidth()))
|
|
162
173
|
.command(
|
|
163
174
|
['$0 [pattern..]', 'run [pattern..]'],
|
|
164
175
|
'Run benchmark files',
|
|
165
|
-
(yargs) =>
|
|
166
|
-
|
|
176
|
+
(yargs) =>
|
|
177
|
+
yargs
|
|
167
178
|
.positional('pattern', {
|
|
168
179
|
array: true,
|
|
169
|
-
|
|
180
|
+
defaultDescription: '(auto-discovered from bench/ directory)',
|
|
170
181
|
describe:
|
|
171
182
|
'File paths, directory paths, or glob patterns for benchmark files',
|
|
172
183
|
type: 'string',
|
|
@@ -176,20 +187,13 @@ export const main = async (
|
|
|
176
187
|
description: 'Path to configuration file',
|
|
177
188
|
type: 'string',
|
|
178
189
|
})
|
|
179
|
-
.option('
|
|
190
|
+
.option('reporter', {
|
|
180
191
|
alias: 'r',
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
return value.flatMap((v) =>
|
|
185
|
-
v.split(',').map((s) => s.trim()),
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
return value.split(',').map((s) => s.trim());
|
|
189
|
-
},
|
|
190
|
-
default: ['human'],
|
|
192
|
+
array: true,
|
|
193
|
+
choices: Object.values(Reporters).sort(),
|
|
194
|
+
defaultDescription: DEFAULT_REPORTER,
|
|
191
195
|
description: 'Output reporters to use (human,json,csv)',
|
|
192
|
-
type: '
|
|
196
|
+
type: 'string',
|
|
193
197
|
})
|
|
194
198
|
.option('output', {
|
|
195
199
|
alias: 'o',
|
|
@@ -197,7 +201,7 @@ export const main = async (
|
|
|
197
201
|
type: 'string',
|
|
198
202
|
})
|
|
199
203
|
.option('output-file', {
|
|
200
|
-
alias: 'of',
|
|
204
|
+
alias: ['of', 'file'],
|
|
201
205
|
description:
|
|
202
206
|
'Custom filename for reporter output (use with single reporter only)',
|
|
203
207
|
requiresArg: true,
|
|
@@ -214,11 +218,12 @@ export const main = async (
|
|
|
214
218
|
type: 'number',
|
|
215
219
|
})
|
|
216
220
|
.option('warmup', {
|
|
217
|
-
alias: 'w',
|
|
221
|
+
alias: ['w', 'warm'],
|
|
218
222
|
description: 'Number of warmup iterations',
|
|
219
223
|
type: 'number',
|
|
220
224
|
})
|
|
221
225
|
.option('limit-by', {
|
|
226
|
+
alias: ['l', 'limit'],
|
|
222
227
|
choices: ['time', 'iterations', 'any', 'all'],
|
|
223
228
|
description:
|
|
224
229
|
'How to limit benchmarks: time (time budget), iterations (sample count), any (either threshold), all (both thresholds)',
|
|
@@ -226,22 +231,15 @@ export const main = async (
|
|
|
226
231
|
})
|
|
227
232
|
.option('bail', {
|
|
228
233
|
alias: 'b',
|
|
229
|
-
|
|
234
|
+
defaultDescription: String(RUN_COMMAND_DEFAULTS.bail),
|
|
230
235
|
description: 'Stop on first failure',
|
|
231
236
|
type: 'boolean',
|
|
232
237
|
})
|
|
233
238
|
.option('exclude', {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (Array.isArray(value)) {
|
|
237
|
-
return value.flatMap((v) =>
|
|
238
|
-
v.split(',').map((s) => s.trim()),
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
return value.split(',').map((s) => s.trim());
|
|
242
|
-
},
|
|
239
|
+
alias: 'X',
|
|
240
|
+
array: true,
|
|
243
241
|
description: 'Exclude patterns (comma-separated)',
|
|
244
|
-
type: '
|
|
242
|
+
type: 'string',
|
|
245
243
|
})
|
|
246
244
|
.option('timeout', {
|
|
247
245
|
description: 'Timeout per benchmark in milliseconds',
|
|
@@ -249,40 +247,25 @@ export const main = async (
|
|
|
249
247
|
})
|
|
250
248
|
.option('quiet', {
|
|
251
249
|
alias: 'q',
|
|
252
|
-
|
|
250
|
+
defaultDescription: String(RUN_COMMAND_DEFAULTS.quiet),
|
|
253
251
|
description: 'Minimal output',
|
|
254
252
|
type: 'boolean',
|
|
255
253
|
})
|
|
256
|
-
.option('
|
|
257
|
-
|
|
258
|
-
// Handle comma-separated values
|
|
259
|
-
if (Array.isArray(value)) {
|
|
260
|
-
return value.flatMap((v) =>
|
|
261
|
-
v.split(',').map((s) => s.trim()),
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
return value.split(',').map((s) => s.trim());
|
|
265
|
-
},
|
|
254
|
+
.option('tag', {
|
|
255
|
+
array: true,
|
|
266
256
|
description: 'Include only benchmarks with any of these tags',
|
|
267
|
-
type: '
|
|
257
|
+
type: 'string',
|
|
268
258
|
})
|
|
269
|
-
.option('exclude-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
if (Array.isArray(value)) {
|
|
273
|
-
return value.flatMap((v) =>
|
|
274
|
-
v.split(',').map((s) => s.trim()),
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
return value.split(',').map((s) => s.trim());
|
|
278
|
-
},
|
|
259
|
+
.option('exclude-tag', {
|
|
260
|
+
alias: 'T',
|
|
261
|
+
array: true,
|
|
279
262
|
description: 'Exclude benchmarks with any of these tags',
|
|
280
|
-
type: '
|
|
263
|
+
type: 'string',
|
|
281
264
|
})
|
|
282
265
|
.option('engine', {
|
|
283
266
|
alias: 'e',
|
|
284
|
-
choices:
|
|
285
|
-
|
|
267
|
+
choices: Object.values(Engines),
|
|
268
|
+
defaultDescription: DEFAULT_ENGINE,
|
|
286
269
|
description:
|
|
287
270
|
'Benchmark engine: tinybench (default) or accurate (requires --allow-natives-syntax)',
|
|
288
271
|
type: 'string',
|
|
@@ -294,12 +277,23 @@ export const main = async (
|
|
|
294
277
|
['$0 run "src/**/*.bench.js"', 'Run specific glob pattern'],
|
|
295
278
|
['$0 run file1.bench.js file2.bench.js', 'Run specific files'],
|
|
296
279
|
['$0 run benchmarks/ tests/perf/', 'Run multiple directories'],
|
|
297
|
-
['$0 run
|
|
280
|
+
['$0 run -r json -r csv', 'Use multiple reporters'],
|
|
298
281
|
['$0 run --iterations 1000', 'Set iteration count'],
|
|
299
282
|
['$0 run --engine accurate', 'Use high-accuracy engine'],
|
|
300
283
|
['$0 run --bail', 'Stop on first failure'],
|
|
301
|
-
])
|
|
302
|
-
|
|
284
|
+
])
|
|
285
|
+
.check((argv) => {
|
|
286
|
+
if (
|
|
287
|
+
argv.reporter &&
|
|
288
|
+
argv.reporter.length > 1 &&
|
|
289
|
+
argv['output-file']
|
|
290
|
+
) {
|
|
291
|
+
throw new Error(
|
|
292
|
+
'--output-file can only be used with a single reporter. Use --output <dir> for multiple reporters.',
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
return true;
|
|
296
|
+
}),
|
|
303
297
|
async (argv) => {
|
|
304
298
|
const context = await createCliContext(
|
|
305
299
|
argv,
|
|
@@ -312,7 +306,7 @@ export const main = async (
|
|
|
312
306
|
cwd: argv.cwd,
|
|
313
307
|
engine: argv.engine,
|
|
314
308
|
exclude: argv.exclude,
|
|
315
|
-
excludeTags: argv['exclude-
|
|
309
|
+
excludeTags: argv['exclude-tag'],
|
|
316
310
|
iterations: argv.iterations,
|
|
317
311
|
json: argv.json,
|
|
318
312
|
noColor: argv.noColor,
|
|
@@ -321,8 +315,8 @@ export const main = async (
|
|
|
321
315
|
pattern: argv.pattern,
|
|
322
316
|
progress: argv.progress,
|
|
323
317
|
quiet: argv.quiet,
|
|
324
|
-
reporters: argv.
|
|
325
|
-
tags: argv.
|
|
318
|
+
reporters: argv.reporter,
|
|
319
|
+
tags: argv.tag,
|
|
326
320
|
time: argv.time,
|
|
327
321
|
timeout: argv.timeout,
|
|
328
322
|
verbose: argv.verbose,
|
|
@@ -331,13 +325,13 @@ export const main = async (
|
|
|
331
325
|
process.exit(exitCode);
|
|
332
326
|
},
|
|
333
327
|
)
|
|
334
|
-
.command('history', 'View and manage benchmark history', (yargs) =>
|
|
335
|
-
|
|
328
|
+
.command('history', 'View and manage benchmark history', (yargs) =>
|
|
329
|
+
yargs
|
|
336
330
|
.command(
|
|
337
331
|
'list',
|
|
338
332
|
'List recent benchmark runs',
|
|
339
|
-
(yargs) =>
|
|
340
|
-
|
|
333
|
+
(yargs) =>
|
|
334
|
+
yargs
|
|
341
335
|
.option('since', {
|
|
342
336
|
description:
|
|
343
337
|
'Show runs since date (ISO 8601 or relative like "1 week ago")',
|
|
@@ -352,18 +346,20 @@ export const main = async (
|
|
|
352
346
|
description: 'Filter by benchmark name pattern',
|
|
353
347
|
type: 'string',
|
|
354
348
|
})
|
|
355
|
-
.option('
|
|
349
|
+
.option('tag', {
|
|
350
|
+
alias: 't',
|
|
351
|
+
array: true,
|
|
356
352
|
description: 'Filter by tags (comma-separated)',
|
|
357
|
-
type: '
|
|
353
|
+
type: 'string',
|
|
358
354
|
})
|
|
359
355
|
.option('limit', {
|
|
360
|
-
|
|
356
|
+
defaultDescription: '10',
|
|
361
357
|
description: 'Maximum number of results',
|
|
362
358
|
type: 'number',
|
|
363
359
|
})
|
|
364
360
|
.option('format', {
|
|
365
361
|
choices: ['human', 'json', 'csv'] as const,
|
|
366
|
-
|
|
362
|
+
defaultDescription: 'human' as const,
|
|
367
363
|
description: 'Output format',
|
|
368
364
|
type: 'string',
|
|
369
365
|
})
|
|
@@ -375,8 +371,7 @@ export const main = async (
|
|
|
375
371
|
],
|
|
376
372
|
['$0 history list --limit 20', 'List 20 most recent runs'],
|
|
377
373
|
['$0 history list --format json', 'List runs in JSON format'],
|
|
378
|
-
])
|
|
379
|
-
},
|
|
374
|
+
]),
|
|
380
375
|
async (argv) => {
|
|
381
376
|
const context = await createCliContext(argv, abortController!);
|
|
382
377
|
const exitCode = await handleListCommand(context, {
|
|
@@ -384,9 +379,8 @@ export const main = async (
|
|
|
384
379
|
format: argv.format,
|
|
385
380
|
limit: argv.limit,
|
|
386
381
|
pattern: argv.pattern,
|
|
387
|
-
quiet: Boolean(argv.quiet),
|
|
388
382
|
since: argv.since,
|
|
389
|
-
tags: argv.
|
|
383
|
+
tags: argv.tag,
|
|
390
384
|
until: argv.until,
|
|
391
385
|
verbose: argv.verbose,
|
|
392
386
|
});
|
|
@@ -396,15 +390,16 @@ export const main = async (
|
|
|
396
390
|
.command(
|
|
397
391
|
'show <run-id>',
|
|
398
392
|
'Show detailed results for a specific run',
|
|
399
|
-
(yargs) =>
|
|
400
|
-
|
|
393
|
+
(yargs) =>
|
|
394
|
+
yargs
|
|
401
395
|
.positional('run-id', {
|
|
396
|
+
demandOption: true,
|
|
402
397
|
describe: 'ID of the benchmark run to show',
|
|
403
398
|
type: 'string',
|
|
404
399
|
})
|
|
405
400
|
.option('format', {
|
|
406
401
|
choices: ['human', 'json', 'csv'] as const,
|
|
407
|
-
|
|
402
|
+
defaultDescription: 'human' as const,
|
|
408
403
|
description: 'Output format',
|
|
409
404
|
type: 'string',
|
|
410
405
|
})
|
|
@@ -417,15 +412,13 @@ export const main = async (
|
|
|
417
412
|
'$0 history show abc123 --format json',
|
|
418
413
|
'Show run in JSON format',
|
|
419
414
|
],
|
|
420
|
-
])
|
|
421
|
-
},
|
|
415
|
+
]),
|
|
422
416
|
async (argv) => {
|
|
423
417
|
const context = await createCliContext(argv, abortController!);
|
|
424
418
|
const exitCode = await handleShowCommand(context, {
|
|
425
419
|
cwd: argv.cwd,
|
|
426
420
|
format: argv.format,
|
|
427
|
-
|
|
428
|
-
runId: String(argv['run-id']),
|
|
421
|
+
runId: argv['run-id'],
|
|
429
422
|
verbose: argv.verbose,
|
|
430
423
|
});
|
|
431
424
|
process.exit(exitCode);
|
|
@@ -434,19 +427,21 @@ export const main = async (
|
|
|
434
427
|
.command(
|
|
435
428
|
'compare <run-id1> <run-id2>',
|
|
436
429
|
'Compare two benchmark runs',
|
|
437
|
-
(yargs) =>
|
|
438
|
-
|
|
430
|
+
(yargs) =>
|
|
431
|
+
yargs
|
|
439
432
|
.positional('run-id1', {
|
|
433
|
+
demandOption: true,
|
|
440
434
|
describe: 'ID of the first benchmark run',
|
|
441
435
|
type: 'string',
|
|
442
436
|
})
|
|
443
437
|
.positional('run-id2', {
|
|
438
|
+
demandOption: true,
|
|
444
439
|
describe: 'ID of the second benchmark run',
|
|
445
440
|
type: 'string',
|
|
446
441
|
})
|
|
447
442
|
.option('format', {
|
|
448
443
|
choices: ['human', 'json'] as const,
|
|
449
|
-
|
|
444
|
+
defaultDescription: 'human' as const,
|
|
450
445
|
description: 'Output format',
|
|
451
446
|
type: 'string',
|
|
452
447
|
})
|
|
@@ -456,16 +451,14 @@ export const main = async (
|
|
|
456
451
|
'$0 history compare abc123 def456 --format json',
|
|
457
452
|
'Compare in JSON format',
|
|
458
453
|
],
|
|
459
|
-
])
|
|
460
|
-
},
|
|
454
|
+
]),
|
|
461
455
|
async (argv) => {
|
|
462
456
|
const context = await createCliContext(argv, abortController!);
|
|
463
457
|
const exitCode = await handleCompareCommand(context, {
|
|
464
458
|
cwd: argv.cwd,
|
|
465
459
|
format: argv.format,
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
runId2: String(argv['run-id2']),
|
|
460
|
+
runId1: argv['run-id1'],
|
|
461
|
+
runId2: argv['run-id2'],
|
|
469
462
|
verbose: argv.verbose,
|
|
470
463
|
});
|
|
471
464
|
process.exit(exitCode);
|
|
@@ -474,8 +467,8 @@ export const main = async (
|
|
|
474
467
|
.command(
|
|
475
468
|
'trends [pattern]',
|
|
476
469
|
'Show performance trends over time',
|
|
477
|
-
(yargs) =>
|
|
478
|
-
|
|
470
|
+
(yargs) =>
|
|
471
|
+
yargs
|
|
479
472
|
.positional('pattern', {
|
|
480
473
|
describe: 'Filter by benchmark name pattern',
|
|
481
474
|
type: 'string',
|
|
@@ -490,9 +483,11 @@ export const main = async (
|
|
|
490
483
|
'Show trends until date (ISO 8601 or relative like "1 day ago")',
|
|
491
484
|
type: 'string',
|
|
492
485
|
})
|
|
493
|
-
.option('
|
|
486
|
+
.option('tag', {
|
|
487
|
+
alias: 't',
|
|
488
|
+
array: true,
|
|
494
489
|
description: 'Filter by tags (comma-separated)',
|
|
495
|
-
type: '
|
|
490
|
+
type: 'string',
|
|
496
491
|
})
|
|
497
492
|
.option('limit', {
|
|
498
493
|
description: 'Maximum number of runs to analyze',
|
|
@@ -500,13 +495,13 @@ export const main = async (
|
|
|
500
495
|
})
|
|
501
496
|
.option('all', {
|
|
502
497
|
alias: 'a',
|
|
503
|
-
|
|
498
|
+
defaultDescription: 'false',
|
|
504
499
|
description: 'Analyze all runs (ignore limit)',
|
|
505
500
|
type: 'boolean',
|
|
506
501
|
})
|
|
507
502
|
.option('format', {
|
|
508
503
|
choices: ['human', 'json'] as const,
|
|
509
|
-
|
|
504
|
+
defaultDescription: 'human' as const,
|
|
510
505
|
description: 'Output format',
|
|
511
506
|
type: 'string',
|
|
512
507
|
})
|
|
@@ -527,19 +522,17 @@ export const main = async (
|
|
|
527
522
|
'$0 history trends --format json',
|
|
528
523
|
'Output trends in JSON format',
|
|
529
524
|
],
|
|
530
|
-
])
|
|
531
|
-
},
|
|
525
|
+
]),
|
|
532
526
|
async (argv) => {
|
|
533
527
|
const context = await createCliContext(argv, abortController!);
|
|
534
528
|
const exitCode = await handleTrendsCommand(context, {
|
|
535
|
-
all:
|
|
529
|
+
all: argv.all,
|
|
536
530
|
cwd: argv.cwd,
|
|
537
531
|
format: argv.format,
|
|
538
532
|
limit: argv.limit,
|
|
539
533
|
pattern: argv.pattern,
|
|
540
|
-
quiet: Boolean(argv.quiet),
|
|
541
534
|
since: argv.since,
|
|
542
|
-
tags: argv.
|
|
535
|
+
tags: argv.tag,
|
|
543
536
|
until: argv.until,
|
|
544
537
|
verbose: argv.verbose,
|
|
545
538
|
});
|
|
@@ -549,8 +542,8 @@ export const main = async (
|
|
|
549
542
|
.command(
|
|
550
543
|
'clean',
|
|
551
544
|
'Clean up old benchmark history',
|
|
552
|
-
(yargs) =>
|
|
553
|
-
|
|
545
|
+
(yargs) =>
|
|
546
|
+
yargs
|
|
554
547
|
.option('max-age', {
|
|
555
548
|
description: 'Remove runs older than this many days',
|
|
556
549
|
type: 'number',
|
|
@@ -563,11 +556,16 @@ export const main = async (
|
|
|
563
556
|
description: 'Keep history under this size in bytes',
|
|
564
557
|
type: 'number',
|
|
565
558
|
})
|
|
566
|
-
.option('
|
|
567
|
-
|
|
559
|
+
.option('yes', {
|
|
560
|
+
alias: 'y',
|
|
568
561
|
description: 'Confirm cleanup without prompting',
|
|
569
562
|
type: 'boolean',
|
|
570
563
|
})
|
|
564
|
+
.option('quiet', {
|
|
565
|
+
default: false,
|
|
566
|
+
description: 'Minimal output',
|
|
567
|
+
type: 'boolean',
|
|
568
|
+
})
|
|
571
569
|
.check((argv) => {
|
|
572
570
|
if (
|
|
573
571
|
!argv['max-age'] &&
|
|
@@ -582,7 +580,7 @@ export const main = async (
|
|
|
582
580
|
})
|
|
583
581
|
.example([
|
|
584
582
|
[
|
|
585
|
-
'$0 history clean --max-runs 50 --
|
|
583
|
+
'$0 history clean --max-runs 50 --yes',
|
|
586
584
|
'Keep only latest 50 runs',
|
|
587
585
|
],
|
|
588
586
|
[
|
|
@@ -593,17 +591,16 @@ export const main = async (
|
|
|
593
591
|
'$0 history clean --max-size 10485760',
|
|
594
592
|
'Keep history under 10MB',
|
|
595
593
|
],
|
|
596
|
-
])
|
|
597
|
-
},
|
|
594
|
+
]),
|
|
598
595
|
async (argv) => {
|
|
599
596
|
const context = await createCliContext(argv, abortController!);
|
|
600
597
|
const exitCode = await handleCleanCommand(context, {
|
|
601
|
-
confirm: argv.
|
|
598
|
+
confirm: argv.yes,
|
|
602
599
|
cwd: argv.cwd,
|
|
603
600
|
maxAge: argv['max-age'],
|
|
604
601
|
maxRuns: argv['max-runs'],
|
|
605
602
|
maxSize: argv['max-size'],
|
|
606
|
-
quiet:
|
|
603
|
+
quiet: argv.quiet,
|
|
607
604
|
verbose: argv.verbose,
|
|
608
605
|
});
|
|
609
606
|
process.exit(exitCode);
|
|
@@ -612,11 +609,11 @@ export const main = async (
|
|
|
612
609
|
.command(
|
|
613
610
|
'export',
|
|
614
611
|
'Export benchmark history to a file',
|
|
615
|
-
(yargs) =>
|
|
616
|
-
|
|
612
|
+
(yargs) =>
|
|
613
|
+
yargs
|
|
617
614
|
.option('format', {
|
|
618
615
|
choices: ['json', 'csv'] as const,
|
|
619
|
-
|
|
616
|
+
defaultDescription: 'json' as const,
|
|
620
617
|
description: 'Export format',
|
|
621
618
|
type: 'string',
|
|
622
619
|
})
|
|
@@ -647,8 +644,7 @@ export const main = async (
|
|
|
647
644
|
'$0 history export -o recent.json --since "1 week ago"',
|
|
648
645
|
'Export recent runs',
|
|
649
646
|
],
|
|
650
|
-
])
|
|
651
|
-
},
|
|
647
|
+
]),
|
|
652
648
|
async (argv) => {
|
|
653
649
|
const context = await createCliContext(argv, abortController!);
|
|
654
650
|
const exitCode = await handleExportCommand(context, {
|
|
@@ -660,7 +656,7 @@ export const main = async (
|
|
|
660
656
|
until: argv.until,
|
|
661
657
|
verbose: argv.verbose,
|
|
662
658
|
});
|
|
663
|
-
process.
|
|
659
|
+
process.exitCode = exitCode;
|
|
664
660
|
},
|
|
665
661
|
)
|
|
666
662
|
.demandCommand(1, 'You must specify a history subcommand')
|
|
@@ -672,6 +668,196 @@ export const main = async (
|
|
|
672
668
|
['$0 history trends', 'Show performance trends'],
|
|
673
669
|
['$0 history clean --max-runs 50', 'Keep only latest 50 runs'],
|
|
674
670
|
['$0 history export -o data.json', 'Export history'],
|
|
671
|
+
]),
|
|
672
|
+
)
|
|
673
|
+
.command('baseline', 'Manage performance baselines', (yargs) => {
|
|
674
|
+
return yargs
|
|
675
|
+
.command(
|
|
676
|
+
'set <name>',
|
|
677
|
+
'Save a benchmark run as a baseline',
|
|
678
|
+
(yargs) => {
|
|
679
|
+
return yargs
|
|
680
|
+
.positional('name', {
|
|
681
|
+
describe: 'Name for the baseline',
|
|
682
|
+
type: 'string',
|
|
683
|
+
})
|
|
684
|
+
.option('run-id', {
|
|
685
|
+
description: 'Specific run ID to save (default: most recent)',
|
|
686
|
+
type: 'string',
|
|
687
|
+
})
|
|
688
|
+
.option('commit', {
|
|
689
|
+
description: 'Git commit SHA (40 characters)',
|
|
690
|
+
type: 'string',
|
|
691
|
+
})
|
|
692
|
+
.option('branch', {
|
|
693
|
+
description: 'Git branch name',
|
|
694
|
+
type: 'string',
|
|
695
|
+
})
|
|
696
|
+
.option('default', {
|
|
697
|
+
defaultDescription: 'false',
|
|
698
|
+
description: 'Set as default baseline',
|
|
699
|
+
type: 'boolean',
|
|
700
|
+
})
|
|
701
|
+
.example([
|
|
702
|
+
[
|
|
703
|
+
'$0 baseline set production-v1.0',
|
|
704
|
+
'Save most recent run as baseline',
|
|
705
|
+
],
|
|
706
|
+
['$0 baseline set v1.0 --default', 'Save and set as default'],
|
|
707
|
+
[
|
|
708
|
+
'$0 baseline set v1.0 --commit abc123...',
|
|
709
|
+
'Save with commit info',
|
|
710
|
+
],
|
|
711
|
+
]);
|
|
712
|
+
},
|
|
713
|
+
async (argv) => {
|
|
714
|
+
const context = await createCliContext(argv, abortController!);
|
|
715
|
+
const exitCode = await handleBaselineSetCommand(context, {
|
|
716
|
+
branch: argv.branch,
|
|
717
|
+
commit: argv.commit,
|
|
718
|
+
cwd: argv.cwd,
|
|
719
|
+
default: argv.default,
|
|
720
|
+
name: String(argv.name),
|
|
721
|
+
quiet: Boolean(argv.quiet),
|
|
722
|
+
runId: argv['run-id'],
|
|
723
|
+
verbose: argv.verbose,
|
|
724
|
+
});
|
|
725
|
+
process.exit(exitCode);
|
|
726
|
+
},
|
|
727
|
+
)
|
|
728
|
+
.command(
|
|
729
|
+
'list',
|
|
730
|
+
'List all saved baselines',
|
|
731
|
+
(yargs) => {
|
|
732
|
+
return yargs
|
|
733
|
+
.option('format', {
|
|
734
|
+
choices: ['human', 'json'] as const,
|
|
735
|
+
defaultDescription: 'human' as const,
|
|
736
|
+
description: 'Output format',
|
|
737
|
+
type: 'string',
|
|
738
|
+
})
|
|
739
|
+
.example([
|
|
740
|
+
['$0 baseline list', 'List all baselines'],
|
|
741
|
+
['$0 baseline list --format json', 'List in JSON format'],
|
|
742
|
+
]);
|
|
743
|
+
},
|
|
744
|
+
async (argv) => {
|
|
745
|
+
const context = await createCliContext(argv, abortController!);
|
|
746
|
+
const exitCode = await handleBaselineListCommand(context, {
|
|
747
|
+
cwd: argv.cwd,
|
|
748
|
+
format: argv.format,
|
|
749
|
+
quiet: Boolean(argv.quiet),
|
|
750
|
+
verbose: argv.verbose,
|
|
751
|
+
});
|
|
752
|
+
process.exit(exitCode);
|
|
753
|
+
},
|
|
754
|
+
)
|
|
755
|
+
.command(
|
|
756
|
+
'show <name>',
|
|
757
|
+
'Show baseline details',
|
|
758
|
+
(yargs) => {
|
|
759
|
+
return yargs
|
|
760
|
+
.positional('name', {
|
|
761
|
+
describe: 'Baseline name to show',
|
|
762
|
+
type: 'string',
|
|
763
|
+
})
|
|
764
|
+
.option('format', {
|
|
765
|
+
choices: ['human', 'json'] as const,
|
|
766
|
+
defaultDescription: 'human' as const,
|
|
767
|
+
description: 'Output format',
|
|
768
|
+
type: 'string',
|
|
769
|
+
})
|
|
770
|
+
.example([
|
|
771
|
+
['$0 baseline show production-v1.0', 'Show baseline details'],
|
|
772
|
+
[
|
|
773
|
+
'$0 baseline show v1.0 --format json',
|
|
774
|
+
'Show in JSON format',
|
|
775
|
+
],
|
|
776
|
+
]);
|
|
777
|
+
},
|
|
778
|
+
async (argv) => {
|
|
779
|
+
const context = await createCliContext(argv, abortController!);
|
|
780
|
+
const exitCode = await handleBaselineShowCommand(context, {
|
|
781
|
+
cwd: argv.cwd,
|
|
782
|
+
format: argv.format,
|
|
783
|
+
name: String(argv.name),
|
|
784
|
+
quiet: Boolean(argv.quiet),
|
|
785
|
+
verbose: argv.verbose,
|
|
786
|
+
});
|
|
787
|
+
process.exit(exitCode);
|
|
788
|
+
},
|
|
789
|
+
)
|
|
790
|
+
.command(
|
|
791
|
+
'delete <name>',
|
|
792
|
+
'Delete a baseline',
|
|
793
|
+
(yargs) => {
|
|
794
|
+
return yargs
|
|
795
|
+
.positional('name', {
|
|
796
|
+
describe: 'Baseline name to delete',
|
|
797
|
+
type: 'string',
|
|
798
|
+
})
|
|
799
|
+
.example([
|
|
800
|
+
['$0 baseline delete old-baseline', 'Delete a baseline'],
|
|
801
|
+
]);
|
|
802
|
+
},
|
|
803
|
+
async (argv) => {
|
|
804
|
+
const context = await createCliContext(argv, abortController!);
|
|
805
|
+
const exitCode = await handleBaselineDeleteCommand(context, {
|
|
806
|
+
cwd: argv.cwd,
|
|
807
|
+
name: String(argv.name),
|
|
808
|
+
quiet: Boolean(argv.quiet),
|
|
809
|
+
verbose: argv.verbose,
|
|
810
|
+
});
|
|
811
|
+
process.exit(exitCode);
|
|
812
|
+
},
|
|
813
|
+
)
|
|
814
|
+
.command(
|
|
815
|
+
'analyze',
|
|
816
|
+
'Analyze history and suggest performance budgets',
|
|
817
|
+
(yargs) => {
|
|
818
|
+
return yargs
|
|
819
|
+
.option('runs', {
|
|
820
|
+
defaultDescription: '10',
|
|
821
|
+
description: 'Number of recent runs to analyze',
|
|
822
|
+
type: 'number',
|
|
823
|
+
})
|
|
824
|
+
.option('confidence', {
|
|
825
|
+
defaultDescription: '0.95',
|
|
826
|
+
description: 'Confidence level (0.5-0.999, default 0.95)',
|
|
827
|
+
type: 'number',
|
|
828
|
+
})
|
|
829
|
+
.example([
|
|
830
|
+
[
|
|
831
|
+
'$0 baseline analyze',
|
|
832
|
+
'Analyze last 10 runs with 95% confidence',
|
|
833
|
+
],
|
|
834
|
+
['$0 baseline analyze --runs 20', 'Analyze last 20 runs'],
|
|
835
|
+
[
|
|
836
|
+
'$0 baseline analyze --confidence 0.90',
|
|
837
|
+
'Use 90% confidence level',
|
|
838
|
+
],
|
|
839
|
+
]);
|
|
840
|
+
},
|
|
841
|
+
async (argv) => {
|
|
842
|
+
const context = await createCliContext(argv, abortController!);
|
|
843
|
+
const exitCode = await handleBaselineAnalyzeCommand(context, {
|
|
844
|
+
confidence: argv.confidence,
|
|
845
|
+
cwd: argv.cwd,
|
|
846
|
+
quiet: Boolean(argv.quiet),
|
|
847
|
+
runs: argv.runs,
|
|
848
|
+
verbose: argv.verbose,
|
|
849
|
+
});
|
|
850
|
+
process.exit(exitCode);
|
|
851
|
+
},
|
|
852
|
+
)
|
|
853
|
+
.demandCommand(1, 'You must specify a baseline subcommand')
|
|
854
|
+
.strict()
|
|
855
|
+
.example([
|
|
856
|
+
['$0 baseline set production-v1.0', 'Save current run as baseline'],
|
|
857
|
+
['$0 baseline list', 'List all baselines'],
|
|
858
|
+
['$0 baseline show production-v1.0', 'Show baseline details'],
|
|
859
|
+
['$0 baseline delete old-baseline', 'Delete a baseline'],
|
|
860
|
+
['$0 baseline analyze', 'Suggest budgets from history'],
|
|
675
861
|
]);
|
|
676
862
|
})
|
|
677
863
|
.command(
|
|
@@ -681,35 +867,35 @@ export const main = async (
|
|
|
681
867
|
return yargs
|
|
682
868
|
.positional('type', {
|
|
683
869
|
choices: ['basic', 'advanced', 'library'] as const,
|
|
684
|
-
|
|
870
|
+
defaultDescription: 'basic' as const,
|
|
685
871
|
describe: 'Type of project to initialize',
|
|
686
872
|
type: 'string',
|
|
687
873
|
})
|
|
688
874
|
.option('examples', {
|
|
689
|
-
|
|
875
|
+
defaultDescription: 'true',
|
|
690
876
|
description: 'Include example benchmark files',
|
|
691
877
|
type: 'boolean',
|
|
692
878
|
})
|
|
693
879
|
.option('config-type', {
|
|
694
880
|
choices: ['json', 'yaml', 'js', 'ts'] as const,
|
|
695
|
-
|
|
881
|
+
defaultDescription: 'json' as const,
|
|
696
882
|
description: 'Configuration file format',
|
|
697
883
|
type: 'string',
|
|
698
884
|
})
|
|
699
885
|
.option('force', {
|
|
700
|
-
|
|
886
|
+
defaultDescription: 'false',
|
|
701
887
|
description: 'Overwrite existing files',
|
|
702
888
|
type: 'boolean',
|
|
703
889
|
})
|
|
704
890
|
.option('yes', {
|
|
705
891
|
alias: 'y',
|
|
706
|
-
|
|
892
|
+
defaultDescription: 'false',
|
|
707
893
|
description: 'Accept all prompts automatically',
|
|
708
894
|
type: 'boolean',
|
|
709
895
|
})
|
|
710
896
|
.option('quiet', {
|
|
711
897
|
alias: 'q',
|
|
712
|
-
|
|
898
|
+
defaultDescription: 'false',
|
|
713
899
|
description: 'Minimal output',
|
|
714
900
|
type: 'boolean',
|
|
715
901
|
})
|
|
@@ -732,24 +918,87 @@ export const main = async (
|
|
|
732
918
|
cwd: argv.cwd,
|
|
733
919
|
examples: argv.examples,
|
|
734
920
|
force: argv.force,
|
|
735
|
-
quiet:
|
|
921
|
+
quiet: argv.quiet,
|
|
736
922
|
type: argv.type,
|
|
737
923
|
verbose: argv.verbose,
|
|
738
924
|
yes: argv.yes,
|
|
739
925
|
});
|
|
740
|
-
process.
|
|
926
|
+
process.exitCode = exitCode;
|
|
741
927
|
},
|
|
742
928
|
)
|
|
743
|
-
.
|
|
929
|
+
.command(
|
|
930
|
+
['analyze [command]', 'profile [command]'],
|
|
931
|
+
'Analyze code execution and identify benchmark candidates',
|
|
932
|
+
(yargs) => {
|
|
933
|
+
return yargs
|
|
934
|
+
.positional('command', {
|
|
935
|
+
description: 'Command to analyze (e.g., "npm test")',
|
|
936
|
+
type: 'string',
|
|
937
|
+
})
|
|
938
|
+
.option('input', {
|
|
939
|
+
alias: 'i',
|
|
940
|
+
description: 'Path to existing *.cpuprofile file',
|
|
941
|
+
type: 'string',
|
|
942
|
+
})
|
|
943
|
+
.option('filter-file', {
|
|
944
|
+
description: 'Filter functions by file glob pattern',
|
|
945
|
+
type: 'string',
|
|
946
|
+
})
|
|
947
|
+
.option('min-percent', {
|
|
948
|
+
alias: ['m', 'min'],
|
|
949
|
+
default: 0.5,
|
|
950
|
+
description: 'Minimum execution percentage to show',
|
|
951
|
+
type: 'number',
|
|
952
|
+
})
|
|
953
|
+
.option('top', {
|
|
954
|
+
alias: 'n',
|
|
955
|
+
default: 25,
|
|
956
|
+
description: 'Number of top functions to show',
|
|
957
|
+
type: 'number',
|
|
958
|
+
})
|
|
959
|
+
.option('group-by-file', {
|
|
960
|
+
default: false,
|
|
961
|
+
description: 'Group results by file',
|
|
962
|
+
type: 'boolean',
|
|
963
|
+
})
|
|
964
|
+
.check((argv) => {
|
|
965
|
+
if (!argv.command && !argv.input) {
|
|
966
|
+
throw new Error('Either [command] or --input must be provided');
|
|
967
|
+
}
|
|
968
|
+
return true;
|
|
969
|
+
});
|
|
970
|
+
},
|
|
971
|
+
async (argv) => {
|
|
972
|
+
// Context not needed for analyze command currently
|
|
973
|
+
const context = {} as CliContext;
|
|
974
|
+
|
|
975
|
+
const options: AnalyzeOptions = {
|
|
976
|
+
color: !argv.noColor,
|
|
977
|
+
command: argv.command,
|
|
978
|
+
cwd: argv.cwd || process.cwd(),
|
|
979
|
+
filterFile: argv.filterFile,
|
|
980
|
+
groupByFile: argv.groupByFile,
|
|
981
|
+
input: argv.input,
|
|
982
|
+
minPercent: argv.minPercent,
|
|
983
|
+
top: argv.top,
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
process.exitCode = await analyzeCommand(context, options);
|
|
987
|
+
},
|
|
988
|
+
)
|
|
989
|
+
.fail((msg, err, yargs) => {
|
|
744
990
|
if (err) {
|
|
745
991
|
console.error('Error:', err.message);
|
|
746
992
|
if (process.env.DEBUG) {
|
|
747
993
|
console.error(err.stack);
|
|
748
994
|
}
|
|
749
995
|
// Show help for file discovery errors (similar to usage errors)
|
|
750
|
-
if (
|
|
996
|
+
if (
|
|
997
|
+
isModestBenchError(err) &&
|
|
998
|
+
err.code === ErrorCodes.FILE_DISCOVERY_FAILED
|
|
999
|
+
) {
|
|
751
1000
|
console.error();
|
|
752
|
-
|
|
1001
|
+
yargs.showHelp();
|
|
753
1002
|
process.exit(ExitCodes.DISCOVERY_ERROR);
|
|
754
1003
|
}
|
|
755
1004
|
process.exit(ExitCodes.RUNTIME_ERROR);
|
|
@@ -757,7 +1006,7 @@ export const main = async (
|
|
|
757
1006
|
// Show help for usage errors (unknown arguments, etc.)
|
|
758
1007
|
console.error(msg);
|
|
759
1008
|
console.error();
|
|
760
|
-
|
|
1009
|
+
yargs.showHelp();
|
|
761
1010
|
process.exit(ExitCodes.CONFIG_ERROR);
|
|
762
1011
|
}
|
|
763
1012
|
})
|
|
@@ -780,20 +1029,20 @@ export const main = async (
|
|
|
780
1029
|
const createCliContext = async (
|
|
781
1030
|
options: GlobalOptions,
|
|
782
1031
|
abortController: AbortController,
|
|
783
|
-
engineType:
|
|
1032
|
+
engineType: Engine = DEFAULT_ENGINE,
|
|
784
1033
|
): Promise<CliContext> => {
|
|
785
1034
|
try {
|
|
786
1035
|
const dependencies = bootstrap();
|
|
787
1036
|
|
|
788
1037
|
// Select engine based on type
|
|
789
1038
|
const engine =
|
|
790
|
-
engineType ===
|
|
1039
|
+
engineType === Engines.ACCURATE
|
|
791
1040
|
? new AccurateEngine(dependencies)
|
|
792
1041
|
: new TinybenchEngine(dependencies);
|
|
793
1042
|
|
|
794
1043
|
// Register built-in reporters
|
|
795
1044
|
engine.registerReporter(
|
|
796
|
-
|
|
1045
|
+
Reporters.HUMAN,
|
|
797
1046
|
new HumanReporter({
|
|
798
1047
|
color: !options.noColor,
|
|
799
1048
|
verbose: options.verbose,
|
|
@@ -846,7 +1095,7 @@ const createCliContext = async (
|
|
|
846
1095
|
const setupSignalHandlers = (abortController: AbortController): void => {
|
|
847
1096
|
let abortRequested = false;
|
|
848
1097
|
|
|
849
|
-
const handleSignal = (signal:
|
|
1098
|
+
const handleSignal = (signal: NodeJS.Signals) => {
|
|
850
1099
|
if (abortRequested) {
|
|
851
1100
|
// Second signal, force exit
|
|
852
1101
|
console.log(`\nReceived ${signal} again, forcing exit...`);
|
|
@@ -861,36 +1110,29 @@ const setupSignalHandlers = (abortController: AbortController): void => {
|
|
|
861
1110
|
setTimeout(() => {
|
|
862
1111
|
console.log('\nBenchmark aborted.');
|
|
863
1112
|
process.exit(computeExitCode(signal));
|
|
864
|
-
},
|
|
1113
|
+
}, ABORT_TIMEOUT);
|
|
865
1114
|
};
|
|
866
1115
|
|
|
867
|
-
process
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
: new UnknownError(
|
|
888
|
-
reason instanceof Error ? reason.message : String(reason),
|
|
889
|
-
{ cause: reason },
|
|
890
|
-
);
|
|
891
|
-
console.error(wrappedError.toString());
|
|
892
|
-
process.exit(ExitCodes.RUNTIME_ERROR);
|
|
893
|
-
});
|
|
1116
|
+
process
|
|
1117
|
+
.once('SIGINT', handleSignal)
|
|
1118
|
+
.once('SIGQUIT', handleSignal)
|
|
1119
|
+
.once('SIGTERM', handleSignal)
|
|
1120
|
+
.once('uncaughtException', (error) => {
|
|
1121
|
+
// Wrap non-ModestBench errors with UnknownError
|
|
1122
|
+
const wrappedError: Error = isModestBenchError(error)
|
|
1123
|
+
? error
|
|
1124
|
+
: new UnknownError(error.message, { cause: error });
|
|
1125
|
+
console.error(`${wrappedError}`);
|
|
1126
|
+
process.exit(ExitCodes.RUNTIME_ERROR);
|
|
1127
|
+
})
|
|
1128
|
+
.once('unhandledRejection', (reason) => {
|
|
1129
|
+
const wrappedError = new UnknownError(
|
|
1130
|
+
isError(reason) ? reason.message : String(reason),
|
|
1131
|
+
{ cause: reason },
|
|
1132
|
+
);
|
|
1133
|
+
console.error(`${wrappedError}`);
|
|
1134
|
+
process.exit(ExitCodes.RUNTIME_ERROR);
|
|
1135
|
+
});
|
|
894
1136
|
};
|
|
895
1137
|
|
|
896
1138
|
// Run CLI if this file is executed directly
|
|
@@ -918,6 +1160,6 @@ try {
|
|
|
918
1160
|
* @param signal - The signal that caused the exit
|
|
919
1161
|
* @returns The exit code
|
|
920
1162
|
*/
|
|
921
|
-
const computeExitCode = (signal:
|
|
1163
|
+
const computeExitCode = (signal: NodeJS.Signals): number => {
|
|
922
1164
|
return 128 + (signal === 'SIGINT' ? 2 : signal === 'SIGQUIT' ? 3 : 15);
|
|
923
1165
|
};
|