@vizzly-testing/cli 0.20.1-beta.0 → 0.20.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/cli.js +177 -2
  2. package/dist/client/index.js +144 -77
  3. package/dist/commands/doctor.js +118 -33
  4. package/dist/commands/finalize.js +8 -3
  5. package/dist/commands/init.js +13 -18
  6. package/dist/commands/login.js +42 -49
  7. package/dist/commands/logout.js +13 -5
  8. package/dist/commands/project.js +95 -67
  9. package/dist/commands/run.js +32 -6
  10. package/dist/commands/status.js +81 -50
  11. package/dist/commands/tdd-daemon.js +61 -32
  12. package/dist/commands/tdd.js +4 -25
  13. package/dist/commands/upload.js +18 -9
  14. package/dist/commands/whoami.js +40 -38
  15. package/dist/reporter/reporter-bundle.css +1 -1
  16. package/dist/reporter/reporter-bundle.iife.js +11 -11
  17. package/dist/server/handlers/tdd-handler.js +113 -7
  18. package/dist/server/http-server.js +9 -3
  19. package/dist/server/routers/baseline.js +58 -0
  20. package/dist/server/routers/dashboard.js +10 -6
  21. package/dist/server/routers/screenshot.js +32 -0
  22. package/dist/server-manager/core.js +5 -2
  23. package/dist/server-manager/operations.js +2 -1
  24. package/dist/tdd/tdd-service.js +190 -126
  25. package/dist/types/client.d.ts +25 -2
  26. package/dist/utils/colors.js +187 -39
  27. package/dist/utils/config-loader.js +3 -6
  28. package/dist/utils/context.js +228 -0
  29. package/dist/utils/output.js +449 -14
  30. package/docs/api-reference.md +173 -8
  31. package/docs/tui-elements.md +560 -0
  32. package/package.json +12 -7
  33. package/dist/report-generator/core.js +0 -315
  34. package/dist/report-generator/index.js +0 -8
  35. package/dist/report-generator/operations.js +0 -196
  36. package/dist/services/static-report-generator.js +0 -65
