diff --git a/Program.cs b/Program.cs index 213763c..76777ff 100644 --- a/Program.cs +++ b/Program.cs @@ -87,6 +87,34 @@ var toolDefs = new[] }, required = System.Array.Empty() } + }, + new + { + name = "delete_file", + description = "Löscht eine Datei oder ein leeres Verzeichnis.", + input_schema = new + { + type = "object", + properties = new Dictionary + { + ["path"] = new { type = "string", description = "Relativer Pfad zur Datei oder zum Verzeichnis" } + }, + required = new[] { "path" } + } + }, + new + { + name = "execute", + description = "Führt einen Shell-Befehl im Workspace-Verzeichnis aus. Gibt stdout und stderr zurück. Timeout: 30 Sekunden.", + input_schema = new + { + type = "object", + properties = new Dictionary + { + ["command"] = new { type = "string", description = "Shell-Befehl zum Ausführen" } + }, + required = new[] { "command" } + } } }; @@ -100,7 +128,7 @@ string ResolvePath(string relativePath) return full; } -string ExecuteTool(string name, JsonElement input) +async Task ExecuteTool(string name, JsonElement input) { switch (name) { @@ -146,6 +174,61 @@ string ExecuteTool(string name, JsonElement input) entries.Add(Path.GetRelativePath(workspaceRoot, file)); return entries.Count == 0 ? "(leer)" : string.Join("\n", entries); } + case "delete_file": + { + var path = ResolvePath(input.GetProperty("path").GetString() ?? ""); + if (File.Exists(path)) + { + File.Delete(path); + return $"Datei gelöscht: {Path.GetRelativePath(workspaceRoot, path)}"; + } + if (Directory.Exists(path)) + { + Directory.Delete(path, recursive: false); + return $"Verzeichnis gelöscht: {Path.GetRelativePath(workspaceRoot, path)}"; + } + return $"Fehler: Nicht gefunden: {Path.GetRelativePath(workspaceRoot, path)}"; + } + case "execute": + { + var command = input.GetProperty("command").GetString() ?? ""; + var psi = new System.Diagnostics.ProcessStartInfo + { + FileName = "/bin/bash", + WorkingDirectory = workspaceRoot, + RedirectStandardInput = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + using var proc = System.Diagnostics.Process.Start(psi); + if (proc == null) return "Fehler: Prozess konnte nicht gestartet werden"; + await proc.StandardInput.WriteAsync(command); + proc.StandardInput.Close(); + var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); + try + { + await proc.WaitForExitAsync(cts.Token); + } + catch (OperationCanceledException) + { + proc.Kill(entireProcessTree: true); + return "Fehler: Timeout nach 30 Sekunden - Prozess abgebrochen"; + } + var stdout = await proc.StandardOutput.ReadToEndAsync(); + var stderr = await proc.StandardError.ReadToEndAsync(); + var result = new StringBuilder(); + if (!string.IsNullOrEmpty(stdout)) result.Append(stdout); + if (!string.IsNullOrEmpty(stderr)) + { + if (result.Length > 0) result.Append("\n--- stderr ---\n"); + result.Append(stderr); + } + if (result.Length == 0) result.Append($"(exit code {proc.ExitCode})"); + else if (proc.ExitCode != 0) result.Append($"\n(exit code {proc.ExitCode})"); + return result.ToString(); + } default: return $"Fehler: Unbekanntes Tool: {name}"; } @@ -374,7 +457,7 @@ app.MapPost("/api/chat", async (HttpRequest req, HttpResponse res, IHttpClientFa // Tool sofort ausführen und streamen string toolResult; bool isError = false; - try { toolResult = ExecuteTool(currentToolName, inputEl); } + try { toolResult = await ExecuteTool(currentToolName, inputEl); } catch (Exception ex) { toolResult = $"Fehler: {ex.Message}"; isError = true; } executedTools.Add((currentToolId, toolResult, isError));