Forge
csharpdeeb25a2
1using CascadeIDE.Contracts;
2namespace CascadeIDE.Features.CursorAcp.DataAcquisition;
3
4/// <summary>
5/// DAL: разрешение путей внутри workspace и чтение/запись текста (инструменты ACP, без обхода корня).
6/// </summary>
7[IoBoundary]
8public static class CursorAcpWorkspaceFileAccess
9{
10 /// <summary>Абсолютный путь, если <paramref name="path"/> внутри <paramref name="workspaceRoot"/>; иначе <c>null</c>.</summary>
11 public static string? TryResolvePathUnderWorkspace(string workspaceRoot, string? path)
12 {
13 if (string.IsNullOrWhiteSpace(path))
14 return null;
15 var full = Path.IsPathRooted(path)
16 ? CanonicalFilePath.Normalize(path)
17 : CanonicalFilePath.Normalize(Path.Combine(workspaceRoot, path));
18 var root = CanonicalFilePath.Normalize(workspaceRoot.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
19 + Path.DirectorySeparatorChar);
20 if (!full.StartsWith(root, StringComparison.OrdinalIgnoreCase))
21 return null;
22 return full;
23 }
24
25 /// <summary>Записывает текст; при невалидном пути — no-op (как пустой ответ ACP).</summary>
26 public static void WriteTextFileUnderWorkspace(string workspaceRoot, string? requestPath, string? content)
27 {
28 var path = TryResolvePathUnderWorkspace(workspaceRoot, requestPath);
29 if (path is null)
30 return;
31 var dir = Path.GetDirectoryName(path);
32 if (!string.IsNullOrEmpty(dir))
33 Directory.CreateDirectory(dir);
34 File.WriteAllText(path, content ?? "");
35 }
36
37 /// <summary>Читает текст или пустую строку, если путь вне workspace или файла нет.</summary>
38 public static string ReadTextFileOrEmpty(string workspaceRoot, string? requestPath)
39 {
40 var path = TryResolvePathUnderWorkspace(workspaceRoot, requestPath);
41 if (path is null || !File.Exists(path))
42 return "";
43 return File.ReadAllText(path);
44 }
45}
46
View only · write via MCP/CIDE