Skip to content

feat: TUI pipeline builder (Phase 1 MVP) + auto-versioning#92

Merged
benbernard merged 5 commits intomasterfrom
issue-cleanups
Feb 23, 2026
Merged

feat: TUI pipeline builder (Phase 1 MVP) + auto-versioning#92
benbernard merged 5 commits intomasterfrom
issue-cleanups

Conversation

@benbernard
Copy link
Owner

Summary

TUI Pipeline Builder (Phase 1 MVP)

Interactive TUI for building RecordStream pipelines, built with OpenTUI + React.

  • Vertical split-pane layout: Pipeline stage list (left) + data inspector (right)
  • Operation picker: Categorized (input/transform/output) with fuzzy search and preview pane
  • Live data inspection: Auto-updates when navigating between stages. Table, prettyprint, and JSON views.
  • Pipeline executor: Reuses all existing RecordStream operations via createOperation(). Handles line-oriented, bulk-content, and self-contained input ops.
  • Export: x copies pipeline as shell pipe script to clipboard. X opens format picker (pipe script / chain command / save to file).
  • Undo/redo: Full undo/redo on all structural pipeline edits (add/delete/edit/toggle/reorder stages). 200-entry stack.
  • Smart caching: Cache invalidation cascades downstream when a stage is edited. Record count ratios shown in inspector header.
  • Error handling: Inline error indicators on failed stages, downstream stages greyed out, error details in inspector.
  • Keyboard-first: vim-style navigation (j/k), context-sensitive key hints in status bar, help panel (?).
  • Entry point: recs tui [file] or recs tui --help

New files: 32 source files under src/tui/ + bin/recs-tui.ts

Auto-Versioning

  • Release workflow auto-increments patch version from git tags on every merge to master
  • No manual version bumps needed — git tags are the source of truth
  • package.json version stamped into build artifacts but not committed back

Advisory Benchmarks

  • Benchmark CI step never fails the build (advisory-only)
  • PR comment includes note about GitHub Actions runner variance
  • Short summary at top with collapsible details section

Test plan

  • 920 tests pass (0 failures)
  • TypeScript type-check clean
  • Lint clean (only pre-existing warning)
  • 88 TUI-specific tests: reducer (42), executor (18), serialization (17), integration (11)
  • Fuzzy search tests (13+)
  • UX review completed — all P0/P1 issues resolved
  • QA verification pass — all imports resolve, CLI entry points work

🤖 Generated with Claude Code

benbernard and others added 5 commits February 22, 2026 07:29
Implements the core data model for the TUI pipeline builder:
- types.ts: All TypeScript types (Stage, Fork, PipelineState, PipelineAction union, etc.)
- reducer.ts: pipelineReducer with undo/redo middleware, all action handlers
- selectors.ts: getActivePath, isDownstreamOfError, getStageOutput, etc.
- undo.ts: extractSnapshot, describeAction, UNDOABLE_ACTIONS set

Also fixes OpenTUI prop usage (color -> fg, backgroundColor -> bg) in modal
components to resolve type errors.

Includes 42 unit tests covering add/delete/move stages, undo/redo,
toggle enabled, error propagation, cursor movement, and selectors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wire `recs tui` subcommand in bin/recs.ts (spawns bin/recs-tui.ts)
- Add bin/recs-tui.ts CLI entry with --session, --pipeline, --list, --clean
- Add src/tui/index.tsx with launchTui() using OpenTUI React renderer
- Add src/tui/components/App.tsx root component with welcome/main scaffolding
- Add src/tui/utils/fuzzy-match.ts for AddStageModal search (13 tests)
- Configure tsconfig.json for JSX (react-jsx, @opentui/react, .tsx includes)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- serialization.ts: exportAsPipeScript() for multi-line shell scripts
  with shebang and proper shellEscape(), exportAsChainCommand() for
  single-line recs chain format, copyToClipboard() via pbcopy/xclip
- ExportPicker.tsx: format picker modal (pipe script / chain / save)
- 17 tests for shell escaping, pipe script output, and chain format

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
11 integration tests exercising the real reducer, executor, and
operations together:
- Full pipeline lifecycle (grep → sort, grep → sort → collate)
- Undo/redo with execution verification
- Cache invalidation after stage modification
- Error propagation and isDownstreamOfError
- Export round-trip (pipe script and chain command)
- Toggle stage enabled/disabled during execution
- Large pipeline (10 stages) with full path execution
- Input op integration (fromcsv with file input)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix P0 bug where UPDATE_STAGE_ARGS and TOGGLE_STAGE did not invalidate
cache entries, causing the inspector to show stale results after editing
a stage's arguments or toggling enabled state. Cache invalidation now
cascades to all downstream stages in the fork.

