Initial commit to new repository
This commit is contained in:
220
.decompiledproj/AxCopilot/Services/Agent/FolderMapTool.cs
Normal file
220
.decompiledproj/AxCopilot/Services/Agent/FolderMapTool.cs
Normal file
@@ -0,0 +1,220 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AxCopilot.Services.Agent;
|
||||
|
||||
public class FolderMapTool : IAgentTool
|
||||
{
|
||||
private static readonly HashSet<string> IgnoredDirs = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"bin", "obj", "node_modules", ".git", ".vs", ".idea", ".vscode", "__pycache__", ".mypy_cache", ".pytest_cache",
|
||||
"dist", "build", "packages", ".nuget", "TestResults", "coverage", ".next", "target", ".gradle", ".cargo"
|
||||
};
|
||||
|
||||
private const int MaxEntries = 500;
|
||||
|
||||
public string Name => "folder_map";
|
||||
|
||||
public string Description => "Generate a directory tree map of the work folder or a specified subfolder. Shows folders and files in a tree structure. Use this to understand the project layout before reading or editing files.";
|
||||
|
||||
public ToolParameterSchema Parameters => new ToolParameterSchema
|
||||
{
|
||||
Properties = new Dictionary<string, ToolProperty>
|
||||
{
|
||||
["path"] = new ToolProperty
|
||||
{
|
||||
Type = "string",
|
||||
Description = "Subdirectory to map. Optional, defaults to work folder root."
|
||||
},
|
||||
["depth"] = new ToolProperty
|
||||
{
|
||||
Type = "integer",
|
||||
Description = "Maximum depth to traverse (1-10). Default: 3."
|
||||
},
|
||||
["include_files"] = new ToolProperty
|
||||
{
|
||||
Type = "boolean",
|
||||
Description = "Whether to include files. Default: true."
|
||||
},
|
||||
["pattern"] = new ToolProperty
|
||||
{
|
||||
Type = "string",
|
||||
Description = "File extension filter (e.g. '.cs', '.py'). Optional, shows all files if omitted."
|
||||
}
|
||||
},
|
||||
Required = new List<string>()
|
||||
};
|
||||
|
||||
public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
|
||||
{
|
||||
JsonElement value;
|
||||
string text = (args.TryGetProperty("path", out value) ? (value.GetString() ?? "") : "");
|
||||
int num = 3;
|
||||
if (args.TryGetProperty("depth", out var value2))
|
||||
{
|
||||
int result;
|
||||
if (value2.ValueKind == JsonValueKind.Number)
|
||||
{
|
||||
num = value2.GetInt32();
|
||||
}
|
||||
else if (value2.ValueKind == JsonValueKind.String && int.TryParse(value2.GetString(), out result))
|
||||
{
|
||||
num = result;
|
||||
}
|
||||
}
|
||||
string s = num.ToString();
|
||||
bool includeFiles = true;
|
||||
if (args.TryGetProperty("include_files", out var value3))
|
||||
{
|
||||
includeFiles = ((value3.ValueKind != JsonValueKind.True && value3.ValueKind != JsonValueKind.False) ? (!string.Equals(value3.GetString(), "false", StringComparison.OrdinalIgnoreCase)) : value3.GetBoolean());
|
||||
}
|
||||
JsonElement value4;
|
||||
string extFilter = (args.TryGetProperty("pattern", out value4) ? (value4.GetString() ?? "") : "");
|
||||
if (!int.TryParse(s, out var result2) || result2 < 1)
|
||||
{
|
||||
result2 = 3;
|
||||
}
|
||||
result2 = Math.Min(result2, 10);
|
||||
string text2 = (string.IsNullOrEmpty(text) ? context.WorkFolder : FileReadTool.ResolvePath(text, context.WorkFolder));
|
||||
if (string.IsNullOrEmpty(text2) || !Directory.Exists(text2))
|
||||
{
|
||||
return Task.FromResult(ToolResult.Fail("디렉토리가 존재하지 않습니다: " + text2));
|
||||
}
|
||||
if (!context.IsPathAllowed(text2))
|
||||
{
|
||||
return Task.FromResult(ToolResult.Fail("경로 접근 차단: " + text2));
|
||||
}
|
||||
try
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
string value5 = Path.GetFileName(text2);
|
||||
if (string.IsNullOrEmpty(value5))
|
||||
{
|
||||
value5 = text2;
|
||||
}
|
||||
StringBuilder stringBuilder2 = stringBuilder;
|
||||
StringBuilder stringBuilder3 = stringBuilder2;
|
||||
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(1, 1, stringBuilder2);
|
||||
handler.AppendFormatted(value5);
|
||||
handler.AppendLiteral("/");
|
||||
stringBuilder3.AppendLine(ref handler);
|
||||
int entryCount = 0;
|
||||
BuildTree(stringBuilder, text2, "", 0, result2, includeFiles, extFilter, context, ref entryCount);
|
||||
if (entryCount >= 500)
|
||||
{
|
||||
stringBuilder2 = stringBuilder;
|
||||
StringBuilder stringBuilder4 = stringBuilder2;
|
||||
handler = new StringBuilder.AppendInterpolatedStringHandler(42, 1, stringBuilder2);
|
||||
handler.AppendLiteral("\n... (");
|
||||
handler.AppendFormatted(500);
|
||||
handler.AppendLiteral("개 항목 제한 도달, depth 또는 pattern을 조정하세요)");
|
||||
stringBuilder4.AppendLine(ref handler);
|
||||
}
|
||||
string value6 = $"폴더 맵 생성 완료 ({entryCount}개 항목, 깊이 {result2})";
|
||||
return Task.FromResult(ToolResult.Ok($"{value6}\n\n{stringBuilder}"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Task.FromResult(ToolResult.Fail("폴더 맵 생성 실패: " + ex.Message));
|
||||
}
|
||||
}
|
||||
|
||||
private static void BuildTree(StringBuilder sb, string dir, string prefix, int currentDepth, int maxDepth, bool includeFiles, string extFilter, AgentContext context, ref int entryCount)
|
||||
{
|
||||
if (currentDepth >= maxDepth || entryCount >= 500)
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<DirectoryInfo> list;
|
||||
try
|
||||
{
|
||||
list = (from d in new DirectoryInfo(dir).GetDirectories()
|
||||
where !d.Attributes.HasFlag(FileAttributes.Hidden) && !IgnoredDirs.Contains(d.Name)
|
||||
orderby d.Name
|
||||
select d).ToList();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<FileInfo> list2 = new List<FileInfo>();
|
||||
if (includeFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
list2 = (from f in new DirectoryInfo(dir).GetFiles()
|
||||
where !f.Attributes.HasFlag(FileAttributes.Hidden) && (string.IsNullOrEmpty(extFilter) || f.Extension.Equals(extFilter, StringComparison.OrdinalIgnoreCase))
|
||||
orderby f.Name
|
||||
select f).ToList();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
int num = list.Count + list2.Count;
|
||||
int num2 = 0;
|
||||
foreach (DirectoryInfo item in list)
|
||||
{
|
||||
if (entryCount >= 500)
|
||||
{
|
||||
break;
|
||||
}
|
||||
num2++;
|
||||
bool flag = num2 == num;
|
||||
string value = (flag ? "└── " : "├── ");
|
||||
string text = (flag ? " " : "│ ");
|
||||
StringBuilder stringBuilder = sb;
|
||||
StringBuilder stringBuilder2 = stringBuilder;
|
||||
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(1, 3, stringBuilder);
|
||||
handler.AppendFormatted(prefix);
|
||||
handler.AppendFormatted(value);
|
||||
handler.AppendFormatted(item.Name);
|
||||
handler.AppendLiteral("/");
|
||||
stringBuilder2.AppendLine(ref handler);
|
||||
entryCount++;
|
||||
if (context.IsPathAllowed(item.FullName))
|
||||
{
|
||||
BuildTree(sb, item.FullName, prefix + text, currentDepth + 1, maxDepth, includeFiles, extFilter, context, ref entryCount);
|
||||
}
|
||||
}
|
||||
foreach (FileInfo item2 in list2)
|
||||
{
|
||||
if (entryCount >= 500)
|
||||
{
|
||||
break;
|
||||
}
|
||||
num2++;
|
||||
string value2 = ((num2 == num) ? "└── " : "├── ");
|
||||
string value3 = FormatSize(item2.Length);
|
||||
StringBuilder stringBuilder = sb;
|
||||
StringBuilder stringBuilder3 = stringBuilder;
|
||||
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(4, 4, stringBuilder);
|
||||
handler.AppendFormatted(prefix);
|
||||
handler.AppendFormatted(value2);
|
||||
handler.AppendFormatted(item2.Name);
|
||||
handler.AppendLiteral(" (");
|
||||
handler.AppendFormatted(value3);
|
||||
handler.AppendLiteral(")");
|
||||
stringBuilder3.AppendLine(ref handler);
|
||||
entryCount++;
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatSize(long bytes)
|
||||
{
|
||||
if (1 == 0)
|
||||
{
|
||||
}
|
||||
string result = ((bytes < 1024) ? $"{bytes} B" : ((bytes >= 1048576) ? $"{(double)bytes / 1048576.0:F1} MB" : $"{(double)bytes / 1024.0:F1} KB"));
|
||||
if (1 == 0)
|
||||
{
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user