using Spectre.Console; namespace AnchorCli; internal static class SetupTui { public static void Run() { var config = AnchorConfig.Load(); AnsiConsole.Write(new Rule("[cornflowerblue]anchor setup[/]").LeftJustified()); AnsiConsole.WriteLine(); // ── API Key ─────────────────────────────────────────────────── string maskedKey = config.ApiKey.Length > 8 ? config.ApiKey[..4] + new string('*', config.ApiKey.Length - 8) + config.ApiKey[^4..] : config.ApiKey.Length > 0 ? "****" : "[dim](not set)[/]"; AnsiConsole.MarkupLine($" Current API key: [dim]{Markup.Escape(maskedKey)}[/]"); string newKey = AnsiConsole.Prompt( new TextPrompt(" New API key [dim](Enter to keep)[/]:") .AllowEmpty() .Secret('*')); if (!string.IsNullOrWhiteSpace(newKey)) config.ApiKey = newKey.Trim(); AnsiConsole.WriteLine(); // ── Provider ──────────────────────────────────────────────────── var providers = new List<(string Value, string Description)> { ("openrouter", "default, pricing support"), ("groq", "high-speed inference"), ("ollama", "local, no auth required"), ("openai", "official OpenAI API"), ("custom", "generic OpenAI-compatible endpoint") }; string currentProvider = config.Provider ?? "openrouter"; AnsiConsole.MarkupLine($" Current provider: [cyan]{Markup.Escape(currentProvider)}[/]"); var selectedProviderChoice = AnsiConsole.Prompt( new SelectionPrompt<(string Value, string Description)>() .Title(" Select a provider:") .UseConverter(p => p.Value + (string.IsNullOrEmpty(p.Description) ? "" : $" [dim]({p.Description})[/]")) .AddChoices(providers)); config.Provider = selectedProviderChoice.Value; if (config.Provider == "custom") { string customEndpoint = AnsiConsole.Prompt( new TextPrompt(" Enter endpoint URL:") .DefaultValue(config.Endpoint) .AllowEmpty()); if (!string.IsNullOrWhiteSpace(customEndpoint)) { config.Endpoint = customEndpoint.Trim(); } } else { config.Endpoint = config.Provider.ToLowerInvariant() switch { "openrouter" => "https://openrouter.ai/api/v1", "groq" => "https://api.groq.com/openai/v1", "ollama" => "http://localhost:11434/v1", "openai" => "https://api.openai.com/v1", _ => config.Endpoint }; } AnsiConsole.WriteLine(); // ── Model ───────────────────────────────────────────────────── AnsiConsole.MarkupLine($" Current model: [cyan]{Markup.Escape(config.Model)}[/]"); var models = config.Provider.ToLowerInvariant() switch { "groq" => new List<(string Value, string Description)> { ("llama-3.3-70b-versatile", "fast, powerful"), ("llama-3.1-8b-instant", "very fast"), ("mixtral-8x7b-32768", "sparse MoE"), ("gemma2-9b-it", "Google's Gemma"), ("Custom...", "") }, "ollama" => new List<(string Value, string Description)> { ("llama3.2", "Meta's Llama 3.2"), ("qwen2.5", "Alibaba Qwen"), ("mistral", "Mistral AI"), ("codellama", "code-focused"), ("Custom...", "") }, "openai" => new List<(string Value, string Description)> { ("gpt-4o", "most capable"), ("gpt-4o-mini", "fast, affordable"), ("o1-preview", "reasoning model"), ("Custom...", "") }, _ => new List<(string Value, string Description)> { ("qwen/qwen3.5-397b-a17b", "smart, expensive"), ("qwen/qwen3.5-122b-a10b", "faster"), ("qwen/qwen3.5-27b", "fast"), ("qwen/qwen3.5-flash-02-23", "cloud, fast"), ("qwen/qwen3.5-plus-02-15", "cloud, smart"), ("Custom...", "") } }; string selectedModel = AnsiConsole.Prompt( new SelectionPrompt<(string Value, string Description)>() .Title(" Select a model:") .UseConverter(m => m.Value + (string.IsNullOrEmpty(m.Description) ? "" : $" [dim]({m.Description})[/]")) .AddChoices(models)) .Value; if (selectedModel == "Custom...") { string customModel = AnsiConsole.Prompt( new TextPrompt(" Enter custom model name:") .AllowEmpty()); if (!string.IsNullOrWhiteSpace(customModel)) config.Model = customModel.Trim(); } else { config.Model = selectedModel; } // ── Save ────────────────────────────────────────────────────── AnsiConsole.WriteLine(); config.Save(); AnsiConsole.MarkupLine("[green]✓ Config saved.[/]"); } }