Skip to content

feat(cli): add revela info command tree (versions + plugins + themes)#71

Merged
kirkone merged 4 commits into
mainfrom
feat/23-revela-info
May 14, 2026
Merged

feat(cli): add revela info command tree (versions + plugins + themes)#71
kirkone merged 4 commits into
mainfrom
feat/23-revela-info

Conversation

@kirkone
Copy link
Copy Markdown
Contributor

@kirkone kirkone commented May 14, 2026

Closes #23

Adds the revela info command tree with TUI inlining, exposes build identity via a new IBuildInfo SDK service, replaces System.CommandLine's default --version action with a human-readable host-kind-aware renderer, and removes the off-brand ASCII logo from the interactive welcome panel.

Commits (3, in review order)

  1. 9db74fafeat(sdk): add IBuildInfo + HostKind for build identity
    New Spectara.Revela.Sdk.Hosting.IBuildInfo interface + HostKind enum. Implementation reads the host kind from the Revela.HostKind AssemblyMetadata attribute set in Cli.Embedded.csproj (sidesteps the AssemblyName="revela" collision that makes name-based detection impossible). System.CommandLine's --version action is replaced so both revela --version and the first line of revela info print the same human-readable identifier:

    revela 1.0.0 (.NET 10.0.7)
    revela 1.0.0 (.NET 10.0.7) — embedded build
    

    New tests project tests/Cli/ with 9 cases covering detection, version-stripping, and FormatVersionLine for both host kinds.

  2. 42f35a4feat(cli): add revela info command tree with TUI inlining
    Three new commands (info, info plugins, info themes) plus the inlining mechanism that lets a parent command render flat in the interactive menu while keeping a clean nested CLI surface. Two opt-in fields on CommandDescriptor (InlineInMenu + InlineDefaultActionLabel); inlined subcommands without nested children are filtered out (a leaf entry with no extension provides no menu value beyond the parent's default action). Plugin-extension via the existing multi-level ParentCommand mechanism — no SDK API change required for info plugins <name> / info themes <name>.

    Bug fix bundled: ShowMainMenuAsync had its own dispatch switch hardcoding [selection.Command.Name] for the args path, ignoring CommandPathOverride from inlined entries. The top-level menu now routes through the same HandleMenuActionAsync as nested menus, honoring the override.

  3. 5f856eerefactor(cli): drop ASCII logo, slim welcome panel
    Removes LogoLines / ShowLogo() / ClearAndShowLogo() (the block-letter ASCII art was off-brand vs. the actual aperture wordmark and added ~6 lines of friction on every menu render). Welcome panel header WelcomeRevela; redundant Version line and Modern static site generator… tagline removed. First-run panel unchanged. CHANGELOG documents all three commits in one consolidated [Unreleased] block.

Verification

Gate Result
dotnet build 0 warnings, 0 errors
dotnet test 625 / 625 passed (9 new in tests/Cli, 6 new in tests/Commands/Info)
dotnet format --verify-no-changes clean
revela --version (Cli) revela 1.0.0 (.NET 10.0.7)
revela --version (Cli.Embedded) revela 1.0.0 (.NET 10.0.7) — embedded build
revela info plugins (Embedded) 6 bundled plugins rendered correctly
revela info themes (showcase) ★ Lumina active marker correct
TUI manual test (Embedded, full session) reported working by maintainer
Local Full release build 131.1 MB, smoke --version OK
Manual end-to-end release run reported working by maintainer

Reviewer focus areas (skeptic's checklist)

  1. TUI inlining is the most novel mechanic — MenuChoice.CommandPathOverride + the new lookup methods on CommandOrderRegistry (IsInlinedParent, GetInlineDefaultActionLabel). Edge case not validated: inlined parents registered with ParentCommand: "..." (i.e. nested rather than top-level) — currently treated as a no-op silently. Acceptable for now; worth a throw new InvalidOperationException(...) later if the pattern grows.
  2. Top-level menu dispatcher unification (ShowMainMenuAsyncHandleMenuActionAsync) changes the routing for every main-menu selection, not just the new info entries. No regression test exists for that path. Manual smoke covered the inlined cases; existing commands (config, generate, theme) were re-checked manually but not asserted.
  3. BuildInfoVersionAction uses SynchronousCommandLineAction. If you ever flip Cli.Embedded to PublishTrimmed/AOT (feat(cli): Enable PublishTrimmed for Cli.Embedded (Phase 2 of #40) #50), the AssemblyMetadataAttribute reflection in BuildInfo should remain trim-safe (SDK already has <IsTrimmable>true</IsTrimmable> + EnableTrimAnalyzer), but worth a fresh trim-analyzer pass when that work happens.
  4. Active-theme marker uses OrdinalIgnoreCase for the name comparison — liberal on purpose since theme config names may diverge in case from the loaded theme metadata.

Out of scope (deferred)

  • Per-plugin/theme detail subcommands (revela info plugins <name>) — Phase 2, plugin authors contribute via ParentCommand: "info plugins"
  • libvips version, project paths, manifest summary, configuration sources — listed in the original "Future Extensions" section
  • --json flag for machine-readable output
  • Optional IPackage.GetDiagnostics() SDK extension for richer per-package info
  • IBuildInfo extensions (IsTrimmed, IsAot, BuildDate) — additive when a concrete consumer appears (non-breaking)
  • "Wait-for-key after command in TUI" — analyzed in spike discussion, deferred (n=1 dev observation, no real photographer-beta feedback yet)

kirkone added 3 commits May 14, 2026 20:01
New SDK service `Spectara.Revela.Sdk.Hosting.IBuildInfo` exposes the
immutable build-time identity of the running host (Standalone vs.
Embedded) plus version, framework, configuration, and runtime
identifier. Single source of truth for `--version`, the upcoming
`revela info` command, and any plugin that needs to branch on host
kind (e.g. self-update plugins hiding themselves in embedded builds).

Detection mechanism: `Revela.HostKind` assembly metadata attribute
set in `Cli.Embedded.csproj`. Both Cli and Cli.Embedded produce an
assembly named `revela`, so name-based detection is impossible —
the metadata attribute sidesteps that collision and makes adding a
third host variant (e.g. Cli.Embedded.Ai) a 3-line change.

System.CommandLine's default `--version` action is replaced with a
human-readable, host-kind-aware renderer:

  revela 1.0.0 (.NET 10.0.7)
  revela 1.0.0 (.NET 10.0.7) — embedded build

Same string is reused as the first line of `revela info`, so both
surfaces report the same identifier — no drift possible.

Conceptual note: `IBuildInfo` is complementary to .NET's
`IHostEnvironment`. The latter describes the runtime *deployment*
environment (Dev/Staging/Prod, overridable via DOTNET_ENVIRONMENT);
`IBuildInfo` describes the immutable *build-time* identity. The
two answer different questions and don't overlap.

Tests cover detection, version-string stripping, and FormatVersionLine
for both HostKind values.
Adds three new diagnostic commands plus the inlining mechanism that
lets a parent command render flat in the interactive menu while
keeping a clean nested CLI surface.

Commands:

  revela info                     Revela summary panel (default action)
  revela info plugins             Lists installed plugins
  revela info plugins <name>      Plugin detail (Phase 2, plugin-provided)
  revela info themes              Lists installed themes (active marker)
  revela info themes <name>       Theme detail (Phase 2, theme-provided)

TUI rendering:

  Info
    Revela              ← virtual default-action entry
    Plugins →           ← only shown when plugins register sub-subcommands
    Themes →            ← only shown when themes register sub-subcommands
  > Exit

The menu group is registered with order 90 (bottom of main menu, above
Exit). Plugins/themes contribute per-package detail subcommands via the
existing multi-level `ParentCommand` mechanism ("info plugins" or
"info themes") — no SDK API change required.

Mechanism (CommandDescriptor + CommandOrderRegistry + MenuChoice):

  - New opt-in fields `InlineInMenu` and `InlineDefaultActionLabel`
    on CommandDescriptor (default false → zero impact on existing
    descriptors).
  - InteractiveMenuService.BuildGroupedSelectionPrompt expands inlined
    parents into a virtual default-action entry plus visible sub-
    subcommands, each with absolute path overrides so CLI dispatch
    remains correct.
  - Inlined subcommands without nested children are filtered out — a
    leaf entry with no extension provides no menu value beyond the
    parent's default action.

Bug fix bundled in:

  ShowMainMenuAsync had its own dispatch switch that hardcoded
  `[selection.Command.Name]` for the args path, ignoring
  CommandPathOverride from inlined entries. Clicking an inlined
  subcommand at top level produced `Unrecognized command or argument`
  from System.CommandLine. The top-level menu now routes through the
  same HandleMenuActionAsync as nested menus, honoring the override.

Plugin convention documented in .github/instructions/plugins.instructions.md:
  info subcommands are read-only diagnostics (no prompts, compact
  output suitable for bug-report copy-paste, safe without project).
The block-letter ASCII art "Revela" rendered at startup was off-brand
vs. the actual aperture wordmark — generic figlet output that has
nothing to do with the project's visual identity. It also added ~6
lines of friction on every interactive menu render, pushing real
content offscreen on small terminals and SSH sessions.

Removed: `LogoLines` array, `ShowLogo()`, `ClearAndShowLogo()`.

Welcome panel slimmed:

  - Header: "Welcome" → "Revela"
  - Removed: redundant "Version" line (now in `revela info`)
  - Removed: "Modern static site generator for photographers"
    tagline (already known to the user invoking the binary)
  - Kept: project/directory line and navigation hint

The first-run panel (`ShowFirstRunPanel`) is unchanged — that genuine
first-contact moment may welcome a future, brand-aligned visual
element, but the per-menu-render branding is gone.

Three call sites in InteractiveMenuService updated from
`ClearAndShowLogo()` to `ClearConsole()` were already shipped in the
previous commit alongside the menu-rendering refactor.

CHANGELOG documents all three #23 commits in one consolidated block.

Closes #23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a revela info command tree (root + plugins + themes), introduces the IBuildInfo SDK service (with HostKind) as the single source of truth for build identity, replaces System.CommandLine's default --version action with a human-readable host-kind-aware renderer, adds an opt-in "inline parent" rendering mode for the interactive menu (InlineInMenu / InlineDefaultActionLabel on CommandDescriptor), unifies top-level menu dispatch so CommandPathOverride is honored, and drops the off-brand ASCII logo from the welcome panel.

Changes:

  • New IBuildInfo SDK contract + BuildInfo implementation; --version now routes through BuildInfoVersionAction.
  • New info command tree with TUI inlining mechanic (MenuChoice.CommandPathOverride, CommandOrderRegistry.RegisterInlinedParent, fix for top-level menu dispatch ignoring the override).
  • Welcome panel slimmed (logo / version / tagline removed); CHANGELOG and plugin instructions updated; new tests/Cli project and Info command tests.

Reviewed changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/Sdk/Hosting/IBuildInfo.cs New SDK interface + HostKind enum.
src/Sdk/Abstractions/CommandDescriptor.cs Adds InlineInMenu / InlineDefaultActionLabel.
src/Cli/Hosting/BuildInfo.cs IBuildInfo implementation using AssemblyMetadata detection.
src/Cli/Hosting/HostBootstrap.cs Registers IBuildInfo, replaces --version action.
src/Cli/Hosting/HostExtensions.cs Wires InlineInMenu descriptors into CommandOrderRegistry; registers Info group.
src/Cli/Hosting/CoreCommandProvider.cs Registers info/plugins/themes commands.
src/Cli/Hosting/CommandOrderRegistry.cs Tracks inlined parents and their labels.
src/Cli/Hosting/CommandGroupRegistry.cs Adds Info group constant.
src/Cli/Hosting/MenuChoice.cs Adds CommandPathOverride and inlined default-action factory.
src/Cli/Hosting/InteractiveMenuService.cs Unifies top-level dispatch; renders inlined parents flat.
src/Cli/Hosting/ConsoleUI.cs Drops ASCII logo; slims welcome panel.
src/Commands/Info/InfoCommand.cs info parent + default-action summary panel.
src/Commands/Info/InfoPluginsCommand.cs info plugins listing.
src/Commands/Info/InfoThemesCommand.cs info themes listing with active marker.
src/Commands/ServiceCollectionExtensions.cs Registers Info commands.
src/Cli.Embedded/Cli.Embedded.csproj Adds Revela.HostKind=Embedded assembly metadata.
Spectara.Revela.slnx Adds tests/Cli project.
tests/Cli/* New tests project for BuildInfo.
tests/Commands/Info/* Tests for the three Info commands.
CHANGELOG.md Documents the unreleased changes.
.github/instructions/plugins.instructions.md Documents the info subcommand convention.

Comment thread CHANGELOG.md Outdated

### Changed

- **`revela --version` is now human-readable and host-kind aware** — the System.CommandLine default action is replaced with a renderer that prints `revela 1.0.0 (.NET 10.0.7)` (or `… — embedded build` for the standalone variant). Identical to the first line of `revela info`, so both surfaces report the same identifier. ([#23](https://github.com/Spectara/Revela/issues/23))
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch — fixed in 415d7cc. Suffix was indeed inverted in the CHANGELOG; the BuildInfo.FormatVersionLine switch correctly emits " — embedded build" for HostKind.Embedded.

The version-suffix " — embedded build" is appended for HostKind.Embedded
in BuildInfo.FormatVersionLine, not for Standalone. CHANGELOG had it
backwards.

Found in PR #71 review by copilot-pull-request-reviewer.
@kirkone kirkone merged commit cfdf4fa into main May 14, 2026
3 checks passed
@kirkone kirkone deleted the feat/23-revela-info branch May 14, 2026 18:24
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.

feat(cli): add revela info command tree (versions + plugins + themes)

2 participants