권한 팝업 순서/즉시반영 정렬: Deny 상단 배치와 탭 기본값 강제
Some checks failed
Release Gate / gate (push) Has been cancelled

- 권한 팝업 핵심 영역에 Deny(활용하지 않음) 포함, 고급은 DontAsk만 유지

- LoadConversationSettings가 대화 권한 미설정 시 탭 기본권한(Chat=Deny, Cowork/Code=DefaultAgentPermission) 즉시 적용

- PermissionModePresentationCatalog 한글 라벨/설명 문자열 정리

- README/DEVELOPMENT 이력(2026-04-04 15:52 KST) 동기화
This commit is contained in:
2026-04-04 15:52:58 +09:00
parent f8669c735d
commit 666416ff65
4 changed files with 40 additions and 13 deletions

View File

@@ -222,7 +222,7 @@ public class MyHandler : IActionHandler
### v0.7.3 — AX Agent 권한 코어 재구성 + 입력 계층 정리 ### v0.7.3 — AX Agent 권한 코어 재구성 + 입력 계층 정리
업데이트: 2026-04-04 15:48 (KST) 업데이트: 2026-04-04 15:52 (KST)
| 분류 | 내용 | | 분류 | 내용 |
|------|------| |------|------|
@@ -290,6 +290,7 @@ public class MyHandler : IActionHandler
| 권한 모드 별칭 정합 보강 | `/permissions`, `/allowed-tools`에서 `none/passive/active/planning/fullauto/silent` 별칭을 지원하고 카탈로그 정규화와 일치시킴 | | 권한 모드 별칭 정합 보강 | `/permissions`, `/allowed-tools`에서 `none/passive/active/planning/fullauto/silent` 별칭을 지원하고 카탈로그 정규화와 일치시킴 |
| 권한 기본값 정책 정렬 | 신규/초기 상태의 기본 권한을 `활용하지 않음(Deny)`으로 변경하고 AppState 기본/요약 상태와 slash 사용 가이드를 동일 체계로 정렬 | | 권한 기본값 정책 정렬 | 신규/초기 상태의 기본 권한을 `활용하지 않음(Deny)`으로 변경하고 AppState 기본/요약 상태와 slash 사용 가이드를 동일 체계로 정렬 |
| 탭 전환 빈 대화 누적 방지 | 탭 전환 중 생성되는 무의미한 빈 대화를 저장 대상에서 제외하고, 목록에서도 빈 노이즈 항목을 숨겨 이력 누적 체감 버그를 완화 | | 탭 전환 빈 대화 누적 방지 | 탭 전환 중 생성되는 무의미한 빈 대화를 저장 대상에서 제외하고, 목록에서도 빈 노이즈 항목을 숨겨 이력 누적 체감 버그를 완화 |
| 권한 팝업 즉시반영 정렬 | 권한 팝업에 `활용하지 않음`을 핵심 영역 맨 위에 배치하고, 대화 권한이 없을 때도 탭 기본값(Deny/DefaultAgentPermission)을 즉시 반영하도록 로딩 경로를 보강 |
| Slash palette 상태 분리 시작 | `ChatWindow`에 몰려 있던 slash 상태를 `SlashPaletteState`로 분리해 이후 Codex/Claude형 composer 개편 기반 마련 | | Slash palette 상태 분리 시작 | `ChatWindow`에 몰려 있던 slash 상태를 `SlashPaletteState`로 분리해 이후 Codex/Claude형 composer 개편 기반 마련 |
| 런처 이미지 미리보기 추가 | `#` 클립보드 이미지 항목에서 `Shift+Enter`로 전용 미리보기 창을 열고, 줌·원본 해상도 확인·PNG/JPEG/BMP 저장·클립보드 복사를 지원 | | 런처 이미지 미리보기 추가 | `#` 클립보드 이미지 항목에서 `Shift+Enter`로 전용 미리보기 창을 열고, 줌·원본 해상도 확인·PNG/JPEG/BMP 저장·클립보드 복사를 지원 |
| 검증 | `dotnet build` 경고 0 / 오류 0, `dotnet test` 436 passed / 0 failed | | 검증 | `dotnet build` 경고 0 / 오류 0, `dotnet test` 436 passed / 0 failed |

View File

