modestbench 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +162 -57
- package/dist/bootstrap.cjs +10 -10
- package/dist/bootstrap.cjs.map +1 -1
- package/dist/bootstrap.d.cts.map +1 -1
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +5 -5
- package/dist/bootstrap.js.map +1 -1
- 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.cjs +108 -266
- package/dist/cli/commands/history.cjs.map +1 -1
- package/dist/cli/commands/history.d.cts +75 -12
- package/dist/cli/commands/history.d.cts.map +1 -1
- package/dist/cli/commands/history.d.ts +75 -12
- package/dist/cli/commands/history.d.ts.map +1 -1
- package/dist/cli/commands/history.js +105 -268
- package/dist/cli/commands/history.js.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 +143 -112
- package/dist/cli/commands/run.cjs.map +1 -1
- package/dist/cli/commands/run.d.cts +17 -3
- package/dist/cli/commands/run.d.cts.map +1 -1
- package/dist/cli/commands/run.d.ts +17 -3
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +142 -78
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/index.cjs +671 -266
- 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 +664 -259
- 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 +104 -15
- package/dist/core/engine.cjs.map +1 -1
- package/dist/core/engine.d.cts +7 -4
- package/dist/core/engine.d.cts.map +1 -1
- package/dist/core/engine.d.ts +7 -4
- package/dist/core/engine.d.ts.map +1 -1
- package/dist/core/engine.js +105 -16
- package/dist/core/engine.js.map +1 -1
- package/dist/core/output-path-resolver.cjs +41 -0
- package/dist/core/output-path-resolver.cjs.map +1 -0
- package/dist/core/output-path-resolver.d.cts +10 -0
- package/dist/core/output-path-resolver.d.cts.map +1 -0
- package/dist/core/output-path-resolver.d.ts +10 -0
- package/dist/core/output-path-resolver.d.ts.map +1 -0
- package/dist/core/output-path-resolver.js +37 -0
- package/dist/core/output-path-resolver.js.map +1 -0
- 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/formatters/history/base.cjs +9 -0
- package/dist/formatters/history/base.cjs.map +1 -0
- package/dist/formatters/history/base.d.cts +26 -0
- package/dist/formatters/history/base.d.cts.map +1 -0
- package/dist/formatters/history/base.d.ts +26 -0
- package/dist/formatters/history/base.d.ts.map +1 -0
- package/dist/formatters/history/base.js +8 -0
- package/dist/formatters/history/base.js.map +1 -0
- package/dist/formatters/history/compare.cjs +127 -0
- package/dist/formatters/history/compare.cjs.map +1 -0
- package/dist/formatters/history/compare.d.cts +21 -0
- package/dist/formatters/history/compare.d.cts.map +1 -0
- package/dist/formatters/history/compare.d.ts +21 -0
- package/dist/formatters/history/compare.d.ts.map +1 -0
- package/dist/formatters/history/compare.js +123 -0
- package/dist/formatters/history/compare.js.map +1 -0
- package/dist/formatters/history/list.cjs +74 -0
- package/dist/formatters/history/list.cjs.map +1 -0
- package/dist/formatters/history/list.d.cts +25 -0
- package/dist/formatters/history/list.d.cts.map +1 -0
- package/dist/formatters/history/list.d.ts +25 -0
- package/dist/formatters/history/list.d.ts.map +1 -0
- package/dist/formatters/history/list.js +70 -0
- package/dist/formatters/history/list.js.map +1 -0
- package/dist/formatters/history/show.cjs +98 -0
- package/dist/formatters/history/show.cjs.map +1 -0
- package/dist/formatters/history/show.d.cts +21 -0
- package/dist/formatters/history/show.d.cts.map +1 -0
- package/dist/formatters/history/show.d.ts +21 -0
- package/dist/formatters/history/show.d.ts.map +1 -0
- package/dist/formatters/history/show.js +94 -0
- package/dist/formatters/history/show.js.map +1 -0
- package/dist/formatters/history/trends.cjs +194 -0
- package/dist/formatters/history/trends.cjs.map +1 -0
- package/dist/formatters/history/trends.d.cts +22 -0
- package/dist/formatters/history/trends.d.cts.map +1 -0
- package/dist/formatters/history/trends.d.ts +22 -0
- package/dist/formatters/history/trends.d.ts.map +1 -0
- package/dist/formatters/history/trends.js +190 -0
- package/dist/formatters/history/trends.js.map +1 -0
- package/dist/formatters/history/visualization.cjs +79 -0
- package/dist/formatters/history/visualization.cjs.map +1 -0
- package/dist/formatters/history/visualization.d.cts +24 -0
- package/dist/formatters/history/visualization.d.cts.map +1 -0
- package/dist/formatters/history/visualization.d.ts +24 -0
- package/dist/formatters/history/visualization.d.ts.map +1 -0
- package/dist/formatters/history/visualization.js +74 -0
- package/dist/formatters/history/visualization.js.map +1 -0
- package/dist/index.cjs +27 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -5
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -9
- package/dist/index.js.map +1 -1
- package/dist/reporters/csv.cjs +39 -19
- package/dist/reporters/csv.cjs.map +1 -1
- package/dist/reporters/csv.d.cts +4 -7
- package/dist/reporters/csv.d.cts.map +1 -1
- package/dist/reporters/csv.d.ts +4 -7
- package/dist/reporters/csv.d.ts.map +1 -1
- package/dist/reporters/csv.js +38 -18
- package/dist/reporters/csv.js.map +1 -1
- package/dist/reporters/human.cjs +87 -99
- package/dist/reporters/human.cjs.map +1 -1
- package/dist/reporters/human.d.cts +15 -14
- package/dist/reporters/human.d.cts.map +1 -1
- package/dist/reporters/human.d.ts +15 -14
- package/dist/reporters/human.d.ts.map +1 -1
- package/dist/reporters/human.js +68 -80
- package/dist/reporters/human.js.map +1 -1
- package/dist/reporters/json.cjs +25 -50
- package/dist/reporters/json.cjs.map +1 -1
- package/dist/reporters/json.d.cts +3 -29
- package/dist/reporters/json.d.cts.map +1 -1
- package/dist/reporters/json.d.ts +3 -29
- package/dist/reporters/json.d.ts.map +1 -1
- package/dist/reporters/json.js +26 -51
- 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 +66 -46
- package/dist/reporters/simple.cjs.map +1 -1
- package/dist/reporters/simple.d.cts +15 -15
- package/dist/reporters/simple.d.cts.map +1 -1
- package/dist/reporters/simple.d.ts +15 -15
- package/dist/reporters/simple.d.ts.map +1 -1
- package/dist/reporters/simple.js +65 -45
- 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/{config/manager.cjs → services/config-manager.cjs} +25 -11
- package/dist/services/config-manager.cjs.map +1 -0
- package/dist/{config/manager.d.cts → services/config-manager.d.cts} +7 -2
- package/dist/services/config-manager.d.cts.map +1 -0
- package/dist/{config/manager.d.ts → services/config-manager.d.ts} +7 -2
- package/dist/services/config-manager.d.ts.map +1 -0
- package/dist/{config/manager.js → services/config-manager.js} +25 -11
- package/dist/services/config-manager.js.map +1 -0
- package/dist/{core/loader.cjs → services/file-loader.cjs} +5 -8
- package/dist/services/file-loader.cjs.map +1 -0
- package/dist/{core/loader.d.cts → services/file-loader.d.cts} +1 -1
- package/dist/services/file-loader.d.cts.map +1 -0
- package/dist/{core/loader.d.ts → services/file-loader.d.ts} +1 -1
- package/dist/services/file-loader.d.ts.map +1 -0
- package/dist/{core/loader.js → services/file-loader.js} +5 -8
- package/dist/services/file-loader.js.map +1 -0
- package/dist/services/history/comparison.cjs +124 -0
- package/dist/services/history/comparison.cjs.map +1 -0
- package/dist/services/history/comparison.d.cts +18 -0
- package/dist/services/history/comparison.d.cts.map +1 -0
- package/dist/services/history/comparison.d.ts +18 -0
- package/dist/services/history/comparison.d.ts.map +1 -0
- package/dist/services/history/comparison.js +120 -0
- package/dist/services/history/comparison.js.map +1 -0
- package/dist/services/history/models.cjs +9 -0
- package/dist/services/history/models.cjs.map +1 -0
- package/dist/services/history/models.d.cts +139 -0
- package/dist/services/history/models.d.cts.map +1 -0
- package/dist/services/history/models.d.ts +139 -0
- package/dist/services/history/models.d.ts.map +1 -0
- package/dist/services/history/models.js +8 -0
- package/dist/services/history/models.js.map +1 -0
- package/dist/services/history/query.cjs +97 -0
- package/dist/services/history/query.cjs.map +1 -0
- package/dist/services/history/query.d.cts +38 -0
- package/dist/services/history/query.d.cts.map +1 -0
- package/dist/services/history/query.d.ts +38 -0
- package/dist/services/history/query.d.ts.map +1 -0
- package/dist/services/history/query.js +92 -0
- package/dist/services/history/query.js.map +1 -0
- package/dist/services/history/trend-analysis.cjs +187 -0
- package/dist/services/history/trend-analysis.cjs.map +1 -0
- package/dist/services/history/trend-analysis.d.cts +34 -0
- package/dist/services/history/trend-analysis.d.cts.map +1 -0
- package/dist/services/history/trend-analysis.d.ts +34 -0
- package/dist/services/history/trend-analysis.d.ts.map +1 -0
- package/dist/services/history/trend-analysis.js +179 -0
- package/dist/services/history/trend-analysis.js.map +1 -0
- package/dist/{storage/history.cjs → services/history-storage.cjs} +1 -1
- package/dist/services/history-storage.cjs.map +1 -0
- package/dist/{storage/history.d.cts → services/history-storage.d.cts} +1 -1
- package/dist/services/history-storage.d.cts.map +1 -0
- package/dist/{storage/history.d.ts → services/history-storage.d.ts} +1 -1
- package/dist/services/history-storage.d.ts.map +1 -0
- package/dist/{storage/history.js → services/history-storage.js} +1 -1
- package/dist/services/history-storage.js.map +1 -0
- 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/{progress/manager.cjs → services/progress-manager.cjs} +1 -1
- package/dist/services/progress-manager.cjs.map +1 -0
- package/dist/{progress/manager.d.cts → services/progress-manager.d.cts} +1 -1
- package/dist/services/progress-manager.d.cts.map +1 -0
- package/dist/{progress/manager.d.ts → services/progress-manager.d.ts} +1 -1
- package/dist/services/progress-manager.d.ts.map +1 -0
- package/dist/{progress/manager.js → services/progress-manager.js} +1 -1
- package/dist/services/progress-manager.js.map +1 -0
- package/dist/{reporters/registry.cjs → services/reporter-registry.cjs} +19 -25
- package/dist/services/reporter-registry.cjs.map +1 -0
- package/dist/{reporters/registry.d.cts → services/reporter-registry.d.cts} +19 -41
- package/dist/services/reporter-registry.d.cts.map +1 -0
- package/dist/{reporters/registry.d.ts → services/reporter-registry.d.ts} +19 -41
- package/dist/services/reporter-registry.d.ts.map +1 -0
- package/dist/{reporters/registry.js → services/reporter-registry.js} +19 -25
- package/dist/services/reporter-registry.js.map +1 -0
- 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 -224
- package/dist/types/cli.d.cts.map +1 -1
- package/dist/types/cli.d.ts +3 -224
- 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/ansi.cjs +61 -0
- package/dist/utils/ansi.cjs.map +1 -0
- package/dist/utils/ansi.d.cts +53 -0
- package/dist/utils/ansi.d.cts.map +1 -0
- package/dist/utils/ansi.d.ts +53 -0
- package/dist/utils/ansi.d.ts.map +1 -0
- package/dist/utils/ansi.js +57 -0
- package/dist/utils/ansi.js.map +1 -0
- 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 +14 -13
- package/src/bootstrap.ts +5 -5
- package/src/cli/commands/analyze.ts +101 -0
- package/src/cli/commands/baseline.ts +577 -0
- package/src/cli/commands/history.ts +194 -342
- package/src/cli/commands/init.ts +105 -183
- package/src/cli/commands/run.ts +186 -88
- package/src/cli/index.ts +731 -234
- 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 +153 -14
- package/src/core/output-path-resolver.ts +46 -0
- package/src/errors/base.ts +11 -2
- package/src/errors/budget.ts +38 -0
- package/src/errors/index.ts +3 -0
- package/src/formatters/history/base.ts +28 -0
- package/src/formatters/history/compare.ts +186 -0
- package/src/formatters/history/list.ts +101 -0
- package/src/formatters/history/show.ts +155 -0
- package/src/formatters/history/trends.ts +281 -0
- package/src/formatters/history/visualization.ts +93 -0
- package/src/index.ts +17 -12
- package/src/reporters/csv.ts +55 -26
- package/src/reporters/human.ts +90 -89
- package/src/reporters/json.ts +27 -72
- package/src/reporters/profile-human.ts +204 -0
- package/src/reporters/simple.ts +85 -54
- package/src/services/baseline-storage.ts +199 -0
- package/src/services/budget-evaluator.ts +182 -0
- package/src/{config/manager.ts → services/config-manager.ts} +24 -9
- package/src/{core/loader.ts → services/file-loader.ts} +4 -7
- package/src/services/history/comparison.ts +130 -0
- package/src/services/history/models.ts +148 -0
- package/src/services/history/query.ts +116 -0
- package/src/services/history/trend-analysis.ts +238 -0
- 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/{reporters/registry.ts → services/reporter-registry.ts} +46 -81
- package/src/types/budgets.ts +180 -0
- package/src/types/cli.ts +5 -235
- 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/ansi.ts +59 -0
- package/src/utils/identifiers.ts +58 -0
- package/src/utils/package.ts +35 -0
- package/src/utils/type-guards.ts +51 -0
- package/dist/config/manager.cjs.map +0 -1
- package/dist/config/manager.d.cts.map +0 -1
- package/dist/config/manager.d.ts.map +0 -1
- package/dist/config/manager.js.map +0 -1
- package/dist/core/loader.cjs.map +0 -1
- package/dist/core/loader.d.cts.map +0 -1
- package/dist/core/loader.d.ts.map +0 -1
- package/dist/core/loader.js.map +0 -1
- package/dist/progress/manager.cjs.map +0 -1
- package/dist/progress/manager.d.cts.map +0 -1
- package/dist/progress/manager.d.ts.map +0 -1
- package/dist/progress/manager.js.map +0 -1
- package/dist/reporters/registry.cjs.map +0 -1
- package/dist/reporters/registry.d.cts.map +0 -1
- package/dist/reporters/registry.d.ts.map +0 -1
- package/dist/reporters/registry.js.map +0 -1
- package/dist/storage/history.cjs.map +0 -1
- package/dist/storage/history.d.cts.map +0 -1
- package/dist/storage/history.d.ts.map +0 -1
- package/dist/storage/history.js.map +0 -1
- /package/src/{storage/history.ts → services/history-storage.ts} +0 -0
- /package/src/{progress/manager.ts → services/progress-manager.ts} +0 -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,9 +41,30 @@ import {
|
|
|
32
41
|
SimpleReporter,
|
|
33
42
|
} from '../reporters/index.js';
|
|
34
43
|
// Import commands
|
|
35
|
-
import {
|
|
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';
|
|
55
|
+
import {
|
|
56
|
+
handleCleanCommand,
|
|
57
|
+
handleCompareCommand,
|
|
58
|
+
handleExportCommand,
|
|
59
|
+
handleListCommand,
|
|
60
|
+
handleShowCommand,
|
|
61
|
+
handleTrendsCommand,
|
|
62
|
+
} from './commands/history.js';
|
|
36
63
|
import { handleInitCommand as initCommand } from './commands/init.js';
|
|
37
|
-
import {
|
|
64
|
+
import {
|
|
65
|
+
RUN_COMMAND_DEFAULTS,
|
|
66
|
+
handleRunCommand as runCommand,
|
|
67
|
+
} from './commands/run.js';
|
|
38
68
|
|
|
39
69
|
/**
|
|
40
70
|
* CLI context with initialized services
|
|
@@ -56,28 +86,15 @@ interface GlobalOptions {
|
|
|
56
86
|
/** Configuration file path */
|
|
57
87
|
config?: string | undefined;
|
|
58
88
|
/** Working directory */
|
|
59
|
-
cwd
|
|
89
|
+
cwd?: string;
|
|
60
90
|
/** JSON output for machine parsing */
|
|
61
|
-
json
|
|
91
|
+
json?: boolean;
|
|
62
92
|
/** Disable colored output */
|
|
63
|
-
noColor
|
|
93
|
+
noColor?: boolean;
|
|
64
94
|
/** Enable verbose output */
|
|
65
|
-
verbose
|
|
95
|
+
verbose?: boolean;
|
|
66
96
|
}
|
|
67
97
|
|
|
68
|
-
/**
|
|
69
|
-
* Exit codes for the CLI
|
|
70
|
-
*/
|
|
71
|
-
export const ExitCodes = {
|
|
72
|
-
BENCHMARK_FAILURES: 1,
|
|
73
|
-
CONFIG_ERROR: 2,
|
|
74
|
-
DISCOVERY_ERROR: 3,
|
|
75
|
-
RUNTIME_ERROR: 5,
|
|
76
|
-
SUCCESS: 0,
|
|
77
|
-
UNKNOWN_ERROR: 99,
|
|
78
|
-
VALIDATION_ERROR: 4,
|
|
79
|
-
} as const;
|
|
80
|
-
|
|
81
98
|
/**
|
|
82
99
|
* Initialize and run the CLI
|
|
83
100
|
*/
|
|
@@ -103,7 +120,9 @@ export const main = async (
|
|
|
103
120
|
const cli = yargs(args);
|
|
104
121
|
|
|
105
122
|
// Configure global options and commands
|
|
123
|
+
|
|
106
124
|
await cli
|
|
125
|
+
.scriptName('modestbench')
|
|
107
126
|
.option('config', {
|
|
108
127
|
alias: 'c',
|
|
109
128
|
description: 'Path to configuration file',
|
|
@@ -112,33 +131,34 @@ export const main = async (
|
|
|
112
131
|
})
|
|
113
132
|
.option('verbose', {
|
|
114
133
|
alias: 'v',
|
|
115
|
-
|
|
134
|
+
defaultDescription: String(RUN_COMMAND_DEFAULTS.verbose),
|
|
116
135
|
description: 'Enable verbose output',
|
|
117
136
|
global: true,
|
|
118
137
|
type: 'boolean',
|
|
119
138
|
})
|
|
120
139
|
.option('no-color', {
|
|
121
|
-
|
|
140
|
+
defaultDescription: 'false',
|
|
122
141
|
description: 'Disable colored output',
|
|
123
142
|
global: true,
|
|
124
143
|
type: 'boolean',
|
|
125
144
|
})
|
|
126
145
|
.option('progress', {
|
|
127
|
-
|
|
146
|
+
defaultDescription: 'true',
|
|
128
147
|
description: 'Show animated progress bar',
|
|
129
148
|
global: true,
|
|
130
149
|
type: 'boolean',
|
|
131
150
|
})
|
|
132
151
|
.option('json', {
|
|
133
|
-
|
|
152
|
+
defaultDescription: 'false',
|
|
134
153
|
description: 'Output results in JSON format',
|
|
135
154
|
global: true,
|
|
136
155
|
type: 'boolean',
|
|
137
156
|
})
|
|
138
157
|
.option('cwd', {
|
|
139
|
-
|
|
158
|
+
defaultDescription: '.',
|
|
140
159
|
description: 'Working directory',
|
|
141
160
|
global: true,
|
|
161
|
+
normalize: true,
|
|
142
162
|
type: 'string',
|
|
143
163
|
})
|
|
144
164
|
.help()
|
|
@@ -146,18 +166,18 @@ export const main = async (
|
|
|
146
166
|
.version()
|
|
147
167
|
.alias('version', 'V')
|
|
148
168
|
.strict()
|
|
149
|
-
.demandCommand(1
|
|
169
|
+
.demandCommand(1)
|
|
150
170
|
.recommendCommands()
|
|
151
171
|
.completion()
|
|
152
172
|
.wrap(Math.min(120, cli.terminalWidth()))
|
|
153
173
|
.command(
|
|
154
174
|
['$0 [pattern..]', 'run [pattern..]'],
|
|
155
175
|
'Run benchmark files',
|
|
156
|
-
(yargs) =>
|
|
157
|
-
|
|
176
|
+
(yargs) =>
|
|
177
|
+
yargs
|
|
158
178
|
.positional('pattern', {
|
|
159
179
|
array: true,
|
|
160
|
-
|
|
180
|
+
defaultDescription: '(auto-discovered from bench/ directory)',
|
|
161
181
|
describe:
|
|
162
182
|
'File paths, directory paths, or glob patterns for benchmark files',
|
|
163
183
|
type: 'string',
|
|
@@ -167,26 +187,26 @@ export const main = async (
|
|
|
167
187
|
description: 'Path to configuration file',
|
|
168
188
|
type: 'string',
|
|
169
189
|
})
|
|
170
|
-
.option('
|
|
190
|
+
.option('reporter', {
|
|
171
191
|
alias: 'r',
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return value.flatMap((v) =>
|
|
176
|
-
v.split(',').map((s) => s.trim()),
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
return value.split(',').map((s) => s.trim());
|
|
180
|
-
},
|
|
181
|
-
default: ['human'],
|
|
192
|
+
array: true,
|
|
193
|
+
choices: Object.values(Reporters).sort(),
|
|
194
|
+
defaultDescription: DEFAULT_REPORTER,
|
|
182
195
|
description: 'Output reporters to use (human,json,csv)',
|
|
183
|
-
type: '
|
|
196
|
+
type: 'string',
|
|
184
197
|
})
|
|
185
198
|
.option('output', {
|
|
186
199
|
alias: 'o',
|
|
187
200
|
description: 'Output directory for reports',
|
|
188
201
|
type: 'string',
|
|
189
202
|
})
|
|
203
|
+
.option('output-file', {
|
|
204
|
+
alias: ['of', 'file'],
|
|
205
|
+
description:
|
|
206
|
+
'Custom filename for reporter output (use with single reporter only)',
|
|
207
|
+
requiresArg: true,
|
|
208
|
+
type: 'string',
|
|
209
|
+
})
|
|
190
210
|
.option('iterations', {
|
|
191
211
|
alias: 'i',
|
|
192
212
|
description: 'Number of iterations per benchmark',
|
|
@@ -198,11 +218,12 @@ export const main = async (
|
|
|
198
218
|
type: 'number',
|
|
199
219
|
})
|
|
200
220
|
.option('warmup', {
|
|
201
|
-
alias: 'w',
|
|
221
|
+
alias: ['w', 'warm'],
|
|
202
222
|
description: 'Number of warmup iterations',
|
|
203
223
|
type: 'number',
|
|
204
224
|
})
|
|
205
225
|
.option('limit-by', {
|
|
226
|
+
alias: ['l', 'limit'],
|
|
206
227
|
choices: ['time', 'iterations', 'any', 'all'],
|
|
207
228
|
description:
|
|
208
229
|
'How to limit benchmarks: time (time budget), iterations (sample count), any (either threshold), all (both thresholds)',
|
|
@@ -210,22 +231,15 @@ export const main = async (
|
|
|
210
231
|
})
|
|
211
232
|
.option('bail', {
|
|
212
233
|
alias: 'b',
|
|
213
|
-
|
|
234
|
+
defaultDescription: String(RUN_COMMAND_DEFAULTS.bail),
|
|
214
235
|
description: 'Stop on first failure',
|
|
215
236
|
type: 'boolean',
|
|
216
237
|
})
|
|
217
238
|
.option('exclude', {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (Array.isArray(value)) {
|
|
221
|
-
return value.flatMap((v) =>
|
|
222
|
-
v.split(',').map((s) => s.trim()),
|
|
223
|
-
);
|
|
224
|
-
}
|
|
225
|
-
return value.split(',').map((s) => s.trim());
|
|
226
|
-
},
|
|
239
|
+
alias: 'X',
|
|
240
|
+
array: true,
|
|
227
241
|
description: 'Exclude patterns (comma-separated)',
|
|
228
|
-
type: '
|
|
242
|
+
type: 'string',
|
|
229
243
|
})
|
|
230
244
|
.option('timeout', {
|
|
231
245
|
description: 'Timeout per benchmark in milliseconds',
|
|
@@ -233,40 +247,25 @@ export const main = async (
|
|
|
233
247
|
})
|
|
234
248
|
.option('quiet', {
|
|
235
249
|
alias: 'q',
|
|
236
|
-
|
|
250
|
+
defaultDescription: String(RUN_COMMAND_DEFAULTS.quiet),
|
|
237
251
|
description: 'Minimal output',
|
|
238
252
|
type: 'boolean',
|
|
239
253
|
})
|
|
240
|
-
.option('
|
|
241
|
-
|
|
242
|
-
// Handle comma-separated values
|
|
243
|
-
if (Array.isArray(value)) {
|
|
244
|
-
return value.flatMap((v) =>
|
|
245
|
-
v.split(',').map((s) => s.trim()),
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
return value.split(',').map((s) => s.trim());
|
|
249
|
-
},
|
|
254
|
+
.option('tag', {
|
|
255
|
+
array: true,
|
|
250
256
|
description: 'Include only benchmarks with any of these tags',
|
|
251
|
-
type: '
|
|
257
|
+
type: 'string',
|
|
252
258
|
})
|
|
253
|
-
.option('exclude-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (Array.isArray(value)) {
|
|
257
|
-
return value.flatMap((v) =>
|
|
258
|
-
v.split(',').map((s) => s.trim()),
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
return value.split(',').map((s) => s.trim());
|
|
262
|
-
},
|
|
259
|
+
.option('exclude-tag', {
|
|
260
|
+
alias: 'T',
|
|
261
|
+
array: true,
|
|
263
262
|
description: 'Exclude benchmarks with any of these tags',
|
|
264
|
-
type: '
|
|
263
|
+
type: 'string',
|
|
265
264
|
})
|
|
266
265
|
.option('engine', {
|
|
267
266
|
alias: 'e',
|
|
268
|
-
choices:
|
|
269
|
-
|
|
267
|
+
choices: Object.values(Engines),
|
|
268
|
+
defaultDescription: DEFAULT_ENGINE,
|
|
270
269
|
description:
|
|
271
270
|
'Benchmark engine: tinybench (default) or accurate (requires --allow-natives-syntax)',
|
|
272
271
|
type: 'string',
|
|
@@ -278,12 +277,23 @@ export const main = async (
|
|
|
278
277
|
['$0 run "src/**/*.bench.js"', 'Run specific glob pattern'],
|
|
279
278
|
['$0 run file1.bench.js file2.bench.js', 'Run specific files'],
|
|
280
279
|
['$0 run benchmarks/ tests/perf/', 'Run multiple directories'],
|
|
281
|
-
['$0 run
|
|
280
|
+
['$0 run -r json -r csv', 'Use multiple reporters'],
|
|
282
281
|
['$0 run --iterations 1000', 'Set iteration count'],
|
|
283
282
|
['$0 run --engine accurate', 'Use high-accuracy engine'],
|
|
284
283
|
['$0 run --bail', 'Stop on first failure'],
|
|
285
|
-
])
|
|
286
|
-
|
|
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
|
+
}),
|
|
287
297
|
async (argv) => {
|
|
288
298
|
const context = await createCliContext(
|
|
289
299
|
argv,
|
|
@@ -296,16 +306,17 @@ export const main = async (
|
|
|
296
306
|
cwd: argv.cwd,
|
|
297
307
|
engine: argv.engine,
|
|
298
308
|
exclude: argv.exclude,
|
|
299
|
-
excludeTags: argv['exclude-
|
|
309
|
+
excludeTags: argv['exclude-tag'],
|
|
300
310
|
iterations: argv.iterations,
|
|
301
311
|
json: argv.json,
|
|
302
312
|
noColor: argv.noColor,
|
|
303
313
|
outputDir: argv.output,
|
|
314
|
+
outputFile: argv['output-file'],
|
|
304
315
|
pattern: argv.pattern,
|
|
305
316
|
progress: argv.progress,
|
|
306
317
|
quiet: argv.quiet,
|
|
307
|
-
reporters: argv.
|
|
308
|
-
tags: argv.
|
|
318
|
+
reporters: argv.reporter,
|
|
319
|
+
tags: argv.tag,
|
|
309
320
|
time: argv.time,
|
|
310
321
|
timeout: argv.timeout,
|
|
311
322
|
verbose: argv.verbose,
|
|
@@ -314,111 +325,541 @@ export const main = async (
|
|
|
314
325
|
process.exit(exitCode);
|
|
315
326
|
},
|
|
316
327
|
)
|
|
317
|
-
.command(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
'
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
'
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
328
|
+
.command('history', 'View and manage benchmark history', (yargs) =>
|
|
329
|
+
yargs
|
|
330
|
+
.command(
|
|
331
|
+
'list',
|
|
332
|
+
'List recent benchmark runs',
|
|
333
|
+
(yargs) =>
|
|
334
|
+
yargs
|
|
335
|
+
.option('since', {
|
|
336
|
+
description:
|
|
337
|
+
'Show runs since date (ISO 8601 or relative like "1 week ago")',
|
|
338
|
+
type: 'string',
|
|
339
|
+
})
|
|
340
|
+
.option('until', {
|
|
341
|
+
description:
|
|
342
|
+
'Show runs until date (ISO 8601 or relative like "1 day ago")',
|
|
343
|
+
type: 'string',
|
|
344
|
+
})
|
|
345
|
+
.option('pattern', {
|
|
346
|
+
description: 'Filter by benchmark name pattern',
|
|
347
|
+
type: 'string',
|
|
348
|
+
})
|
|
349
|
+
.option('tag', {
|
|
350
|
+
alias: 't',
|
|
351
|
+
array: true,
|
|
352
|
+
description: 'Filter by tags (comma-separated)',
|
|
353
|
+
type: 'string',
|
|
354
|
+
})
|
|
355
|
+
.option('limit', {
|
|
356
|
+
defaultDescription: '10',
|
|
357
|
+
description: 'Maximum number of results',
|
|
358
|
+
type: 'number',
|
|
359
|
+
})
|
|
360
|
+
.option('format', {
|
|
361
|
+
choices: ['human', 'json', 'csv'] as const,
|
|
362
|
+
defaultDescription: 'human' as const,
|
|
363
|
+
description: 'Output format',
|
|
364
|
+
type: 'string',
|
|
365
|
+
})
|
|
366
|
+
.example([
|
|
367
|
+
['$0 history list', 'List recent benchmark runs'],
|
|
368
|
+
[
|
|
369
|
+
'$0 history list --since "1 week ago"',
|
|
370
|
+
'List runs from last week',
|
|
371
|
+
],
|
|
372
|
+
['$0 history list --limit 20', 'List 20 most recent runs'],
|
|
373
|
+
['$0 history list --format json', 'List runs in JSON format'],
|
|
374
|
+
]),
|
|
375
|
+
async (argv) => {
|
|
376
|
+
const context = await createCliContext(argv, abortController!);
|
|
377
|
+
const exitCode = await handleListCommand(context, {
|
|
378
|
+
cwd: argv.cwd,
|
|
379
|
+
format: argv.format,
|
|
380
|
+
limit: argv.limit,
|
|
381
|
+
pattern: argv.pattern,
|
|
382
|
+
since: argv.since,
|
|
383
|
+
tags: argv.tag,
|
|
384
|
+
until: argv.until,
|
|
385
|
+
verbose: argv.verbose,
|
|
386
|
+
});
|
|
387
|
+
process.exit(exitCode);
|
|
388
|
+
},
|
|
389
|
+
)
|
|
390
|
+
.command(
|
|
391
|
+
'show <run-id>',
|
|
392
|
+
'Show detailed results for a specific run',
|
|
393
|
+
(yargs) =>
|
|
394
|
+
yargs
|
|
395
|
+
.positional('run-id', {
|
|
396
|
+
demandOption: true,
|
|
397
|
+
describe: 'ID of the benchmark run to show',
|
|
398
|
+
type: 'string',
|
|
399
|
+
})
|
|
400
|
+
.option('format', {
|
|
401
|
+
choices: ['human', 'json', 'csv'] as const,
|
|
402
|
+
defaultDescription: 'human' as const,
|
|
403
|
+
description: 'Output format',
|
|
404
|
+
type: 'string',
|
|
405
|
+
})
|
|
406
|
+
.example([
|
|
407
|
+
[
|
|
408
|
+
'$0 history show abc123',
|
|
409
|
+
'Show detailed results for run abc123',
|
|
410
|
+
],
|
|
411
|
+
[
|
|
412
|
+
'$0 history show abc123 --format json',
|
|
413
|
+
'Show run in JSON format',
|
|
414
|
+
],
|
|
415
|
+
]),
|
|
416
|
+
async (argv) => {
|
|
417
|
+
const context = await createCliContext(argv, abortController!);
|
|
418
|
+
const exitCode = await handleShowCommand(context, {
|
|
419
|
+
cwd: argv.cwd,
|
|
420
|
+
format: argv.format,
|
|
421
|
+
runId: argv['run-id'],
|
|
422
|
+
verbose: argv.verbose,
|
|
423
|
+
});
|
|
424
|
+
process.exit(exitCode);
|
|
425
|
+
},
|
|
426
|
+
)
|
|
427
|
+
.command(
|
|
428
|
+
'compare <run-id1> <run-id2>',
|
|
429
|
+
'Compare two benchmark runs',
|
|
430
|
+
(yargs) =>
|
|
431
|
+
yargs
|
|
432
|
+
.positional('run-id1', {
|
|
433
|
+
demandOption: true,
|
|
434
|
+
describe: 'ID of the first benchmark run',
|
|
435
|
+
type: 'string',
|
|
436
|
+
})
|
|
437
|
+
.positional('run-id2', {
|
|
438
|
+
demandOption: true,
|
|
439
|
+
describe: 'ID of the second benchmark run',
|
|
440
|
+
type: 'string',
|
|
441
|
+
})
|
|
442
|
+
.option('format', {
|
|
443
|
+
choices: ['human', 'json'] as const,
|
|
444
|
+
defaultDescription: 'human' as const,
|
|
445
|
+
description: 'Output format',
|
|
446
|
+
type: 'string',
|
|
447
|
+
})
|
|
448
|
+
.example([
|
|
449
|
+
['$0 history compare abc123 def456', 'Compare two runs'],
|
|
450
|
+
[
|
|
451
|
+
'$0 history compare abc123 def456 --format json',
|
|
452
|
+
'Compare in JSON format',
|
|
453
|
+
],
|
|
454
|
+
]),
|
|
455
|
+
async (argv) => {
|
|
456
|
+
const context = await createCliContext(argv, abortController!);
|
|
457
|
+
const exitCode = await handleCompareCommand(context, {
|
|
458
|
+
cwd: argv.cwd,
|
|
459
|
+
format: argv.format,
|
|
460
|
+
runId1: argv['run-id1'],
|
|
461
|
+
runId2: argv['run-id2'],
|
|
462
|
+
verbose: argv.verbose,
|
|
463
|
+
});
|
|
464
|
+
process.exit(exitCode);
|
|
465
|
+
},
|
|
466
|
+
)
|
|
467
|
+
.command(
|
|
468
|
+
'trends [pattern]',
|
|
469
|
+
'Show performance trends over time',
|
|
470
|
+
(yargs) =>
|
|
471
|
+
yargs
|
|
472
|
+
.positional('pattern', {
|
|
473
|
+
describe: 'Filter by benchmark name pattern',
|
|
474
|
+
type: 'string',
|
|
475
|
+
})
|
|
476
|
+
.option('since', {
|
|
477
|
+
description:
|
|
478
|
+
'Show trends since date (ISO 8601 or relative like "1 week ago")',
|
|
479
|
+
type: 'string',
|
|
480
|
+
})
|
|
481
|
+
.option('until', {
|
|
482
|
+
description:
|
|
483
|
+
'Show trends until date (ISO 8601 or relative like "1 day ago")',
|
|
484
|
+
type: 'string',
|
|
485
|
+
})
|
|
486
|
+
.option('tag', {
|
|
487
|
+
alias: 't',
|
|
488
|
+
array: true,
|
|
489
|
+
description: 'Filter by tags (comma-separated)',
|
|
490
|
+
type: 'string',
|
|
491
|
+
})
|
|
492
|
+
.option('limit', {
|
|
493
|
+
description: 'Maximum number of runs to analyze',
|
|
494
|
+
type: 'number',
|
|
495
|
+
})
|
|
496
|
+
.option('all', {
|
|
497
|
+
alias: 'a',
|
|
498
|
+
defaultDescription: 'false',
|
|
499
|
+
description: 'Analyze all runs (ignore limit)',
|
|
500
|
+
type: 'boolean',
|
|
501
|
+
})
|
|
502
|
+
.option('format', {
|
|
503
|
+
choices: ['human', 'json'] as const,
|
|
504
|
+
defaultDescription: 'human' as const,
|
|
505
|
+
description: 'Output format',
|
|
506
|
+
type: 'string',
|
|
507
|
+
})
|
|
508
|
+
.example([
|
|
509
|
+
[
|
|
510
|
+
'$0 history trends',
|
|
511
|
+
'Show performance trends for all benchmarks',
|
|
512
|
+
],
|
|
513
|
+
[
|
|
514
|
+
'$0 history trends --since "1 month ago"',
|
|
515
|
+
'Show trends from last month',
|
|
516
|
+
],
|
|
517
|
+
[
|
|
518
|
+
'$0 history trends "array-*"',
|
|
519
|
+
'Show trends for array benchmarks',
|
|
520
|
+
],
|
|
521
|
+
[
|
|
522
|
+
'$0 history trends --format json',
|
|
523
|
+
'Output trends in JSON format',
|
|
524
|
+
],
|
|
525
|
+
]),
|
|
526
|
+
async (argv) => {
|
|
527
|
+
const context = await createCliContext(argv, abortController!);
|
|
528
|
+
const exitCode = await handleTrendsCommand(context, {
|
|
529
|
+
all: argv.all,
|
|
530
|
+
cwd: argv.cwd,
|
|
531
|
+
format: argv.format,
|
|
532
|
+
limit: argv.limit,
|
|
533
|
+
pattern: argv.pattern,
|
|
534
|
+
since: argv.since,
|
|
535
|
+
tags: argv.tag,
|
|
536
|
+
until: argv.until,
|
|
537
|
+
verbose: argv.verbose,
|
|
538
|
+
});
|
|
539
|
+
process.exit(exitCode);
|
|
540
|
+
},
|
|
541
|
+
)
|
|
542
|
+
.command(
|
|
543
|
+
'clean',
|
|
544
|
+
'Clean up old benchmark history',
|
|
545
|
+
(yargs) =>
|
|
546
|
+
yargs
|
|
547
|
+
.option('max-age', {
|
|
548
|
+
description: 'Remove runs older than this many days',
|
|
549
|
+
type: 'number',
|
|
550
|
+
})
|
|
551
|
+
.option('max-runs', {
|
|
552
|
+
description: 'Keep only this many most recent runs',
|
|
553
|
+
type: 'number',
|
|
554
|
+
})
|
|
555
|
+
.option('max-size', {
|
|
556
|
+
description: 'Keep history under this size in bytes',
|
|
557
|
+
type: 'number',
|
|
558
|
+
})
|
|
559
|
+
.option('yes', {
|
|
560
|
+
alias: 'y',
|
|
561
|
+
description: 'Confirm cleanup without prompting',
|
|
562
|
+
type: 'boolean',
|
|
563
|
+
})
|
|
564
|
+
.option('quiet', {
|
|
565
|
+
default: false,
|
|
566
|
+
description: 'Minimal output',
|
|
567
|
+
type: 'boolean',
|
|
568
|
+
})
|
|
569
|
+
.check((argv) => {
|
|
570
|
+
if (
|
|
571
|
+
!argv['max-age'] &&
|
|
572
|
+
!argv['max-runs'] &&
|
|
573
|
+
!argv['max-size']
|
|
574
|
+
) {
|
|
575
|
+
throw new Error(
|
|
576
|
+
'At least one cleanup criterion must be specified (--max-age, --max-runs, or --max-size)',
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
return true;
|
|
580
|
+
})
|
|
581
|
+
.example([
|
|
582
|
+
[
|
|
583
|
+
'$0 history clean --max-runs 50 --yes',
|
|
584
|
+
'Keep only latest 50 runs',
|
|
585
|
+
],
|
|
586
|
+
[
|
|
587
|
+
'$0 history clean --max-age 30',
|
|
588
|
+
'Preview removing runs older than 30 days',
|
|
589
|
+
],
|
|
590
|
+
[
|
|
591
|
+
'$0 history clean --max-size 10485760',
|
|
592
|
+
'Keep history under 10MB',
|
|
593
|
+
],
|
|
594
|
+
]),
|
|
595
|
+
async (argv) => {
|
|
596
|
+
const context = await createCliContext(argv, abortController!);
|
|
597
|
+
const exitCode = await handleCleanCommand(context, {
|
|
598
|
+
confirm: argv.yes,
|
|
599
|
+
cwd: argv.cwd,
|
|
600
|
+
maxAge: argv['max-age'],
|
|
601
|
+
maxRuns: argv['max-runs'],
|
|
602
|
+
maxSize: argv['max-size'],
|
|
603
|
+
quiet: argv.quiet,
|
|
604
|
+
verbose: argv.verbose,
|
|
605
|
+
});
|
|
606
|
+
process.exit(exitCode);
|
|
607
|
+
},
|
|
608
|
+
)
|
|
609
|
+
.command(
|
|
610
|
+
'export',
|
|
611
|
+
'Export benchmark history to a file',
|
|
612
|
+
(yargs) =>
|
|
613
|
+
yargs
|
|
614
|
+
.option('format', {
|
|
615
|
+
choices: ['json', 'csv'] as const,
|
|
616
|
+
defaultDescription: 'json' as const,
|
|
617
|
+
description: 'Export format',
|
|
618
|
+
type: 'string',
|
|
619
|
+
})
|
|
620
|
+
.option('output', {
|
|
621
|
+
alias: 'o',
|
|
622
|
+
demandOption: true,
|
|
623
|
+
description: 'Output file path',
|
|
624
|
+
type: 'string',
|
|
625
|
+
})
|
|
626
|
+
.option('since', {
|
|
627
|
+
description: 'Export runs since date',
|
|
628
|
+
type: 'string',
|
|
629
|
+
})
|
|
630
|
+
.option('until', {
|
|
631
|
+
description: 'Export runs until date',
|
|
632
|
+
type: 'string',
|
|
633
|
+
})
|
|
634
|
+
.example([
|
|
635
|
+
[
|
|
636
|
+
'$0 history export -o history.json',
|
|
637
|
+
'Export all history to JSON',
|
|
638
|
+
],
|
|
639
|
+
[
|
|
640
|
+
'$0 history export -o history.csv --format csv',
|
|
641
|
+
'Export to CSV',
|
|
642
|
+
],
|
|
643
|
+
[
|
|
644
|
+
'$0 history export -o recent.json --since "1 week ago"',
|
|
645
|
+
'Export recent runs',
|
|
646
|
+
],
|
|
647
|
+
]),
|
|
648
|
+
async (argv) => {
|
|
649
|
+
const context = await createCliContext(argv, abortController!);
|
|
650
|
+
const exitCode = await handleExportCommand(context, {
|
|
651
|
+
cwd: argv.cwd,
|
|
652
|
+
format: argv.format,
|
|
653
|
+
outputPath: argv.output,
|
|
654
|
+
quiet: Boolean(argv.quiet),
|
|
655
|
+
since: argv.since,
|
|
656
|
+
until: argv.until,
|
|
657
|
+
verbose: argv.verbose,
|
|
658
|
+
});
|
|
659
|
+
process.exitCode = exitCode;
|
|
660
|
+
},
|
|
661
|
+
)
|
|
662
|
+
.demandCommand(1, 'You must specify a history subcommand')
|
|
663
|
+
.strict()
|
|
664
|
+
.example([
|
|
665
|
+
['$0 history list', 'List recent benchmark runs'],
|
|
666
|
+
['$0 history show <run-id>', 'Show detailed results'],
|
|
667
|
+
['$0 history compare <run-id1> <run-id2>', 'Compare two runs'],
|
|
668
|
+
['$0 history trends', 'Show performance trends'],
|
|
669
|
+
['$0 history clean --max-runs 50', 'Keep only latest 50 runs'],
|
|
670
|
+
['$0 history export -o data.json', 'Export history'],
|
|
671
|
+
]),
|
|
421
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'],
|
|
861
|
+
]);
|
|
862
|
+
})
|
|
422
863
|
.command(
|
|
423
864
|
'init [type]',
|
|
424
865
|
'Initialize a new benchmark project',
|
|
@@ -426,35 +867,35 @@ export const main = async (
|
|
|
426
867
|
return yargs
|
|
427
868
|
.positional('type', {
|
|
428
869
|
choices: ['basic', 'advanced', 'library'] as const,
|
|
429
|
-
|
|
870
|
+
defaultDescription: 'basic' as const,
|
|
430
871
|
describe: 'Type of project to initialize',
|
|
431
872
|
type: 'string',
|
|
432
873
|
})
|
|
433
874
|
.option('examples', {
|
|
434
|
-
|
|
875
|
+
defaultDescription: 'true',
|
|
435
876
|
description: 'Include example benchmark files',
|
|
436
877
|
type: 'boolean',
|
|
437
878
|
})
|
|
438
879
|
.option('config-type', {
|
|
439
880
|
choices: ['json', 'yaml', 'js', 'ts'] as const,
|
|
440
|
-
|
|
881
|
+
defaultDescription: 'json' as const,
|
|
441
882
|
description: 'Configuration file format',
|
|
442
883
|
type: 'string',
|
|
443
884
|
})
|
|
444
885
|
.option('force', {
|
|
445
|
-
|
|
886
|
+
defaultDescription: 'false',
|
|
446
887
|
description: 'Overwrite existing files',
|
|
447
888
|
type: 'boolean',
|
|
448
889
|
})
|
|
449
890
|
.option('yes', {
|
|
450
891
|
alias: 'y',
|
|
451
|
-
|
|
892
|
+
defaultDescription: 'false',
|
|
452
893
|
description: 'Accept all prompts automatically',
|
|
453
894
|
type: 'boolean',
|
|
454
895
|
})
|
|
455
896
|
.option('quiet', {
|
|
456
897
|
alias: 'q',
|
|
457
|
-
|
|
898
|
+
defaultDescription: 'false',
|
|
458
899
|
description: 'Minimal output',
|
|
459
900
|
type: 'boolean',
|
|
460
901
|
})
|
|
@@ -477,24 +918,87 @@ export const main = async (
|
|
|
477
918
|
cwd: argv.cwd,
|
|
478
919
|
examples: argv.examples,
|
|
479
920
|
force: argv.force,
|
|
480
|
-
quiet:
|
|
921
|
+
quiet: argv.quiet,
|
|
481
922
|
type: argv.type,
|
|
482
923
|
verbose: argv.verbose,
|
|
483
924
|
yes: argv.yes,
|
|
484
925
|
});
|
|
485
|
-
process.
|
|
926
|
+
process.exitCode = exitCode;
|
|
927
|
+
},
|
|
928
|
+
)
|
|
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);
|
|
486
987
|
},
|
|
487
988
|
)
|
|
488
|
-
.fail((msg
|
|
989
|
+
.fail((msg, err, yargs) => {
|
|
489
990
|
if (err) {
|
|
490
991
|
console.error('Error:', err.message);
|
|
491
992
|
if (process.env.DEBUG) {
|
|
492
993
|
console.error(err.stack);
|
|
493
994
|
}
|
|
494
995
|
// Show help for file discovery errors (similar to usage errors)
|
|
495
|
-
if (
|
|
996
|
+
if (
|
|
997
|
+
isModestBenchError(err) &&
|
|
998
|
+
err.code === ErrorCodes.FILE_DISCOVERY_FAILED
|
|
999
|
+
) {
|
|
496
1000
|
console.error();
|
|
497
|
-
|
|
1001
|
+
yargs.showHelp();
|
|
498
1002
|
process.exit(ExitCodes.DISCOVERY_ERROR);
|
|
499
1003
|
}
|
|
500
1004
|
process.exit(ExitCodes.RUNTIME_ERROR);
|
|
@@ -502,7 +1006,7 @@ export const main = async (
|
|
|
502
1006
|
// Show help for usage errors (unknown arguments, etc.)
|
|
503
1007
|
console.error(msg);
|
|
504
1008
|
console.error();
|
|
505
|
-
|
|
1009
|
+
yargs.showHelp();
|
|
506
1010
|
process.exit(ExitCodes.CONFIG_ERROR);
|
|
507
1011
|
}
|
|
508
1012
|
})
|
|
@@ -525,20 +1029,20 @@ export const main = async (
|
|
|
525
1029
|
const createCliContext = async (
|
|
526
1030
|
options: GlobalOptions,
|
|
527
1031
|
abortController: AbortController,
|
|
528
|
-
engineType:
|
|
1032
|
+
engineType: Engine = DEFAULT_ENGINE,
|
|
529
1033
|
): Promise<CliContext> => {
|
|
530
1034
|
try {
|
|
531
1035
|
const dependencies = bootstrap();
|
|
532
1036
|
|
|
533
1037
|
// Select engine based on type
|
|
534
1038
|
const engine =
|
|
535
|
-
engineType ===
|
|
1039
|
+
engineType === Engines.ACCURATE
|
|
536
1040
|
? new AccurateEngine(dependencies)
|
|
537
1041
|
: new TinybenchEngine(dependencies);
|
|
538
1042
|
|
|
539
1043
|
// Register built-in reporters
|
|
540
1044
|
engine.registerReporter(
|
|
541
|
-
|
|
1045
|
+
Reporters.HUMAN,
|
|
542
1046
|
new HumanReporter({
|
|
543
1047
|
color: !options.noColor,
|
|
544
1048
|
verbose: options.verbose,
|
|
@@ -591,7 +1095,7 @@ const createCliContext = async (
|
|
|
591
1095
|
const setupSignalHandlers = (abortController: AbortController): void => {
|
|
592
1096
|
let abortRequested = false;
|
|
593
1097
|
|
|
594
|
-
const handleSignal = (signal:
|
|
1098
|
+
const handleSignal = (signal: NodeJS.Signals) => {
|
|
595
1099
|
if (abortRequested) {
|
|
596
1100
|
// Second signal, force exit
|
|
597
1101
|
console.log(`\nReceived ${signal} again, forcing exit...`);
|
|
@@ -606,36 +1110,29 @@ const setupSignalHandlers = (abortController: AbortController): void => {
|
|
|
606
1110
|
setTimeout(() => {
|
|
607
1111
|
console.log('\nBenchmark aborted.');
|
|
608
1112
|
process.exit(computeExitCode(signal));
|
|
609
|
-
},
|
|
1113
|
+
}, ABORT_TIMEOUT);
|
|
610
1114
|
};
|
|
611
1115
|
|
|
612
|
-
process
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
: new UnknownError(
|
|
633
|
-
reason instanceof Error ? reason.message : String(reason),
|
|
634
|
-
{ cause: reason },
|
|
635
|
-
);
|
|
636
|
-
console.error(wrappedError.toString());
|
|
637
|
-
process.exit(ExitCodes.RUNTIME_ERROR);
|
|
638
|
-
});
|
|
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
|
+
});
|
|
639
1136
|
};
|
|
640
1137
|
|
|
641
1138
|
// Run CLI if this file is executed directly
|
|
@@ -663,6 +1160,6 @@ try {
|
|
|
663
1160
|
* @param signal - The signal that caused the exit
|
|
664
1161
|
* @returns The exit code
|
|
665
1162
|
*/
|
|
666
|
-
const computeExitCode = (signal:
|
|
1163
|
+
const computeExitCode = (signal: NodeJS.Signals): number => {
|
|
667
1164
|
return 128 + (signal === 'SIGINT' ? 2 : signal === 'SIGQUIT' ? 3 : 15);
|
|
668
1165
|
};
|