diff --git a/src/cycod/CommandLineCommands/ChatCommand.cs b/src/cycod/CommandLineCommands/ChatCommand.cs index 67e96cbc..94e17968 100644 --- a/src/cycod/CommandLineCommands/ChatCommand.cs +++ b/src/cycod/CommandLineCommands/ChatCommand.cs @@ -281,6 +281,10 @@ private string GetSystemPromptAdds() { skipAssistant = HandleHelpCommand(); } + else if (userPrompt == "/info") + { + skipAssistant = HandleInfoCommand(); + } else if (_cycoDmdCommandHandler?.IsCommand(userPrompt) == true) { skipAssistant = await HandleCycoDmdCommand(chat, userPrompt); @@ -354,6 +358,7 @@ private bool HandleHelpCommand() helpBuilder.AppendLine(" /save Save chat history to file"); helpBuilder.AppendLine(" /clear Clear chat history"); helpBuilder.AppendLine(" /cost Show token usage statistics"); + helpBuilder.AppendLine(" /info Display program information"); helpBuilder.AppendLine(" /help Show this help message"); helpBuilder.AppendLine(); @@ -429,6 +434,207 @@ private bool HandleHelpCommand() return true; } + private bool HandleInfoCommand() + { + var programNameUppercase = ProgramInfo.Name.ToUpper(); + var programDescription = ProgramInfo.Description; + var version = VersionInfo.GetVersion(); + + var bannerText = $"{programNameUppercase} - {programDescription}\n" + + "Copyright (c) 2025, Rob Chambers. All rights reserved.\n\n"; + ConsoleHelpers.WriteLine(bannerText, overrideQuiet: true); + + // Parse and display version components + var versionInfo = ParseVersionString(version); + ConsoleHelpers.WriteLine($"Version: {versionInfo.BaseVersion}", overrideQuiet: true); + if (versionInfo.IsDevBuild && !string.IsNullOrEmpty(versionInfo.Developer)) + { + ConsoleHelpers.WriteLine($"Developer: {versionInfo.Developer}", overrideQuiet: true); + } + if (!string.IsNullOrEmpty(versionInfo.BuildDate)) + { + ConsoleHelpers.WriteLine($"Built: {versionInfo.BuildDate}", overrideQuiet: true); + } + if (!string.IsNullOrEmpty(versionInfo.CommitHash)) + { + ConsoleHelpers.WriteLine($"Commit: {versionInfo.CommitHash}", overrideQuiet: true); + } + ConsoleHelpers.WriteLine("", overrideQuiet: true); + + // Display AGENTS.md file location if present + var agentsFile = AgentsFileHelpers.FindAgentsFile(); + if (agentsFile != null) + { + ConsoleHelpers.WriteLine($"AGENTS.md: {agentsFile}\n", overrideQuiet: true); + } + else + { + ConsoleHelpers.WriteLine("AGENTS.md: No AGENTS.md file found\n", overrideQuiet: true); + } + + return true; + } + + /// + /// Parses a version string into its components. + /// + /// + /// Expected version string format: + /// + /// {baseVersion}[-DEV-{developer}-{buildDate}][+{commitHash}] + /// + /// + /// + /// Components: + /// + /// + /// + /// baseVersion: The main version number (e.g., "1.0.0"). + /// + /// + /// + /// + /// -DEV: Optional marker indicating a development build. + /// + /// + /// + /// + /// {developer}: Optional developer identifier (e.g., "phs"). + /// + /// + /// + /// + /// {buildDate}: Optional build date and time in the format "yyyyMMdd.HHmm" (e.g., "20251023.1319"). + /// + /// + /// + /// + /// +{commitHash}: Optional commit hash (e.g., "4d348df87afc2a42e460aaa3d4056acee19894c4"). + /// + /// + /// + /// + /// + /// Parsing logic: + /// + /// + /// + /// If the version string contains a '+', the substring after '+' is treated as the commit hash. + /// + /// + /// + /// + /// The main part before '+' is split by '-', and if it contains "DEV", it is considered a development build. + /// + /// + /// + /// + /// If present, the developer and build date are extracted from the segments following "DEV". + /// + /// + /// + /// + /// The base version is always the first segment. + /// + /// + /// + /// + /// + /// Example: + /// + /// 1.0.0-DEV-phs-20251023.1319+4d348df87afc2a42e460aaa3d4056acee19894c4 + /// + /// + /// + /// The version string to parse. + /// + /// A tuple containing: + /// - BaseVersion: The main version number. + /// - IsDevBuild: True if this is a development build. + /// - Developer: The developer identifier, if present. + /// - BuildDate: The build date, if present. + /// - CommitHash: The commit hash, if present. + /// + private (string BaseVersion, bool IsDevBuild, string Developer, string BuildDate, string CommitHash) ParseVersionString(string version) + { + // Example: 1.0.0-DEV-phs-20251023.1319+4d348df87afc2a42e460aaa3d4056acee19894c4 + var baseVersion = version; + var isDevBuild = false; + var developer = string.Empty; + var buildDate = string.Empty; + var commitHash = string.Empty; + + try + { + // Extract commit hash (after +) + var plusIndex = version.IndexOf('+'); + if (plusIndex >= 0) + { + commitHash = version.Substring(plusIndex + 1); + if (commitHash.Length > 8) commitHash = commitHash.Substring(0, 8); // Short hash + version = version.Substring(0, plusIndex); + } + + // Split by dash to get parts + var parts = version.Split('-'); + if (parts.Length > 0) + { + baseVersion = parts[0]; // 1.0.0 + } + + // Check if this is a DEV build (typically 2nd part) + if (parts.Length >= 2) + { + isDevBuild = parts[1].Equals("DEV", StringComparison.OrdinalIgnoreCase); + } + + // Look for developer name (typically 3rd part, after version and DEV/config) + if (parts.Length >= 3) + { + developer = parts[2]; // phs + } + + // Look for date/time (typically 4th part) + if (parts.Length >= 4) + { + var dateTimePart = parts[3]; // 20251023.1319 + var dotIndex = dateTimePart.IndexOf('.'); + + if (dotIndex >= 0) + { + var datePart = dateTimePart.Substring(0, dotIndex); // 20251023 + var timePart = dateTimePart.Substring(dotIndex + 1); // 1319 + + // Parse date: YYYYMMDD + if (datePart.Length == 8) + { + var year = datePart.Substring(0, 4); + var month = datePart.Substring(4, 2); + var day = datePart.Substring(6, 2); + + // Parse time: HHMM + var time = string.Empty; + if (timePart.Length == 4) + { + var hour = timePart.Substring(0, 2); + var minute = timePart.Substring(2, 2); + time = $" {hour}:{minute}"; + } + + buildDate = $"{year}-{month}-{day}{time}"; + } + } + } + } + catch (Exception ex) + { + // If parsing fails, just return what we have + ConsoleHelpers.LogException(ex, "Failed to parse version string", showToUser: false); + } + + return (baseVersion, isDevBuild, developer, buildDate, commitHash); + } + private async Task CompleteChatStreamingAsync( FunctionCallingChat chat, string userPrompt,