Files

239 lines
8.2 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace AxCopilot.Services.Agent;
public class ZipTool : IAgentTool
{
private const long MaxExtractSize = 524288000L;
public string Name => "zip_tool";
public string Description => "Compress or extract zip archives. Actions: 'compress' — create a zip file from files/folders; 'extract' — extract a zip file to a directory; 'list' — list contents of a zip file without extracting.";
public ToolParameterSchema Parameters
{
get
{
ToolParameterSchema toolParameterSchema = new ToolParameterSchema();
Dictionary<string, ToolProperty> dictionary = new Dictionary<string, ToolProperty>();
ToolProperty obj = new ToolProperty
{
Type = "string",
Description = "Action to perform"
};
int num = 3;
List<string> list = new List<string>(num);
CollectionsMarshal.SetCount(list, num);
Span<string> span = CollectionsMarshal.AsSpan(list);
span[0] = "compress";
span[1] = "extract";
span[2] = "list";
obj.Enum = list;
dictionary["action"] = obj;
dictionary["zip_path"] = new ToolProperty
{
Type = "string",
Description = "Path to the zip file (to create or extract)"
};
dictionary["source_path"] = new ToolProperty
{
Type = "string",
Description = "Source file or directory path (for compress action)"
};
dictionary["dest_path"] = new ToolProperty
{
Type = "string",
Description = "Destination directory (for extract action)"
};
toolParameterSchema.Properties = dictionary;
num = 2;
List<string> list2 = new List<string>(num);
CollectionsMarshal.SetCount(list2, num);
Span<string> span2 = CollectionsMarshal.AsSpan(list2);
span2[0] = "action";
span2[1] = "zip_path";
toolParameterSchema.Required = list2;
return toolParameterSchema;
}
}
public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken))
{
string text = args.GetProperty("action").GetString() ?? "";
string text2 = args.GetProperty("zip_path").GetString() ?? "";
if (!Path.IsPathRooted(text2))
{
text2 = Path.Combine(context.WorkFolder, text2);
}
try
{
if (1 == 0)
{
}
ToolResult result = text switch
{
"compress" => Compress(args, text2, context),
"extract" => Extract(args, text2, context),
"list" => ListContents(text2),
_ => ToolResult.Fail("Unknown action: " + text),
};
if (1 == 0)
{
}
return Task.FromResult(result);
}
catch (Exception ex)
{
return Task.FromResult(ToolResult.Fail("Zip 오류: " + ex.Message));
}
}
private static ToolResult Compress(JsonElement args, string zipPath, AgentContext context)
{
if (!args.TryGetProperty("source_path", out var value))
{
return ToolResult.Fail("'source_path' is required for compress action");
}
string text = value.GetString() ?? "";
if (!Path.IsPathRooted(text))
{
text = Path.Combine(context.WorkFolder, text);
}
if (File.Exists(zipPath))
{
return ToolResult.Fail("Zip file already exists: " + zipPath);
}
if (Directory.Exists(text))
{
ZipFile.CreateFromDirectory(text, zipPath, CompressionLevel.Optimal, includeBaseDirectory: false);
FileInfo fileInfo = new FileInfo(zipPath);
return ToolResult.Ok($"✓ Created {zipPath} ({fileInfo.Length / 1024}KB)", zipPath);
}
if (File.Exists(text))
{
using (ZipArchive destination = ZipFile.Open(zipPath, ZipArchiveMode.Create))
{
destination.CreateEntryFromFile(text, Path.GetFileName(text), CompressionLevel.Optimal);
FileInfo fileInfo2 = new FileInfo(zipPath);
return ToolResult.Ok($"✓ Created {zipPath} ({fileInfo2.Length / 1024}KB)", zipPath);
}
}
return ToolResult.Fail("Source not found: " + text);
}
private static ToolResult Extract(JsonElement args, string zipPath, AgentContext context)
{
if (!File.Exists(zipPath))
{
return ToolResult.Fail("Zip file not found: " + zipPath);
}
JsonElement value;
string text = (args.TryGetProperty("dest_path", out value) ? (value.GetString() ?? "") : "");
if (string.IsNullOrEmpty(text))
{
text = Path.Combine(Path.GetDirectoryName(zipPath) ?? context.WorkFolder, Path.GetFileNameWithoutExtension(zipPath));
}
if (!Path.IsPathRooted(text))
{
text = Path.Combine(context.WorkFolder, text);
}
using (ZipArchive zipArchive = ZipFile.OpenRead(zipPath))
{
long num = zipArchive.Entries.Sum((ZipArchiveEntry e) => e.Length);
if (num > 524288000)
{
return ToolResult.Fail($"Uncompressed size ({num / 1024 / 1024}MB) exceeds 500MB limit");
}
foreach (ZipArchiveEntry entry in zipArchive.Entries)
{
string fullPath = Path.GetFullPath(Path.Combine(text, entry.FullName));
if (!fullPath.StartsWith(Path.GetFullPath(text), StringComparison.OrdinalIgnoreCase))
{
return ToolResult.Fail("Security: entry '" + entry.FullName + "' escapes destination directory");
}
}
}
Directory.CreateDirectory(text);
ZipFile.ExtractToDirectory(zipPath, text, overwriteFiles: true);
int value2 = Directory.GetFiles(text, "*", SearchOption.AllDirectories).Length;
return ToolResult.Ok($"✓ Extracted {value2} files to {text}");
}
private static ToolResult ListContents(string zipPath)
{
if (!File.Exists(zipPath))
{
return ToolResult.Fail("Zip file not found: " + zipPath);
}
using ZipArchive zipArchive = ZipFile.OpenRead(zipPath);
StringBuilder stringBuilder = new StringBuilder();
StringBuilder stringBuilder2 = stringBuilder;
StringBuilder stringBuilder3 = stringBuilder2;
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(14, 2, stringBuilder2);
handler.AppendLiteral("Archive: ");
handler.AppendFormatted(Path.GetFileName(zipPath));
handler.AppendLiteral(" (");
handler.AppendFormatted(new FileInfo(zipPath).Length / 1024);
handler.AppendLiteral("KB)");
stringBuilder3.AppendLine(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder4 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
handler.AppendLiteral("Entries: ");
handler.AppendFormatted(zipArchive.Entries.Count);
stringBuilder4.AppendLine(ref handler);
stringBuilder.AppendLine();
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder5 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(4, 3, stringBuilder2);
handler.AppendFormatted<string>("Size", 10);
handler.AppendLiteral(" ");
handler.AppendFormatted<string>("Compressed", 10);
handler.AppendLiteral(" ");
handler.AppendFormatted("Name");
stringBuilder5.AppendLine(ref handler);
stringBuilder.AppendLine(new string('-', 60));
int num = Math.Min(zipArchive.Entries.Count, 200);
foreach (ZipArchiveEntry item in zipArchive.Entries.Take(num))
{
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder6 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(4, 3, stringBuilder2);
handler.AppendFormatted(item.Length, 10);
handler.AppendLiteral(" ");
handler.AppendFormatted(item.CompressedLength, 10);
handler.AppendLiteral(" ");
handler.AppendFormatted(item.FullName);
stringBuilder6.AppendLine(ref handler);
}
if (zipArchive.Entries.Count > num)
{
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder7 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(22, 1, stringBuilder2);
handler.AppendLiteral("\n... and ");
handler.AppendFormatted(zipArchive.Entries.Count - num);
handler.AppendLiteral(" more entries");
stringBuilder7.AppendLine(ref handler);
}
long num2 = zipArchive.Entries.Sum((ZipArchiveEntry e) => e.Length);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder8 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(23, 1, stringBuilder2);
handler.AppendLiteral("\nTotal uncompressed: ");
handler.AppendFormatted(num2 / 1024);
handler.AppendLiteral("KB");
stringBuilder8.AppendLine(ref handler);
return ToolResult.Ok(stringBuilder.ToString());
}
}