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,