@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 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,6 @@
1
1
  {
2
2
  "name": "@lewishowles/cli-style",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Shared terminal output styles for Lewis Howles tools, diagnostics, and package CLIs.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -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(["--no-color", "--no-colour", "--no-unicode", "--plain"]);
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(["--no-color", "--no-colour", "--no-unicode", "--plain"]);
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.
@@ -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`;