From c275eeef704aa2017c4f48d9320b18872d87854a Mon Sep 17 00:00:00 2001 From: Gaoyang Date: Wed, 16 Sep 2026 10:52:44 +0800 Subject: [PATCH] feat: show app version footer in watch view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a small "aimon vX.Y.Z · " footer under the watch command's continuously refreshed output, so users can tell which build they're running without checking separately. One-shot commands keep unchanged output since their result is short-lived and the footer would just add noise. --- src/AIUsageMonitor.Cli/Commands/WatchCommand.cs | 16 ++++++++++++++-- .../Rendering/SpectreRenderer.cs | 13 +++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/AIUsageMonitor.Cli/Commands/WatchCommand.cs b/src/AIUsageMonitor.Cli/Commands/WatchCommand.cs index 802a697..76f2763 100644 --- a/src/AIUsageMonitor.Cli/Commands/WatchCommand.cs +++ b/src/AIUsageMonitor.Cli/Commands/WatchCommand.cs @@ -113,6 +113,7 @@ public static Command Create(DataService dataService, IUpdateChecker updateCheck // visible while it runs rather than only after it exits. var updateInfo = await updateChecker.CheckForUpdateAsync(ct); var updateNotice = UpdateNotice.BuildRenderable(updateInfo); + var versionFooter = SpectreRenderer.BuildVersionFooter(); IRenderable BuildCurrent(IProgress? progress = null) { @@ -151,8 +152,19 @@ IRenderable BuildLimits(IProgress? progress) ClearScreen(); - IRenderable WithUpdateNotice(IRenderable content) => - updateNotice is null ? content : new Rows(content, updateNotice); + IRenderable WithUpdateNotice(IRenderable content) + { + var rows = new List { content }; + if (updateNotice is not null) + { + rows.Add(updateNotice); + } + if (versionFooter is not null) + { + rows.Add(versionFooter); + } + return rows.Count == 1 ? content : new Rows(rows); + } var current = view == "limits" ? WithUpdateNotice(SpectreRenderer.BuildUsageLimits(lastSessionWindow!, lastWeekWindow!, effectiveSessionTokenLimit, effectiveWeekTokenLimit, recalibrationEnabled, effectiveSessionResetAt is not null)) diff --git a/src/AIUsageMonitor.Cli/Rendering/SpectreRenderer.cs b/src/AIUsageMonitor.Cli/Rendering/SpectreRenderer.cs index 91a4696..55f155d 100644 --- a/src/AIUsageMonitor.Cli/Rendering/SpectreRenderer.cs +++ b/src/AIUsageMonitor.Cli/Rendering/SpectreRenderer.cs @@ -1,4 +1,5 @@ using AIUsageMonitor.Core.Models; +using AIUsageMonitor.UpdateCheck; using Spectre.Console; using Spectre.Console.Rendering; @@ -364,6 +365,18 @@ public static IRenderable BuildUsageLimits( /// The session statistics data to render. public static void RenderSessionStats(SessionStats stats) => AnsiConsole.Write(BuildSessionStats(stats)); + /// + /// Builds a footer line naming the application and its running version, for display under + /// the continuously refreshed watch view only - a one-shot command's output is short + /// enough that the version line would just be noise under it. + /// + /// A grey markup line, or if the version could not be determined. + public static IRenderable? BuildVersionFooter() + { + var version = AppVersion.GetCurrent(); + return version is null ? null : new Markup($"[grey]aimon v{version} · https://github.com/coldhighsun/AIUsageMonitor[/]"); + } + /// /// Builds a titled table with a single row of centered stat values, one column per stat. ///