Wire missing keybindings: x (export pipe script), X (ExportPicker),
r (re-run from cursor), t (cycle inspector view), J/K (reorder stages),
v (export records to temp file), Ctrl+C (quit). Remove Phase 2+
shortcuts (f, b, i, p) from HelpPanel and StatusBar.

Additional UX fixes: auto-calculate RecordTable column widths from data,
show "N of M records (X%)" ratio in InspectorHeader, increase pipeline
panel width from 28 to 32.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link

Performance Benchmark Results

⚠️ 12 regressions detected out of 103 benchmarks (threshold: 25%)

Benchmark Median Baseline Delta
InputStream.fromString — 100 records 376.0µs 216.7µs +73.5% 🔴
Compiled KeySpec.resolveValue — nested (address/zip) 302.8µs 169.1µs +79.1% 🔴
Compiled KeySpec.resolveValue — deep (address/coords/lat) 230.9µs 122.8µs +87.9% 🔴
Compiled KeySpec.resolveValue — array (tags/#0) 261.0µs 155.4µs +68.0% 🔴
grep — 10K records (string match) 821.8µs 452.2µs +81.8% 🔴
collate — 100 records (count by city) 438.4µs 315.6µs +38.9% 🔴
chain — 5 ops (grep eval grep eval
new Record() — 10K objects 153.3µs 97.0µs +58.1% 🔴
Record.dataRef — 10K records (zero-copy) 86.2µs 35.1µs +145.7% 🔴
chain — 3 ops (grep eval grep), 100 records 162.4µs
chain — 3 ops (grep eval grep), 10K records 1.36ms
manual buffer (isolated) — 10K lines 6.67ms 5.32ms +25.3% 🔴

103 benchmarks: 7 faster, 19 slower, 77 within noise (10%)

ℹ️ Note: Benchmarks are advisory-only. GitHub Actions shared runners have variable performance, so results may fluctuate ±25% between runs. For reliable benchmarking, run locally with bun run bench.

Full benchmark results

JSON Parsing

Benchmark Median Baseline Delta Throughput
Record.fromJSON — 100 lines 158.5µs 161.2µs -1.7% 630.73K rec/s
Record.fromJSON — 10K lines 13.88ms 13.16ms +5.5% 720.54K rec/s, 213.4 MB/s
InputStream.fromString — 100 records 376.0µs 216.7µs +73.5% 🔴 265.98K rec/s
InputStream.fromString — 10K records 18.25ms 18.50ms -1.3% 548.03K rec/s, 162.3 MB/s
JSON.parse baseline — 10K lines (no Record) 12.76ms 13.23ms -3.5% 783.52K rec/s, 232.0 MB/s
JSON.parse single array — 10K records 12.31ms 12.91ms -4.6% 812.35K rec/s, 240.6 MB/s

JSON Serialization

Benchmark Median Baseline Delta Throughput
Record.toString — 100 records 82.6µs 90.4µs -8.6% 1.21M rec/s
Record.toString — 10K records 8.38ms 7.07ms +18.5% 🔴 1.19M rec/s, 353.6 MB/s
Record.toJSON — 10K records 282.3µs 285.1µs -1.0% 35.43M rec/s
JSON.stringify baseline — 10K objects (no Record) 7.82ms 8.06ms -3.0% 1.28M rec/s, 378.8 MB/s
Batch join — 10K records (map+join) 8.24ms 8.71ms -5.4% 1.21M rec/s, 359.5 MB/s

KeySpec Access

Benchmark Median Baseline Delta Throughput
KeySpec — simple key (name) 223.6µs 212.5µs +5.2% 44.73M rec/s
KeySpec — nested key (address/zip) 560.9µs 556.2µs +0.8% 17.83M rec/s
KeySpec — deep nested (address/coords/lat) 1.07ms 1.09ms -1.5% 9.35M rec/s
KeySpec — array index (tags/#0) 924.6µs 922.7µs +0.2% 10.82M rec/s
Direct property access baseline (rec['name']) 80.5µs 90.0µs -10.6% 🟢 124.25M rec/s
Direct nested access baseline (rec.address.coords.lat) 93.8µs 96.8µs -3.1% 106.63M rec/s
KeySpec construction — cached (same spec 10K times) 343.3µs 279.6µs +22.8% 🔴 29.13M rec/s
KeySpec construction — unique specs (10K different) 2.27ms 2.51ms -9.5% 4.40M rec/s
Compiled KeySpec.resolveValue — nested (address/zip) 302.8µs 169.1µs +79.1% 🔴 33.03M rec/s
Compiled KeySpec.resolveValue — deep (address/coords/lat) 230.9µs 122.8µs +87.9% 🔴 43.31M rec/s
Compiled KeySpec.resolveValue — array (tags/#0) 261.0µs 155.4µs +68.0% 🔴 38.31M rec/s
Compiled KeySpec.setValue — nested (address/zip) 151.9µs 147.6µs +2.9% 65.84M rec/s

Core Operations

Benchmark Median Baseline Delta Throughput
grep — 10K records (r.age > 50) 449.1µs 456.3µs -1.6% 22.27M rec/s
grep — 10K records (string match) 821.8µs 452.2µs +81.8% 🔴 12.17M rec/s
eval — 10K records (add computed field) 2.09ms 2.46ms -15.2% 🟢 4.79M rec/s
xform — 10K records (push each record) 1.83ms 1.75ms +4.4% 5.46M rec/s
sort — 100 records (by score, numeric) 167.6µs 141.0µs +18.8% 🔴 596.77K rec/s
sort — 10K records (by score, numeric) 17.86ms 17.98ms -0.6% 559.83K rec/s
sort — 10K records (by name, lexical) 12.99ms 11.85ms +9.7% 769.54K rec/s
collate — 100 records (count by city) 438.4µs 315.6µs +38.9% 🔴 228.11K rec/s
collate — 10K records (count by city) 11.86ms 13.12ms -9.6% 842.97K rec/s
fromcsv — 10K rows (parse CSV to records) 16.22ms 15.32ms +5.9% 616.59K rec/s, 40.5 MB/s

Pipeline Overhead

Benchmark Median Baseline Delta Throughput
chain — single op (grep), 10K records 7.72ms 7.37ms +4.7% 1.30M rec/s
chain — 3 ops (grep eval grep), 10K records 7.41ms 7.50ms
chain — 5 ops (grep eval grep eval grep), 10K records
passthrough baseline — 10K records (direct collector) 6.36ms 6.56ms -3.0% 1.57M rec/s

Record Creation & Serialization

Benchmark Median Baseline Delta Throughput
new Record() — 10K objects 153.3µs 97.0µs +58.1% 🔴 65.25M rec/s
new Record() empty — 10K 145.1µs 141.1µs +2.8% 68.94M rec/s
Record.get — 10K records × 3 fields 61.3µs 51.1µs +19.9% 🔴 489.33M rec/s
Record.set — 10K records × 1 field 61.1µs 61.6µs -0.8% 163.68M rec/s
Record.toJSON — 10K records 281.9µs 285.1µs -1.2% 35.48M rec/s
Record.toString — 10K records 8.52ms 7.07ms +20.6% 🔴 1.17M rec/s
Record.clone — 10K records 58.72ms 60.76ms -3.3% 170.29K rec/s
Record.fromJSON — 10K lines 13.37ms 13.16ms +1.6% 747.91K rec/s, 221.5 MB/s
Record.dataRef — 10K records (zero-copy) 86.2µs 35.1µs +145.7% 🔴 116.07M rec/s
Record.sort — 10K records (numeric field) 11.38ms 11.66ms -2.4% 878.39K rec/s
Record.sort — 10K records (lexical field) 6.03ms 6.05ms -0.4% 1.66M rec/s
Record.cmp — 1M comparisons (single field) 104.96ms 113.88ms -7.8% 9.53M rec/s
Record.sort — 10K records (nested field numeric) 15.94ms 15.26ms +4.5% 627.17K rec/s
Record.cmp — 1M comparisons (multi-field cached) 87.99ms 88.86ms -1.0% 11.36M rec/s
Record.sort — 10K records (cached comparator reuse) 11.59ms 11.64ms -0.4% 862.47K rec/s

Chain vs Pipe

Benchmark Median Baseline Delta Throughput
chain — 2 ops (grep eval), 100 records 166.1µs 155.6µs +6.8%
pipe — 2 ops (grep eval), 100 records 359.93ms 373.10ms -3.5%
implicit — 2 ops (grep eval), 100 records 142.5µs 136.4µs +4.4%
chain — 2 ops (grep eval), 1K records 290.7µs 314.7µs -7.6%
pipe — 2 ops (grep eval), 1K records 374.31ms 426.88ms -12.3% 🟢
implicit — 2 ops (grep eval), 1K records 208.2µs 191.2µs +8.9%
chain — 2 ops (grep eval), 10K records 1.06ms 1.06ms +0.0%
pipe — 2 ops (grep eval), 10K records 383.41ms 366.77ms +4.5%
implicit — 2 ops (grep eval), 10K records 1.07ms 1.08ms -0.8%
chain — 3 ops (grep eval grep), 100 records 162.4µs 102.0µs
pipe — 3 ops (grep eval grep), 100 records 549.05ms 549.01ms
implicit — 3 ops (grep eval grep), 100 records 178.6µs 192.2µs
chain — 3 ops (grep eval grep), 1K records 300.3µs 297.2µs
pipe — 3 ops (grep eval grep), 1K records 562.57ms 558.11ms
implicit — 3 ops (grep eval grep), 1K records 230.6µs 214.8µs
chain — 3 ops (grep eval grep), 10K records 1.36ms 1.07ms
pipe — 3 ops (grep eval grep), 10K records 554.31ms 549.33ms
implicit — 3 ops (grep eval grep), 10K records 1.08ms 1.08ms
chain — 5 ops (grep eval grep eval grep), 100 records
pipe — 5 ops (grep eval grep eval grep), 100 records
implicit — 5 ops (grep eval grep eval grep), 100 records
chain — 5 ops (grep eval grep eval grep), 1K records
pipe — 5 ops (grep eval grep eval grep), 1K records
implicit — 5 ops (grep eval grep eval grep), 1K records
chain — 5 ops (grep eval grep eval grep), 10K records
pipe — 5 ops (grep eval grep eval grep), 10K records
implicit — 5 ops (grep eval grep eval grep), 10K records

Line Reading

Benchmark Median Baseline Delta Throughput
InputStream.fromFile — 100 lines 476.8µs 487.4µs -2.2% 209.73K rec/s, 61.9 MB/s
InputStream.fromString — 100 lines 182.6µs 197.6µs -7.6% 547.56K rec/s, 161.7 MB/s
manual buffer (isolated) — 100 lines 263.3µs 253.3µs +3.9% 379.81K rec/s, 112.2 MB/s
bulk text + split — 100 lines 70.3µs 75.9µs -7.4% 1.42M rec/s, 420.1 MB/s
node readline — 100 lines 545.0µs 449.6µs +21.2% 🔴 183.48K rec/s, 54.2 MB/s
TextDecoderStream — 100 lines 247.4µs 273.9µs -9.7% 404.21K rec/s, 119.4 MB/s
binary newline scan — 100 lines 274.5µs 371.8µs -26.2% 🟢 364.28K rec/s, 107.6 MB/s
bun native stdin — 100 lines 24.62ms 24.44ms +0.8% 4.06K rec/s, 1.2 MB/s
InputStream.fromFile — 10K lines 23.22ms 22.54ms +3.0% 430.68K rec/s, 127.5 MB/s
InputStream.fromString — 10K lines 18.09ms 17.63ms +2.6% 552.84K rec/s, 163.7 MB/s
manual buffer (isolated) — 10K lines 6.67ms 5.32ms +25.3% 🔴 1.50M rec/s, 443.7 MB/s
bulk text + split — 10K lines 2.38ms 2.50ms -4.8% 4.20M rec/s, 1243.6 MB/s
node readline — 10K lines 9.13ms 8.95ms +2.0% 1.10M rec/s, 324.5 MB/s
TextDecoderStream — 10K lines 5.49ms 5.13ms +7.0% 1.82M rec/s, 539.0 MB/s
binary newline scan — 10K lines 7.80ms 6.25ms +24.7% 🔴 1.28M rec/s, 379.8 MB/s
bun native stdin — 10K lines 41.96ms 43.34ms -3.2% 238.30K rec/s, 70.6 MB/s
InputStream.fromFile — 100K lines 260.11ms 262.35ms -0.9% 384.46K rec/s, 114.2 MB/s
InputStream.fromString — 100K lines 222.95ms 220.89ms +0.9% 448.52K rec/s, 133.3 MB/s
manual buffer (isolated) — 100K lines 32.49ms 33.14ms -2.0% 3.08M rec/s, 914.7 MB/s
bulk text + split — 100K lines 27.95ms 27.52ms +1.6% 3.58M rec/s, 1063.0 MB/s
node readline — 100K lines 84.68ms 84.09ms +0.7% 1.18M rec/s, 350.9 MB/s
TextDecoderStream — 100K lines 42.23ms 41.21ms +2.5% 2.37M rec/s, 703.7 MB/s
binary newline scan — 100K lines 63.82ms 64.03ms -0.3% 1.57M rec/s, 465.6 MB/s
bun native stdin — 100K lines 114.57ms 122.92ms -6.8% 872.83K rec/s, 259.4 MB/s

@benbernard benbernard merged commit 06317bf into master Feb 23, 2026
4 checks passed
@benbernard benbernard deleted the issue-cleanups branch February 23, 2026 05:40
benbernard added a commit that referenced this pull request Feb 23, 2026
feat: TUI pipeline builder (Phase 1 MVP) + auto-versioning
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant