- OperationalStatusPresentationCatalog를 추가해 compact strip과 quick strip의 색상/노출 계산을 AppStateService 밖으로 분리함 - PermissionRequestPresentationCatalog와 ToolResultPresentationCatalog에 Kind/Description 메타를 추가해 transcript fallback 설명을 타입 기반으로 정리함 - PermissionModePresentationCatalog와 ChatWindow.PermissionPresentation에서 제거된 계획 모드 표현 분기를 걷어 권한 UI를 실제 지원 모드만 다루도록 단순화함 - README, DEVELOPMENT, claw-code parity plan 문서를 2026-04-06 09:36 (KST) 기준으로 갱신함 - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ (경고 0 / 오류 0)
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
using AxCopilot.Services;
|
||||
|
||||
namespace AxCopilot.Services.Agent;
|
||||
|
||||
internal static class OperationalStatusPresentationCatalog
|
||||
{
|
||||
public static AppStateService.OperationalStatusPresentationState Resolve(
|
||||
AppStateService.OperationalStatusState status,
|
||||
string tab,
|
||||
bool hasLiveRuntimeActivity,
|
||||
int runningConversationCount,
|
||||
int spotlightConversationCount,
|
||||
bool runningOnlyFilter,
|
||||
bool sortConversationsByRecent)
|
||||
{
|
||||
var showCompactStrip = !string.Equals(tab, "Chat", StringComparison.OrdinalIgnoreCase)
|
||||
&& (string.Equals(status.StripKind, "permission_waiting", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(status.StripKind, "failed_run", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(status.StripKind, "permission_denied", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var (stripBackgroundHex, stripBorderHex, stripForegroundHex) = ResolveStripColors(status.StripKind, showCompactStrip);
|
||||
|
||||
var allowQuickStrip = !string.Equals(tab, "Chat", StringComparison.OrdinalIgnoreCase);
|
||||
var quickRunningActive = runningOnlyFilter && runningConversationCount > 0;
|
||||
var quickHotActive = !sortConversationsByRecent && spotlightConversationCount > 0;
|
||||
var showQuickStrip = allowQuickStrip && (quickRunningActive || quickHotActive);
|
||||
|
||||
return new AppStateService.OperationalStatusPresentationState
|
||||
{
|
||||
ShowRuntimeBadge = status.ShowRuntimeBadge && hasLiveRuntimeActivity,
|
||||
RuntimeLabel = status.RuntimeLabel,
|
||||
ShowLastCompleted = status.ShowLastCompleted,
|
||||
LastCompletedText = status.LastCompletedText,
|
||||
ShowCompactStrip = showCompactStrip,
|
||||
StripKind = showCompactStrip ? status.StripKind : "none",
|
||||
StripText = showCompactStrip ? status.StripText : "",
|
||||
StripBackgroundHex = stripBackgroundHex,
|
||||
StripBorderHex = stripBorderHex,
|
||||
StripForegroundHex = stripForegroundHex,
|
||||
ShowQuickStrip = showQuickStrip,
|
||||
QuickRunningText = runningConversationCount > 0 ? $"진행 {runningConversationCount}" : "진행",
|
||||
QuickHotText = spotlightConversationCount > 0 ? $"활동 {spotlightConversationCount}" : "활동",
|
||||
QuickRunningActive = quickRunningActive,
|
||||
QuickHotActive = quickHotActive,
|
||||
QuickRunningBackgroundHex = quickRunningActive ? "#DBEAFE" : "#F8FAFC",
|
||||
QuickRunningBorderHex = quickRunningActive ? "#93C5FD" : "#E5E7EB",
|
||||
QuickRunningForegroundHex = quickRunningActive ? "#1D4ED8" : "#6B7280",
|
||||
QuickHotBackgroundHex = quickHotActive ? "#F5F3FF" : "#F8FAFC",
|
||||
QuickHotBorderHex = quickHotActive ? "#C4B5FD" : "#E5E7EB",
|
||||
QuickHotForegroundHex = quickHotActive ? "#6D28D9" : "#6B7280",
|
||||
};
|
||||
}
|
||||
|
||||
private static (string backgroundHex, string borderHex, string foregroundHex) ResolveStripColors(string stripKind, bool visible)
|
||||
{
|
||||
if (!visible)
|
||||
return ("", "", "");
|
||||
|
||||
if (string.Equals(stripKind, "permission_waiting", StringComparison.OrdinalIgnoreCase))
|
||||
return ("#FFF7ED", "#FDBA74", "#C2410C");
|
||||
|
||||
if (string.Equals(stripKind, "failed_run", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(stripKind, "permission_denied", StringComparison.OrdinalIgnoreCase))
|
||||
return ("#FEF2F2", "#FECACA", "#991B1B");
|
||||
|
||||
return ("", "", "");
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace AxCopilot.Services.Agent;
|
||||
namespace AxCopilot.Services.Agent;
|
||||
|
||||
internal sealed record PermissionModePresentation(
|
||||
string Mode,
|
||||
@@ -23,12 +23,6 @@ internal static class PermissionModePresentationCatalog
|
||||
"편집 자동 승인",
|
||||
"모든 파일 편집을 자동 승인합니다.",
|
||||
"#107C10"),
|
||||
new PermissionModePresentation(
|
||||
PermissionModeCatalog.Plan,
|
||||
"\uE7C3",
|
||||
"계획 모드",
|
||||
"변경하기 전에 계획을 먼저 만듭니다.",
|
||||
"#4338CA"),
|
||||
new PermissionModePresentation(
|
||||
PermissionModeCatalog.BypassPermissions,
|
||||
"\uE814",
|
||||
@@ -41,7 +35,7 @@ internal static class PermissionModePresentationCatalog
|
||||
{
|
||||
var normalized = PermissionModeCatalog.NormalizeGlobalMode(mode);
|
||||
return Ordered.FirstOrDefault(item =>
|
||||
string.Equals(item.Mode, normalized, StringComparison.OrdinalIgnoreCase))
|
||||
?? Ordered[0];
|
||||
string.Equals(item.Mode, normalized, StringComparison.OrdinalIgnoreCase))
|
||||
?? Ordered[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace AxCopilot.Services.Agent;
|
||||
|
||||
internal sealed record PermissionRequestPresentation(
|
||||
string Kind,
|
||||
string Icon,
|
||||
string Label,
|
||||
string Description,
|
||||
string BackgroundHex,
|
||||
string ForegroundHex);
|
||||
|
||||
@@ -15,49 +15,106 @@ internal static class PermissionRequestPresentationCatalog
|
||||
var tool = (toolName ?? string.Empty).Trim().ToLowerInvariant();
|
||||
|
||||
if (tool.Contains("bash") || tool.Contains("powershell") || tool.Contains("process"))
|
||||
{
|
||||
return pending
|
||||
? new PermissionRequestPresentation("\uE756", "명령 실행 권한 요청", "#FEF2F2", "#DC2626")
|
||||
: new PermissionRequestPresentation("\uE73E", "명령 실행 권한 승인", "#ECFDF5", "#059669");
|
||||
}
|
||||
return Build(
|
||||
"command",
|
||||
pending,
|
||||
"\uE756",
|
||||
"명령 실행 권한 요청",
|
||||
"명령 실행 권한 확인",
|
||||
"터미널 명령을 실행하기 전에 확인이 필요합니다.",
|
||||
"명령 실행이 승인되어 계속 진행합니다.",
|
||||
"#FEF2F2",
|
||||
"#DC2626");
|
||||
|
||||
if (tool.Contains("web") || tool.Contains("fetch") || tool.Contains("http"))
|
||||
{
|
||||
return pending
|
||||
? new PermissionRequestPresentation("\uE774", "웹 요청 권한 요청", "#FFF7ED", "#C2410C")
|
||||
: new PermissionRequestPresentation("\uE73E", "웹 요청 권한 승인", "#ECFDF5", "#059669");
|
||||
}
|
||||
return Build(
|
||||
"web",
|
||||
pending,
|
||||
"\uE774",
|
||||
"웹 요청 권한 요청",
|
||||
"웹 요청 권한 확인",
|
||||
"외부 웹 요청 전 사용자 확인이 필요합니다.",
|
||||
"웹 요청이 승인되어 계속 진행합니다.",
|
||||
"#FFF7ED",
|
||||
"#C2410C");
|
||||
|
||||
if (tool.Contains("skill"))
|
||||
{
|
||||
return pending
|
||||
? new PermissionRequestPresentation("\uE8A5", "스킬 실행 권한 요청", "#F5F3FF", "#7C3AED")
|
||||
: new PermissionRequestPresentation("\uE73E", "스킬 실행 권한 승인", "#ECFDF5", "#059669");
|
||||
}
|
||||
return Build(
|
||||
"skill",
|
||||
pending,
|
||||
"\uE8A5",
|
||||
"스킬 실행 권한 요청",
|
||||
"스킬 실행 권한 확인",
|
||||
"연결된 스킬 실행 전 확인이 필요합니다.",
|
||||
"스킬 실행이 승인되어 계속 진행합니다.",
|
||||
"#F5F3FF",
|
||||
"#7C3AED");
|
||||
|
||||
if (tool.Contains("ask"))
|
||||
{
|
||||
return pending
|
||||
? new PermissionRequestPresentation("\uE897", "의견 요청 권한 확인", "#EFF6FF", "#2563EB")
|
||||
: new PermissionRequestPresentation("\uE73E", "의견 요청 권한 승인", "#ECFDF5", "#059669");
|
||||
}
|
||||
return Build(
|
||||
"question",
|
||||
pending,
|
||||
"\uE897",
|
||||
"의견 요청 확인",
|
||||
"의견 요청 완료",
|
||||
"사용자에게 선택이나 답변을 요청합니다.",
|
||||
"사용자 의견을 받아 다음 단계로 진행합니다.",
|
||||
"#EFF6FF",
|
||||
"#2563EB");
|
||||
|
||||
if (tool.Contains("file_edit") || tool.Contains("file_write") || tool.Contains("edit"))
|
||||
{
|
||||
return pending
|
||||
? new PermissionRequestPresentation("\uE70F", "파일 수정 권한 요청", "#FFF7ED", "#C2410C")
|
||||
: new PermissionRequestPresentation("\uE73E", "파일 수정 권한 승인", "#ECFDF5", "#059669");
|
||||
}
|
||||
return Build(
|
||||
"file_edit",
|
||||
pending,
|
||||
"\uE70F",
|
||||
"파일 수정 권한 요청",
|
||||
"파일 수정 권한 확인",
|
||||
"파일을 만들거나 수정하기 전에 확인이 필요합니다.",
|
||||
"파일 수정이 승인되어 계속 진행합니다.",
|
||||
"#FFF7ED",
|
||||
"#C2410C");
|
||||
|
||||
if (tool.Contains("file") || tool.Contains("glob") || tool.Contains("grep") || tool.Contains("folder"))
|
||||
{
|
||||
return pending
|
||||
? new PermissionRequestPresentation("\uE8A5", "파일 접근 권한 요청", "#FFF7ED", "#C2410C")
|
||||
: new PermissionRequestPresentation("\uE73E", "파일 접근 권한 승인", "#ECFDF5", "#059669");
|
||||
}
|
||||
return Build(
|
||||
"file_access",
|
||||
pending,
|
||||
"\uE8A5",
|
||||
"파일 접근 권한 요청",
|
||||
"파일 접근 권한 확인",
|
||||
"폴더와 파일 내용을 읽기 전에 확인이 필요합니다.",
|
||||
"파일 접근이 승인되어 계속 진행합니다.",
|
||||
"#FFF7ED",
|
||||
"#C2410C");
|
||||
|
||||
return pending
|
||||
? new PermissionRequestPresentation("\uE897", "권한 요청", "#FFF7ED", "#C2410C")
|
||||
: new PermissionRequestPresentation("\uE73E", "권한 승인", "#ECFDF5", "#059669");
|
||||
return Build(
|
||||
"generic",
|
||||
pending,
|
||||
"\uE897",
|
||||
"권한 요청",
|
||||
"권한 확인",
|
||||
"계속 진행하기 전에 사용자 확인이 필요합니다.",
|
||||
"요청이 승인되어 계속 진행합니다.",
|
||||
"#FFF7ED",
|
||||
"#C2410C");
|
||||
}
|
||||
|
||||
private static PermissionRequestPresentation Build(
|
||||
string kind,
|
||||
bool pending,
|
||||
string icon,
|
||||
string pendingLabel,
|
||||
string resolvedLabel,
|
||||
string pendingDescription,
|
||||
string resolvedDescription,
|
||||
string backgroundHex,
|
||||
string foregroundHex)
|
||||
{
|
||||
return new PermissionRequestPresentation(
|
||||
kind,
|
||||
pending ? icon : "\uE73E",
|
||||
pending ? pendingLabel : resolvedLabel,
|
||||
pending ? pendingDescription : resolvedDescription,
|
||||
pending ? backgroundHex : "#ECFDF5",
|
||||
pending ? foregroundHex : "#059669");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace AxCopilot.Services.Agent;
|
||||
|
||||
internal sealed record ToolResultPresentation(
|
||||
string Kind,
|
||||
string Icon,
|
||||
string Label,
|
||||
string Description,
|
||||
string BackgroundHex,
|
||||
string ForegroundHex,
|
||||
string StatusKind);
|
||||
@@ -16,76 +16,134 @@ internal static class ToolResultPresentationCatalog
|
||||
var summary = (evt.Summary ?? string.Empty).Trim();
|
||||
var tool = (evt.ToolName ?? string.Empty).Trim().ToLowerInvariant();
|
||||
var baseLabel = string.IsNullOrWhiteSpace(fallbackLabel) ? "도구 결과" : fallbackLabel;
|
||||
var kind = ResolveKind(tool);
|
||||
|
||||
if (summary.Contains("취소", StringComparison.OrdinalIgnoreCase) ||
|
||||
summary.Contains("중단", StringComparison.OrdinalIgnoreCase) ||
|
||||
evt.Type == AgentEventType.StopRequested)
|
||||
{
|
||||
return new ToolResultPresentation("\uE711", $"{baseLabel} 취소", "#F8FAFC", "#475569", "cancel");
|
||||
return new ToolResultPresentation(
|
||||
"cancel",
|
||||
"\uE711",
|
||||
$"{baseLabel} 취소",
|
||||
"요청이 중단되어 결과가 취소되었습니다.",
|
||||
"#F8FAFC",
|
||||
"#475569",
|
||||
"cancel");
|
||||
}
|
||||
|
||||
if (summary.Contains("거부", StringComparison.OrdinalIgnoreCase) ||
|
||||
summary.Contains("반려", StringComparison.OrdinalIgnoreCase) ||
|
||||
summary.Contains("권한 거부", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new ToolResultPresentation("\uE783", $"{baseLabel} 거부", "#FEF2F2", "#DC2626", "reject");
|
||||
return new ToolResultPresentation(
|
||||
"reject",
|
||||
"\uE783",
|
||||
$"{baseLabel} 거부",
|
||||
"권한이 거부되어 작업이 중단되었습니다.",
|
||||
"#FEF2F2",
|
||||
"#DC2626",
|
||||
"reject");
|
||||
}
|
||||
|
||||
if (!evt.Success || evt.Type == AgentEventType.Error)
|
||||
{
|
||||
return new ToolResultPresentation(
|
||||
kind,
|
||||
"\uE783",
|
||||
BuildFailureLabel(tool, baseLabel),
|
||||
BuildFailureLabel(kind, baseLabel),
|
||||
BuildFailureDescription(kind),
|
||||
"#FEF2F2",
|
||||
"#DC2626",
|
||||
"error");
|
||||
}
|
||||
|
||||
return new ToolResultPresentation(
|
||||
kind,
|
||||
"\uE73E",
|
||||
BuildSuccessLabel(tool, baseLabel),
|
||||
BuildSuccessLabel(kind, baseLabel),
|
||||
BuildSuccessDescription(kind),
|
||||
"#ECFDF5",
|
||||
"#16A34A",
|
||||
"success");
|
||||
}
|
||||
|
||||
private static string BuildSuccessLabel(string tool, string baseLabel)
|
||||
private static string ResolveKind(string tool)
|
||||
{
|
||||
if (tool.Contains("file"))
|
||||
return "파일 작업 완료";
|
||||
return "file";
|
||||
if (tool.Contains("build") || tool.Contains("test"))
|
||||
return "빌드/테스트 완료";
|
||||
return "build";
|
||||
if (tool.Contains("git") || tool.Contains("diff"))
|
||||
return "Git 작업 완료";
|
||||
return "git";
|
||||
if (tool.Contains("document") || tool.Contains("format") || tool.Contains("template"))
|
||||
return "문서 작업 완료";
|
||||
return "document";
|
||||
if (tool.Contains("skill"))
|
||||
return "스킬 실행 완료";
|
||||
return "skill";
|
||||
if (tool.Contains("web") || tool.Contains("fetch") || tool.Contains("http"))
|
||||
return "웹 요청 완료";
|
||||
return "web";
|
||||
if (tool.Contains("process") || tool.Contains("bash") || tool.Contains("powershell"))
|
||||
return "명령 실행 완료";
|
||||
|
||||
return baseLabel;
|
||||
return "command";
|
||||
return "generic";
|
||||
}
|
||||
|
||||
private static string BuildFailureLabel(string tool, string baseLabel)
|
||||
private static string BuildSuccessLabel(string kind, string baseLabel)
|
||||
{
|
||||
if (tool.Contains("file"))
|
||||
return "파일 작업 실패";
|
||||
if (tool.Contains("build") || tool.Contains("test"))
|
||||
return "빌드/테스트 실패";
|
||||
if (tool.Contains("git") || tool.Contains("diff"))
|
||||
return "Git 작업 실패";
|
||||
if (tool.Contains("document") || tool.Contains("format") || tool.Contains("template"))
|
||||
return "문서 작업 실패";
|
||||
if (tool.Contains("skill"))
|
||||
return "스킬 실행 실패";
|
||||
if (tool.Contains("web") || tool.Contains("fetch") || tool.Contains("http"))
|
||||
return "웹 요청 실패";
|
||||
if (tool.Contains("process") || tool.Contains("bash") || tool.Contains("powershell"))
|
||||
return "명령 실행 실패";
|
||||
return kind switch
|
||||
{
|
||||
"file" => "파일 작업 완료",
|
||||
"build" => "빌드/테스트 완료",
|
||||
"git" => "Git 작업 완료",
|
||||
"document" => "문서 작업 완료",
|
||||
"skill" => "스킬 실행 완료",
|
||||
"web" => "웹 요청 완료",
|
||||
"command" => "명령 실행 완료",
|
||||
_ => baseLabel,
|
||||
};
|
||||
}
|
||||
|
||||
return $"{baseLabel} 실패";
|
||||
private static string BuildFailureLabel(string kind, string baseLabel)
|
||||
{
|
||||
return kind switch
|
||||
{
|
||||
"file" => "파일 작업 실패",
|
||||
"build" => "빌드/테스트 실패",
|
||||
"git" => "Git 작업 실패",
|
||||
"document" => "문서 작업 실패",
|
||||
"skill" => "스킬 실행 실패",
|
||||
"web" => "웹 요청 실패",
|
||||
"command" => "명령 실행 실패",
|
||||
_ => $"{baseLabel} 실패",
|
||||
};
|
||||
}
|
||||
|
||||
private static string BuildSuccessDescription(string kind)
|
||||
{
|
||||
return kind switch
|
||||
{
|
||||
"file" => "파일 처리 결과가 정상적으로 반영되었습니다.",
|
||||
"build" => "빌드나 테스트 단계가 성공적으로 끝났습니다.",
|
||||
"git" => "Git 관련 작업이 정상적으로 완료되었습니다.",
|
||||
"document" => "문서 생성 또는 변환 작업이 완료되었습니다.",
|
||||
"skill" => "선택된 스킬이 정상적으로 실행되었습니다.",
|
||||
"web" => "웹 요청이 정상적으로 완료되었습니다.",
|
||||
"command" => "명령 실행이 정상적으로 끝났습니다.",
|
||||
_ => "요청한 작업이 정상적으로 완료되었습니다.",
|
||||
};
|
||||
}
|
||||
|
||||
private static string BuildFailureDescription(string kind)
|
||||
{
|
||||
return kind switch
|
||||
{
|
||||
"file" => "파일 처리 중 문제가 발생했습니다.",
|
||||
"build" => "빌드나 테스트 단계에서 실패가 발생했습니다.",
|
||||
"git" => "Git 관련 작업이 실패했습니다.",
|
||||
"document" => "문서 생성 또는 변환 작업이 실패했습니다.",
|
||||
"skill" => "스킬 실행 중 문제가 발생했습니다.",
|
||||
"web" => "웹 요청 처리에 실패했습니다.",
|
||||
"command" => "명령 실행 중 오류가 발생했습니다.",
|
||||
_ => "작업 처리 중 오류가 발생했습니다.",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,60 +654,14 @@ public sealed class AppStateService
|
||||
bool sortConversationsByRecent)
|
||||
{
|
||||
var status = GetOperationalStatus(tab);
|
||||
var showCompactStrip = !string.Equals(tab, "Chat", StringComparison.OrdinalIgnoreCase)
|
||||
&& (string.Equals(status.StripKind, "permission_waiting", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(status.StripKind, "failed_run", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(status.StripKind, "permission_denied", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var stripBackgroundHex = "";
|
||||
var stripBorderHex = "";
|
||||
var stripForegroundHex = "";
|
||||
if (showCompactStrip)
|
||||
{
|
||||
if (string.Equals(status.StripKind, "permission_waiting", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stripBackgroundHex = "#FFF7ED";
|
||||
stripBorderHex = "#FDBA74";
|
||||
stripForegroundHex = "#C2410C";
|
||||
}
|
||||
else if (string.Equals(status.StripKind, "failed_run", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(status.StripKind, "permission_denied", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stripBackgroundHex = "#FEF2F2";
|
||||
stripBorderHex = "#FECACA";
|
||||
stripForegroundHex = "#991B1B";
|
||||
}
|
||||
}
|
||||
|
||||
var allowQuickStrip = !string.Equals(tab, "Chat", StringComparison.OrdinalIgnoreCase);
|
||||
var quickRunningActive = runningOnlyFilter && runningConversationCount > 0;
|
||||
var quickHotActive = !sortConversationsByRecent && spotlightConversationCount > 0;
|
||||
var showQuickStrip = allowQuickStrip && (quickRunningActive || quickHotActive);
|
||||
|
||||
return new OperationalStatusPresentationState
|
||||
{
|
||||
ShowRuntimeBadge = status.ShowRuntimeBadge && hasLiveRuntimeActivity,
|
||||
RuntimeLabel = status.RuntimeLabel,
|
||||
ShowLastCompleted = status.ShowLastCompleted,
|
||||
LastCompletedText = status.LastCompletedText,
|
||||
ShowCompactStrip = showCompactStrip,
|
||||
StripKind = showCompactStrip ? status.StripKind : "none",
|
||||
StripText = showCompactStrip ? status.StripText : "",
|
||||
StripBackgroundHex = stripBackgroundHex,
|
||||
StripBorderHex = stripBorderHex,
|
||||
StripForegroundHex = stripForegroundHex,
|
||||
ShowQuickStrip = showQuickStrip,
|
||||
QuickRunningText = runningConversationCount > 0 ? $"진행 {runningConversationCount}" : "진행",
|
||||
QuickHotText = spotlightConversationCount > 0 ? $"활동 {spotlightConversationCount}" : "활동",
|
||||
QuickRunningActive = quickRunningActive,
|
||||
QuickHotActive = quickHotActive,
|
||||
QuickRunningBackgroundHex = quickRunningActive ? "#DBEAFE" : "#F8FAFC",
|
||||
QuickRunningBorderHex = quickRunningActive ? "#93C5FD" : "#E5E7EB",
|
||||
QuickRunningForegroundHex = quickRunningActive ? "#1D4ED8" : "#6B7280",
|
||||
QuickHotBackgroundHex = quickHotActive ? "#F5F3FF" : "#F8FAFC",
|
||||
QuickHotBorderHex = quickHotActive ? "#C4B5FD" : "#E5E7EB",
|
||||
QuickHotForegroundHex = quickHotActive ? "#6D28D9" : "#6B7280",
|
||||
};
|
||||
return OperationalStatusPresentationCatalog.Resolve(
|
||||
status,
|
||||
tab,
|
||||
hasLiveRuntimeActivity,
|
||||
runningConversationCount,
|
||||
spotlightConversationCount,
|
||||
runningOnlyFilter,
|
||||
sortConversationsByRecent);
|
||||
}
|
||||
|
||||
public IReadOnlyList<DraftQueueItem> GetDraftQueueItems(string tab)
|
||||
|
||||
@@ -134,6 +134,15 @@ public partial class ChatWindow
|
||||
? GetAgentItemDisplayName(evt.ToolName, slashPrefix: true)
|
||||
: GetAgentItemDisplayName(evt.ToolName);
|
||||
var eventSummaryText = BuildAgentEventSummaryText(evt, itemDisplayName);
|
||||
if (string.IsNullOrWhiteSpace(eventSummaryText))
|
||||
{
|
||||
eventSummaryText = evt.Type switch
|
||||
{
|
||||
AgentEventType.PermissionRequest or AgentEventType.PermissionGranted => permissionPresentation?.Description ?? "",
|
||||
AgentEventType.ToolResult => toolResultPresentation?.Description ?? "",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.Black;
|
||||
var secondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.DimGray;
|
||||
|
||||
@@ -21,9 +21,7 @@ public partial class ChatWindow
|
||||
|
||||
ChatConversation? currentConversation;
|
||||
lock (_convLock) currentConversation = _currentConversation;
|
||||
var coreLevels = PermissionModePresentationCatalog.Ordered
|
||||
.Where(item => !string.Equals(item.Mode, PermissionModeCatalog.Plan, StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
var coreLevels = PermissionModePresentationCatalog.Ordered.ToList();
|
||||
var current = PermissionModeCatalog.NormalizeGlobalMode(_settings.Settings.Llm.FilePermission);
|
||||
|
||||
void AddPermissionRows(Panel container, IEnumerable<PermissionModePresentation> levels)
|
||||
@@ -210,7 +208,6 @@ public partial class ChatWindow
|
||||
PermissionIcon.Text = perm switch
|
||||
{
|
||||
"AcceptEdits" => "\uE73E",
|
||||
"Plan" => "\uE7C3",
|
||||
"BypassPermissions" => "\uE7BA",
|
||||
"Deny" => "\uE711",
|
||||
_ => "\uE8D7",
|
||||
@@ -218,7 +215,7 @@ public partial class ChatWindow
|
||||
if (BtnPermission != null)
|
||||
{
|
||||
var operationMode = OperationModePolicy.Normalize(_settings.Settings.OperationMode);
|
||||
BtnPermission.ToolTip = $"{summary.Description}\n운영 모드: {operationMode}\n기본값 {PermissionModeCatalog.ToDisplayLabel(summary.DefaultMode)} · 예외 {summary.OverrideCount}개";
|
||||
BtnPermission.ToolTip = $"{summary.Description}\n운영 모드: {operationMode}\n기본값: {PermissionModeCatalog.ToDisplayLabel(summary.DefaultMode)} · 예외 {summary.OverrideCount}개";
|
||||
BtnPermission.Background = Brushes.Transparent;
|
||||
BtnPermission.BorderThickness = new Thickness(1);
|
||||
}
|
||||
@@ -240,7 +237,7 @@ public partial class ChatWindow
|
||||
PermissionTopBannerIcon.Foreground = activeColor;
|
||||
PermissionTopBannerTitle.Text = "현재 권한 모드 · 편집 자동 승인";
|
||||
PermissionTopBannerTitle.Foreground = BrushFromHex("#166534");
|
||||
PermissionTopBannerText.Text = "모든 파일 편집을 자동 승인합니다. 명령 실행은 계속 확인합니다.";
|
||||
PermissionTopBannerText.Text = "모든 파일 편집은 자동 승인하고, 명령 실행만 계속 확인합니다.";
|
||||
PermissionTopBanner.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
@@ -258,7 +255,7 @@ public partial class ChatWindow
|
||||
PermissionTopBannerIcon.Foreground = denyColor;
|
||||
PermissionTopBannerTitle.Text = "현재 권한 모드 · 읽기 전용";
|
||||
PermissionTopBannerTitle.Foreground = denyColor;
|
||||
PermissionTopBannerText.Text = "파일 읽기만 허용하고 생성/수정/삭제는 차단합니다.";
|
||||
PermissionTopBannerText.Text = "파일 읽기만 허용하고 생성, 수정, 삭제는 차단합니다.";
|
||||
PermissionTopBanner.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
@@ -283,30 +280,14 @@ public partial class ChatWindow
|
||||
else
|
||||
{
|
||||
var defaultFg = BrushFromHex("#2563EB");
|
||||
var iconFg = perm switch
|
||||
{
|
||||
"Plan" => new SolidColorBrush(Color.FromRgb(0x43, 0x38, 0xCA)),
|
||||
_ => new SolidColorBrush(Color.FromRgb(0x25, 0x63, 0xEB)),
|
||||
};
|
||||
var iconFg = new SolidColorBrush(Color.FromRgb(0x25, 0x63, 0xEB));
|
||||
PermissionLabel.Foreground = defaultFg;
|
||||
PermissionIcon.Foreground = iconFg;
|
||||
if (BtnPermission != null)
|
||||
BtnPermission.BorderBrush = perm == PermissionModeCatalog.Plan
|
||||
? BrushFromHex("#C7D2FE")
|
||||
: BrushFromHex("#BFDBFE");
|
||||
BtnPermission.BorderBrush = BrushFromHex("#BFDBFE");
|
||||
if (PermissionTopBanner != null)
|
||||
{
|
||||
if (perm == PermissionModeCatalog.Plan)
|
||||
{
|
||||
PermissionTopBanner.BorderBrush = BrushFromHex("#C7D2FE");
|
||||
PermissionTopBannerIcon.Text = "\uE7C3";
|
||||
PermissionTopBannerIcon.Foreground = BrushFromHex("#4338CA");
|
||||
PermissionTopBannerTitle.Text = "현재 권한 모드 · 계획 모드";
|
||||
PermissionTopBannerTitle.Foreground = BrushFromHex("#4338CA");
|
||||
PermissionTopBannerText.Text = "변경 전에 계획을 먼저 만들고 승인 흐름을 우선합니다.";
|
||||
PermissionTopBanner.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
else if (perm == PermissionModeCatalog.Default)
|
||||
if (perm == PermissionModeCatalog.Default)
|
||||
{
|
||||
PermissionTopBanner.BorderBrush = BrushFromHex("#BFDBFE");
|
||||
PermissionTopBannerIcon.Text = "\uE8D7";
|
||||
|
||||
Reference in New Issue
Block a user