@@ -0,0 +1,560 @@
1
+ # TUI Elements Reference
2
+
3
+ The Vizzly CLI includes a comprehensive terminal UI toolkit for consistent, beautiful output across all commands. This guide documents the available helpers and how to use them.
4
+
5
+ ## Design System
6
+
7
+ The TUI elements follow the **Observatory Design System** - Vizzly's visual language. Key characteristics:
8
+
9
+ - **Amber** (`#F59E0B`) is the signature brand color used for primary actions and highlights
10
+ - **Semantic colors** communicate meaning consistently (green=success, red=error, amber=warning, blue=info)
11
+ - **Text hierarchy** uses four levels for clear information architecture
12
+ - **Dark theme first** - colors are optimized for dark terminal backgrounds
13
+
14
+ ## Quick Reference
15
+
16
+ | Helper | Purpose | Example |
17
+ |--------|---------|---------|
18
+ | `header()` | Command branding | `header('tdd', 'local')` |
19
+ | `success()` | Success message with checkmark | `success('Build uploaded')` |
20
+ | `result()` | Final result with timing | `result('5 screenshots')` |
21
+ | `complete()` | Completion message | `complete('Ready', { detail: 'port 47392' })` |
22
+ | `error()` | Error message | `error('Failed', err)` |
23
+ | `warn()` | Warning message | `warn('Token expires soon')` |
24
+ | `info()` | Info message | `info('Processing started')` |
25
+ | `debug()` | Debug with component | `debug('server', 'listening', { port: 47392 })` |
26
+ | `list()` | Bullet point list | `list(['Item 1', 'Item 2'])` |
27
+ | `keyValue()` | Key-value table | `keyValue({ Name: 'build-123' })` |
28
+ | `labelValue()` | Single key-value | `labelValue('Status', 'ready')` |
29
+ | `hint()` | Muted tip/hint | `hint('Use --verbose for details')` |
30
+ | `divider()` | Separator line | `divider({ width: 40 })` |
31
+ | `box()` | Bordered box | `box('Dashboard ready')` |
32
+ | `printBox()` | Print box to stderr | `printBox('Content', { title: 'Info' })` |
33
+ | `diffBar()` | Visual diff bar | `diffBar(4.2)` |
34
+ | `progressBar()` | Gradient progress | `progressBar(75, 100)` |
35
+ | `badge()` | Status badge | `badge('READY', 'success')` |
36
+ | `statusDot()` | Colored dot | `statusDot('success')` |
37
+ | `link()` | Styled URL | `link('Dashboard', 'http://...')` |
38
+ | `startSpinner()` | Animated spinner | `startSpinner('Loading...')` |
39
+ | `progress()` | Progress update | `progress('Uploading', 5, 10)` |
40
+
41
+ ## Import
42
+
43
+ ```javascript
44
+ import * as output from '../utils/output.js';
45
+
46
+ // Or import specific functions
47
+ import {
48
+ header,
49
+ success,
50
+ error,
51
+ keyValue,
52
+ startSpinner
53
+ } from '../utils/output.js';
54
+ ```
55
+
56
+ ## Configuration
57
+
58
+ Call `configure()` at the start of your command to set output options:
59
+
60
+ ```javascript
61
+ output.configure({
62
+ json: globalOptions.json, // Enable JSON output mode
63
+ verbose: globalOptions.verbose, // Enable debug logging
64
+ color: !globalOptions.noColor, // Enable/disable colors
65
+ silent: false, // Suppress all output
66
+ logFile: null, // Path to log file
67
+ resetTimer: true // Reset elapsed timer (default: true)
68
+ });
69
+ ```
70
+
71
+ ## Visual Elements
72
+
73
+ ### Header
74
+
75
+ Show command branding at the start of output. Uses amber for "vizzly", info blue for command name, and muted text for mode.
76
+
77
+ ```javascript
78
+ output.header('tdd', 'local');
79
+ // Output:
80
+ //
81
+ // vizzly · tdd · local
82
+ //
83
+ ```
84
+
85
+ The header automatically:
86
+ - Only shows once per command execution
87
+ - Skips in JSON or silent mode
88
+ - Uses brand colors from Observatory
89
+
90
+ ### Box
91
+
92
+ Create bordered boxes for important information:
93
+
94
+ ```javascript
95
+ // Simple box
96
+ output.printBox('Dashboard: http://localhost:47392');
97
+ // ╭───────────────────────────────────────╮
98
+ // │ Dashboard: http://localhost:47392 │
99
+ // ╰───────────────────────────────────────╯
100
+
101
+ // Box with title
102
+ output.printBox('Server started successfully', {
103
+ title: 'Ready',
104
+ style: 'branded' // Uses amber border
105
+ });
106
+ // ╭─ Ready ────────────────────────────────╮
107
+ // │ Server started successfully │
108
+ // ╰────────────────────────────────────────╯
109
+
110
+ // Multi-line content
111
+ output.printBox([
112
+ 'Dashboard: http://localhost:47392',
113
+ 'API: http://localhost:47392/api'
114
+ ]);
115
+ ```
116
+
117
+ Options:
118
+ - `title` - Optional title in border
119
+ - `padding` - Horizontal padding (default: 1)
120
+ - `borderColor` - Color function for border
121
+ - `style` - `'default'` or `'branded'` (amber border)
122
+
123
+ ### Diff Bar
124
+
125
+ Color-coded visual representation of diff percentages:
126
+
127
+ ```javascript
128
+ output.diffBar(0.5); // ████░░░░░░ (green - minimal)
129
+ output.diffBar(4.2); // ████░░░░░░ (amber - attention)
130
+ output.diffBar(15.0); // ██████░░░░ (red - significant)
131
+ ```
132
+
133
+ Color thresholds:
134
+ - `< 1%` - Success green (minimal change)
135
+ - `1-5%` - Warning amber (attention needed)
136
+ - `> 5%` - Danger red (significant change)
137
+
138
+ ### Progress Bar
139
+
140
+ Gradient progress indicator using amber brand colors:
141
+
142
+ ```javascript
143
+ let bar = output.progressBar(75, 100);
144
+ // ███████████████░░░░░ (amber gradient)
145
+
146
+ // Custom colors
147
+ let bar = output.progressBar(50, 100, 20, {
148
+ from: '#10B981', // Start color
149
+ to: '#34D399' // End color
150
+ });
151
+ ```
152
+
153
+ ### Badge
154
+
155
+ Status badges with background colors:
156
+
157
+ ```javascript
158
+ output.badge('READY', 'success'); // Green background
159
+ output.badge('PENDING', 'warning'); // Amber background
160
+ output.badge('FAILED', 'error'); // Red background
161
+ output.badge('SYNC', 'info'); // Blue background
162
+ ```
163
+
164
+ ### Status Dot
165
+
166
+ Simple colored status indicators:
167
+
168
+ ```javascript
169
+ output.statusDot('success'); // ● (green)
170
+ output.statusDot('warning'); // ● (amber)
171
+ output.statusDot('error'); // ● (red)
172
+ output.statusDot('info'); // ● (blue)
173
+ ```
174
+
175
+ ### Divider
176
+
177
+ Visual separator line:
178
+
179
+ ```javascript
180
+ output.divider();
181
+ // ────────────────────────────────────────
182
+
183
+ output.divider({ width: 20, char: '═' });
184
+ // ════════════════════
185
+ ```
186
+
187
+ ## Text Formatting
188
+
189
+ ### List
190
+
191
+ Bullet point lists with style variants:
192
+
193
+ ```javascript
194
+ // Default style (muted bullets)
195
+ output.list(['Item one', 'Item two', 'Item three']);
196
+ // • Item one
197
+ // • Item two
198
+ // • Item three
199
+
200
+ // Success style (green checkmarks)
201
+ output.list(['Config loaded', 'Server started'], { style: 'success' });
202
+ // ✓ Config loaded
203
+ // ✓ Server started
204
+
205
+ // Warning style (amber exclamation)
206
+ output.list(['Missing token', 'Outdated config'], { style: 'warning' });
207
+ // ! Missing token
208
+ // ! Outdated config
209
+
210
+ // Error style (red X)
211
+ output.list(['Connection failed', 'Upload timeout'], { style: 'error' });
212
+ // ✗ Connection failed
213
+ // ✗ Upload timeout
214
+
215
+ // Custom indent
216
+ output.list(['Item 1', 'Item 2'], { indent: 4 });
217
+ ```
218
+
219
+ ### Key-Value Table
220
+
221
+ Display structured data as aligned key-value pairs:
222
+
223
+ ```javascript
224
+ output.keyValue({
225
+ Project: 'my-app',
226
+ Branch: 'feature/login',
227
+ Commit: 'abc1234',
228
+ Environment: 'staging'
229
+ });
230
+ // Project my-app
231
+ // Branch feature/login
232
+ // Commit abc1234
233
+ // Environment staging
234
+
235
+ // Custom key width
236
+ output.keyValue({ Name: 'value' }, { keyWidth: 20 });
237
+ ```
238
+
239
+ ### Label-Value
240
+
241
+ Single key-value pair (inline):
242
+
243
+ ```javascript
244
+ output.labelValue('Status', 'ready');
245
+ // Status: ready
246
+
247
+ output.labelValue('Screenshots', '15');
248
+ // Screenshots: 15
249
+ ```
250
+
251
+ ### Hint
252
+
253
+ Muted tips and additional information:
254
+
255
+ ```javascript
256
+ output.hint('Use --verbose for more details');
257
+ // Use --verbose for more details
258
+
259
+ output.hint('Dashboard: http://localhost:47392', { indent: 4 });
260
+ // Dashboard: http://localhost:47392
261
+ ```
262
+
263
+ ### Link
264
+
265
+ Styled URLs with underline and info blue color:
266
+
267
+ ```javascript
268
+ let url = output.link('Dashboard', 'http://localhost:47392');
269
+ // Returns: underlined blue URL
270
+
271
+ // Usage in output
272
+ output.labelValue('View', output.link('Dashboard', 'http://localhost:47392'));
273
+ // View: http://localhost:47392 (underlined, blue)
274
+ ```
275
+
276
+ ### Complete
277
+
278
+ Success/completion message with checkmark:
279
+
280
+ ```javascript
281
+ output.complete('Build uploaded');
282
+ // ✓ Build uploaded
283
+
284
+ output.complete('Build uploaded', { detail: 'build-abc123' });
285
+ // ✓ Build uploaded build-abc123
286
+ ```
287
+
288
+ ## Logging
289
+
290
+ ### Success, Result, Error, Warn, Info
291
+
292
+ Standard logging functions with appropriate icons and colors:
293
+
294
+ ```javascript
295
+ output.success('Configuration saved');
296
+ // ✓ Configuration saved
297
+
298
+ output.result('5 screenshots uploaded'); // Includes elapsed time
299
+ // ✓ 5 screenshots uploaded · 234ms
300
+
301
+ output.error('Upload failed', err);
302
+ // ✖ Upload failed
303
+ // Connection timeout (if err.message differs from message)
304
+
305
+ output.warn('Token expires in 24 hours');
306
+ // ⚠ Token expires in 24 hours
307
+
308
+ output.info('Processing started');
309
+ // ℹ Processing started
310
+ ```
311
+
312
+ ### Debug
313
+
314
+ Component-based debug logging (only shown when verbose):
315
+
316
+ ```javascript
317
+ output.debug('server', 'listening on port', { port: 47392 });
318
+ // server listening on port port=47392
319
+
320
+ output.debug('config', 'loaded from file', { path: './vizzly.config.js' });
321
+ // config loaded from file path=./vizzly.config.js
322
+
323
+ output.debug('upload', 'batch complete', { uploaded: 5, total: 10 });
324
+ // upload batch complete uploaded=5 total=10
325
+ ```
326
+
327
+ Component colors are mapped semantically:
328
+ - `server`, `baseline` - Success green (infrastructure)
329
+ - `tdd`, `compare` - Info blue (processing)
330
+ - `config`, `build`, `auth` - Warning amber (configuration)
331
+ - `upload`, `api` - Info blue (processing)
332
+ - `run` - Amber (primary action)
333
+
334
+ ### Spinner
335
+
336
+ Animated loading indicator (only in TTY):
337
+
338
+ ```javascript
339
+ output.startSpinner('Loading configuration...');
340
+ // ⠋ Loading configuration... (animated)
341
+
342
+ output.updateSpinner('Processing', 5, 10);
343
+ // ⠙ Processing (5/10)
344
+
345
+ output.stopSpinner();
346
+ // Clears the spinner line
347
+ ```
348
+
349
+ The spinner uses the amber brand color for the animation and plain text for the message.
350
+
351
+ ### Progress
352
+
353
+ Progress updates that work with spinner or JSON mode:
354
+
355
+ ```javascript
356
+ output.progress('Uploading screenshots', 3, 10);
357
+ // In TTY: updates spinner with (3/10)
358
+ // In JSON: outputs {"status":"progress","message":"...","progress":{"current":3,"total":10}}
359
+ ```
360
+
361
+ ## Colors
362
+
363
+ Access the colors object for custom formatting:
364
+
365
+ ```javascript
366
+ let colors = output.getColors();
367
+
368
+ // Basic colors
369
+ colors.red('error text');
370
+ colors.green('success text');
371
+ colors.yellow('warning text');
372
+
373
+ // Brand colors (Observatory Design System)
374
+ colors.brand.amber('primary brand'); // #F59E0B
375
+ colors.brand.success('approved'); // #10B981
376
+ colors.brand.warning('pending'); // #F59E0B
377
+ colors.brand.danger('rejected'); // #EF4444
378
+ colors.brand.info('processing'); // #3B82F6
379
+
380
+ // Text hierarchy
381
+ colors.brand.textPrimary('heading'); // #FFFFFF
382
+ colors.brand.textSecondary('body'); // #9CA3AF
383
+ colors.brand.textTertiary('caption'); // #6B7280
384
+ colors.brand.textMuted('disabled'); // #4B5563
385
+
386
+ // Modifiers
387
+ colors.bold('important');
388
+ colors.dim('muted');
389
+ colors.underline('link');
390
+ colors.italic('emphasis');
391
+
392
+ // Backgrounds
393
+ colors.brand.bgSuccess(' PASS ');
394
+ colors.brand.bgWarning(' WARN ');
395
+ colors.brand.bgDanger(' FAIL ');
396
+ colors.brand.bgInfo(' INFO ');
397
+ ```
398
+
399
+ ## JSON Mode
400
+
401
+ All TUI helpers respect JSON mode. When `json: true`:
402
+ - Visual elements return empty strings or plain text
403
+ - Logging functions output structured JSON
404
+ - Spinners are disabled
405
+
406
+ ```javascript
407
+ output.configure({ json: true });
408
+
409
+ output.success('Done');
410
+ // {"status":"success","message":"Done"}
411
+
412
+ output.error('Failed', new Error('Connection timeout'));
413
+ // {"status":"error","message":"Failed","error":{"name":"Error","message":"Connection timeout"}}
414
+
415
+ output.progress('Uploading', 5, 10);
416
+ // {"status":"progress","message":"Uploading","progress":{"current":5,"total":10}}
417
+ ```
418
+
419
+ ## Best Practices
420
+
421
+ ### 1. Always configure at command start
422
+
423
+ ```javascript
424
+ export async function myCommand(options, globalOptions) {
425
+ output.configure({
426
+ json: globalOptions.json,
427
+ verbose: globalOptions.verbose,
428
+ color: !globalOptions.noColor,
429
+ });
430
+ // ... rest of command
431
+ }
432
+ ```
433
+
434
+ ### 2. Use header for command branding
435
+
436
+ ```javascript
437
+ output.header('upload', 'cloud');
438
+ ```
439
+
440
+ ### 3. Stop spinner before other output
441
+
442
+ ```javascript
443
+ output.startSpinner('Processing...');
444
+ // ... async work ...
445
+ output.stopSpinner(); // Always stop before success/error
446
+ output.success('Done');
447
+ ```
448
+
449
+ Most output functions call `stopSpinner()` automatically, but explicit stopping is clearer.
450
+
451
+ ### 4. Use semantic functions for their purpose
452
+
453
+ ```javascript
454
+ // Good
455
+ output.complete('Build ready'); // Completion state
456
+ output.success('Upload successful'); // Success message
457
+ output.result('5 screenshots'); // Final result with timing
458
+
459
+ // Avoid mixing purposes
460
+ ```
461
+
462
+ ### 5. Leverage debug for troubleshooting
463
+
464
+ ```javascript
465
+ output.debug('api', 'request sent', { url, method });
466
+ output.debug('api', 'response received', { status, duration: '234ms' });
467
+ ```
468
+
469
+ ### 6. Clean up resources
470
+
471
+ ```javascript
472
+ try {
473
+ // ... command logic
474
+ } finally {
475
+ output.cleanup(); // Stops spinner, flushes logs
476
+ }
477
+ ```
478
+
479
+ ## Examples
480
+
481
+ ### Diagnostic Command
482
+
483
+ ```javascript
484
+ export async function doctorCommand(options, globalOptions) {
485
+ output.configure({ ... });
486
+ output.header('doctor', 'full');
487
+
488
+ let checks = [];
489
+
490
+ // Run checks...
491
+ checks.push({ name: 'Node.js', value: 'v20.10.0', ok: true });
492
+ checks.push({ name: 'API', value: 'connected', ok: true });
493
+
494
+ // Display results
495
+ let colors = output.getColors();
496
+ for (let check of checks) {
497
+ let icon = check.ok ? colors.brand.success('✓') : colors.brand.danger('✗');
498
+ let label = colors.brand.textTertiary(check.name.padEnd(12));
499
+ output.print(` ${icon} ${label} ${check.value}`);
500
+ }
501
+
502
+ output.blank();
503
+ output.complete('Preflight passed');
504
+ }
505
+ ```
506
+
507
+ ### Upload Command
508
+
509
+ ```javascript
510
+ export async function uploadCommand(path, options, globalOptions) {
511
+ output.configure({ ... });
512
+ output.header('upload', 'cloud');
513
+
514
+ output.startSpinner('Uploading screenshots...');
515
+
516
+ for (let i = 0; i < screenshots.length; i++) {
517
+ output.progress('Uploading', i + 1, screenshots.length);
518
+ await upload(screenshots[i]);
519
+ }
520
+
521
+ output.stopSpinner();
522
+
523
+ output.keyValue({
524
+ Build: buildId,
525
+ Screenshots: String(screenshots.length),
526
+ Branch: branch
527
+ });
528
+
529
+ output.blank();
530
+ output.labelValue('View', output.link('Build', buildUrl));
531
+ output.result(`${screenshots.length} screenshots uploaded`);
532
+ }
533
+ ```
534
+
535
+ ### TDD Dashboard
536
+
537
+ ```javascript
538
+ output.printBox([
539
+ `Dashboard: ${output.link('', dashboardUrl)}`,
540
+ `Baselines: ${baselineCount} screenshots`
541
+ ], { title: 'Ready', style: 'branded' });
542
+
543
+ output.blank();
544
+ output.hint('Press Ctrl+C to stop the server');
545
+ ```
546
+
547
+ ## Accessibility
548
+
549
+ The TUI toolkit is designed with accessibility in mind:
550
+
551
+ - **Color is not the only indicator** - Icons accompany colors (✓, ✗, ⚠, ℹ)
552
+ - **NO_COLOR support** - Respects `NO_COLOR` environment variable
553
+ - **Screen reader friendly** - Unicode characters are widely supported
554
+ - **High contrast** - Colors chosen for visibility on dark backgrounds
555
+
556
+ ## Related Documentation
557
+
558
+ - [API Reference](./api-reference.md) - Complete CLI API documentation
559
+ - [Getting Started](./getting-started.md) - Quick start guide
560
+ - [Plugins](./plugins.md) - Creating plugins with TUI access
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizzly-testing/cli",
3
- "version": "0.20.1-beta.0",
3
+ "version": "0.20.1-beta.1",
4
4
  "description": "Visual review platform for UI developers and designers",
