Windows Shell-Ausführung: Temp-Script statt stdin/ShellArguments, background_execute Tool, konfigurierbarer Timeout
Execute-Tools (execute, background_execute, SessionEndpoint.HandleExec): - Windows: Befehl in temp .cmd-Datei statt cmd.exe stdin (interaktiver Modus, &-Parsing, Mehr?-Prompt) oder ShellArguments (falsches \"-Escaping für cmd.exe) - Linux: weiterhin stdin an /bin/bash (funktioniert zuverlässig) - Script-Cleanup in allen Codepfaden (Success, Timeout, Error) Neues Tool background_execute: - Startet Prozesse losgelöst ohne Warten, gibt PID zurück - Temp-Script-Ansatz: funktioniert auch mit mehrzeiligen Befehlen - Windows: .cmd mit del "%~f0" (Selbstlöschung) - Linux: .sh mit rm -f (Selbstlöschung) Konfigurierbarer Execute-Timeout: - Neues Server-Setting ExecuteTimeout (Default: 180s) - IConfiguration in ToolService injected - Tool-Description zeigt aktuellen Timeout dynamisch an SessionEndpoint.HandleExec (foreground): - Pipe-Deadlock-Fix: ReadToEndAsync vor WaitForExitAsync - Gleicher Temp-Script-Ansatz wie ToolService WorkspaceHelper.ShellArguments() entfernt (keine Aufrufer mehr)
This commit is contained in:
1 parent
3e590a6d03
commit
d6d7b6c04f
5 files changed
+102
-20
No files matched your search
@@ -325,22 +325,31 @@ public static class SessionEndpoint
|
||||
// Synchron ausführen, auf Ergebnis warten
|
||||
try
|
||||
{
|
||||
string scriptPath = null;
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = WorkspaceHelper.ShellExecutable,
|
||||
WorkingDirectory = workingDir,
|
||||
RedirectStandardInput = !WorkspaceHelper.IsWindows,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
if (WorkspaceHelper.IsWindows)
|
||||
psi.Arguments = WorkspaceHelper.ShellArguments(command);
|
||||
{
|
||||
scriptPath = Path.Combine(Path.GetTempPath(), $"gott_exec_{Guid.NewGuid():N}.cmd");
|
||||
await System.IO.File.WriteAllTextAsync(scriptPath, $"@echo off\r\n{command}\r\n");
|
||||
psi.Arguments = $"/c \"{scriptPath}\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
psi.RedirectStandardInput = true;
|
||||
}
|
||||
|
||||
using var proc = System.Diagnostics.Process.Start(psi);
|
||||
if (proc == null)
|
||||
{
|
||||
if (scriptPath != null) try { System.IO.File.Delete(scriptPath); } catch { }
|
||||
ctx.Response.StatusCode = 500;
|
||||
await ctx.Response.WriteAsJsonAsync(new { error = "Prozess konnte nicht gestartet werden" });
|
||||
return;
|
||||
@@ -352,6 +361,9 @@ public static class SessionEndpoint
|
||||
proc.StandardInput.Close();
|
||||
}
|
||||
|
||||
var stdoutTask = proc.StandardOutput.ReadToEndAsync();
|
||||
var stderrTask = proc.StandardError.ReadToEndAsync();
|
||||
|
||||
using var cts = new System.Threading.CancellationTokenSource(TimeSpan.FromSeconds(30));
|
||||
try
|
||||
{
|
||||
@@ -360,12 +372,14 @@ public static class SessionEndpoint
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
proc.Kill(entireProcessTree: true);
|
||||
if (scriptPath != null) try { System.IO.File.Delete(scriptPath); } catch { }
|
||||
await ctx.Response.WriteAsJsonAsync(new { status = "timeout", output = "Timeout nach 30 Sekunden", exitCode = -1 });
|
||||
return;
|
||||
}
|
||||
if (scriptPath != null) try { System.IO.File.Delete(scriptPath); } catch { }
|
||||
|
||||
var stdout = await proc.StandardOutput.ReadToEndAsync();
|
||||
var stderr = await proc.StandardError.ReadToEndAsync();
|
||||
var stdout = await stdoutTask;
|
||||
var stderr = await stderrTask;
|
||||
|
||||
var output = new System.Text.StringBuilder();
|
||||
if (!string.IsNullOrEmpty(stdout)) output.Append(stdout);
|
||||
|
||||
Reference in new issue
Block a user