Initial commit to new repository

This commit is contained in:
2026-04-03 18:22:19 +09:00
commit 4458bb0f52
7672 changed files with 452440 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
using System.Diagnostics;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;
namespace AxCopilot.Handlers;
/// <summary>
/// 실행 중인 프로세스를 검색하고 종료합니다. "kill " 프리픽스로 사용합니다.
/// 예: kill chrome → Chrome 프로세스 목록 표시 후 선택하면 종료
/// kill → 현재 실행 중인 모든 사용자 프로세스 표시
/// </summary>
public class ProcessHandler : IActionHandler
{
public string? Prefix => "kill "; // 뒤에 공백 포함 — 오탐 방지
public PluginMetadata Metadata => new(
"ProcessKiller",
"프로세스 종료 — kill 뒤에 프로세스명 입력",
"1.0",
"AX");
// 시스템 핵심 프로세스 보호 목록 (종료 방지)
private static readonly HashSet<string> ProtectedProcesses = new(StringComparer.OrdinalIgnoreCase)
{
"system", "smss", "csrss", "wininit", "winlogon", "services", "lsass",
"svchost", "explorer", "dwm", "fontdrvhost", "spoolsv", "registry",
};
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
{
if (string.IsNullOrWhiteSpace(query))
{
return Task.FromResult<IEnumerable<LauncherItem>>(
[
new LauncherItem(
"종료할 프로세스명을 입력하세요",
"예: kill chrome · kill notepad · kill explorer",
null, null, Symbol: Symbols.Power)
]);
}
var q = query.Trim().ToLowerInvariant();
try
{
var processes = Process.GetProcesses()
.Where(p =>
!ProtectedProcesses.Contains(p.ProcessName) &&
p.ProcessName.ToLowerInvariant().Contains(q))
.OrderBy(p => p.ProcessName)
.Take(12)
.ToList();
if (processes.Count == 0)
{
return Task.FromResult<IEnumerable<LauncherItem>>(
[
new LauncherItem(
$"'{query}' 프로세스를 찾을 수 없습니다",
"실행 중인 프로세스가 없거나 이름이 다릅니다",
null, null, Symbol: Symbols.Warning)
]);
}
// 같은 이름의 프로세스 묶기
var grouped = processes
.GroupBy(p => p.ProcessName, StringComparer.OrdinalIgnoreCase)
.Select(g =>
{
var pids = g.Select(p => p.Id).ToList();
var memMb = g.Sum(p =>
{
try { return p.WorkingSet64 / 1024 / 1024; }
catch { return 0L; }
});
var title = g.Count() > 1
? $"{g.Key} ({g.Count()}개 인스턴스)"
: g.Key;
var subtitle = $"PID: {string.Join(", ", pids)} · 메모리: {memMb} MB · Enter로 종료";
return new LauncherItem(
title,
subtitle,
null,
new ProcessKillData(g.Key, pids),
Symbol: Symbols.Power);
})
.ToList();
return Task.FromResult<IEnumerable<LauncherItem>>(grouped);
}
catch (Exception ex)
{
LogService.Warn($"프로세스 목록 조회 실패: {ex.Message}");
return Task.FromResult<IEnumerable<LauncherItem>>(
[
new LauncherItem("프로세스 목록 조회 실패", ex.Message, null, null, Symbol: Symbols.Error)
]);
}
}
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
{
if (item.Data is not ProcessKillData data) return Task.CompletedTask;
int killed = 0, failed = 0;
foreach (var pid in data.Pids)
{
try
{
var proc = Process.GetProcessById(pid);
proc.Kill(entireProcessTree: false);
killed++;
}
catch
{
failed++;
}
}
LogService.Info($"프로세스 종료: {data.Name} — {killed}개 성공, {failed}개 실패");
return Task.CompletedTask;
}
private record ProcessKillData(string Name, List<int> Pids);
}