<b>AX Commander</b>
개발 문서
Windows 전용 시맨틱 런처 & 워크스페이스 매니저
AX Commander는 사내 전용 프로그램입니다. 아래 원칙을 반드시 준수하여 개발하세요.
| 금지 항목 | 설명 |
|---|---|
| 외부 HTTP/HTTPS 호출 | HttpClient, WebClient, HttpWebRequest 등으로 외부 서버에 요청 금지 |
| 외부 SDK 연동 | 서드파티 클라우드 SDK, AI API, SaaS 라이브러리 사용 금지 |
| 원격 플러그인 다운로드 | 런타임에 외부에서 DLL/코드 다운로드 금지 |
| 텔레메트리 / 오류 수집 | 사용 데이터를 외부 서버로 전송하는 일체의 코드 금지 |
| NuGet 패키지 | 외부 네트워크 통신이 내장된 패키지 신규 도입 금지 |
허용: 로컬 파일 시스템 접근, Windows API (P/Invoke), 사내 인트라넷 URL, 로컬 프로세스 실행
| 컴포넌트 | 역할 |
|---|---|
| App.xaml.cs | 앱 진입점, 서비스 초기화, 트레이 아이콘 관리 |
| LauncherWindow | WPF 메인 UI (AllowsTransparency, WindowStyle=None) |
| CommandResolver | 프리픽스 기반 핸들러 라우팅 테이블 |
| FuzzyEngine | 퍼지 검색 + 한국어 초성(ㅅㄷ) 매칭 |
| IndexService | 파일 시스템 인덱서 + FileSystemWatcher |
| SettingsService | settings.json 로드/저장 (자동 백업) |
| ClipboardHistoryService | WM_CLIPBOARDUPDATE 훅 기반 히스토리 |
| PluginHost | DLL/JSON 스킬 플러그인 로더 |
| NotificationService | 트레이 풍선 알림 (타이머/알람) |
| 프리픽스 | 핸들러 | 기능 |
|---|---|---|
| (없음) | FuzzyEngine | 앱·파일 퍼지 검색 + 한국어 초성 |
| = | CalculatorHandler | 수식 계산, 단위/통화 변환 |
| / | SystemCommandHandler | lock, sleep, restart, shutdown, timer, alarm |
| ; | SnippetHandler | 텍스트 스니펫 키워드 검색 & 붙여넣기 |
| # | ClipboardHistoryHandler | 클립보드 히스토리 검색 & 병합 |
| @ | UrlAliasHandler | URL 단축키 |
| ~ | FolderAliasHandler | 폴더 단축키 |
| > | BatchHandler | 명령 실행 / 배치 단축키 |
| $ | ClipboardHandler | 클립보드 텍스트 12종 변환 |
| ! | WorkspaceHandler | 워크스페이스 저장·복원 |
| emoji | EmojiHandler | 이모지 피커 (300+) |
| color | ColorHandler | HEX/RGB/HSL/HSV 색상 변환 |
| recent | RecentFilesHandler | Windows 최근 파일 |
| note | NoteHandler | 빠른 메모 저장·조회 |
| uninstall | UninstallHandler | 앱 제거 (레지스트리) |
| port | PortHandler | TCP 포트/프로세스 점검 |
| env | EnvHandler | 환경변수 조회 |
| json | JsonHandler | JSON 검증/포맷/미니파이 |
| encode | EncodeHandler | base64/url/hex/md5/sha256 인코딩 |
| snap | SnapHandler | 창 배치 레이아웃 |
| cap | ScreenCaptureHandler | 화면/창/스크롤 캡처 |
| help | HelpHandler | 도움말 |
경로: %APPDATA%\AxCommander\settings.json
| 키 | 타입 | 설명 |
|---|---|---|
| version | string | 설정 버전 |
| hotkey | string | 글로벌 단축키 (기본: Alt+Space) |
| launcher.opacity | float | 창 투명도 (0.0~1.0, 기본 0.96) |
| launcher.maxResults | int | 최대 결과 수 (기본 7) |
| launcher.theme | string | 테마 (system|dark|light|oled|nord|monokai|catppuccin|sepia|alfred|alfredlight|custom) |
| launcher.position | string | 런처 위치 (center-top|center|bottom) |
| launcher.webSearchEngine | string | 기본 검색 엔진 (g|n|d|y|w) |
| launcher.snippetAutoExpand | bool | 스니펫 자동 확장 활성화 |
| indexPaths | string[] | 인덱싱할 폴더 경로 목록 |
| aliases | object[] | URL/폴더/배치 단축키 목록 |
| snippets | object[] | 텍스트 스니펫 목록 |
| clipboardHistory.enabled | bool | 클립보드 히스토리 활성화 |
| clipboardHistory.maxItems | int | 최대 보관 개수 (기본 50) |
| plugins | object[] | DLL 플러그인 경로 목록 |
| 테마 키 | 이름 | 특징 |
|---|---|---|
| system | 시스템 | Windows 다크/라이트 모드 자동 감지 |
| dark | Dark | 딥 네이비 다크 (기본) |
| light | Light | 클린 화이트 라이트 |
| oled | OLED | 순수 블랙 (OLED 절전) |
| nord | Nord | Arctic 컬러 팔레트 |
| monokai | Monokai | Sublime Text 스타일 |
| catppuccin | Catppuccin | Mocha 따뜻한 파스텔 |
| sepia | Sepia | 황갈색 아날로그 감성 |
| alfred | Alfred Dark | Alfred 5 다크 팔레트 (딥 퍼플-차콜) |
| alfredlight | Alfred Light | Alfred 5 라이트 팔레트 (클린 화이트) |
| custom | 커스텀 | 14개 색상 완전 커스터마이징 |
| 키 | 용도 |
|---|---|
| LauncherBackground | 전체 배경 |
| ItemBackground | 항목 기본 배경 |
| ItemSelectedBackground | 선택된 항목 배경 |
| ItemHoverBackground | 호버 배경 |
| PrimaryText | 주 텍스트 색상 |
| SecondaryText | 보조 텍스트 색상 |
| PlaceholderText | 플레이스홀더 텍스트 |
| AccentColor | 강조색 (선택 바, 배지 등) |
| SeparatorColor | 구분선 색상 |
| HintBackground | ESC 힌트 배경 |
| HintText | ESC 힌트 텍스트 |
| BorderColor | 창 테두리 |
| ScrollbarThumb | 스크롤바 색상 |
| ShadowColor | 드롭 섀도우 색상 |
| 항목 | 구현 |
|---|---|
| URL 스킴 검증 | http, https, ftp, ms-settings, mailto, file 허용. javascript: 등 차단 |
| PowerShell 인젝션 방지 | > 명령어 입력의 " 이스케이프 처리 |
| ReDoS 방지 | 사용자 정의 Regex에 TimeSpan 타임아웃 적용 |
| 자격증명 저장 | Windows Credential Manager (advapi32.dll, DPAPI 암호화) |
| 클립보드 민감 데이터 | Regex 기반 제외 패턴 — 신용카드·IP 등 기본 차단 |
| API 타임아웃 | JSON 스킬 HTTP 요청 3초 제한 |
| 시스템 명령 확인 | 재시작·종료·로그아웃 실행 전 MessageBox.Show 2단계 확인 |
| 파일 | 테스트 수 | 대상 |
|---|---|---|
| FuzzyEngineTests.cs | 19 | CalculateScore, FuzzyMatch, 초성 검색 |
| ClipboardTransformTests.cs | 21 | 12개 내장 변환기 |
| SettingsServiceTests.cs | 17 | 기본값, JSON 직렬화 라운드트립 |
빌드 오류 3건, 컴파일 경고 1건, 런타임 버그 6건, 보안 이슈 2건을 수정하였습니다.
| 파일 | 수정 내용 | 오류 코드 |
|---|---|---|
| UsageRankingService.cs | using System.IO; 누락 추가 | CS0103 |
| SettingsWindow.xaml.cs | Key.Enter or Key.Return 단일 arm으로 통합 | CS8510 |
| ContextManager.cs | EnumDisplayMonitors 람다 타입 혼합 수정 | CS0748 |
| 파일 | 버그 | 수정 |
|---|---|---|
| JsonSkillLoader.cs | field[0 형식 오류 방지 (IndexOf 반환 -1) | closingIdx < 0 가드 추가 |
| ClipboardHistoryService.cs | _ignoreNext 스레드 비안전, 이중 초기화 | volatile + 이중 초기화 가드 |
| IndexService.cs | ScheduleRebuild 타이머 비원자적 교체 | _timerLock으로 원자적 교체 |
| SettingsService.cs | 백업 실패 무음 catch | LogService.Warn으로 기록 |
| LauncherWindow.xaml.cs | Window에 RenderTransform 설정 시 InvalidOperationException | Content(루트 Border)에 적용 |
| 파일 | 수정 내용 |
|---|---|
| JsonSkillLoader.cs | ActionUrl 실행 전 http/https 스킴 검증 추가 |
| SettingsWindow.xaml.cs | NewIndexPathBox null 역참조 방어 처리 |
# 개발 실행
dotnet run --project src/AxCommander
# Release 단일 파일 빌드 (self-contained)
dotnet publish src/AxCommander -c Release -r win-x64 --self-contained
# 단위 테스트
dotnet test src/AxCommander.Tests
| 용도 | 경로 |
|---|---|
| 설정 파일 | %APPDATA%\AxCommander\settings.json |
| 로그 | %APPDATA%\AxCommander\logs\app-YYYY-MM-DD.log |
| 스킬 파일 | %APPDATA%\AxCommander\skills\*.skill.json |
| 메모 | %APPDATA%\AxCommander\notes.txt |
| 사용 빈도 | %APPDATA%\AxCommander\usage.json |
| 크래시 덤프 | %APPDATA%\AxCommander\crashes\ |
AxCommander.SDK를 참조하여 IActionHandler 인터페이스를 구현합니다.
using AxCommander.SDK;
public class MyHandler : IActionHandler
{
public string? Prefix => "?"; // 트리거 프리픽스
public PluginMetadata Metadata => new("MyPlugin", "설명", "1.0");
public async Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
{
return [ new LauncherItem("제목", "부제목", null, myData, Symbol: "\uE721") ];
}
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
{
return Task.CompletedTask;
}
}
경로: %APPDATA%\AxCommander\skills\*.skill.json
{
"id": "my-api",
"name": "API 연동",
"prefix": "?",
"request": {
"method": "GET",
"url": "https://intranet.example.com/api?q={{INPUT}}"
},
"response": {
"resultsPath": "items",
"titleField": "name",
"subtitleField": "description",
"actionUrl": "url"
},
"cache": 30
}
AX Commander · .NET 8.0 · WPF · MIT License