termkit 2.0.2 → 2.2.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.
Files changed (73) hide show
  1. package/README.md +582 -37
  2. package/dist/config.d.ts +11 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/index.d.ts +49 -96
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +2584 -170
  7. package/dist/index.mjs +2563 -165
  8. package/dist/models/Bar.d.ts +125 -0
  9. package/dist/models/Bar.d.ts.map +1 -0
  10. package/dist/models/Chart.d.ts +106 -0
  11. package/dist/models/Chart.d.ts.map +1 -0
  12. package/dist/models/Column.d.ts +20 -0
  13. package/dist/models/Column.d.ts.map +1 -0
  14. package/dist/models/Command.d.ts +38 -0
  15. package/dist/models/Command.d.ts.map +1 -0
  16. package/dist/models/Input.d.ts +58 -0
  17. package/dist/models/Input.d.ts.map +1 -0
  18. package/dist/models/Log.d.ts +24 -0
  19. package/dist/models/Log.d.ts.map +1 -0
  20. package/dist/models/Markup.d.ts +17 -0
  21. package/dist/models/Markup.d.ts.map +1 -0
  22. package/dist/models/MultiBar.d.ts +17 -0
  23. package/dist/models/MultiBar.d.ts.map +1 -0
  24. package/dist/models/MultiSelect.d.ts +45 -0
  25. package/dist/models/MultiSelect.d.ts.map +1 -0
  26. package/dist/models/Option.d.ts +17 -0
  27. package/dist/models/Option.d.ts.map +1 -0
  28. package/dist/models/Scrollbox.d.ts +20 -0
  29. package/dist/models/Scrollbox.d.ts.map +1 -0
  30. package/dist/models/Select.d.ts +39 -0
  31. package/dist/models/Select.d.ts.map +1 -0
  32. package/dist/models/Spinner.d.ts +67 -0
  33. package/dist/models/Spinner.d.ts.map +1 -0
  34. package/dist/models/Table.d.ts +26 -0
  35. package/dist/models/Table.d.ts.map +1 -0
  36. package/dist/models/TermKit.d.ts +19 -0
  37. package/dist/models/TermKit.d.ts.map +1 -0
  38. package/dist/models/Variable.d.ts +28 -0
  39. package/dist/models/Variable.d.ts.map +1 -0
  40. package/dist/types.d.ts +10 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/utils/cleanup.d.ts +2 -0
  43. package/dist/utils/cleanup.d.ts.map +1 -0
  44. package/dist/utils/color.d.ts +29 -0
  45. package/dist/utils/color.d.ts.map +1 -0
  46. package/dist/utils/findCommand.d.ts +3 -0
  47. package/dist/utils/findCommand.d.ts.map +1 -0
  48. package/dist/utils/findCommandVariables.d.ts +3 -0
  49. package/dist/utils/findCommandVariables.d.ts.map +1 -0
  50. package/dist/utils/findOption.d.ts +3 -0
  51. package/dist/utils/findOption.d.ts.map +1 -0
  52. package/dist/utils/findOptions.d.ts +3 -0
  53. package/dist/utils/findOptions.d.ts.map +1 -0
  54. package/dist/utils/findVariable.d.ts +5 -0
  55. package/dist/utils/findVariable.d.ts.map +1 -0
  56. package/dist/utils/findVariables.d.ts +3 -0
  57. package/dist/utils/findVariables.d.ts.map +1 -0
  58. package/dist/utils/getVariables.d.ts +3 -0
  59. package/dist/utils/getVariables.d.ts.map +1 -0
  60. package/dist/utils/padLeft.d.ts +2 -0
  61. package/dist/utils/padLeft.d.ts.map +1 -0
  62. package/dist/utils/padRight.d.ts +2 -0
  63. package/dist/utils/padRight.d.ts.map +1 -0
  64. package/dist/utils/padSides.d.ts +2 -0
  65. package/dist/utils/padSides.d.ts.map +1 -0
  66. package/dist/utils/stringLength.d.ts +2 -0
  67. package/dist/utils/stringLength.d.ts.map +1 -0
  68. package/dist/utils/truncate.d.ts +2 -0
  69. package/dist/utils/truncate.d.ts.map +1 -0
  70. package/dist/utils/wrap.d.ts +2 -0
  71. package/dist/utils/wrap.d.ts.map +1 -0
  72. package/package.json +35 -7
  73. package/dist/index.d.mts +0 -99
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TermKit
2
2
 
