using System.Diagnostics; using Spectre.Console; using Toak.Configuration; using Toak.Core.Skills; namespace Toak.Commands; public static class OnboardCommand { public static async Task ExecuteAsync(bool verbose) { Core.Logger.Verbose = verbose; var configManager = new ConfigManager(); var config = configManager.LoadConfig(); AnsiConsole.Write(new FigletText("Toak").Color(Color.Green)); AnsiConsole.MarkupLine("[grey]Welcome to the Toak configuration wizard.[/]"); AnsiConsole.WriteLine(); config.LlmProvider = AnsiConsole.Prompt( new SelectionPrompt() .Title("Select [green]LLM Provider[/]:") .AddChoices(new[] { "groq", "together", "cerebras", "fireworks" }) .UseConverter(c => c == "groq" ? "Groq (Default)" : c == "together" ? "Together AI" : c == "cerebras" ? "Cerebras" : "Fireworks AI")); if (config.LlmProvider == "together") { config.TogetherApiKey = AnsiConsole.Prompt( new TextPrompt("Together AI API Key:") .DefaultValue(string.IsNullOrWhiteSpace(config.TogetherApiKey) ? "" : config.TogetherApiKey) .AllowEmpty()); config.LlmModel = AnsiConsole.Prompt( new SelectionPrompt() .Title("Select [green]LLM Model[/]:") .AddChoices(new[] { "meta-llama/Llama-3.3-70B-Instruct-Turbo", "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", "openai/gpt-oss-20b" })); } else if (config.LlmProvider == "cerebras") { config.CerebrasApiKey = AnsiConsole.Prompt( new TextPrompt("Cerebras API Key:") .DefaultValue(string.IsNullOrWhiteSpace(config.CerebrasApiKey) ? "" : config.CerebrasApiKey) .AllowEmpty()); config.LlmModel = AnsiConsole.Prompt( new SelectionPrompt() .Title("Select [green]LLM Model[/]:") .AddChoices(new[] { "llama3.1-8b", "gpt-oss-120b" })); } else if (config.LlmProvider == "fireworks") { config.FireworksApiKey = AnsiConsole.Prompt( new TextPrompt("Fireworks API Key:") .DefaultValue(string.IsNullOrWhiteSpace(config.FireworksApiKey) ? "" : config.FireworksApiKey) .AllowEmpty()); config.LlmModel = AnsiConsole.Prompt( new SelectionPrompt() .Title("Select [green]LLM Model[/]:") .AddChoices(new[] { "accounts/fireworks/models/deepseek-v3p1", "fireworks/gpt-oss-120b", "fireworks/deepseek-v3p2", "fireworks/qwen3-8b", "fireworks/minimax-m2p5" }) .UseConverter(c => c.Split('/').Last())); } else { config.GroqApiKey = AnsiConsole.Prompt( new TextPrompt("Groq API Key:") .DefaultValue(string.IsNullOrWhiteSpace(config.GroqApiKey) ? "" : config.GroqApiKey) .AllowEmpty()); config.LlmModel = AnsiConsole.Prompt( new SelectionPrompt() .Title("Select [green]LLM Model[/]:") .AddChoices(new[] { "openai/gpt-oss-20b", "llama-3.1-8b-instant", "llama-3.3-70b-versatile" }) .UseConverter(c => c == "openai/gpt-oss-20b" ? "openai/gpt-oss-20b (Fastest)" : c == "llama-3.1-8b-instant" ? "llama-3.1-8b-instant (Cheapest)" : "llama-3.3-70b-versatile (More Accurate)")); if (config.LlmModel.Contains(" ")) config.LlmModel = config.LlmModel.Split(' ')[0]; } config.ReasoningEffort = AnsiConsole.Prompt( new SelectionPrompt() .Title("Select [green]Reasoning Effort[/]:") .AddChoices(new[] { "none", "low" }) .UseConverter(c => c == "none" ? "None (Standard)" : "Low (Moderate Reasoning)")); config.WhisperProvider = AnsiConsole.Prompt( new SelectionPrompt() .Title("Select [green]Whisper Provider[/]:") .AddChoices(new[] { "groq", "fireworks" }) .UseConverter(c => c == "groq" ? "Groq (Default)" : "Fireworks AI")); if (config.WhisperProvider == "fireworks") { if (string.IsNullOrWhiteSpace(config.FireworksApiKey)) { config.FireworksApiKey = AnsiConsole.Prompt( new TextPrompt("Fireworks API Key (required for Whisper):") .DefaultValue("") .AllowEmpty()); } config.WhisperModel = AnsiConsole.Prompt( new SelectionPrompt() .Title("Select [green]Whisper Model[/]:") .AddChoices(new[] { "fireworks/whisper-v3", "fireworks/whisper-v3-turbo" })); } else { if (string.IsNullOrWhiteSpace(config.GroqApiKey)) { config.GroqApiKey = AnsiConsole.Prompt( new TextPrompt("Groq API Key (required for Whisper):") .DefaultValue("") .AllowEmpty()); } config.WhisperModel = AnsiConsole.Prompt( new SelectionPrompt() .Title("Select [green]Whisper Model[/]:") .AddChoices(new[] { "whisper-large-v3", "whisper-large-v3-turbo" }) .UseConverter(c => c == "whisper-large-v3" ? "whisper-large-v3 (Accurate)" : "whisper-large-v3-turbo (Fast)")); } config.WhisperLanguage = AnsiConsole.Prompt( new TextPrompt("Microphone Spoken Language (e.g. en, es, zh):") .DefaultValue(string.IsNullOrWhiteSpace(config.WhisperLanguage) ? "en" : config.WhisperLanguage) .AllowEmpty() .Validate(lang => { if (string.IsNullOrWhiteSpace(lang)) return ValidationResult.Success(); if (lang.Contains(",") || lang.Contains(" ")) return ValidationResult.Error("[red]Please provide only one language code (e.g., 'en' not 'en, es')[/]"); return ValidationResult.Success(); })); var sessionType = Environment.GetEnvironmentVariable("XDG_SESSION_TYPE")?.ToLowerInvariant(); var typingBackends = sessionType == "wayland" ? new[] { "wtype", "ydotool", "xdotool" } : new[] { "xdotool", "ydotool" }; config.TypingBackend = AnsiConsole.Prompt( new SelectionPrompt() .Title($"Select [green]Typing Backend[/] (Detected: {sessionType}):") .AddChoices(typingBackends)); config.AudioBackend = AnsiConsole.Prompt( new SelectionPrompt() .Title("Select [green]Audio Recording Backend[/]:") .AddChoices(new[] { "pw-record", "ffmpeg" }) .UseConverter(c => c == "pw-record" ? "pw-record (Default PipeWire)" : "ffmpeg (Universal PulseAudio)")); var availableSkills = SkillRegistry.AllSkills.Select(s => s.Name).ToList(); if (availableSkills.Any()) { config.ActiveSkills = AnsiConsole.Prompt( new MultiSelectionPrompt() .Title("Select [green]Active Skills[/]:") .NotRequired() .InstructionsText("[grey](Press [blue][/] to toggle a skill, [green][/] to accept)[/]") .AddChoices(availableSkills)); } configManager.SaveConfig(config); AnsiConsole.MarkupLine("\n[bold green]Configuration saved successfully![/]"); try { var processInfo = new ProcessStartInfo("systemctl", "--user restart toak.service") { CreateNoWindow = true, UseShellExecute = false }; Process.Start(processInfo)?.WaitForExit(); AnsiConsole.MarkupLine("[grey]Restarted Toak daemon service.[/]"); } catch (Exception ex) { Core.Logger.LogDebug($"Failed to restart toak service: {ex.Message}"); } } }