Token导航 LogoToken导航TokenDH.com
研究检索执行命令github未标认证来源可访问许可证需确认审计通过

dotnet-spectre-consoledotnet 幽灵控制台

Agent Skill

dotnet-spectre-console 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

535

周安装

23

GitHub Stars

16

下载量

188
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:dotnet-spectre-console(dotnet 幽灵控制台)
来源仓库:https://github.com/wshaddix/dotnet-skills
仓库路径:skills/dotnet-spectre-console
安装命令:
npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-spectre-console
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-spectre-console

简介

dotnet-spectre-console 用于构建丰富的控制台输出界面,支持表格、树形结构、进度条和交互式提示。

  • 适用于需要美观终端展示的场景,如 CLI 工具开发、数据报表生成或系统监控界面。
  • 通过 Spectre.Console 和 Spectre.Console.Cli 实现结构化命令行应用解析与跨平台兼容。
  • 安装需确认 .NET 8.0+ 环境及对应包版本,注意可能涉及终端渲染和网络依赖。
  • 建议结合官方文档验证具体用法,评估是否触发文件读写或命令执行权限。

SKILL.md

dotnet-spectre-console

Spectre.Console for building rich console output (tables, trees, progress bars, prompts, markup, live displays) and Spectre.Console.Cli for structured command-line application parsing. Cross-platform across Windows, macOS, and Linux terminals.

Version assumptions:.NET 8.0+ baseline. Spectre.Console 0.54.0 (latest stable). Spectre.Console.Cli 0.53.1 (latest stable). Both packages target net8.0+ and netstandard2.0.

Scope boundary: This skill owns rich console output and Spectre.Console.Cli command parsing. Full TUI applications (windows, menus, dialogs, views) are owned by [skill:dotnet-terminal-gui]. System.CommandLine parsing is owned by [skill:dotnet-system-commandline]. CLI application architecture and distribution are owned by [skill:dotnet-cli-architecture] and [skill:dotnet-cli-distribution].

Cross-references: [skill:dotnet-terminal-gui] for full TUI alternative, [skill:dotnet-system-commandline] for System.CommandLine scope boundary, [skill:dotnet-cli-architecture] for CLI structure, [skill:dotnet-csharp-async-patterns] for async patterns, [skill:dotnet-csharp-dependency-injection] for DI with Spectre.Console.Cli, [skill:dotnet-accessibility] for TUI accessibility limitations and screen reader considerations.


Package References

<ItemGroup>
  <!-- Rich console output: markup, tables, trees, progress, prompts, live displays -->
  <PackageReference Include="Spectre.Console" Version="0.54.0" />

  <!-- CLI command framework (adds command parsing, settings, DI support) -->
  <PackageReference Include="Spectre.Console.Cli" Version="0.53.1" />
</ItemGroup>

Spectre.Console.Cli has a dependency on Spectre.Console -- install both only when you need the CLI framework. For rich output only, Spectre.Console alone is sufficient.


Markup and Styling

Spectre.Console uses a BBCode-inspired markup syntax for styled console output.

Basic Markup

using Spectre.Console;

// Styled text with markup tags
AnsiConsole.MarkupLine("[bold red]Error:[/] File not found.");
AnsiConsole.MarkupLine("[green]Success![/] Build completed in [blue]2.3s[/].");
AnsiConsole.MarkupLine("[underline]https://example.com[/]");
AnsiConsole.MarkupLine("[dim italic]This is subtle text[/]");

// Nested styles
AnsiConsole.MarkupLine("[bold [red on white]Warning:[/] check config[/]");

// Escape brackets with double brackets
AnsiConsole.MarkupLine("Use [[bold]] for bold text.");

Figlet Text

AnsiConsole.Write(
    new FigletText("Hello!")
        .Color(Color.Green)
        .Centered());

Rule (Horizontal Line)

// Simple rule
AnsiConsole.Write(new Rule());

// Titled rule
AnsiConsole.Write(new Rule("[yellow]Section Title[/]"));