3
- A fluent CLI framework for Node.js with nested subcommands, middleware, and TypeScript support.
3
+ TermKit is a complete terminal toolkit for Node.js. Build CLI programs with a fluent command API — nested subcommands, middleware, typed options — then prompt users interactively, render progress bars, tables, and charts, all from a single package with full TypeScript support.
4
4
 
5
5
  ## Installation
6
6
 
@@ -10,12 +10,14 @@ npm install termkit
10
10
 
11
11
  ## Usage
12
12
 
13
- ### Basic program
13
+ ### Program
14
+
15
+ `Program` is the entry point for CLI argument parsing. Define commands with `Program.command`, declare options, attach middleware and actions, then call `Program.parse` to run.
14
16
 
15
17
  ```ts
16
- import { command, option, parse } from 'termkit'
18
+ import { Program } from 'termkit'
17
19
 
18
- const program = command('my-app')
20
+ Program.command('my-app')
19
21
  .version('1.0.0')
20
22
  .description('My CLI application')
21
23
  .option('v', 'verbose', null, 'Enable verbose output')
@@ -24,11 +26,7 @@ const program = command('my-app')
24
26
  console.log(options.output)
25
27
  })
26
28
 
27
- try {
28
- program.parse(process.argv)
29
- } catch (err) {
30
- console.error(err)
31
- }
29
+ Program.parse(process.argv)
32
30
  ```
33
31
 
34
32
  ### Options
