feat(cli): add revela info command tree (versions + plugins + themes)#71
Conversation
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
There was a problem hiding this comment.
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
IBuildInfoSDK contract +BuildInfoimplementation;--versionnow routes throughBuildInfoVersionAction. - New
infocommand 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/Cliproject 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. |
|
|
||
| ### 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)) |
There was a problem hiding this comment.
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.
Closes #23
Adds the
revela infocommand tree with TUI inlining, exposes build identity via a newIBuildInfoSDK service, replaces System.CommandLine's default--versionaction 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)
9db74fa—feat(sdk): add IBuildInfo + HostKind for build identityNew
Spectara.Revela.Sdk.Hosting.IBuildInfointerface +HostKindenum. Implementation reads the host kind from theRevela.HostKindAssemblyMetadataattribute set inCli.Embedded.csproj(sidesteps theAssemblyName="revela"collision that makes name-based detection impossible). System.CommandLine's--versionaction is replaced so bothrevela --versionand the first line ofrevela infoprint the same human-readable identifier:New tests project
tests/Cli/with 9 cases covering detection, version-stripping, andFormatVersionLinefor both host kinds.42f35a4—feat(cli): add revela info command tree with TUI inliningThree 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 onCommandDescriptor(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-levelParentCommandmechanism — no SDK API change required forinfo plugins <name>/info themes <name>.Bug fix bundled:
ShowMainMenuAsynchad its own dispatch switch hardcoding[selection.Command.Name]for the args path, ignoringCommandPathOverridefrom inlined entries. The top-level menu now routes through the sameHandleMenuActionAsyncas nested menus, honoring the override.5f856ee—refactor(cli): drop ASCII logo, slim welcome panelRemoves
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 headerWelcome→Revela; redundantVersionline andModern static site generator…tagline removed. First-run panel unchanged. CHANGELOG documents all three commits in one consolidated[Unreleased]block.Verification
dotnet builddotnet testtests/Cli, 6 new intests/Commands/Info)dotnet format --verify-no-changesrevela --version(Cli)revela 1.0.0 (.NET 10.0.7)revela --version(Cli.Embedded)revela 1.0.0 (.NET 10.0.7) — embedded buildrevela info plugins(Embedded)revela info themes(showcase)★ Luminaactive marker correct--versionOKReviewer focus areas (skeptic's checklist)
MenuChoice.CommandPathOverride+ the new lookup methods onCommandOrderRegistry(IsInlinedParent,GetInlineDefaultActionLabel). Edge case not validated: inlined parents registered withParentCommand: "..."(i.e. nested rather than top-level) — currently treated as a no-op silently. Acceptable for now; worth athrow new InvalidOperationException(...)later if the pattern grows.ShowMainMenuAsync→HandleMenuActionAsync) changes the routing for every main-menu selection, not just the newinfoentries. 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.BuildInfoVersionActionusesSynchronousCommandLineAction. If you ever flip Cli.Embedded toPublishTrimmed/AOT (feat(cli): Enable PublishTrimmed for Cli.Embedded (Phase 2 of #40) #50), theAssemblyMetadataAttributereflection inBuildInfoshould remain trim-safe (SDK already has<IsTrimmable>true</IsTrimmable>+EnableTrimAnalyzer), but worth a fresh trim-analyzer pass when that work happens.OrdinalIgnoreCasefor the name comparison — liberal on purpose since theme config names may diverge in case from the loaded theme metadata.Out of scope (deferred)
revela info plugins <name>) — Phase 2, plugin authors contribute viaParentCommand: "info plugins"--jsonflag for machine-readable outputIPackage.GetDiagnostics()SDK extension for richer per-package infoIBuildInfoextensions (IsTrimmed,IsAot,BuildDate) — additive when a concrete consumer appears (non-breaking)