// Aligned rule
AnsiConsole.Write(new Rule("[blue]Left Aligned[/]").LeftJustified());

Tables

var table = new Table();

// Add columns
table.AddColumn("Name");
table.AddColumn(new TableColumn("Age").Centered());
table.AddColumn(new TableColumn("City").RightAligned());

// Add rows
table.AddRow("Alice", "30", "Seattle");
table.AddRow("[green]Bob[/]", "25", "Portland");
table.AddRow("Charlie", "35", "Vancouver");

// Styling
table.Border(TableBorder.Rounded);
table.BorderColor(Color.Grey);
table.Title("[underline]Team Members[/]");
table.Caption("[dim]Updated daily[/]");

// Column configuration
table.Columns[0].PadLeft(2);
table.Columns[0].NoWrap();

AnsiConsole.Write(table);

Nested Tables

var innerTable = new Table()
    .AddColumn("Detail")
    .AddColumn("Value")
    .AddRow("Role", "Developer")
    .AddRow("Level", "Senior");

var outerTable = new Table()
    .AddColumn("Name")
    .AddColumn("Info")
    .AddRow("Alice", innerTable);

AnsiConsole.Write(outerTable);

Trees

var tree = new Tree("Solution");

// Add nodes
var srcNode = tree.AddNode("[yellow]src[/]");
var apiNode = srcNode.AddNode("Api");
apiNode.AddNode("Controllers/");
apiNode.AddNode("Program.cs");

var libNode = srcNode.AddNode("Library");
libNode.AddNode("Services/");

var testNode = tree.AddNode("[blue]tests[/]");
testNode.AddNode("Api.Tests/");

// Styling
tree.Style = Style.Parse("dim");

AnsiConsole.Write(tree);

Panels

var panel = new Panel("This is [green]important[/] content.")
    .Header("[bold]Notice[/]")
    .Border(BoxBorder.Rounded)
    .BorderColor(Color.Blue)
    .Padding(2, 1)    // horizontal, vertical
    .Expand();         // fill available width

AnsiConsole.Write(panel);

Composing Renderables with Columns

AnsiConsole.Write(new Columns(
    new Panel("Left panel").Expand(),
    new Panel("Right panel").Expand()));

Progress Displays

Progress Bars

await AnsiConsole.Progress()
    .AutoClear(false)       // keep completed tasks visible
    .HideCompleted(false)
    .Columns(
        new TaskDescriptionColumn(),
        new ProgressBarColumn(),
        new PercentageColumn(),
        new RemainingTimeColumn(),
        new SpinnerColumn())
    .StartAsync(async ctx =>
    {
        var downloadTask = ctx.AddTask("[green]Downloading[/]", maxValue: 100);
        var extractTask = ctx.AddTask("[blue]Extracting[/]", maxValue: 100);

        while (!ctx.IsFinished)
        {
            await Task.Delay(50);
            downloadTask.Increment(1.5);

            if (downloadTask.Value > 50)
            {
                extractTask.Increment(0.8);
            }
        }
    });

Status Spinners

await AnsiConsole.Status()
    .Spinner(Spinner.Known.Dots)
    .SpinnerStyle(Style.Parse("green bold"))
    .StartAsync("Processing...", async ctx =>
    {
        await Task.Delay(1000);
        ctx.Status("Compiling...");
        ctx.Spinner(Spinner.Known.Star);
        await Task.Delay(1000);
        ctx.Status("Publishing...");
        await Task.Delay(1000);
    });

Prompts

Text Prompt

// Simple typed input
var name = AnsiConsole.Ask<string>("What's your [green]name[/]?");
var age = AnsiConsole.Ask<int>("What's your [green]age[/]?");

// With default value
var city = AnsiConsole.Prompt(
    new TextPrompt<string>("Enter [green]city[/]:")
        .DefaultValue("Seattle")
        .ShowDefaultValue());

// Secret input (password)
var password = AnsiConsole.Prompt(
    new TextPrompt<string>("Enter [green]password[/]:")
        .Secret());

// With validation
var email = AnsiConsole.Prompt(
    new TextPrompt<string>("Enter [green]email[/]:")
        .Validate(input =>
            input.Contains('@') && input.Contains('.')
                ? ValidationResult.Success()
                : ValidationResult.Error("[red]Invalid email address[/]")));

// Optional (allow empty)
var nickname = AnsiConsole.Prompt(
    new TextPrompt<string>("Enter [green]nickname[/] (optional):")
        .AllowEmpty());

Confirmation Prompt

bool proceed = AnsiConsole.Confirm("Continue with deployment?");

Selection Prompt

var fruit = AnsiConsole.Prompt(
    new SelectionPrompt<string>()
        .Title("Pick a [green]fruit[/]:")
        .PageSize(10)
        .EnableSearch()
        .WrapAround()
        .AddChoices("Apple", "Banana", "Orange", "Mango", "Grape"));

// Grouped choices
var country = AnsiConsole.Prompt(
    new SelectionPrompt<string>()
        .Title("Select [green]destination[/]:")
        .AddChoiceGroup("Europe", "France", "Italy", "Spain")
        .AddChoiceGroup("Asia", "Japan", "Thailand", "Vietnam"));

Multi-Selection Prompt

var toppings = AnsiConsole.Prompt(
    new MultiSelectionPrompt<string>()
        .Title("Choose [green]toppings[/]:")
        .PageSize(10)
        .Required()
        .InstructionsText("[grey](Press [blue]<space>[/] to toggle, [green]<enter>[/] to accept)[/]")
        .AddChoices("Cheese", "Pepperoni", "Mushrooms", "Olives", "Onions"));

Live Displays

Live displays update in-place for dynamic content that changes over time.

var table = new Table()
    .AddColumn("Time")
    .AddColumn("Status");

await AnsiConsole.Live(table)
    .AutoClear(false)
    .Overflow(VerticalOverflow.Ellipsis)
    .Cropping(VerticalOverflowCropping.Bottom)
    .StartAsync(async ctx =>
    {
        table.AddRow(DateTime.Now.ToString("T"), "[yellow]Starting...[/]");
        ctx.Refresh();
        await Task.Delay(1000);

        table.AddRow(DateTime.Now.ToString("T"), "[green]Processing...[/]");
        ctx.Refresh();
        await Task.Delay(1000);

        table.AddRow(DateTime.Now.ToString("T"), "[blue]Complete![/]");
        ctx.Refresh();
    });

Replacing the Target

await AnsiConsole.Live(new Markup("[yellow]Initializing...[/]"))
    .StartAsync(async ctx =>
    {
        await Task.Delay(1000);
        ctx.UpdateTarget(new Markup("[green]Ready![/]"));
        await Task.Delay(1000);
        ctx.UpdateTarget(
            new Panel("Final result: [bold]42[/]")
                .Header("Done")
                .Border(BoxBorder.Rounded));
    });

Spectre.Console.Cli Framework

Spectre.Console.Cli provides a structured command-line parsing framework with command hierarchies, typed settings, validation, and automatic help generation.

Basic Command App

using Spectre.Console.Cli;

var app = new CommandApp<GreetCommand>();
return app.Run(args);

// Command with typed settings
public sealed class GreetSettings : CommandSettings
{
    [CommandArgument(0, "<name>")]
    [Description("The person to greet")]
    public string Name { get; init; } = string.Empty;

    [CommandOption("-c|--count")]
    [Description("Number of times to greet")]
    [DefaultValue(1)]
    public int Count { get; init; }

    [CommandOption("--shout")]
    [Description("Greet in uppercase")]
    public bool Shout { get; init; }
}

public sealed class GreetCommand : Command<GreetSettings>
{
    public override int Execute(CommandContext context, GreetSettings settings)
    {
        for (int i = 0; i < settings.Count; i++)
        {
            var greeting = $"Hello, {settings.Name}!";
            AnsiConsole.MarkupLine(settings.Shout
                ? $"[bold]{greeting.ToUpperInvariant()}[/]"
                : greeting);
        }
        return 0;  // exit code
    }
}

