Skip to content

Implement Terminal.Gui.Cli library (Stage A) and migrate clet#176

Closed
tig wants to merge 13 commits into
developfrom
tig/curly-bassoon
Closed

Implement Terminal.Gui.Cli library (Stage A) and migrate clet#176
tig wants to merge 13 commits into
developfrom
tig/curly-bassoon

Conversation

@tig
Copy link
Copy Markdown
Member

@tig tig commented May 23, 2026

Summary

Implements Stage A of the Terminal.Gui.Cli library spec: extract clet's hosting infrastructure into a reusable Terminal.Gui.Cli class library, migrate clet to consume it via ProjectReference, and delete all duplicated code.

What this PR delivers

New library: src/Terminal.Gui.Cli/ (26 source files)

A complete, AOT-friendly CLI hosting library with:

  • Core abstractionsICliCommand, ICliCommand<T>, IViewerCommand, ICommandRegistry, CommandRunOptions, CommandResult, CommandKind, CommandStatus, CommandOptionDescriptor
  • RegistryCommandRegistry (case-insensitive, duplicate-rejecting, PrimaryAlias validation)
  • ParserArgParser (data-driven: framework flags + consumer globals + per-command options)
  • HostCliHost (parse → root flags → dispatch → TUI lifecycle → output → exit codes)
  • OutputJsonEnvelope (SchemaV1), ResultWriter, OpenCliWriter (OpenCLI-conformant introspection)
  • HelpMetadataHelpProvider, IHelpProvider interface
  • SecurityTerminalEscapeSanitizer (input sanitization + SGR-only output pass-through)

Library tests: tests/Terminal.Gui.Cli.Tests/ (98 tests)

Covers registry, parser, host dispatch, JSON envelope, exit codes, type names, escape sanitizer, and consumer global options flow.

clet migration

  • All 14 input clets + 4 viewer clets now use library types (ICliCommand, CommandRunOptions, etc.)
  • Program.cs rewritten to use CliHost
  • MarkdownHelpRenderer simplified to use Markdown.RenderToAnsi() (TG #5388)
  • 16 superseded files deleted (old abstractions, registry, parser, dispatcher, formatter, JSON context)

Dependency updates

  • Terminal.Gui bumped to 2.4.1-develop.11 (includes Markdown.RenderToAnsi() API)
  • Terminal.Gui.Editor bumped to 2.4.1 (compatible with TG 2.4.x)

Key design decisions

# Decision Rationale
1 Library owns TG lifecycle Commands receive IApplication; they never call Application.Create()
2 No reflection; NativeAOT from day one Source-generated JSON, explicit registration
3 --opencli replaces list command OpenCLI-conformant JSON introspection as a root flag
4 --cat is a framework flag ArgParser handles it; CliHost calls IViewerCommand.RenderCatAsync
5 Consumer global options via Extensions dictionary --allow-file, --allow-binary, --no-browse registered via CliHostOptions.GlobalOptions
6 InputCletRunner stays in clet Adds CletStyling.BaseSchemeName which library deliberately omits (spec §9.1)
7 FileAccessPolicy/MarkdownContentResolver stay in clet Security/content helpers are clet-specific, not library-level

Security fixes (from code review)

  • OpenCliWriter: Option names now escaped via AppendJsonString (prevents JSON injection)
  • CommandRegistry: PrimaryAlias must be in Aliases (throws ArgumentException at registration)
  • SanitizeRenderedOutput: Only SGR sequences (m-terminated CSI) pass through; device queries/erase/mode changes stripped

Test results

Suite Count Status
Terminal.Gui.Cli.Tests 98
Clet.UnitTests 310
Clet.IntegrationTests 54 ✅ (2 skipped)
Clet.ConfigTests 26
Clet.SmokeTests 14 ✅ (1 skipped)
Clet.UITests 20
Total 522 0 failures

Zero warnings in both Debug and Release builds.

Spec/doc impact

  • specs/terminal-gui-cli.md — authoritative spec (unchanged; this PR implements it)
  • specs/stage-a-progress.md — new tracking doc with decisions, learnings, and spec feedback
  • No stale spec references found (--cat in §6.1, no list command mentions)

Upstream dependency

  • Filed TG #5385 requesting Markdown.RenderToAnsi() API
  • TG #5388 implemented and merged it
  • This PR consumes it via the 2.4.1-develop.11 package

Comprehensive design document for extracting clet's hosting infrastructure
into a reusable Terminal.Gui.Cli library. Key design decisions:

- Library owns the TG lifecycle (commands never call Application.Create)
- No reflection; NativeAOT from day one
- Registry is instances, not types (dynamic, DI-friendly)
- Extensible CommandRunOptions with repeatable option accumulation
- OpenCLI-conformant structured introspection (--opencli flag)
- help/agent-guide as registered IViewerCommand implementations
- IViewerCommand.RenderCatAsync for --cat dispatch without TUI
- 3-part AI agent discovery model (llms.txt, agent-guide, --opencli)
- Engineering Constitution with 8 architectural rules (C1-C8)
- 4-stage implementation strategy (prove in clet, rewrite in gui-cs/cli)

Honestly acknowledges extraction costs: ArgParser must be rewritten from
scratch (data-driven vs clet's hard-coded flag enumeration).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tig tig marked this pull request as ready for review May 23, 2026 17:01
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6851e39740

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread specs/terminal-gui-cli.md
tig and others added 12 commits May 23, 2026 11:38
Implement the core Terminal.Gui.Cli class library as specified in
specs/terminal-gui-cli.md §13 Stage A. The library extracts and
generalizes clet's hosting infrastructure into a reusable package.

Key components:
- Core abstractions: ICliCommand, ICliCommand<T>, IViewerCommand,
  CommandRunOptions, CommandResult, ICommandRegistry
- CommandRegistry: case-insensitive, duplicate-rejecting alias lookup
- ArgParser: data-driven parser (rewritten from scratch, not extracted)
  with --option=value and -- separator support
- CliHost: main entry point owning parse/dispatch/lifecycle/output
- JsonEnvelope: AOT-safe source-generated JSON wire format
- ExitCodes: POSIX-conventional exit code mapping
- InputCommandRunner: shared boilerplate for TUI input commands
- OpenCliWriter: hand-built OpenCLI JSON from registry metadata
- TerminalEscapeSanitizer: terminal escape sequence filtering
- TypeNames, ResultWriter, IHelpProvider, MetadataHelpProvider

Test coverage: 95 tests covering registry, parser, exit codes,
JSON envelope, sanitizer, run options, and CliHost end-to-end.

Full solution builds with 0 warnings, 0 errors. All 445 existing
clet unit tests continue to pass (library is additive, no refactoring
of clet yet).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Delete Abstractions/, Json/, and hosting files now provided by the library
  (IClet, ICletRegistry, CletRunOptions, CletRunResult, CletRunStatus,
  CletKind, CletOptionDescriptor, BoxedCletResult, CletRegistry,
  ExitCodes, TerminalEscapeSanitizer, CletTypeNames, OutputFormatter,
  CommandLineRoot, AliasDispatcher, SchemaV1, CletJsonContext)
- Replace Program.cs to use CliHost from Terminal.Gui.Cli
- Update BuiltInClets to use ICommandRegistry
- Update MarkdownHelpRenderer to use ICliCommand, ICommandRegistry,
  CommandOptionDescriptor, CommandKind, TypeNames
- Update MarkdownContentResolver to use CommandRunOptions with
  GetExtensionList/HasExtension for global options
- Update all clet implementations to use library interfaces:
  ICliCommand<T>, IViewerCommand, CommandResult<T>, CommandResult,
  CommandStatus, CommandKind, CommandOptionDescriptor, CommandRunOptions
- Add ProjectReference to Terminal.Gui.Cli (already present in csproj)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…types

- Add ProjectReference to Terminal.Gui.Cli in all three test projects
- Delete test files now covered by Terminal.Gui.Cli.Tests:
  CommandLineRootTests, CletRegistryTests, OutputFormatterTests,
  SchemaV1Tests, TerminalEscapeSanitizerTests, CletTypeNamesTests,
  CletRunResultTests, ExitCodesTests
- Replace old types with library equivalents across remaining tests:
  ICletRegistry -> ICommandRegistry, IClet -> ICliCommand,
  CletKind -> CommandKind, CletRunOptions -> CommandRunOptions,
  CletRunResult -> CommandResult, CletRunStatus -> CommandStatus,
  IViewerClet -> IViewerCommand, CletRegistry -> CommandRegistry
- Update CletOptions -> CommandOptions
- Replace AllowedFiles property with Extensions allow-file
- Fix CommandResult<T> record struct construction (positional ctor)
- Include IntegrationTests migration to library types

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tests

- Program.cs: version includes Terminal.Gui version for --version output
- MarkdownClet: add RenderCatAsync for --cat mode (replaces AliasDispatcher logic)
- MarkdownClet: remove --cat and --no-browse from per-command options
  (now framework flag and global option respectively)
- Smoke tests: update to use --opencli instead of deleted 'list --json'
- Smoke tests: version regex updated for 'clet X.Y.Z (...)' format
- Unit test: fix Options_ContainsTheme assertion count

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1. OpenCliWriter: escape option names through AppendJsonString to prevent
   JSON injection via CommandOptionDescriptor with special characters.

2. CommandRegistry: validate PrimaryAlias is included in Aliases collection
   at registration time. Throws InvalidOperationException if missing,
   preventing commands that appear in help but can't be invoked.

3. TerminalEscapeSanitizer.SanitizeRenderedOutput: restrict CSI pass-through
   to SGR sequences only (m-terminated). Non-SGR CSI sequences (device
   queries, erase, mode changes) are now stripped for defense-in-depth.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
# Conflicts:
#	src/Clet/Clets/Input/ConfirmClet.cs
#	src/Clet/Hosting/CommandLineRoot.cs
#	tests/Clet.UnitTests/CommandLineRootTests.cs
Replace the ~20-line headless driver workaround in MarkdownHelpRenderer
with a single call to Markdown.RenderToAnsi() (TG #5388).

- Bump Terminal.Gui to 2.4.1-develop.11 (includes RenderToAnsi)
- Bump Terminal.Gui.Editor to 2.4.1 (compatible with TG 2.4.x)
- Fix xUnit1051 warnings in CliHostTests (pass CancellationToken)
- Regenerate help.ans golden (minor rendering difference)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tig tig changed the title Add Terminal.Gui.Cli library spec (draft) Prototype Terminal.Gui.cli library May 23, 2026
@tig tig changed the title Prototype Terminal.Gui.cli library Implement Terminal.Gui.Cli library (Stage A) and migrate clet May 23, 2026
Copilot AI mentioned this pull request May 23, 2026
7 tasks
@tig tig closed this May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant