# AXCommander_SRS_v1.0

<b>OLEDi Commander</b>

Software Requirements Specification

Windows 전용 시맨틱 런처 & 워크스페이스 매니저

항목 | 내용
--- | ---
문서 버전 | v1.0
작성일 | 2026-03-21
최종 검토일 | 2026-03-21
상태 | 초안 (Draft)
대상 플랫폼 | Windows 10 / 11 (x64)
구현 언어 | C# / .NET 8 / WPF

<br/>

# <b>목차</b>

<br/>

# <b>1. 개요 (Overview)</b>

## <b>1.1 프로젝트 목적</b>

OLEDi Commander는 macOS 생산성 도구 Alfred에서 영감을 받아, Windows 환경에서 동등하거나 그 이상의 생산성을 제공하기 위해 설계된 키보드 우선(Keyboard-first) 런처 겸 워크스페이스 매니저입니다.

전통적인 마우스 중심 UI 조작을 Alt+Space 단축키 하나로 대체하여, 개발자·파워유저가 컨텍스트 전환 비용 없이 빠르게 작업을 수행할 수 있도록 합니다.

## <b>1.2 범위 (Scope)</b>

본 문서는 OLEDi Commander 1.0 릴리스를 대상으로 하며, 아래 두 핵심 모듈을 포함합니다.

- The Shifter: 워크스페이스 창 배치 스냅샷 및 복원
- The Alfred: 시맨틱 커맨드 런처 (별칭, 클립보드 변환, Fuzzy 검색)

아래 항목은 v1.0 범위에서 제외됩니다.

- macOS / Linux 지원
- 클라우드 동기화
- 플러그인 마켓플레이스 UI (v2.0 예정)

## <b>1.3 용어 정의 (Glossary)</b>

용어 | 정의
--- | ---
HWND | Windows API에서 창(Window)을 식별하는 핸들 값
Rect | 창의 좌상단·우하단 좌표로 이루어진 사각형 구조체
Profile | 특정 시점의 창 배치 및 크기 정보를 저장한 JSON 객체
Alias | 긴 경로·명령을 짧게 치환하는 사용자 정의 키워드
Fuzzy Search | 오타·부분 입력도 유사 항목을 찾아주는 비정확 검색
Global Hook | 어떤 앱이 포커스를 갖고 있어도 키 입력을 감지하는 OS 훅
Plugin | CommandResolver에 새로운 ActionHandler를 추가하는 확장 단위
Skill | Plugin의 다른 표현. 사용자 정의 실행 규칙 묶음
settings.json | 사용자 설정 및 Alias를 저장하는 로컬 JSON 파일

## <b>1.4 참조 문서</b>

- Microsoft Docs – User32.dll API Reference
- WPF Documentation (.NET 8)
- Windows Accessibility API (MSAA / UI Automation)
- Alfred App – https://www.alfredapp.com (인터페이스 참조)

<br/>

# <b>2. 시스템 아키텍처</b>

OLEDi Commander는 단일 프로세스(Single-process) 구조이며, 아래 5개 핵심 모듈로 구성됩니다. 모든 모듈은 의존성 주입(DI) 방식으로 연결되어 테스트 및 확장이 용이합니다.

모듈 | 역할 | 핵심 기술
--- | --- | ---
Input Listener | 글로벌 키 훅 – 어떤 앱에서도 Alt+Space 감지 | WH_KEYBOARD_LL, RegisterHotKey
Context Manager | 열린 창의 HWND, Rect, 프로세스 경로 수집 및 복원 | EnumWindows, GetWindowPlacement, SetWindowPos
Command Resolver | 입력 텍스트 파싱 → ActionHandler 라우팅 | Prefix 테이블, ActionHandler 인터페이스
Fuzzy Engine | 파일명·키워드 부분 입력으로 빠른 유사 항목 탐색 | Fuse.js 알고리즘 포팅 또는 FuzzySharp
Plugin Host | 외부 .dll 또는 JSON 기반 스킬을 로드·실행 | Reflection, IActionHandler 인터페이스

## <b>2.1 모듈 간 데이터 흐름</b>

[사용자 키 입력] → Input Listener → Command Resolver → ActionHandler (Shifter / Alfred / Plugin)

[창 배치 저장] → Context Manager → Profile JSON → settings.json

[창 배치 복원] → settings.json → Context Manager → User32 API

## <b>2.2 Prefix 라우팅 테이블</b>

Command Resolver는 입력 텍스트의 첫 번째 토큰(prefix)을 기준으로 ActionHandler를 선택합니다. 빌트인 prefix는 다음과 같습니다.

Prefix | 타입 | 예시 | 동작
--- | --- | --- | ---
! | 워크스페이스 | !dev | 저장된 "dev" 프로필 즉시 복원
@ | URL / 웹 | @blog | settings.json의 해당 URL 브라우저로 오픈
# | 동적 API | #jira | 설정된 API 어댑터 호출 후 결과 표시
> | 터미널 명령 | >git status | Windows Terminal / PowerShell에서 실행
~ | 파일 경로 | ~projects | 등록된 폴더 경로를 탐색기로 오픈
(없음) | Fuzzy 검색 | vsc | 인덱스에서 유사 파일·앱·Alias 검색

확장 가능성 위 prefix 목록은 settings.json의 "prefixMap" 배열을 통해 사용자가 직접 추가·변경할 수 있습니다. 플러그인 개발자는 IActionHandler 인터페이스를 구현하는 .dll을 제공하여 새로운 prefix 동작을 등록합니다. 자세한 내용은 섹션 7 개발자 확장 가이드를 참조하십시오.

<br/>

# <b>3. 기능 요구사항</b>

## <b>3.1 워크스페이스 스냅샷 & 시프트 (The Shifter)</b>

"어떤 위치에 어떤 크기로" 떠 있는지까지 관리하는 워크스페이스 레이아웃 엔진입니다. 단순 앱 실행을 넘어 창의 상태(State)를 완전히 복원합니다.

### <b>3.1.1 Snapshot Capture</b>

- 현재 화면에 있는 모든 가시(Visible) 업무용 창의 배치를 "프로필"로 저장
- 저장 정보: HWND, 프로세스 실행 경로(EXE), 창 제목, Rect (좌상단 x/y, 폭, 높이), 최소화/최대화/일반 상태(ShowCmd)
- 저장 위치: settings.json의 "profiles" 배열
- 저장 명령어: !save <프로필명> 또는 UI의 저장 버튼
- 시스템 트레이 UI(Task Bar) 및 바탕화면은 캡처 제외

### <b>3.1.2 Instant Restore</b>

- !<프로필명> 입력 시 해당 프로필의 창 배치를 강제 복원
- 복원 순서: 1) 저장된 EXE 경로로 프로세스 존재 확인 → 2) HWND 유효성 검사 → 3) SetWindowPos 호출
- 앱이 실행 중이지 않은 경우: 자동으로 EXE를 실행한 후 창 생성을 최대 3초간 대기
- 3초 내 창이 생성되지 않으면 해당 앱을 건너뛰고 나머지 복원 진행, 결과 알림 표시
- 관리자 권한 창(elevated process)은 복원 시 UAC 프롬프트 없이 위치만 조정 (권한 상승 없이 처리 가능한 범위 내에서 수행)

### <b>3.1.3 Profile 관리</b>

- 목록 보기: 런처 UI에서 !<엔터> 입력 시 저장된 프로필 전체 목록 표시
- 이름 변경: !rename <현재명> <새이름>
- 삭제: !delete <프로필명> (확인 다이얼로그 필요)
- 내보내기/가져오기: settings.json 파일 직접 공유 가능 (JSON 스키마 준수 시)

### <b>3.1.4 Multi-Monitor 지원</b>

- 각 모니터의 DPI 및 좌표계 독립 저장
- 모니터 구성 변경 감지: WM_DISPLAYCHANGE 메시지 수신 시 활성 프로필과 현재 모니터 구성 비교
- 모니터 불일치 시 동작 옵션 (settings.json으로 설정 가능):
- "fit": 사용 가능한 모니터에 좌표 스케일링하여 배치
- "skip": 해당 모니터의 창만 건너뜀
- "warn": 복원 전 경고 팝업 표시 (기본값)

## <b>3.2 시맨틱 커맨드 런처 (The Alfred)</b>

키보드만으로 마우스 클릭 수십 번의 가치를 만들어냅니다. Alt+Space → 명령어 입력의 단일 패턴으로 모든 작업을 처리합니다.

### <b>3.2.1 Smart Aliases</b>

긴 경로나 복잡한 명령을 짧은 별칭으로 등록합니다. settings.json의 "aliases" 배열로 관리됩니다.

Alias 타입 | 예시 | 동작 설명
--- | --- | ---
url | @blog → https://swarchitect.net/admin | 브라우저로 URL 오픈
folder | ~proj → C:\\Dev\\Projects | 탐색기로 폴더 오픈
app | @term → C:\\Windows\\wt.exe | 지정 실행파일 실행
batch | >build → cmd /c build.bat | 커맨드 실행 (출력 창 선택)
api | #jira → JiraAdapter (토큰 설정 필요) | 동적 데이터 조회 후 결과 표시
clipboard | $upper → UPPER_CASE 변환 | 현재 클립보드 텍스트 변환

### <b>3.2.2 Fuzzy Engine</b>

- 검색 범위: 사용자 정의 인덱스 폴더(기본: 바탕화면, 시작 메뉴, 최근 파일) + 등록된 모든 Alias
- 인덱싱: 앱 시작 시 1회 전체 인덱싱, 이후 FileSystemWatcher로 변경 감지 시 증분 업데이트
- 응답 목표: 타이핑 후 100ms 이내에 결과 표시 (로컬 인덱스 기준)
- 결과 랭킹 기준: 1) 정확히 일치하는 Alias 최우선, 2) 문자열 유사도, 3) 최근 실행 빈도 가중치
- 최대 결과 수: UI에 5~7개 표시 (설정으로 최대 20개까지 확장 가능)
- 대소문자 구분 없음, 한글 초성 검색 지원 (예: "ㅂㅅ" → "Visual Studio")

### <b>3.2.3 Clipboard Transformer</b>

복사한 텍스트를 규칙에 따라 가공합니다. $ prefix로 호출하며, 변환 결과를 클립보드에 덮어쓴 후 활성 창에 붙여넣기(Ctrl+V) 시뮬레이션을 수행합니다.

빌트인 변환 | 명령 | 예시
--- | --- | ---
JSON 포맷팅 | $json | {"a":1} → 들여쓰기 적용 JSON
유닉스 타임스탬프 → 날짜 | $ts | 1700000000 → 2023-11-14 22:13:20
날짜 → 유닉스 타임스탬프 | $epoch | 2023-11-14 → 1700000000
대문자 변환 | $upper | hello → HELLO
소문자 변환 | $lower | HELLO → hello
URL 인코딩 | $urle | 한글 → %ED%95%9C%EA%B8%80
URL 디코딩 | $urld | %ED%95%9C%EA%B8%80 → 한글
Base64 인코딩 | $b64e | text → dGV4dA==
Base64 디코딩 | $b64d | dGV4dA== → text
마크다운 → 텍스트 | $md | **bold** → bold

사용자 정의 변환 규칙은 settings.json의 "clipboardTransformers" 배열에 추가하며, 정규식 기반 변환과 외부 스크립트 호출을 지원합니다. 자세한 내용은 섹션 7.4를 참조하십시오.

## <b>3.3 동적 API Alias (#)</b>

# prefix를 사용하는 Alias는 외부 API를 호출하여 동적 결과를 표시합니다. 각 API 연결은 "apiAdapters" 설정으로 정의합니다.

항목 | 요구사항
--- | ---
인증 | Personal Access Token(PAT) 또는 OAuth 2.0. 토큰은 Windows Credential Manager에 저장
네트워크 오류 | 3초 내 응답 없으면 타임아웃, 오프라인 캐시(최대 1시간) 표시
결과 표시 | 최대 10개 항목을 런처 결과 리스트에 표시, Enter로 기본 동작(URL 오픈) 실행
빌트인 어댑터 | Jira Cloud, GitHub Issues (v1.0). 추가 어댑터는 플러그인으로 제공

<br/>

# <b>4. UI/UX 디자인 요구사항</b>

## <b>4.1 런처 윈도우</b>

요소 | 명세
--- | ---
형태 | 화면 중앙 상단 1/3 지점에 위치하는 반투명 바(Bar) 형태 오버레이
기본 크기 | 너비: 680px, 높이: 54px (입력 상태). 결과 표시 시 높이 자동 확장
투명도 | Opacity 0.96 (기본). settings.json에서 0.7~1.0 조정 가능
테마 | 시스템 다크/라이트 모드 자동 감지(WMI 또는 레지스트리 감시). 수동 고정 설정 가능
폰트 | Segoe UI (영문), Malgun Gothic (한글), 16px
애니메이션 | 호출: 상단 20px에서 Fade-in + SlideDown (120ms). 닫힘: Fade-out (80ms)
항상 최상위 | Topmost = true. 다른 창에 가려지지 않음
포커스 처리 | 런처 외부 클릭 시 자동 닫힘 (LostFocus 이벤트)

## <b>4.2 결과 리스트</b>

- 최대 5~7개 항목 표시 (기본 5개, settings.json에서 조정)
- 각 항목: 아이콘(32x32) + 제목 + 부제목(경로 또는 설명)
- 키보드 탐색: ↑↓ 화살표, Enter로 실행, Esc로 닫기, Tab으로 자동완성
- 마우스 클릭으로도 실행 가능
- 결과 없음 시: "일치하는 항목이 없습니다" 메시지 표시

## <b>4.3 접근성 (Accessibility)</b>

- UI Automation(UIA) 속성 제공으로 스크린 리더 지원
- 고대비(High Contrast) 모드 지원
- 글꼴 크기 배율: 시스템 DPI 설정 반영 (100% / 125% / 150% / 200%)
- Alt+Space 단축키는 settings.json에서 변경 가능

<br/>

# <b>5. 비기능 요구사항 (NFR)</b>

## <b>5.1 성능</b>

항목 | 목표 수치 | 측정 방법
--- | --- | ---
Fuzzy 검색 응답 | < 100ms (p95) | 로컬 인덱스 10,000건 기준 자동화 벤치마크
Instant Restore (5창 기준) | < 1.5초 | 스톱워치 측정, 5회 평균
앱 시작 시간 | < 800ms (백그라운드 Ready 상태) | 프로세스 시작 → 트레이 아이콘 표시까지
메모리 사용량 | 유휴 시 < 80MB RSS | Process Explorer 모니터링
CPU 점유율 | 유휴 시 < 0.5% | 10분 유휴 후 평균
인덱싱 시간 | 10,000파일 < 3초 | 초기 기동 시 측정

## <b>5.2 신뢰성 & 안정성</b>

- Global Hook 스레드 예외 시 자동 재등록 (최대 3회 재시도, 이후 트레이 경고 알림)
- 앱 크래시 시 Windows Error Reporting 연동 및 로컬 크래시 덤프 저장 (%APPDATA%\OLEDiCommander\crashes\)
- settings.json 파싱 실패 시 기본값(default) 설정으로 폴백, 원본 파일은 .bak 확장자로 백업
- MTBF(평균 무고장 시간) 목표: 7일 연속 사용 시 크래시 없음

## <b>5.3 보안</b>

- Global Keyboard Hook(WH_KEYBOARD_LL): 키 입력을 로깅하지 않음. Alt+Space 패턴 감지 후 즉시 버퍼 파기
- API 토큰: Windows Credential Manager(DPAPI) 저장, settings.json에 평문 토큰 기록 금지
- 플러그인 .dll: 디지털 서명 검증 권장 (v1.0에서는 경고 표시, v2.0에서 강제 서명 요구 예정)
- UAC: 앱 자체는 일반 사용자 권한으로 실행. 관리자 권한이 필요한 동작 시 명시적 UAC 프롬프트
- 네트워크 통신: HTTPS only (TLS 1.2+). 자체 서명 인증서 거부

보안 주의사항 – Windows Defender / EDR 탐지 WH_KEYBOARD_LL 훅은 일부 보안 소프트웨어에서 키로거로 오탐될 수 있습니다. 대응 방안: 앱 배포 시 코드 서명 인증서 적용, Microsoft Store 등록 검토. 기업 환경 배포 시에는 GPO 화이트리스트 등록 가이드를 별도 제공합니다.

## <b>5.4 유지보수성</b>

- 모듈 간 의존성: DI 컨테이너(Microsoft.Extensions.DependencyInjection) 사용
- 로깅: Serilog 사용, 레벨(DEBUG/INFO/WARN/ERROR) 설정 가능. 로그 파일: %APPDATA%\OLEDiCommander\logs\
- 단위 테스트 커버리지: 핵심 모듈(CommandResolver, FuzzyEngine) 80% 이상 목표
- 업데이트: Squirrel.Windows 또는 MSIX 패키지 업데이트 채널 사용

## <b>5.5 호환성</b>

- 최소 지원 OS: Windows 10 (버전 1903, 빌드 18362) 이상
- 권장 OS: Windows 11
- .NET 런타임: .NET 8.0 (Self-contained 배포로 별도 설치 불필요)
- DPI 지원: System DPI 및 Per-Monitor DPI v2 (WPF DPI 자동 스케일링)
- 멀티 모니터: 동일 DPI 및 혼합 DPI 환경 모두 지원

<br/>

# <b>6. 예외 처리 및 엣지 케이스</b>

시나리오 | 원인 | 처리 방침
--- | --- | ---
Restore 시 앱 미실행 | 저장된 EXE가 닫혀 있음 | 자동 EXE 실행 → 3초 대기 → 실패 시 건너뜀, 결과 알림
모니터 구성 변경 | 모니터 추가/제거/해상도 변경 | settings.json의 "monitorMismatch" 정책에 따라 fit/skip/warn
단축키 충돌 | 타 앱이 Alt+Space 선점 | 등록 실패 감지 → 트레이에 경고 → 대체 단축키 제안
관리자 권한 창 제어 | 타 프로세스가 elevated | SetWindowPos 예외 캐치 → 해당 창 건너뜀, 로그 기록
settings.json 손상 | JSON 파싱 오류 | 원본 .bak 저장 → 기본값 로드 → 복구 안내 메시지
Alias 중복 등록 | 동일 키워드 중복 | 나중에 추가된 항목이 우선. 경고 로그 기록
플러그인 로드 실패 | .dll 서명 불일치 또는 예외 | 해당 플러그인 건너뜀, 오류 로그. 앱은 계속 실행
API 타임아웃 | 네트워크 불안정 | 3초 타임아웃 → 오프라인 캐시 표시 (1시간 유효) → 캐시 없으면 오류 메시지
앱 인덱스 폴더 접근 불가 | 권한 없는 폴더 | 해당 폴더 스킵, 인덱싱 완료 후 경고 로그
Fuzzy 검색 결과 없음 | 입력에 일치 항목 없음 | "일치하는 항목이 없습니다" 표시, 입력 지속 허용

<br/>

# <b>7. 데이터 스키마 (settings.json)</b>

모든 사용자 설정과 Profile, Alias는 단일 JSON 파일로 관리됩니다. 파일 위치: %APPDATA%\OLEDiCommander\settings.json

{

"version": "1.0",

"hotkey": "Alt+Space",

"launcher": {

"opacity": 0.96,

"maxResults": 7,

"theme": "system",

"position": "center-top"

},

"indexPaths": [

"%USERPROFILE%\\Desktop",

"%APPDATA%\\Microsoft\\Windows\\Start Menu"

],

"monitorMismatch": "warn",

"profiles": [

{

"name": "dev",

"windows": [

{

"exe": "C:\\Program Files\\Microsoft VS Code\\Code.exe",

"title": "Visual Studio Code",

"rect": { "x": 0, "y": 0, "width": 1280, "height": 1080 },

"showCmd": "Normal",

"monitor": 0

}

]

}

],

"aliases": [

{ "key": "@blog", "type": "url", "target": "https://swarchitect.net/admin" },

{ "key": "#jira", "type": "api", "adapter": "jira", "query": "assignee=currentUser() ORDER BY updated DESC" },

{ "key": "~proj", "type": "folder", "target": "C:\\Dev\\Projects" },

{ "key": ">build", "type": "batch", "target": "cmd /c C:\\Dev\\build.bat", "showWindow": false }

],

"clipboardTransformers": [

{ "key": "$myRule", "type": "regex", "pattern": "(\\d{4})-(\\d{2})-(\\d{2})", "replace": "$3/$2/$1" }

],

"apiAdapters": [

{ "id": "jira", "baseUrl": "https://yourorg.atlassian.net", "credentialKey": "jira_pat" }

],

"plugins": [

{ "path": "C:\\OLEDiPlugins\\MyPlugin.dll", "enabled": true }

]

}

<br/>

# <b>8. 개발자 확장 가이드 (Plugin & Skill Development)</b>

이 섹션은 OLEDi Commander에 새로운 기능, 명령어, API 연결, 변환 규칙을 추가하려는 개발자를 위한 문서입니다. 확장 방법은 세 가지 경로로 제공됩니다.

확장 방법 | 난이도 | 추천 대상
--- | --- | ---
settings.json 수정 | 쉬움 | URL Alias, 폴더 단축키, 배치 명령 추가
JSON 스킬 파일 (.skill.json) | 보통 | API 어댑터, 커스텀 변환 규칙
.dll 플러그인 (C# IActionHandler) | 어려움 | 완전히 새로운 명령 타입, UI 커스터마이징

## <b>8.1 settings.json으로 Alias 추가하기</b>

가장 간단한 확장 방법입니다. settings.json 파일을 텍스트 에디터로 열어 "aliases" 배열에 항목을 추가합니다.

// URL 열기 Alias 추가

{ "key": "@notion", "type": "url", "target": "https://notion.so/your-workspace" }

// 폴더 열기 Alias 추가

{ "key": "~dl", "type": "folder", "target": "%USERPROFILE%\\Downloads" }

// 배치 파일 실행 Alias 추가 (출력 창 표시)

{ "key": ">deploy", "type": "batch", "target": "cmd /c C:\\deploy.bat", "showWindow": true }

// 배치 파일 실행 Alias 추가 (백그라운드 실행)

{ "key": ">silent", "type": "batch", "target": "powershell -File C:\\task.ps1", "showWindow": false }

팁: 환경변수 사용 "target" 값에 %USERPROFILE%, %APPDATA%, %TEMP% 등 Windows 환경변수를 사용할 수 있습니다. 앱 실행 시 자동으로 확장됩니다.

## <b>8.2 Clipboard Transformer 규칙 추가하기</b>

settings.json의 "clipboardTransformers" 배열에 변환 규칙을 추가합니다. 정규식(regex) 또는 외부 스크립트(script) 타입을 지원합니다.

// 정규식 변환: 날짜 형식 YYYY-MM-DD → DD/MM/YYYY

{

"key": "$date",

"type": "regex",

"pattern": "(\\d{4})-(\\d{2})-(\\d{2})",

"replace": "$3/$2/$1",

"description": "ISO 날짜를 로컬 날짜 형식으로 변환"

}

// PowerShell 스크립트 호출 변환

{

"key": "$ps",

"type": "script",

"command": "powershell -NoProfile -Command \"$input | ConvertTo-Json\"",

"timeout": 5000,

"description": "클립보드 텍스트를 PowerShell로 처리"

}

스크립트 타입의 경우, 앱은 클립보드 텍스트를 stdin으로 전달하고 stdout 결과를 클립보드에 저장합니다. timeout(ms) 초과 시 원본 텍스트를 유지합니다.

## <b>8.3 JSON 스킬 파일로 API Adapter 추가하기</b>

새로운 API 서비스(예: Notion, Linear, Slack)를 연결하려면 .skill.json 파일을 작성합니다. 파일은 %APPDATA%\OLEDiCommander\skills\ 폴더에 저장합니다.

// %APPDATA%\OLEDiCommander\skills\notion.skill.json

{

"id": "notion",

"name": "Notion 페이지 검색",

"version": "1.0",

"prefix": "#notion",

"credential": {

"type": "bearer_token",

"credentialKey": "notion_api_token"

},

"request": {

"method": "POST",

"url": "https://api.notion.com/v1/search",

"headers": { "Notion-Version": "2022-06-28" },

"body": { "query": "{{INPUT}}", "page_size": 10 }

},

"response": {

"resultsPath": "results",

"titleField": "properties.title.title[0].plain_text",

"subtitleField": "url",

"actionUrl": "url"

},

"cache": { "ttl": 300 }

}

{{INPUT}}은 사용자가 # 이후에 입력한 텍스트로 치환됩니다. 토큰은 앱 내 설정 화면에서 입력하며 Windows Credential Manager에 암호화 저장됩니다.

필드 | 필수 | 설명
--- | --- | ---
id | 예 | 스킬 고유 식별자 (영문 소문자, 하이픈 허용)
prefix | 예 | 런처에서 이 스킬을 호출하는 명령어 (예: #notion)
credential.type | 예 | bearer_token / basic_auth / oauth2 중 선택
request.url | 예 | API 엔드포인트. {{INPUT}}, {{TOKEN}} 템플릿 변수 사용 가능
response.resultsPath | 예 | JSON 응답에서 결과 배열 경로 (dot notation)
response.actionUrl | 예 | Enter 시 열리는 URL 필드 경로
cache.ttl | 아니오 | 결과 캐시 유효 시간(초). 기본값 0 (캐시 없음)

## <b>8.4 C# .dll 플러그인으로 새 ActionHandler 개발하기</b>

완전히 새로운 명령 타입, 복잡한 UI, 또는 OS 레벨 기능이 필요한 경우 C# 플러그인을 개발합니다.

### <b>8.4.1 인터페이스 정의</b>

// OLEDiCommander.SDK NuGet 패키지 설치 후 사용

using OLEDiCommander.SDK;

/// <summary>

/// 모든 플러그인은 이 인터페이스를 구현해야 합니다.

/// </summary>

public interface IActionHandler

{

// 이 핸들러가 처리할 prefix (예: "@", "#", "!") 또는 null (Fuzzy 결과에만 등록)

string? Prefix { get; }

// 런처 결과 리스트에 표시할 항목을 반환합니다.

// query: prefix 이후의 입력 텍스트

Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct);

// 사용자가 항목을 선택(Enter)했을 때 실행됩니다.

Task ExecuteAsync(LauncherItem item, CancellationToken ct);

// 플러그인 메타데이터

PluginMetadata Metadata { get; }

}

public record LauncherItem(

string Title,

string Subtitle,

string? IconPath, // null이면 기본 아이콘 사용

object? Data // ExecuteAsync에 전달되는 임의 데이터

);

public record PluginMetadata(

string Id,

string Name,

string Version,

string Author

);

### <b>8.4.2 예제: 계산기 플러그인</b>

using OLEDiCommander.SDK;

using System.Data;

[Export(typeof(IActionHandler))]

public class CalculatorHandler : IActionHandler

{

public string? Prefix => "="; // "=2+3" 입력 시 이 핸들러 호출

public PluginMetadata Metadata => new("calculator", "계산기", "1.0", "YourName");

public async Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)

{

try

{

var result = new DataTable().Compute(query, null);

return [new LauncherItem($"= {result}", "Enter로 복사", null, result.ToString())];

}

catch

{

return [new LauncherItem("수식 오류", "올바른 수식을 입력하세요", null, null)];

}

}

public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)

{

if (item.Data is string val)

Clipboard.SetText(val); // 결과를 클립보드에 복사

}

}

### <b>8.4.3 플러그인 배포 및 등록</b>

- 프로젝트를 빌드하여 MyPlugin.dll 생성
- .dll을 임의 폴더에 저장 (예: C:\\OLEDiPlugins\\MyPlugin.dll)
- settings.json의 "plugins" 배열에 경로 등록:

{ "path": "C:\\OLEDiPlugins\\MyPlugin.dll", "enabled": true }

- OLEDi Commander 재시작 → 시스템 트레이 아이콘 우클릭 → "플러그인 재로드"

개발 팁: 핫 리로드 개발 중에는 시스템 트레이 → "개발자 모드" 활성화 시 플러그인 파일 변경 감지 후 자동 재로드됩니다. OLEDiCommander.SDK.dll은 NuGet 패키지(OLEDiCommander.SDK)로 배포됩니다. 단위 테스트 시 MockLauncherContext를 주입하여 UI 없이 IActionHandler를 테스트할 수 있습니다.

## <b>8.5 확장 체크리스트</b>

새 기능을 추가하기 전에 아래 항목을 확인하십시오.

체크 항목 | 확인 기준
--- | ---
Prefix 충돌 확인 | 기존 Prefix 테이블(섹션 2.2)과 중복 없는지 확인
에러 처리 | 네트워크 오류, 타임아웃, null 결과 등 모든 예외 처리 구현
CancellationToken 사용 | 사용자가 ESC 입력 시 진행 중인 비동기 작업 즉시 취소
캐싱 고려 | API 호출 결과는 TTL 캐시 적용으로 불필요한 네트워크 요청 방지
로깅 추가 | ILogger<T>를 통해 DEBUG/ERROR 레벨 로그 기록
단위 테스트 | GetItemsAsync, ExecuteAsync 각각 최소 1개 이상 테스트 케이스 작성
아이콘 제공 | 32x32 PNG 아이콘을 LauncherItem.IconPath에 포함
설명 작성 | PluginMetadata.Name, settings.json의 description 필드 작성

<br/>

# <b>9. 설치 및 배포</b>

항목 | 내용
--- | ---
배포 형태 | MSIX 패키지 (Microsoft Store) 또는 Squirrel.Windows 인스톨러 (.exe)
Self-contained | .NET 8 Self-contained 배포 – 별도 런타임 설치 불필요
설치 경로 | %LOCALAPPDATA%\Programs\OLEDiCommander\
설정 경로 | %APPDATA%\OLEDiCommander\
자동 시작 | HKCU Run 레지스트리 키 등록 (설치 시 옵션 선택)
자동 업데이트 | 앱 실행 시 GitHub Releases API 버전 확인, 백그라운드 다운로드
제거 | 일반 "앱 및 기능"으로 제거 가능. 설정 파일 유지 여부 선택

# <b>10. 미결 사항 및 향후 계획 (v2.0)</b>

항목 | 우선순위 | 비고
--- | --- | ---
플러그인 마켓플레이스 UI | 높음 | 서드파티 스킬 검색/설치/업데이트 통합 UI
OAuth 2.0 인증 흐름 | 높음 | GitHub, Google 등 OAuth 기반 API 어댑터 지원
AI 자연어 명령 | 중간 | 예: "1주일 전 내 Jira 티켓 열어줘" → #jira 쿼리 자동 생성
클라우드 설정 동기화 | 중간 | OneDrive / iCloud Drive를 통한 settings.json 동기화
플러그인 서명 강제화 | 높음 | v2.0부터 서명 없는 .dll 실행 차단
스크립트 언어 지원 | 낮음 | Python / Node.js 스크립트를 스킬로 직접 등록
음성 명령 입력 | 낮음 | Windows Speech API 연동

# <b>변경 이력</b>

버전 | 날짜 | 작성자 | 변경 내용
--- | --- | --- | ---
v1.0 | 2026-03-21 | — | 초안 작성 (SRS 전체 구조 + 개발자 확장 가이드 포함)