AX Commander 비교본 런처 기능 대량 이식
변경 목적: Agent Compare 아래 비교본의 개발 문서와 런처 소스를 기준으로 현재 AX Commander에 빠져 있던 신규 런처 기능을 동일한 흐름으로 옮겨, 비교본 수준의 기능 폭을 현재 제품에 반영했습니다. 핵심 수정사항: 비교본의 신규 런처 핸들러 다수를 src/AxCopilot/Handlers로 이식하고 App.xaml.cs 등록 흐름에 연결했습니다. 빠른 링크, 파일 태그, 알림 센터, 포모도로, 파일 브라우저, 핫키 관리, OCR, 세션/스케줄/매크로, Git/정규식/네트워크/압축/해시/UUID/JWT/QR 등 AX Commander 기능을 추가했습니다. 핵심 수정사항: 신규 기능이 실제 동작하도록 AppSettings 확장, SchedulerService/FileTagService/NotificationCenterService/IconCacheService/UrlTemplateEngine/PomodoroService 추가, 배치 이름변경/세션/스케줄/매크로 편집 창 추가, NotificationService와 Symbols 보강, QR/OCR용 csproj 의존성과 Windows 타겟 프레임워크를 반영했습니다. 문서 반영: README.md와 docs/DEVELOPMENT.md에 비교본 기반 런처 기능 이식 이력과 검증 결과를 업데이트했습니다. 검증 결과: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ 실행 기준 경고 0개, 오류 0개를 확인했습니다.
This commit is contained in:
342
src/AxCopilot/Handlers/NpmHandler.cs
Normal file
342
src/AxCopilot/Handlers/NpmHandler.cs
Normal file
@@ -0,0 +1,342 @@
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using AxCopilot.SDK;
|
||||
using AxCopilot.Services;
|
||||
using AxCopilot.Themes;
|
||||
|
||||
namespace AxCopilot.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// L19-4: npm/yarn/pnpm 패키지 매니저 명령어 생성·실행 핸들러. "npm" 프리픽스로 사용합니다.
|
||||
///
|
||||
/// 예: npm → 자주 쓰는 명령어 목록
|
||||
/// npm init → npm/yarn/pnpm init 명령 비교
|
||||
/// npm install lodash → npm/yarn/pnpm install lodash 명령 비교
|
||||
/// npm i lodash → install 단축키
|
||||
/// npm run dev → npm/yarn/pnpm run dev
|
||||
/// npm uninstall lodash → npm/yarn/pnpm uninstall
|
||||
/// npm update → 패키지 업데이트 명령
|
||||
/// npm list → 패키지 목록 명령
|
||||
/// npm audit → 보안 감사 명령
|
||||
/// npm publish → 배포 명령
|
||||
/// npm scripts → package.json scripts 확인 방법
|
||||
/// npm global → 전역 패키지 목록 명령
|
||||
/// npm clean → 캐시·node_modules 정리 명령
|
||||
/// Enter → 클립보드 복사 (또는 터미널에서 실행).
|
||||
/// </summary>
|
||||
public class NpmHandler : IActionHandler
|
||||
{
|
||||
public string? Prefix => "npm";
|
||||
|
||||
public PluginMetadata Metadata => new(
|
||||
"NPM",
|
||||
"npm/yarn/pnpm 명령어 생성기 — install·run·audit·publish·clean",
|
||||
"1.0",
|
||||
"AX");
|
||||
|
||||
private record PmCmd(string Manager, string Cmd, string Description);
|
||||
|
||||
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
|
||||
{
|
||||
var q = query.Trim();
|
||||
var items = new List<LauncherItem>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(q))
|
||||
{
|
||||
items.Add(new LauncherItem("npm/yarn/pnpm 명령어 생성기",
|
||||
"npm install / run / init / build / test / audit / publish / clean …",
|
||||
null, null, Symbol: "\uE756"));
|
||||
AddCommandGroups(items);
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
|
||||
var parts = q.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
|
||||
var sub = parts[0].ToLowerInvariant();
|
||||
var arg = parts.Length > 1 ? parts[1].Trim() : "";
|
||||
|
||||
// 단축키 정규화
|
||||
sub = sub switch
|
||||
{
|
||||
"i" => "install",
|
||||
"un" => "uninstall",
|
||||
"rm" => "uninstall",
|
||||
"up" => "update",
|
||||
"ls" => "list",
|
||||
_ => sub
|
||||
};
|
||||
|
||||
switch (sub)
|
||||
{
|
||||
case "init":
|
||||
AddSection(items, "프로젝트 초기화", [
|
||||
new("npm", "npm init -y", "기본값으로 package.json 생성"),
|
||||
new("yarn", "yarn init -y", "기본값으로 package.json 생성"),
|
||||
new("pnpm", "pnpm init", "기본값으로 package.json 생성"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "install" when !string.IsNullOrWhiteSpace(arg):
|
||||
AddSection(items, $"패키지 설치: {arg}", [
|
||||
new("npm", $"npm install {arg}", $"npm으로 {arg} 설치"),
|
||||
new("yarn", $"yarn add {arg}", $"yarn으로 {arg} 설치"),
|
||||
new("pnpm", $"pnpm add {arg}", $"pnpm으로 {arg} 설치"),
|
||||
]);
|
||||
AddSection(items, $"개발 의존성으로 설치: {arg}", [
|
||||
new("npm", $"npm install {arg} --save-dev", "devDependencies에 추가"),
|
||||
new("yarn", $"yarn add {arg} --dev", "devDependencies에 추가"),
|
||||
new("pnpm", $"pnpm add {arg} --save-dev", "devDependencies에 추가"),
|
||||
]);
|
||||
AddSection(items, $"전역 설치: {arg}", [
|
||||
new("npm", $"npm install -g {arg}", "전역 설치"),
|
||||
new("yarn", $"yarn global add {arg}", "전역 설치"),
|
||||
new("pnpm", $"pnpm add -g {arg}", "전역 설치"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "install":
|
||||
AddSection(items, "의존성 설치 (node_modules)", [
|
||||
new("npm", "npm install", "package.json 의존성 모두 설치"),
|
||||
new("yarn", "yarn install", "package.json 의존성 모두 설치"),
|
||||
new("pnpm", "pnpm install", "package.json 의존성 모두 설치"),
|
||||
]);
|
||||
AddSection(items, "프로덕션 의존성만", [
|
||||
new("npm", "npm install --production", "--production 플래그"),
|
||||
new("yarn", "yarn install --production", "--production 플래그"),
|
||||
new("pnpm", "pnpm install --prod", "--prod 플래그"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "uninstall" when !string.IsNullOrWhiteSpace(arg):
|
||||
AddSection(items, $"패키지 제거: {arg}", [
|
||||
new("npm", $"npm uninstall {arg}", $"npm으로 {arg} 제거"),
|
||||
new("yarn", $"yarn remove {arg}", $"yarn으로 {arg} 제거"),
|
||||
new("pnpm", $"pnpm remove {arg}", $"pnpm으로 {arg} 제거"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "run" when !string.IsNullOrWhiteSpace(arg):
|
||||
AddSection(items, $"스크립트 실행: {arg}", [
|
||||
new("npm", $"npm run {arg}", $"npm run {arg}"),
|
||||
new("yarn", $"yarn {arg}", $"yarn {arg}"),
|
||||
new("pnpm", $"pnpm run {arg}", $"pnpm run {arg}"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "start":
|
||||
case "run":
|
||||
AddSection(items, "주요 스크립트", [
|
||||
new("npm", "npm start", "start 스크립트 실행"),
|
||||
new("npm", "npm run dev", "dev 스크립트 실행"),
|
||||
new("npm", "npm run build", "build 스크립트 실행"),
|
||||
new("npm", "npm test", "test 스크립트 실행"),
|
||||
]);
|
||||
AddSection(items, "yarn 동등 명령", [
|
||||
new("yarn", "yarn start", "start"),
|
||||
new("yarn", "yarn dev", "dev"),
|
||||
new("yarn", "yarn build", "build"),
|
||||
new("yarn", "yarn test", "test"),
|
||||
]);
|
||||
AddSection(items, "pnpm 동등 명령", [
|
||||
new("pnpm", "pnpm start", "start"),
|
||||
new("pnpm", "pnpm run dev", "dev"),
|
||||
new("pnpm", "pnpm run build", "build"),
|
||||
new("pnpm", "pnpm test", "test"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "build":
|
||||
AddSection(items, "빌드", [
|
||||
new("npm", "npm run build", "build 스크립트"),
|
||||
new("yarn", "yarn build", "build 스크립트"),
|
||||
new("pnpm", "pnpm run build", "build 스크립트"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "test":
|
||||
AddSection(items, "테스트", [
|
||||
new("npm", "npm test", "test 스크립트"),
|
||||
new("npm", "npm run test:watch", "테스트 와처"),
|
||||
new("yarn", "yarn test", "test 스크립트"),
|
||||
new("pnpm", "pnpm test", "test 스크립트"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "update" or "upgrade":
|
||||
AddSection(items, "패키지 업데이트", [
|
||||
new("npm", "npm update", "모든 패키지 업데이트"),
|
||||
new("npm", "npm outdated", "오래된 패키지 확인"),
|
||||
new("npm", "npx npm-check-updates", "버전 업그레이드 체크"),
|
||||
new("yarn", "yarn upgrade", "모든 패키지 업그레이드"),
|
||||
new("pnpm", "pnpm update", "모든 패키지 업데이트"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "list" or "ls":
|
||||
AddSection(items, "패키지 목록", [
|
||||
new("npm", "npm list", "설치된 패키지 목록"),
|
||||
new("npm", "npm list --depth=0", "최상위 패키지만"),
|
||||
new("npm", "npm list -g --depth=0", "전역 패키지 목록"),
|
||||
new("yarn", "yarn list", "설치된 패키지 목록"),
|
||||
new("pnpm", "pnpm list", "설치된 패키지 목록"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "audit":
|
||||
AddSection(items, "보안 감사", [
|
||||
new("npm", "npm audit", "보안 취약점 스캔"),
|
||||
new("npm", "npm audit fix", "자동 수정"),
|
||||
new("yarn", "yarn audit", "보안 취약점 스캔"),
|
||||
new("pnpm", "pnpm audit", "보안 취약점 스캔"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "publish":
|
||||
AddSection(items, "패키지 배포", [
|
||||
new("npm", "npm publish", "npm 레지스트리에 배포"),
|
||||
new("npm", "npm publish --access public","공개 패키지로 배포"),
|
||||
new("npm", "npm version patch", "패치 버전 올리기"),
|
||||
new("npm", "npm version minor", "마이너 버전 올리기"),
|
||||
new("npm", "npm version major", "메이저 버전 올리기"),
|
||||
new("yarn", "yarn publish", "yarn으로 배포"),
|
||||
new("pnpm", "pnpm publish", "pnpm으로 배포"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "scripts":
|
||||
AddSection(items, "package.json 스크립트 확인", [
|
||||
new("npm", "npm run", "스크립트 목록 보기"),
|
||||
new("npm", "cat package.json", "package.json 확인"),
|
||||
new("yarn", "yarn run", "스크립트 목록 보기"),
|
||||
new("pnpm", "pnpm run", "스크립트 목록 보기"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "global":
|
||||
AddSection(items, "전역 패키지", [
|
||||
new("npm", "npm list -g --depth=0", "전역 패키지 목록"),
|
||||
new("npm", "npm root -g", "전역 node_modules 경로"),
|
||||
new("yarn", "yarn global list", "전역 패키지 목록"),
|
||||
new("pnpm", "pnpm list -g", "전역 패키지 목록"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "clean":
|
||||
AddSection(items, "캐시 및 모듈 정리", [
|
||||
new("npm", "npm cache clean --force", "npm 캐시 삭제"),
|
||||
new("npm", "Remove-Item -Recurse -Force node_modules", "node_modules 삭제 (PowerShell)"),
|
||||
new("npm", "rm -rf node_modules && npm install", "재설치 (bash)"),
|
||||
new("yarn", "yarn cache clean", "yarn 캐시 삭제"),
|
||||
new("pnpm", "pnpm store prune", "pnpm 스토어 정리"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "ci":
|
||||
AddSection(items, "CI/CD용 클린 설치", [
|
||||
new("npm", "npm ci", "package-lock.json 기반 클린 설치"),
|
||||
new("yarn", "yarn install --frozen-lockfile", "lockfile 기반 클린 설치"),
|
||||
new("pnpm", "pnpm install --frozen-lockfile", "lockfile 기반 클린 설치"),
|
||||
]);
|
||||
break;
|
||||
|
||||
case "lock":
|
||||
AddSection(items, "lockfile 관리", [
|
||||
new("npm", "npm install --package-lock-only", "lockfile만 갱신"),
|
||||
new("yarn", "yarn import", "package-lock → yarn.lock 변환"),
|
||||
new("pnpm", "pnpm import", "다른 lockfile → pnpm-lock.yaml 변환"),
|
||||
]);
|
||||
break;
|
||||
|
||||
default:
|
||||
items.Add(new LauncherItem($"알 수 없는 명령: '{sub}'",
|
||||
"init · install · uninstall · run · build · test · update · list · audit · publish · clean · global",
|
||||
null, null, Symbol: "\uE783"));
|
||||
AddCommandGroups(items);
|
||||
break;
|
||||
}
|
||||
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
|
||||
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
|
||||
{
|
||||
switch (item.Data)
|
||||
{
|
||||
case ("copy", string text):
|
||||
try
|
||||
{
|
||||
System.Windows.Application.Current.Dispatcher.Invoke(
|
||||
() => Clipboard.SetText(text));
|
||||
NotificationService.Notify("NPM", "클립보드에 복사했습니다.");
|
||||
}
|
||||
catch { }
|
||||
break;
|
||||
|
||||
case ("run", string cmd):
|
||||
RunInTerminal(cmd);
|
||||
break;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// ── 헬퍼 ────────────────────────────────────────────────────────────────
|
||||
|
||||
private static void AddCommandGroups(List<LauncherItem> items)
|
||||
{
|
||||
var groups = new (string Title, string[] Keys)[]
|
||||
{
|
||||
("초기화·설치", ["npm init", "npm install", "npm install <패키지>"]),
|
||||
("개발 워크플로우", ["npm start", "npm run dev", "npm run build", "npm test"]),
|
||||
("패키지 관리", ["npm update", "npm uninstall <패키지>", "npm list"]),
|
||||
("보안·배포", ["npm audit", "npm audit fix", "npm publish"]),
|
||||
("캐시·정리", ["npm cache clean --force", "npm ci"]),
|
||||
};
|
||||
foreach (var (title, keys) in groups)
|
||||
items.Add(new LauncherItem(title, string.Join(" / ", keys), null, null, Symbol: "\uE756"));
|
||||
}
|
||||
|
||||
private static void AddSection(List<LauncherItem> items, string title, PmCmd[] cmds)
|
||||
{
|
||||
items.Add(new LauncherItem($"── {title} ──", "", null, null, Symbol: "\uE756"));
|
||||
foreach (var c in cmds)
|
||||
{
|
||||
var icon = c.Manager switch
|
||||
{
|
||||
"yarn" => "🧶",
|
||||
"pnpm" => "📦",
|
||||
_ => "📦"
|
||||
};
|
||||
items.Add(new LauncherItem(c.Cmd, $"{c.Manager} · {c.Description} · Enter 복사",
|
||||
null, ("copy", c.Cmd), Symbol: "\uE756"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void RunInTerminal(string cmd)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Windows Terminal 우선
|
||||
var wtPath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
@"Microsoft\WindowsApps\wt.exe");
|
||||
if (File.Exists(wtPath))
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = wtPath,
|
||||
Arguments = $"cmd /k \"{cmd}\"",
|
||||
UseShellExecute = true
|
||||
});
|
||||
return;
|
||||
}
|
||||
// cmd 폴백
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "cmd.exe",
|
||||
Arguments = $"/k {cmd}",
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user