@@ -3605,3 +3605,25 @@ else:
### 4) 품질 게이트 ### 4) 품질 게이트
- `dotnet build src/AxCopilot/AxCopilot.csproj -c Debug -p:UseSharedCompilation=false -nodeReuse:false` 통과 (경고 0, 오류 0). - `dotnet build src/AxCopilot/AxCopilot.csproj -c Debug -p:UseSharedCompilation=false -nodeReuse:false` 통과 (경고 0, 오류 0).
- `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj --filter "FullyQualifiedName~ChatSessionStateServiceTests|FullyQualifiedName~AppStateServiceTests|FullyQualifiedName~OperationModePolicyTests|FullyQualifiedName~ChatWindowSlashPolicyTests"` 통과 (132 passed, 0 failed). - `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj --filter "FullyQualifiedName~ChatSessionStateServiceTests|FullyQualifiedName~AppStateServiceTests|FullyQualifiedName~OperationModePolicyTests|FullyQualifiedName~ChatWindowSlashPolicyTests"` 통과 (132 passed, 0 failed).
## 2026-04-04 추가 진행 기록 (연속 실행 40차: 권한 팝업 순서/즉시반영 정렬)
업데이트: 2026-04-04 15:52 (KST)
### 1) 권한 팝업 표시 순서 정렬
- `ChatWindow` 권한 팝업의 핵심 모드 목록에 `활용하지 않음(Deny)`을 포함해 맨 위에서 선택 가능하도록 조정.
- 고급 모드는 `질문 없이 진행(DontAsk)`만 유지해 핵심/고급 구분을 단순화.
### 2) 탭/대화 전환 시 권한 즉시반영 보강
- `LoadConversationSettings`에서 대화 권한이 비어 있는 경우에도 명시적으로 탭 기본값을 적용:
- `Chat` 탭: `Deny`
- `Cowork/Code` 탭: `DefaultAgentPermission`
- 효과: 이전 대화의 권한 값이 남아 2번 눌러야 반영되는 현상 완화.
### 3) 권한 프리젠테이션 카탈로그 문자열 정리
- `PermissionModePresentationCatalog`의 권한 라벨/설명 문자열을 정상 한글 문구로 정리(깨짐 문자열 제거).
- 표시 문구와 실제 권한 의미를 일치시켜 UX 혼선을 줄임.
### 4) 품질 게이트
- `dotnet build src/AxCopilot/AxCopilot.csproj -c Debug -p:UseSharedCompilation=false -nodeReuse:false` 통과 (경고 0, 오류 0).
- `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj --filter "FullyQualifiedName~PermissionModePresentationCatalogTests|FullyQualifiedName~PermissionModeCatalogTests|FullyQualifiedName~ChatWindowSlashPolicyTests|FullyQualifiedName~ChatSessionStateServiceTests"` 통과 (111 passed, 0 failed).

View File

@@ -1,4 +1,4 @@
namespace AxCopilot.Services.Agent; namespace AxCopilot.Services.Agent;
internal sealed record PermissionModePresentation( internal sealed record PermissionModePresentation(
string Mode, string Mode,
@@ -15,37 +15,37 @@ internal static class PermissionModePresentationCatalog
PermissionModeCatalog.Deny, PermissionModeCatalog.Deny,
"\uE711", "\uE711",
"활용하지 않음", "활용하지 않음",
"파일 읽기만 허용하고 생성/수정/삭제 차단합니다", "파일 읽기만 허용하고 생성/수정/삭제 차단합니다.",
"#107C10"), "#107C10"),
new PermissionModePresentation( new PermissionModePresentation(
PermissionModeCatalog.Default, PermissionModeCatalog.Default,
"\uE8D7", "\uE8D7",
"소극 활용", "소극 활용",
"변경 전 확인하 필요할 때만 파일 접근을 진행합니다", "변경 전 확인하고, 필요한 경우에만 파일 접근을 진행합니다.",
"#2563EB"), "#2563EB"),
new PermissionModePresentation( new PermissionModePresentation(
PermissionModeCatalog.AcceptEdits, PermissionModeCatalog.AcceptEdits,
"\uE73E", "\uE73E",
"적극 활용", "적극 활용",
"파일 편집 도구를 자동 승인하고 명령 실행은 계속 확인합니다", "파일 편집 도구를 자동 승인하고 명령 실행은 계속 확인합니다.",
"#107C10"), "#107C10"),
new PermissionModePresentation( new PermissionModePresentation(
PermissionModeCatalog.Plan, PermissionModeCatalog.Plan,
"\uE7C3", "\uE7C3",
"계획 중심", "계획 중심",
"쓰기 전 계획/승인 흐름을 우선합니다", "쓰기 전 계획승인 흐름을 우선합니다.",
"#4338CA"), "#4338CA"),
new PermissionModePresentation( new PermissionModePresentation(
PermissionModeCatalog.BypassPermissions, PermissionModeCatalog.BypassPermissions,
"\uE814", "\uE814",
"완전 자동", "완전 자동",
"권한 확인을 대부분 생략합니다. 민감 작업 주의하세요", "권한 확인을 대부분 생략합니다. 민감 작업 주의하세요.",
"#B45309"), "#B45309"),
new PermissionModePresentation( new PermissionModePresentation(
PermissionModeCatalog.DontAsk, PermissionModeCatalog.DontAsk,
"\uE8A5", "\uE8A5",
"질문 없이 진행", "질문 없이 진행",
"권한 질문 없이 진행합니다. 자동 실행 범위를 점검하세요", "권한 질문 없이 진행합니다. 자동 실행 범위를 점검하세요.",
"#B91C1C"), "#B91C1C"),
}; };

