@lewishowles/cli-style 0.9.0 → 0.10.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 +13 -0
- package/README.md +77 -1
- package/bin/cli-style.js +10 -0
- package/package.json +1 -1
- package/src/capability/terminal.js +98 -0
- package/src/catalogue/renderer-catalogue.js +62 -0
- package/src/cli/catalogue-command.js +108 -0
- package/src/cli/gallery-command.js +8 -1
- package/src/cli/help.js +5 -0
- package/src/cli/render-command.js +17 -2
- package/src/formatters/ansi.js +17 -1
- package/src/gallery/render-gallery.js +108 -2
- package/src/index.js +18 -2
- package/src/patterns/diff-block.js +333 -0
- package/src/primitives/chip.js +1 -1
- package/src/primitives/panel.js +6 -1
- package/src/primitives/sparkline.js +209 -0
- package/src/theme/colours.js +172 -36
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.10.0 - 2026-07-20
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added light and dark ANSI-256 colour palettes with automatic theme detection (explicit flag/option, `COLORFGBG`, then a `COLORTERM`/`TERM_PROGRAM` best-effort signal, falling back to dark).
|
|
10
|
+
- Added `cli-style list` and `cli-style describe` for static renderer catalogue discovery.
|
|
11
|
+
- Added a `sparkline()` renderer (`sparkline` for `cli-style render`) for compact trend display with latest, minimum, and maximum values.
|
|
12
|
+
- Added a `diffBlock()` renderer (`diff-block` for `cli-style render`) for structured added/removed/context/header diff presentation.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Fixed panel body text losing legibility against its background fill in some theme/terminal combinations by giving panels their own explicit theme-matched text colour instead of relying on the terminal-inherited default.
|
|
17
|
+
|
|
5
18
|
## 0.9.0 - 2026-07-16
|
|
6
19
|
|
|
7
20
|
### Added
|
package/README.md
CHANGED
|
@@ -241,10 +241,12 @@ Renderer names are stable for `cli-style render`, `cli_style_render`, and Python
|
|
|
241
241
|
| `table` | `table(options)` | Use `cli_style_render` | Use `render("table", ...)` | Use `CliStyle.render` | Tabular records with narrow-width fallback. |
|
|
242
242
|
| `progress-bar` | `progressBar(options)` | Use `cli_style_render` | Use `render("progress-bar", ...)` | Use `CliStyle.render` | Single progress value with numeric text. |
|
|
243
243
|
| `bar-chart` | `barChart(options)` | Use `cli_style_render` | Use `render("bar-chart", ...)` | Use `CliStyle.render` | Multi-row bar chart. |
|
|
244
|
+
| `sparkline` | `sparkline(options)` | Use `cli_style_render` | Use `render("sparkline", ...)` | Use `CliStyle.render` | Compact trend with latest, minimum, and maximum values. |
|
|
244
245
|
| `step` | `step(label, state, options)` | Use `cli_style_render` | Use `render("step", ...)` | Use `CliStyle.render` | One workflow step. |
|
|
245
246
|
| `step-progress` | `stepProgress(options)` | Use `cli_style_render` | Use `render("step-progress", ...)` | Use `CliStyle.render` | Numbered workflow steps. |
|
|
246
247
|
| `empty-state` | `emptyState(title, detail, options)` | Use `cli_style_render` | Use `render("empty-state", ...)` | Use `CliStyle.render` | Empty result message. |
|
|
247
248
|
| `error-block` | `errorBlock(title, lines, options)` | Use `cli_style_render` | Use `render("error-block", ...)` | Use `CliStyle.render` | Structured error block. |
|
|
249
|
+
| `diff-block` | `diffBlock(diff, options)` | Use `cli_style_render` | Use `render("diff-block", ...)` | Use `CliStyle.render` | Structured added, removed, context, and header lines. |
|
|
248
250
|
|
|
249
251
|
Use `render("<renderer>", data, ...)` (Python) or `CliStyle.render(_:data:options:)` (Swift) for aggregate patterns (`diagnostic-report`, `agent-transcript`, `compact-data-table`) or any renderer with multi-item fields.
|
|
250
252
|
|
|
@@ -337,6 +339,7 @@ Pre-render a `span` when only part of the hint needs emphasis.
|
|
|
337
339
|
| `table` | `columns`, `rows`, `width` |
|
|
338
340
|
| `progress-bar` | `value`, `max`, `barWidth`, `tone` |
|
|
339
341
|
| `bar-chart` | `rows`, `barWidth` |
|
|
342
|
+
| `sparkline` | `values`, `label`, `tone`, `width` |
|
|
340
343
|
| `step` | `label`, `state` |
|
|
341
344
|
| `step-progress` | `steps`, `current` |
|
|
342
345
|
| `empty-state` | `title`, `detail` |
|
|
@@ -344,6 +347,35 @@ Pre-render a `span` when only part of the hint needs emphasis.
|
|
|
344
347
|
|
|
345
348
|
For visual examples, run `cli-style gallery --section primitives`.
|
|
346
349
|
|
|
350
|
+
### `sparkline`
|
|
351
|
+
|
|
352
|
+
Pass finite numbers in time order. The rendered trend always includes `latest`, `min`, and `max` context. Set `width` to limit plotted samples, `tone` to choose an optional semantic colour, `colour: false` to disable ANSI output, or `unicode: false` for an ASCII-only ramp.
|
|
353
|
+
|
|
354
|
+
```js
|
|
355
|
+
sparkline({ label: "Deploys", values: [1, 2, 3, 5, 8] });
|
|
356
|
+
// Deploys: ▁▂▃▅█ latest=8 min=1 max=8
|
|
357
|
+
|
|
358
|
+
sparkline({ label: "Rollback rate", values: [8, 6, 4, 2], tone: "warning" });
|
|
359
|
+
// Rollback rate: █▆▃▁ latest=2 min=2 max=8
|
|
360
|
+
|
|
361
|
+
sparkline({ label: "Flat", values: [4, 4, 4, 4] });
|
|
362
|
+
// Flat: ▄▄▄▄ latest=4 min=4 max=4
|
|
363
|
+
|
|
364
|
+
sparkline({ label: "Negative", values: [-6, -4, -2], colour: false });
|
|
365
|
+
// Negative: ▁▅█ latest=-2 min=-6 max=-2
|
|
366
|
+
|
|
367
|
+
sparkline({ label: "Narrow", values: [0, 10, -5, 5, 2, 8], width: 4 });
|
|
368
|
+
// Narrow: ▃█▁▇ latest=8 min=-5 max=10
|
|
369
|
+
|
|
370
|
+
sparkline({ label: "No colour", values: [1, 3, 2], colour: false });
|
|
371
|
+
// No colour: ▁█▅ latest=2 min=1 max=3
|
|
372
|
+
|
|
373
|
+
sparkline({ label: "No Unicode", values: [1, 3, 2], unicode: false });
|
|
374
|
+
// No Unicode: .#= latest=2 min=1 max=3
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Empty or unusable `values` return `""`.
|
|
378
|
+
|
|
347
379
|
## Patterns
|
|
348
380
|
|
|
349
381
|
Patterns are built-in composite renderers for common report shapes. They use the same lower-level primitives internally, but accept structured objects so callers do not need to assemble panels, statuses, tables, and rows by hand.
|
|
@@ -358,6 +390,33 @@ Patterns are built-in composite renderers for common report shapes. They use the
|
|
|
358
390
|
| `confirmation-result` | `confirmationResult(confirmation, options)` | Confirmation outcome with detail. | `title`, `state`, `action`, `item`, `detail` |
|
|
359
391
|
| `next-step-block` | `nextStepBlock(nextStep, options)` | Next-step guidance. | `title`, `next`, `reason`, `commands`, `alternatives` |
|
|
360
392
|
| `compact-data-table` | `compactDataTable(data, options)` | Titled compact data table. | `title`, `summary`, `columns`, `rows` |
|
|
393
|
+
| `diff-block` | `diffBlock(diff, options)` | Structured diff presentation. | `title`, `path`, `lines` |
|
|
394
|
+
|
|
395
|
+
### `diff-block`
|
|
396
|
+
|
|
397
|
+
Pass structured lines with one of four types. The renderer adds stable textual prefixes, so colour is optional and never carries meaning alone.
|
|
398
|
+
|
|
399
|
+
```json
|
|
400
|
+
{
|
|
401
|
+
"title": "Renderer change",
|
|
402
|
+
"path": "src/render.js",
|
|
403
|
+
"lines": [
|
|
404
|
+
{ "type": "header", "text": "render()" },
|
|
405
|
+
{ "type": "added", "newLineNumber": 102, "text": "return nextStep;" },
|
|
406
|
+
{ "type": "removed", "oldLineNumber": 101, "text": "return currentStep;" },
|
|
407
|
+
{
|
|
408
|
+
"type": "context",
|
|
409
|
+
"oldLineNumber": 100,
|
|
410
|
+
"newLineNumber": 100,
|
|
411
|
+
"text": "const currentStep = getStep();"
|
|
412
|
+
}
|
|
413
|
+
]
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
`oldLineNumber` and `newLineNumber` are optional caller-supplied fields. Added lines use the new number, removed lines use the old number, and context lines use both. Numbered blocks show a stable gutter and computed `(+added -removed)` summary. Missing numbers fall back to the unnumbered output.
|
|
418
|
+
|
|
419
|
+
`diff-block` presents structured data only. It does not parse unified-diff strings, calculate patches or line numbers, or apply changes. Invalid line entries are ignored safely.
|
|
361
420
|
|
|
362
421
|
For visual examples, run `cli-style gallery --section patterns`.
|
|
363
422
|
|
|
@@ -533,16 +592,18 @@ Most renderers accept the same output options:
|
|
|
533
592
|
| --------- | ------------------------------------------------------------------------- |
|
|
534
593
|
| `profile` | Output profile: `human`, `agent`, `diagnostic`, `ci`, `plain`, or `json`. |
|
|
535
594
|
| `colour` | Whether ANSI colour should be applied. |
|
|
595
|
+
| `theme` | `auto`, `light`, or `dark` semantic colour palette. |
|
|
536
596
|
| `unicode` | Whether Unicode symbols should be used. |
|
|
537
597
|
| `width` | Available output width for renderers that adapt layout. |
|
|
538
598
|
|
|
539
|
-
Use `createCliStyle()` to resolve these options from `argv`, `env`, `stdout`, CI, TTY, `NO_COLOR`, `FORCE_COLOR`, and terminal capability.
|
|
599
|
+
Use `createCliStyle()` to resolve these options from `argv`, `env`, `stdout`, CI, TTY, `NO_COLOR`, `FORCE_COLOR`, and terminal capability. `theme: "auto"` resolves in this order: explicit `--light`/`--dark` flags or `theme: "light"`/`"dark"`, recognised `COLORFGBG` background slot, `COLORTERM` or `TERM_PROGRAM`, then a dark fallback. The additional environment signals are best-effort terminal identifiers, so they select the conservative dark palette rather than claiming a light or dark preference. `NO_COLOR`, `TERM=dumb`, `--plain`, and explicit no-colour flags still disable colour.
|
|
540
600
|
|
|
541
601
|
### CLI and Bash flags
|
|
542
602
|
|
|
543
603
|
| Flag | Purpose |
|
|
544
604
|
| ---------------------------- | -------------------------------------- |
|
|
545
605
|
| `--profile <name>` | Render with a named profile. |
|
|
606
|
+
| `--light` / `--dark` | Override automatic terminal theme. |
|
|
546
607
|
| `--plain` | Disable colour and Unicode decoration. |
|
|
547
608
|
| `--no-colour` / `--no-color` | Disable ANSI colour. |
|
|
548
609
|
| `--no-unicode` | Use ASCII symbols. |
|
|
@@ -606,6 +667,19 @@ Tone values used by public APIs include `info`, `success`, `warning`, `danger`,
|
|
|
606
667
|
|
|
607
668
|
## Gallery
|
|
608
669
|
|
|
670
|
+
## Renderer discovery
|
|
671
|
+
|
|
672
|
+
List the available renderers or inspect one renderer before constructing a JSON payload:
|
|
673
|
+
|
|
674
|
+
```bash
|
|
675
|
+
cli-style list
|
|
676
|
+
cli-style list --json
|
|
677
|
+
cli-style describe progress-bar
|
|
678
|
+
cli-style describe progress-bar --json
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
`describe` includes the JavaScript API name, main input fields, and a focused gallery command when one is available.
|
|
682
|
+
|
|
609
683
|
Use the gallery to review current renderer output:
|
|
610
684
|
|
|
611
685
|
```bash
|
|
@@ -617,6 +691,8 @@ cli-style gallery --fixture audit-finding
|
|
|
617
691
|
cli-style gallery --profile agent
|
|
618
692
|
cli-style gallery --width 64
|
|
619
693
|
cli-style gallery --variants
|
|
694
|
+
cli-style gallery --light --section primitives
|
|
695
|
+
cli-style gallery --dark --section primitives
|
|
620
696
|
```
|
|
621
697
|
|
|
622
698
|
Use `--interactive` to select a section or fixture with `fzf` when it is installed.
|
package/bin/cli-style.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { Buffer } from "node:buffer";
|
|
4
4
|
import { createCliStyle, renderGallery, renderHelp } from "../src/index.js";
|
|
5
5
|
import { parseAdapterPathRequest, renderAdapterPath } from "../src/cli/adapter-path-command.js";
|
|
6
|
+
import { parseCatalogueRequest, renderCatalogue } from "../src/cli/catalogue-command.js";
|
|
6
7
|
import { parseRenderRequest, renderJsonInput } from "../src/cli/render-command.js";
|
|
7
8
|
|
|
8
9
|
import {
|
|
@@ -54,6 +55,15 @@ if (command === undefined || command === "--help" || command === "-h") {
|
|
|
54
55
|
console.error(error.message);
|
|
55
56
|
process.exitCode = 1;
|
|
56
57
|
}
|
|
58
|
+
} else if (command === "list" || command === "describe") {
|
|
59
|
+
try {
|
|
60
|
+
const request = parseCatalogueRequest(command, args.slice(1));
|
|
61
|
+
|
|
62
|
+
print(renderCatalogue(request, ui.options));
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error(error.message);
|
|
65
|
+
process.exitCode = 1;
|
|
66
|
+
}
|
|
57
67
|
} else if (command === "render") {
|
|
58
68
|
try {
|
|
59
69
|
const request = parseRenderRequest(args.slice(1));
|
package/package.json
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { isTheme, themes } from "../theme/colours.js";
|
|
2
|
+
|
|
1
3
|
// Default terminal width when no stream width is available.
|
|
2
4
|
const defaultWidth = 80;
|
|
3
5
|
|
|
6
|
+
// Known terminal signals support a conservative dark palette when no theme is explicit.
|
|
7
|
+
const terminalThemeSignals = ["COLORTERM", "TERM_PROGRAM"];
|
|
8
|
+
|
|
4
9
|
/**
|
|
5
10
|
* Resolve terminal output capabilities from injected args, env, and stream data.
|
|
6
11
|
*
|
|
@@ -47,11 +52,104 @@ export function resolveTerminalCapabilities(options = {}) {
|
|
|
47
52
|
isCi,
|
|
48
53
|
isDumb,
|
|
49
54
|
isTty,
|
|
55
|
+
theme: resolveTheme({
|
|
56
|
+
argv,
|
|
57
|
+
env,
|
|
58
|
+
theme: options.theme,
|
|
59
|
+
}),
|
|
50
60
|
unicode,
|
|
51
61
|
width,
|
|
52
62
|
};
|
|
53
63
|
}
|
|
54
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Resolve a terminal theme from explicit overrides and terminal signals.
|
|
67
|
+
*
|
|
68
|
+
* @param {object} options
|
|
69
|
+
* Theme resolution inputs.
|
|
70
|
+
* @returns {string}
|
|
71
|
+
* Resolved light or dark theme.
|
|
72
|
+
*/
|
|
73
|
+
export function resolveTheme(options = {}) {
|
|
74
|
+
const flagTheme = readThemeFlag(options.argv ?? []);
|
|
75
|
+
|
|
76
|
+
if (flagTheme !== undefined) {
|
|
77
|
+
return flagTheme;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (isTheme(options.theme) && options.theme !== themes.AUTO) {
|
|
81
|
+
return options.theme;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const colourFgBgTheme = resolveColourFgBgTheme(options.env?.COLORFGBG);
|
|
85
|
+
|
|
86
|
+
if (colourFgBgTheme !== themes.AUTO) {
|
|
87
|
+
return colourFgBgTheme;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return resolveTerminalSignalTheme(options.env) ?? themes.DARK;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Resolve a conservative theme from best-effort terminal signals.
|
|
95
|
+
*
|
|
96
|
+
* @param {object} env
|
|
97
|
+
* Environment values to inspect.
|
|
98
|
+
* @returns {string|undefined}
|
|
99
|
+
* Dark theme when a known terminal signal is present.
|
|
100
|
+
*/
|
|
101
|
+
function resolveTerminalSignalTheme(env = {}) {
|
|
102
|
+
if (terminalThemeSignals.some((signal) => env[signal])) {
|
|
103
|
+
return themes.DARK;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Resolve known COLORFGBG background slots without guessing custom palettes.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} colourFgBg
|
|
113
|
+
* Terminal foreground and background capability string.
|
|
114
|
+
* @returns {string}
|
|
115
|
+
* Resolved light, dark, or automatic theme.
|
|
116
|
+
*/
|
|
117
|
+
function resolveColourFgBgTheme(colourFgBg) {
|
|
118
|
+
const background = colourFgBg?.split(";").at(-1);
|
|
119
|
+
|
|
120
|
+
if (background === "0" || background === "8") {
|
|
121
|
+
return themes.DARK;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (background === "7" || background === "15") {
|
|
125
|
+
return themes.LIGHT;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return themes.AUTO;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Read the final explicit theme flag so later command arguments can override earlier ones.
|
|
133
|
+
*
|
|
134
|
+
* @param {string[]} argv
|
|
135
|
+
* CLI arguments to inspect.
|
|
136
|
+
* @returns {string|undefined}
|
|
137
|
+
* Explicit theme when present.
|
|
138
|
+
*/
|
|
139
|
+
function readThemeFlag(argv) {
|
|
140
|
+
let theme;
|
|
141
|
+
|
|
142
|
+
for (const argument of argv) {
|
|
143
|
+
if (argument === "--dark") {
|
|
144
|
+
theme = themes.DARK;
|
|
145
|
+
} else if (argument === "--light") {
|
|
146
|
+
theme = themes.LIGHT;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return theme;
|
|
151
|
+
}
|
|
152
|
+
|
|
55
153
|
/**
|
|
56
154
|
* Resolve colour support from explicit flags and terminal state.
|
|
57
155
|
*
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Static renderer metadata shared by CLI discovery and render validation.
|
|
2
|
+
export const rendererCatalogue = [
|
|
3
|
+
["agent-transcript", "pattern", "agentTranscript", ["entries"], "agent-transcript"],
|
|
4
|
+
["audit-finding", "pattern", "auditFinding", ["finding", "result"], "audit-finding"],
|
|
5
|
+
["bar-chart", "primitive", "barChart", ["rows"], undefined],
|
|
6
|
+
["chip", "primitive", "chip", ["label", "tone"], undefined],
|
|
7
|
+
["command-result", "pattern", "commandResult", ["result", "summary"], "command-result"],
|
|
8
|
+
["compact-data-table", "pattern", "compactDataTable", ["columns", "rows"], "compact-data-table"],
|
|
9
|
+
[
|
|
10
|
+
"confirmation-result",
|
|
11
|
+
"pattern",
|
|
12
|
+
"confirmationResult",
|
|
13
|
+
["action", "state"],
|
|
14
|
+
"confirmation-result",
|
|
15
|
+
],
|
|
16
|
+
[
|
|
17
|
+
"diagnostic-report",
|
|
18
|
+
"pattern",
|
|
19
|
+
"diagnosticReport",
|
|
20
|
+
["findings", "summary"],
|
|
21
|
+
"diagnostic-report",
|
|
22
|
+
],
|
|
23
|
+
["diff-block", "pattern", "diffBlock", ["lines"], "diff-block"],
|
|
24
|
+
["divider", "primitive", "divider", ["label"], undefined],
|
|
25
|
+
["empty-state", "primitive", "emptyState", ["detail", "title"], undefined],
|
|
26
|
+
["error-block", "primitive", "errorBlock", ["lines", "title"], undefined],
|
|
27
|
+
["hint", "primitive", "hint", ["message"], undefined],
|
|
28
|
+
["next-step-block", "pattern", "nextStepBlock", ["next", "reason"], "next-step-block"],
|
|
29
|
+
["panel", "primitive", "panel", ["lines", "title", "tone"], undefined],
|
|
30
|
+
["progress-bar", "primitive", "progressBar", ["max", "value"], undefined],
|
|
31
|
+
["row", "primitive", "row", ["label", "value"], undefined],
|
|
32
|
+
["row-group", "primitive", "rowGroup", ["rows"], undefined],
|
|
33
|
+
["sparkline", "primitive", "sparkline", ["values"], "sparkline"],
|
|
34
|
+
["span", "primitive", "span", ["tone", "value"], undefined],
|
|
35
|
+
["status", "primitive", "status", ["detail", "type"], undefined],
|
|
36
|
+
["step", "primitive", "step", ["label", "state"], undefined],
|
|
37
|
+
["step-progress", "primitive", "stepProgress", ["current", "steps"], undefined],
|
|
38
|
+
["table", "primitive", "table", ["columns", "rows"], undefined],
|
|
39
|
+
["task-summary", "pattern", "taskSummary", ["result", "task"], "task-summary"],
|
|
40
|
+
].map(([name, category, api, fields, fixture]) => ({
|
|
41
|
+
api,
|
|
42
|
+
category,
|
|
43
|
+
fields,
|
|
44
|
+
fixture,
|
|
45
|
+
name,
|
|
46
|
+
purpose: `${api} renderer.`,
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
// Stable CLI names derived from the catalogue.
|
|
50
|
+
export const rendererNames = rendererCatalogue.map((renderer) => renderer.name);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Find renderer metadata by its stable CLI name.
|
|
54
|
+
*
|
|
55
|
+
* @param {string} name
|
|
56
|
+
* Renderer name to look up.
|
|
57
|
+
* @returns {object|undefined}
|
|
58
|
+
* Renderer metadata when found.
|
|
59
|
+
*/
|
|
60
|
+
export function getRendererMetadata(name) {
|
|
61
|
+
return rendererCatalogue.find((renderer) => renderer.name === name);
|
|
62
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { getRendererMetadata, rendererCatalogue } from "../catalogue/renderer-catalogue.js";
|
|
2
|
+
|
|
3
|
+
// Rendering flags are resolved before catalogue command parsing.
|
|
4
|
+
const globalRenderingFlags = new Set([
|
|
5
|
+
"--dark",
|
|
6
|
+
"--json",
|
|
7
|
+
"--light",
|
|
8
|
+
"--no-color",
|
|
9
|
+
"--no-colour",
|
|
10
|
+
"--no-unicode",
|
|
11
|
+
"--plain",
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse a catalogue discovery request.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} command
|
|
18
|
+
* Catalogue command name.
|
|
19
|
+
* @param {string[]} args
|
|
20
|
+
* Arguments after the command.
|
|
21
|
+
* @returns {object}
|
|
22
|
+
* Parsed catalogue request.
|
|
23
|
+
*/
|
|
24
|
+
export function parseCatalogueRequest(command, args = []) {
|
|
25
|
+
const commandArgs = args.filter((argument) => !globalRenderingFlags.has(argument));
|
|
26
|
+
|
|
27
|
+
if (command === "list" && commandArgs.length === 0) {
|
|
28
|
+
return {
|
|
29
|
+
command,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (
|
|
34
|
+
command === "describe" &&
|
|
35
|
+
commandArgs.length === 1 &&
|
|
36
|
+
getRendererMetadata(commandArgs[0]) !== undefined
|
|
37
|
+
) {
|
|
38
|
+
return {
|
|
39
|
+
command,
|
|
40
|
+
renderer: commandArgs[0],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (command === "describe" && commandArgs.length === 1) {
|
|
45
|
+
throw new Error(`Unknown renderer: ${commandArgs[0]}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
throw new Error(
|
|
49
|
+
command === "describe" ? "Usage: cli-style describe <renderer>" : "Usage: cli-style list",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Render catalogue data for the requested output profile.
|
|
55
|
+
*
|
|
56
|
+
* @param {object} request
|
|
57
|
+
* Parsed catalogue request.
|
|
58
|
+
* @param {object} options
|
|
59
|
+
* Resolved rendering options.
|
|
60
|
+
* @returns {string}
|
|
61
|
+
* Text or JSON catalogue output.
|
|
62
|
+
*/
|
|
63
|
+
export function renderCatalogue(request, options = {}) {
|
|
64
|
+
const data =
|
|
65
|
+
request.command === "list" ? rendererCatalogue : getRendererMetadata(request.renderer);
|
|
66
|
+
|
|
67
|
+
if (options.profile === "json") {
|
|
68
|
+
return JSON.stringify(data, null, 2);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (request.command === "describe") {
|
|
72
|
+
return renderDescription(data);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return ["primitive", "pattern"]
|
|
76
|
+
.flatMap((category) => [
|
|
77
|
+
category,
|
|
78
|
+
...rendererCatalogue
|
|
79
|
+
.filter((renderer) => renderer.category === category)
|
|
80
|
+
.map((renderer) => ` ${renderer.name} ${renderer.api}`),
|
|
81
|
+
"",
|
|
82
|
+
])
|
|
83
|
+
.slice(0, -1)
|
|
84
|
+
.join("\n");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Render one renderer's discovery details.
|
|
89
|
+
*
|
|
90
|
+
* @param {object} renderer
|
|
91
|
+
* Renderer metadata.
|
|
92
|
+
* @returns {string}
|
|
93
|
+
* Human-readable renderer description.
|
|
94
|
+
*/
|
|
95
|
+
function renderDescription(renderer) {
|
|
96
|
+
const gallery =
|
|
97
|
+
renderer.fixture === undefined
|
|
98
|
+
? "No focused fixture."
|
|
99
|
+
: `cli-style gallery --fixture ${renderer.fixture}`;
|
|
100
|
+
|
|
101
|
+
return [
|
|
102
|
+
renderer.name,
|
|
103
|
+
`Category: ${renderer.category}`,
|
|
104
|
+
`JavaScript: ${renderer.api}`,
|
|
105
|
+
`Fields: ${renderer.fields.join(", ")}`,
|
|
106
|
+
`Gallery: ${gallery}`,
|
|
107
|
+
].join("\n");
|
|
108
|
+
}
|
|
@@ -4,7 +4,14 @@ import { galleryFixtures, gallerySections, galleryVariants } from "../gallery/re
|
|
|
4
4
|
import { isProfile, profiles } from "../profiles/profiles.js";
|
|
5
5
|
|
|
6
6
|
// Global rendering flags accepted after `gallery` for focused review commands.
|
|
7
|
-
const globalRenderingFlags = new Set([
|
|
7
|
+
const globalRenderingFlags = new Set([
|
|
8
|
+
"--dark",
|
|
9
|
+
"--light",
|
|
10
|
+
"--no-color",
|
|
11
|
+
"--no-colour",
|
|
12
|
+
"--no-unicode",
|
|
13
|
+
"--plain",
|
|
14
|
+
]);
|
|
8
15
|
|
|
9
16
|
/**
|
|
10
17
|
* Parse gallery command arguments.
|
package/src/cli/help.js
CHANGED
|
@@ -5,18 +5,23 @@ const helpLines = [
|
|
|
5
5
|
"Usage:",
|
|
6
6
|
" cli-style --help",
|
|
7
7
|
" cli-style adapter-path bash|python",
|
|
8
|
+
" cli-style list [options]",
|
|
9
|
+
" cli-style describe <renderer> [options]",
|
|
8
10
|
" cli-style gallery [variant] [options]",
|
|
9
11
|
" cli-style render <renderer> [options] < input.json",
|
|
10
12
|
"",
|
|
11
13
|
"Commands:",
|
|
12
14
|
" adapter-path Print a Bash or Python adapter path.",
|
|
13
15
|
" gallery Print the read-only style gallery.",
|
|
16
|
+
" list List available primitives and patterns.",
|
|
17
|
+
" describe Describe one renderer and its input fields.",
|
|
14
18
|
" render Render caller-provided JSON from stdin.",
|
|
15
19
|
"",
|
|
16
20
|
"Gallery variants:",
|
|
17
21
|
" current, no-colour, no-unicode, plain",
|
|
18
22
|
"",
|
|
19
23
|
"Options:",
|
|
24
|
+
" --light, --dark Override automatic terminal-theme detection.",
|
|
20
25
|
" --section <name> Show primitives or patterns.",
|
|
21
26
|
" --fixture <name> Show one named pattern fixture.",
|
|
22
27
|
" --profile <name> Render with a text profile.",
|
|
@@ -4,6 +4,7 @@ import { commandResult } from "../patterns/command-result.js";
|
|
|
4
4
|
import { compactDataTable } from "../patterns/compact-data-table.js";
|
|
5
5
|
import { confirmationResult } from "../patterns/confirmation-result.js";
|
|
6
6
|
import { diagnosticReport } from "../patterns/diagnostic-report.js";
|
|
7
|
+
import { diffBlock } from "../patterns/diff-block.js";
|
|
7
8
|
import { nextStepBlock } from "../patterns/next-step-block.js";
|
|
8
9
|
import { taskSummary } from "../patterns/task-summary.js";
|
|
9
10
|
import { barChart } from "../primitives/bar-chart.js";
|
|
@@ -14,11 +15,13 @@ import { panel } from "../primitives/panel.js";
|
|
|
14
15
|
import { progressBar } from "../primitives/progress-bar.js";
|
|
15
16
|
import { row } from "../primitives/row.js";
|
|
16
17
|
import { rowGroup } from "../primitives/row-group.js";
|
|
18
|
+
import { sparkline } from "../primitives/sparkline.js";
|
|
17
19
|
import { span } from "../primitives/span.js";
|
|
18
20
|
import { status } from "../primitives/status.js";
|
|
19
21
|
import { step, stepProgress } from "../primitives/step-progress.js";
|
|
20
22
|
import { table } from "../primitives/table.js";
|
|
21
23
|
import { isProfile, profiles } from "../profiles/profiles.js";
|
|
24
|
+
export { rendererNames } from "../catalogue/renderer-catalogue.js";
|
|
22
25
|
|
|
23
26
|
// Renderer names accepted by the custom-input render command.
|
|
24
27
|
const renderers = {
|
|
@@ -38,6 +41,7 @@ const renderers = {
|
|
|
38
41
|
"compact-data-table": (input, options) => compactDataTable(input, options),
|
|
39
42
|
"confirmation-result": (input, options) => confirmationResult(input, options),
|
|
40
43
|
"diagnostic-report": (input, options) => diagnosticReport(input, options),
|
|
44
|
+
"diff-block": (input, options) => diffBlock(input, options),
|
|
41
45
|
divider: (input, options) =>
|
|
42
46
|
divider({
|
|
43
47
|
...input,
|
|
@@ -79,6 +83,11 @@ const renderers = {
|
|
|
79
83
|
...input,
|
|
80
84
|
...options,
|
|
81
85
|
}),
|
|
86
|
+
sparkline: (input, options) =>
|
|
87
|
+
sparkline({
|
|
88
|
+
...input,
|
|
89
|
+
...options,
|
|
90
|
+
}),
|
|
82
91
|
span: (input, options) =>
|
|
83
92
|
span(input.value, input.tone, {
|
|
84
93
|
...input,
|
|
@@ -108,10 +117,16 @@ const renderers = {
|
|
|
108
117
|
};
|
|
109
118
|
|
|
110
119
|
// Global rendering flags accepted after `render <renderer>`.
|
|
111
|
-
const globalRenderingFlags = new Set([
|
|
120
|
+
const globalRenderingFlags = new Set([
|
|
121
|
+
"--dark",
|
|
122
|
+
"--light",
|
|
123
|
+
"--no-color",
|
|
124
|
+
"--no-colour",
|
|
125
|
+
"--no-unicode",
|
|
126
|
+
"--plain",
|
|
127
|
+
]);
|
|
112
128
|
|
|
113
129
|
// Renderer names exposed for help text and tests.
|
|
114
|
-
export const rendererNames = Object.keys(renderers);
|
|
115
130
|
|
|
116
131
|
/**
|
|
117
132
|
* Parse render command arguments.
|
package/src/formatters/ansi.js
CHANGED
|
@@ -100,7 +100,7 @@ export function stripAnsi(value) {
|
|
|
100
100
|
* Coloured text, or the original text when colour is disabled.
|
|
101
101
|
*/
|
|
102
102
|
function wrapColour(value, colour, options, createCode) {
|
|
103
|
-
const resolvedColour = resolveColourValue(colour);
|
|
103
|
+
const resolvedColour = resolveColourValue(colour, options);
|
|
104
104
|
|
|
105
105
|
if (options.colour !== true || resolvedColour === null) {
|
|
106
106
|
return value;
|
|
@@ -118,6 +118,14 @@ function wrapColour(value, colour, options, createCode) {
|
|
|
118
118
|
* ANSI foreground sequence.
|
|
119
119
|
*/
|
|
120
120
|
function createForegroundCode(colour) {
|
|
121
|
+
if (colour === "default-foreground") {
|
|
122
|
+
return "\u001b[39m";
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (colour.startsWith("ansi-256:")) {
|
|
126
|
+
return `\u001b[38;5;${colour.slice("ansi-256:".length)}m`;
|
|
127
|
+
}
|
|
128
|
+
|
|
121
129
|
const { blue, green, red } = parseHexColour(colour);
|
|
122
130
|
|
|
123
131
|
return `\u001b[38;2;${red};${green};${blue}m`;
|
|
@@ -132,6 +140,14 @@ function createForegroundCode(colour) {
|
|
|
132
140
|
* ANSI background sequence.
|
|
133
141
|
*/
|
|
134
142
|
function createBackgroundCode(colour) {
|
|
143
|
+
if (colour === "default-background") {
|
|
144
|
+
return "\u001b[49m";
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (colour.startsWith("ansi-256:")) {
|
|
148
|
+
return `\u001b[48;5;${colour.slice("ansi-256:".length)}m`;
|
|
149
|
+
}
|
|
150
|
+
|
|
135
151
|
const { blue, green, red } = parseHexColour(colour);
|
|
136
152
|
|
|
137
153
|
return `\u001b[48;2;${red};${green};${blue}m`;
|