beautiful-python-cli 0.0.0-stage → 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 syrex1013
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,107 @@
1
- # Temporary Holding Version
1
+ # beautiful-python-cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A comprehensive agent skill for crafting polished, accessible terminal user interfaces (TUIs) and CLI applications in Python using [Rich](https://github.com/Textualize/rich).
4
+
5
+ Designed for modern AI coding assistants including Claude Code, Cursor, Gemini / Antigravity, Codex, Windsurf, and Pi.
6
+
7
+ ---
8
+
9
+ ## Capabilities
10
+
11
+ - **Status & Spinners**: Indeterminate operation indicators with clean context manager lifecycle.
12
+ - **Progress Bars**: Measurable multi-task, byte-transfer, and ETA progress bars.
13
+ - **Live Dashboards & TUIs**: Real-time updating multi-pane layouts with responsive screen partitioning.
14
+ - **Interactive Prompts**: Input validation, defaults, yes/no confirmations, and masked secret entries.
15
+ - **Structured Output**: Stylized tables, summary panels, and tree structures with terminal width adaptability.
16
+ - **Diagnostics & Tracebacks**: Production-safe stack trace formatting and syntax highlighting.
17
+ - **Contract Adherence**: Full compliance with `NO_COLOR`, non-TTY environments, and pure machine-readable `--json` streams.
18
+
19
+ ---
20
+
21
+ ## Installation
22
+
23
+ ### Via `npx skills` (Recommended)
24
+
25
+ Install directly into your AI coding assistant:
26
+
27
+ ```bash
28
+ # Add to current project
29
+ npx skills add syrex1013/beautiful-python-cli
30
+
31
+ # Install globally across all agents
32
+ npx skills add syrex1013/beautiful-python-cli -g
33
+ ```
34
+
35
+ ### Via Shell Installer
36
+
37
+ Clone and run the universal installer:
38
+
39
+ ```bash
40
+ git clone https://github.com/syrex1013/beautiful-python-cli.git
41
+ cd beautiful-python-cli
42
+
43
+ # Install for all supported agents
44
+ ./install.sh --all
45
+
46
+ # Or target specific agents
47
+ ./install.sh --claude
48
+ ./install.sh --cursor
49
+ ./install.sh --antigravity
50
+ ./install.sh --codex
51
+ ./install.sh --windsurf
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Directory Structure
57
+
58
+ ```text
59
+ beautiful-python-cli/
60
+ ├── SKILL.md # Core agent skill instructions and routing
61
+ ├── package.json # npm / skills.sh package metadata
62
+ ├── LICENSE # MIT License
63
+ ├── requirements.txt # Python dependencies (rich)
64
+ ├── install.sh # Multi-agent installer script
65
+ ├── references/ # In-depth architectural guides
66
+ │ ├── rich-components.md # Component selection and theme definitions
67
+ │ ├── interaction-patterns.md # Spinners, progress, and live updates
68
+ │ ├── prompts-and-inputs.md # Interactive prompt validation & secrets
69
+ │ ├── tracebacks-and-debugging.md # Error reporting and syntax highlighting
70
+ │ ├── layouts-and-tui.md # Screen partitioning & responsive grids
71
+ │ ├── concurrent-progress.md # Multi-threaded and async workers
72
+ │ └── testing-and-accessibility.md # Non-TTY handling, JSON purity, test suite
73
+ ├── examples/ # Runnable implementation patterns
74
+ │ ├── showcase.py # Tables, panels, status, and progress
75
+ │ ├── live_dashboard.py # Dynamic Live dashboard
76
+ │ ├── interactive_prompts.py # Prompts, choices, and confirmation
77
+ │ ├── concurrent_progress.py # ThreadPoolExecutor multi-bar progress
78
+ │ └── tui_layout.py # Multi-pane terminal dashboard
79
+ └── tests/
80
+ └── test_skill.py # Automated unit tests
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Running the Examples
86
+
87
+ ```bash
88
+ python3 -m pip install -r requirements.txt
89
+
90
+ # Run the comprehensive showcase
91
+ python3 examples/showcase.py
92
+
93
+ # Run interactive wizard demonstration
94
+ python3 examples/interactive_prompts.py --non-interactive
95
+
96
+ # Run multi-threaded progress demo
97
+ python3 examples/concurrent_progress.py --workers 4
98
+
99
+ # Run real-time monitoring TUI
100
+ python3 examples/tui_layout.py --seconds 3
101
+ ```
102
+
103
+ ---
104
+
105
+ ## License
106
+
107
+ MIT © syrex1013
package/SKILL.md ADDED
@@ -0,0 +1,178 @@
1
+ ---
2
+ name: beautiful-python-cli
3
+ description: Design, implement, or refactor Python command-line output into polished, accessible terminal UIs using Rich. Use when adding spinners, loading states, progress bars, concurrent tasks, interactive prompts, live dashboards, TUI layouts, real-time logs, colored status, tables, panels, themes, or terminal UX. Do not use for GUI/web interfaces or trivial one-off scripts that only need plain output.
4
+ ---
5
+
6
+ # Beautiful Python CLI
7
+
8
+ Build terminal interfaces that are useful first and visually polished second. Prefer clear information hierarchy, truthful status, restrained color, and reusable rendering code over decoration.
9
+
10
+ ## Instruction priority
11
+
12
+ Follow the user's explicit requirements and the repository's established conventions first. This skill supplies defaults where the user or project has not specified a choice. Do not migrate CLI frameworks, redesign unrelated code, or add dependencies without a concrete reason.
13
+
14
+ ## Workflow
15
+
16
+ 1. **Inspect before changing**
17
+ - Read the relevant entry point, CLI framework, `pyproject.toml`/requirements, supported Python version, and nearby tests.
18
+ - Identify whether stdout is intended for humans, scripts, or both.
19
+ - Preserve existing commands, flags, exit codes, output contracts, and business logic.
20
+ 2. **Choose the smallest useful design**
21
+ - Use `rich` for rendering. Keep the project's existing `argparse`, Typer, Click, or other CLI framework; Typer is optional, not a requirement.
22
+ - Avoid adding `questionary`, `loguru`, or other dependencies when Rich or the existing stack is sufficient.
23
+ - If Rich is missing, explain the dependency and add it through the repository's existing dependency mechanism. Do not silently run a global `pip install`.
24
+ 3. **Centralize presentation**
25
+ - Create one shared `Console` (or a small UI module) and a reusable semantic theme.
26
+ - Keep UI/rendering separate from domain logic. Prefer functions such as `render_summary`, `render_findings_table`, `show_status`, and `make_progress`.
27
+ - Use stable style names (`success`, `warning`, `error`, `info`, `muted`, `accent`) instead of scattering raw ANSI escapes or color literals.
28
+ 4. **Match the indicator to the work**
29
+ - Use a spinner/status for work whose completion percentage is unknown.
30
+ - Use a progress bar only when real progress can be measured (items, bytes, stages, or completed tasks).
31
+ - Use a live dashboard only when continuously changing information materially helps the operator.
32
+ - Never invent percentages, ETAs, throughput, completion counts, or scan results.
33
+ 5. **Handle every output environment**
34
+ - Detect TTY/terminal capability; do not force ANSI color or animation by default.
35
+ - Support `NO_COLOR`, redirected output, CI logs, SSH terminals, and narrow terminal widths.
36
+ - Keep machine-readable output (especially JSON) clean. Send human diagnostics/progress to stderr when stdout is a data stream.
37
+ - Provide a plain or no-color mode when appropriate.
38
+ 6. **Verify the result**
39
+ - Run focused tests and the project's formatter/linter/type checker where available.
40
+ - Test a normal terminal, redirected/non-TTY output, narrow width, errors, and empty results.
41
+ - Confirm that progress and live displays stop cleanly on success, failure, and cancellation.
42
+
43
+ ## Visual system
44
+
45
+ Use a restrained, consistent palette with semantic meaning:
46
+
47
+ | Role | Suggested style | Meaning |
48
+ |---|---|---|
49
+ | Success | `green` / `bold green` | Completed, valid, healthy |
50
+ | Warning | `yellow` / `bold yellow` | Degraded, partial, needs attention |
51
+ | Error | `red` / `bold red` | Failed, invalid, blocked |
52
+ | Info | `cyan` | Neutral operational information |
53
+ | Accent | `bright_magenta` or `bright_blue` | Product identity or emphasis |
54
+ | Muted | `dim` | Secondary metadata |
55
+
56
+ Color must never be the only signal. Pair it with words (`OK`, `WARN`, `FAIL`), symbols, or explicit columns. Avoid rainbow output, excessive bolding, and large banners on every command. Respect user-specified brand colors and existing themes.
57
+
58
+ ## Required UI patterns
59
+
60
+ ### Startup and command header
61
+ - Show a compact application name/version only when it adds context.
62
+ - Keep banners short; avoid delaying useful output with decorative animations.
63
+ - Display target, scope, configuration, or execution mode only when relevant and safe to disclose.
64
+ - Never print credentials, tokens, cookies, private keys, or other secrets.
65
+
66
+ ### Spinners and loading states
67
+ - Use `console.status("Connecting…", spinner="dots")` for a short, indeterminate operation.
68
+ - Choose a spinner that renders reliably in common terminals; allow Rich to fall back when Unicode is unavailable.
69
+ - Use `console.status` as a context manager so it stops on exceptions.
70
+ - Do not show a spinner for instant operations or when output is non-interactive.
71
+ - For multiple independent tasks, prefer a multi-task `Progress` display over nested spinners.
72
+
73
+ ### Progress bars
74
+ - Use `rich.progress.Progress` with columns that answer useful questions:
75
+ - `SpinnerColumn` or `TextColumn` for task identity
76
+ - `BarColumn` for visual completion
77
+ - `TaskProgressColumn` or `MofNCompleteColumn` for actual progress
78
+ - `TimeElapsedColumn` and `TimeRemainingColumn` only when meaningful
79
+ - `DownloadColumn` and `TransferSpeedColumn` for byte transfers
80
+ - Track real units: files, hosts, requests, records, bytes, or completed stages.
81
+ - For unknown totals, use an indeterminate task; do not display a fabricated total.
82
+ - For concurrent work, use separate named tasks and synchronized updates. Avoid interleaved `print()` calls from workers.
83
+ - Use `transient=True` only when the progress display should disappear after completion; keep important final results visible.
84
+ - Disable animated progress when `not console.is_terminal`.
85
+
86
+ ### Tables
87
+ - Use `rich.table.Table` for structured results. Give columns concise names and meaningful alignment.
88
+ - Right-align numbers; left-align names and descriptions; use `no_wrap` selectively.
89
+ - Use sensible overflow (`fold`, `ellipsis`, or `crop`) and let Rich adapt to terminal width.
90
+ - Include a useful empty-state message instead of rendering a blank table.
91
+ - Sort or group results when that improves scanning; do not hide important fields just to make the table look tidy.
92
+ - For security findings, distinguish severity, confidence, status, and evidence; do not imply severity from color alone.
93
+
94
+ ### Panels, summaries, and hierarchy
95
+ - Use `Panel` for a cohesive summary, alert, or grouped section—not around every line.
96
+ - Use `Rule` for major section boundaries and `Columns`/`Group` for compact related content.
97
+ - Put the most actionable information first. Keep secondary metadata dim and concise.
98
+ - Prefer one strong summary panel plus detailed tables over many nested boxes.
99
+
100
+ ### Live output and dashboards
101
+ - Use `Live` with `Layout`, `Table`, `Group`, or a custom renderable for dashboards that update repeatedly.
102
+ - Keep refresh rates modest (typically 4–10 updates/second); slower is usually sufficient for CLI monitoring.
103
+ - Use `screen=True` only for intentional full-screen terminal applications. Prefer `screen=False` for ordinary CLI progress.
104
+ - Use `console.log()` for timestamped messages while a live display is active; do not call built-in `print()` and corrupt the live region.
105
+ - Keep the dashboard readable at narrow widths and provide a final static summary when it exits.
106
+ - Ensure `Live` is stopped via a context manager, including on exceptions and Ctrl-C.
107
+
108
+ ### Interactive prompts and user input
109
+ - Use `Prompt.ask` for text input with defaults and validation.
110
+ - Use `Prompt.ask(..., choices=[...])` for constrained choices instead of freeform parsing.
111
+ - Use `Confirm.ask` for yes/no decisions.
112
+ - Use `Prompt.ask(..., password=True)` for secrets and tokens; never echo secrets back to stdout.
113
+ - Check `sys.stdin.isatty()` and provide safe non-interactive defaults for CI/CD or automated pipelines.
114
+
115
+ ### Tracebacks and error diagnostics
116
+ - Use `rich.traceback.install(show_locals=False, max_frames=5)` at the CLI boundary for readable error reports.
117
+ - Suppress framework frames (`click`, `typer`, `asyncio`) to focus on user code.
118
+ - Only enable `show_locals=True` when explicitly requested via `--debug` or `--verbose`.
119
+ - Prefer actionable summary panels for anticipated errors over raw stack traces.
120
+
121
+ ### Layouts and multi-pane TUIs
122
+ - Use `rich.layout.Layout` to partition terminal windows into headers, sidebars, main bodies, and footers.
123
+ - Combine with `rich.live.Live` for real-time monitoring and surveillance TUIs.
124
+ - Default to `screen=False` so command history remains accessible in scrollback.
125
+ - Design responsive layouts that remain clean down to 80x24 terminal dimensions.
126
+
127
+ ### Logs and errors
128
+ - Use `RichHandler` when integrating Python `logging`; configure it once at the application boundary.
129
+ - Keep logs concise and structured. Use timestamps/levels when they help diagnosis, not as decoration.
130
+ - Present expected operational errors as short actionable messages; expose tracebacks only in debug mode.
131
+ - Preserve non-zero exit codes and send diagnostics to stderr.
132
+ - Never swallow exceptions merely to keep the interface attractive.
133
+
134
+ ### Themes and output modes
135
+ - Define a `Theme` once and pass it to the shared `Console`.
136
+ - Use `Console(no_color=True)` or an explicit `--no-color` option when the project supports it; otherwise rely on terminal detection and `NO_COLOR`.
137
+ - When supporting `--json`, `--quiet`, or `--plain`, make these modes real contracts:
138
+ - `--json`: valid JSON only on stdout; no banner, spinner, table, or progress text on stdout.
139
+ - `--quiet`: suppress decorative and routine output while preserving errors and requested machine output.
140
+ - `--plain`: readable text without box drawing or ANSI styling.
141
+ - Do not hardcode terminal width. Use Rich's layout/wrapping behavior and test narrow widths.
142
+
143
+ ## Code quality rules
144
+
145
+ - Prefer Rich renderables over hand-built ANSI escape sequences.
146
+ - Use `console.print`, `console.log`, `console.status`, `Progress`, `Live`, `Table`, `Panel`, `Columns`, `Tree`, `Syntax`, and `JSON` where they fit.
147
+ - Avoid global monkey-patching, shelling out to `clear`, and repeated terminal erasure.
148
+ - Do not couple core operations to Rich objects; return data from core logic and render it at the CLI boundary.
149
+ - Do not add decorative output that makes copy/paste, piping, or log parsing harder.
150
+ - Use context managers for progress, status, live displays, and other resources.
151
+ - Make cancellation and failure paths as polished and reliable as the success path.
152
+
153
+ ## Definition of done
154
+
155
+ - The output communicates state, progress, results, and errors accurately.
156
+ - Spinners are used only for indeterminate work; progress bars reflect real measurements.
157
+ - Tables and panels remain readable at typical and narrow terminal widths.
158
+ - Live updates do not corrupt logs or final output.
159
+ - Redirected, CI, `NO_COLOR`, and JSON output remain usable.
160
+ - Existing CLI behavior and exit semantics are preserved.
161
+ - Tests or a reproducible manual verification cover the relevant output paths.
162
+
163
+ ## Supporting references
164
+
165
+ Read only the reference needed for the task:
166
+ - `references/rich-components.md` — Rich APIs, columns, tables, themes, and renderables.
167
+ - `references/interaction-patterns.md` — spinners, progress, live dashboards, async/concurrency patterns.
168
+ - `references/prompts-and-inputs.md` — interactive prompts, validation, secrets, and non-TTY guards.
169
+ - `references/tracebacks-and-debugging.md` — exception formatting, syntax highlighting, and introspection.
170
+ - `references/layouts-and-tui.md` — multi-pane screen partitioning and dynamic TUIs.
171
+ - `references/concurrent-progress.md` — thread-safe and async multi-task progress bars.
172
+ - `references/testing-and-accessibility.md` — TTY behavior, JSON/plain output, accessibility, and tests.
173
+ - `references/activation-tests.md` — positive and negative prompts for checking skill routing.
174
+ - `examples/showcase.py` — comprehensive panels, tables, and progress showcase.
175
+ - `examples/live_dashboard.py` — dynamic Live dashboard updating in real-time.
176
+ - `examples/interactive_prompts.py` — prompts, input validation, confirmation, and secret masking.
177
+ - `examples/concurrent_progress.py` — multi-threaded background workers with simultaneous progress bars.
178
+ - `examples/tui_layout.py` — multi-pane terminal layout for system monitoring.
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env python3
2
+ """Demonstration of multi-threaded concurrent workers with Rich progress bars."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import concurrent.futures
8
+ import random
9
+ import time
10
+
11
+ from rich.console import Console
12
+ from rich.panel import Panel
13
+ from rich.progress import (
14
+ BarColumn,
15
+ Progress,
16
+ SpinnerColumn,
17
+ TaskID,
18
+ TaskProgressColumn,
19
+ TextColumn,
20
+ TimeRemainingColumn,
21
+ )
22
+ from rich.table import Table
23
+ from rich.theme import Theme
24
+
25
+ THEME = Theme(
26
+ {
27
+ "success": "bold green",
28
+ "warning": "bold yellow",
29
+ "error": "bold red",
30
+ "info": "cyan",
31
+ "muted": "dim",
32
+ "accent": "bold cyan",
33
+ }
34
+ )
35
+
36
+ console = Console(theme=THEME)
37
+
38
+
39
+ def simulate_worker(progress: Progress, task_id: TaskID, name: str, total_chunks: int) -> tuple[str, bool, int]:
40
+ chunks_done = 0
41
+ for chunk in range(total_chunks):
42
+ time.sleep(random.uniform(0.02, 0.06))
43
+ chunks_done += 1
44
+ progress.advance(task_id, advance=1)
45
+ if chunk == total_chunks // 2:
46
+ progress.update(task_id, description=f"[info]{name}[/info] [muted](halfway)[/muted]")
47
+ progress.update(task_id, description=f"[success]{name}[/success] [muted](done)[/muted]")
48
+ return name, True, chunks_done
49
+
50
+
51
+ def main() -> None:
52
+ parser = argparse.ArgumentParser(description="Demonstrate concurrent multi-task progress.")
53
+ parser.add_argument("--workers", type=int, default=4, help="Number of concurrent workers")
54
+ args = parser.parse_args()
55
+
56
+ console.print(
57
+ Panel(
58
+ f"[accent]Concurrent Processing Engine[/accent]\n"
59
+ f"[muted]Dispatching {args.workers} background worker threads...[/muted]",
60
+ border_style="cyan",
61
+ )
62
+ )
63
+
64
+ results: list[tuple[str, bool, int]] = []
65
+
66
+ with Progress(
67
+ SpinnerColumn(),
68
+ TextColumn("[progress.description]{task.description}"),
69
+ BarColumn(bar_width=None),
70
+ TaskProgressColumn(),
71
+ TimeRemainingColumn(),
72
+ console=console,
73
+ ) as progress:
74
+ with concurrent.futures.ThreadPoolExecutor(max_workers=args.workers) as executor:
75
+ task_map = {}
76
+ for i in range(args.workers):
77
+ worker_name = f"Worker #{i + 1}"
78
+ steps = random.randint(15, 25)
79
+ task_id = progress.add_task(f"[accent]{worker_name}[/accent]", total=steps)
80
+ future = executor.submit(simulate_worker, progress, task_id, worker_name, steps)
81
+ task_map[future] = worker_name
82
+
83
+ for future in concurrent.futures.as_completed(task_map):
84
+ results.append(future.result())
85
+
86
+ # Final summary table
87
+ table = Table(title="Worker Execution Summary", expand=True)
88
+ table.add_column("Worker", style="bold")
89
+ table.add_column("Status", justify="center")
90
+ table.add_column("Processed Chunks", justify="right")
91
+
92
+ for name, success, chunks in sorted(results):
93
+ status_text = "[success]COMPLETED[/success]" if success else "[error]FAILED[/error]"
94
+ table.add_row(name, status_text, str(chunks))
95
+
96
+ console.print(table)
97
+
98
+
99
+ if __name__ == "__main__":
100
+ main()
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env python3
2
+ """Demonstration of interactive prompts, validation, and confirmation dialogs."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import sys
8
+
9
+ from rich.console import Console
10
+ from rich.panel import Panel
11
+ from rich.prompt import Confirm, IntPrompt, Prompt
12
+ from rich.theme import Theme
13
+
14
+ THEME = Theme(
15
+ {
16
+ "success": "bold green",
17
+ "warning": "bold yellow",
18
+ "error": "bold red",
19
+ "info": "cyan",
20
+ "muted": "dim",
21
+ "accent": "bold bright_magenta",
22
+ }
23
+ )
24
+
25
+ console = Console(theme=THEME)
26
+
27
+
28
+ def main() -> None:
29
+ parser = argparse.ArgumentParser(description="Demonstrate Rich interactive prompts.")
30
+ parser.add_argument("--non-interactive", action="store_true", help="Run with simulated answers")
31
+ args = parser.parse_args()
32
+
33
+ console.print(
34
+ Panel(
35
+ "[accent]CLI Configuration Wizard[/accent]\n"
36
+ "[muted]Demonstrates Prompt, Confirm, IntPrompt, and secret masking.[/muted]",
37
+ border_style="magenta",
38
+ )
39
+ )
40
+
41
+ if args.non_interactive or not sys.stdin.isatty():
42
+ console.print("[info]Running in non-interactive mode. Using defaults.[/info]")
43
+ project = "my-awesome-app"
44
+ env = "staging"
45
+ port = 8080
46
+ proceed = True
47
+ else:
48
+ project = Prompt.ask("[bold]Project Name[/bold]", default="my-awesome-app", console=console)
49
+ env = Prompt.ask(
50
+ "[bold]Environment[/bold]",
51
+ choices=["development", "staging", "production"],
52
+ default="staging",
53
+ console=console,
54
+ )
55
+ port = IntPrompt.ask("[bold]Service Port[/bold]", default=8080, console=console)
56
+ _token = Prompt.ask("[bold]API Token (masked)[/bold]", password=True, console=console)
57
+ proceed = Confirm.ask("\nSave configuration and initialize?", default=True, console=console)
58
+
59
+ if proceed:
60
+ console.print(
61
+ Panel(
62
+ f"[success]Configuration saved![/success]\n\n"
63
+ f"• Project: [accent]{project}[/accent]\n"
64
+ f"• Environment: [info]{env}[/info]\n"
65
+ f"• Port: [muted]{port}[/muted]",
66
+ title="[success]Summary[/success]",
67
+ border_style="green",
68
+ )
69
+ )
70
+ else:
71
+ console.print("[warning]Setup aborted by user.[/warning]")
72
+
73
+
74
+ if __name__ == "__main__":
75
+ try:
76
+ main()
77
+ except KeyboardInterrupt:
78
+ console.print("\n[error]Operation cancelled.[/error]")
79
+ sys.exit(130)
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env python3
2
+ """A small Live dashboard example with a durable final summary."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import random
8
+ import time
9
+ from dataclasses import dataclass
10
+
11
+ from rich.console import Console
12
+ from rich.live import Live
13
+ from rich.table import Table
14
+ from rich.theme import Theme
15
+
16
+ THEME = Theme(
17
+ {
18
+ "success": "bold green",
19
+ "warning": "bold yellow",
20
+ "error": "bold red",
21
+ "muted": "dim",
22
+ "accent": "bold cyan",
23
+ }
24
+ )
25
+
26
+
27
+ @dataclass
28
+ class Worker:
29
+ name: str
30
+ completed: int = 0
31
+ total: int = 12
32
+ state: str = "RUNNING"
33
+
34
+
35
+ def render(workers: list[Worker]) -> Table:
36
+ table = Table(title="Live worker dashboard", expand=True)
37
+ table.add_column("Worker", style="accent")
38
+ table.add_column("State")
39
+ table.add_column("Completed", justify="right")
40
+ table.add_column("Progress", ratio=1)
41
+
42
+ for worker in workers:
43
+ if worker.state == "DONE":
44
+ state = "[success]DONE[/success]"
45
+ else:
46
+ state = "[warning]RUNNING[/warning]"
47
+ table.add_row(
48
+ worker.name,
49
+ state,
50
+ f"{worker.completed}/{worker.total}",
51
+ f"{worker.completed / worker.total:.0%}",
52
+ )
53
+ return table
54
+
55
+
56
+ def main() -> int:
57
+ parser = argparse.ArgumentParser(description="Demonstrate a Rich live dashboard.")
58
+ parser.add_argument("--seconds", type=float, default=4.0)
59
+ args = parser.parse_args()
60
+
61
+ console = Console(theme=THEME)
62
+ workers = [Worker("worker-01"), Worker("worker-02"), Worker("worker-03")]
63
+
64
+ if not console.is_terminal:
65
+ console.print("Live dashboard disabled: stdout is not an interactive terminal.")
66
+ return 0
67
+
68
+ deadline = time.monotonic() + max(0.2, args.seconds)
69
+ with Live(render(workers), console=console, refresh_per_second=4, screen=False) as live:
70
+ while time.monotonic() < deadline and any(w.completed < w.total for w in workers):
71
+ for worker in workers:
72
+ if worker.completed < worker.total and random.random() > 0.35:
73
+ worker.completed += 1
74
+ if worker.completed == worker.total:
75
+ worker.state = "DONE"
76
+ live.update(render(workers), refresh=True)
77
+ time.sleep(0.25)
78
+
79
+ console.print(render(workers))
80
+ console.print("[success]Dashboard stopped; final state retained.[/success]")
81
+ return 0
82
+
83
+
84
+ if __name__ == "__main__":
85
+ raise SystemExit(main())