@@ -36,7 +34,7 @@ try {
36
34
  Options support four variable shapes:
37
35
 
38
36
  ```ts
39
- command('app')
37
+ Program.command('app')
40
38
  .option('b', 'boolean', null, 'Flag with no value')
41
39
  .option('o', 'optional', '[val]', 'Optional value')
42
40
  .option('r', 'required', '<val>', 'Required value')
@@ -56,34 +54,40 @@ Accessible in actions and middleware via the long name:
56
54
 
57
55
  ### Value coercion
58
56
 
59
- Append `:number` or `:boolean` to a variable to coerce the parsed string:
57
+ Append `:number`, `:integer`, or `:boolean` to a variable to coerce the parsed string. Append `(min,max)` to enforce a numeric or length range. Use `|`-separated values for an enum:
60
58
 
61
59
  ```ts
62
- command('app')
63
- .option('p', 'port', '<port:number>', 'Port number')
64
- .option('v', 'verbose', '[verbose:boolean]', 'Verbose mode')
65
- .option('n', 'nums', '[nums:number...]', 'List of numbers')
60
+ Program.command('app')
61
+ .option('p', 'port', '<port:integer(1,65535)>', 'Port number')
62
+ .option('e', 'env', '<env:dev|staging|prod>', 'Environment')
63
+ .option('n', 'nums', '[nums:number...]', 'List of numbers')
64
+ .option('t', 'token', '<token:string(32,64)>', 'API token')
66
65
  .action((options) => {
67
- options.port // number
68
- options.verbose // boolean
69
- options.nums // number[]
66
+ options.port // number
67
+ options.env // 'dev' | 'staging' | 'prod'
68
+ options.nums // number[]
69
+ options.token // string
70
70
  })
71
71
  ```
72
72
 
73
+ Append `=default` inside the brackets to set a default value:
74
+
75
+ ```ts
76
+ .option('p', 'port', '[port:integer=3000]', 'Port number')
77
+ ```
78
+
73
79
  ### Subcommands
74
80
 
75
81
  Commands nest to any depth. Each level can have its own options and middleware.
76
82
 
77
83
  ```ts
78
- import { command, option } from 'termkit'
79
-
80
- command('app')
84
+ Program.command('app')
81
85
  .commands([
82
- command('serve')
86
+ Program.command('serve')
83
87
  .option('p', 'port', '<port:number>', 'Port to listen on')
84
88
  .action((options) => startServer(options.port)),
85
89
 
86
- command('build')
90
+ Program.command('build')
87
91
  .option('w', 'watch', null, 'Watch for changes')
88
92
  .action((options) => runBuild(options)),
89
93
  ])
@@ -92,9 +96,9 @@ command('app')
92
96
  Commands can also carry their own positional variables:
93
97
 
94
98
  ```ts
95
- command('get', '<id>') // required
96
- command('list', '[filter]') // optional
97
- command('tag', '[tags...]') // array
99
+ Program.command('get', '<id>') // required
100
+ Program.command('list', '[filter]') // optional
101
+ Program.command('tag', '[tags...]') // array
98
102
  ```
99
103
 
100
104
  ### Middleware
@@ -102,7 +106,7 @@ command('tag', '[tags...]') // array
102
106
  Middleware runs before the action. It can mutate the options object and supports async.
103
107
 
104
108
  ```ts
105
- command('app')
109
+ Program.command('app')
106
110
  .middleware(async (options) => {
107
111
  options.user = await getUser(options.token)
108
112
  })
@@ -118,9 +122,7 @@ Use `.middlewares([...])` to register several at once. When navigating into a su
118
122
  Apply middleware or options to every command created after the call:
119
123
 
120
124
  ```ts
121
- import { setDefaults } from 'termkit'
122
-
123
- setDefaults({
125
+ Program.setDefaults({
124
126
  middlewares: [
125
127
  async (options) => { options.timestamp = Date.now() }
126
128
  ]
@@ -136,25 +138,568 @@ my-app help
136
138
  my-app serve help
137
139
  ```
138
140
 
141
+ ### configure
142
+
143
+ Sets global display options for the entire toolkit — accent color used in help output, tables, charts, and prompts; plus Unicode glyph support.
144
+
145
+ ```ts
146
+ import { configure } from 'termkit'
147
+
148
+ configure({
149
+ color: '#a855f7', // any named color, hex string, or xterm number
150
+ glyphs: true,
151
+ })
152
+ ```
153
+
154
+ ### Input
155
+
156
+ Interactive text prompt. Supports string, number, integer, boolean, and enum types with validation.
157
+
158
+ ```ts
159
+ import { input, confirm } from 'termkit'
160
+
161
+ const name = await input('Project name?', { default: 'my-app', minLength: 2, maxLength: 20 })
162
+ const port = await input('Port?', { type: 'number', default: 3000, min: 1024, max: 65535 })
163
+ const env = await input('Environment?', { type: 'enum', enum: ['dev', 'staging', 'prod'] })
164
+ ```
165
+
166
+ Use `confirm` as a shorthand for boolean prompts:
167
+
168
+ ```ts
169
+ const deploy = await confirm('Deploy to production?', { default: false })
170
+ ```
171
+
172
+ The text cursor supports left/right arrows, Home/End, Ctrl+A/E, and forward Delete for mid-string editing.
173
+
174
+ Options: `type`, `default`, `placeholder`, `mask`, `inline`, `required`, `min`, `max`, `minLength`, `maxLength`, `enum`, `match`, `regex`, `errorMessage`, `promptColor`, `promptGlyph`, `inputColor`, `errorColor`.
175
+
176
+ ### Select
177
+
178
+ Single-item interactive picker. Navigate with ↑↓ or number keys, confirm with Enter.
179
+
180
+ ```ts
181
+ import { select } from 'termkit'
182
+
183
+ const env = await select('Deploy target?', [
184
+ { label: 'Production', description: 'live traffic' },
185
+ { label: 'Staging', description: 'QA sign-off required' },
186
+ { label: 'Development', description: 'free-for-all' },
187
+ ])
188
+ ```
189
+
190
+ Pass `search: true` to add a type-to-filter input. Typing narrows the list; Backspace removes the last character. Number shortcuts are disabled in search mode — use ↑↓.
191
+
192
+ ```ts
193
+ const pkg = await select('Pick a package:', packages, { search: true })
194
+ ```
195
+
196
+ Pass `maxHeight` to cap the visible rows and enable scrolling. The viewport follows the cursor automatically.
197
+
198
+ ```ts
199
+ const tz = await select('Timezone?', timezones, { maxHeight: 8 })
200
+ ```
201
+
202
+ Both options compose freely:
203
+
204
+ ```ts
205
+ const country = await select('Country?', countries, { search: true, maxHeight: 6 })
206
+ ```
207
+
208
+ Options: `colors`, `colorCycle`, `shimmer`, `skipLabel`, `promptColor`, `promptGlyph`, `descriptionColor`, `selectedPrefix`, `selectedSuffix`, `interval`, `search`, `maxHeight`.
209
+
210
+ ### MultiSelect
211
+
212
+ Multi-item interactive picker. Returns an array of the selected items.
213
+
214
+ ```ts
215
+ import { multiSelect } from 'termkit'
216
+
217
+ const features = await multiSelect('Enable features?', [
218
+ { label: 'Authentication' },
219
+ { label: 'Rate limiting' },
220
+ { label: 'Caching', description: 'Redis-backed' },
221
+ { label: 'Webhooks' },
222
+ ])
223
+ ```
224
+
225
+ Keyboard controls: ↑↓ navigate · Space/Tab toggle · → select · ← deselect · `a` select all · Enter confirm.
226
+
227
+ Enforce selection counts with `min` and `max`:
228
+
229
+ ```ts
230
+ const roles = await multiSelect('Assign roles:', items, { min: 1, max: 3 })
231
+ ```
232
+
233
+ Pass `search: true` to add a type-to-filter input. All printable characters go to the query; `a` select-all is disabled in search mode. Checked items are tracked by their position in the original list so toggling survives filtering.
234
+
235
+ ```ts
236
+ const pkgs = await multiSelect('Add dependencies:', packages, { search: true })
237
+ ```
238
+
239
+ Pass `maxHeight` to cap the visible rows with auto-scrolling:
240
+
241
+ ```ts
242
+ const regions = await multiSelect('Deploy to:', regions, { maxHeight: 6 })
243
+ ```
244
+
245
+ Options: `min`, `max`, `allowSkip`, `colors`, `colorCycle`, `shimmer`, `checkedPrefix`, `uncheckedPrefix`, `promptColor`, `promptGlyph`, `descriptionColor`, `errorColor`, `interval`, `search`, `maxHeight`.
246
+
247
+ ### Log
248
+
249
+ `log` is a singleton logger. `Log` is the class for custom instances.
250
+
251
+ ```ts
252
+ import { log } from 'termkit'
253
+
254
+ log.succeed('Build complete')
255
+ log.fail('Connection refused')
256
+ log.warn('Rate limited, retrying')
257
+ log.info('Listening on port 3000')
258
+ log.data({ user: 'alice', role: 'admin', active: true })
259
+ ```
260
+
261
+ Custom instance with colors:
262
+
263
+ ```ts
264
+ import { Log } from 'termkit'
265
+
266
+ const logger = new Log({ successColor: '#a855f7', failColor: '#ef4444' })
267
+ logger.succeed('Custom color')
268
+ ```
269
+
270
+ ### markup
271
+
272
+ Pretty-prints any value with syntax coloring — strings, numbers, booleans, `null`, `Date`, nested objects, and arrays.
273
+
274
+ ```ts
275
+ import { markup } from 'termkit'
276
+
277
+ console.log(markup({ name: 'alice', roles: ['admin', 'editor'], active: true }))
278
+ ```
279
+
280
+ Custom styles and value translations:
281
+
282
+ ```ts
283
+ import { markup, Color } from 'termkit'
284
+
285
+ const out = markup(data, {
286
+ styles: {
287
+ number: (v) => Color.hex('#f97316')(v),
288
+ boolean: (v) => Color.hex('#a855f7')(v),
289
+ },
290
+ translations: {
291
+ createdAt: (v) => new Date(v as string),
292
+ },
293
+ })
294
+ console.log(out)
295
+ ```
296
+
297
+ ### Table
298
+
299
+ Renders tabular data with auto-sized columns, optional titles, alignment, and meta rows.
300
+
301
+ ```ts
302
+ import { Table } from 'termkit'
303
+
304
+ const rows = [
305
+ { name: 'Alice', role: 'admin', active: true },
306
+ { name: 'Bob', role: 'editor', active: false },
307
+ ]
308
+
309
+ new Table(rows).print()
310
+ ```
311
+
312
+ Column configuration — pass a `columns` array to control ordering, titles, alignment, and value formatting:
313
+
314
+ ```ts
315
+ new Table(rows, {
316
+ title: 'Users',
317
+ columns: [
318
+ { key: 'name', title: 'Name' },
319
+ { key: 'role', title: 'Role', align: 'center' },
320
+ { key: 'active', title: 'Active', value: (v) => (v ? 'yes' : 'no'), align: 'right' },
321
+ ],
322
+ separator: ' ',
323
+ }).print()
324
+ ```
325
+
326
+ Global alignment, margin, and meta rows (rendered below a separator after the data rows):
327
+
328
+ ```ts
329
+ new Table(rows, {
330
+ align: Table.center, // Table.left | Table.center | Table.right
331
+ margin: 1, // extra space added to each column's padding
332
+ meta: [{ name: 'Total', role: '', active: '' }],
333
+ }).print()
334
+ ```
335
+
336
+ Passing a string shorthand instead of a `ColumnOptions` object uses the key as both key and title:
337
+
338
+ ```ts
339
+ new Table(rows, { columns: ['name', 'role'] }).print()
340
+ ```
341
+
342
+ ### Chart
343
+
344
+ The `Chart` namespace provides horizontal bar, vertical column, heatmap, scatter, line, and sparkline visualizations. Every chart class has a `.print()` method that writes to stdout and a `.toString()` method that returns the rendered string.
345
+
346
+ All chart constructors accept optional `paddingX` and `paddingY` options to add whitespace around the output.
347
+
348
+ #### Chart.Bar
349
+
350
+ Horizontal bar chart. Each item maps a label to a value; the bar width scales to fill the terminal.
351
+
352
+ ```ts
353
+ import { Chart } from 'termkit'
354
+
355
+ new Chart.Bar([
356
+ { key: 'Mon', value: 42 },
357
+ { key: 'Tue', value: 67 },
358
+ { key: 'Wed', value: 31 },
359
+ ]).print()
360
+ ```
361
+
362
+ Custom style and `null` gaps (blank rows):
363
+
364
+ ```ts
365
+ import { Chart, Color } from 'termkit'
366
+
367
+ new Chart.Bar([
368
+ { key: 'Errors', value: 12, style: Color.red },
369
+ { key: 'Warnings', value: 45, style: Color.yellow },
370
+ null,
371
+ { key: 'OK', value: 89, style: Color.green },
372
+ ]).print()
373
+ ```
374
+
375
+ Pass `character` to use a custom fill character instead of a solid block:
376
+
377
+ ```ts
378
+ new Chart.Bar([
379
+ { key: 'CPU', value: 72, character: '▪' },
380
+ { key: 'RAM', value: 55, character: '▪' },
381
+ ]).print()
382
+ ```
383
+
384
+ Pass `width` to override the terminal column width used for scaling:
385
+
386
+ ```ts
387
+ new Chart.Bar(data, { width: 60, paddingX: 2, paddingY: 1 }).print()
388
+ ```
389
+
390
+ #### Chart.VerticalBar
391
+
392
+ Vertical column chart using Unicode block characters with fractional height resolution.
393
+
394
+ ```ts
395
+ new Chart.VerticalBar([
396
+ { key: 'M', value: 10 },
397
+ { key: 'T', value: 25 },
398
+ { key: 'W', value: 18 },
399
+ { key: 'T', value: 30 },
400
+ { key: 'F', value: 22 },
401
+ ], { height: 8, colWidth: 3 }).print()
402
+ ```
403
+
404
+ Pass `null` items to insert gaps between column groups:
405
+
406
+ ```ts
407
+ new Chart.VerticalBar([
408
+ { key: 'A', value: 15, style: Color.blue },
409
+ { key: 'B', value: 28, style: Color.blue },
410
+ null,
411
+ { key: 'C', value: 10, style: Color.magenta },
412
+ ], { height: 10 }).print()
413
+ ```
414
+
415
+ Pass `width` to have `colWidth` auto-calculated to fill a fixed total width:
416
+
417
+ ```ts
418
+ new Chart.VerticalBar(data, { width: 40, height: 12 }).print()
419
+ ```
420
+
421
+ #### Chart.Heatmap
422
+
423
+ 2-D grid colored by value intensity between a configurable low and high color.
424
+
425
+ ```ts
426
+ new Chart.Heatmap(
427
+ [
428
+ [1, 5, 9, 3],
429
+ [2, 6, 3, 8],
430
+ [8, 4, 7, 2],
431
+ ],
432
+ {
433
+ rowLabels: ['Row A', 'Row B', 'Row C'],
434
+ colLabels: ['C1', 'C2', 'C3', 'C4'],
435
+ colors: ['#0000ff', '#ff0000'],
436
+ }
437
+ ).print()
438
+ ```
439
+
440
+ Multi-stop color scale and explicit range:
441
+
442
+ ```ts
443
+ new Chart.Heatmap(data, {
444
+ colors: ['#0000ff', '#00ffff', '#ffff00', '#ff0000'],
445
+ min: 0,
446
+ max: 100,
447
+ cellWidth: 3,
448
+ }).print()
449
+ ```
450
+
451
+ #### Chart.Scatter
452
+
453
+ 2-D scatter plot with optional labeled axes. Points outside the plot bounds are silently clipped.
454
+
455
+ ```ts
456
+ new Chart.Scatter([
457
+ { x: 1, y: 2 },
458
+ { x: 3, y: 5 },
459
+ { x: 7, y: 3 },
460
+ ]).print()
461
+ ```
462
+
463
+ Custom characters, per-point styles, and explicit axis bounds:
464
+
465
+ ```ts
466
+ import { Chart, Color } from 'termkit'
467
+
468
+ new Chart.Scatter([
469
+ { x: 10, y: 20, character: '●', style: Color.green },
470
+ { x: 30, y: 50, character: '●', style: Color.red },
471
+ ], {
472
+ width: 60,
473
+ height: 20,
474
+ xMin: 0,
475
+ xMax: 40,
476
+ yMin: 0,
477
+ yMax: 60,
478
+ }).print()
479
+ ```
480
+
481
+ Disable axes for a raw grid output:
482
+
483
+ ```ts
484
+ new Chart.Scatter(data, { axes: false }).print()
485
+ ```
486
+
487
+ #### Chart.Line
488
+
489
+ Line chart that interpolates between data points. Accepts the same axis options as `Chart.Scatter`.
490
+
491
+ ```ts
492
+ import { Chart } from 'termkit'
493
+
494
+ new Chart.Line(
495
+ Array.from({ length: 40 }, (_, i) => ({ x: i, y: Math.sin(i * 0.3) * 4 })),
496
+ { height: 12 }
497
+ ).print()
498
+ ```
499
+
500
+ Per-point styles and optional fill below the line:
501
+
502
+ ```ts
503
+ import { Chart, Color } from 'termkit'
504
+
505
+ new Chart.Line(data, { fill: true, style: (s) => Color.cyan(s) }).print()
506
+ ```
507
+
508
+ Options: `width`, `height`, `xMin`, `xMax`, `yMin`, `yMax`, `character`, `axes`, `fill`, `paddingX`, `paddingY`.
509
+
510
+ #### Chart.Sparkline
511
+
512
+ Returns a single-line sparkline string using Unicode block characters. Useful for inline metrics.
513
+
514
+ ```ts
515
+ import { Chart, Color } from 'termkit'
516
+
517
+ const samples = [12, 45, 23, 67, 89, 55, 34, 78, 61]
518
+ console.log('CPU ' + Chart.Sparkline(samples, { style: (s) => Color.green(s) }))
519
+ // CPU ▁▃▁▅█▄▂▆▄
520
+ ```
521
+
522
+ Options: `min`, `max`, `style`.
523
+
524
+ ### Bar — ETA and rate tracking
525
+
526
+ Attach progress tracking to an animated `Bar` with `.track()` and `.tick()`.
527
+
528
+ ```ts
529
+ import { Bar } from 'termkit'
530
+
531
+ const total = 500
532
+ const bar = new Bar({ progress: 0 })
533
+ bar.track(total, { showRate: true, showEta: true, unit: 'files' })
534
+ bar.message('Processing…')
535
+ bar.start()
536
+
537
+ for await (const item of items) {
538
+ await process(item)
539
+ bar.tick()
540
+ }
541
+
542
+ bar.stop()
543
+ bar.succeed(`Done — ${total} files processed`)
544
+ ```
545
+
546
+ Each `tick(n?)` increments the completed count, updates `progress`, and appends a live `12.3/s · ETA 8s` suffix that shrinks the bar to keep the full line within terminal width.
547
+
548
+ Raw values are available as getters at any time:
549
+
550
+ ```ts
551
+ bar.rate // units per second (number)
552
+ bar.eta // estimated seconds remaining (number)
553
+ ```
554
+
555
+ Options on `track(total, opts?)`: `unit` (label appended to rate), `showRate` (default `true`), `showEta` (default `true`). Both can also be set via constructor: `new Bar({ showRate: true, showEta: true, rateUnit: 'MB' })`.
556
+
557
+ ### MultiBar
558
+
559
+ Renders multiple `Bar` instances as a synchronized block. Each bar animates independently; calling `.succeed()`, `.fail()`, `.warn()`, or `.info()` on a bar freezes that line while the others keep running. The group stops automatically when every bar is finalized.
560
+
561
+ ```ts
562
+ import { MultiBar, Bar } from 'termkit'
563
+
564
+ const multi = new MultiBar()
565
+ const download = multi.add({ text: 'Downloading', progress: 0, colors: Bar.COLORS.cool })
566
+ const build = multi.add({ text: 'Building', progress: 0, colors: Bar.COLORS.heat })
567
+ const deploy = multi.add({ text: 'Deploying' }) // indeterminate until started
568
+
569
+ multi.start()
570
+
571
+ await runDownload(p => { download.progress = p })
572
+ download.succeed('Downloaded')
573
+
574
+ await runBuild(p => { build.progress = p })
575
+ build.succeed('Built')
576
+
577
+ deploy.progress = 0
578
+ await runDeploy(p => { deploy.progress = p })
579
+ deploy.succeed('Deployed')
580
+
581
+ multi.stop()
582
+ ```
583
+
584
+ Each `add()` call accepts the same options as `Bar` and returns a `Bar` instance — `.message()`, `.tick()`, `.track()`, `.progress`, and the completion methods all work the same way. Bars must be added before `.start()`.
585
+
586
+ Options: `interval`.
587
+
588
+ ### Spinner
589
+
590
+ Animated spinner for indeterminate work. Shares the same completion API as `Bar` — `.succeed()`, `.fail()`, `.warn()`, `.info()`.
591
+
592
+ ```ts
593
+ import { Spinner } from 'termkit'
594
+
595
+ const spinner = new Spinner({ text: 'Loading…' })
596
+ spinner.start()
597
+
598
+ await doWork()
599
+
600
+ spinner.succeed('Done')
601
+ ```
602
+
603
+ Update the label while running:
604
+
605
+ ```ts
606
+ spinner.message('Still working…')
607
+ ```
608
+
609
+ Built-in frame sets are available on `Spinner.FRAMES`:
610
+
611
+ ```ts
612
+ new Spinner({ frames: Spinner.FRAMES.dots, text: 'Thinking…' }).start()
613
+ ```
614
+
615
+ Frame sets: `braille`, `dots`, `line`, `arrow`, `bounce`.
616
+
617
+ Options: `frames`, `text`, `prefix`, `suffix`, `reverse`, `interval`, `colors`, `bgColors`, `colorCycle`, `shimmer`, `successColor`, `failColor`, `warnColor`, `infoColor`, `glyphs`.
618
+
619
+ ### Scrollbox
620
+
621
+ Interactive terminal pager. Renders a fixed-height viewport over an array of strings with keyboard navigation. Requires an interactive TTY.
622
+
623
+ ```ts
624
+ import { scrollbox } from 'termkit'
625
+
626
+ await scrollbox(lines, { height: 20, title: 'Output', lineNumbers: true })
627
+ ```
628
+
629
+ Or use the class directly for more control:
630
+
631
+ ```ts
632
+ import { Scrollbox } from 'termkit'
633
+
634
+ const box = new Scrollbox({ height: 15, scrollbar: true, wrapLines: true })
635
+ await box.show(lines)
636
+ ```
637
+
638
+ Keyboard controls: ↑↓ / `j` `k` scroll one line · `d` / `u` half-page · `f` / `b` full page · `g` top · `G` bottom · Enter / Escape / `q` close.
639
+
640
+ Options: `height`, `title`, `lineNumbers`, `scrollbar`, `borderColor`, `wrapLines`.
641
+
642
+ ### truncate
643
+
644
+ ANSI-aware string truncation. Measures visible length ignoring escape codes, and appends a configurable suffix.
645
+
646
+ ```ts
647
+ import { truncate } from 'termkit'
648
+
649
+ truncate('The quick brown fox jumps over the lazy dog', 20)
650
+ // 'The quick brown fox…'
651
+
652
+ truncate(coloredString, 40, ' [more]')
653
+ ```
654
+
655
+ ### wrap
656
+
657
+ ANSI-aware word wrap. Breaks at spaces to keep each line within a given column width.
658
+
659
+ ```ts
660
+ import { wrap } from 'termkit'
661
+
662
+ console.log(wrap(longParagraph, 60))
663
+ ```
664
+
139
665
  ## API
140
666
 
667
+ ### Program
668
+
669
+ | Method | Signature | Description |
670
+ |---|---|---|
671
+ | `Program.command` | `(name, variables?, info?) => Command` | Create a command |
672
+ | `Program.option` | `(short, long, variables, info) => Option` | Create a standalone option |
673
+ | `Program.middleware` | `(fn) => fn` | Identity helper for typing middleware inline |
674
+ | `Program.parse` | `(argv) => Promise<void>` | Parse argv using the root command |
675
+ | `Program.setDefaults` | `(defaults) => void` | Apply middleware/options to all new commands |
676
+
141
677
  ### Functions
142
678
 
143
679
  | Function | Signature | Description |
144
680
  |---|---|---|
145
- | `command` | `(name, variables?, info?) => Command` | Create a command |
146
- | `option` | `(short, long, variables, info) => Option` | Create an option |
147
- | `middleware` | `(fn) => fn` | Identity helper for typing middleware inline |
148
- | `parse` | `(argv) => Promise<unknown>` | Parse using the root command |
149
- | `setDefaults` | `(defaults) => void` | Set defaults applied to all new commands |
681
+ | `configure` | `(opts) => void` | Set global accent color and display options |
682
+ | `scrollbox` | `(lines, options?) => Promise<void>` | Interactive terminal pager |
683
+ | `markup` | `(data, options?) => string` | Pretty-print a value with syntax coloring |
684
+ | `input` | `(prompt, options?) => Promise<string \| number \| boolean \| null>` | Interactive text prompt |
685
+ | `confirm` | `(prompt, options?) => Promise<boolean \| null>` | Boolean yes/no prompt |
686
+ | `select` | `(prompt, items, options?) => Promise<T \| null>` | Single-item interactive picker |
687
+ | `multiSelect` | `(prompt, items, options?) => Promise<T[] \| null>` | Multi-item interactive picker |
688
+ | `Chart.Sparkline` | `(data, options?) => string` | Single-line sparkline string |
689
+ | `truncate` | `(s, maxLength, suffix?) => string` | ANSI-aware string truncation |
690
+ | `wrap` | `(s, width) => string` | ANSI-aware word wrap |
691
+ | `padLeft` | `(s, width) => string` | Right-align a string within a fixed width |
692
+ | `padRight` | `(s, width) => string` | Left-align a string within a fixed width |
693
+ | `padSides` | `(s, width) => string` | Center a string within a fixed width |
694
+ | `stringLength` | `(s) => number` | Visual length of a string, stripping ANSI escape codes |
150
695
 
151
696
  ### Classes
152
697
 
153
- `Command`, `Option`, `Variable`, `TermKit`
698
+ `Command`, `Option`, `Variable`, `TermKit`, `Bar`, `MultiBar`, `Spinner`, `Scrollbox`, `Input`, `Select`, `MultiSelect`, `Log`, `Table`, `Column`, `Chart.Bar`, `Chart.VerticalBar`, `Chart.Heatmap`, `Chart.Scatter`, `Chart.Line`
154
699
 
155
700
  ### Types
156
701
 
157
- `ActionFn`, `MiddlewareFn`, `ParsedOptions`, `CommandDefaults`, `VariableType`
702
+ `ActionFn`, `MiddlewareFn`, `ParsedOptions`, `CommandDefaults`, `VariableType`, `BarMode`, `BarOptions`, `MultiBarOptions`, `SpinnerOptions`, `InputOptions`, `InputReturn`, `InputType`, `SelectItem`, `SelectOptions`, `MultiSelectItem`, `MultiSelectOptions`, `LogOptions`, `TableOptions`, `ColumnOptions`, `ColumnAlign`, `MarkupOptions`, `MarkupStyleFn`, `MarkupStyles`, `HelpColor`, `Chart.BarItem`, `Chart.BarOptions`, `Chart.VerticalBarItem`, `Chart.VerticalBarOptions`, `Chart.HeatmapOptions`, `Chart.ScatterPoint`, `Chart.ScatterOptions`, `Chart.LinePoint`, `Chart.LineOptions`, `Chart.SparklineOptions`
158
703
 
159
704
  ## Authors
160
705