using System.Diagnostics; namespace AgentWikiUi.Core; // Unico punto di avvio dei motori, condiviso da CLI e GUI. static class EngineRunner { public static ProcessStartInfo CreateStart(Engine engine, string prompt, bool captured, string? sessionId = null, bool resume = false, string model = "", string effort = "") { var psi = new ProcessStartInfo(engine.Executable) { WorkingDirectory = AppContext.BaseDirectory, // mai la cwd del chiamante né Assembly.Location (vuoto in single-file) UseShellExecute = false, RedirectStandardInput = true, // chiuso subito dal chiamante: evita l'attesa di stdin del motore RedirectStandardOutput = captured, RedirectStandardError = captured, CreateNoWindow = true, }; foreach (var a in engine.BuildArgs(prompt, sessionId, resume, model, effort, structured: captured)) psi.ArgumentList.Add(a); return psi; } // CLI: stdout/stderr ereditati (streaming), exit code propagato, 127 se l'eseguibile manca. public static int RunInherited(Engine engine, string prompt) { try { using var p = Process.Start(CreateStart(engine, prompt, captured: false))!; p.StandardInput.Close(); p.WaitForExit(); return p.ExitCode; } catch (System.ComponentModel.Win32Exception) { Console.Error.WriteLine($"'{engine.Executable}' non trovato nel PATH."); return 127; } } // GUI: output catturato e interpretato dal motore. Win32Exception se l'eseguibile non è nel PATH. public static async Task RunCapturedAsync(Engine engine, string prompt, string? sessionId, bool resume, string model, string effort) { using var p = Process.Start(CreateStart(engine, prompt, captured: true, sessionId, resume, model, effort))!; p.StandardInput.Close(); var o = p.StandardOutput.ReadToEndAsync(); var e = p.StandardError.ReadToEndAsync(); await p.WaitForExitAsync(); return engine.Parse(p.ExitCode, await o, await e); } }