Files
AX-Copilot-Codex/docs/DEVELOPMENT.md
lacvet ac37311e41 문서형 기본 제공 스킬 노출과 추천 메타데이터를 정리한다
- pptx/docx/report/prd/회의록/주간보고/markdown 변환 스킬에 when_to_use 및 argument-hint 메타를 추가해 자동 추천 품질을 높인다.

- 설정 화면과 스킬 갤러리에서 managed 스코프를 기본 제공 스킬로 분리해 배포 자산과 사용자 스킬이 섞여 보이지 않게 한다.

- README와 DEVELOPMENT 문서에 2026-04-14 18:37(KST) 기준 작업 이력과 검증 결과를 반영한다.

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_docskills\\ -p:IntermediateOutputPath=obj\\verify_docskills\\ 경고 0 / 오류 0
2026-04-14 18:41:20 +09:00

834 lines
50 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AX Copilot - 개발 문서
> 최종 업데이트: 2026-04-13 · 버전 0.7.3
## 업데이트 로그
- 업데이트: 2026-04-14 17:46 (KST)
- 도구 이름 정합성 문제를 줄이기 위해 `src/AxCopilot/Services/Agent/AgentToolCatalog.cs`를 추가했습니다. canonical id, legacy alias, 탭 노출, 설정 카테고리, 병렬 read-only 분류를 한곳에서 관리하도록 정리했습니다.
- `ToolRegistry`, `AgentLoopService`, `AgentLoopParallelExecution`, `IAgentTool`, `AgentHookRunner`, `SkillService`가 모두 같은 카탈로그를 사용하도록 연결했습니다. 이에 따라 `git/lsp/zip/project_rule/snippet_run` 같은 예전 이름도 런타임에서 자동 정규화됩니다.
- 내부설정 연동도 함께 반영했습니다. `AgentSettingsWindow``SettingsWindow`의 도구 카드, 훅 편집기, 비활성 도구 저장, 도구 권한 저장이 canonical 이름 기준으로 동작하며 기존 저장값은 alias 호환으로 흡수합니다.
- 스킬 관련 설명은 현재 구조에 맞게 완화했습니다. 기본 스킬 폴더와 추가 폴더를 함께 로드하는 흐름, 직접 호출 스킬과 런타임 정책 연결 스킬을 같이 보여주는 방향으로 설정/헬프 문구를 보정했습니다.
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_toolcat\\ -p:IntermediateOutputPath=obj\\verify_toolcat\\` 경고 0 / 오류 0
- 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentToolCatalogTests -p:OutputPath=bin\\verify_toolcat_tests\\ -p:IntermediateOutputPath=obj\\verify_toolcat_tests\\` 통과 8
- 참고: 테스트 빌드 중 기존 파일 `src/AxCopilot.Tests/Services/WorkspaceContextGeneratorTests.cs`의 nullable 경고 1건이 함께 표시되었으나, 이번 변경에서 새 경고를 추가하지는 않았습니다.
---
## 1. 프로젝트 개요
AX Copilot은 Windows용 생산성 런처 + AI 에이전트 데스크톱 앱입니다.
- **런처**: Alfred/Raycast 스타일의 퍼지 검색, 명령 실행, 위젯
- **에이전트**: LLM 기반 대화형 코드/문서 작업 자동화 (도구 호출 루프)
- **독 바**: 시스템 리소스, 클립보드, 스크린샷 등 빠른 접근
---
## 2. 기술 스택
| 항목 | 값 |
|------|-----|
| 프레임워크 | .NET 8 (net8.0-windows10.0.17763.0) |
| UI | WPF + Windows Forms (하이브리드) |
| 언어 | C# 12 |
| 패턴 | MVVM, 이벤트 기반, 싱글톤 서비스 |
| 테스트 | xUnit 2.9 + FluentAssertions 6.12 |
| 빌드 | dotnet CLI, PublishSingleFile |
### 주요 NuGet 패키지
| 패키지 | 용도 |
|--------|------|
| DocumentFormat.OpenXml 3.2.0 | DOCX/XLSX/PPTX 생성 |
| Markdig 0.37.0 | Markdown → HTML 렌더링 |
| Microsoft.Data.Sqlite 8.0 | SQLite (대화 저장소) |
| Microsoft.Web.WebView2 | HTML 미리보기, 가이드 뷰어 |
| QRCoder 1.6.0 | QR 코드 생성 |
| System.Security.Cryptography.ProtectedData | DPAPI 암호화 |
| UglyToad.PdfPig | PDF 읽기 |
---
## 3. 솔루션 구조
```
src/
├── AxCopilot/ # 메인 WPF 앱 (v0.7.3)
│ ├── Assets/ # 아이콘, 프리셋 JSON, 암호화된 가이드, 마스코트
│ ├── Core/ # FuzzyEngine, CommandResolver, InputListener, PluginHost
│ ├── Handlers/ # 136개 빌트인 명령 핸들러
│ ├── Models/ # AppSettings, ChatModels, McpSettings
│ ├── Security/ # AntiTamper (디버거/디컴파일러 탐지)
│ ├── Services/ # 60개 서비스
│ │ └── Agent/ # 에이전트 루프 + 114개 도구
│ ├── Themes/ # 9개 테마 (Dark, Light, OLED, Nord, Monokai 등)
│ ├── ViewModels/ # LauncherViewModel, SettingsViewModel, StatisticsViewModel
│ └── Views/ # 30개 XAML 윈도우
├── AxCopilot.SDK/ # 플러그인 SDK (IActionHandler 인터페이스)
├── AxCopilot.Installer/ # Windows Forms 설치 프로그램 (.NET Framework 4.8)
├── AxCopilot.Tests/ # xUnit 단위/통합 테스트
└── AxKeyEncryptor/ # API 키 DPAPI 암호화 유틸리티
```
---
## 4. 앱 시작 흐름 (App.xaml.cs)
```
OnStartup()
├─ AntiTamper 디버거 감지 (Release 빌드)
├─ 단일 인스턴스 뮤텍스 확인
├─ SettingsService 초기화 + 설정 로드
├─ ChatStorageService 보관 정책 실행 (만료 대화 정리)
├─ L10n 언어 초기화
├─ 서비스 초기화
│ ├─ AgentMemoryService
│ ├─ ChatSessionStateService
│ ├─ AppStateService
│ ├─ IndexService (백그라운드 파일 인덱싱)
│ ├─ FuzzyEngine + CommandResolver
│ ├─ ContextManager
│ ├─ SessionTrackingService
│ ├─ WorktimeReminderService
│ └─ ClipboardHistoryService
├─ 빌트인 핸들러 등록 (136개)
├─ SchedulerService + PluginHost 초기화
├─ InputListener 시작 (글로벌 핫키)
└─ 런처/설정/트레이 윈도우 생성
```
---
## 5. 핵심 아키텍처
### 5.1 런처 (Launcher)
**검색 파이프라인**: 사용자 입력 → `CommandResolver` (접두어 매칭) → `FuzzyEngine` (퍼지 검색) → 결과 정렬 → UI 렌더링
- `FuzzyEngine`: 파일 인덱스 기반 퍼지 매칭, 점수 순위
- `CommandResolver`: 핸들러 라우팅 (접두어 `@`, `!`, `#`, `~`, `>`, `$` 등)
- `IndexService`: 백그라운드 파일 인덱싱 (`.git`, `node_modules` 등 제외)
**위젯**: 성능 모니터, 포모도로, 메모, 날씨, 캘린더, 배터리
### 5.2 에이전트 (Agent Loop)
```
사용자 메시지
→ LlmService.StreamAsync() (LLM API 호출)
→ 응답 스트리밍 수신
→ 도구 호출 감지 시:
→ ToolRegistry에서 도구 조회
→ 권한 확인 (AskPermissionCallback)
→ 도구 실행
→ 결과를 컨텍스트에 추가
→ LLM 재호출 (반복)
→ 최종 텍스트 응답 반환
```
**핵심 클래스**:
- `AgentLoopService` — 루프 엔진 (반복, 일시정지/재개, 이벤트 발행)
- `AxAgentExecutionEngine` — 도구 실행 조율
- `AgentLoopParallelExecution` — 병렬 도구 실행
- `AgentLoopTransitions` / `.Execution` — 상태 전이 로직
- `ToolRegistry` — 도구 등록/조회
- `ContextCondenser` — 컨텍스트 압축 (토큰 관리)
**도구 카테고리** (114개):
| 카테고리 | 예시 |
|---------|------|
| 파일 I/O | FileReadTool, FileEditTool, FileManageTool, FileWriteTool |
| 검색 | GlobTool, GrepTool, CodeSearchTool, FileSearchTool |
| 문서 | DocumentReaderTool, ExcelSkill, DocxSkill, PptxSkill, CsvSkill, HtmlSkill |
| 코드 | BuildRunTool, SnippetRunnerTool, CodeReviewTool, TestLoopTool, LspTool |
| 데이터 | JsonTool, XmlTool, SqlTool, DataPivotTool, RegexTool |
| 시스템 | ProcessTool, EnvTool, ZipTool, ClipboardTool |
| 계획/추적 | TodoWriteTool, TaskTrackerTool, CheckpointTool, PlaybookTool |
| 사용자 | UserAskTool, SuggestActionsTool, NotifyTool |
| MCP | McpTool, McpListResourcesTool, McpReadResourceTool |
**탭별 도구 필터링** (`ToolRegistry.ToolTabOverrides`):
`IAgentTool.TabCategory` 또는 `ToolTabOverrides` 딕셔너리로 도구를 탭별로 분류합니다.
`GetActiveToolsForTab(activeTab)` 메서드가 현재 탭에 맞는 도구만 LLM에 전송하여 토큰을 절약합니다.
| 탭 | 활성 도구 범위 | 설명 |
|------|--------------|------|
| **Chat** | 0개 | 순수 대화. 도구 없이 LLM만 응답 |
| **Cowork** | ~50개 | 파일/검색 + 문서생성(xlsx, docx, pptx...) + 데이터/유틸 |
| **Code** | ~50개 | 파일/검색 + 개발(git, build, lsp...) + 태스크/워크트리 + 유틸 |
- Chat 탭 토큰 절약: ~14,400토큰 → 0 (도구 정의 완전 제거)
- Cowork/Code: 교차 제외로 각 ~3,600토큰 추가 절약
### 5.3 LLM 서비스
**지원 공급자**:
| 서비스 | 설명 |
|--------|------|
| `claude` / `sigmoid` | Anthropic Claude (Sigmoid API 경유) |
| `gemini` | Google Gemini API |
| `vllm` | OpenAI 호환 vLLM (IBM CP4D 지원 포함) |
| `ollama` | 로컬 Ollama 모델 |
**모델 라우팅**: `ModelRouterService`를 통한 오버라이드 스택 — 대화 중 모델/서비스를 동적으로 전환 가능
**토큰 관리**: `TokenEstimator`로 컨텍스트 길이 추정, 오버플로우 시 `ContextCondenser`가 자동 압축
- `EstimateBaseOverhead(systemPromptLength, toolCount)`: 시스템 프롬프트 + 도구 정의 오버헤드 추정
- `_tool_use_blocks` 메시지 0.6x, `tool_result` 메시지 0.7x 할인 적용
- 컨텍스트 사용량 표시에 시스템 프롬프트 + 도구 오버헤드 포함
### 5.4 대화 저장소
- `ChatStorageService`: SQLite 기반 대화 영속화
- `ChatSessionStateService`: 메모리 내 세션 상태 관리
- `ChatConversation`: 메시지 목록 + 실행 이벤트 타임라인 + `Archived` 아카이브 플래그
---
## 6. UI 계층
### 주요 윈도우
| 윈도우 | 역할 |
|--------|------|
| `LauncherWindow` | 메인 런처 (검색, 위젯, 결과 목록) |
| `ChatWindow` | AI 에이전트 대화 (채팅/Cowork/코드 탭) |
| `DockBarWindow` | 독 바 (시스템 리소스, 빠른 접근) |
| `SettingsWindow` | 설정 관리 |
| `AgentSettingsWindow` | 에이전트 전용 설정 |
| `AgentStatsDashboardWindow` | 에이전트 통계 대시보드 |
| `SkillEditorWindow` | 스킬 편집기 |
| `SkillGalleryWindow` | 스킬 갤러리 |
| `TrayMenuWindow` | 시스템 트레이 메뉴 |
| `PreviewWindow` | 문서 미리보기 (WebView2) |
### ChatWindow 분할 구조
`ChatWindow.xaml.cs`는 partial class로 기능별 분할:
| 파일 | 역할 |
|------|------|
| `ChatWindow.xaml.cs` | 메인 오케스트레이션, 스트리밍, 입력 처리 |
| `ChatWindow.AgentEventProcessor.cs` | 에이전트 이벤트 수신/라우팅 |
| `ChatWindow.AgentEventRendering.cs` | 에이전트 이벤트 배너/카드 렌더링 (SessionStart/UserPromptSubmit 숨김) |
| `ChatWindow.AgentStatusPresentation.cs` | 에이전트 실시간 상태 표시 |
| `ChatWindow.ComposerQueuePresentation.cs` | 작성기 큐 UI |
| `ChatWindow.ContextUsagePresentation.cs` | 컨텍스트 사용량 링/팝업 |
| `ChatWindow.ConversationFilterPresentation.cs` | 대화 필터링 |
| `ChatWindow.ConversationListPresentation.cs` | 사이드바 대화 목록 |
| `ChatWindow.ConversationManagementPresentation.cs` | 대화 생성/삭제/관리 |
| `ChatWindow.FileBrowserPresentation.cs` | 파일 브라우저 UI |
| `ChatWindow.FooterPresentation.cs` | 하단 바 (폴더, 권한) |
| `ChatWindow.GitBranchPresentation.cs` | Git 브랜치 표시/전환 |
| `ChatWindow.LiveProgressPresentation.cs` | 실시간 진행 상태 |
| `ChatWindow.MessageBubblePresentation.cs` | 메시지 버블 렌더링 |
| `ChatWindow.MessageInteractions.cs` | 메시지 복사/편집/재전송 |
| `ChatWindow.PermissionPresentation.cs` | 권한 팝업/배너 UI |
| `ChatWindow.PlanApprovalPresentation.cs` | 계획 승인 카드 |
| `ChatWindow.PopupPresentation.cs` | 공통 팝업 구성 |
| `ChatWindow.PreviewPresentation.cs` | 파일 미리보기 탭 |
| `ChatWindow.SelectionPopupPresentation.cs` | 워크트리 선택 팝업 |
| `ChatWindow.SidebarInteractionPresentation.cs` | 사이드바 상호작용 |
| `ChatWindow.StatusPresentation.cs` | 상태 배지/스트립 |
| `ChatWindow.SurfaceVisualPresentation.cs` | 시각 효과 (글로우, 펄스 등) |
| `ChatWindow.TaskSummary.cs` | 작업 요약 카드 |
| `ChatWindow.TimelinePresentation.cs` | 타임라인 정렬, 캐시, 이벤트 필터링 |
| `ChatWindow.TopicPresetPresentation.cs` | 주제 프리셋 UI |
| `ChatWindow.TranscriptHost.cs` | 트랜스크립트 호스트 컨테이너 |
| `ChatWindow.TranscriptPolicy.cs` | 트랜스크립트 표시 정책 |
| `ChatWindow.TranscriptRenderExecution.cs` | 트랜스크립트 렌더 실행 |
| `ChatWindow.TranscriptRenderPlanner.cs` | 트랜스크립트 렌더 계획 |
| `ChatWindow.TranscriptRendering.cs` | 트랜스크립트 렌더링 |
| `ChatWindow.TranscriptVirtualization.cs` | 트랜스크립트 가상화 (대규모 대화) |
| `ChatWindow.SystemPromptBuilder.cs` | 시스템 프롬프트 동적 조립 (탭/프리셋/컨텍스트 주입) |
| `ChatWindow.OverlaySettingsPresentation.cs` | 인라인 설정 팝업 (모델, 빠른액션) |
| `ChatWindow.UserAskPresentation.cs` | 사용자 질문 인라인 카드 |
| `ChatWindow.VisualInteractionHelpers.cs` | 시각 상호작용 헬퍼 |
### 테마 시스템
9개 테마 XAML 리소스 딕셔너리: `Dark`, `Light`, `OLED`, `Nord`, `Monokai`, `Catppuccin`, `Sepia`, `Alfred`, `AlfredLight`
런타임 테마 전환: `SettingsService.Settings.Launcher.Theme` 변경 → 리소스 딕셔너리 교체
---
## 7. 설정 구조 (AppSettings)
### 최상위 설정
| 속성 | 기본값 | 설명 |
|------|--------|------|
| `AiEnabled` | true | AI 기능 활성화 |
| `OperationMode` | "internal" | 운영 모드 (internal/external) |
| `Hotkey` | "Alt+Space" | 런처 단축키 |
| `CleanupPeriodDays` | 30 | 대화 보관 기간 (일) |
| `InternalModeEnabled` | true | 사내 모드 여부 |
### LauncherSettings (중첩)
| 그룹 | 주요 속성 |
|------|----------|
| 표시 | `Theme`, `Opacity`, `Position`, `Width`, `MaxResults` |
| 글로우 | `EnableRainbowGlow`, `EnableSelectionGlow`, `ShowLauncherBorder` |
| 위젯 | `ShowWidgetPerf`, `ShowWidgetPomo`, `ShowWidgetNote`, `ShowWidgetWeather`, `ShowWidgetCalendar`, `ShowWidgetBattery` |
| 독 바 | `DockBarItems`, `DockBarAutoShow`, `DockBarOpacity`, `DockBarRainbowGlow` |
| 기능 | `EnableFavorites`, `EnableRecent`, `EnableActionMode`, `EnableClipboardAutoCategory` |
### LlmSettings (중첩)
에이전트의 LLM 연결 설정: 서비스 선택, 모델, API 키 (DPAPI 암호화), 엔드포인트, 온도, 최대 토큰 등
| 속성 | 기본값 | 설명 |
|------|--------|------|
| `UseAutomaticProfileTemperature` | true | 등록 모델 프로파일의 자동 temperature 정책 |
| `EnableDetailedLog` | false | 워크플로우 상세 로그 (LLM 요청/응답, 도구 이력) |
| `DetailedLogRetentionDays` | 3 | 상세 로그 보관 기간 (일) |
| `EnableRawLlmLog` | false | LLM 요청/응답 원문 기록 (디버깅용) |
### RegisteredModel 실행 프로파일
모델별 `ExecutionProfile`로 도구 호출 강도, 재시도, 메모리/압축 주입량을 조절:
| 프로파일 | 설명 |
|---------|------|
| `balanced` | 기본 균형 모드 |
| `tool_call_strict` | 도구 호출 강제/엄격 모드 |
| `reasoning_first` | 추론 우선 모드 |
| `fast_readonly` | 빠른 읽기 전용 모드 |
| `document_heavy` | 문서 처리 집중 모드 |
---
## 8. 플러그인 시스템
### SDK (AxCopilot.SDK)
```csharp
public interface IActionHandler
{
string? Prefix { get; } // 접두어 (null이면 퍼지 검색만)
PluginMetadata Metadata { get; }
Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct);
Task ExecuteAsync(LauncherItem item, CancellationToken ct);
}
```
### 개발 방법
1. `AxCopilot.SDK` 참조하여 `IActionHandler` 구현
2. 빌드된 `.dll``settings.json``Plugins` 배열에 경로 등록
3. `PluginHost`가 앱 시작 시 동적 로드
---
## 9. 빌드 및 실행
### 개발 빌드
```bash
dotnet build src/AxCopilot/AxCopilot.csproj
```
### 빠른 빌드 (암호화/설치프로그램 생략)
```bash
./build-quick.sh
```
메인 앱만 self-contained 단일 파일로 빌드합니다. AxKeyEncryptor/Installer/난독화를 건너뛰어 빠른 개발 반복에 적합합니다.
### 릴리스 빌드 (단일 파일)
```bash
dotnet publish src/AxCopilot/AxCopilot.csproj -c Release -r win-x64 --self-contained
```
릴리스 빌드 옵션:
- `PublishSingleFile`: 단일 실행 파일
- `EnableCompressionInSingleFile`: 압축 적용
- `PublishReadyToRun`: AOT 프리컴파일
- `DebugType=none`: 디버그 심볼 제거
- `TrimMode=partial`: IL 트리밍
### 테스트
```bash
dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj
```
---
## 10. 버전 관리
- `AxCopilot.csproj``<Version>` 태그 하나만 변경하면 앱 전체에 반영
- 설정 스키마 버전은 `SettingsService.cs``CurrentSettingsVersion`에서 별도 관리
- 마이그레이션: `SettingsService`가 이전 버전 설정 파일을 자동 업그레이드
---
## 11. 보안
| 항목 | 구현 |
|------|------|
| API 키 저장 | DPAPI 암호화 (System.Security.Cryptography.ProtectedData) |
| 키 관리 도구 | AxKeyEncryptor (별도 유틸리티) |
| 안티 탬퍼 | 디버거/디컴파일러 감지 (Release 빌드, `Security/AntiTamper.cs`) |
| Unsafe 코드 | `AllowUnsafeBlocks=true` (ScreenCaptureHandler 포인터 연산용) |
---
## 12. 성능 최적화 내역
### 유휴 CPU 최적화 (2026-04-09)
| 대상 | 변경 전 | 변경 후 |
|------|---------|---------|
| PerformanceMonitorService 폴링 | 2초 | 5초 |
| 위젯 타이머 | 1초 | 3초 |
| 레인보우 글로우 타이머 | 150ms | 300ms |
| ServerStatusService 핑 | 15초 | 60초 |
### 스트리밍 렌더링 최적화 (2026-04-09)
- **TypingTimer**: 50ms → 80ms, `string.Concat``char[]` 버퍼 재사용
- **CursorTimer**: 전체 문자열 재생성 → 마지막 문자만 교체
- **StringBuilder.ToString()**: 30ms 최소 간격 쓰로틀링
- **RenderMessages**: 스트리밍 중 불필요한 전체 재렌더링 방지 (조기 반환)
- **타임라인 이벤트**: 접힌 모드에서 연속 동일 ToolCall 병합
### 런타임 안정성 수정 (2026-04-09)
| 파일 | 수정 내용 |
|------|----------|
| `CsvSkill.cs` | JSON 배열 첫 요소 `ValueKind` 검증 추가 |
| `HtmlSkill.cs` | gradient `Split(',')` 결과 `Length >= 2` 가드 추가 |
| `ChatWindow.xaml.cs` | `ParseGenericAction` 빈 배열 가드, `ShowDropActionMenu` null 가드, `GetAgentLoop` `.FirstOrDefault()` 전환 |
| `ChatWindow.GitBranchPresentation.cs` | async void 핸들러 try/catch 보호 |
| `ChatWindow.xaml.cs` (BtnGitBranch_Click) | async void 핸들러 try/catch 보호 |
### UI 스레드 부하 최적화 2차 (2026-04-09)
| 대상 | 변경 전 | 변경 후 | 효과 |
|------|---------|---------|------|
| 스크롤 애니메이션 | 매번 새 16ms 타이머 생성 | 재사용 32ms 타이머 1개 | GC 압력 + 타이머 누적 해소 |
| 사이드바 애니메이션 | 매번 새 10ms 타이머 생성 | 재사용 32ms 타이머 1개 | 동일 |
| Git 브랜치 UI | `Dispatcher.Invoke` (블로킹) | `Dispatcher.InvokeAsync` (논블로킹) | UI 스레드 차단 해소 |
| 토큰 사용량 호 | 매 250ms PathGeometry 재생성 | 1% 미만 변화 시 렌더링 생략 | 불필요한 레이아웃 연산 제거 |
| 대화 검색 타이머 | 140ms | 300ms | 초당 7회 → 3회 |
| 에이전트 이벤트 타이머 | 140ms (스트리밍: 300/420) | 200ms (스트리밍: 350/500) | 이벤트 처리 빈도 완화 |
| 반응형 레이아웃 타이머 | 120ms | 250ms | 리사이즈 디바운스 강화 |
| 대화 목록 LINQ | Where×2 + Count×3 = 리스트 5회 순회 | Where 1회 병합 + 단일 루프 카운트 | 할당/순회 대폭 감소 |
### 구조적 메모리/안정성 수정 (2026-04-09)
| 문제 | 위치 | 수정 |
|------|------|------|
| Events 컬렉션 무한 성장 | `AgentLoopService.cs` | 500개 초과 시 오래된 이벤트 자동 제거 |
| 파일 브라우저 타이머 좀비 | `ChatWindow.FileBrowserPresentation.cs` | 매번 새 타이머 생성 → 재사용 패턴 |
| 엘리먼트 캐시 미정리 | `ChatWindow.TranscriptVirtualization.cs` | 보유 한도 240→120, 1.5배 초과 시 정리 |
| WorkflowAnalyzer UI 블로킹 | `WorkflowAnalyzerWindow.xaml.cs` | `Dispatcher.Invoke``InvokeAsync` |
### 구조적 리팩토링 P1 (2026-04-09)
| 대상 | 파일 | 변경 |
|------|------|------|
| 인크리멘탈 렌더 hiddenCount 안정화 | `ChatWindow.TranscriptRenderPlanner.cs` | 스트리밍 중 hiddenCount 감소 차단 → prefix 키 불일치로 인한 전체 재빌드 폴백 방지 |
| 비가시 렌더 차단 | `ChatWindow.TranscriptRendering.cs` | 최소화/숨김 상태에서 RenderMessages 즉시 반환 → 불필요한 UI 재구축 제거 |
| ConversationList 이벤트 위임 | `ChatWindow.ConversationListPresentation.cs` | 항목당 5개 람다 핸들러 → ConversationPanel에 단일 위임 핸들러 (Tag 기반 분기). 탭 전환 시 250개 핸들러 누적 해소 |
| TopicPreset 이벤트 위임 | `ChatWindow.TopicPresetPresentation.cs` | 카드당 3개 람다 핸들러 → TopicButtonPanel에 단일 위임 핸들러. 탭 전환 시 45개 핸들러 누적 해소 |
| 공통 VisualTree 헬퍼 | `ChatWindow.VisualInteractionHelpers.cs` | `FindAncestorWithTag<T>`, `FindAncestor<T>` 유틸 추가 |
### 구조적 리팩토링 P2 (2026-04-09)
| 대상 | 파일 | 변경 |
|------|------|------|
| _agentLiveContainer 인크리멘탈 허용 | `TranscriptRenderPlanner.cs`, `TranscriptRenderExecution.cs` | 라이브 컨테이너를 expectedChildCount에 포함, 인크리멘탈 시 임시 분리/재삽입 → `hasExternalChildren` 차단 해소 |
| 스트리밍 append-only 렌더 | `TranscriptRenderExecution.cs`, `TranscriptRendering.cs` | prefix 비교 우회하는 `TryApplyStreamingAppendRender` 추가 — stable 키 부분집합 관계만 확인, 새 항목만 추가 |
| Permission 이벤트 위임 | `ChatWindow.PermissionPresentation.cs` | 행당 4개 람다 → PermissionItems에 단일 위임 핸들러 + `PermissionItemTag` |
| Preview 탭 이벤트 위임 | `ChatWindow.PreviewPresentation.cs` | 탭당 7개 람다 → PreviewTabPanel에 단일 위임 핸들러 + `PreviewTabTag` |
| GitBranch 이벤트 위임 | `ChatWindow.GitBranchPresentation.cs`, `SelectionPopupPresentation.cs` | `CreateFlatPopupRow`/`CreatePopupMenuRow` 행의 람다 → GitBranchItems에 단일 위임 + `PopupRowTag` |
### 구조적 리팩토링 P3 (2026-04-09)
| 대상 | 파일 | 변경 |
|------|------|------|
| FileBrowser 명시적 해제 | `ChatWindow.FileBrowserPresentation.cs` | TreeViewItem 람다→명명 메서드(`FileTreeItem_Expanded/DoubleClick/RightClick`) 전환. `BuildFileTree()``DetachFileTreeHandlers()` 재귀 호출로 Clear 전 핸들러 해제. 트리 재구축당 300개 핸들러 누적 해소 |
> 전체 계획 완료. `docs/STRUCTURAL_REFACTORING_PLAN.md` 참조.
### 런처 · 에이전트 리소스/안정성 수정 (2026-04-09)
| 대상 | 파일 | 변경 |
|------|------|------|
| LauncherWindow 이벤트 누수 | `LauncherWindow.xaml.cs` | `vm.CloseRequested`, `vm.PropertyChanged`, `app.IndexService.IndexRebuilt` 핸들러를 필드 저장 → `OnClosed`에서 `-=` 해제. ViewModel보다 Window가 먼저 닫힐 때 GC 누수 방지 |
| ChatWindow 타이머 정리 | `ChatWindow.xaml.cs` | `Closed` 핸들러에 누락된 8개 타이머 명시적 `Stop()` 추가 + `StopAgentEventProcessor()` 호출 |
| Events 스레드 안전 | `AgentLoopService.cs` | Dispatcher 없을 때 `Events` 접근에 `lock(Events)` 추가 — 동시 EmitEvent 호출 시 IndexOutOfRange 크래시 방지 |
| NotifyTool 타이머 누적 | `NotifyTool.cs` | 알림당 `new DispatcherTimer``DoubleAnimation.Completed` 콜백으로 대체. 100개 알림 시 100개 타이머 동시 존재 해소 |
| LauncherWindow 토스트 타이머 | `LauncherWindow.xaml.cs` | `ShowToast()` 매 호출 `new DispatcherTimer` → 재사용 패턴 + 명명 메서드(`ToastTimer_Tick`) |
| LauncherWindow 타이머 정리 | `LauncherWindow.xaml.cs` | `OnClosed``_toastTimer?.Stop()`, `_indexStatusTimer?.Stop()` 추가 |
### Hot path · 리소스 추가 최적화 (2026-04-09)
| 대상 | 파일 | 변경 |
|------|------|------|
| GetRuntimeActiveTools 캐시 | `AgentLoopService.cs` | 반복당 1~4회 호출 → `cachedActiveTools` 로컬 변수로 1회 캐시. foreach 내 `activeToolNames` 계산도 루프 밖으로 호이스트 |
| SubAgentTool 취소 전파 | `SubAgentTool.cs` | `CancellationTokenSource.CreateLinkedTokenSource(ct)` 연동. Task.Run + loop.RunAsync에 토큰 전달. 부모 중지 시 자식 즉시 취소 |
| 아이콘 애니메이션 재귀 제어 | `LauncherWindow.xaml.cs` | `sb.Completed`에서 즉시 재귀 → `_iconAnimationDelayTimer` 8초 딜레이. 할당 빈도 75% 감소. 클릭 시 딜레이 취소 후 즉시 전환 |
| JsonSerializerOptions 공유 | `AgentLoopService.cs` | `s_jsonOpts` 정적 필드 추가, 4개 `JsonSerializer.Serialize` 호출에 적용. L4096 `System.Text.Json.` 접두사 정규화 |
### Claude Desktop 스타일 UI 개선 (2026-04-09)
| 항목 | 파일 | 수정 내용 |
|------|------|----------|
| 미리보기 Split Button | `ChatWindow.xaml` | 기존 `BtnPreviewToggle` (Ellipse 점 + "프리뷰") → `[▶ 미리보기 | ]` Split Button으로 교체. 좌측 토글, 우측 셰브론 드롭다운 |
| 미리보기 드롭다운 | `ChatWindow.PreviewPresentation.cs` | `ShowPreviewTabDropdown()` — 열린 탭 목록 팝업, 파일 확장자별 아이콘, 활성 탭 하이라이트 |
| PreviewDot → PreviewIcon | `ChatWindow.PreviewPresentation.cs` | `PreviewDot.Fill` 4곳 → `PreviewIcon.Foreground` (AccentColor/SecondaryText) 전환 |
| 셰브론 동기화 | `ChatWindow.PreviewPresentation.cs` | `UpdatePreviewChevronState()``_previewTabs.Count` 기반 IsHitTestVisible/Opacity 제어 |
| 계획 버튼 이동 | `ChatWindow.xaml` | MoodIconPanel 동적 주입 → StatusBar XAML 선언 요소 `BtnPlanViewer`로 이동 |
| ShowPlanButton 리팩토링 | `ChatWindow.PlanApprovalPresentation.cs` | 동적 Add/Remove → `Visibility` 토글 단순화 + 레거시 정리 유지 |
### UX 개선 및 탭별 도구 필터링 (2026-04-09)
| 항목 | 파일 | 수정 내용 |
|------|------|----------|
| 탭별 도구 필터링 | `IAgentTool.cs`, `ToolRegistry.cs`, `AgentLoopService.cs` | `TabCategory` 속성 + `ToolTabOverrides` 딕셔너리로 Chat/Cowork/Code 탭별 도구 분류. Chat=0개, Cowork=문서/데이터, Code=개발/태스크 |
| FolderMapTool 기본값 변경 | `FolderMapTool.cs` | `include_files` 기본값 `false``true`. Description에 사용 제한 가이드 추가 |
| 에이전트 이벤트 숨김 | `AgentEventRendering.cs`, `TimelinePresentation.cs` | `SessionStart`/`UserPromptSubmit` 내부 이벤트 타임라인 비표시 |
| 사용자 메시지 렌더링 | `ChatWindow.xaml.cs` | 전송 시 `InvalidateTimelineCache()` + `preserveViewport:false`로 즉시 표시 보장 |
| 아카이브 기능 | `ChatModels.cs`, `ConversationManagementPresentation.cs`, `ConversationFilterPresentation.cs`, `ConversationListPresentation.cs` | `Archived` 속성, 컨텍스트 메뉴 아카이브 토글, 사이드바 필터 버튼 |
| 커스텀 슬림 스크롤바 | `ChatWindow.xaml` | 6px 슬림 ScrollBar + Thumb 라운드, ScrollViewer 마우스 오버 fade in/out 애니메이션 |
| 스트리밍 메트릭 레이블 | `ChatWindow.xaml`, `StatusPresentation.cs` | 입력 박스 위에 `StreamMetricsLabel` (경과시간 · ↓ 토큰 수) 실시간 표시 |
| 프리셋 카드 클릭 안정화 | `ChatWindow.xaml`, `ChatWindow.xaml.cs` | WrapPanel `Background="Transparent"` + Dispatcher 우선순위 `Loaded`로 상향 |
| 컨텍스트 토큰 정확도 | `TokenEstimator.cs`, `ContextUsagePresentation.cs`, `ILlmService.cs` | 시스템 프롬프트 + 도구 오버헤드 추정, `_tool_use_blocks`/`tool_result` 할인 |
| UI 프리징 방지 | `ChatWindow.xaml.cs` | `SaveLastConversations()`/`PersistConversationSnapshot()` → 렌더링 후 `Task.Run()` 비동기 실행 |
| 빠른 빌드 스크립트 | `build-quick.sh` | 암호화/난독화/설치프로그램 건너뛰는 개발용 빌드 스크립트 |
### 에이전트 루프 문서 생성 흐름 수정 (2026-04-09)
| 파일 | 수정 내용 |
|------|----------|
| `AgentLoopTransitions.Documents.cs` | `TryHandleTerminalDocumentCompletionTransitionAsync`에서 `document_plan` 없이 바로 문서 도구 호출 시 조기 종료 방지 — LLM이 추가 반복으로 내용을 보강할 수 있도록 허용 |
| `HtmlSkill.cs` | `MarkdownToHtml`에서 LLM이 삽입한 `<br>` 태그가 이스케이프되는 버그 수정 — 이스케이프 전 플레이스홀더로 보존 후 복원 |
### Cowork 문서 미생성 · 스크롤 · 전송 후 10초 멈춤 수정 (2026-04-09)
#### 문서 생성 탐색 정책 수정
| 파일 | 수정 내용 |
|------|----------|
| `AgentLoopExplorationPolicy.cs` | `ExplorationScope.DirectCreation` 신규 스코프 추가. `HasDocumentCreationIntent()`로 "작성해줘/만들어줘/써줘" 등 생성 동사 + 문서/보고서 대상 키워드 감지 |
| `AgentLoopExplorationPolicy.cs` | `DirectCreation` 스코프에서 glob/grep/folder_map 탐색 차단 → `document_plan → docx_create/html_create` 바로 이동 |
| `AgentLoopExplorationPolicy.cs` | `FilterExplorationToolsForCurrentIteration`에서 문서 생성 도구를 최우선 순위로 배치 |
| `AgentLoopExplorationPolicy.cs` | `ShouldInjectExplorationCorrection`에서 DirectCreation 시 탐색 도구 1회 호출만으로 즉시 교정 주입 |
| `TaskTypePolicy.cs` | docs 가이던스를 생성 vs 읽기로 분기 — 생성 시 "반드시 실제 파일을 만들어라" 명시 |
| `AgentLoopService.cs` | DirectCreation 스코프 이벤트 메시지: "문서 생성 모드 · 바로 문서를 만드는 중" |
#### 스크롤 버그 수정
| 파일 | 수정 내용 |
|------|----------|
| `ChatWindow.xaml.cs` | 메시지 전송/슬래시 커맨드/컴팩트 후 `RenderMessages(preserveViewport: true)` + `ForceScrollToEnd()` 조합 → `RenderMessages(preserveViewport: false)`로 변경. viewport 복원과 ForceScrollToEnd 경합 제거 |
**원인**: `preserveViewport: true`는 렌더링 후 이전 스크롤 위치를 복원하는 코드를 `DispatcherPriority.Background`로 예약. `ForceScrollToEnd()`도 같은 우선순위로 하단 스크롤을 예약하여 두 코드가 경합, 스크롤이 하단으로 안 가는 문제 발생.
#### 전송 후 10초 멈춤 수정 (Critical Performance Fix)
| 파일 | 수정 내용 |
|------|----------|
| `ChatWindow.AgentStatusPresentation.cs` | `BuildFeedbackContext()``_storage.LoadAllMeta()` (모든 .axchat 파일 복호화) + `_storage.Load()` x20회를 매 전송마다 동기 실행 → 1분 캐시 + 현재 대화 피드백만 즉시 반영 + 전체 갱신은 백그라운드 |
| `ChatWindow.xaml.cs` | `Dispatcher.Invoke()` (동기 블로킹) → `Dispatcher.InvokeAsync()` (비동기). background task에서 UI 스레드 블로킹 제거 |
| `ChatWindow.xaml.cs` | `PrepareExecutionForConversation()` (시스템 프롬프트 빌드: 프로젝트 규칙/메모리/피드백 디스크 I/O) → `await Task.Run()`으로 백그라운드 실행. UI 스레드 즉시 해방 |
**원인 분석**: `BuildFeedbackContext()``LoadAllMeta()` (모든 `.axchat` 파일 복호화·파싱) + `Load()` x20 (20개 대화 전체 로드·복호화) 를 UI 스레드에서 동기 실행. 대화 30개 이상이면 5~10초 블로킹 발생.
### 스트리밍 중 UI 버벅임 대폭 개선 (2026-04-09)
Claude Desktop(React)은 도구 호출이 수십 건이어도 매끄러운 반면, WPF 앱은 심하게 버벅이는 문제의 원인 분석 및 수정.
**근본 원인**: React virtual DOM은 변경된 부분만 diff/patch하지만, WPF는 매 렌더마다 전체 시각적 트리를 파괴 후 재생성.
| 원인 | 파일 | 수정 |
|------|------|------|
| `ItemsSource = null/재연결` — 전체 시각적 트리 파괴 + VirtualizingStackPanel 컨테이너 재생성 | `TranscriptRenderExecution.cs` | 스트리밍 중에는 ItemsSource 분리/재연결 건너뜀 — ObservableCollection 직접 변경으로 레이아웃 패스 최소화 |
| 라이브 진행 카드 매번 재생성 — 헤더/구분선/스텝 전체를 0부터 다시 생성 + 애니메이션 재적용 | `AgentEventRendering.cs` | `_liveProgressCard` 캐시 + `UpdateLiveProgressStepsInPlace()` — 카드 1회 생성 후 새 스텝만 추가, 기존 스텝은 터치 안 함 |
| 렌더 타이머 간격 1.5~2.2초 — WPF 전체 재빌드에 비해 너무 공격적 | `ChatWindow.xaml.cs` | lightweight: 2.2s→4s, normal: 1.5s→3s — 렌더 간 충분한 여유 확보 |
| 매 렌더마다 3개 애니메이션(Opacity + ScaleX + ScaleY) 재적용 | `AgentEventRendering.cs` | 라이브 카드 in-place 업데이트로 기존 애니메이션 보존, 새 스텝에만 애니메이션 적용 |
**비교**:
| 항목 | 수정 전 (WPF) | 수정 후 | Claude Desktop (React) |
|------|-------------|---------|----------------------|
| 업데이트 전략 | 전체 트리 파괴→재생성 | 4단계: StreamingAppend → Incremental → **DiffRender** → FullRender | Virtual DOM diff |
| 렌더 간격 | 1.5~2.2초 | 3~4초 | ~16ms (requestAnimationFrame) |
| 요소 재사용 | Clear→재생성 | 캐시→재사용 + 키 기반 diff | Recycled/Memoized |
| 애니메이션 | 매번 재적용 (3개/요소) | 1회 적용 후 보존 | CSS transform (GPU) |
---
### 12-3. Virtual DOM Diff 렌더 (`TryApplyDiffRender`)
React의 reconciliation과 동일한 원리를 WPF에 적용한 키 기반 diff 렌더입니다.
**렌더 체인 (우선순위 순):**
```
StreamingAppend → Incremental(prefix-match) → DiffRender(key-based) → FullRender
```
| 단계 | 조건 | 동작 |
|------|------|------|
| StreamingAppend | 스트리밍 중 + 기존 stable 키가 부분집합 | 새 키만 append |
| Incremental | prefix가 완전 일치 | 꼬리 부분만 추가 |
| **DiffRender** | hiddenCount 동일 + 키 집합 변화 있음 | old에만 있는 키 삭제(뒤→앞) + new에만 있는 키 추가 |
| FullRender | 위 3개 모두 실패 | 전체 Clear→재생성 |
**핵심 알고리즘:**
1. `oldKeys` → index 딕셔너리 / `newKeys` → HashSet 구축
2. 라이브 컨테이너 임시 분리
3. `oldKeys` 뒤에서부터 순회하며 `newKeySet`에 없는 항목 제거 (인덱스 안정성)
4. `renderPlan.VisibleTimeline`에서 `oldKeyIndex`에 없는 항목만 `Render()`
5. 라이브 컨테이너 재삽입
**파일:** `ChatWindow.TranscriptRenderExecution.cs`, `ChatWindow.TranscriptRendering.cs` (체인 삽입)
---
### 12-4. LSP 코드 인텔리전스 도구 확장
`lsp_code_intel` 도구를 6개 액션에서 9개로 확장하여 구조적 코드 탐색을 대폭 강화했습니다.
| 액션 | 용도 | 신규 |
|------|------|------|
| `goto_definition` | 심볼 정의 위치 | |
| `find_references` | 심볼 사용 위치 | |
| `hover` | 타입/문서 정보 | ✅ |
| `goto_implementation` | 인터페이스/추상 구현 위치 | ✅ |
| `symbols` | 파일 내 심볼 목록 | |
| `workspace_symbols` | 워크스페이스 전체 심볼 검색 | ✅ |
| `prepare_call_hierarchy` | 호출 계층 기준 심볼 | ✅ |
| `incoming_calls` | 상위 호출자 | ✅ |
| `outgoing_calls` | 하위 호출 대상 | ✅ |
**주요 변경:**
- `line`/`character` 입력: 1-based 기대 → 내부에서 0-based 자동 변환 (`NormalizePosition`)
- `query` 파라미터 추가 (workspace_symbols용)
- 결과에 파일 수, 대표 위치, 첫 결과 요약 포함
- LSP 프로토콜: `textDocument/implementation`, `textDocument/hover`, `workspace/symbol`, `textDocument/prepareCallHierarchy`, `callHierarchy/incomingCalls`, `callHierarchy/outgoingCalls`
**파일:** `LspTool.cs`, `LspClientService.cs`
---
### 12-5. IBM/Qwen 도구 이력 평탄화
IBM watsonx + Qwen 배포형에서 `tool_calls`/`role=tool` 이력 검사가 엄격한 문제를 해결합니다.
**변경 전:**
```
assistant { tool_calls: [...] } → tool { tool_call_id, content }
```
**변경 후 (평탄 transcript):**
```
assistant: "텍스트\n<tool_call>\n{name,arguments}\n</tool_call>"
user: "[Tool Result: tool_name] (id=xxx)\ncontent"
```
**핵심 메서드:**
- `BuildIbmAssistantTranscript()` — tool_use 블록 → `<tool_call>` 태그 직렬화
- `BuildIbmToolResultTranscript()` — tool_result → `[Tool Result]` 헤더 + 내용
- `TryExtractTextContent()` — string/array/nested 형태 모두 텍스트 추출
- `TryParseContentArrayToolBlock()` — content 배열 내 tool_use/tool_call 블록 파싱
**파일:** `LlmService.ToolUse.cs`
---
### 12-6. 도구 노출 순서 정렬 및 프롬프트 완화
**도구 순서 (`ToolRegistry.OrderToolsForExposure`):**
| 버킷 | 도구 |
|------|------|
| 0 (최우선) | file_read, file_edit, glob, grep, lsp_code_intel, build_run, document_plan, 생성 도구 등 |
| 1 | document_review, format_convert, tool_search, code_search |
| 2 | mcp_*, spawn_agent, wait_agents |
| 3 | task_* |
**프롬프트 완화 (SystemPromptBuilder):**
- "Tools First, Always" → "Tools First When Needed"
- `tool_search`: 후보에서 바로 선택 가능하면 직접 호출, 모호할 때만 사용
- `spawn_agent`: 병렬 조사가 실제로 도움이 될 때만 사용
- `document_review`: 큰 문서/명시적 요청 시에만 권장
- Code 탐색: 정의/참조/구현/호출관계 → `lsp_code_intel` 우선
**파일:** `ToolRegistry.cs`, `ChatWindow.SystemPromptBuilder.cs`, `AgentLoopService.cs`, `TaskTypePolicy.cs`, `AgentLoopExplorationPolicy.cs`
---
## 13. 디렉토리별 가이드
| 디렉토리 | 수정 시 주의사항 |
|---------|----------------|
| `Core/` | `FuzzyEngine` 점수 공식 변경 시 검색 품질에 직접 영향 |
| `Handlers/` | 새 핸들러 추가 시 `App.xaml.cs`에 등록 필요 |
| `Services/Agent/` | 새 도구 추가 시 `ToolRegistry`에 등록 + 스킬 파일(`.skill.md`) 작성 + `ToolTabOverrides`에 탭 카테고리 지정 |
| `Themes/` | 리소스 키 변경 시 모든 테마에 동일하게 적용 필요 |
| `Models/AppSettings.cs` | 속성 추가 시 `SettingsService` 마이그레이션 고려 |
| `Views/ChatWindow.*` | partial class 분할 — 관련 기능은 해당 파일에서 수정 |
---
### 12-7. PPT 고품질 템플릿 시스템
`template` 파라미터로 8개 고품질 양식의 색상/레이아웃을 사용할 수 있습니다.
**현재 구현 (방법 1 — 내장 메타데이터):**
- 각 템플릿의 테마 색상을 `FullThemes` 딕셔너리에 하드코딩 (0KB 추가)
- 원본 .pptx 없이도 동일 색상+레이아웃으로 PPT 생성 가능
- 원본 .pptx가 `Assets/ppt/` 또는 `%APPDATA%/AXCopilot/templates/ppt/`에 있으면 마스터 복제(고품질) 자동 업그레이드
| 템플릿 이름 | 원본 파일 | 색상 특징 |
|------------|----------|----------|
| `basic100` | BASIC100 기준 템플릿 V1.pptx (67MB) | 모던 블루 (#2572EF) |
| `core100` | CORE100 기준템플릿 V1.pptx (141MB) | 딥 블루 (#266DF1) |
| `frame_blue` | 프레임디자인 블루 (19MB) | 프레임 블루 (#126BF6) + 카드 |
| `mr_ppt_01` | 미스터 피피티 01 (18MB) | 다크 네이비 + 블루 (#0049F0) |
| `mr_ppt_02` | 미스터 피피티 02 (24MB) | 블루 + 그레이 카드 (#2269F7) |
| `mr_ppt_03` | 미스터 피피티 03 (5.5MB) | 네이비 + 골드 (#F4BB05) |
| `mr_ppt_04` | 미스터 피피티 04 (8.8MB) | 딥 인디고 + 스카이블루 (#0583F2) |
| `mr_ppt_05` | 미스터 피피티 05 (16MB) | 모던 블랙 + 블루 (#007AF9) |
**향후 구현 옵션:**
#### 방법 2 — 자동 다운로드 (권장)
```
첫 사용 시 사내 NAS/서버에서 템플릿 자동 다운로드 → %APPDATA%/AXCopilot/templates/ppt/ 캐시
구현 포인트:
- AppSettings에 TemplateServerUrl 설정 추가 (예: https://nas.internal/ax-templates/)
- ResolveTemplatePath에서 파일 미발견 시 다운로드 트리거
- 다운로드 진행률 UI (ChatWindow 또는 설정 화면)
- 오프라인 폴백: 내장 메타데이터(방법 1)로 자동 전환
- 버전 관리: 서버에 manifest.json → 로컬 캐시 버전과 비교
예상 작업량: 중 (다운로드 서비스 + UI + 설정)
파일: PptxSkill.cs, AppSettings.cs, SettingsService.cs
```
#### 방법 3 — 빌드에 포함
```
csproj에 Content로 등록하여 배포 패키지에 포함
구현:
1. AxCopilot.csproj에 아래 추가:
<Content Include="Assets\ppt\*.pptx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
2. 설치파일 용량 영향: +~200MB (압축 후)
- 현재 설치파일 ~107MB → ~307MB 예상
3. 선택적 포함 (용량 절충):
- 경량 템플릿만 포함 (mr_ppt_03: 5.5MB, mr_ppt_04: 8.8MB 등)
- 대형 템플릿 (core100: 141MB)은 방법 2로 다운로드
<Content Include="Assets\ppt\미스터*" Condition="Exists('Assets\ppt\')">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
주의: build.bat의 payload.zip 압축 단계에서 자동 포함됨
```
---
## 14. 지능형 에이전트 고도화 (oh-my-openagent 참조)
> 상세 계획: `docs/AGENT_ROADMAP.md` 8절 참조
### 즉시 개발 (P1~P5)
| 순위 | 기능 | 핵심 파일 | 설명 |
|------|------|----------|------|
| P1 | **IntentGate** (의도 분류기) | `IntentGateService.cs`(신규) | 사용자 입력 → 작업 유형 자동 분류 → 최적 실행 프로파일(temperature/tool 권한/반복 상한) 자동 적용. 기존 `ClassifyTaskType` + `IntentDetector` 통합 확장 |
| P2 | **카테고리 서브에이전트 프로파일** | `SubAgentProfile.cs`(신규), `SubAgentTool.cs` | 단일 모델 + 다른 system prompt/tool 권한/temperature 조합으로 가상 멀티에이전트. researcher/coder/writer/reviewer/planner 5개 프로파일 |
| P3 | **누적 학습** | `SessionLearningCollector.cs`(신규) | 세션 내 발견사항(빌드 에러, 파일 구조, 패턴)을 자동 수집하여 후속 반복에 컨텍스트로 주입. 반복 실수 방지 |
| P4 | **워크스페이스 컨텍스트 자동 생성** | `WorkspaceContextGenerator.cs`(신규) | 작업 폴더 구조/기술스택을 `.ax-context.md`로 자동 생성. 서브에이전트 컨텍스트 효율화 |
| P5 | **병렬 서브에이전트 확장** | `SpawnAgentsTool.cs`(신규) | 여러 서브에이전트를 한 번에 생성/실행. IntentGate 연동으로 복합 요청 자동 분해 |
### 추후 개발 (P6~P7)
| 순위 | 기능 | 선행 조건 | 설명 |
|------|------|----------|------|
| P6 | **폴백 체인** | P1 + P2 | 실행 실패 시 다른 프로파일/전략으로 자동 재시도 (최대 2회) |
| P7 | **모델 성격 매칭** | P1 + 멀티모델 | 작업 유형별 최적 모델 자동 선택 (RegisteredModel.strengths 매칭) |
### 구현 의존 관계
```
P1 (IntentGate) ─────┬──→ P2 (카테고리 프로파일) ──→ P5 (병렬 확장)
├──→ P3 (누적 학습) [독립]
└──→ P4 (워크스페이스 컨텍스트) [독립]
P1 + P2 완료 후 ──→ P6 (폴백 체인)
P1 + 멀티모델 후 ──→ P7 (모델 성격 매칭)
```
---
## 15. 복원 체크포인트
UI 디자인 대규모 리팩토링 등 위험 작업 전 기록한 안전 복원 지점입니다.
| 날짜 | 커밋 해시 | 설명 | 복원 명령 |
|------|-----------|------|-----------|
| 2026-04-13 | `4d1d160` | UI 디자인 개선 직전 — 테마 교정, IBM 진단 로깅, 뷰어 명칭 변경 완료 (704 tests pass) | `git checkout 4d1d160 -- src/AxCopilot/` |
> **전체 롤백**: `git revert <커밋>` 또는 `git reset --hard 4d1d160` (주의: 이후 작업 모두 소실)
> **부분 복원**: `git checkout 4d1d160 -- <파일경로>` 로 특정 파일만 되돌리기
---
## 16. 관련 문서
| 문서 | 내용 |
|------|------|
| `docs/AGENT_ROADMAP.md` | 에이전트 기능 로드맵 (지능형 고도화 P1~P7 상세 포함) |
| `docs/LAUNCHER_ROADMAP.md` | 런처 기능 로드맵 |
| `docs/OPENCODE_PARITY_PLAN.md` | OpenCode 기능 대응 계획 |
| `docs/TOOL_PARITY_REPORT.md` | 도구 호환성 리포트 |
| `docs/AX_AGENT_UI_CHECKLIST.md` | 에이전트 UI 체크리스트 |
| `docs/UI_UX_CHECKLIST.md` | UI/UX 체크리스트 |
> 업데이트: 2026-04-14 18:08 (KST)
> - 스킬 시스템 Phase 2 1~6번을 반영했습니다. `SkillService`는 프로젝트 `.claude/skills` 재귀 로드, namespaced `SKILL.md`, 번들 스킬 주입, `$ARGUMENTS`/named args/스킬 폴더 변수 치환, inline shell block 실행까지 지원하도록 확장했습니다.
> - `ChatWindow` 런타임 경로도 함께 정리했습니다. 슬래시 호출은 `BuildSlashInvocationAsync`를 통해 컴파일된 스킬 프롬프트를 사용하고, 일반 대화는 `when_to_use`/`paths`/`user-invocable` 메타데이터를 바탕으로 선택된 자동 스킬 가이드를 보조 시스템 프롬프트로 붙입니다.
> - 설정/UI 연결도 새 스킬 모델 기준으로 맞췄습니다. Agent 설정, 일반 설정, 오버레이, 스킬 관리자 도구는 번들/프로젝트/사용자 스킬 분류와 프로젝트 `.claude/skills` 경로를 반영해 설명과 리스트를 구성합니다.
> - 도구 노출 단계는 `AgentLoopService.GetRuntimeActiveTools()`에서 blanket deny 권한을 먼저 적용하도록 보강했습니다. 패턴 기반 규칙은 call-time 검사를 유지하고, 단순 deny 도구는 모델 노출 전 필터링으로 정리했습니다.
> - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_phase2\\ -p:IntermediateOutputPath=obj\\verify_phase2\\` 경고 0 / 오류 0
> - 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentToolCatalogTests|SkillServiceRuntimePolicyTests" -p:OutputPath=bin\\verify_phase2_tests\\ -p:IntermediateOutputPath=obj\\verify_phase2_tests\\` 통과 16
> - 참고: 테스트 프로젝트의 기존 nullable 경고 `src/AxCopilot.Tests/Services/WorkspaceContextGeneratorTests.cs(76)` 1건은 유지됩니다.
> 업데이트: 2026-04-14 18:22 (KST)
> - 스킬 소스 확장 Phase 3을 반영했습니다. `SkillService`는 상위 디렉터리까지 포함한 프로젝트 `.claude/skills` 탐색, 플러그인 스킬 폴더 탐색, 추가 공용 폴더 목록, `.claude/commands` markdown command를 legacy skill로 변환하는 경로를 함께 지원합니다.
> - 파일형 스킬은 body를 즉시 메모리에 올리지 않고 필요 시점에만 읽는 lazy prompt body 캐시를 추가했습니다. `SkillManagerTool`, `SkillEditorWindow`, `SkillGalleryWindow`는 이 경로를 통해 실제 본문을 표시합니다.
> - 인자 모델도 확장했습니다. `arguments`와 `argument-hint`를 함께 해석해 named placeholder 치환을 강화했고, 인자가 부족하면 usage 가이드를 프롬프트 앞에 붙여 실행 품질을 보완합니다.
> - 도구 deny 필터는 `AgentToolCatalog` 공통 메서드로 이동해 런타임과 설정 UI가 같은 blanket deny 규칙을 공유하도록 정리했습니다.
> - 설정 저장에는 `additionalSkillFolders`를 추가했고, 일반 설정/AX Agent 설정 UI에 줄 단위 입력 필드를 넣어 여러 공용 스킬 폴더를 연결할 수 있게 했습니다.
> - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_phase3\\ -p:IntermediateOutputPath=obj\\verify_phase3\\` 경고 0 / 오류 0
> - 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentToolCatalogTests|SkillServiceRuntimePolicyTests" -p:OutputPath=bin\\verify_phase3_tests\\ -p:IntermediateOutputPath=obj\\verify_phase3_tests\\` 통과 18
> - 참고: 테스트 프로젝트의 기존 nullable 경고 `src/AxCopilot.Tests/Services/WorkspaceContextGeneratorTests.cs(76)` 1건은 유지됩니다.
> 업데이트: 2026-04-14 18:33 (KST)
> - 스킬 정책 제어를 추가했습니다. `LlmSettings`에 `enableProjectSkillDiscovery`, `enablePluginSkillDiscovery`, `enableLegacyCommandSkills`, `enableSkillInlineShell`, `skillInlineShellTimeoutSeconds`, `skillInlineShellMaxOutputChars`를 추가하고 일반 설정/AX Agent 설정 UI에 연결했습니다.
> - 스킬 로드 시그니처는 이제 소스 디렉터리 목록뿐 아니라 실제 스킬 파일 수와 최근 수정 시각을 함께 반영합니다. 같은 폴더 구성이라도 파일 내용이 바뀌면 다음 로드 요청에서 재탐색됩니다.
> - inline shell 실행기는 설정 기반 비활성화, timeout, 출력 길이 제한을 적용하도록 보강했습니다. 비활성 상태나 시간 초과는 프롬프트 안에서 식별 가능한 안내 문자열로 반환합니다.
> - `SkillEditorWindow`와 `SkillGalleryWindow`는 lazy prompt body 경로를 사용하도록 맞췄고, 설정 변경 후 `ReloadFromCurrentSettings()`를 통해 현재 스킬 소스를 다시 읽도록 정리했습니다.
> - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_phase4b\\ -p:IntermediateOutputPath=obj\\verify_phase4b\\` 경고 0 / 오류 0
> - 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentToolCatalogTests|SkillServiceRuntimePolicyTests" -p:OutputPath=bin\\verify_phase4b_tests\\ -p:IntermediateOutputPath=obj\\verify_phase4b_tests\\` 통과 18
> - 참고: 테스트 프로젝트의 기존 nullable 경고 `src/AxCopilot.Tests/Services/WorkspaceContextGeneratorTests.cs(76)` 1건은 유지됩니다.
- 업데이트: 2026-04-14 18:37 (KST)
- claude-code 로컬 스냅샷을 다시 확인했지만, 현재 스냅샷에는 PPT/문서 전용 번들 스킬이 뚜렷하지 않았습니다. 대신 AX가 기본 포함하고 있는 문서형 managed skill 세트를 중심으로 배포 자산 품질을 다듬었습니다.
- pptx-creator, docx-creator, report-writer, prd-generator, meeting-minutes, weekly-report, markdown-to-doc에 when_to_use와 argument-hint 메타를 추가해 proactive skill 선택과 슬래시 호출 가이드를 보강했습니다.
- 일반 설정과 AX Agent 설정의 스킬 목록은 managed 스코프를 별도 기본 제공 스킬 그룹으로 분리했고, 스킬 갤러리도 기본 제공 / 프로젝트 / 플러그인 / 사용자 / 고급 필터와 배지를 사용하도록 정리했습니다.
- 이 변경으로 문서·프레젠테이션 스킬은 빌드 출력 skills 폴더를 통해 기본 배포되면서도, UI에서 사용자 스킬과 구분된 상태로 확인할 수 있습니다.
- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_docskills\\ -p:IntermediateOutputPath=obj\\verify_docskills\\ 경고 0 / 오류 0