Command Hierarchy with Branches

var app = new CommandApp();
app.Configure(config =>
{
    config.AddBranch<RemoteSettings>("remote", remote =>
    {
        remote.AddCommand<RemoteAddCommand>("add")
            .WithDescription("Add a remote");
        remote.AddCommand<RemoteRemoveCommand>("remove")
            .WithDescription("Remove a remote");
    });

    config.AddCommand<CloneCommand>("clone")
        .WithDescription("Clone a repository");
});

return app.Run(args);

// Shared settings for the branch -- inherited by subcommands
public class RemoteSettings : CommandSettings
{
    [CommandOption("-v|--verbose")]
    [Description("Verbose output")]
    public bool Verbose { get; init; }
}

// Subcommand settings inherit from branch settings
public sealed class RemoteAddSettings : RemoteSettings
{
    [CommandArgument(0, "<name>")]
    public string Name { get; init; } = string.Empty;

    [CommandArgument(1, "<url>")]
    public string Url { get; init; } = string.Empty;
}

public sealed class RemoteAddCommand : Command<RemoteAddSettings>
{
    public override int Execute(CommandContext context, RemoteAddSettings settings)
    {
        if (settings.Verbose)
        {
            AnsiConsole.MarkupLine($"[dim]Adding remote...[/]");
        }
        AnsiConsole.MarkupLine($"Added remote [green]{settings.Name}[/] -> {settings.Url}");
        return 0;
    }
}

Settings Validation

public sealed class DeploySettings : CommandSettings
{
    [CommandArgument(0, "<environment>")]
    public string Environment { get; init; } = string.Empty;

    [CommandOption("--timeout")]
    [DefaultValue(30)]
    public int TimeoutSeconds { get; init; }

    public override ValidationResult Validate()
    {
        var validEnvs = new[] { "dev", "staging", "prod" };
        if (!validEnvs.Contains(Environment, StringComparer.OrdinalIgnoreCase))
        {
            return ValidationResult.Error(
                $"Environment must be one of: {string.Join(", ", validEnvs)}");
        }

        if (TimeoutSeconds <= 0)
        {
            return ValidationResult.Error("Timeout must be positive");
        }

        return ValidationResult.Success();
    }
}

Async Commands

public sealed class FetchCommand : AsyncCommand<FetchSettings>
{
    public override async Task<int> ExecuteAsync(
        CommandContext context, FetchSettings settings)
    {
        await AnsiConsole.Status()
            .StartAsync("Fetching data...", async ctx =>
            {
                await Task.Delay(2000); // simulate work
            });

        AnsiConsole.MarkupLine("[green]Done![/]");
        return 0;
    }
}

Dependency Injection with ITypeRegistrar

using Microsoft.Extensions.DependencyInjection;
using Spectre.Console.Cli;

// Set up DI container
var services = new ServiceCollection();
services.AddSingleton<IGreetingService, GreetingService>();
services.AddSingleton<IAnsiConsole>(AnsiConsole.Console);

var registrar = new TypeRegistrar(services);
var app = new CommandApp<GreetCommand>(registrar);
return app.Run(args);

// TypeRegistrar bridges Microsoft DI to Spectre.Console.Cli
public sealed class TypeRegistrar(IServiceCollection services) : ITypeRegistrar
{
    public ITypeResolver Build() => new TypeResolver(services.BuildServiceProvider());

    public void Register(Type service, Type implementation)
        => services.AddSingleton(service, implementation);

    public void RegisterInstance(Type service, object implementation)
        => services.AddSingleton(service, implementation);

    public void RegisterLazy(Type service, Func<object> factory)
        => services.AddSingleton(service, _ => factory());
}

public sealed class TypeResolver(IServiceProvider provider) : ITypeResolver
{
    public object? Resolve(Type? type)
        => type is null ? null : provider.GetService(type);
}

