From 6dcc1429077d390049c140c9388f4ff3ccb4211e Mon Sep 17 00:00:00 2001 From: David Shnayder Date: Tue, 3 Mar 2026 18:38:11 +0200 Subject: [PATCH 1/7] fix typo in csproj --- PrettyConsole/PrettyConsole.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PrettyConsole/PrettyConsole.csproj b/PrettyConsole/PrettyConsole.csproj index e5b135f..39ecfce 100755 --- a/PrettyConsole/PrettyConsole.csproj +++ b/PrettyConsole/PrettyConsole.csproj @@ -13,7 +13,7 @@ true true snupkg - true + true true David Shnayder From a442dd83d7de6cce2b6285cf9e18f13e2e5797c0 Mon Sep 17 00:00:00 2001 From: David Shnayder Date: Tue, 3 Mar 2026 20:40:02 +0200 Subject: [PATCH 2/7] Add agent skill for PrettyConsole expertise --- .agents/skills/prettyconsole-expert/SKILL.md | 76 +++++++++++ .../prettyconsole-expert/agents/openai.yaml | 4 + .../references/v5-api-map.md | 126 ++++++++++++++++++ AGENTS.md | 8 +- README.md | 57 +++++--- 5 files changed, 249 insertions(+), 22 deletions(-) create mode 100644 .agents/skills/prettyconsole-expert/SKILL.md create mode 100644 .agents/skills/prettyconsole-expert/agents/openai.yaml create mode 100644 .agents/skills/prettyconsole-expert/references/v5-api-map.md diff --git a/.agents/skills/prettyconsole-expert/SKILL.md b/.agents/skills/prettyconsole-expert/SKILL.md new file mode 100644 index 0000000..c41f541 --- /dev/null +++ b/.agents/skills/prettyconsole-expert/SKILL.md @@ -0,0 +1,76 @@ +--- +name: prettyconsole-expert +description: Expert workflow for using PrettyConsole correctly and efficiently in C# console apps. Use when tasks involve console styling, colored output, regular prints, prompts, typed input parsing, confirmation prompts, menu/table rendering, overwrite-based rendering, progress bars, spinners, OutputPipe routing, or migration from Spectre.Console/manual ANSI/older PrettyConsole APIs. +--- + +# PrettyConsole Expert + +## Core Workflow + +1. Verify the installed PrettyConsole version before coding. +- Read `Directory.Packages.props`, `*.csproj`, and/or run `dotnet list package`. +- Keep implementation compatible with the installed version; do not "fix" compilation by downgrading unless the user explicitly requests downgrading. + +2. Bring extension APIs into scope: + +```csharp +using PrettyConsole; +using static System.Console; // optional +``` + +3. Choose APIs by intent. +- Styled output: `Console.WriteInterpolated`, `Console.WriteLineInterpolated`. +- Inputs/prompts: `Console.TryReadLine`, `Console.ReadLine`, `Console.Confirm`, `Console.RequestAnyInput`. +- Dynamic rendering: `Console.Overwrite`, `Console.ClearNextLines`, `Console.SkipLines`. +- Progress UI: `ProgressBar.Update`, `ProgressBar.Render`, `Spinner.RunAsync`. +- Menus/tables: `Console.Selection`, `Console.MultiSelection`, `Console.TreeMenu`, `Console.Table`. +- Low-level override only: use `Console.Write(...)` / `Console.WriteLine(...)` span+`ISpanFormattable` overloads only when you intentionally bypass the handler for a custom formatting pipeline. + +## Performance Rules + +- Prefer interpolated-handler APIs over manually concatenated strings. +- Avoid span/formattable `Write`/`WriteLine` overloads in normal app code; reserve them for rare advanced/manual formatting scenarios. +- Keep ANSI/decorations inside interpolation holes (for example, `$"{Markup.Bold}..."`) instead of literal escape codes inside string literals. +- Route transient UI (spinner/progress/overwrite loops) to `OutputPipe.Error` to keep stdout pipe-friendly. +- After the last overwrite/progress frame, clear the UI region once with `Console.ClearNextLines(totalLines, pipe)` or intentionally keep it with `Console.SkipLines`. + +## API Guardrails (Current Surface) + +- Use `Spinner`, not `IndeterminateProgressBar`. +- Use `Pattern`, not `AnimationSequence`. +- Use `ProgressBar.Render(...)`, not `ProgressBar.WriteProgressBar(...)`. +- Use `ConsoleContext`, not `PrettyConsoleExtensions`. +- Use `ConsoleColor` helpers/tuples (for example `ConsoleColor.Red / ConsoleColor.White`), not removed `ColoredOutput`/`Color` types. +- Use `Confirm(ReadOnlySpan trueValues, ref PrettyConsoleInterpolatedStringHandler handler, bool emptyIsTrue = true)` (boolean parameter is last). +- Use handler factory overloads for dynamic spinner/progress headers: + `(builder, out handler) => handler = builder.Build(OutputPipe.Error, $"...")`. + +## Fast Templates + +```csharp +// Colored/status output +Console.WriteLineInterpolated($"{ConsoleColor.Green / ConsoleColor.DefaultBackground}OK{ConsoleColor.Default}"); + +// Typed input +if (!Console.TryReadLine(out int port, $"Port ({ConsoleColor.Cyan}5000{ConsoleColor.Default}): ")) + port = 5000; + +// Confirm with custom truthy tokens +bool deploy = Console.Confirm(["y", "yes", "deploy"], $"Deploy now? ", emptyIsTrue: false); + +// Spinner +var spinner = new Spinner(); +await spinner.RunAsync(workTask, (builder, out handler) => + handler = builder.Build(OutputPipe.Error, $"Syncing...")); + +// Progress rendering +var bar = new ProgressBar { ProgressColor = ConsoleColor.Green }; +bar.Update(65, "Downloading", sameLine: true); +ProgressBar.Render(OutputPipe.Error, 65, ConsoleColor.Green); +``` + +## Reference File + +Read [references/v5-api-map.md](references/v5-api-map.md) when you need exact usage snippets, migration mapping from old APIs, or a compile-fix checklist. + +If public API usage changes in the edited project, ask whether to update `README.md` and changelog/release-notes files. diff --git a/.agents/skills/prettyconsole-expert/agents/openai.yaml b/.agents/skills/prettyconsole-expert/agents/openai.yaml new file mode 100644 index 0000000..98b4e8b --- /dev/null +++ b/.agents/skills/prettyconsole-expert/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "PrettyConsole Expert" + short_description: "Use PrettyConsole APIs correctly for fast console UIs" + default_prompt: "Implement PrettyConsole features with current APIs, migration-safe names, and allocation-conscious patterns." diff --git a/.agents/skills/prettyconsole-expert/references/v5-api-map.md b/.agents/skills/prettyconsole-expert/references/v5-api-map.md new file mode 100644 index 0000000..03b0020 --- /dev/null +++ b/.agents/skills/prettyconsole-expert/references/v5-api-map.md @@ -0,0 +1,126 @@ +# PrettyConsole v5 API Map + +Use this file when implementing or reviewing PrettyConsole usage so code compiles against modern APIs and keeps allocation-conscious patterns. + +## 1. Version First + +Read installed version before coding: + +```bash +dotnet list package +rg -n "PrettyConsole" --glob "*.csproj" . +# optionally also check central package management if present: +# rg -n "PrettyConsole" Directory.Packages.props +``` + +If version and request conflict, keep the installed version and adapt code accordingly. + +## 2. Namespace and Setup + +```csharp +using PrettyConsole; +using static System.Console; // optional +``` + +PrettyConsole methods are extension members on `System.Console`. + +## 3. Correct Modern APIs + +- Styled writes: + - `Console.WriteInterpolated(...)` + - `Console.WriteLineInterpolated(...)` +- Inputs: + - `Console.TryReadLine(...)` + - `Console.ReadLine(...)` + - `Console.Confirm(...)` + - `Console.RequestAnyInput(...)` +- Rendering: + - `Console.Overwrite(...)` + - `Console.ClearNextLines(...)` + - `Console.SkipLines(...)` +- Progress: + - `ProgressBar.Update(...)` + - `ProgressBar.Render(...)` + - `Spinner.RunAsync(...)` +- Menus/tables: + - `Console.Selection(...)` + - `Console.MultiSelection(...)` + - `Console.TreeMenu(...)` + - `Console.Table(...)` + +### Low-level escape hatch (rare) + +Use these only when intentionally bypassing the interpolated handler for a custom formatting pipeline: + +- `Console.Write(...) where T : ISpanFormattable` +- `Console.Write(ReadOnlySpan ...)` +- `Console.WriteLine(...)` + +## 4. Old -> New Migration Table + +- `IndeterminateProgressBar` -> `Spinner` +- `AnimationSequence` -> `Pattern` +- `ProgressBar.WriteProgressBar` -> `ProgressBar.Render` +- `PrettyConsoleExtensions` -> `ConsoleContext` +- Legacy `ColoredOutput`/`Color` types -> `ConsoleColor` helpers and tuples + +## 5. Compile-Safe Patterns + +### Styled output + +```csharp +Console.WriteInterpolated($"[{ConsoleColor.Cyan}info{ConsoleColor.Default}] {message}"); +Console.WriteLineInterpolated(OutputPipe.Error, $"{ConsoleColor.Yellow}warn{ConsoleColor.Default}"); +``` + +### Typed input + +```csharp +if (!Console.TryReadLine(out int port, $"Port ({ConsoleColor.Green}5000{ConsoleColor.Default}): ")) + port = 5000; +``` + +### Confirmation + +```csharp +bool yes = Console.Confirm(["y", "yes"], $"Continue? ", emptyIsTrue: false); +``` + +### Spinner with dynamic header + +```csharp +var spinner = new Spinner(); +await spinner.RunAsync(workTask, (builder, out handler) => + handler = builder.Build(OutputPipe.Error, $"Processing {DateTime.Now:T}")); +``` + +### Progress bar + +```csharp +var progress = new ProgressBar { + ProgressColor = ConsoleColor.Green, + ForegroundColor = ConsoleColor.DarkGray +}; + +progress.Update(40, "Downloading", sameLine: true); +ProgressBar.Render(OutputPipe.Error, 40, ConsoleColor.Green); +``` + +### Overwrite loop cleanup + +```csharp +Console.Overwrite(() => { + Console.WriteLineInterpolated(OutputPipe.Error, $"Running..."); + ProgressBar.Render(OutputPipe.Error, percent, ConsoleColor.Cyan); +}, lines: 2, pipe: OutputPipe.Error); + +Console.ClearNextLines(2, OutputPipe.Error); +``` + +## 6. Performance Checklist + +- Prefer interpolated handlers over string concatenation. +- Treat span/formattable `Write`/`WriteLine` overloads as advanced escape hatches, not default app-level APIs. +- Keep ANSI/decorations in interpolation holes, not raw literal spans. +- Use `OutputPipe.Error` for transient rendering. +- Avoid introducing wrapper abstractions when direct PrettyConsole APIs already solve the task. diff --git a/AGENTS.md b/AGENTS.md index d09488a..8c756ec 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,7 +10,7 @@ Summary - PrettyConsole.Tests/ — interactive/demo runner (manually selects visual feature demos) - PrettyConsole.Tests.Unit/ — xUnit v3 unit tests using Microsoft Testing Platform - Examples/ — standalone `.cs` sample apps plus `assets/` previews; documented in `Examples/README.md` and excluded from automated builds/tests -- v5.3.1 (current) renames `IndeterminateProgressBar` to `Spinner` (and `AnimationSequence` to `Pattern`), triggers the line reset at the start of each spinner frame, gives all `RunAsync` overloads default cancellation tokens, and renames `ProgressBar.WriteProgressBar` to `Render` while adding handler-factory overloads and switching header parameters to `string`. It still passes handlers by `ref`, adds `AppendInline`, and introduces the ctor that takes only `OutputPipe` + optional `IFormatProvider`; `SkipLines` advances the cursor while keeping overwritten UIs; `Confirm(trueValues, ref handler, bool emptyIsTrue = true)` has the boolean last; spinner header factories use `PrettyConsoleInterpolatedStringHandlerFactory` with the singleton builder; `AnsiColors` is public. v5.2.0 rewrote the handler to buffer before writing and added `WhiteSpace`; v5.1.0 renamed `PrettyConsoleExtensions` to `ConsoleContext`, added `Console.WriteWhiteSpaces(length, pipe)`, and made `Out`/`Error`/`In` settable; v5.0.0 removed the legacy `ColoredOutput`/`Color` types in favor of `ConsoleColor` helpers and tuples. +- v5.4.0 (current) renames `IndeterminateProgressBar` to `Spinner` (and `AnimationSequence` to `Pattern`), triggers the line reset at the start of each spinner frame, gives all `RunAsync` overloads default cancellation tokens, and renames `ProgressBar.WriteProgressBar` to `Render` while adding handler-factory overloads and switching header parameters to `string`. It still passes handlers by `ref`, adds `AppendInline`, and introduces the ctor that takes only `OutputPipe` + optional `IFormatProvider`; `SkipLines` advances the cursor while keeping overwritten UIs; `Confirm(trueValues, ref handler, bool emptyIsTrue = true)` has the boolean last; spinner header factories use `PrettyConsoleInterpolatedStringHandlerFactory` with the singleton builder; `AnsiColors` is public. v5.2.0 rewrote the handler to buffer before writing and added `WhiteSpace`; v5.1.0 renamed `PrettyConsoleExtensions` to `ConsoleContext`, added `Console.WriteWhiteSpaces(length, pipe)`, and made `Out`/`Error`/`In` settable; v5.0.0 removed the legacy `ColoredOutput`/`Color` types in favor of `ConsoleColor` helpers and tuples. Commands you’ll use often @@ -56,9 +56,9 @@ High-level architecture and key concepts - Markup decorations - The `Markup` static class exposes ANSI sequences for underline, bold, italic, and strikethrough. Fields expand to escape codes only when output/error aren’t redirected; otherwise they collapse to empty strings so callers can safely interpolate them without extra checks. - Write APIs - - `WriteInterpolated`/`WriteLineInterpolated` host the interpolated-string handler; `Write`/`WriteLine` overloads target `ISpanFormattable` values (including `ref struct`s) and raw `ReadOnlySpan` spans with optional foreground/background overrides. Implementations rent buffers from `ArrayPool.Shared` to avoid allocation spikes and always reset colors. + - `WriteInterpolated`/`WriteLineInterpolated` are the default output APIs and host the interpolated-string handler; this path already covers high-performance formatting and coloring. Keep `Write`/`WriteLine` overloads (`ISpanFormattable`/`ReadOnlySpan`) for rare low-level scenarios where callers intentionally bypass the handler with custom formatting pipelines. Those overloads still rent buffers from `ArrayPool.Shared` and reset colors. - TextWriter helpers - - `ConsoleContext` surfaces the live `Out`/`Error` writers (now with public setters for test doubles) and keeps helpers like `GetWidthOrDefault`. Use `Console.WriteWhiteSpaces(int length, OutputPipe pipe = OutputPipe.Out)` for direct padding from call sites; `TextWriter.WriteWhiteSpaces(int)` remains available on the writers if you already have them on hand. + - `ConsoleContext` surfaces the live `Out`/`Error` writers (now with public setters for test doubles) and keeps helpers like `GetWidthOrDefault`. Use `Console.WriteWhiteSpaces(int length)` for the default output path and specify `OutputPipe.Error` only when needed; `TextWriter.WriteWhiteSpaces(int)` remains available on the writers if you already have them on hand. - Inputs - `ReadLine`/`TryReadLine` support `IParsable` types, optional defaults, enum parsing with `ignoreCase`, and interpolated prompts. `Confirm` exposes `DefaultConfirmValues`, overloads for custom truthy tokens, and interpolated prompts; `RequestAnyInput` blocks on `ReadKey` with colored prompts if desired. - Rendering controls @@ -83,7 +83,7 @@ Testing structure and workflows Notes and gotchas -- The library aims to minimize allocations; prefer span-based overloads (`ReadOnlySpan`, `ISpanFormattable`) plus the inline `ConsoleColor` tuples instead of recreating strings or structs. +- The library aims to minimize allocations; for normal app-level output prefer interpolated-handler APIs (`WriteInterpolated`/`WriteLineInterpolated`) plus inline `ConsoleColor` tuples. Use span-based `Write`/`WriteLine` overloads only for rare low-level formatting bypass scenarios. - When authoring new features, pick the appropriate OutputPipe to keep CLI piping behavior intact. - On macOS terminals, ANSI is supported; Windows legacy terminals are handled via ANSI-compatible rendering in the library. - `ProgressBar.Update` re-renders on every call (even when the percentage is unchanged) and accepts `sameLine` to place the status above the bar; the static `ProgressBar.Render` renders one-off bars without writing a trailing newline, so rely on `Console.Overwrite`/`lines` to stack multiple bars cleanly. diff --git a/README.md b/README.md index 44a5909..b7a6f45 100755 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ PrettyConsole is a high-performance, ultra-low-latency, allocation-free extensio - 🔁 Advanced rendering primitives (`Overwrite`, `ClearNextLines`, `GoToLine`, `SkipLines`, progress bars) that respect console pipes - 🧱 Handler-aware `WhiteSpace` struct for zero-allocation padding directly inside interpolated strings - 🧰 Rich input helpers (`TryReadLine`, `Confirm`, `RequestAnyInput`) with `IParsable` and enum support -- ⚙️ Allocation-conscious span-first APIs (`ISpanFormattable`, `ReadOnlySpan`, `Console.WriteWhiteSpaces` / `TextWriter.WriteWhiteSpaces`) -- ⛓ Output routing through `OutputPipe.Out` and `OutputPipe.Error` so piping/redirects continue to work +- ⚙️ Low-level output escape hatches (`Console.Write/WriteLine` span and `ISpanFormattable` overloads) for advanced custom formatting pipelines +- ⛓ Output routing through `OutputPipe.Out` (default) and `OutputPipe.Error` so piping/redirects continue to work ## Performance @@ -35,6 +35,18 @@ PrettyConsole is **the go-to choice for ultra-low-latency, allocation-free conso dotnet add package PrettyConsole ``` +## Agent Skill + +If you use coding agents, install the bundled `prettyconsole-expert` skill into your project so agents immediately use valid, current PrettyConsole APIs: + +```bash +mkdir -p .agents/skills +curl -Ls https://codeload.github.com/dusrdev/PrettyConsole/tar.gz/refs/heads/stable \ + | tar -xz -C .agents/skills --strip-components=3 PrettyConsole-stable/.agents/skills/prettyconsole-expert +``` + +This extracts `.agents/skills/prettyconsole-expert` from the repository archive directly into your local `.agents/skills` folder. + ## Examples Standalone samples made with .NET 10 file-based apps with preview clips are available in [Examples](Examples/README.md). @@ -120,17 +132,26 @@ Avoid embedding the escape directly in the literal (`"\u001b[38;5;213maccent tex // Interpolated text Console.WriteInterpolated($"Processed {items} items in {elapsed:duration}"); // Processed 42 items in 3h 44m 9s Console.WriteLineInterpolated(OutputPipe.Error, $"{ConsoleColor.Magenta}debug{ConsoleColor.Default}"); +``` + +`WriteInterpolated` / `WriteLineInterpolated` should be your default output path. The handler already applies the high-performance formatting path internally and supports inline colors/alignment/specifiers. + +### Low-level output escape hatch (rare) +Use these only when you intentionally bypass the interpolated handler and own formatting end-to-end (advanced/manual pipelines): + +```csharp // Span + color overloads (no boxing) ReadOnlySpan header = "Title"; -Console.Write(header, OutputPipe.Out, ConsoleColor.White, ConsoleColor.DarkBlue); -Console.NewLine(); // writes newline to the default output pipe +Console.Write(header, OutputPipe.Error, ConsoleColor.White, ConsoleColor.DarkBlue); +Console.NewLine(OutputPipe.Error); // ISpanFormattable (works with ref structs) -Console.Write(percentage, OutputPipe.Out, ConsoleColor.Cyan, ConsoleColor.DefaultBackground, format: "F2", formatProvider: null); +Console.Write(percentage); // uses the default output pipe +Console.Write(percentage, OutputPipe.Error, ConsoleColor.Cyan, ConsoleColor.DefaultBackground, format: "F2", formatProvider: null); ``` -Behind the scenes these overloads rent buffers from the shared `ArrayPool` and route output to the correct pipe through `ConsoleContext.GetWriter`. +These overloads stay public mainly for compatibility and niche scenarios; for normal app code, prefer interpolated handler calls. ### Basic inputs @@ -158,7 +179,7 @@ if (!Console.Confirm($"Deploy to production? ({ConsoleColor.Green}y{ConsoleColor return; } -var customTruths = new[] { "sure", "do it" }; +string[] customTruths = ["sure", "do it"]; bool overwrite = Console.Confirm(customTruths, $"Overwrite existing files? ", emptyIsTrue: false); ``` @@ -203,19 +224,19 @@ Always call `Console.ClearNextLines(totalLines, pipe)` once after the last `Over ### Menus and tables ```csharp -var choice = Console.Selection("Pick an environment:", new[] { "Dev", "QA", "Prod" }); -var multi = Console.MultiSelection("Services to restart:", new[] { "API", "Worker", "Scheduler" }); +var choice = Console.Selection("Pick an environment:", ["Dev", "QA", "Prod"]); +var multi = Console.MultiSelection("Services to restart:", ["API", "Worker", "Scheduler"]); var (area, action) = Console.TreeMenu("Actions", new Dictionary> { - ["Users"] = new[] { "List", "Create", "Disable" }, - ["Jobs"] = new[] { "Queue", "Retry" } + ["Users"] = ["List", "Create", "Disable"], + ["Jobs"] = ["Queue", "Retry"] }); Console.Table( - headers: new[] { "Name", "Status" }, - columns: new[] { - new[] { "API", "Worker" }, - new[] { "Running", "Stopped" } - } + headers: ["Name", "Status"], + columns: [ + ["API", "Worker"], + ["Running", "Stopped"] + ] ); ``` @@ -224,7 +245,7 @@ Menus validate user input (throwing `ArgumentException` on invalid selections) a ### Progress bars ```csharp -using var progress = new ProgressBar { +var progress = new ProgressBar { ProgressChar = '■', ForegroundColor = ConsoleColor.DarkGray, ProgressColor = ConsoleColor.Green, @@ -262,7 +283,7 @@ The factory runs each frame so you can inject dynamic status text without alloca using System.Linq; using System.Threading.Channels; -var downloads = new[] { "Video.mp4", "Archive.zip", "Assets.pak" }; +string[] downloads = ["Video.mp4", "Archive.zip", "Assets.pak"]; var progress = new double[downloads.Length]; var updates = Channel.CreateUnbounded<(int index, double percent)>(); From 1a71548e454bcef9d7bf7bfb29c4f1a00e25c55e Mon Sep 17 00:00:00 2001 From: David Shnayder Date: Tue, 3 Mar 2026 22:02:52 +0200 Subject: [PATCH 3/7] Add notes about special formats --- .agents/skills/prettyconsole-expert/SKILL.md | 8 ++++++++ .../skills/prettyconsole-expert/references/v5-api-map.md | 9 +++++++++ PrettyConsole/PrettyConsoleInterpolatedStringHandler.cs | 1 - 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.agents/skills/prettyconsole-expert/SKILL.md b/.agents/skills/prettyconsole-expert/SKILL.md index c41f541..f4024d6 100644 --- a/.agents/skills/prettyconsole-expert/SKILL.md +++ b/.agents/skills/prettyconsole-expert/SKILL.md @@ -26,6 +26,14 @@ using static System.Console; // optional - Menus/tables: `Console.Selection`, `Console.MultiSelection`, `Console.TreeMenu`, `Console.Table`. - Low-level override only: use `Console.Write(...)` / `Console.WriteLine(...)` span+`ISpanFormattable` overloads only when you intentionally bypass the handler for a custom formatting pipeline. +## Handler Special Formats + +- Use `:duration` with `TimeSpan` to render compact elapsed time text from the handler: + `Console.WriteInterpolated($"Elapsed {elapsed:duration}")` -> `Elapsed 12h 5m 33s` +- Use `:bytes` with `double` to render human-readable file sizes from the handler: + `Console.WriteInterpolated($"Transferred {bytes:bytes}")` -> `Transferred 12.3 MB` +- Prefer these formats in status/progress output instead of manual formatting logic. + ## Performance Rules - Prefer interpolated-handler APIs over manually concatenated strings. diff --git a/.agents/skills/prettyconsole-expert/references/v5-api-map.md b/.agents/skills/prettyconsole-expert/references/v5-api-map.md index 03b0020..b448639 100644 --- a/.agents/skills/prettyconsole-expert/references/v5-api-map.md +++ b/.agents/skills/prettyconsole-expert/references/v5-api-map.md @@ -48,6 +48,15 @@ PrettyConsole methods are extension members on `System.Console`. - `Console.TreeMenu(...)` - `Console.Table(...)` +### Interpolated-handler special formats + +- `TimeSpan` with `:duration`: + - `Console.WriteInterpolated($"Elapsed {elapsed:duration}")` + - Example output: `Elapsed 5h 32m 12s` +- `double` with `:bytes`: + - `Console.WriteInterpolated($"Downloaded {size:bytes}")` + - Example output: `Downloaded 12.3 MB` + ### Low-level escape hatch (rare) Use these only when intentionally bypassing the interpolated handler for a custom formatting pipeline: diff --git a/PrettyConsole/PrettyConsoleInterpolatedStringHandler.cs b/PrettyConsole/PrettyConsoleInterpolatedStringHandler.cs index cd59cb4..6c32090 100644 --- a/PrettyConsole/PrettyConsoleInterpolatedStringHandler.cs +++ b/PrettyConsole/PrettyConsoleInterpolatedStringHandler.cs @@ -311,7 +311,6 @@ private void AppendSpanFormattable(T value, int alignment, string? format) ReadOnlySpan formatSpan = format.AsSpan(); int charsWritten; - // int start = _index; while (true) { Span dest = _buffer.AsSpan(_index); From d1aa2c91b777ea19f32df05dd365bcd7ae1952fd Mon Sep 17 00:00:00 2001 From: David Shnayder Date: Tue, 3 Mar 2026 22:10:54 +0200 Subject: [PATCH 4/7] Apply versioning to the skill --- .agents/skills/prettyconsole-expert/SKILL.md | 20 ++++++++++++++--- .agents/skills/prettyconsole-expert/VERSION | 1 + .../prettyconsole-expert/agents/openai.yaml | 2 +- .../references/v5-api-map.md | 22 ++++++++++++++++--- AGENTS.md | 1 + README.md | 9 ++++++++ 6 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 .agents/skills/prettyconsole-expert/VERSION diff --git a/.agents/skills/prettyconsole-expert/SKILL.md b/.agents/skills/prettyconsole-expert/SKILL.md index f4024d6..05b6a11 100644 --- a/.agents/skills/prettyconsole-expert/SKILL.md +++ b/.agents/skills/prettyconsole-expert/SKILL.md @@ -5,11 +5,25 @@ description: Expert workflow for using PrettyConsole correctly and efficiently i # PrettyConsole Expert +## Skill Version + +- Skill version: `5.4.0` (stored in `.agents/skills/prettyconsole-expert/VERSION`). +- The skill version must match the installed `PrettyConsole` package version before implementing code changes. + ## Core Workflow -1. Verify the installed PrettyConsole version before coding. -- Read `Directory.Packages.props`, `*.csproj`, and/or run `dotnet list package`. -- Keep implementation compatible with the installed version; do not "fix" compilation by downgrading unless the user explicitly requests downgrading. +1. Run a version-sync preflight before coding. +- Read the skill version from `.agents/skills/prettyconsole-expert/VERSION`. +- Read the installed package version via `dotnet list package | rg PrettyConsole`. +- If `PrettyConsole` is not installed, install the skill version (`dotnet add package PrettyConsole --version `). +- If package version is newer than skill version, refresh the skill from GitHub: + ```bash + mkdir -p .agents/skills + curl -Ls https://codeload.github.com/dusrdev/PrettyConsole/tar.gz/refs/heads/stable \ + | tar -xz -C .agents/skills --strip-components=3 PrettyConsole-stable/.agents/skills/prettyconsole-expert + ``` +- If skill version is newer than package version, check availability with `dotnet list package --outdated | rg PrettyConsole` and upgrade the package when available (`dotnet add package PrettyConsole`). +- Continue only after versions match, or after the user explicitly confirms an intentional mismatch. 2. Bring extension APIs into scope: diff --git a/.agents/skills/prettyconsole-expert/VERSION b/.agents/skills/prettyconsole-expert/VERSION new file mode 100644 index 0000000..8a30e8f --- /dev/null +++ b/.agents/skills/prettyconsole-expert/VERSION @@ -0,0 +1 @@ +5.4.0 diff --git a/.agents/skills/prettyconsole-expert/agents/openai.yaml b/.agents/skills/prettyconsole-expert/agents/openai.yaml index 98b4e8b..eba62bf 100644 --- a/.agents/skills/prettyconsole-expert/agents/openai.yaml +++ b/.agents/skills/prettyconsole-expert/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "PrettyConsole Expert" short_description: "Use PrettyConsole APIs correctly for fast console UIs" - default_prompt: "Implement PrettyConsole features with current APIs, migration-safe names, and allocation-conscious patterns." + default_prompt: "Start by syncing skill version with installed PrettyConsole package version, then implement with current APIs and allocation-conscious patterns." diff --git a/.agents/skills/prettyconsole-expert/references/v5-api-map.md b/.agents/skills/prettyconsole-expert/references/v5-api-map.md index b448639..9ab2d63 100644 --- a/.agents/skills/prettyconsole-expert/references/v5-api-map.md +++ b/.agents/skills/prettyconsole-expert/references/v5-api-map.md @@ -2,18 +2,34 @@ Use this file when implementing or reviewing PrettyConsole usage so code compiles against modern APIs and keeps allocation-conscious patterns. -## 1. Version First +## 1. Version Sync (Required) -Read installed version before coding: +Compare skill and package versions before coding: ```bash +cat .agents/skills/prettyconsole-expert/VERSION dotnet list package rg -n "PrettyConsole" --glob "*.csproj" . # optionally also check central package management if present: # rg -n "PrettyConsole" Directory.Packages.props ``` -If version and request conflict, keep the installed version and adapt code accordingly. +Resolve mismatches before implementation: + +- If package is missing, install `PrettyConsole` using the skill version. +- If package version > skill version, update the skill folder from GitHub: + ```bash + mkdir -p .agents/skills + curl -Ls https://codeload.github.com/dusrdev/PrettyConsole/tar.gz/refs/heads/stable \ + | tar -xz -C .agents/skills --strip-components=3 PrettyConsole-stable/.agents/skills/prettyconsole-expert + ``` +- If skill version > package version, check upgrade availability: + ```bash + dotnet list package --outdated | rg PrettyConsole + dotnet add package PrettyConsole + ``` + Upgrade package when available. +- Proceed only when skill and package versions match, or when the user explicitly accepts a mismatch. ## 2. Namespace and Setup diff --git a/AGENTS.md b/AGENTS.md index 8c756ec..a92fe8e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,6 +11,7 @@ Summary - PrettyConsole.Tests.Unit/ — xUnit v3 unit tests using Microsoft Testing Platform - Examples/ — standalone `.cs` sample apps plus `assets/` previews; documented in `Examples/README.md` and excluded from automated builds/tests - v5.4.0 (current) renames `IndeterminateProgressBar` to `Spinner` (and `AnimationSequence` to `Pattern`), triggers the line reset at the start of each spinner frame, gives all `RunAsync` overloads default cancellation tokens, and renames `ProgressBar.WriteProgressBar` to `Render` while adding handler-factory overloads and switching header parameters to `string`. It still passes handlers by `ref`, adds `AppendInline`, and introduces the ctor that takes only `OutputPipe` + optional `IFormatProvider`; `SkipLines` advances the cursor while keeping overwritten UIs; `Confirm(trueValues, ref handler, bool emptyIsTrue = true)` has the boolean last; spinner header factories use `PrettyConsoleInterpolatedStringHandlerFactory` with the singleton builder; `AnsiColors` is public. v5.2.0 rewrote the handler to buffer before writing and added `WhiteSpace`; v5.1.0 renamed `PrettyConsoleExtensions` to `ConsoleContext`, added `Console.WriteWhiteSpaces(length, pipe)`, and made `Out`/`Error`/`In` settable; v5.0.0 removed the legacy `ColoredOutput`/`Color` types in favor of `ConsoleColor` helpers and tuples. +- The agent skill `.agents/skills/prettyconsole-expert` is versioned by `.agents/skills/prettyconsole-expert/VERSION` and should match `PrettyConsole` package version; when package version changes, update skill versioning/docs in lockstep. Commands you’ll use often diff --git a/README.md b/README.md index b7a6f45..6f7c32b 100755 --- a/README.md +++ b/README.md @@ -47,6 +47,15 @@ curl -Ls https://codeload.github.com/dusrdev/PrettyConsole/tar.gz/refs/heads/sta This extracts `.agents/skills/prettyconsole-expert` from the repository archive directly into your local `.agents/skills` folder. +The skill is versioned via `.agents/skills/prettyconsole-expert/VERSION` (current: `5.4.0`) and should match your installed `PrettyConsole` package version. Before using the skill: + +```bash +cat .agents/skills/prettyconsole-expert/VERSION +dotnet list package | rg PrettyConsole +``` + +If versions differ, upgrade the package when available (`dotnet list package --outdated | rg PrettyConsole`) or refresh the skill folder from GitHub. + ## Examples Standalone samples made with .NET 10 file-based apps with preview clips are available in [Examples](Examples/README.md). From 3ffd263bc86fdadf5f77db4e942daf41df6429ff Mon Sep 17 00:00:00 2001 From: David Shnayder Date: Fri, 6 Mar 2026 19:39:09 +0200 Subject: [PATCH 5/7] Remove versioning --- .agents/skills/prettyconsole-expert/SKILL.md | 20 +++-------------- .agents/skills/prettyconsole-expert/VERSION | 1 - .../prettyconsole-expert/agents/openai.yaml | 2 +- .../references/v5-api-map.md | 22 +++---------------- AGENTS.md | 1 - README.md | 21 ------------------ 6 files changed, 7 insertions(+), 60 deletions(-) delete mode 100644 .agents/skills/prettyconsole-expert/VERSION diff --git a/.agents/skills/prettyconsole-expert/SKILL.md b/.agents/skills/prettyconsole-expert/SKILL.md index 05b6a11..f4024d6 100644 --- a/.agents/skills/prettyconsole-expert/SKILL.md +++ b/.agents/skills/prettyconsole-expert/SKILL.md @@ -5,25 +5,11 @@ description: Expert workflow for using PrettyConsole correctly and efficiently i # PrettyConsole Expert -## Skill Version - -- Skill version: `5.4.0` (stored in `.agents/skills/prettyconsole-expert/VERSION`). -- The skill version must match the installed `PrettyConsole` package version before implementing code changes. - ## Core Workflow -1. Run a version-sync preflight before coding. -- Read the skill version from `.agents/skills/prettyconsole-expert/VERSION`. -- Read the installed package version via `dotnet list package | rg PrettyConsole`. -- If `PrettyConsole` is not installed, install the skill version (`dotnet add package PrettyConsole --version `). -- If package version is newer than skill version, refresh the skill from GitHub: - ```bash - mkdir -p .agents/skills - curl -Ls https://codeload.github.com/dusrdev/PrettyConsole/tar.gz/refs/heads/stable \ - | tar -xz -C .agents/skills --strip-components=3 PrettyConsole-stable/.agents/skills/prettyconsole-expert - ``` -- If skill version is newer than package version, check availability with `dotnet list package --outdated | rg PrettyConsole` and upgrade the package when available (`dotnet add package PrettyConsole`). -- Continue only after versions match, or after the user explicitly confirms an intentional mismatch. +1. Verify the installed PrettyConsole version before coding. +- Read `Directory.Packages.props`, `*.csproj`, and/or run `dotnet list package`. +- Keep implementation compatible with the installed version; do not "fix" compilation by downgrading unless the user explicitly requests downgrading. 2. Bring extension APIs into scope: diff --git a/.agents/skills/prettyconsole-expert/VERSION b/.agents/skills/prettyconsole-expert/VERSION deleted file mode 100644 index 8a30e8f..0000000 --- a/.agents/skills/prettyconsole-expert/VERSION +++ /dev/null @@ -1 +0,0 @@ -5.4.0 diff --git a/.agents/skills/prettyconsole-expert/agents/openai.yaml b/.agents/skills/prettyconsole-expert/agents/openai.yaml index eba62bf..98b4e8b 100644 --- a/.agents/skills/prettyconsole-expert/agents/openai.yaml +++ b/.agents/skills/prettyconsole-expert/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "PrettyConsole Expert" short_description: "Use PrettyConsole APIs correctly for fast console UIs" - default_prompt: "Start by syncing skill version with installed PrettyConsole package version, then implement with current APIs and allocation-conscious patterns." + default_prompt: "Implement PrettyConsole features with current APIs, migration-safe names, and allocation-conscious patterns." diff --git a/.agents/skills/prettyconsole-expert/references/v5-api-map.md b/.agents/skills/prettyconsole-expert/references/v5-api-map.md index 9ab2d63..b448639 100644 --- a/.agents/skills/prettyconsole-expert/references/v5-api-map.md +++ b/.agents/skills/prettyconsole-expert/references/v5-api-map.md @@ -2,34 +2,18 @@ Use this file when implementing or reviewing PrettyConsole usage so code compiles against modern APIs and keeps allocation-conscious patterns. -## 1. Version Sync (Required) +## 1. Version First -Compare skill and package versions before coding: +Read installed version before coding: ```bash -cat .agents/skills/prettyconsole-expert/VERSION dotnet list package rg -n "PrettyConsole" --glob "*.csproj" . # optionally also check central package management if present: # rg -n "PrettyConsole" Directory.Packages.props ``` -Resolve mismatches before implementation: - -- If package is missing, install `PrettyConsole` using the skill version. -- If package version > skill version, update the skill folder from GitHub: - ```bash - mkdir -p .agents/skills - curl -Ls https://codeload.github.com/dusrdev/PrettyConsole/tar.gz/refs/heads/stable \ - | tar -xz -C .agents/skills --strip-components=3 PrettyConsole-stable/.agents/skills/prettyconsole-expert - ``` -- If skill version > package version, check upgrade availability: - ```bash - dotnet list package --outdated | rg PrettyConsole - dotnet add package PrettyConsole - ``` - Upgrade package when available. -- Proceed only when skill and package versions match, or when the user explicitly accepts a mismatch. +If version and request conflict, keep the installed version and adapt code accordingly. ## 2. Namespace and Setup diff --git a/AGENTS.md b/AGENTS.md index a92fe8e..8c756ec 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,7 +11,6 @@ Summary - PrettyConsole.Tests.Unit/ — xUnit v3 unit tests using Microsoft Testing Platform - Examples/ — standalone `.cs` sample apps plus `assets/` previews; documented in `Examples/README.md` and excluded from automated builds/tests - v5.4.0 (current) renames `IndeterminateProgressBar` to `Spinner` (and `AnimationSequence` to `Pattern`), triggers the line reset at the start of each spinner frame, gives all `RunAsync` overloads default cancellation tokens, and renames `ProgressBar.WriteProgressBar` to `Render` while adding handler-factory overloads and switching header parameters to `string`. It still passes handlers by `ref`, adds `AppendInline`, and introduces the ctor that takes only `OutputPipe` + optional `IFormatProvider`; `SkipLines` advances the cursor while keeping overwritten UIs; `Confirm(trueValues, ref handler, bool emptyIsTrue = true)` has the boolean last; spinner header factories use `PrettyConsoleInterpolatedStringHandlerFactory` with the singleton builder; `AnsiColors` is public. v5.2.0 rewrote the handler to buffer before writing and added `WhiteSpace`; v5.1.0 renamed `PrettyConsoleExtensions` to `ConsoleContext`, added `Console.WriteWhiteSpaces(length, pipe)`, and made `Out`/`Error`/`In` settable; v5.0.0 removed the legacy `ColoredOutput`/`Color` types in favor of `ConsoleColor` helpers and tuples. -- The agent skill `.agents/skills/prettyconsole-expert` is versioned by `.agents/skills/prettyconsole-expert/VERSION` and should match `PrettyConsole` package version; when package version changes, update skill versioning/docs in lockstep. Commands you’ll use often diff --git a/README.md b/README.md index 6f7c32b..f96e80a 100755 --- a/README.md +++ b/README.md @@ -35,27 +35,6 @@ PrettyConsole is **the go-to choice for ultra-low-latency, allocation-free conso dotnet add package PrettyConsole ``` -## Agent Skill - -If you use coding agents, install the bundled `prettyconsole-expert` skill into your project so agents immediately use valid, current PrettyConsole APIs: - -```bash -mkdir -p .agents/skills -curl -Ls https://codeload.github.com/dusrdev/PrettyConsole/tar.gz/refs/heads/stable \ - | tar -xz -C .agents/skills --strip-components=3 PrettyConsole-stable/.agents/skills/prettyconsole-expert -``` - -This extracts `.agents/skills/prettyconsole-expert` from the repository archive directly into your local `.agents/skills` folder. - -The skill is versioned via `.agents/skills/prettyconsole-expert/VERSION` (current: `5.4.0`) and should match your installed `PrettyConsole` package version. Before using the skill: - -```bash -cat .agents/skills/prettyconsole-expert/VERSION -dotnet list package | rg PrettyConsole -``` - -If versions differ, upgrade the package when available (`dotnet list package --outdated | rg PrettyConsole`) or refresh the skill folder from GitHub. - ## Examples Standalone samples made with .NET 10 file-based apps with preview clips are available in [Examples](Examples/README.md). From 7602186d87bacdc10d562cb9a35722cac821ac86 Mon Sep 17 00:00:00 2001 From: David Shnayder Date: Sat, 7 Mar 2026 17:00:26 +0200 Subject: [PATCH 6/7] Add Payload and improve skill --- .../SKILL.md | 9 +- .../agents/openai.yaml | 0 .../references/v5-api-map.md | 87 ++++++++++++++++--- PrettyConsole/PrettyConsole.csproj | 12 ++- README.md | 23 +++++ 5 files changed, 117 insertions(+), 14 deletions(-) rename .agents/skills/{prettyconsole-expert => pretty-console-expert}/SKILL.md (82%) rename .agents/skills/{prettyconsole-expert => pretty-console-expert}/agents/openai.yaml (100%) rename .agents/skills/{prettyconsole-expert => pretty-console-expert}/references/v5-api-map.md (53%) diff --git a/.agents/skills/prettyconsole-expert/SKILL.md b/.agents/skills/pretty-console-expert/SKILL.md similarity index 82% rename from .agents/skills/prettyconsole-expert/SKILL.md rename to .agents/skills/pretty-console-expert/SKILL.md index f4024d6..d3bedbb 100644 --- a/.agents/skills/prettyconsole-expert/SKILL.md +++ b/.agents/skills/pretty-console-expert/SKILL.md @@ -1,5 +1,5 @@ --- -name: prettyconsole-expert +name: pretty-console-expert description: Expert workflow for using PrettyConsole correctly and efficiently in C# console apps. Use when tasks involve console styling, colored output, regular prints, prompts, typed input parsing, confirmation prompts, menu/table rendering, overwrite-based rendering, progress bars, spinners, OutputPipe routing, or migration from Spectre.Console/manual ANSI/older PrettyConsole APIs. --- @@ -40,8 +40,15 @@ using static System.Console; // optional - Avoid span/formattable `Write`/`WriteLine` overloads in normal app code; reserve them for rare advanced/manual formatting scenarios. - Keep ANSI/decorations inside interpolation holes (for example, `$"{Markup.Bold}..."`) instead of literal escape codes inside string literals. - Route transient UI (spinner/progress/overwrite loops) to `OutputPipe.Error` to keep stdout pipe-friendly. +- For very frequent concurrent status updates, prefer a single-reader bounded `Channel` that owns `Console.Overwrite(...)`; let workers `TryWrite` snapshots into a capacity-1 channel with `FullMode = DropWrite` so producers stay non-blocking and intermediate frames can be skipped. - After the last overwrite/progress frame, clear the UI region once with `Console.ClearNextLines(totalLines, pipe)` or intentionally keep it with `Console.SkipLines`. +## Practical Patterns + +- For wizard-like flows, wrap `Console.Selection(...)` / `Console.MultiSelection(...)` in retrying `Console.Overwrite(...)` loops so each step reuses one screen region instead of scrolling. +- Prefer `Console.Overwrite(state, static ...)` for fixed-height live regions such as `status + progress`; it avoids closure captures and keeps the rendered surface explicit through `lines`. +- For dynamic spinner headers tied to concurrent work, keep the mutable step/progress state outside the spinner and read it with `Volatile.Read` / `Interlocked` inside the handler factory. + ## API Guardrails (Current Surface) - Use `Spinner`, not `IndeterminateProgressBar`. diff --git a/.agents/skills/prettyconsole-expert/agents/openai.yaml b/.agents/skills/pretty-console-expert/agents/openai.yaml similarity index 100% rename from .agents/skills/prettyconsole-expert/agents/openai.yaml rename to .agents/skills/pretty-console-expert/agents/openai.yaml diff --git a/.agents/skills/prettyconsole-expert/references/v5-api-map.md b/.agents/skills/pretty-console-expert/references/v5-api-map.md similarity index 53% rename from .agents/skills/prettyconsole-expert/references/v5-api-map.md rename to .agents/skills/pretty-console-expert/references/v5-api-map.md index b448639..8b73b5b 100644 --- a/.agents/skills/prettyconsole-expert/references/v5-api-map.md +++ b/.agents/skills/pretty-console-expert/references/v5-api-map.md @@ -95,26 +95,58 @@ if (!Console.TryReadLine(out int port, $"Port ({ConsoleColor.Green}5000{ConsoleC bool yes = Console.Confirm(["y", "yes"], $"Continue? ", emptyIsTrue: false); ``` -### Spinner with dynamic header +### Wizard-style menus ```csharp -var spinner = new Spinner(); -await spinner.RunAsync(workTask, (builder, out handler) => - handler = builder.Build(OutputPipe.Error, $"Processing {DateTime.Now:T}")); +static string PromptSelection(string title, string[] options) { + string selection = string.Empty; + + while (selection.Length == 0) { + Console.Overwrite(() => { + selection = Console.Selection(options, $"{ConsoleColor.Cyan}{title}{ConsoleColor.DefaultForeground}:"); + if (selection.Length == 0) + Console.WriteLineInterpolated(OutputPipe.Error, $"{ConsoleColor.Red}Invalid choice."); + }, lines: options.Length + 3, pipe: OutputPipe.Out); + } + + return selection; +} ``` -### Progress bar +Use this when you want multi-step prompts to behave like page transitions instead of adding scrollback on each retry. + +### Spinner with shared progress state ```csharp -var progress = new ProgressBar { - ProgressColor = ConsoleColor.Green, - ForegroundColor = ConsoleColor.DarkGray -}; +string[] steps = ["Restore", "Compile", "Pack"]; +var step = 0; + +var workTask = Task.Run(async () => { + for (; step < steps.Length; Interlocked.Increment(ref step)) + await Task.Delay(500); +}); -progress.Update(40, "Downloading", sameLine: true); -ProgressBar.Render(OutputPipe.Error, 40, ConsoleColor.Green); +var spinner = new Spinner(); +await spinner.RunAsync(workTask, (builder, out handler) => { + var current = Math.Min(Volatile.Read(ref step), steps.Length - 1); + handler = builder.Build(OutputPipe.Error, $"Current step: {ConsoleColor.Green}{steps[current]}"); +}); +``` + +Use this when the spinner header should reflect concurrently changing state without locking around the render path. + +### Stateful overwrite rendering + +```csharp +Console.Overwrite(percent, static current => { + ProgressBar.Render(OutputPipe.Error, current, ConsoleColor.Cyan, maxLineWidth: 40); + Console.NewLine(OutputPipe.Error); + Console.WriteInterpolated(OutputPipe.Error, $"Downloading assets... {ConsoleColor.Cyan}{current}"); +}, lines: 2, pipe: OutputPipe.Error); ``` +Prefer this shape for live `status + progress` regions. It keeps the state explicit, avoids closure allocations, and makes the rendered height obvious. + ### Overwrite loop cleanup ```csharp @@ -126,6 +158,39 @@ Console.Overwrite(() => { Console.ClearNextLines(2, OutputPipe.Error); ``` +### High-frequency concurrent status updates + +Use one reader task to own all `Console.Overwrite(...)` calls and let concurrent workers publish snapshots through a bounded channel: + +```csharp +using System.Threading.Channels; + +var channel = Channel.CreateBounded(new BoundedChannelOptions(1) { + SingleWriter = false, + SingleReader = true, + FullMode = BoundedChannelFullMode.DropWrite +}); + +_ = Task.Run(async () => { + await foreach (var stats in channel.Reader.ReadAllAsync(cancellationToken).ConfigureAwait(false)) { + Console.Overwrite(stats, static current => { + PrintMetrics(current); + }, lines: 2, pipe: OutputPipe.Error); + } + + Console.ClearNextLines(2, OutputPipe.Error); +}, cancellationToken); + +// Workers stay non-blocking and may skip intermediate frames when the UI is busy. +channel.Writer.TryWrite(latestStats); +``` + +Why this works: + +- only one reader ever renders, so `Overwrite` calls do not race each other +- capacity `1` + `DropWrite` avoids backpressure on workers during high-frequency updates +- this pattern is best when dropped intermediate states are acceptable and only recent snapshots matter + ## 6. Performance Checklist - Prefer interpolated handlers over string concatenation. diff --git a/PrettyConsole/PrettyConsole.csproj b/PrettyConsole/PrettyConsole.csproj index 39ecfce..f86754f 100755 --- a/PrettyConsole/PrettyConsole.csproj +++ b/PrettyConsole/PrettyConsole.csproj @@ -26,7 +26,7 @@ https://github.com/dusrdev/PrettyConsole/ https://github.com/dusrdev/PrettyConsole/ git - 5.4.0 + 5.4.1-rc1 enable MIT True @@ -34,7 +34,7 @@ - + @@ -55,6 +55,14 @@ + + + + + + PrettyConsoleExpert + .agents/skills/pretty-console-expert + diff --git a/README.md b/README.md index f96e80a..ed1aff6 100755 --- a/README.md +++ b/README.md @@ -35,6 +35,29 @@ PrettyConsole is **the go-to choice for ultra-low-latency, allocation-free conso dotnet add package PrettyConsole ``` +## Included Skill + +`PrettyConsole` ships a universal skill named `pretty-console-expert`. The package uses `Payload` to copy it into the consuming repository during build at `.agents/skills/pretty-console-expert`, giving the repo its own PrettyConsole expert. + +Consumers can control that payload with `PayloadPolicy`: + +```xml + + + +``` + +- `CopyOnBuild="true"` is the default and keeps the skill synchronized on build. Set it to `false` to stop future copies. +- `OverridePath` is optional and changes the destination base path. The package-defined `TargetPath` stays `.agents/skills/pretty-console-expert`, so `OverridePath="/custom/root"` copies the skill to `/custom/root/.agents/skills/pretty-console-expert`. + +For .NET 10 file-based apps, if repo-root detection is not available, set `PayloadRootDirectory` explicitly: + +```csharp +#:property PayloadRootDirectory=. +``` + ## Examples Standalone samples made with .NET 10 file-based apps with preview clips are available in [Examples](Examples/README.md). From 217686c443991f5a4ca3891290591d8d5d95871a Mon Sep 17 00:00:00 2001 From: David Shnayder Date: Sat, 7 Mar 2026 19:16:31 +0200 Subject: [PATCH 7/7] Bump version and note span support in interpolation in skill --- .agents/skills/pretty-console-expert/SKILL.md | 1 + .../pretty-console-expert/references/v5-api-map.md | 9 +++++++++ PrettyConsole/PrettyConsole.csproj | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.agents/skills/pretty-console-expert/SKILL.md b/.agents/skills/pretty-console-expert/SKILL.md index d3bedbb..900c4f6 100644 --- a/.agents/skills/pretty-console-expert/SKILL.md +++ b/.agents/skills/pretty-console-expert/SKILL.md @@ -32,6 +32,7 @@ using static System.Console; // optional `Console.WriteInterpolated($"Elapsed {elapsed:duration}")` -> `Elapsed 12h 5m 33s` - Use `:bytes` with `double` to render human-readable file sizes from the handler: `Console.WriteInterpolated($"Transferred {bytes:bytes}")` -> `Transferred 12.3 MB` +- Interpolation holes accept `ReadOnlySpan` directly and prefer `ISpanFormattable`, so slices and span-format-capable values stay on the high-performance handler path without dropping to low-level `Write(ReadOnlySpan)` APIs. - Prefer these formats in status/progress output instead of manual formatting logic. ## Performance Rules diff --git a/.agents/skills/pretty-console-expert/references/v5-api-map.md b/.agents/skills/pretty-console-expert/references/v5-api-map.md index 8b73b5b..7d05a02 100644 --- a/.agents/skills/pretty-console-expert/references/v5-api-map.md +++ b/.agents/skills/pretty-console-expert/references/v5-api-map.md @@ -56,6 +56,15 @@ PrettyConsole methods are extension members on `System.Console`. - `double` with `:bytes`: - `Console.WriteInterpolated($"Downloaded {size:bytes}")` - Example output: `Downloaded 12.3 MB` +- `ReadOnlySpan` and `ISpanFormattable` values work directly in interpolation holes: + + ```csharp + ReadOnlySpan prefix = "artifact:".AsSpan()[..8]; + int count = 42; + Console.WriteInterpolated($"{prefix} {count:D4}"); + ``` + + Prefer this over dropping to low-level span `Write(...)` APIs when you still want normal interpolated output composition. ### Low-level escape hatch (rare) diff --git a/PrettyConsole/PrettyConsole.csproj b/PrettyConsole/PrettyConsole.csproj index f86754f..5bb74bd 100755 --- a/PrettyConsole/PrettyConsole.csproj +++ b/PrettyConsole/PrettyConsole.csproj @@ -26,7 +26,7 @@ https://github.com/dusrdev/PrettyConsole/ https://github.com/dusrdev/PrettyConsole/ git - 5.4.1-rc1 + 5.4.1 enable MIT True @@ -55,7 +55,7 @@ - +