From 15b675d9c4ae0957f78e64ba57096df443319ee7 Mon Sep 17 00:00:00 2001 From: lacvet Date: Sat, 4 Apr 2026 13:26:34 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B6=8C=ED=95=9C=20=ED=91=9C=EC=8B=9C=20?= =?UTF-8?q?=EC=B9=B4=ED=83=88=EB=A1=9C=EA=B7=B8=EB=A5=BC=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=ED=95=B4=20UI=20=ED=91=9C=EB=A9=B4=20=EA=B8=B0?= =?UTF-8?q?=EC=A4=80=EC=9D=84=20=EB=8B=A8=EC=9D=BC=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PermissionModePresentationCatalog 신규 추가: 모드 라벨/설명/아이콘/색을 단일 소스로 관리 - ChatWindow 권한 팝업에서 하드코딩 튜플을 제거하고 카탈로그 기반 렌더링으로 전환 - 유지보수 관점에서 권한 표면 기준 변경 포인트를 1곳으로 축소 - README.md 업데이트 시각(2026-04-04 13:25 KST) 및 변경 이력 항목 갱신 - docs/DEVELOPMENT.md 연속 실행 27차 기록 추가 - 검증: dotnet build 경고 0/오류 0, slash+operation mode 필터 테스트 43건 통과 --- README.md | 3 +- docs/DEVELOPMENT.md | 21 +++++++ .../PermissionModePresentationCatalog.cs | 59 +++++++++++++++++++ src/AxCopilot/Views/ChatWindow.xaml.cs | 23 +++----- 4 files changed, 90 insertions(+), 16 deletions(-) create mode 100644 src/AxCopilot/Services/Agent/PermissionModePresentationCatalog.cs diff --git a/README.md b/README.md index 027915c..71622f1 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,7 @@ public class MyHandler : IActionHandler ### v0.7.3 — AX Agent 권한 코어 재구성 + 입력 계층 정리 -업데이트: 2026-04-04 13:24 (KST) +업데이트: 2026-04-04 13:25 (KST) | 분류 | 내용 | |------|------| @@ -277,6 +277,7 @@ public class MyHandler : IActionHandler | 권한 요청창 한국어/인코딩 복구 | `PermissionRequestWindow`의 깨진 문자열을 복구하고 권한 선택/위험도/미리보기 문구를 한국어 기준으로 정리 | | slash 명령 카탈로그 분리 | `ChatWindow` 내부 대형 slash 사전을 `SlashCommandCatalog`로 분리해 입력 계층 결합도를 낮추고 유지보수 범위를 축소 | | slash 조회 API 전환 | 내장 slash 매칭/조회 경로를 `SlashCommandCatalog.MatchBuiltinCommands`/`TryGetEntry`로 통일 | +| 권한 표시 카탈로그 분리 | 권한 모드 라벨/설명/아이콘/색을 `PermissionModePresentationCatalog`로 분리해 팝업 표면 기준을 단일화 | | Slash palette 상태 분리 시작 | `ChatWindow`에 몰려 있던 slash 상태를 `SlashPaletteState`로 분리해 이후 Codex/Claude형 composer 개편 기반 마련 | | 런처 이미지 미리보기 추가 | `#` 클립보드 이미지 항목에서 `Shift+Enter`로 전용 미리보기 창을 열고, 줌·원본 해상도 확인·PNG/JPEG/BMP 저장·클립보드 복사를 지원 | | 검증 | `dotnet build` 경고 0 / 오류 0, `dotnet test` 436 passed / 0 failed | diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 936d23f..9f6e6ca 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -3322,3 +3322,24 @@ else: ### 3) 참고 - 테스트 재빌드 시점에 AxCopilot.dll 파일 잠금(CS2012)이 간헐 발생하여, 빌드 산출물 기준 --no-build 실행으로 테스트를 검증함. +## 2026-04-04 추가 진행 기록 (연속 실행 27차: 권한 표시 카탈로그 단일화) + +업데이트: 2026-04-04 13:25 (KST) + +### 1) 권한 표시 카탈로그 분리 +- 신규 파일 PermissionModePresentationCatalog를 추가. +- 권한 모드별 라벨/설명/아이콘/색상 정보를 단일 소스로 관리: + - 활용하지 않음 + - 소극 활용 + - 적극 활용 + - 계획 중심 + - 완전 자동 + - 질문 없이 진행 + +### 2) ChatWindow 연동 +- 권한 팝업의 핵심 모드 리스트 생성 시 하드코딩 튜플을 제거하고 카탈로그를 사용하도록 전환. +- 결과: 권한 표면 기준(순서/문구/아이콘/색상)의 유지보수 포인트를 1곳으로 축소. + +### 3) 품질 게이트 +- dotnet build src/AxCopilot/AxCopilot.csproj 통과 (경고 0, 오류 0). +- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj --no-build --filter "FullyQualifiedName~ChatWindowSlashPolicyTests|FullyQualifiedName~OperationModeReadinessTests" 통과 (43 passed, 0 failed). diff --git a/src/AxCopilot/Services/Agent/PermissionModePresentationCatalog.cs b/src/AxCopilot/Services/Agent/PermissionModePresentationCatalog.cs new file mode 100644 index 0000000..e04d187 --- /dev/null +++ b/src/AxCopilot/Services/Agent/PermissionModePresentationCatalog.cs @@ -0,0 +1,59 @@ +namespace AxCopilot.Services.Agent; + +internal sealed record PermissionModePresentation( + string Mode, + string Icon, + string Title, + string Description, + string ColorHex); + +internal static class PermissionModePresentationCatalog +{ + public static readonly IReadOnlyList Ordered = new[] + { + new PermissionModePresentation( + PermissionModeCatalog.Deny, + "\uE711", + "활용하지 않음", + "파일 읽기만 허용하고 생성/수정/삭제를 차단합니다", + "#107C10"), + new PermissionModePresentation( + PermissionModeCatalog.Default, + "\uE8D7", + "소극 활용", + "변경 전 확인하며 필요할 때만 파일 접근을 진행합니다", + "#2563EB"), + new PermissionModePresentation( + PermissionModeCatalog.AcceptEdits, + "\uE73E", + "적극 활용", + "파일 편집 도구를 자동 승인하고 명령 실행은 계속 확인합니다", + "#107C10"), + new PermissionModePresentation( + PermissionModeCatalog.Plan, + "\uE7C3", + "계획 중심", + "쓰기 전 계획/승인 흐름을 우선합니다", + "#4338CA"), + new PermissionModePresentation( + PermissionModeCatalog.BypassPermissions, + "\uE814", + "완전 자동", + "권한 확인을 대부분 생략합니다. 민감 작업에 주의하세요", + "#B45309"), + new PermissionModePresentation( + PermissionModeCatalog.DontAsk, + "\uE8A5", + "질문 없이 진행", + "권한 질문 없이 진행합니다. 자동 실행 범위를 점검하세요", + "#B91C1C"), + }; + + public static PermissionModePresentation Resolve(string? mode) + { + var normalized = PermissionModeCatalog.NormalizeGlobalMode(mode); + return Ordered.FirstOrDefault(item => + string.Equals(item.Mode, normalized, StringComparison.OrdinalIgnoreCase)) + ?? Ordered[1]; + } +} diff --git a/src/AxCopilot/Views/ChatWindow.xaml.cs b/src/AxCopilot/Views/ChatWindow.xaml.cs index 01058a8..a5fab71 100644 --- a/src/AxCopilot/Views/ChatWindow.xaml.cs +++ b/src/AxCopilot/Views/ChatWindow.xaml.cs @@ -1901,20 +1901,13 @@ public partial class ChatWindow : Window }; } - var coreLevels = new (string Level, string Sym, string Title, string Desc, string Color)[] - { - (PermissionModeCatalog.Deny, "\uE711", "활용하지 않음", "파일 읽기만 허용하고 생성/수정/삭제를 차단합니다", "#107C10"), - (PermissionModeCatalog.Default, "\uE8D7", "소극 활용", "변경 전 확인하며 필요할 때만 파일 접근을 진행합니다", "#2563EB"), - (PermissionModeCatalog.AcceptEdits, "\uE73E", "적극 활용", "파일 편집 도구를 자동 승인하고 명령 실행은 계속 확인합니다", "#107C10"), - (PermissionModeCatalog.Plan, "\uE7C3", "계획 중심", "쓰기 전 계획/승인 흐름을 우선합니다", "#4338CA"), - (PermissionModeCatalog.BypassPermissions, "\uE814", "완전 자동", "권한 확인을 대부분 생략합니다. 민감 작업에 주의하세요", "#B45309"), - (PermissionModeCatalog.DontAsk, "\uE8A5", "질문 없이 진행", "권한 질문 없이 진행합니다. 자동 실행 범위를 점검하세요", "#B91C1C"), - }; + var coreLevels = PermissionModePresentationCatalog.Ordered; var current = PermissionModeCatalog.NormalizeGlobalMode(_settings.Settings.Llm.FilePermission); - void AddPermissionRows(Panel container, IEnumerable<(string Level, string Sym, string Title, string Desc, string Color)> levels) + void AddPermissionRows(Panel container, IEnumerable levels) { - foreach (var (level, sym, title, desc, color) in levels) + foreach (var item in levels) { + var level = item.Mode; var isActive = level.Equals(current, StringComparison.OrdinalIgnoreCase); var rowBorder = new Border { @@ -1936,10 +1929,10 @@ public partial class ChatWindow : Window row.Children.Add(new TextBlock { - Text = sym, + Text = item.Icon, FontFamily = new FontFamily("Segoe MDL2 Assets"), FontSize = 13.5, - Foreground = BrushFromHex(color), + Foreground = BrushFromHex(item.ColorHex), Margin = new Thickness(2, 0, 9, 0), VerticalAlignment = VerticalAlignment.Center, }); @@ -1947,14 +1940,14 @@ public partial class ChatWindow : Window var textStack = new StackPanel(); textStack.Children.Add(new TextBlock { - Text = title, + Text = item.Title, FontSize = 11.5, FontWeight = FontWeights.SemiBold, Foreground = TryFindResource("PrimaryText") as Brush ?? Brushes.White, }); textStack.Children.Add(new TextBlock { - Text = desc, + Text = item.Description, FontSize = 10, Margin = new Thickness(0, 2, 0, 0), Foreground = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray,