using System.Diagnostics; using System.Windows.Forms; if (args.Length == 0) { ApplicationConfiguration.Initialize(); Application.Run(new Gui()); return 0; } var psi = NewClaude(string.Join(' ', args)); try { using var p = Process.Start(psi)!; // stdout/stderr ereditati: streaming in tempo reale p.StandardInput.Close(); p.WaitForExit(); return p.ExitCode; } catch (System.ComponentModel.Win32Exception) { Console.Error.WriteLine("'claude' non trovato nel PATH."); return 127; } static ProcessStartInfo NewClaude(string prompt) { var psi = new ProcessStartInfo("claude") { WorkingDirectory = AppContext.BaseDirectory, UseShellExecute = false, RedirectStandardInput = true, // evita l'attesa di stdin di claude }; psi.ArgumentList.Add("-p"); psi.ArgumentList.Add(prompt); return psi; } class Gui : Form { readonly TextBox prompt = new() { Dock = DockStyle.Top, Multiline = true, Height = 120, AcceptsReturn = true }; readonly Button send = new() { Dock = DockStyle.Top, Text = "Invia a Claude", Height = 32 }; readonly TextBox output = new() { Dock = DockStyle.Fill, Multiline = true, ReadOnly = true, ScrollBars = ScrollBars.Vertical }; record Model(string Label, string Id) { public override string ToString() => Label; } static readonly Model[] Models = [ new("Fable 5.1 (claude-fable-5-1)", "claude-fable-5-1"), new("Opus 5.5 (claude-opus-5-5)", "claude-opus-5-5"), new("Sonnet 5.5 (claude-sonnet-5-5)", "claude-sonnet-5-5"), new("Haiku 5.5 (claude-haiku-5-5)", "claude-haiku-5-5"), ]; const string Default = "predefinito"; readonly ComboBox model = new() { DropDownStyle = ComboBoxStyle.DropDown, Width = 300 }; // editabile: ID completo readonly ComboBox effort = new() { DropDownStyle = ComboBoxStyle.DropDownList, Width = 100 }; public Gui() { Text = "LlmRun"; Width = 1000; Height = 700; model.Items.Add(Default); model.Items.AddRange(Models); model.SelectedIndex = 0; effort.Items.AddRange([Default, "low", "medium", "high", "xhigh", "max"]); effort.SelectedIndex = 0; var settings = new FlowLayoutPanel { Dock = DockStyle.Top, Height = 32, Padding = new Padding(4) }; settings.Controls.AddRange([new Label { Text = "Modello", AutoSize = true, Margin = new Padding(0, 6, 0, 0) }, model, new Label { Text = "Effort", AutoSize = true, Margin = new Padding(8, 6, 0, 0) }, effort]); Controls.Add(output); Controls.Add(send); Controls.Add(prompt); Controls.Add(settings); // Fill per primo: l'ordine inverso dei Dock send.Click += async (_, _) => await Run(); } async Task Run() { if (string.IsNullOrWhiteSpace(prompt.Text)) return; send.Enabled = false; output.Clear(); try { var psi = NewClaude(prompt.Text); using var p = Process.Start(psi)!; p.StandardInput.Close(); void Append(string? l) { if (l != null) BeginInvoke(() => output.AppendText(l + Environment.NewLine)); } p.OutputDataReceived += (_, e) => Append(e.Data); p.ErrorDataReceived += (_, e) => Append(e.Data); p.BeginOutputReadLine(); p.BeginErrorReadLine(); await p.WaitForExitAsync(); output.AppendText($"[exit {p.ExitCode}]"); } catch (System.ComponentModel.Win32Exception) { output.Text = "'claude' non trovato nel PATH."; } finally { send.Enabled = true; } } ProcessStartInfo NewClaude(string prompt) { var psi = new ProcessStartInfo("claude") { WorkingDirectory = AppContext.BaseDirectory, UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, }; psi.ArgumentList.Add("-p"); psi.ArgumentList.Add(prompt); foreach (var (flag, value) in new[] { ("--model", model.SelectedItem is Model m ? m.Id : model.Text.Trim()), ("--effort", effort.Text) }) if (value != "" && value != Default) { psi.ArgumentList.Add(flag); psi.ArgumentList.Add(value); } return psi; } }