View File

@@ -1561,8 +1561,13 @@ public partial class ChatWindow : Window
lock (_convLock) conv = _currentConversation; lock (_convLock) conv = _currentConversation;
var llm = _settings.Settings.Llm; var llm = _settings.Settings.Llm;
if (conv != null && conv.Permission != null) var fallbackPermission = _activeTab == "Chat"
_settings.Settings.Llm.FilePermission = PermissionModeCatalog.NormalizeGlobalMode(conv.Permission); ? PermissionModeCatalog.Deny
: PermissionModeCatalog.NormalizeGlobalMode(llm.DefaultAgentPermission);
var conversationPermission = !string.IsNullOrWhiteSpace(conv?.Permission)
? PermissionModeCatalog.NormalizeGlobalMode(conv.Permission)
: fallbackPermission;
_settings.Settings.Llm.FilePermission = conversationPermission;
_folderDataUsage = conv?.DataUsage ?? llm.FolderDataUsage ?? "none"; _folderDataUsage = conv?.DataUsage ?? llm.FolderDataUsage ?? "none";
_selectedMood = conv?.Mood ?? llm.DefaultMood ?? "modern"; _selectedMood = conv?.Mood ?? llm.DefaultMood ?? "modern";
@@ -1903,15 +1908,14 @@ public partial class ChatWindow : Window
var coreLevels = PermissionModePresentationCatalog.Ordered var coreLevels = PermissionModePresentationCatalog.Ordered
.Where(x => .Where(x =>
string.Equals(x.Mode, PermissionModeCatalog.Deny, StringComparison.OrdinalIgnoreCase) ||
string.Equals(x.Mode, PermissionModeCatalog.Default, StringComparison.OrdinalIgnoreCase) || string.Equals(x.Mode, PermissionModeCatalog.Default, StringComparison.OrdinalIgnoreCase) ||
string.Equals(x.Mode, PermissionModeCatalog.AcceptEdits, StringComparison.OrdinalIgnoreCase) || string.Equals(x.Mode, PermissionModeCatalog.AcceptEdits, StringComparison.OrdinalIgnoreCase) ||
string.Equals(x.Mode, PermissionModeCatalog.Plan, StringComparison.OrdinalIgnoreCase) || string.Equals(x.Mode, PermissionModeCatalog.Plan, StringComparison.OrdinalIgnoreCase) ||
string.Equals(x.Mode, PermissionModeCatalog.BypassPermissions, StringComparison.OrdinalIgnoreCase)) string.Equals(x.Mode, PermissionModeCatalog.BypassPermissions, StringComparison.OrdinalIgnoreCase))
.ToList(); .ToList();
var advancedLevels = PermissionModePresentationCatalog.Ordered var advancedLevels = PermissionModePresentationCatalog.Ordered
.Where(x => .Where(x => string.Equals(x.Mode, PermissionModeCatalog.DontAsk, StringComparison.OrdinalIgnoreCase))
string.Equals(x.Mode, PermissionModeCatalog.Deny, StringComparison.OrdinalIgnoreCase) ||
string.Equals(x.Mode, PermissionModeCatalog.DontAsk, StringComparison.OrdinalIgnoreCase))
.ToList(); .ToList();
var current = PermissionModeCatalog.NormalizeGlobalMode(_settings.Settings.Llm.FilePermission); var current = PermissionModeCatalog.NormalizeGlobalMode(_settings.Settings.Llm.FilePermission);
void AddPermissionRows(Panel container, IEnumerable<PermissionModePresentation> levels) void AddPermissionRows(Panel container, IEnumerable<PermissionModePresentation> levels)