Skip to content

Commit acf7dda

Browse files
authored
feat(history): implement trend analysis and comparison (#64)
feat: implement date parsing, compare, and trend analysis core - Add relative date parsing (ISO 8601, relative expressions, shorthand) - Enhance compare subcommand with detailed task-by-task comparisons - Implement core trend analysis functions (statistics, trend direction, percent change, regression detection) - Add visualization helpers (sparklines, bar charts, synthwave colors) - Comprehensive unit tests for all new functionality feat: implement full trends command with visualizations - Complete handleTrendsCommand with task-level trend analysis - Build trend data from historical runs across all tasks - Generate human output with synthwave-colored sparklines and bar charts - Show performance summary with improving/degrading/stable counts - Display regression warnings for tasks exceeding 5% threshold - Show performance distribution histogram for top task - Comprehensive JSON output with summary, trends, and regressions - Sort tasks by absolute percent change (most significant first) test: add comprehensive integration tests for trends command - Test trends output for multiple runs with task-level analysis - Verify JSON format output with summary and trends data - Test limit option for restricting analyzed runs - Verify handling of empty history - Test date range filtering (--since flag) docs: expand historical tracking section with comprehensive documentation - Document enhanced compare command with task-by-task analysis - Add complete trends command documentation with examples - Document date range filtering (ISO 8601, relative, shorthand formats) - Include example JSON output structures for compare and trends - Add CI/CD integration examples with regression detection script - Document trend analysis features: statistics, regression detection, visualizations - Show examples of sparklines and bar chart histogram output feat(history): implement trends and comparison ...and make everything look ELiTE docs(guides): update advanced guide with new history capabilities chore(ai): update AGENTS.md
1 parent d5fb662 commit acf7dda

35 files changed

+6862
-583
lines changed

AGENTS.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
# ModestBench Development Guide
1+
# modestbench Development Guide
22

33
## Project-Specific Practices
44

5+
### Stylized Name
6+
7+
In Markdown text, refer to the name of this project as `**modestbench**` (bold) instead of `ModestBench` or `Modestbench`.
8+
59
### Git Workflow
610

711
**Linear History Required:**

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
"prepack": "run-s -s clean build",
8686
"prepare": "husky; run-s -s build",
8787
"pretest:base": "run-s -s build:compile",
88+
"start": "node dist/cli/index.js",
8889
"test": "run-s -s test:runtime test:types",
8990
"test:base": "node --import tsx --test --test-reporter=spec",
9091
"test:contract": "npm run test:base -- \"test/contract/**/*.test.ts\"",

public/demos/history-compare.cast

Lines changed: 12 additions & 0 deletions
Large diffs are not rendered by default.

public/demos/history-list.cast

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{"version":3,"term":{"cols":81,"rows":52,"type":"xterm-256color","version":"iTerm2 3.6.0beta4","theme":{"fg":"#dcdcdc","bg":"#15191e","palette":"#15181d:#a74532:#57bf37:#c7c53f:#2d43c0:#b249b9:#59c3c6:#c7c7c7:#686868:#d07e78:#82e498:#ebe24a:#a8abed:#d483dc:#8efafe:#ffffff"}},"timestamp":1761365328,"idle_time_limit":0.5,"command":"bash -c 'node /Users/boneskull/projects/boneskull/modestbench/worktrees/history-subcommands/dist/cli/index.js history list --limit 5'","env":{"SHELL":"/bin/zsh"}}
2+
[0.128884, "o", "\u001b[95m\u001b[1m\r\nRecent Benchmark Runs\u001b[0m\u001b[0m\r\n\r\n \u001b[91m×\u001b[0m \u001b[97m\u001b[1m077ua0l\u001b[0m\u001b[0m \u001b[2m•\u001b[0m \u001b[90m2025-10-25T00:30:05.088Z\u001b[0m \u001b[2m•\u001b[0m \u001b[95m2.7s\u001b[0m\r\n \u001b[2m5 files, 20 tasks:\u001b[0m \u001b[96m19 passed\u001b[0m, \u001b[91m1 failed\u001b[0m\r\n\r\n \u001b[91m×\u001b[0m \u001b[97m\u001b[1m0ib2kx7\u001b[0m\u001b[0m \u001b[2m•\u001b[0m \u001b[90m2025-10-25T00:30:01.245Z\u001b[0m \u001b[2m•\u001b[0m \u001b[95m2.7s\u001b[0m\r\n \u001b[2m5 files, 20 tasks:\u001b[0m \u001b[96m19 passed\u001b[0m, \u001b[91m1 failed\u001b[0m\r\n\r\n \u001b[91m×\u001b[0m \u001b[97m\u001b[1m01skdlo\u001b[0m\u001b[0m \u001b[2m•\u001b[0m \u001b[90m2025-10-25T00:29:57.416Z\u001b[0m \u001b[2m•\u001b[0m \u001b[95m2.7s\u001b[0m\r\n \u001b[2m5 files, 20 tasks:\u001b[0m \u001b[96m19 passed\u001b[0m, \u001b[91m1 failed\u001b[0m\r\n\r\n \u001b[91m×\u001b[0m \u001b[97m\u001b[1m1dmesmx\u001b[0m\u001b[0m \u001b[2m•\u001b[0m \u001b[90m2025-10-25T00:29:53.584Z\u001b[0m \u001b[2m•\u001b[0m \u001b[95m2.7s\u001b[0m\r\n \u001b[2m5 files, 20 tasks:\u001b[0m \u001b[96m19 passed\u001b[0m, \u001b[91m1 failed\u001b[0m\r\n\r\n \u001b[91m×\u001b[0m \u001b[97m\u001b[1m1mtos59\u001b[0m\u001b[0m \u001b[2m•\u001b[0m \u001b[90m2025-10-25T00:29:49.790Z\u001b[0m \u001b[2m•\u001b[0m \u001b[95m2.7s\u001b[0m\r\n \u001b[2m5 files, 20 tasks:\u001b[0m \u001b[96m19 passed\u001b[0m, \u001b[91m1 failed\u001b[0m\r\n\r\n"]
3+
[0.001899, "x", "0"]

public/demos/history-show.cast

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{"version":3,"term":{"cols":81,"rows":25,"type":"xterm-256color","version":"iTerm2 3.6.0beta4","theme":{"fg":"#dcdcdc","bg":"#15191e","palette":"#15181d:#a74532:#57bf37:#c7c53f:#2d43c0:#b249b9:#59c3c6:#c7c7c7:#686868:#d07e78:#82e498:#ebe24a:#a8abed:#d483dc:#8efafe:#ffffff"}},"timestamp":1761365519,"idle_time_limit":0.5,"command":"bash -c 'node /Users/boneskull/projects/boneskull/modestbench/worktrees/history-subcommands/dist/cli/index.js history show \"077ua0l\"'","env":{"SHELL":"/bin/zsh"}}
2+
[0.119227, "o", "\u001b[36m\u001b[1m\r\nBenchmark Run: \u001b[97m\u001b[1m077ua0l\u001b[0m\u001b[0m\u001b[0m\u001b[0m\r\n \u001b[96m•\u001b[0m \u001b[37m2025-10-25T00:30:05.088Z\u001b[0m\r\n \u001b[96m•\u001b[0m \u001b[37mDuration:\u001b[0m \u001b[35m2.7s\u001b[0m\r\n \u001b[96m•\u001b[0m Node.js \u001b[97mv24.10.0\u001b[0m on \u001b[97mdarwin\u001b[0m (\u001b[97marm64\u001b[0m)\r\n \u001b[96m•\u001b[0m \u001b[97m16\u001b[0m cores @ \u001b[97m2400MHz\u001b[0m on \u001b[97mApple M4 Max\u001b[0m\r\n\r\n\u001b[36mSummary\u001b[0m\r\n \u001b[2m▪\u001b[0m Files: \u001b[97m5\u001b[0m\r\n \u001b[2m▪\u001b[0m Suites: \u001b[97m9\u001b[0m\r\n \u001b[2m▪\u001b[0m Tasks: \u001b[97m20\u001b[0m\r\n \u001b[2m▪\u001b[0m Passed: \u001b[96m19\u001b[0m\r\n \u001b[2m▪\u001b[0m Failed: \u001b[91m\u001b[1m1\u001b[0m\u001b[0m\r\n\r\n\u001b[36mResults\u001b[0m\r\n\r\n\u001b[2m•\u001b[0m \u001b[95m\u001b[1mexamples/benchmarks/advanced-operations.bench.js\u001b[0m\u001b[0m\r\n \u001b[2m•\u001b[0m \u001b[97mArray Algorithms\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mArray.findIndex()\u001b[0m: \u001b[95m166.67ns\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±0.01\u001b[0m \u001b[2m•\u001b[0m \u001b[35m6,384,665\u001b[0m ops/sec\r\n \u001b[2m4171 iterations, cv: 0.3%\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mLinear Search\u001b[0m: \u001b[95m166.67ns\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±0.01\u001b[0m \u001b[2m•\u001b[0m \u001b[35m5,997,911\u001b[0m ops/sec\r\n \u001b[2m4670 iterations, cv: 0.3%\u001b[0m\r\n \u001b[2m•\u001b[0m \u001b[97mString Ope"]
3+
[0.00002, "o", "rations\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mRegExp.test()\u001b[0m: \u001b[95m24.31ns\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±0.20\u001b[0m \u001b[2m•\u001b[0m \u001b[35m30,931,045\u001b[0m ops/sec\r\n \u001b[2m40650 iterations, cv: 84.9%\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mString.includes()\u001b[0m: \u001b[95m17.61ns\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±0.17\u001b[0m \u001b[2m•\u001b[0m \u001b[35m42,710,902\u001b[0m ops/sec\r\n \u001b[2m56395 iterations, cv: 117.0%\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mString.indexOf()\u001b[0m: \u001b[95m18.55ns\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±0.18\u001b[0m \u001b[2m•\u001b[0m \u001b[35m40,550,467\u001b[0m ops/sec\r\n \u001b[2m53814 iterations, cv: 111.8%\u001b[0m\r\n\r\n\u001b[2m•\u001b[0m \u001b[95m\u001b[1mexamples/benchmarks/array-operations.bench.js\u001b[0m\u001b[0m\r\n \u001b[2m•\u001b[0m \u001b[97mArray Operations\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mArray.push()\u001b[0m: \u001b[95m41.67ns\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±0.01\u001b[0m \u001b[2m•\u001b[0m \u001b[35m23,940,091\u001b[0m ops/sec\r\n \u001b[2m22628 iterations, cv: 1.1%\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mArray.unshift()\u001b[0m: \u001b[95m106.03ns\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±0.44\u001b[0m \u001b[2m•\u001b[0m \u001b[35m9,836,996\u001b[0m ops/sec\r\n \u001b[2m9403 iterations, cv: 20.4%\u001b[0m\r\n\r\n\u001b[2m•\u001b[0m \u001b[95m\u001b[1mexamples/be"]
4+
[0.000025, "o", "nchmarks/async-operations.bench.js\u001b[0m\u001b[0m\r\n \u001b[2m•\u001b[0m \u001b[97mAsync Operations\u001b[0m\r\n \u001b[91m×\u001b[0m \u001b[37mFailing Benchmark\u001b[0m \u001b[2m•\u001b[0m \u001b[91mfailed\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mFetch Simulation With A Really Long Name For A Task Because It I Wanna See What Happens\u001b[0m: \u001b[95m1.169ms\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±1704.75\u001b[0m \u001b[2m•\u001b[0m \u001b[35m1,392\u001b[0m ops/sec\r\n \u001b[2m185 iterations, cv: 1.0%\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mPromise.resolve()\u001b[0m: \u001b[95m83.33ns\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±0.01\u001b[0m \u001b[2m•\u001b[0m \u001b[35m12,632,631\u001b[0m ops/sec\r\n \u001b[2m10438 iterations, cv: 0.6%\u001b[0m\r\n \u001b[2m•\u001b[0m \u001b[97mSingle Task Suite\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37msetTimeout Promise\u001b[0m: \u001b[95m1.169ms\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±1059.58\u001b[0m \u001b[2m•\u001b[0m \u001b[35m1,619\u001b[0m ops/sec\r\n \u001b[2m166 iterations, cv: 0.6%\u001b[0m\r\n\r\n\u001b[2m•\u001b[0m \u001b[95m\u001b[1mexamples/benchmarks/performance-tips.bench.js\u001b[0m\u001b[0m\r\n \u001b[2m•\u001b[0m \u001b[97mIteration Examples\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mArray Access\u001b[0m: \u001b[95m18.32ns\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±0.18\u001b[0m \u001b[2m•\u001b[0m \u001b[35m40,401,037\u001b[0m ops/s"]
5+
[0.000009, "o", "ec\r\n \u001b[2m53198 iterations, cv: 114.0%\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mHeavy Computation\u001b[0m: \u001b[95m403.580µs\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±469.15\u001b[0m \u001b[2m•\u001b[0m \u001b[35m2,457\u001b[0m ops/sec\r\n \u001b[2m176 iterations, cv: 0.8%\u001b[0m\r\n \u001b[2m•\u001b[0m \u001b[97mOptimization Examples\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mFast Benchmark\u001b[0m: \u001b[95m119.793µs\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±453.20\u001b[0m \u001b[2m•\u001b[0m \u001b[35m8,317\u001b[0m ops/sec\r\n \u001b[2m190 iterations, cv: 2.7%\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mSlow Benchmark\u001b[0m: \u001b[95m40.457µs\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±62.29\u001b[0m \u001b[2m•\u001b[0m \u001b[35m24,625\u001b[0m ops/sec\r\n \u001b[2m190 iterations, cv: 1.1%\u001b[0m\r\n \u001b[2m•\u001b[0m \u001b[97mSorting Algorithms\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mBubble Sort\u001b[0m: \u001b[95m1.173ms\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±4168.76\u001b[0m \u001b[2m•\u001b[0m \u001b[35m851\u001b[0m ops/sec\r\n \u001b[2m196 iterations, cv: 2.5%\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mNative Sort\u001b[0m: \u001b[95m65.819µs\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±55.21\u001b[0m \u001b[2m•\u001b[0m \u001b[35m15,259\u001b[0m ops/sec\r\n \u001b[2m137 iterations, cv: 0.5%\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mQuick Sort\u001b[0m: \u001b[95m62.633µs\u001b[0m"]
6+
[0.000005, "o", " \u001b[2m•\u001b[0m \u001b[94m±328.32\u001b[0m \u001b[2m•\u001b[0m \u001b[35m15,987\u001b[0m ops/sec\r\n \u001b[2m181 iterations, cv: 3.6%\u001b[0m\r\n\r\n\u001b[2m•\u001b[0m \u001b[95m\u001b[1mexamples/benchmarks/typescript-example.bench.ts\u001b[0m\u001b[0m\r\n \u001b[2m•\u001b[0m \u001b[97mTypeScript Array Processing\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mArray.map() + reduce()\u001b[0m: \u001b[95m9.273µs\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±10.15\u001b[0m \u001b[2m•\u001b[0m \u001b[35m108,365\u001b[0m ops/sec\r\n \u001b[2m183 iterations, cv: 0.8%\u001b[0m\r\n \u001b[96m√\u001b[0m \u001b[37mArray.reduce()\u001b[0m: \u001b[95m314.67ns\u001b[0m \u001b[2m•\u001b[0m \u001b[94m±0.77\u001b[0m \u001b[2m•\u001b[0m \u001b[35m3,159,416\u001b[0m ops/sec\r\n \u001b[2m2785 iterations, cv: 6.6%\u001b[0m\r\n\r\n"]
7+
[0.002009, "x", "0"]

public/demos/history-trends.cast

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{"version":3,"term":{"cols":81,"rows":52,"type":"xterm-256color","version":"iTerm2 3.6.0beta4","theme":{"fg":"#dcdcdc","bg":"#15191e","palette":"#15181d:#a74532:#57bf37:#c7c53f:#2d43c0:#b249b9:#59c3c6:#c7c7c7:#686868:#d07e78:#82e498:#ebe24a:#a8abed:#d483dc:#8efafe:#ffffff"}},"timestamp":1761365328,"idle_time_limit":0.5,"command":"bash -c 'node /Users/boneskull/projects/boneskull/modestbench/worktrees/history-subcommands/dist/cli/index.js history trends --limit 10'","env":{"SHELL":"/bin/zsh"}}
2+
[0.115998, "o", "\u001b[95m\u001b[1m\r\nPerformance Trends (10 runs)\u001b[0m\u001b[0m\r\n\u001b[2mTime range: 10/24/2025 to 10/24/2025\u001b[0m\r\n\r\n\u001b[94mSummary:\u001b[0m\r\n \u001b[96m▲\u001b[0m 1 improving \u001b[91m▼\u001b[0m 6 degrading \u001b[2m→\u001b[0m 12 stable\r\n\r\n\u001b[95mTask Performance Summary:\u001b[0m\r\n\r\n \u001b[91m▼\u001b[0m \u001b[37mSorting Algorithms › Quick Sort\u001b[0m \u001b[91m +12.8%\u001b[0m \u001b[91m▁▄▄▄▆▁█▂▆▆\u001b[0m\r\n \u001b[91m▼\u001b[0m \u001b[37mSorting Algorithms › Native Sort\u001b[0m \u001b[91m +10.2%\u001b[0m \u001b[91m▂█▁▃▃██▄█▇\u001b[0m\r\n \u001b[91m▼\u001b[0m \u001b[37mString Operations › RegExp.test()\u001b[0m \u001b[91m +10.2%\u001b[0m \u001b[91m▁▂▄▆▇▅▅█▇█\u001b[0m\r\n \u001b[91m▼\u001b[0m \u001b[37mIteration Examples › Array Access\u001b[0m \u001b[91m +10.1%\u001b[0m \u001b[91m▃▂▂▂▅▅▃▁▂█\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mTypeScript Array Processing › Array.map() + reduce()\u001b[0m \u001b[91m +9.7%\u001b[0m \u001b[36m▁██▁▁▁▂▂█▇\u001b[0m\r\n \u001b[91m▼\u001b[0m \u001b[37mArray Operations › Array.unshift()\u001b[0m "]
3+
[0.000013, "o", "\u001b[91m +9.5%\u001b[0m \u001b[91m▁▁▁▂█▅▇▆▄▇\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mOptimization Examples › Fast Benchmark\u001b[0m \u001b[96m -8.6%\u001b[0m \u001b[36m█▁▁▁▃▃▁▄▁▂\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mString Operations › String.includes()\u001b[0m \u001b[2m +4.7%\u001b[0m \u001b[36m▁▆▂▆▅█▆█▆▄\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mIteration Examples › Heavy Computation\u001b[0m \u001b[2m +3.2%\u001b[0m \u001b[36m▄▂▄▂▅▁▆▂▃█\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mString Operations › String.indexOf()\u001b[0m \u001b[2m +3.1%\u001b[0m \u001b[36m▄▅▅▅▁▄▅▄█▆\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mSorting Algorithms › Bubble Sort\u001b[0m \u001b[2m -2.6%\u001b[0m \u001b[36m▅▁▃▁▁▃▃▄█▃\u001b[0m\r\n \u001b[91m▼\u001b[0m \u001b[37mTypeScript Array Processing › Array.reduce()\u001b[0m \u001b[2m +2.0%\u001b[0m \u001b[91m▁▁▁▁█▁▁▁█▁\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mOptimization Examples › Slow Benchmark\u001b[0m \u001b[2m +1.4%\u001b[0m \u001b[36m▁▅█▇▃▂"]
4+
[0.000011, "o", "▂▄▄▄\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mAsync Operations › Fetch Simulation With A Really Long Name For A Task Because It I Wanna See What Happens\u001b[0m\r\n \u001b[2m +0.4%\u001b[0m \u001b[36m▁▇▆▆▅█▅▇█▄\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mSingle Task Suite › setTimeout Promise\u001b[0m \u001b[2m +0.2%\u001b[0m \u001b[36m▁▄█▂█▆▆▆▄▂\u001b[0m\r\n \u001b[96m▲\u001b[0m \u001b[37mAsync Operations › Promise.resolve()\u001b[0m \u001b[2m +0.0%\u001b[0m \u001b[96m▁▁█▁▁▁▁▁▁▁\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mArray Algorithms › Array.findIndex()\u001b[0m \u001b[2m +0.0%\u001b[0m \u001b[36m▃▄▁▁▁▂▁█▄█\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mArray Operations › Array.push()\u001b[0m \u001b[2m -0.0%\u001b[0m \u001b[36m▅▁█▁▃▂▇▆▁▂\u001b[0m\r\n \u001b[2m→\u001b[0m \u001b[37mArray Algorithms › Linear Search\u001b[0m \u001b[2m +0.0%\u001b[0m \u001b[36m▄▆▄▄▄▄▄▁█▄\u001b[0m\r\n\r\n\u001b[91m\u001b[1mRegressions Detected:\u001b[0m\u001b[0m\r\n\r\n \u001b[91m"]
5+
[0.000003, "o", "▼\u001b[0m \u001b[37mSorting Algorithms › Quick Sort\u001b[0m: \u001b[91m12.8% slower\u001b[0m (10 runs)\r\n \u001b[91m▼\u001b[0m \u001b[37mSorting Algorithms › Native Sort\u001b[0m: \u001b[91m10.2% slower\u001b[0m (10 runs)\r\n \u001b[91m▼\u001b[0m \u001b[37mString Operations › RegExp.test()\u001b[0m: \u001b[91m10.2% slower\u001b[0m (10 runs)\r\n \u001b[91m▼\u001b[0m \u001b[37mIteration Examples › Array Access\u001b[0m: \u001b[91m10.1% slower\u001b[0m (10 runs)\r\n \u001b[91m▼\u001b[0m \u001b[37mArray Operations › Array.unshift()\u001b[0m: \u001b[91m9.5% slower\u001b[0m (10 runs)\r\n\r\n\u001b[95mPerformance Distribution (most variable task):\u001b[0m\r\n\u001b[37mTypeScript Array Processing › Array.reduce()\u001b[0m\r\n\u001b[2m Variability: 147.6%\u001b[0m\r\n\r\n\u001b[96m █████████████████████████ 0.30-1.19µs (8 runs)\u001b[0m\r\n\u001b[96m ██████░░░░░░░░░░░░░░░░░░░ 3.83-4.71µs (2 runs)\u001b[0m\r\n\r\n\u001b[2m Mean: 0.001ms Median: 0.000ms StdDev: 0.002ms\u001b[0m\r\n\r\n"]
6+
[0.001901, "x", "0"]

scripts/README-demos.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Recording History Command Demos
2+
3+
This directory contains scripts to generate asciinema recordings of ModestBench history commands for documentation. The `.cast` files can be embedded in documentation using the AsciinemaPlayer component.
4+
5+
## Quick Start
6+
7+
Record all history command demos:
8+
9+
```bash
10+
./scripts/record-all-history-demos.sh
11+
```
12+
13+
This generates `.cast` files to `public/demos/` for use in site documentation.
14+
15+
## Individual Scripts
16+
17+
### Record All Demos
18+
19+
```bash
20+
./scripts/record-all-history-demos.sh [output-directory]
21+
```
22+
23+
Records all history command demos in sequence. Generates:
24+
25+
- `history-list.cast`
26+
- `history-show.cast`
27+
- `history-compare.cast`
28+
- `history-trends.cast`
29+
30+
### Record History List
31+
32+
```bash
33+
./scripts/record-history-list.sh [output-file]
34+
```
35+
36+
Records the `modestbench history list` command showing recent runs.
37+
38+
**Output:** `public/demos/history-list.cast` (default)
39+
40+
### Record History Show
41+
42+
```bash
43+
./scripts/record-history-show.sh [output-file] [run-id]
44+
```
45+
46+
Records the `modestbench history show` command for a specific run.
47+
48+
**Output:** `public/demos/history-show.cast` (default)
49+
**Run ID:** Auto-detected from latest run if not provided
50+
51+
### Record History Compare
52+
53+
```bash
54+
./scripts/record-history-compare.sh [output-file] [run-id-1] [run-id-2]
55+
```
56+
57+
Records the `modestbench history compare` command comparing two runs.
58+
59+
**Output:** `public/demos/history-compare.cast` (default)
60+
**Run IDs:** Auto-detected from last 2 runs if not provided
61+
62+
### Record History Trends
63+
64+
```bash
65+
./scripts/record-history-trends.sh [output-file]
66+
```
67+
68+
Records the `modestbench history trends` command with trend analysis and visualizations.
69+
70+
**Output:** `public/demos/history-trends.cast` (default)
71+
72+
## Using in Documentation
73+
74+
Once generated, reference the `.cast` files in Astro components:
75+
76+
```astro
77+
---
78+
import { AsciinemaPlayer } from '@components/AsciinemaPlayer.astro';
79+
---
80+
81+
<AsciinemaPlayer src="/demos/history-list.cast" />
82+
```
83+
84+
## Environment Variables
85+
86+
All scripts respect `FORCE_COLOR=1` for colored output (enabled by default).
87+
88+
## Requirements
89+
90+
- `asciinema` command-line tool installed
91+
- ModestBench with historical data (at least 1 run for `list`, 2 runs for `compare`, etc.)
92+
- bash shell
93+
94+
Install asciinema:
95+
96+
```bash
97+
npm install -g asciinema
98+
# or
99+
brew install asciinema
100+
```
101+
102+
## Notes
103+
104+
- Scripts use idle time of 0.5 seconds between commands for readability
105+
- Empty lines are removed for cleaner playback
106+
- Color output is forced to ensure ANSI codes are captured
107+
- Run ID detection is automatic; provide explicit IDs to override

0 commit comments

Comments
 (0)