5
5
  "keywords": [
6
6
  "visual-testing",
@@ -66,14 +66,17 @@
66
66
  "dev:reporter": "cd src/reporter && vite --config vite.dev.config.js",
67
67
  "test:types": "tsd",
68
68
  "prepublishOnly": "npm run build",
69
- "test": "node --experimental-test-coverage --test --test-name-pattern='.*' $(find tests -name '*.test.js')",
70
- "test:watch": "node --test --watch $(find tests -name '*.test.js')",
69
+ "test": "node --experimental-test-coverage --test --test-concurrency=1 --test-reporter=spec $(find tests -name '*.test.js')",
70
+ "test:watch": "node --test --test-reporter=spec --watch $(find tests -name '*.test.js')",
71
71
  "test:reporter": "playwright test --config=tests/reporter/playwright.config.js",
72
72
  "test:reporter:visual": "node bin/vizzly.js run \"npm run test:reporter\"",
73
+ "test:tui": "node --test --test-reporter=spec tests/tui/*.test.js",
74
+ "test:tui:docker": "./tests/tui/run-tui-tests.sh",
73
75
  "lint": "biome check src tests",
74
- "lint:fix": "biome check --write src tests",
76
+ "lint:fix": "biome check --write --unsafe src tests",
75
77
  "format": "biome format --write src tests",
76
- "format:check": "biome format src tests"
78
+ "format:check": "biome format src tests",
79
+ "fix": "npm run format && npm run lint:fix"
77
80
  },