// Command receives services via constructor injection
public sealed class GreetCommand(IGreetingService greetingService) : Command<GreetSettings>
{
    public override int Execute(CommandContext context, GreetSettings settings)
    {
        var message = greetingService.GetGreeting(settings.Name);
        AnsiConsole.MarkupLine(message);
        return 0;
    }
}

Testable Console Output

Spectre.Console provides IAnsiConsole for testable output instead of writing directly to the real console.

// Production: use AnsiConsole.Console (the real console)
IAnsiConsole console = AnsiConsole.Console;

// Testing: use a recording console
var console = AnsiConsole.Create(new AnsiConsoleSettings
{
    Out = new AnsiConsoleOutput(new StringWriter())
});

// Use the abstraction instead of static AnsiConsole methods
console.MarkupLine("[green]Testable output[/]");
console.Write(new Table().AddColumn("Col").AddRow("Val"));

Agent Gotchas

  1. **Do not use AnsiConsole.Markup* in redirected output.** When stdout is redirected (piped to a file or another process), ANSI escape codes corrupt the output. Check AnsiConsole.Profile.Capabilities.Ansi before using markup, or use IAnsiConsole with appropriate settings. See [skill:dotnet-csharp-async-patterns] for async pipeline patterns.
  2. Do not assume ANSI support in CI environments. CI runners (GitHub Actions, Azure Pipelines) may not support ANSI escape codes. Set TERM=dumb or use AnsiConsole.Create() with ColorSystemSupport.NoColors for CI-safe output. Spectre.Console auto-detects capabilities, but explicit configuration prevents flaky rendering.
  3. Do not mix AnsiConsole static calls with IAnsiConsole instance calls. Static AnsiConsole.Write() always targets the real console. When using DI with IAnsiConsole, consistently use the injected instance. Mixing the two produces duplicated or interleaved output.
  4. Do not modify a renderable from a background thread during Live(). Live displays are not thread-safe. Mutate the target renderable only inside the Start/StartAsync callback, then call ctx.Refresh(). Concurrent mutations cause corrupted terminal output.
  5. Do not use prompts in non-interactive contexts. TextPrompt, SelectionPrompt, and ConfirmationPrompt block waiting for user input. In CI or automated scripts, use environment variables or command-line arguments for input instead of prompts. Check AnsiConsole.Profile.Capabilities.Interactive before prompting.
  6. Do not confuse Spectre.Console.Cli with System.CommandLine. They are independent frameworks with different APIs. Spectre.Console.Cli uses CommandSettings classes with [CommandArgument]/[CommandOption] attributes, while System.CommandLine uses Option<T> and Argument<T> builder pattern. Do not mix APIs. For System.CommandLine, see [skill:dotnet-system-commandline].
  7. Do not forget ctx.Refresh() after modifying live display content. Changes to tables, trees, or panels inside a Live() callback are not rendered until ctx.Refresh() is called. Omitting it produces stale displays.
  8. Do not hardcode color values without fallback. Terminals with limited color support silently degrade TrueColor values. Use named colors (Color.Green) when possible and test with NO_COLOR=1 environment variable to verify graceful degradation.

Prerequisites

  • NuGet packages: Spectre.Console 0.54.0 for rich output; add Spectre.Console.Cli 0.53.1 for CLI framework
  • Target framework: net8.0 or later (also supports netstandard2.0)
  • Terminal: Any terminal emulator supporting ANSI escape sequences. Windows Terminal, iTerm2, or modern Linux terminal recommended for best experience (TrueColor, Unicode). Console output degrades gracefully on limited terminals.
  • For DI with Spectre.Console.Cli: Microsoft.Extensions.DependencyInjection package for the ITypeRegistrar/ITypeResolver bridge

References

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

36.09%
按下载量换算68

Claude

28.2%
按下载量换算53

Cursor

18.44%
按下载量换算35

Gemini CLI

9.43%
按下载量换算18

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

执行命令

安装流程涉及命令执行,可能通过 npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-spectre-console 联网下载 Skill 或依赖。用户安装前应确认命令来源、仓库内容和执行环境。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills