@lewishowles/cli-style 0.8.1 → 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,29 @@
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
+
18
+ ## 0.9.0 - 2026-07-16
19
+
20
+ ### Added
21
+
22
+ - Added a `rowGroup` primitive (`rowGroup()` in JS, the `row-group` renderer for `cli-style render`, and the same generic `render()`/`cli_style_render`/`CliStyle.render` entry points in Python, Bash, and Swift) that aligns a group of related rows automatically, without the caller computing `labelWidth` by hand.
23
+
24
+ ### Fixed
25
+
26
+ - Fixed the Python, Bash, and Swift adapters silently dropping `row()`, `span()`, and `divider()` options beyond their two or three main fields. `row()` now forwards `labelWidth`, `labelColour`, `valueColour`, and `separator`; `span()` forwards `weight`; `divider()` forwards `dividerWidth`, `dividerColour`, and `labelColour`.
27
+
5
28
  ## 0.8.1 - 2026-07-15
6
29
 
7
30
  ### Fixed
package/README.md CHANGED
@@ -227,6 +227,7 @@ Renderer names are stable for `cli-style render`, `cli_style_render`, and Python
227
227
  | --------------------- | ------------------------------------- | ------------------------------------ | ---------------------------------- | -------------------------------------- | --------------------------------------------------------------- |
228
228
  | `status` | `status(resultType, detail, options)` | `cli_style_status type label detail` | `status(type, label, detail)` | `CliStyle.status(type, label, detail)` | Result line with symbol, label, and detail. |
229
229
  | `row` | `row(label, value, options)` | `cli_style_row label value [result]` | `row(label, value, result)` | `CliStyle.row(label, value, result)` | Aligned label/value row, optionally marked with a result state. |
230
+ | `row-group` | `rowGroup(options)` | Use `cli_style_render` | Use `render("row-group", ...)` | Use `CliStyle.render` | Auto-aligned group of labelled value rows. |
230
231
  | `span` | `span(value, tone, options)` | `cli_style_span value [tone]` | `span(value, tone)` | `CliStyle.span(value, tone)` | Inline colour or weight for a word, command, file, or value. |
231
232
  | `hint` | `hint(message, options)` | `cli_style_hint message` | `hint(message)` | `CliStyle.hint(message)` | Informational hint line. |
232
233
  | `divider` | `divider(options)` | `cli_style_divider label` | `divider(label)` | `CliStyle.divider(label)` | Section divider with an optional label. |
@@ -240,10 +241,12 @@ Renderer names are stable for `cli-style render`, `cli_style_render`, and Python
240
241
  | `table` | `table(options)` | Use `cli_style_render` | Use `render("table", ...)` | Use `CliStyle.render` | Tabular records with narrow-width fallback. |
241
242
  | `progress-bar` | `progressBar(options)` | Use `cli_style_render` | Use `render("progress-bar", ...)` | Use `CliStyle.render` | Single progress value with numeric text. |
242
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. |
243
245
  | `step` | `step(label, state, options)` | Use `cli_style_render` | Use `render("step", ...)` | Use `CliStyle.render` | One workflow step. |
244
246
  | `step-progress` | `stepProgress(options)` | Use `cli_style_render` | Use `render("step-progress", ...)` | Use `CliStyle.render` | Numbered workflow steps. |
245
247
  | `empty-state` | `emptyState(title, detail, options)` | Use `cli_style_render` | Use `render("empty-state", ...)` | Use `CliStyle.render` | Empty result message. |
246
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. |
247
250
 
248
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.
249
252
 
@@ -282,6 +285,27 @@ Use these shapes with `cli-style render`, `cli_style_render`, or Python `render(
282
285
  - `labelWidth`: optional minimum label width
283
286
  - `labelColour`, `valueColour`, `separator`: optional presentation overrides
284
287
 
288
+ ### `row-group`
289
+
290
+ ```json
291
+ {
292
+ "rows": [
293
+ {
294
+ "label": "Package",
295
+ "value": "@lewishowles/components"
296
+ },
297
+ {
298
+ "label": "Version",
299
+ "value": "minor: 2.7.4 -> 2.8.0"
300
+ }
301
+ ]
302
+ }
303
+ ```
304
+
305
+ - `rows`: labelled values to align and render
306
+ - `labelWidth`: optional minimum width for every label
307
+ - Per-row fields match `row`, including `label`, `value`, `result`, `labelColour`, `valueColour`, and `separator`
308
+
285
309
  ### `span`
286
310
 
287
311
  ```json
