Initial commit to new repository
This commit is contained in:
195
.decompiledproj/AxCopilot/Services/Agent/ProcessTool.cs
Normal file
195
.decompiledproj/AxCopilot/Services/Agent/ProcessTool.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AxCopilot.Services.Agent;
|
||||
|
||||
public class ProcessTool : IAgentTool
|
||||
{
|
||||
private static readonly string[] DangerousPatterns = new string[16]
|
||||
{
|
||||
"format ", "del /s", "rd /s", "rmdir /s", "rm -rf", "Remove-Item -Recurse -Force", "Stop-Computer", "Restart-Computer", "shutdown", "taskkill /f",
|
||||
"reg delete", "reg add", "net user", "net localgroup", "schtasks /create", "schtasks /delete"
|
||||
};
|
||||
|
||||
public string Name => "process";
|
||||
|
||||
public string Description => "Execute a shell command (cmd or powershell). Returns stdout and stderr. Has a timeout limit.";
|
||||
|
||||
public ToolParameterSchema Parameters
|
||||
{
|
||||
get
|
||||
{
|
||||
ToolParameterSchema toolParameterSchema = new ToolParameterSchema();
|
||||
Dictionary<string, ToolProperty> obj = new Dictionary<string, ToolProperty> { ["command"] = new ToolProperty
|
||||
{
|
||||
Type = "string",
|
||||
Description = "Command to execute"
|
||||
} };
|
||||
ToolProperty obj2 = new ToolProperty
|
||||
{
|
||||
Type = "string",
|
||||
Description = "Shell to use: 'cmd' or 'powershell'. Default: 'cmd'."
|
||||
};
|
||||
int num = 2;
|
||||
List<string> list = new List<string>(num);
|
||||
CollectionsMarshal.SetCount(list, num);
|
||||
Span<string> span = CollectionsMarshal.AsSpan(list);
|
||||
span[0] = "cmd";
|
||||
span[1] = "powershell";
|
||||
obj2.Enum = list;
|
||||
obj["shell"] = obj2;
|
||||
obj["timeout"] = new ToolProperty
|
||||
{
|
||||
Type = "integer",
|
||||
Description = "Timeout in seconds. Default: 30, max: 120."
|
||||
};
|
||||
toolParameterSchema.Properties = obj;
|
||||
num = 1;
|
||||
List<string> list2 = new List<string>(num);
|
||||
CollectionsMarshal.SetCount(list2, num);
|
||||
CollectionsMarshal.AsSpan(list2)[0] = "command";
|
||||
toolParameterSchema.Required = list2;
|
||||
return toolParameterSchema;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
|
||||
{
|
||||
if (!args.TryGetProperty("command", out var cmdEl))
|
||||
{
|
||||
return ToolResult.Fail("command가 필요합니다.");
|
||||
}
|
||||
string command = cmdEl.GetString() ?? "";
|
||||
JsonElement sh;
|
||||
string shell = (args.TryGetProperty("shell", out sh) ? (sh.GetString() ?? "cmd") : "cmd");
|
||||
JsonElement to;
|
||||
int timeout = (args.TryGetProperty("timeout", out to) ? Math.Min(to.GetInt32(), 120) : 30);
|
||||
if (string.IsNullOrWhiteSpace(command))
|
||||
{
|
||||
return ToolResult.Fail("명령이 비어 있습니다.");
|
||||
}
|
||||
string[] dangerousPatterns = DangerousPatterns;
|
||||
foreach (string pattern in dangerousPatterns)
|
||||
{
|
||||
if (command.Contains(pattern, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ToolResult.Fail("위험 명령 차단: '" + pattern + "' 패턴이 감지되었습니다.");
|
||||
}
|
||||
}
|
||||
if (!(await context.CheckWritePermissionAsync(Name, command)))
|
||||
{
|
||||
return ToolResult.Fail("명령 실행 권한 거부");
|
||||
}
|
||||
try
|
||||
{
|
||||
string arguments;
|
||||
string fileName;
|
||||
if (!(shell == "powershell"))
|
||||
{
|
||||
string text = "/C " + command;
|
||||
arguments = text;
|
||||
fileName = "cmd.exe";
|
||||
}
|
||||
else
|
||||
{
|
||||
string text = "-NoProfile -NonInteractive -Command \"" + command.Replace("\"", "\\\"") + "\"";
|
||||
arguments = text;
|
||||
fileName = "powershell.exe";
|
||||
}
|
||||
ProcessStartInfo psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = arguments,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true,
|
||||
StandardOutputEncoding = Encoding.UTF8,
|
||||
StandardErrorEncoding = Encoding.UTF8
|
||||
};
|
||||
if (!string.IsNullOrEmpty(context.WorkFolder) && Directory.Exists(context.WorkFolder))
|
||||
{
|
||||
psi.WorkingDirectory = context.WorkFolder;
|
||||
}
|
||||
using Process process = new Process
|
||||
{
|
||||
StartInfo = psi
|
||||
};
|
||||
StringBuilder stdout = new StringBuilder();
|
||||
StringBuilder stderr = new StringBuilder();
|
||||
process.OutputDataReceived += delegate(object _, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e.Data != null)
|
||||
{
|
||||
stdout.AppendLine(e.Data);
|
||||
}
|
||||
};
|
||||
process.ErrorDataReceived += delegate(object _, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e.Data != null)
|
||||
{
|
||||
stderr.AppendLine(e.Data);
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(timeout));
|
||||
try
|
||||
{
|
||||
await process.WaitForExitAsync(cts.Token);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
try
|
||||
{
|
||||
process.Kill(entireProcessTree: true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return ToolResult.Fail($"명령 실행 타임아웃 ({timeout}초 초과)");
|
||||
}
|
||||
string output = stdout.ToString().TrimEnd();
|
||||
string error = stderr.ToString().TrimEnd();
|
||||
if (output.Length > 8000)
|
||||
{
|
||||
output = output.Substring(0, 8000) + "\n... (출력 잘림)";
|
||||
}
|
||||
StringBuilder result = new StringBuilder();
|
||||
StringBuilder stringBuilder = result;
|
||||
StringBuilder stringBuilder2 = stringBuilder;
|
||||
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder);
|
||||
handler.AppendLiteral("[Exit code: ");
|
||||
handler.AppendFormatted(process.ExitCode);
|
||||
handler.AppendLiteral("]");
|
||||
stringBuilder2.AppendLine(ref handler);
|
||||
if (!string.IsNullOrEmpty(output))
|
||||
{
|
||||
result.AppendLine(output);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
{
|
||||
stringBuilder = result;
|
||||
StringBuilder stringBuilder3 = stringBuilder;
|
||||
handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder);
|
||||
handler.AppendLiteral("[stderr]\n");
|
||||
handler.AppendFormatted(error);
|
||||
stringBuilder3.AppendLine(ref handler);
|
||||
}
|
||||
return (process.ExitCode == 0) ? ToolResult.Ok(result.ToString()) : ToolResult.Ok(result.ToString());
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
return ToolResult.Fail("명령 실행 실패: " + ex2.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user