using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace AxCopilot.Services.Agent; public class FileManageTool : IAgentTool { public string Name => "file_manage"; public string Description => "Manage files and directories. Actions: 'move' — move file/folder to destination; 'copy' — copy file/folder to destination; 'rename' — rename file/folder; 'delete' — delete file (requires Ask permission); 'mkdir' — create directory recursively."; public ToolParameterSchema Parameters { get { ToolParameterSchema toolParameterSchema = new ToolParameterSchema(); Dictionary dictionary = new Dictionary(); ToolProperty obj = new ToolProperty { Type = "string", Description = "Action to perform" }; int num = 5; List list = new List(num); CollectionsMarshal.SetCount(list, num); Span span = CollectionsMarshal.AsSpan(list); span[0] = "move"; span[1] = "copy"; span[2] = "rename"; span[3] = "delete"; span[4] = "mkdir"; obj.Enum = list; dictionary["action"] = obj; dictionary["path"] = new ToolProperty { Type = "string", Description = "Source file/folder path" }; dictionary["destination"] = new ToolProperty { Type = "string", Description = "Destination path (for move/copy/rename)" }; toolParameterSchema.Properties = dictionary; num = 2; List list2 = new List(num); CollectionsMarshal.SetCount(list2, num); Span span2 = CollectionsMarshal.AsSpan(list2); span2[0] = "action"; span2[1] = "path"; toolParameterSchema.Required = list2; return toolParameterSchema; } } public async Task ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken)) { string action = args.GetProperty("action").GetString() ?? ""; string rawPath = args.GetProperty("path").GetString() ?? ""; JsonElement d; string dest = (args.TryGetProperty("destination", out d) ? (d.GetString() ?? "") : ""); string path = (Path.IsPathRooted(rawPath) ? rawPath : Path.Combine(context.WorkFolder, rawPath)); if (!context.IsPathAllowed(path)) { return ToolResult.Fail("경로 접근 차단: " + path); } try { switch (action) { case "mkdir": Directory.CreateDirectory(path); return ToolResult.Ok("디렉토리 생성: " + path); case "delete": if (context.AskPermission != null && !(await context.AskPermission("file_manage(delete)", path))) { return ToolResult.Fail("사용자가 삭제를 거부했습니다."); } if (File.Exists(path)) { File.Delete(path); return ToolResult.Ok("파일 삭제: " + path, path); } if (Directory.Exists(path)) { Directory.Delete(path, recursive: true); return ToolResult.Ok("폴더 삭제: " + path, path); } return ToolResult.Fail("경로를 찾을 수 없습니다: " + path); case "move": case "copy": case "rename": { if (string.IsNullOrEmpty(dest)) { return ToolResult.Fail("'" + action + "' 작업에는 'destination'이 필요합니다."); } string destPath = (Path.IsPathRooted(dest) ? dest : Path.Combine(context.WorkFolder, dest)); if (!context.IsPathAllowed(destPath)) { return ToolResult.Fail("대상 경로 접근 차단: " + destPath); } string destDir = Path.GetDirectoryName(destPath); if (!string.IsNullOrEmpty(destDir) && !Directory.Exists(destDir)) { Directory.CreateDirectory(destDir); } if (action == "rename") { string dir = Path.GetDirectoryName(path) ?? context.WorkFolder; destPath = Path.Combine(dir, dest); } if (File.Exists(path)) { if (action == "copy") { File.Copy(path, destPath, overwrite: true); } else { File.Move(path, destPath, overwrite: true); } return ToolResult.Ok($"{action}: {path} → {destPath}", destPath); } if (Directory.Exists(path)) { if (action == "copy") { CopyDirectory(path, destPath); } else { Directory.Move(path, destPath); } return ToolResult.Ok($"{action}: {path} → {destPath}", destPath); } return ToolResult.Fail("소스 경로를 찾을 수 없습니다: " + path); } default: return ToolResult.Fail("Unknown action: " + action); } } catch (Exception ex) { return ToolResult.Fail("파일 관리 오류: " + ex.Message); } } private static void CopyDirectory(string src, string dst) { Directory.CreateDirectory(dst); string[] files = Directory.GetFiles(src); foreach (string text in files) { File.Copy(text, Path.Combine(dst, Path.GetFileName(text)), overwrite: true); } string[] directories = Directory.GetDirectories(src); foreach (string text2 in directories) { CopyDirectory(text2, Path.Combine(dst, Path.GetFileName(text2))); } } }