78
81
  "engines": {
79
82
  "node": ">=22.0.0"
@@ -83,7 +86,8 @@
83
86
  "registry": "https://registry.npmjs.org/"
84
87
  },
85
88
  "dependencies": {
86
- "@vizzly-testing/honeydiff": "^0.6.0",
89
+ "@vizzly-testing/honeydiff": "^0.7.1",
90
+ "ansis": "^4.2.0",
87
91
  "commander": "^14.0.0",
88
92
  "cosmiconfig": "^9.0.0",
89
93
  "dotenv": "^17.2.1",
@@ -113,7 +117,7 @@
113
117
  "@playwright/test": "^1.55.1",
114
118
  "@tailwindcss/postcss": "^4.1.13",
115
119
  "@tanstack/react-query": "^5.90.11",
116
- "@types/node": "^24.10.1",
120
+ "@types/node": "^25.0.2",
117
121
  "@vitejs/plugin-react": "^5.0.3",
118
122
  "autoprefixer": "^10.4.21",
119
123
  "babel-plugin-transform-remove-console": "^6.9.4",
@@ -123,6 +127,7 @@
123
127
  "rimraf": "^6.0.1",
124
128
  "tailwindcss": "^4.1.13",
125
129
  "tsd": "^0.33.0",
130
+ "tui-driver": "github:vizzly-testing/tui-driver",
126
131
  "typescript": "^5.0.4",
127
132
  "vite": "^7.1.7",
128
133
  "wouter": "^3.7.1"