@@ -315,6 +339,7 @@ Pre-render a `span` when only part of the hint needs emphasis.
315
339
  | `table` | `columns`, `rows`, `width` |
316
340
  | `progress-bar` | `value`, `max`, `barWidth`, `tone` |
317
341
  | `bar-chart` | `rows`, `barWidth` |
342
+ | `sparkline` | `values`, `label`, `tone`, `width` |
318
343
  | `step` | `label`, `state` |
319
344
  | `step-progress` | `steps`, `current` |
320
345
  | `empty-state` | `title`, `detail` |
@@ -322,6 +347,35 @@ Pre-render a `span` when only part of the hint needs emphasis.
322
347
 
323
348
  For visual examples, run `cli-style gallery --section primitives`.
324
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
+
325
379
  ## Patterns
326
380
 
327
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.
@@ -336,6 +390,33 @@ Patterns are built-in composite renderers for common report shapes. They use the
336
390
  | `confirmation-result` | `confirmationResult(confirmation, options)` | Confirmation outcome with detail. | `title`, `state`, `action`, `item`, `detail` |
337
391
  | `next-step-block` | `nextStepBlock(nextStep, options)` | Next-step guidance. | `title`, `next`, `reason`, `commands`, `alternatives` |
338
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.
339
420
 
340
421
  For visual examples, run `cli-style gallery --section patterns`.
341
422
 
@@ -511,16 +592,18 @@ Most renderers accept the same output options:
511
592
  | --------- | ------------------------------------------------------------------------- |
512
593
  | `profile` | Output profile: `human`, `agent`, `diagnostic`, `ci`, `plain`, or `json`. |
513
594
  | `colour` | Whether ANSI colour should be applied. |
595
+ | `theme` | `auto`, `light`, or `dark` semantic colour palette. |
514
596
  | `unicode` | Whether Unicode symbols should be used. |
515
597
  | `width` | Available output width for renderers that adapt layout. |
516
598
 
517
- 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.
518
600
 
519
601
  ### CLI and Bash flags
520
602
 
521
603
  | Flag | Purpose |
522
604
  | ---------------------------- | -------------------------------------- |
523
605
  | `--profile <name>` | Render with a named profile. |
606
+ | `--light` / `--dark` | Override automatic terminal theme. |
524
607
  | `--plain` | Disable colour and Unicode decoration. |
525
608
  | `--no-colour` / `--no-color` | Disable ANSI colour. |
526
609
  | `--no-unicode` | Use ASCII symbols. |
@@ -584,6 +667,19 @@ Tone values used by public APIs include `info`, `success`, `warning`, `danger`,
584
667
 
585
668
  ## Gallery
586
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
+
587
683
  Use the gallery to review current renderer output:
588
684
 
589
685
  ```bash
@@ -595,6 +691,8 @@ cli-style gallery --fixture audit-finding
595
691
  cli-style gallery --profile agent
596
692
  cli-style gallery --width 64
597
693
  cli-style gallery --variants
694
+ cli-style gallery --light --section primitives
695
+ cli-style gallery --dark --section primitives
598
696
  ```
599
697
 
600
698
  Use `--interactive` to select a section or fixture with `fzf` when it is installed.
@@ -159,6 +159,11 @@ cli_style_row() {
159
159
  local label="${1:-}"
160
160
  local value="${2:-}"
161
161
  local result=""
162
+ local label_width=""
163
+ local label_colour_json="null"
164
+ local value_colour_json="null"
165
+ local separator_json="null"
166
+ local -a render_args=()
162
167
  local json
163
168
 
164
169
  if (($# >= 3)) && [[ "${3:-}" != --* ]]; then
@@ -170,9 +175,60 @@ cli_style_row() {
170
175
  set --
171
176
  fi
172
177
 
173
- json="{\"label\":$(cli_style_json_string "$label"),\"value\":$(cli_style_json_string "$value"),\"result\":$(cli_style_json_string "$result")}"
178
+ while (($# > 0)); do
179
+ case "$1" in
180
+ --label-width)
181
+ label_width="${2:-}"
182
+ shift 2
183
+ ;;
184
+ --label-width=*)
185
+ label_width="${1#*=}"
186
+ shift
187
+ ;;
188
+ --label-colour)
189
+ label_colour_json="$(cli_style_json_string "${2:-}")"
190
+ shift 2
191
+ ;;
192
+ --label-colour=*)
193
+ label_colour_json="$(cli_style_json_string "${1#*=}")"
194
+ shift
195
+ ;;
196
+ --value-colour)
197
+ value_colour_json="$(cli_style_json_string "${2:-}")"
198
+ shift 2
199
+ ;;
200
+ --value-colour=*)
201
+ value_colour_json="$(cli_style_json_string "${1#*=}")"
202
+ shift
203
+ ;;
204
+ --separator)
205
+ separator_json="$(cli_style_json_string "${2:-}")"
206
+ shift 2
207
+ ;;
208
+ --separator=*)
209
+ separator_json="$(cli_style_json_string "${1#*=}")"
210
+ shift
211
+ ;;
212
+ *)
213
+ render_args+=("$1")
214
+ shift
215
+ ;;
216
+ esac
217
+ done
218
+
219
+ json="{\"label\":$(cli_style_json_string "$label"),\"value\":$(cli_style_json_string "$value"),\"result\":$(cli_style_json_string "$result"),\"labelWidth\":$(cli_style_json_integer_or_null "$label_width"),\"separator\":$separator_json"
220
+
221
+ if [[ "$label_colour_json" != "null" ]]; then
222
+ json="${json},\"labelColour\":$label_colour_json"
223
+ fi
174
224
 
175
- cli_style_render_json row "$json" "$@"
225
+ if [[ "$value_colour_json" != "null" ]]; then
226
+ json="${json},\"valueColour\":$value_colour_json"
227
+ fi
228
+
229
+ json="${json}}"
230
+
231
+ cli_style_render_json row "$json" "${render_args[@]}"
176
232
  }
177
233
 
178
234
  # Render an inline span from Bash string values.
