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
@@ -1,11 +1,53 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Gott.Models;
|
||||
|
||||
namespace Gott.Services;
|
||||
|
||||
public static class WorkspaceHelper
|
||||
{
|
||||
/// <summary>True wenn die Plattform Windows ist.</summary>
|
||||
internal static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
|
||||
/// <summary>Plattformunabhängiges Temp-Verzeichnis ohne Trailing-Separator.</summary>
|
||||
internal static string TempDir => Path.GetTempPath().TrimEnd(Path.DirectorySeparatorChar);
|
||||
|
||||
/// <summary>
|
||||
/// Prüft ob ein Pfad ein Sub-Pfad eines Basis-Pfads ist (oder gleich).
|
||||
/// Auf Windows case-insensitive, auf Linux case-sensitive.
|
||||
/// </summary>
|
||||
internal static bool IsSubPathOf(string path, string basePath)
|
||||
{
|
||||
var comparison = IsWindows ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
|
||||
var normalizedPath = Path.GetFullPath(path);
|
||||
var normalizedBase = Path.GetFullPath(basePath);
|
||||
return normalizedPath.Equals(normalizedBase, comparison)
|
||||
|| normalizedPath.StartsWith(normalizedBase + Path.DirectorySeparatorChar, comparison);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gibt den relativen Pfad zurück – immer mit Forward-Slashes (für Agent-Output/API).
|
||||
/// </summary>
|
||||
internal static string GetRelativePath(string relativeTo, string path)
|
||||
{
|
||||
var rel = Path.GetRelativePath(relativeTo, path);
|
||||
return IsWindows ? rel.Replace('\\', '/') : rel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gibt den Shell-Dateinamen zurück (cmd.exe auf Windows, /bin/bash auf Linux).
|
||||
/// </summary>
|
||||
internal static string ShellExecutable => IsWindows ? "cmd.exe" : "/bin/bash";
|
||||
|
||||
/// <summary>
|
||||
/// Gibt die Shell-Argumente zurück um einen Befehl auszuführen.
|
||||
/// Windows: /c "command", Linux: via stdin.
|
||||
/// </summary>
|
||||
internal static string ShellArguments(string command)
|
||||
=> IsWindows ? $"/c \"{command.Replace("\"", "\\\"")}\"" : "";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Löst den Workspace-Pfad einer Session auf.
|
||||
/// session.Workspace ist relativ zum user.DefaultPath.
|
||||
@@ -30,8 +72,7 @@ public static class WorkspaceHelper
|
||||
var resolved = Path.GetFullPath(Path.Combine(basePath, workspace));
|
||||
|
||||
// Sicherheit: darf nicht aus dem DefaultPath ausbrechen
|
||||
var normalizedBase = Path.GetFullPath(basePath);
|
||||
if (!resolved.StartsWith(normalizedBase + Path.DirectorySeparatorChar) && resolved != normalizedBase)
|
||||
if (!IsSubPathOf(resolved, Path.GetFullPath(basePath)))
|
||||
return null;
|
||||
|
||||
return resolved;
|
||||
@@ -47,7 +88,7 @@ public static class WorkspaceHelper
|
||||
if (string.IsNullOrWhiteSpace(workspace))
|
||||
return null;
|
||||
|
||||
var trimmed = workspace.Trim().TrimStart('/').TrimEnd('/');
|
||||
var trimmed = workspace.Trim().TrimStart('/', '\\').TrimEnd('/', '\\');
|
||||
if (string.IsNullOrEmpty(trimmed))
|
||||
return null;
|
||||
|
||||
@@ -76,11 +117,12 @@ public static class WorkspaceHelper
|
||||
|
||||
var normalizedBase = Path.GetFullPath(defaultPath.Trim());
|
||||
var normalizedWorkspace = Path.GetFullPath(absoluteWorkspace.Trim());
|
||||
var comparison = IsWindows ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
|
||||
|
||||
if (normalizedWorkspace.StartsWith(normalizedBase + Path.DirectorySeparatorChar))
|
||||
if (normalizedWorkspace.StartsWith(normalizedBase + Path.DirectorySeparatorChar, comparison))
|
||||
return normalizedWorkspace.Substring(normalizedBase.Length + 1);
|
||||
|
||||
if (normalizedWorkspace == normalizedBase)
|
||||
if (normalizedWorkspace.Equals(normalizedBase, comparison))
|
||||
return "";
|
||||
|
||||
return absoluteWorkspace; // Außerhalb des DefaultPath → absoluten Pfad beibehalten (Legacy)
|
||||
|
||||
Reference in new issue
Block a user