@lewishowles/cli-style 0.5.0 → 0.7.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 +24 -1
- package/README.md +402 -100
- package/adapters/bash/cli-style.sh +235 -2
- package/adapters/python/cli_style.py +215 -0
- package/package.json +1 -1
- package/src/cli/render-command.js +6 -0
- package/src/gallery/render-gallery.js +7 -1
- package/src/index.js +1 -0
- package/src/primitives/row.js +94 -5
- package/src/primitives/span.js +33 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 0.7.0 - 2026-07-05
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Added Python adapter convenience functions for scalar pattern usage: `command_result`, `audit_finding`, `task_summary`, `confirmation_result`, and `next_step_block`.
|
|
8
|
+
- Added Python adapter convenience functions for common primitives: `status`, `row`, `span`, `hint`, and `divider`.
|
|
9
|
+
- Added Bash adapter convenience functions for scalar pattern usage: `cli_style_command_result`, `cli_style_audit_finding`, `cli_style_task_summary`, `cli_style_confirmation_result`, and `cli_style_next_step_block`.
|
|
10
|
+
- Added Bash adapter helpers for JSON string arrays and integer/null fields, so pattern wrappers can safely pass single-item list fields and exit codes.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Extended the README renderer table with a Python helper column covering all 20 renderers, including convenience functions and `render()` fallbacks for aggregate patterns.
|
|
15
|
+
|
|
16
|
+
## 0.6.0 - 2026-07-03
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Added result-state support to `row()` and `cli_style_row`, so label/value rows can render failed, warning, success, or other status cues while keeping column alignment.
|
|
21
|
+
- Added the `span()` inline emphasis primitive and `cli_style_span` Bash helper for highlighting commands, files, or values inside existing line renderers such as `hint()`.
|
|
22
|
+
- Added `span` support to `cli-style render` and the public JavaScript export.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Reworked the README around integration paths, available renderers, primitive data shapes, patterns, options, profiles, result types, and gallery commands.
|
|
4
27
|
|
|
5
28
|
## 0.5.0 - 2026-07-02
|
|
6
29
|
|
package/README.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# CLI style
|
|
2
2
|
|
|
3
|
-
Shared terminal output styles for tools, diagnostics, and package CLIs.
|
|
3
|
+
Shared terminal output styles for local tools, diagnostics, agent-facing reports, and package CLIs.
|
|
4
|
+
|
|
5
|
+
Use it directly from JavaScript, or call the same renderers from Bash and Python through the `cli-style` binary.
|
|
4
6
|
|
|
5
7
|
## Requirements
|
|
6
8
|
|
|
7
9
|
- Bun and Node.js 20 or newer for JavaScript projects and local binary builds
|
|
8
|
-
- The standalone binary for Bash or Python projects that should not install Bun
|
|
10
|
+
- The standalone `cli-style` binary for Bash or Python projects that should not install Bun
|
|
9
11
|
|
|
10
12
|
## Install
|
|
11
13
|
|
|
@@ -21,7 +23,29 @@ Bash and Python projects call the `cli-style` binary through thin adapters. If t
|
|
|
21
23
|
export PATH="/path/to/cli-style/bin:$PATH"
|
|
22
24
|
```
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
Build a standalone binary when a repo should not need Bun at runtime:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
bun run build:binary
|
|
30
|
+
bun run smoke:binary
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Create a binary install tarball:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
bun run package:binary
|
|
37
|
+
tar -tzf dist/release/cli-style-*.tar.gz
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The package contains `bin/cli-style` and `adapters/`.
|
|
41
|
+
|
|
42
|
+
## Choose an integration
|
|
43
|
+
|
|
44
|
+
All renderers return text. JavaScript imports functions directly. CLI, Bash, and Python integrations pass JSON-compatible data to a named renderer.
|
|
45
|
+
|
|
46
|
+
### JavaScript
|
|
47
|
+
|
|
48
|
+
Create the `ui` instance at the CLI entrypoint, then pass `ui.options` to renderers. That keeps flag, environment, stream, colour, Unicode, and width detection in one place.
|
|
25
49
|
|
|
26
50
|
```js
|
|
27
51
|
import { createCliStyle, status } from "@lewishowles/cli-style";
|
|
@@ -42,170 +66,428 @@ ui.print(output);
|
|
|
42
66
|
|
|
43
67
|
Renderer methods return strings. `ui.print()`, `ui.write()`, and CLI commands handle stdout and stderr.
|
|
44
68
|
|
|
45
|
-
|
|
69
|
+
### CLI render
|
|
46
70
|
|
|
47
|
-
|
|
71
|
+
Use `cli-style render <renderer>` when a script needs rendered text from JSON input:
|
|
48
72
|
|
|
49
|
-
|
|
73
|
+
```bash
|
|
74
|
+
cli-style render status --profile diagnostic <<'JSON'
|
|
75
|
+
{
|
|
76
|
+
"type": "success",
|
|
77
|
+
"label": "Build passed",
|
|
78
|
+
"detail": "184 tests"
|
|
79
|
+
}
|
|
80
|
+
JSON
|
|
81
|
+
```
|
|
50
82
|
|
|
51
|
-
|
|
52
|
-
import { createReporter } from "@lewishowles/cli-style";
|
|
83
|
+
Use renderer names from the tables below, for example `status`, `row`, `diagnostic-report`, or `task-summary`.
|
|
53
84
|
|
|
54
|
-
|
|
55
|
-
colour: false,
|
|
56
|
-
});
|
|
85
|
+
### Bash
|
|
57
86
|
|
|
58
|
-
|
|
59
|
-
reporter.group(
|
|
60
|
-
"Agent scripts",
|
|
61
|
-
[
|
|
62
|
-
{
|
|
63
|
-
label: "project-diagnostics.py",
|
|
64
|
-
result: "unchanged",
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
label: "repo-context.py",
|
|
68
|
-
result: "unchanged",
|
|
69
|
-
},
|
|
70
|
-
],
|
|
71
|
-
{
|
|
72
|
-
summary: "2 already linked",
|
|
73
|
-
},
|
|
74
|
-
);
|
|
75
|
-
reporter.status("success", "Done.");
|
|
87
|
+
Source the Bash adapter, then use convenience helpers for common primitive and per-script pattern renderers:
|
|
76
88
|
|
|
77
|
-
|
|
78
|
-
|
|
89
|
+
```bash
|
|
90
|
+
source "$(cli-style adapter-path bash)"
|
|
79
91
|
|
|
80
|
-
|
|
92
|
+
label='Build "passed"'
|
|
93
|
+
detail="/path/to/project"
|
|
81
94
|
|
|
82
|
-
|
|
95
|
+
cli_style_status success "$label" "$detail" --profile diagnostic
|
|
96
|
+
cli_style_row "Workspace" "$detail" --plain
|
|
97
|
+
cli_style_row "Bundle" "is 22.3 KB, above the 12.0 KB budget" failed --plain
|
|
98
|
+
command="$(cli_style_span "npm run docs:readme" info --plain)"
|
|
99
|
+
cli_style_hint "Run $command before release" --plain
|
|
100
|
+
cli_style_divider "Project setup" --plain
|
|
83
101
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
102
|
+
cli_style_command_result success "Build passed" "bun run test:unit" 0 "1.2s" "184 tests" --plain
|
|
103
|
+
cli_style_task_summary partial "Adopt cli-style" "Bash wrappers added" "Updated adapter" "Update scripts" --plain
|
|
104
|
+
cli_style_confirmation_result confirmed "Publish release" "v0.6.0" "Tag push starts npm publish" --plain
|
|
105
|
+
cli_style_next_step_block "Update helpers scripts" "Wrappers are now available" "scripts/setup.sh --check" "" --plain
|
|
88
106
|
```
|
|
89
107
|
|
|
90
|
-
|
|
108
|
+
The convenience functions build JSON internally, so callers do not need to escape quotes, backslashes, or paths by hand.
|
|
91
109
|
|
|
92
|
-
|
|
110
|
+
Set `CLI_STYLE_BIN` when `cli-style` is not on `PATH`:
|
|
93
111
|
|
|
94
112
|
```bash
|
|
95
|
-
cli-style
|
|
96
|
-
{
|
|
97
|
-
"type": "success",
|
|
98
|
-
"label": "Build passed",
|
|
99
|
-
"detail": "184 tests"
|
|
100
|
-
}
|
|
101
|
-
JSON
|
|
113
|
+
CLI_STYLE_BIN="/path/to/cli-style" cli_style_status success "Build passed" "" --plain
|
|
102
114
|
```
|
|
103
115
|
|
|
116
|
+
Use `cli_style_render` for literal or prebuilt JSON, especially for aggregate patterns or multi-item pattern fields:
|
|
117
|
+
|
|
104
118
|
```bash
|
|
105
|
-
|
|
119
|
+
cli_style_render diagnostic-report --profile diagnostic <<'JSON'
|
|
106
120
|
{
|
|
107
|
-
"title": "
|
|
108
|
-
"
|
|
109
|
-
|
|
121
|
+
"title": "Release checks",
|
|
122
|
+
"checks": [
|
|
123
|
+
{
|
|
124
|
+
"name": "README",
|
|
125
|
+
"result": "success"
|
|
126
|
+
}
|
|
127
|
+
]
|
|
110
128
|
}
|
|
111
129
|
JSON
|
|
112
130
|
```
|
|
113
131
|
|
|
114
|
-
|
|
132
|
+
### Python
|
|
115
133
|
|
|
116
|
-
|
|
134
|
+
Add the adapter directory to `PYTHONPATH`, then import the generic `render()` helper or convenience functions:
|
|
117
135
|
|
|
118
136
|
```bash
|
|
119
|
-
|
|
120
|
-
bun run smoke:binary
|
|
137
|
+
export PYTHONPATH="$(cli-style adapter-path python):$PYTHONPATH"
|
|
121
138
|
```
|
|
122
139
|
|
|
123
|
-
|
|
140
|
+
```python
|
|
141
|
+
from cli_style import status, row, span, hint, divider
|
|
124
142
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
143
|
+
kwargs = {"binary": "./bin/cli-style.js", "plain": True}
|
|
144
|
+
|
|
145
|
+
print(status("success", "Build passed", "184 tests", **kwargs))
|
|
146
|
+
print(row("Workspace", "/path/to/project", **kwargs))
|
|
147
|
+
print(row("Bundle", "over budget", "failed", **kwargs))
|
|
148
|
+
command = span("npm run docs:readme", "info", **kwargs)
|
|
149
|
+
print(hint(f"Run {command} before release", **kwargs))
|
|
150
|
+
print(divider("Project setup", **kwargs))
|
|
128
151
|
```
|
|
129
152
|
|
|
130
|
-
|
|
153
|
+
Convenience functions build the renderer payload internally, so callers pass plain Python strings without hand-building JSON.
|
|
131
154
|
|
|
132
|
-
|
|
155
|
+
Pass `binary=` when `cli-style` is not on `PATH`. The generic `render()` helper remains for aggregate patterns or multi-item fields:
|
|
133
156
|
|
|
134
|
-
```
|
|
135
|
-
|
|
157
|
+
```python
|
|
158
|
+
from cli_style import render
|
|
136
159
|
|
|
137
|
-
|
|
138
|
-
|
|
160
|
+
output = render(
|
|
161
|
+
"diagnostic-report",
|
|
162
|
+
{
|
|
163
|
+
"title": "Release checks",
|
|
164
|
+
"checks": [{"name": "README", "result": "success"}],
|
|
165
|
+
},
|
|
166
|
+
profile="diagnostic",
|
|
167
|
+
)
|
|
139
168
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
169
|
+
print(output)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Available renderers
|
|
173
|
+
|
|
174
|
+
Renderer names are stable for `cli-style render`, `cli_style_render`, and Python `render()`. JavaScript uses camel-case function names.
|
|
175
|
+
|
|
176
|
+
| Renderer | JavaScript | Bash helper | Python helper | Purpose |
|
|
177
|
+
| --------------------- | ------------------------------------- | ------------------------------------ | ---------------------------------- | --------------------------------------------------------------- |
|
|
178
|
+
| `status` | `status(resultType, detail, options)` | `cli_style_status type label detail` | `status(type, label, detail)` | Result line with symbol, label, and detail. |
|
|
179
|
+
| `row` | `row(label, value, options)` | `cli_style_row label value [result]` | `row(label, value, result)` | Aligned label/value row, optionally marked with a result state. |
|
|
180
|
+
| `span` | `span(value, tone, options)` | `cli_style_span value [tone]` | `span(value, tone)` | Inline colour or weight for a word, command, file, or value. |
|
|
181
|
+
| `hint` | `hint(message, options)` | `cli_style_hint message` | `hint(message)` | Informational hint line. |
|
|
182
|
+
| `divider` | `divider(options)` | `cli_style_divider label` | `divider(label)` | Section divider with an optional label. |
|
|
183
|
+
| `command-result` | `commandResult(options)` | `cli_style_command_result ...` | `command_result(...)` | Command execution outcome with exit code and duration. |
|
|
184
|
+
| `audit-finding` | `auditFinding(options)` | `cli_style_audit_finding ...` | `audit_finding(...)` | Structured audit finding with evidence and recommendation. |
|
|
185
|
+
| `task-summary` | `taskSummary(options)` | `cli_style_task_summary ...` | `task_summary(...)` | Task progress with completed and remaining items. |
|
|
186
|
+
| `confirmation-result` | `confirmationResult(options)` | `cli_style_confirmation_result ...` | `confirmation_result(...)` | Confirmation outcome with action and item. |
|
|
187
|
+
| `next-step-block` | `nextStepBlock(options)` | `cli_style_next_step_block ...` | `next_step_block(...)` | Next-step guidance with command and alternative. |
|
|
188
|
+
| `chip` | `chip(label, tone, options)` | Use `cli_style_render` | Use `render("chip", ...)` | Compact labelled state. |
|
|
189
|
+
| `panel` | `panel(options)` | Use `cli_style_render` | Use `render("panel", ...)` | Framed content block for grouped output. |
|
|
190
|
+
| `table` | `table(options)` | Use `cli_style_render` | Use `render("table", ...)` | Tabular records with narrow-width fallback. |
|
|
191
|
+
| `progress-bar` | `progressBar(options)` | Use `cli_style_render` | Use `render("progress-bar", ...)` | Single progress value with numeric text. |
|
|
192
|
+
| `bar-chart` | `barChart(options)` | Use `cli_style_render` | Use `render("bar-chart", ...)` | Multi-row bar chart. |
|
|
193
|
+
| `step` | `step(label, state, options)` | Use `cli_style_render` | Use `render("step", ...)` | One workflow step. |
|
|
194
|
+
| `step-progress` | `stepProgress(options)` | Use `cli_style_render` | Use `render("step-progress", ...)` | Numbered workflow steps. |
|
|
195
|
+
| `empty-state` | `emptyState(title, detail, options)` | Use `cli_style_render` | Use `render("empty-state", ...)` | Empty result message. |
|
|
196
|
+
| `error-block` | `errorBlock(title, lines, options)` | Use `cli_style_render` | Use `render("error-block", ...)` | Structured error block. |
|
|
197
|
+
|
|
198
|
+
Use `render("<renderer>", data, ...)` for aggregate patterns (`diagnostic-report`, `agent-transcript`, `compact-data-table`) or any renderer with multi-item fields.
|
|
199
|
+
|
|
200
|
+
## Primitive data shapes
|
|
201
|
+
|
|
202
|
+
Use these shapes with `cli-style render`, `cli_style_render`, or Python `render()`. JavaScript callers pass the listed function arguments directly.
|
|
203
|
+
|
|
204
|
+
### `status`
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"type": "success",
|
|
209
|
+
"label": "Build passed",
|
|
210
|
+
"detail": "184 tests"
|
|
211
|
+
}
|
|
144
212
|
```
|
|
145
213
|
|
|
146
|
-
|
|
214
|
+
- `type`: one of the result types listed below
|
|
215
|
+
- `label`: optional label override
|
|
216
|
+
- `detail`: optional text after the label
|
|
147
217
|
|
|
148
|
-
|
|
218
|
+
### `row`
|
|
149
219
|
|
|
150
|
-
```
|
|
151
|
-
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"label": "Bundle",
|
|
223
|
+
"value": "is 22.3 KB, above the 12.0 KB budget",
|
|
224
|
+
"result": "failed",
|
|
225
|
+
"labelWidth": 8
|
|
226
|
+
}
|
|
152
227
|
```
|
|
153
228
|
|
|
154
|
-
|
|
229
|
+
- `label`: left-hand label
|
|
230
|
+
- `value`: right-hand value
|
|
231
|
+
- `result`: optional result type for a symbol and tone
|
|
232
|
+
- `labelWidth`: optional minimum label width
|
|
233
|
+
- `labelColour`, `valueColour`, `separator`: optional presentation overrides
|
|
155
234
|
|
|
156
|
-
|
|
157
|
-
|
|
235
|
+
### `span`
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
{
|
|
239
|
+
"value": "npm run docs:readme",
|
|
240
|
+
"tone": "info"
|
|
241
|
+
}
|
|
158
242
|
```
|
|
159
243
|
|
|
160
|
-
|
|
244
|
+
- `value`: inline text to emphasise
|
|
245
|
+
- `tone`: optional tone, defaulting to `info`
|
|
246
|
+
- `weight`: optional ANSI style, defaulting to `bold`
|
|
161
247
|
|
|
162
|
-
|
|
163
|
-
|
|
248
|
+
### `hint`
|
|
249
|
+
|
|
250
|
+
```json
|
|
164
251
|
{
|
|
165
|
-
|
|
166
|
-
"label": "Build passed"
|
|
252
|
+
"message": "Run npm run docs:readme before release"
|
|
167
253
|
}
|
|
168
|
-
JSON
|
|
169
254
|
```
|
|
170
255
|
|
|
171
|
-
|
|
256
|
+
Pre-render a `span` when only part of the hint needs emphasis.
|
|
257
|
+
|
|
258
|
+
### Structured primitives
|
|
259
|
+
|
|
260
|
+
| Renderer | Main fields |
|
|
261
|
+
| --------------- | -------------------------------------- |
|
|
262
|
+
| `divider` | `label`, `dividerWidth`, `character` |
|
|
263
|
+
| `chip` | `label`, `tone` |
|
|
264
|
+
| `panel` | `title`, `lines`, `tone`, `panelWidth` |
|
|
265
|
+
| `table` | `columns`, `rows`, `width` |
|
|
266
|
+
| `progress-bar` | `value`, `max`, `barWidth`, `tone` |
|
|
267
|
+
| `bar-chart` | `rows`, `barWidth` |
|
|
268
|
+
| `step` | `label`, `state` |
|
|
269
|
+
| `step-progress` | `steps`, `current` |
|
|
270
|
+
| `empty-state` | `title`, `detail` |
|
|
271
|
+
| `error-block` | `title`, `lines` |
|
|
272
|
+
|
|
273
|
+
For visual examples, run `cli-style gallery --section primitives`.
|
|
274
|
+
|
|
275
|
+
## Patterns
|
|
276
|
+
|
|
277
|
+
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.
|
|
278
|
+
|
|
279
|
+
| Renderer | JavaScript | Purpose | Main fields |
|
|
280
|
+
| --------------------- | ------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
281
|
+
| `diagnostic-report` | `diagnosticReport(report, options)` | Aggregate check report. | `title`, `checks`, `findings`, `skippedChecks`, `nextActions` |
|
|
282
|
+
| `command-result` | `commandResult(result, options)` | Single command outcome with metadata. | `title`, `result`, `summary`, `command`, `exitCode`, `duration`, `details` |
|
|
283
|
+
| `audit-finding` | `auditFinding(finding, options)` | Single audit finding. | `title`, `result`, `finding`, `location`, `evidence`, `recommendation`, `references` |
|
|
284
|
+
| `task-summary` | `taskSummary(summary, options)` | Completed and remaining task summary. | `title`, `task`, `result`, `summary`, `completed`, `remaining` |
|
|
285
|
+
| `agent-transcript` | `agentTranscript(transcript, options)` | User, agent, and tool transcript. | `title`, `entries` |
|
|
286
|
+
| `confirmation-result` | `confirmationResult(confirmation, options)` | Confirmation outcome with detail. | `title`, `state`, `action`, `item`, `detail` |
|
|
287
|
+
| `next-step-block` | `nextStepBlock(nextStep, options)` | Next-step guidance. | `title`, `next`, `reason`, `commands`, `alternatives` |
|
|
288
|
+
| `compact-data-table` | `compactDataTable(data, options)` | Titled compact data table. | `title`, `summary`, `columns`, `rows` |
|
|
172
289
|
|
|
173
|
-
|
|
290
|
+
For visual examples, run `cli-style gallery --section patterns`.
|
|
291
|
+
|
|
292
|
+
The Bash adapter also exposes scalar convenience wrappers for per-script usage:
|
|
293
|
+
|
|
294
|
+
| Bash helper | Renderer | Arguments before render flags |
|
|
295
|
+
| ------------------------------- | --------------------- | -------------------------------------------------------------------------- |
|
|
296
|
+
| `cli_style_command_result` | `command-result` | `result`, `summary`, `command`, `exit_code`, `duration`, `detail` |
|
|
297
|
+
| `cli_style_audit_finding` | `audit-finding` | `result`, `finding`, `location`, `recommendation`, `evidence`, `reference` |
|
|
298
|
+
| `cli_style_task_summary` | `task-summary` | `result`, `task`, `summary`, `completed`, `remaining` |
|
|
299
|
+
| `cli_style_confirmation_result` | `confirmation-result` | `state`, `action`, `item`, `detail` |
|
|
300
|
+
| `cli_style_next_step_block` | `next-step-block` | `next`, `reason`, `command`, `alternative` |
|
|
301
|
+
|
|
302
|
+
Pass an empty string for optional positional fields you want to skip. Use `cli_style_render` or `cli_style_render_json` for aggregate reports, tables, transcripts, and multi-item arrays.
|
|
303
|
+
|
|
304
|
+
### Pattern example
|
|
305
|
+
|
|
306
|
+
JavaScript:
|
|
307
|
+
|
|
308
|
+
```js
|
|
309
|
+
import { createCliStyle, diagnosticReport } from "@lewishowles/cli-style";
|
|
310
|
+
|
|
311
|
+
const ui = createCliStyle({
|
|
312
|
+
argv: process.argv.slice(2),
|
|
313
|
+
env: process.env,
|
|
314
|
+
stdout: process.stdout,
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const output = diagnosticReport(
|
|
318
|
+
{
|
|
319
|
+
title: "Release checks",
|
|
320
|
+
checks: [
|
|
321
|
+
{
|
|
322
|
+
name: "README",
|
|
323
|
+
result: "success",
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
detail: "object-BmsQavd_.js over budget",
|
|
327
|
+
name: "Package size",
|
|
328
|
+
result: "failed",
|
|
329
|
+
},
|
|
330
|
+
],
|
|
331
|
+
findings: [
|
|
332
|
+
{
|
|
333
|
+
message: "dist/object-BmsQavd_.js is 22.3 KB, above the 12.0 KB budget",
|
|
334
|
+
result: "failed",
|
|
335
|
+
},
|
|
336
|
+
],
|
|
337
|
+
nextActions: ["Reduce package size, or raise the budget with a release-note-worthy reason."],
|
|
338
|
+
},
|
|
339
|
+
ui.options,
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
ui.print(output);
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
CLI:
|
|
174
346
|
|
|
175
347
|
```bash
|
|
176
|
-
|
|
348
|
+
cli-style render diagnostic-report --profile diagnostic <<'JSON'
|
|
349
|
+
{
|
|
350
|
+
"title": "Release checks",
|
|
351
|
+
"checks": [
|
|
352
|
+
{
|
|
353
|
+
"name": "README",
|
|
354
|
+
"result": "success"
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
"name": "Package size",
|
|
358
|
+
"result": "failed",
|
|
359
|
+
"detail": "object-BmsQavd_.js over budget"
|
|
360
|
+
}
|
|
361
|
+
],
|
|
362
|
+
"findings": [
|
|
363
|
+
{
|
|
364
|
+
"result": "failed",
|
|
365
|
+
"message": "dist/object-BmsQavd_.js is 22.3 KB, above the 12.0 KB budget"
|
|
366
|
+
}
|
|
367
|
+
],
|
|
368
|
+
"nextActions": [
|
|
369
|
+
"Reduce package size, or raise the budget with a release-note-worthy reason."
|
|
370
|
+
]
|
|
371
|
+
}
|
|
372
|
+
JSON
|
|
177
373
|
```
|
|
178
374
|
|
|
375
|
+
Python:
|
|
376
|
+
|
|
179
377
|
```python
|
|
180
378
|
from cli_style import render
|
|
181
379
|
|
|
182
380
|
output = render(
|
|
183
|
-
"
|
|
381
|
+
"diagnostic-report",
|
|
184
382
|
{
|
|
185
|
-
"
|
|
186
|
-
"
|
|
187
|
-
|
|
383
|
+
"title": "Release checks",
|
|
384
|
+
"checks": [
|
|
385
|
+
{
|
|
386
|
+
"name": "README",
|
|
387
|
+
"result": "success",
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"name": "Package size",
|
|
391
|
+
"result": "failed",
|
|
392
|
+
"detail": "object-BmsQavd_.js over budget",
|
|
393
|
+
},
|
|
394
|
+
],
|
|
395
|
+
"findings": [
|
|
396
|
+
{
|
|
397
|
+
"result": "failed",
|
|
398
|
+
"message": "dist/object-BmsQavd_.js is 22.3 KB, above the 12.0 KB budget",
|
|
399
|
+
},
|
|
400
|
+
],
|
|
401
|
+
"nextActions": [
|
|
402
|
+
"Reduce package size, or raise the budget with a release-note-worthy reason.",
|
|
403
|
+
],
|
|
188
404
|
},
|
|
189
405
|
profile="diagnostic",
|
|
190
406
|
)
|
|
191
|
-
|
|
192
|
-
print(output)
|
|
193
407
|
```
|
|
194
408
|
|
|
195
|
-
|
|
409
|
+
## Reporter
|
|
196
410
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
411
|
+
Use a reporter when a JavaScript script needs grouped output built over time.
|
|
412
|
+
|
|
413
|
+
```js
|
|
414
|
+
import { createReporter } from "@lewishowles/cli-style";
|
|
415
|
+
|
|
416
|
+
const reporter = createReporter({
|
|
417
|
+
colour: false,
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
reporter.divider("Project setup", "Claude + Codex");
|
|
421
|
+
reporter.group(
|
|
422
|
+
"Agent scripts",
|
|
423
|
+
[
|
|
424
|
+
{
|
|
425
|
+
label: "project-diagnostics.py",
|
|
426
|
+
result: "unchanged",
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
label: "repo-context.py",
|
|
430
|
+
result: "unchanged",
|
|
431
|
+
},
|
|
432
|
+
],
|
|
200
433
|
{
|
|
201
|
-
|
|
202
|
-
"label": "Build passed",
|
|
434
|
+
summary: "2 already linked",
|
|
203
435
|
},
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
436
|
+
);
|
|
437
|
+
reporter.status("success", "Done.");
|
|
438
|
+
|
|
439
|
+
console.log(reporter.render());
|
|
207
440
|
```
|
|
208
441
|
|
|
442
|
+
Use `reporter.divider()` for major phases. Use `reporter.section()` for a normal `info` status row inside a phase. Panels are for framed content blocks, not headings.
|
|
443
|
+
|
|
444
|
+
Groups can include verbose detail rows when a caller opts in:
|
|
445
|
+
|
|
446
|
+
```js
|
|
447
|
+
const reporter = createReporter({
|
|
448
|
+
verbose: process.env.AGENTS_VERBOSE === "1",
|
|
449
|
+
});
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
## Options and flags
|
|
453
|
+
|
|
454
|
+
### JavaScript options
|
|
455
|
+
|
|
456
|
+
Most renderers accept the same output options:
|
|
457
|
+
|
|
458
|
+
| Option | Purpose |
|
|
459
|
+
| --------- | ------------------------------------------------------------------------- |
|
|
460
|
+
| `profile` | Output profile: `human`, `agent`, `diagnostic`, `ci`, `plain`, or `json`. |
|
|
461
|
+
| `colour` | Whether ANSI colour should be applied. |
|
|
462
|
+
| `unicode` | Whether Unicode symbols should be used. |
|
|
463
|
+
| `width` | Available output width for renderers that adapt layout. |
|
|
464
|
+
|
|
465
|
+
Use `createCliStyle()` to resolve these options from `argv`, `env`, `stdout`, CI, TTY, `NO_COLOR`, and terminal capability.
|
|
466
|
+
|
|
467
|
+
### CLI and Bash flags
|
|
468
|
+
|
|
469
|
+
| Flag | Purpose |
|
|
470
|
+
| ---------------------------- | -------------------------------------- |
|
|
471
|
+
| `--profile <name>` | Render with a named profile. |
|
|
472
|
+
| `--plain` | Disable colour and Unicode decoration. |
|
|
473
|
+
| `--no-colour` / `--no-color` | Disable ANSI colour. |
|
|
474
|
+
| `--no-unicode` | Use ASCII symbols. |
|
|
475
|
+
| `--width <columns>` | Override detected output width. |
|
|
476
|
+
|
|
477
|
+
`cli-style render` rejects `--json`. JSON profile behaviour is for library calls and machine-readable commands.
|
|
478
|
+
|
|
479
|
+
### Python options
|
|
480
|
+
|
|
481
|
+
| Argument | Purpose |
|
|
482
|
+
| ------------ | ------------------------------------------------ |
|
|
483
|
+
| `profile` | Render with a named profile. |
|
|
484
|
+
| `width` | Override detected output width. |
|
|
485
|
+
| `plain` | Disable colour and Unicode decoration. |
|
|
486
|
+
| `no_colour` | Disable ANSI colour. |
|
|
487
|
+
| `no_unicode` | Use ASCII symbols. |
|
|
488
|
+
| `binary` | Path or command name for the `cli-style` binary. |
|
|
489
|
+
| `extra_args` | Extra CLI arguments to pass through. |
|
|
490
|
+
|
|
209
491
|
## Profiles
|
|
210
492
|
|
|
211
493
|
| Profile | Behaviour |
|
|
@@ -217,11 +499,31 @@ output = render(
|
|
|
217
499
|
| `plain` | No ANSI, no Unicode dependency, simple text layout. |
|
|
218
500
|
| `json` | Machine-readable only; library calls return structured data unchanged. |
|
|
219
501
|
|
|
502
|
+
## Result types and tones
|
|
503
|
+
|
|
504
|
+
Result types drive symbols, labels, priority, and semantic colour:
|
|
505
|
+
|
|
506
|
+
| Result | Label | Unicode | ASCII | Tone |
|
|
507
|
+
| ----------- | --------- | ------- | ----- | --------- |
|
|
508
|
+
| `success` | Success | `✓` | `OK` | `success` |
|
|
509
|
+
| `info` | Info | `→` | `>` | `info` |
|
|
510
|
+
| `warning` | Warning | `⚠` | `!` | `warning` |
|
|
511
|
+
| `partial` | Partial | `◐` | `!` | `warning` |
|
|
512
|
+
| `unchanged` | Unchanged | `↪` | `-` | `muted` |
|
|
513
|
+
| `skipped` | Skipped | `–` | `-` | `muted` |
|
|
514
|
+
| `unknown` | Unknown | `?` | `?` | `muted` |
|
|
515
|
+
| `failed` | Failed | `×` | `x` | `danger` |
|
|
516
|
+
|
|
517
|
+
Tone values used by public APIs include `info`, `success`, `warning`, `danger`, and `muted`.
|
|
518
|
+
|
|
220
519
|
## Gallery
|
|
221
520
|
|
|
521
|
+
Use the gallery to review current renderer output:
|
|
522
|
+
|
|
222
523
|
```bash
|
|
223
524
|
cli-style gallery
|
|
224
525
|
cli-style gallery no-colour
|
|
526
|
+
cli-style gallery --section primitives
|
|
225
527
|
cli-style gallery --section patterns
|
|
226
528
|
cli-style gallery --fixture audit-finding
|
|
227
529
|
cli-style gallery --profile agent
|
|
@@ -229,4 +531,4 @@ cli-style gallery --width 64
|
|
|
229
531
|
cli-style gallery --variants
|
|
230
532
|
```
|
|
231
533
|
|
|
232
|
-
Use
|
|
534
|
+
Use `--interactive` to select a section or fixture with `fzf` when it is installed.
|
|
@@ -41,6 +41,41 @@ cli_style_json_string() {
|
|
|
41
41
|
printf '"%s"' "$value"
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
# Escape Bash strings for a JSON string array.
|
|
45
|
+
#
|
|
46
|
+
# @param {string} ...
|
|
47
|
+
# String values to encode. Empty values are skipped.
|
|
48
|
+
cli_style_json_string_array() {
|
|
49
|
+
local item
|
|
50
|
+
local separator=""
|
|
51
|
+
|
|
52
|
+
printf '['
|
|
53
|
+
|
|
54
|
+
for item in "$@"; do
|
|
55
|
+
if [[ "$item" != "" ]]; then
|
|
56
|
+
printf '%s' "$separator"
|
|
57
|
+
cli_style_json_string "$item"
|
|
58
|
+
separator=","
|
|
59
|
+
fi
|
|
60
|
+
done
|
|
61
|
+
|
|
62
|
+
printf ']'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Render a Bash value as a JSON integer or null.
|
|
66
|
+
#
|
|
67
|
+
# @param {string} value
|
|
68
|
+
# Integer value to encode.
|
|
69
|
+
cli_style_json_integer_or_null() {
|
|
70
|
+
local value="${1:-}"
|
|
71
|
+
|
|
72
|
+
if [[ "$value" =~ ^-?[0-9]+$ ]]; then
|
|
73
|
+
printf '%s' "$value"
|
|
74
|
+
else
|
|
75
|
+
printf 'null'
|
|
76
|
+
fi
|
|
77
|
+
}
|
|
78
|
+
|
|
44
79
|
# Render a JSON object through the shared cli-style command.
|
|
45
80
|
#
|
|
46
81
|
# @param {string} renderer
|
|
@@ -116,24 +151,57 @@ cli_style_status() {
|
|
|
116
151
|
# Row label.
|
|
117
152
|
# @param {string} value
|
|
118
153
|
# Row value.
|
|
154
|
+
# @param {string} result
|
|
155
|
+
# Optional result type before render flags.
|
|
119
156
|
# @param {string} ...
|
|
120
157
|
# Render flags passed through to `cli-style render`.
|
|
121
158
|
cli_style_row() {
|
|
122
159
|
local label="${1:-}"
|
|
123
160
|
local value="${2:-}"
|
|
161
|
+
local result=""
|
|
124
162
|
local json
|
|
125
163
|
|
|
126
|
-
if (($# >=
|
|
164
|
+
if (($# >= 3)) && [[ "${3:-}" != --* ]]; then
|
|
165
|
+
result="${3:-}"
|
|
166
|
+
shift 3
|
|
167
|
+
elif (($# >= 2)); then
|
|
127
168
|
shift 2
|
|
128
169
|
else
|
|
129
170
|
set --
|
|
130
171
|
fi
|
|
131
172
|
|
|
132
|
-
json="{\"label\":$(cli_style_json_string "$label"),\"value\":$(cli_style_json_string "$value")}"
|
|
173
|
+
json="{\"label\":$(cli_style_json_string "$label"),\"value\":$(cli_style_json_string "$value"),\"result\":$(cli_style_json_string "$result")}"
|
|
133
174
|
|
|
134
175
|
cli_style_render_json row "$json" "$@"
|
|
135
176
|
}
|
|
136
177
|
|
|
178
|
+
# Render an inline span from Bash string values.
|
|
179
|
+
#
|
|
180
|
+
# @param {string} value
|
|
181
|
+
# Span text.
|
|
182
|
+
# @param {string} tone
|
|
183
|
+
# Optional colour tone.
|
|
184
|
+
# @param {string} ...
|
|
185
|
+
# Render flags passed through to `cli-style render`.
|
|
186
|
+
cli_style_span() {
|
|
187
|
+
local value="${1:-}"
|
|
188
|
+
local tone="info"
|
|
189
|
+
local json
|
|
190
|
+
|
|
191
|
+
if (($# >= 2)) && [[ "${2:-}" != --* ]]; then
|
|
192
|
+
tone="${2:-}"
|
|
193
|
+
shift 2
|
|
194
|
+
elif (($# >= 1)); then
|
|
195
|
+
shift
|
|
196
|
+
else
|
|
197
|
+
set --
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
json="{\"value\":$(cli_style_json_string "$value"),\"tone\":$(cli_style_json_string "$tone")}"
|
|
201
|
+
|
|
202
|
+
cli_style_render_json span "$json" "$@"
|
|
203
|
+
}
|
|
204
|
+
|
|
137
205
|
# Render a divider from a Bash string value.
|
|
138
206
|
#
|
|
139
207
|
# @param {string} label
|
|
@@ -175,3 +243,168 @@ cli_style_hint() {
|
|
|
175
243
|
|
|
176
244
|
cli_style_render_json hint "$json" "$@"
|
|
177
245
|
}
|
|
246
|
+
|
|
247
|
+
# Render a command result pattern from Bash string values.
|
|
248
|
+
#
|
|
249
|
+
# @param {string} result
|
|
250
|
+
# Result type such as success, failed, warning, or skipped.
|
|
251
|
+
# @param {string} summary
|
|
252
|
+
# Summary line.
|
|
253
|
+
# @param {string} command
|
|
254
|
+
# Optional command text.
|
|
255
|
+
# @param {string} exit_code
|
|
256
|
+
# Optional integer exit code.
|
|
257
|
+
# @param {string} duration
|
|
258
|
+
# Optional duration text.
|
|
259
|
+
# @param {string} detail
|
|
260
|
+
# Optional detail line.
|
|
261
|
+
# @param {string} ...
|
|
262
|
+
# Render flags passed through to `cli-style render`.
|
|
263
|
+
cli_style_command_result() {
|
|
264
|
+
local result="${1:-}"
|
|
265
|
+
local summary="${2:-}"
|
|
266
|
+
local command="${3:-}"
|
|
267
|
+
local exit_code="${4:-}"
|
|
268
|
+
local duration="${5:-}"
|
|
269
|
+
local detail="${6:-}"
|
|
270
|
+
local json
|
|
271
|
+
|
|
272
|
+
if (($# >= 6)); then
|
|
273
|
+
shift 6
|
|
274
|
+
else
|
|
275
|
+
set --
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
json="{\"result\":$(cli_style_json_string "$result"),\"summary\":$(cli_style_json_string "$summary"),\"command\":$(cli_style_json_string "$command"),\"exitCode\":$(cli_style_json_integer_or_null "$exit_code"),\"duration\":$(cli_style_json_string "$duration"),\"details\":$(cli_style_json_string_array "$detail")}"
|
|
279
|
+
|
|
280
|
+
cli_style_render_json command-result "$json" "$@"
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
# Render an audit finding pattern from Bash string values.
|
|
284
|
+
#
|
|
285
|
+
# @param {string} result
|
|
286
|
+
# Result type such as success, failed, warning, or skipped.
|
|
287
|
+
# @param {string} finding
|
|
288
|
+
# Finding summary.
|
|
289
|
+
# @param {string} location
|
|
290
|
+
# Optional source location.
|
|
291
|
+
# @param {string} recommendation
|
|
292
|
+
# Optional recommendation text.
|
|
293
|
+
# @param {string} evidence
|
|
294
|
+
# Optional evidence line.
|
|
295
|
+
# @param {string} reference
|
|
296
|
+
# Optional reference line.
|
|
297
|
+
# @param {string} ...
|
|
298
|
+
# Render flags passed through to `cli-style render`.
|
|
299
|
+
cli_style_audit_finding() {
|
|
300
|
+
local result="${1:-}"
|
|
301
|
+
local finding="${2:-}"
|
|
302
|
+
local location="${3:-}"
|
|
303
|
+
local recommendation="${4:-}"
|
|
304
|
+
local evidence="${5:-}"
|
|
305
|
+
local reference="${6:-}"
|
|
306
|
+
local json
|
|
307
|
+
|
|
308
|
+
if (($# >= 6)); then
|
|
309
|
+
shift 6
|
|
310
|
+
else
|
|
311
|
+
set --
|
|
312
|
+
fi
|
|
313
|
+
|
|
314
|
+
json="{\"result\":$(cli_style_json_string "$result"),\"finding\":$(cli_style_json_string "$finding"),\"location\":$(cli_style_json_string "$location"),\"recommendation\":$(cli_style_json_string "$recommendation"),\"evidence\":$(cli_style_json_string_array "$evidence"),\"references\":$(cli_style_json_string_array "$reference")}"
|
|
315
|
+
|
|
316
|
+
cli_style_render_json audit-finding "$json" "$@"
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
# Render a task summary pattern from Bash string values.
|
|
320
|
+
#
|
|
321
|
+
# @param {string} result
|
|
322
|
+
# Result type such as success, failed, warning, or skipped.
|
|
323
|
+
# @param {string} task
|
|
324
|
+
# Task label.
|
|
325
|
+
# @param {string} summary
|
|
326
|
+
# Optional summary detail.
|
|
327
|
+
# @param {string} completed
|
|
328
|
+
# Optional completed item.
|
|
329
|
+
# @param {string} remaining
|
|
330
|
+
# Optional remaining item.
|
|
331
|
+
# @param {string} ...
|
|
332
|
+
# Render flags passed through to `cli-style render`.
|
|
333
|
+
cli_style_task_summary() {
|
|
334
|
+
local result="${1:-}"
|
|
335
|
+
local task="${2:-}"
|
|
336
|
+
local summary="${3:-}"
|
|
337
|
+
local completed="${4:-}"
|
|
338
|
+
local remaining="${5:-}"
|
|
339
|
+
local json
|
|
340
|
+
|
|
341
|
+
if (($# >= 5)); then
|
|
342
|
+
shift 5
|
|
343
|
+
else
|
|
344
|
+
set --
|
|
345
|
+
fi
|
|
346
|
+
|
|
347
|
+
json="{\"result\":$(cli_style_json_string "$result"),\"task\":$(cli_style_json_string "$task"),\"summary\":$(cli_style_json_string "$summary"),\"completed\":$(cli_style_json_string_array "$completed"),\"remaining\":$(cli_style_json_string_array "$remaining")}"
|
|
348
|
+
|
|
349
|
+
cli_style_render_json task-summary "$json" "$@"
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
# Render a confirmation result pattern from Bash string values.
|
|
353
|
+
#
|
|
354
|
+
# @param {string} state
|
|
355
|
+
# Confirmation state such as confirmed, cancelled, or skipped.
|
|
356
|
+
# @param {string} action
|
|
357
|
+
# Action label.
|
|
358
|
+
# @param {string} item
|
|
359
|
+
# Optional item label.
|
|
360
|
+
# @param {string} detail
|
|
361
|
+
# Optional detail text.
|
|
362
|
+
# @param {string} ...
|
|
363
|
+
# Render flags passed through to `cli-style render`.
|
|
364
|
+
cli_style_confirmation_result() {
|
|
365
|
+
local state="${1:-}"
|
|
366
|
+
local action="${2:-}"
|
|
367
|
+
local item="${3:-}"
|
|
368
|
+
local detail="${4:-}"
|
|
369
|
+
local json
|
|
370
|
+
|
|
371
|
+
if (($# >= 4)); then
|
|
372
|
+
shift 4
|
|
373
|
+
else
|
|
374
|
+
set --
|
|
375
|
+
fi
|
|
376
|
+
|
|
377
|
+
json="{\"state\":$(cli_style_json_string "$state"),\"action\":$(cli_style_json_string "$action"),\"item\":$(cli_style_json_string "$item"),\"detail\":$(cli_style_json_string "$detail")}"
|
|
378
|
+
|
|
379
|
+
cli_style_render_json confirmation-result "$json" "$@"
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
# Render a next-step block pattern from Bash string values.
|
|
383
|
+
#
|
|
384
|
+
# @param {string} next
|
|
385
|
+
# Next step text.
|
|
386
|
+
# @param {string} reason
|
|
387
|
+
# Optional reason text.
|
|
388
|
+
# @param {string} command
|
|
389
|
+
# Optional command line.
|
|
390
|
+
# @param {string} alternative
|
|
391
|
+
# Optional alternative line.
|
|
392
|
+
# @param {string} ...
|
|
393
|
+
# Render flags passed through to `cli-style render`.
|
|
394
|
+
cli_style_next_step_block() {
|
|
395
|
+
local next="${1:-}"
|
|
396
|
+
local reason="${2:-}"
|
|
397
|
+
local command="${3:-}"
|
|
398
|
+
local alternative="${4:-}"
|
|
399
|
+
local json
|
|
400
|
+
|
|
401
|
+
if (($# >= 4)); then
|
|
402
|
+
shift 4
|
|
403
|
+
else
|
|
404
|
+
set --
|
|
405
|
+
fi
|
|
406
|
+
|
|
407
|
+
json="{\"next\":$(cli_style_json_string "$next"),\"reason\":$(cli_style_json_string "$reason"),\"commands\":$(cli_style_json_string_array "$command"),\"alternatives\":$(cli_style_json_string_array "$alternative")}"
|
|
408
|
+
|
|
409
|
+
cli_style_render_json next-step-block "$json" "$@"
|
|
410
|
+
}
|
|
@@ -83,6 +83,221 @@ def render(
|
|
|
83
83
|
return result.stdout.rstrip("\n")
|
|
84
84
|
|
|
85
85
|
|
|
86
|
+
# Render a result status line from Python values.
|
|
87
|
+
#
|
|
88
|
+
# @param {str} type
|
|
89
|
+
# Result type such as success, failed, warning, or skipped.
|
|
90
|
+
# @param {str} label
|
|
91
|
+
# Status label.
|
|
92
|
+
# @param {str} detail
|
|
93
|
+
# Optional detail text.
|
|
94
|
+
def status(
|
|
95
|
+
type: str,
|
|
96
|
+
label: str = "",
|
|
97
|
+
detail: str = "",
|
|
98
|
+
**kwargs: Any,
|
|
99
|
+
) -> str:
|
|
100
|
+
return render("status", {"type": type, "label": label, "detail": detail}, **kwargs)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# Render a labelled value row from Python values.
|
|
104
|
+
#
|
|
105
|
+
# @param {str} label
|
|
106
|
+
# Row label.
|
|
107
|
+
# @param {str} value
|
|
108
|
+
# Row value.
|
|
109
|
+
# @param {str} result
|
|
110
|
+
# Optional result type for a symbol and tone.
|
|
111
|
+
def row(
|
|
112
|
+
label: str,
|
|
113
|
+
value: str,
|
|
114
|
+
result: str = "",
|
|
115
|
+
**kwargs: Any,
|
|
116
|
+
) -> str:
|
|
117
|
+
return render("row", {"label": label, "value": value, "result": result}, **kwargs)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# Render an inline span from Python values.
|
|
121
|
+
#
|
|
122
|
+
# @param {str} value
|
|
123
|
+
# Span text.
|
|
124
|
+
# @param {str} tone
|
|
125
|
+
# Optional colour tone, defaulting to info.
|
|
126
|
+
def span(
|
|
127
|
+
value: str,
|
|
128
|
+
tone: str = "info",
|
|
129
|
+
**kwargs: Any,
|
|
130
|
+
) -> str:
|
|
131
|
+
return render("span", {"value": value, "tone": tone}, **kwargs)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# Render a divider from a Python value.
|
|
135
|
+
#
|
|
136
|
+
# @param {str} label
|
|
137
|
+
# Optional divider label.
|
|
138
|
+
def divider(
|
|
139
|
+
label: str = "",
|
|
140
|
+
**kwargs: Any,
|
|
141
|
+
) -> str:
|
|
142
|
+
return render("divider", {"label": label}, **kwargs)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# Render a hint from a Python value.
|
|
146
|
+
#
|
|
147
|
+
# @param {str} message
|
|
148
|
+
# Hint message.
|
|
149
|
+
def hint(
|
|
150
|
+
message: str,
|
|
151
|
+
**kwargs: Any,
|
|
152
|
+
) -> str:
|
|
153
|
+
return render("hint", {"message": message}, **kwargs)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# Render a command result pattern from Python values.
|
|
157
|
+
#
|
|
158
|
+
# @param {str} result
|
|
159
|
+
# Result type such as success, failed, warning, or skipped.
|
|
160
|
+
# @param {str} summary
|
|
161
|
+
# Summary line.
|
|
162
|
+
# @param {str} command
|
|
163
|
+
# Optional command text.
|
|
164
|
+
# @param {int|None} exit_code
|
|
165
|
+
# Optional integer exit code.
|
|
166
|
+
# @param {str} duration
|
|
167
|
+
# Optional duration text.
|
|
168
|
+
# @param {str} detail
|
|
169
|
+
# Optional detail line.
|
|
170
|
+
def command_result(
|
|
171
|
+
result: str,
|
|
172
|
+
summary: str,
|
|
173
|
+
command: str = "",
|
|
174
|
+
exit_code: int | None = None,
|
|
175
|
+
duration: str = "",
|
|
176
|
+
detail: str = "",
|
|
177
|
+
**kwargs: Any,
|
|
178
|
+
) -> str:
|
|
179
|
+
return render("command-result", {
|
|
180
|
+
"result": result,
|
|
181
|
+
"summary": summary,
|
|
182
|
+
"command": command,
|
|
183
|
+
"exitCode": exit_code,
|
|
184
|
+
"duration": duration,
|
|
185
|
+
"details": [detail] if detail else [],
|
|
186
|
+
}, **kwargs)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# Render an audit finding pattern from Python values.
|
|
190
|
+
#
|
|
191
|
+
# @param {str} result
|
|
192
|
+
# Result type such as success, failed, warning, or skipped.
|
|
193
|
+
# @param {str} finding
|
|
194
|
+
# Finding summary.
|
|
195
|
+
# @param {str} location
|
|
196
|
+
# Optional source location.
|
|
197
|
+
# @param {str} recommendation
|
|
198
|
+
# Optional recommendation text.
|
|
199
|
+
# @param {str} evidence
|
|
200
|
+
# Optional evidence line.
|
|
201
|
+
# @param {str} reference
|
|
202
|
+
# Optional reference line.
|
|
203
|
+
def audit_finding(
|
|
204
|
+
result: str,
|
|
205
|
+
finding: str,
|
|
206
|
+
location: str = "",
|
|
207
|
+
recommendation: str = "",
|
|
208
|
+
evidence: str = "",
|
|
209
|
+
reference: str = "",
|
|
210
|
+
**kwargs: Any,
|
|
211
|
+
) -> str:
|
|
212
|
+
return render("audit-finding", {
|
|
213
|
+
"result": result,
|
|
214
|
+
"finding": finding,
|
|
215
|
+
"location": location,
|
|
216
|
+
"recommendation": recommendation,
|
|
217
|
+
"evidence": [evidence] if evidence else [],
|
|
218
|
+
"references": [reference] if reference else [],
|
|
219
|
+
}, **kwargs)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
# Render a task summary pattern from Python values.
|
|
223
|
+
#
|
|
224
|
+
# @param {str} result
|
|
225
|
+
# Result type such as success, failed, warning, or skipped.
|
|
226
|
+
# @param {str} task
|
|
227
|
+
# Task label.
|
|
228
|
+
# @param {str} summary
|
|
229
|
+
# Optional summary detail.
|
|
230
|
+
# @param {str} completed
|
|
231
|
+
# Optional completed item.
|
|
232
|
+
# @param {str} remaining
|
|
233
|
+
# Optional remaining item.
|
|
234
|
+
def task_summary(
|
|
235
|
+
result: str,
|
|
236
|
+
task: str,
|
|
237
|
+
summary: str = "",
|
|
238
|
+
completed: str = "",
|
|
239
|
+
remaining: str = "",
|
|
240
|
+
**kwargs: Any,
|
|
241
|
+
) -> str:
|
|
242
|
+
return render("task-summary", {
|
|
243
|
+
"result": result,
|
|
244
|
+
"task": task,
|
|
245
|
+
"summary": summary,
|
|
246
|
+
"completed": [completed] if completed else [],
|
|
247
|
+
"remaining": [remaining] if remaining else [],
|
|
248
|
+
}, **kwargs)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
# Render a confirmation result pattern from Python values.
|
|
252
|
+
#
|
|
253
|
+
# @param {str} state
|
|
254
|
+
# Confirmation state such as confirmed, cancelled, or skipped.
|
|
255
|
+
# @param {str} action
|
|
256
|
+
# Action label.
|
|
257
|
+
# @param {str} item
|
|
258
|
+
# Optional item label.
|
|
259
|
+
# @param {str} detail
|
|
260
|
+
# Optional detail text.
|
|
261
|
+
def confirmation_result(
|
|
262
|
+
state: str,
|
|
263
|
+
action: str,
|
|
264
|
+
item: str = "",
|
|
265
|
+
detail: str = "",
|
|
266
|
+
**kwargs: Any,
|
|
267
|
+
) -> str:
|
|
268
|
+
return render("confirmation-result", {
|
|
269
|
+
"state": state,
|
|
270
|
+
"action": action,
|
|
271
|
+
"item": item,
|
|
272
|
+
"detail": detail,
|
|
273
|
+
}, **kwargs)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
# Render a next-step block pattern from Python values.
|
|
277
|
+
#
|
|
278
|
+
# @param {str} next_step
|
|
279
|
+
# Next step text.
|
|
280
|
+
# @param {str} reason
|
|
281
|
+
# Optional reason text.
|
|
282
|
+
# @param {str} command
|
|
283
|
+
# Optional command line.
|
|
284
|
+
# @param {str} alternative
|
|
285
|
+
# Optional alternative line.
|
|
286
|
+
def next_step_block(
|
|
287
|
+
next_step: str,
|
|
288
|
+
reason: str = "",
|
|
289
|
+
command: str = "",
|
|
290
|
+
alternative: str = "",
|
|
291
|
+
**kwargs: Any,
|
|
292
|
+
) -> str:
|
|
293
|
+
return render("next-step-block", {
|
|
294
|
+
"next": next_step,
|
|
295
|
+
"reason": reason,
|
|
296
|
+
"commands": [command] if command else [],
|
|
297
|
+
"alternatives": [alternative] if alternative else [],
|
|
298
|
+
}, **kwargs)
|
|
299
|
+
|
|
300
|
+
|
|
86
301
|
# Resolve a command name or executable path for subprocess use.
|
|
87
302
|
#
|
|
88
303
|
# @param {str} binary
|
package/package.json
CHANGED
|
@@ -13,6 +13,7 @@ import { emptyState, errorBlock, hint } from "../primitives/feedback.js";
|
|
|
13
13
|
import { panel } from "../primitives/panel.js";
|
|
14
14
|
import { progressBar } from "../primitives/progress-bar.js";
|
|
15
15
|
import { row } from "../primitives/row.js";
|
|
16
|
+
import { span } from "../primitives/span.js";
|
|
16
17
|
import { status } from "../primitives/status.js";
|
|
17
18
|
import { step, stepProgress } from "../primitives/step-progress.js";
|
|
18
19
|
import { table } from "../primitives/table.js";
|
|
@@ -72,6 +73,11 @@ const renderers = {
|
|
|
72
73
|
...input,
|
|
73
74
|
...options,
|
|
74
75
|
}),
|
|
76
|
+
span: (input, options) =>
|
|
77
|
+
span(input.value, input.tone, {
|
|
78
|
+
...input,
|
|
79
|
+
...options,
|
|
80
|
+
}),
|
|
75
81
|
status: (input, options) =>
|
|
76
82
|
status(input.type, input.detail, {
|
|
77
83
|
...input,
|
|
@@ -14,6 +14,7 @@ import { emptyState, errorBlock, hint } from "../primitives/feedback.js";
|
|
|
14
14
|
import { panel } from "../primitives/panel.js";
|
|
15
15
|
import { progressBar } from "../primitives/progress-bar.js";
|
|
16
16
|
import { row } from "../primitives/row.js";
|
|
17
|
+
import { span } from "../primitives/span.js";
|
|
17
18
|
import { status } from "../primitives/status.js";
|
|
18
19
|
import { step, stepProgress, stepStates } from "../primitives/step-progress.js";
|
|
19
20
|
import { table } from "../primitives/table.js";
|
|
@@ -676,7 +677,7 @@ function renderPrimitives(options) {
|
|
|
676
677
|
}),
|
|
677
678
|
"",
|
|
678
679
|
"Feedback",
|
|
679
|
-
hint("
|
|
680
|
+
hint(`Run ${span("npm run docs:readme", "info", options)}`, options),
|
|
680
681
|
emptyState("No results", "tone: muted", options),
|
|
681
682
|
errorBlock("Failed", ["tone: danger"], {
|
|
682
683
|
...options,
|
|
@@ -709,6 +710,11 @@ function renderPrimitives(options) {
|
|
|
709
710
|
...options,
|
|
710
711
|
labelWidth: 8,
|
|
711
712
|
}),
|
|
713
|
+
row("Bundle", "is 22.3 KB, above the 12.0 KB budget", {
|
|
714
|
+
...options,
|
|
715
|
+
labelWidth: 8,
|
|
716
|
+
result: resultTypes.FAILED,
|
|
717
|
+
}),
|
|
712
718
|
].join("\n");
|
|
713
719
|
}
|
|
714
720
|
|
package/src/index.js
CHANGED
|
@@ -35,6 +35,7 @@ export { emptyState, errorBlock, hint } from "./primitives/feedback.js";
|
|
|
35
35
|
export { panel } from "./primitives/panel.js";
|
|
36
36
|
export { progressBar } from "./primitives/progress-bar.js";
|
|
37
37
|
export { row } from "./primitives/row.js";
|
|
38
|
+
export { span } from "./primitives/span.js";
|
|
38
39
|
export { status } from "./primitives/status.js";
|
|
39
40
|
export { step, stepProgress, stepStates } from "./primitives/step-progress.js";
|
|
40
41
|
export { table } from "./primitives/table.js";
|
package/src/primitives/row.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { foreground } from "../formatters/ansi.js";
|
|
2
|
+
import { getResultSymbol, getResultToken } from "../theme/results.js";
|
|
2
3
|
|
|
3
4
|
// Row labels use the same subdued tone as table headers by default.
|
|
4
5
|
const defaultLabelColour = "muted";
|
|
@@ -21,6 +22,8 @@ const defaultSeparator = " ";
|
|
|
21
22
|
* Colour token for the label.
|
|
22
23
|
* @param {number} options.labelWidth
|
|
23
24
|
* Minimum label width before the separator.
|
|
25
|
+
* @param {string} options.result
|
|
26
|
+
* Optional semantic result state for the row.
|
|
24
27
|
* @param {string} options.separator
|
|
25
28
|
* Text between label and value.
|
|
26
29
|
* @param {string} options.valueColour
|
|
@@ -29,8 +32,10 @@ const defaultSeparator = " ";
|
|
|
29
32
|
* Rendered row.
|
|
30
33
|
*/
|
|
31
34
|
export function row(label, value = "", options = {}) {
|
|
32
|
-
const
|
|
33
|
-
const
|
|
35
|
+
const resultToken = resolveResultToken(options);
|
|
36
|
+
const displayLabel = renderDisplayLabel(label, resultToken, options);
|
|
37
|
+
const labelWidth = Math.max(displayLabel.length, options.labelWidth ?? 0);
|
|
38
|
+
const labelText = displayLabel.padEnd(labelWidth, " ");
|
|
34
39
|
const renderedLabel = renderLabel(labelText, options);
|
|
35
40
|
|
|
36
41
|
if (value === "") {
|
|
@@ -43,6 +48,44 @@ export function row(label, value = "", options = {}) {
|
|
|
43
48
|
return `${renderedLabel}${separator}${renderedValue}`;
|
|
44
49
|
}
|
|
45
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Resolve the row's optional result token.
|
|
53
|
+
*
|
|
54
|
+
* @param {object} options
|
|
55
|
+
* Rendering options.
|
|
56
|
+
* @returns {object|null}
|
|
57
|
+
* Result token when a row result is provided.
|
|
58
|
+
*/
|
|
59
|
+
function resolveResultToken(options) {
|
|
60
|
+
if (typeof options.result !== "string" || options.result === "") {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return getResultToken(options.result);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Render the visible row label, including any result symbol.
|
|
69
|
+
*
|
|
70
|
+
* @param {string} label
|
|
71
|
+
* Label text to render.
|
|
72
|
+
* @param {object|null} resultToken
|
|
73
|
+
* Optional result token.
|
|
74
|
+
* @param {object} options
|
|
75
|
+
* Rendering options.
|
|
76
|
+
* @returns {string}
|
|
77
|
+
* Label text with any result prefix.
|
|
78
|
+
*/
|
|
79
|
+
function renderDisplayLabel(label, resultToken, options) {
|
|
80
|
+
if (resultToken === null) {
|
|
81
|
+
return label;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const symbol = getResultSymbol(options.result, options);
|
|
85
|
+
|
|
86
|
+
return `${symbol} ${label}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
46
89
|
/**
|
|
47
90
|
* Render a row label.
|
|
48
91
|
*
|
|
@@ -58,7 +101,7 @@ function renderLabel(label, options) {
|
|
|
58
101
|
return label;
|
|
59
102
|
}
|
|
60
103
|
|
|
61
|
-
return foreground(label, options
|
|
104
|
+
return foreground(label, getLabelColour(options), options);
|
|
62
105
|
}
|
|
63
106
|
|
|
64
107
|
/**
|
|
@@ -72,9 +115,55 @@ function renderLabel(label, options) {
|
|
|
72
115
|
* Rendered value.
|
|
73
116
|
*/
|
|
74
117
|
function renderValue(value, options) {
|
|
75
|
-
if (options.colour !== true
|
|
118
|
+
if (options.colour !== true) {
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const colour = getValueColour(options);
|
|
123
|
+
|
|
124
|
+
if (colour === undefined) {
|
|
76
125
|
return value;
|
|
77
126
|
}
|
|
78
127
|
|
|
79
|
-
return foreground(value,
|
|
128
|
+
return foreground(value, colour, options);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Resolve the colour token for the row label.
|
|
133
|
+
*
|
|
134
|
+
* @param {object} options
|
|
135
|
+
* Rendering options.
|
|
136
|
+
* @returns {string}
|
|
137
|
+
* Colour token for the label.
|
|
138
|
+
*/
|
|
139
|
+
function getLabelColour(options) {
|
|
140
|
+
if (options.labelColour !== undefined) {
|
|
141
|
+
return options.labelColour;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (typeof options.result === "string" && options.result !== "") {
|
|
145
|
+
return getResultToken(options.result).tone;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return defaultLabelColour;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Resolve the colour token for the row value.
|
|
153
|
+
*
|
|
154
|
+
* @param {object} options
|
|
155
|
+
* Rendering options.
|
|
156
|
+
* @returns {string|undefined}
|
|
157
|
+
* Colour token for the value.
|
|
158
|
+
*/
|
|
159
|
+
function getValueColour(options) {
|
|
160
|
+
if (options.valueColour !== undefined) {
|
|
161
|
+
return options.valueColour;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (typeof options.result === "string" && options.result !== "") {
|
|
165
|
+
return getResultToken(options.result).tone;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return undefined;
|
|
80
169
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { foreground, style } from "../formatters/ansi.js";
|
|
2
|
+
|
|
3
|
+
// Inline spans use the same informational tone as hints by default.
|
|
4
|
+
const defaultTone = "info";
|
|
5
|
+
|
|
6
|
+
// Inline emphasis should remain visible without forcing a block-level renderer.
|
|
7
|
+
const defaultWeight = "bold";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Render an inline text span.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} value
|
|
13
|
+
* Text to render.
|
|
14
|
+
* @param {string} tone
|
|
15
|
+
* Colour tone for the span.
|
|
16
|
+
* @param {object} options
|
|
17
|
+
* Rendering options.
|
|
18
|
+
* @param {boolean} options.colour
|
|
19
|
+
* Whether ANSI colour should be applied.
|
|
20
|
+
* @param {string} options.weight
|
|
21
|
+
* Optional ANSI text weight.
|
|
22
|
+
* @returns {string}
|
|
23
|
+
* Rendered span.
|
|
24
|
+
*/
|
|
25
|
+
export function span(value = "", tone = defaultTone, options = {}) {
|
|
26
|
+
if (options.colour !== true) {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const renderedValue = foreground(value, tone, options);
|
|
31
|
+
|
|
32
|
+
return style(renderedValue, options.weight ?? defaultWeight, options);
|
|
33
|
+
}
|