Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 108 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,108 @@
# cli
A `Terminal.Gui` library that lets applications expose Views as scriptable CLI commands with typed JSON output, POSIX exit codes, and AI-agent discoverability.
# Terminal.Gui.Cli

![Terminal.Gui.Cli Example App](docs/images/hero.gif)

A .NET library that lets [Terminal.Gui](https://github.com/gui-cs/Terminal.Gui) applications expose Views as scriptable CLI commands with typed JSON output, POSIX exit codes, and AI-agent discoverability.

Ships as a single NuGet package: **[`Terminal.Gui.Cli`](https://www.nuget.org/packages/Terminal.Gui.Cli)**.

## What it does

`Terminal.Gui.Cli` provides a hosting layer (`CliHost`) that wires up:

- **CLI parsing** — positional command dispatch, typed options, `--initial` pre-fill for input commands.
- **Structured output** — `--json` emits a versioned `JsonEnvelope`; `--cat` renders viewer content headlessly.
- **AI-agent discoverability** — `--opencli` emits machine-readable metadata; `--agent-guide` serves embedded Markdown guidance.
- **Built-in help** — `--help` renders command/option metadata via pluggable `IHelpProvider`.
- **Exit codes** — deterministic POSIX exit codes from `CommandResult` status.

## Command model

| Kind | Interface | Description |
|------|-----------|-------------|
| **Input** | `ICliCommand<T>` | Launches a Terminal.Gui UI, returns a typed result. |
| **Viewer** | `IViewerCommand` | Displays content; supports `--cat` for headless rendering. |

Commands register explicitly (no reflection scanning) and resolve by case-insensitive alias.

## Quickstart

```csharp
using Terminal.Gui.Cli;

CliHost host = new (options =>
{
options.ApplicationName = "my-app";
options.Version = "1.0.0";
});

host.Registry.Register (new MyCommand ());

return await host.RunAsync (args);
```

```sh
# Interactive (launches Terminal.Gui)
my-app greet --initial "World"

# JSON envelope
my-app greet --initial "World" --json

# Agent discovery
my-app --opencli
my-app agent-guide

# Headless viewer
my-app info --cat
```

## Framework options

All commands inherit these options from the host:

| Option | Description |
|--------|-------------|
| `--help` / `-h` | Show help |
| `--version` | Show version |
| `--opencli` | Emit OpenCLI metadata JSON |
| `--json` | Wrap output in JSON envelope |
| `--initial <value>` | Pre-fill input value |
| `--timeout <duration>` | Cancel after duration (e.g., `30s`, `5m`) |
| `--output <path>` / `-o` | Write output to file |
| `--cat` | Headless render (viewer commands only) |

## Repository layout

```
specs/ Constitution and library spec
src/ Terminal.Gui.Cli library
tests/ Unit, integration, and smoke tests
examples/ Example console app
scripts/ Tooling and recording scripts
docs/ Images and documentation assets
```

## Build

Requires .NET 10 SDK. Solution file: `Terminal.Gui.Cli.slnx`.

```sh
dotnet restore Terminal.Gui.Cli.slnx
dotnet build Terminal.Gui.Cli.slnx

# Tests
dotnet run --project tests/Terminal.Gui.Cli.Tests
dotnet run --project tests/Terminal.Gui.Cli.IntegrationTests
dotnet run --project tests/Terminal.Gui.Cli.SmokeTests

# Example app
dotnet run --project examples/Terminal.Gui.Cli.ExampleApp -- greet --initial "World" --json
```

## Status

**Alpha** — `0.1.0-develop` pre-release stream on the `develop` branch.

## License

MIT; see [`LICENSE`](LICENSE).
Binary file added docs/images/hero.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
86 changes: 86 additions & 0 deletions scripts/HERO-GIF.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Hero GIF Recording Guide

Produces `docs/images/hero.gif` — an animated GIF demonstrating the example app's CLI features.

## Prerequisites

- [tuirec](https://github.com/gui-cs/tuirec) v0.3.4+ on PATH (`go install github.com/gui-cs/tuirec/cmd/tuirec@latest`)
- .NET 10 SDK (for building the example app)
- PowerShell 7+ (`pwsh`) on PATH
- `agg` is auto-downloaded by tuirec on first use

## Build the example app

```powershell
dotnet build examples/Terminal.Gui.Cli.ExampleApp -c Debug --nologo
```

## Record

The recording uses a PowerShell script to run multiple CLI invocations in sequence,
captured by tuirec in `--inline` mode (no alternate screen, normal scrolling buffer).

```powershell
$binary = (Resolve-Path "examples/Terminal.Gui.Cli.ExampleApp/bin/Debug/net10.0/Terminal.Gui.Cli.ExampleApp.exe").Path

# Create the demo script that runs each CLI feature
$script = @"
Write-Host '`$ example-app --help' -ForegroundColor Green
& '$binary' --help
Write-Host ''
Write-Host '`$ example-app greet --initial "World" --json' -ForegroundColor Green
& '$binary' greet --initial 'World' --json
Write-Host ''
Write-Host '`$ example-app info --cat' -ForegroundColor Green
& '$binary' info --cat
Write-Host ''
Write-Host '`$ example-app --opencli' -ForegroundColor Green
& '$binary' --opencli
"@
$script | Set-Content -Path artifacts/demo.ps1 -Encoding utf8

tuirec record `
--binary "pwsh" `
--args "-NoProfile","-File","artifacts/demo.ps1" `
--name "hero" `
--inline `
--show-command '$ ./demo.ps1' `
--keystrokes 'wait:5000' `
--startup-delay 3000 `
--drain 2000 `
--cols 100 `
--rows 35 `
--keystroke-delay 60 `
--max-duration 20 `
--verbosity high

# Copy to final location
Copy-Item ./artifacts/hero.gif ./docs/images/hero.gif -Force
```

## Demo sequence

The script runs four CLI invocations back-to-back. All output appears in a single scrolling terminal frame:

| Feature | Command |
|------------------------|-------------------------------------------------|
| Help | `example-app --help` — lists commands + options |
| JSON envelope | `example-app greet --initial "World" --json` |
| Headless viewer | `example-app info --cat` |
| Agent discovery | `example-app --opencli` — machine-readable JSON |

## Tuning tips

- **Terminal size**: 100x35 gives enough vertical space to show all outputs without scrolling previous content off-screen.
- **`--inline` mode**: Required because the demo runs non-interactive commands that print to stdout and exit. Without `--inline`, tuirec captures an empty alternate screen.
- **`--startup-delay 3000`**: Allows `pwsh` to start. Reduce on fast machines.
- **`--drain 2000`**: Holds the final frame so viewers can read the opencli output.
- **GIF too large**: Reduce `--rows` or remove one of the demo commands. Current result is ~75KB.
- **Wrong binary path**: After building, verify the exe exists. On Linux/macOS omit `.exe`.

## Troubleshooting

1. **Empty GIF (just the show-command prompt)**: You probably forgot `--inline`. Without it, the normal-screen output from pwsh is invisible.
2. **Output garbled or overlapping**: Increase `--startup-delay` so pwsh finishes initialization before tuirec starts capturing.
3. **GIF not generated**: Ensure `agg` was downloaded. Check `./artifacts/` for the `.cast` file; if present, re-run `agg` manually.
4. **PowerShell colors wrong**: The demo uses `Write-Host -ForegroundColor Green` for prompts. This renders as ANSI color 10 which most themes show as green.
Loading