feat: Windows-Kompatibilität
- WorkspaceHelper: Zentrale Hilfsmethoden (IsWindows, TempDir, IsSubPathOf, GetRelativePath, ShellExecutable, ShellArguments) - ToolService: execute nutzt cmd.exe auf Windows, GetRelativePath mit Forward-Slashes, IsSubPathOf für case-insensitive Pfadprüfung - SessionEndpoint: /tmp → Path.GetTempPath(), bash → cmd.exe, Fire-and-forget via .bat statt systemd-run auf Windows - ChatService: /tmp → WorkspaceHelper.TempDir - MemoryService: IsSubPathOf + GetRelativePath - WorkspaceEndpoint: HandleBrowse zeigt Laufwerke auf Windows, IsSubPathOf statt StartsWith - InfoEndpoint: gott.exe auf Windows, isWindows-Flag in API-Response - Frontend: File-Explorer mit Laufwerks-Navigation auf Windows
This commit is contained in:
1 parent
79899a6981
commit
5d090e160b
9 files changed
+155
-61
No files matched your search
+22
-17
@@ -300,7 +300,7 @@ public class ToolService
|
||||
return "Fehler: Kein Workspace konfiguriert";
|
||||
var path = ResolvePath(input.GetProperty("path").GetString() ?? "", workspace);
|
||||
if (!File.Exists(path))
|
||||
return $"Fehler: Datei nicht gefunden: {Path.GetRelativePath(workspace, path)}";
|
||||
return $"Fehler: Datei nicht gefunden: {WorkspaceHelper.GetRelativePath(workspace, path)}";
|
||||
return File.ReadAllText(path);
|
||||
}
|
||||
case "write_file":
|
||||
@@ -312,7 +312,7 @@ public class ToolService
|
||||
if (dir != null) Directory.CreateDirectory(dir);
|
||||
var content = input.GetProperty("content").GetString() ?? "";
|
||||
File.WriteAllText(path, content);
|
||||
return $"Datei geschrieben: {Path.GetRelativePath(workspace, path)} ({content.Length} Zeichen)";
|
||||
return $"Datei geschrieben: {WorkspaceHelper.GetRelativePath(workspace, path)} ({content.Length} Zeichen)";
|
||||
}
|
||||
case "edit_file":
|
||||
{
|
||||
@@ -320,7 +320,7 @@ public class ToolService
|
||||
return "Fehler: Kein Workspace konfiguriert";
|
||||
var path = ResolvePath(input.GetProperty("path").GetString() ?? "", workspace);
|
||||
if (!File.Exists(path))
|
||||
return $"Fehler: Datei nicht gefunden: {Path.GetRelativePath(workspace, path)}";
|
||||
return $"Fehler: Datei nicht gefunden: {WorkspaceHelper.GetRelativePath(workspace, path)}";
|
||||
var fileContent = File.ReadAllText(path);
|
||||
var oldText = input.GetProperty("old_text").GetString() ?? "";
|
||||
var newText = input.GetProperty("new_text").GetString() ?? "";
|
||||
@@ -328,7 +328,7 @@ public class ToolService
|
||||
return "Fehler: old_text nicht in der Datei gefunden. Exakter Match nötig.";
|
||||
fileContent = fileContent.Replace(oldText, newText);
|
||||
File.WriteAllText(path, fileContent);
|
||||
return $"Datei bearbeitet: {Path.GetRelativePath(workspace, path)}";
|
||||
return $"Datei bearbeitet: {WorkspaceHelper.GetRelativePath(workspace, path)}";
|
||||
}
|
||||
case "list_files":
|
||||
{
|
||||
@@ -336,12 +336,12 @@ public class ToolService
|
||||
return "Fehler: Kein Workspace konfiguriert";
|
||||
var path = ResolvePath(input.TryGetProperty("path", out var p) ? p.GetString() ?? "" : "", workspace);
|
||||
if (!Directory.Exists(path))
|
||||
return $"Fehler: Verzeichnis nicht gefunden: {Path.GetRelativePath(workspace, path)}";
|
||||
return $"Fehler: Verzeichnis nicht gefunden: {WorkspaceHelper.GetRelativePath(workspace, path)}";
|
||||
var entries = new List<string>();
|
||||
foreach (var dir in Directory.GetDirectories(path))
|
||||
entries.Add(Path.GetRelativePath(workspace, dir) + "/");
|
||||
entries.Add(WorkspaceHelper.GetRelativePath(workspace, dir) + "/");
|
||||
foreach (var file in Directory.GetFiles(path))
|
||||
entries.Add(Path.GetRelativePath(workspace, file));
|
||||
entries.Add(WorkspaceHelper.GetRelativePath(workspace, file));
|
||||
return entries.Count == 0 ? "(leer)" : string.Join("\n", entries);
|
||||
}
|
||||
case "delete_file":
|
||||
@@ -352,14 +352,14 @@ public class ToolService
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
return $"Datei gelöscht: {Path.GetRelativePath(workspace, path)}";
|
||||
return $"Datei gelöscht: {WorkspaceHelper.GetRelativePath(workspace, path)}";
|
||||
}
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
Directory.Delete(path, recursive: false);
|
||||
return $"Verzeichnis gelöscht: {Path.GetRelativePath(workspace, path)}";
|
||||
return $"Verzeichnis gelöscht: {WorkspaceHelper.GetRelativePath(workspace, path)}";
|
||||
}
|
||||
return $"Fehler: Nicht gefunden: {Path.GetRelativePath(workspace, path)}";
|
||||
return $"Fehler: Nicht gefunden: {WorkspaceHelper.GetRelativePath(workspace, path)}";
|
||||
}
|
||||
case "execute":
|
||||
{
|
||||
@@ -368,18 +368,23 @@ public class ToolService
|
||||
var command = input.GetProperty("command").GetString() ?? "";
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = "/bin/bash",
|
||||
FileName = WorkspaceHelper.ShellExecutable,
|
||||
WorkingDirectory = workspace,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardInput = !WorkspaceHelper.IsWindows,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
if (WorkspaceHelper.IsWindows)
|
||||
psi.Arguments = WorkspaceHelper.ShellArguments(command);
|
||||
using var proc = Process.Start(psi);
|
||||
if (proc == null) return "Fehler: Prozess konnte nicht gestartet werden";
|
||||
await proc.StandardInput.WriteAsync(command);
|
||||
proc.StandardInput.Close();
|
||||
if (!WorkspaceHelper.IsWindows)
|
||||
{
|
||||
await proc.StandardInput.WriteAsync(command);
|
||||
proc.StandardInput.Close();
|
||||
}
|
||||
// Timeout (180s) UND externen CancellationToken verknüpfen
|
||||
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(180));
|
||||
@@ -423,7 +428,7 @@ public class ToolService
|
||||
var dirInfo = new DirectoryInfoWrapper(new DirectoryInfo(searchRoot));
|
||||
var result = matcher.Execute(dirInfo);
|
||||
var matches = result.Files
|
||||
.Select(f => Path.GetRelativePath(workspace, Path.Combine(searchRoot, f.Path)))
|
||||
.Select(f => WorkspaceHelper.GetRelativePath(workspace, Path.Combine(searchRoot, f.Path)))
|
||||
.OrderBy(f => f)
|
||||
.ToList();
|
||||
return matches.Count == 0 ? "(keine Treffer)" : string.Join("\n", matches);
|
||||
@@ -459,7 +464,7 @@ public class ToolService
|
||||
for (var i = 0; i < lines.Length; i++)
|
||||
{
|
||||
if (regex.IsMatch(lines[i]))
|
||||
results.Add($"{Path.GetRelativePath(workspace, file)}:{i + 1}: {lines[i].Trim()}");
|
||||
results.Add($"{WorkspaceHelper.GetRelativePath(workspace, file)}:{i + 1}: {lines[i].Trim()}");
|
||||
}
|
||||
}
|
||||
if (results.Count == 0) return "(keine Treffer)";
|
||||
@@ -521,7 +526,7 @@ public class ToolService
|
||||
private string ResolvePath(string relativePath, string workspace)
|
||||
{
|
||||
var full = Path.GetFullPath(Path.Combine(workspace, relativePath ?? ""));
|
||||
if (!full.StartsWith(workspace))
|
||||
if (!WorkspaceHelper.IsSubPathOf(full, workspace))
|
||||
throw new Exception("Zugriff außerhalb des Workspace nicht erlaubt");
|
||||
return full;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user