@@ -186,6 +242,8 @@ cli_style_row() {
186
242
  cli_style_span() {
187
243
  local value="${1:-}"
188
244
  local tone="info"
245
+ local weight_json="null"
246
+ local -a render_args=()
189
247
  local json
190
248
 
191
249
  if (($# >= 2)) && [[ "${2:-}" != --* ]]; then
@@ -197,9 +255,26 @@ cli_style_span() {
197
255
  set --
198
256
  fi
199
257
 
200
- json="{\"value\":$(cli_style_json_string "$value"),\"tone\":$(cli_style_json_string "$tone")}"
258
+ while (($# > 0)); do
259
+ case "$1" in
260
+ --weight)
261
+ weight_json="$(cli_style_json_string "${2:-}")"
262
+ shift 2
263
+ ;;
264
+ --weight=*)
265
+ weight_json="$(cli_style_json_string "${1#*=}")"
266
+ shift
267
+ ;;
268
+ *)
269
+ render_args+=("$1")
270
+ shift
271
+ ;;
272
+ esac
273
+ done
274
+
275
+ json="{\"value\":$(cli_style_json_string "$value"),\"tone\":$(cli_style_json_string "$tone"),\"weight\":$weight_json}"
201
276
 
202
- cli_style_render_json span "$json" "$@"
277
+ cli_style_render_json span "$json" "${render_args[@]}"
203
278
  }
204
279
 
205
280
  # Render a divider from a Bash string value.
@@ -210,6 +285,10 @@ cli_style_span() {
210
285
  # Render flags passed through to `cli-style render`.
211
286
  cli_style_divider() {
212
287
  local label="${1:-}"
288
+ local divider_width=""
289
+ local divider_colour_json="null"
290
+ local label_colour_json="null"
291
+ local -a render_args=()
213
292
  local json
214
293
 
215
294
  if (($# >= 1)); then
@@ -218,9 +297,52 @@ cli_style_divider() {
218
297
  set --
219
298
  fi
220
299
 
221
- json="{\"label\":$(cli_style_json_string "$label")}"
300
+ while (($# > 0)); do
301
+ case "$1" in
302
+ --divider-width)
303
+ divider_width="${2:-}"
304
+ shift 2
305
+ ;;
306
+ --divider-width=*)
307
+ divider_width="${1#*=}"
308
+ shift
309
+ ;;
310
+ --divider-colour)
311
+ divider_colour_json="$(cli_style_json_string "${2:-}")"
312
+ shift 2
313
+ ;;
314
+ --divider-colour=*)
315
+ divider_colour_json="$(cli_style_json_string "${1#*=}")"
316
+ shift
317
+ ;;
318
+ --label-colour)
319
+ label_colour_json="$(cli_style_json_string "${2:-}")"
320
+ shift 2
321
+ ;;
322
+ --label-colour=*)
323
+ label_colour_json="$(cli_style_json_string "${1#*=}")"
324
+ shift
325
+ ;;
326
+ *)
327
+ render_args+=("$1")
328
+ shift
329
+ ;;
330
+ esac
331
+ done
332
+
333
+ json="{\"label\":$(cli_style_json_string "$label"),\"dividerWidth\":$(cli_style_json_integer_or_null "$divider_width")"
334
+
335
+ if [[ "$divider_colour_json" != "null" ]]; then
336
+ json="${json},\"dividerColour\":$divider_colour_json"
337
+ fi
338
+
339
+ if [[ "$label_colour_json" != "null" ]]; then
340
+ json="${json},\"labelColour\":$label_colour_json"
341
+ fi
342
+
343
+ json="${json}}"
222
344
 
223
- cli_style_render_json divider "$json" "$@"
345
+ cli_style_render_json divider "$json" "${render_args[@]}"
224
346
  }
225
347
 
226
348
  # Render a hint from a Bash string value.
@@ -124,13 +124,39 @@ def status(
124
124
  # Row value.
125
125
  # @param {str} result
126
126
  # Optional result type for a symbol and tone.
127
+ # @param {int|None} label_width
128
+ # Optional minimum label width.
129
+ # @param {str|None} label_colour
130
+ # Optional label colour token.
131
+ # @param {str|None} value_colour
132
+ # Optional value colour token.
133
+ # @param {str|None} separator
134
+ # Optional text between the label and value.
127
135
  def row(
128
136
  label: str,
129
137
  value: str,
130
138
  result: str = "",
139
+ label_width: int | None = None,
140
+ label_colour: str | None = None,
141
+ value_colour: str | None = None,
142
+ separator: str | None = None,
131
143
  **kwargs: Any,
132
144
  ) -> str:
133
- return render("row", {"label": label, "value": value, "result": result}, **kwargs)
145
+ data = {
146
+ "label": label,
147
+ "value": value,
148
+ "result": result,
149
+ "labelWidth": label_width,
150
+ "separator": separator,
151
+ }
152
+
153
+ if label_colour is not None:
154
+ data["labelColour"] = label_colour
155
+
156
+ if value_colour is not None:
157
+ data["valueColour"] = value_colour
158
+
159
+ return render("row", data, **kwargs)
134
160
 
135
161
 
136
162
  # Render an inline span from Python values.
@@ -139,23 +165,46 @@ def row(
139
165
  # Span text.
140
166
  # @param {str} tone
141
167
  # Optional colour tone, defaulting to info.
168
+ # @param {str|None} weight
169
+ # Optional ANSI text weight.
142
170
  def span(
143
171
  value: str,
144
172
  tone: str = "info",
173
+ weight: str | None = None,
145
174
  **kwargs: Any,
146
175
  ) -> str:
147
- return render("span", {"value": value, "tone": tone}, **kwargs)
176
+ return render("span", {"value": value, "tone": tone, "weight": weight}, **kwargs)
148
177
 
149
178
 
150
179
  # Render a divider from a Python value.
151
180
  #
152
181
  # @param {str} label
153
182
  # Optional divider label.
183
+ # @param {int|None} divider_width
184
+ # Optional divider width.
185
+ # @param {str|None} divider_colour
186
+ # Optional divider colour token.
187
+ # @param {str|None} label_colour
188
+ # Optional label colour token.
154
189
  def divider(
155
190
  label: str = "",
191
+ divider_width: int | None = None,
192
+ divider_colour: str | None = None,
193
+ label_colour: str | None = None,
156
194
  **kwargs: Any,
157
195
  ) -> str:
158
- return render("divider", {"label": label}, **kwargs)
196
+ data = {
197
+ "label": label,
198
+ "dividerWidth": divider_width,
199
+ }
200
+
201
+ if divider_colour is not None:
202
+ data["dividerColour"] = divider_colour
203
+
204
+ if label_colour is not None:
205
+ data["labelColour"] = label_colour
206
+
207
+ return render("divider", data, **kwargs)
159
208
 
160
209
 
161
210
  # Render a hint from a Python value.
@@ -175,6 +175,10 @@ enum CliStyle {
175
175
  - parameter label: Row label.
176
176
  - parameter value: Row value.
177
177
  - parameter result: Optional result type for a symbol and tone.
178
+ - parameter labelWidth: Optional minimum label width.
179
+ - parameter labelColour: Optional label colour token.
180
+ - parameter valueColour: Optional value colour token.
181
+ - parameter separator: Optional text between the label and value.
178
182
  - parameter options: Render options.
179
183
  - returns: Rendered row line.
180
184
  - throws: `CliStyleError` on failure.
@@ -183,13 +187,35 @@ enum CliStyle {
183
187
  label: String,
184
188
  value: String,
185
189
  result: String = "",
190
+ labelWidth: Int? = nil,
191
+ labelColour: String? = nil,
192
+ valueColour: String? = nil,
193
+ separator: String? = nil,
186
194
  options: CliStyleOptions = .init()
187
195
  ) throws -> String {
188
- try render("row", data: [
196
+ var data: [String: Any] = [
189
197
  "label": label,
190
198
  "value": value,
191
199
  "result": result,
192
- ], options: options)
200
+ ]
201
+
202
+ if let labelWidth = labelWidth {
203
+ data["labelWidth"] = labelWidth
204
+ }
205
+
206
+ if let labelColour = labelColour {
207
+ data["labelColour"] = labelColour
208
+ }
209
+
210
+ if let valueColour = valueColour {
211
+ data["valueColour"] = valueColour
212
+ }
213
+
214
+ if let separator = separator {
215
+ data["separator"] = separator
216
+ }
217
+
218
+ return try render("row", data: data, options: options)
193
219
  }
194
220
 
195
221
  /**
@@ -197,6 +223,7 @@ enum CliStyle {
197
223
 
198
224
  - parameter value: Span text.
199
225
  - parameter tone: Optional colour tone, defaulting to info.
226
+ - parameter weight: Optional ANSI text weight.
200
227
  - parameter options: Render options.
201
228
  - returns: Rendered span string.
202
229
  - throws: `CliStyleError` on failure.
@@ -204,29 +231,56 @@ enum CliStyle {
204
231
  static func span(
205
232
  value: String,
206
233
  tone: String = "info",
234
+ weight: String? = nil,
207
235
  options: CliStyleOptions = .init()
208
236
  ) throws -> String {
209
- try render("span", data: [
237
+ var data: [String: Any] = [
210
238
  "value": value,
211
239
  "tone": tone,
212
- ], options: options)
240
+ ]
241
+
242
+ if let weight = weight {
243
+ data["weight"] = weight
244
+ }
245
+
246
+ return try render("span", data: data, options: options)
213
247
  }
214
248
 
215
249
  /**
216
250
  Render a divider.
217
251
 
218
252
  - parameter label: Optional divider label.
253
+ - parameter dividerWidth: Optional divider width.
254
+ - parameter dividerColour: Optional divider colour token.
255
+ - parameter labelColour: Optional label colour token.
219
256
  - parameter options: Render options.
220
257
  - returns: Rendered divider line.
221
258
  - throws: `CliStyleError` on failure.
222
259
  */
223
260
  static func divider(
224
261
  label: String = "",
262
+ dividerWidth: Int? = nil,
263
+ dividerColour: String? = nil,
264
+ labelColour: String? = nil,
225
265
  options: CliStyleOptions = .init()
226
266
  ) throws -> String {
227
- try render("divider", data: [
267
+ var data: [String: Any] = [
228
268
  "label": label,
229
- ], options: options)
269
+ ]
270
+
271
+ if let dividerWidth = dividerWidth {
272
+ data["dividerWidth"] = dividerWidth
273
+ }
274
+
275
+ if let dividerColour = dividerColour {
276
+ data["dividerColour"] = dividerColour
277
+ }
278
+
279
+ if let labelColour = labelColour {
280
+ data["labelColour"] = labelColour
281
+ }
282
+
283
+ return try render("divider", data: data, options: options)
230
284
  }
231
285
 
232
286
  /**
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.8.1",
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": {