AX Commander 비교본 런처 기능 대량 이식

변경 목적: Agent Compare 아래 비교본의 개발 문서와 런처 소스를 기준으로 현재 AX Commander에 빠져 있던 신규 런처 기능을 동일한 흐름으로 옮겨, 비교본 수준의 기능 폭을 현재 제품에 반영했습니다.

핵심 수정사항: 비교본의 신규 런처 핸들러 다수를 src/AxCopilot/Handlers로 이식하고 App.xaml.cs 등록 흐름에 연결했습니다. 빠른 링크, 파일 태그, 알림 센터, 포모도로, 파일 브라우저, 핫키 관리, OCR, 세션/스케줄/매크로, Git/정규식/네트워크/압축/해시/UUID/JWT/QR 등 AX Commander 기능을 추가했습니다.

핵심 수정사항: 신규 기능이 실제 동작하도록 AppSettings 확장, SchedulerService/FileTagService/NotificationCenterService/IconCacheService/UrlTemplateEngine/PomodoroService 추가, 배치 이름변경/세션/스케줄/매크로 편집 창 추가, NotificationService와 Symbols 보강, QR/OCR용 csproj 의존성과 Windows 타겟 프레임워크를 반영했습니다.

문서 반영: README.md와 docs/DEVELOPMENT.md에 비교본 기반 런처 기능 이식 이력과 검증 결과를 업데이트했습니다.

검증 결과: 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:
2026-04-05 00:59:45 +09:00
parent 0929778ca7
commit 0336904258
115 changed files with 30749 additions and 1 deletions

View File

@@ -0,0 +1,251 @@
<Window x:Class="AxCopilot.Views.SessionEditorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="AX Commander — 세션 편집"
Width="640" Height="540"
MinWidth="500" MinHeight="400"
WindowStyle="None" AllowsTransparency="True"
Background="Transparent"
WindowStartupLocation="CenterScreen"
ResizeMode="CanResizeWithGrip"
ShowInTaskbar="False">
<Border Background="{DynamicResource LauncherBackground}" CornerRadius="12"
BorderBrush="{DynamicResource BorderColor}" BorderThickness="1"
Margin="6">
<Border.Effect>
<DropShadowEffect BlurRadius="22" ShadowDepth="4" Opacity="0.32" Color="Black" Direction="270"/>
</Border.Effect>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="44"/> <!-- 타이틀바 -->
<RowDefinition Height="Auto"/> <!-- 세션 정보 -->
<RowDefinition Height="*"/> <!-- 앱 목록 -->
<RowDefinition Height="Auto"/> <!-- 하단 버튼 -->
</Grid.RowDefinitions>
<!-- ─── 타이틀바 ─────────────────────────────────────────────── -->
<Border Grid.Row="0" CornerRadius="12,12,0,0"
Background="{DynamicResource ItemBackground}"
MouseLeftButtonDown="TitleBar_MouseDown">
<Grid Margin="14,0,8,0">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="&#xE8A1;"
FontFamily="Segoe MDL2 Assets" FontSize="15"
Foreground="{DynamicResource AccentColor}"
VerticalAlignment="Center" Margin="0,1,10,0"/>
<TextBlock Text="세션 편집"
FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryText}"
VerticalAlignment="Center"/>
</StackPanel>
<Border HorizontalAlignment="Right" VerticalAlignment="Center"
CornerRadius="4" Padding="8,4" Cursor="Hand"
MouseLeftButtonUp="BtnClose_Click">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#40C05050"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="&#xE711;" FontFamily="Segoe MDL2 Assets" FontSize="13"
Foreground="{DynamicResource SecondaryText}"/>
</Border>
</Grid>
</Border>
<!-- ─── 세션 이름·설명 ───────────────────────────────────────── -->
<Border Grid.Row="1"
Background="{DynamicResource ItemBackground}"
BorderBrush="{DynamicResource BorderColor}" BorderThickness="0,1,0,1"
Padding="14,10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="12"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="4"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
Text="세션 이름" FontSize="10" FontWeight="Medium"
Foreground="{DynamicResource SecondaryText}" Margin="0,0,0,3"/>
<TextBlock Grid.Row="0" Grid.Column="2"
Text="설명 (선택)" FontSize="10" FontWeight="Medium"
Foreground="{DynamicResource SecondaryText}" Margin="0,0,0,3"/>
<TextBox Grid.Row="2" Grid.Column="0"
x:Name="NameBox"
FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryText}"
Background="{DynamicResource LauncherBackground}"
BorderBrush="{DynamicResource BorderColor}"
BorderThickness="1"
Padding="8,5"
VerticalContentAlignment="Center"/>
<TextBox Grid.Row="2" Grid.Column="2"
x:Name="DescBox"
FontSize="12"
Foreground="{DynamicResource PrimaryText}"
Background="{DynamicResource LauncherBackground}"
BorderBrush="{DynamicResource BorderColor}"
BorderThickness="1"
Padding="8,5"
VerticalContentAlignment="Center"/>
</Grid>
</Border>
<!-- ─── 앱 목록 ──────────────────────────────────────────────── -->
<Grid Grid.Row="2">
<!-- 컬럼 헤더 -->
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0"
Background="{DynamicResource ItemBackground}"
BorderBrush="{DynamicResource BorderColor}" BorderThickness="0,0,0,1"
Padding="14,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <!-- 경로 -->
<ColumnDefinition Width="100"/> <!-- 라벨 -->
<ColumnDefinition Width="108"/> <!-- 스냅 -->
<ColumnDefinition Width="30"/> <!-- 삭제 -->
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="앱 경로" FontSize="10" FontWeight="Medium"
Foreground="{DynamicResource SecondaryText}" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="라벨" FontSize="10" FontWeight="Medium"
Foreground="{DynamicResource SecondaryText}" VerticalAlignment="Center" Margin="8,0,0,0"/>
<TextBlock Grid.Column="2" Text="스냅 위치" FontSize="10" FontWeight="Medium"
Foreground="{DynamicResource SecondaryText}" VerticalAlignment="Center" Margin="8,0,0,0"/>
</Grid>
</Border>
<!-- 앱 행 목록 -->
<ScrollViewer Grid.Row="1"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled">
<StackPanel x:Name="AppListPanel" Margin="0,0,0,4">
<!-- 행은 코드에서 동적으로 생성 -->
</StackPanel>
</ScrollViewer>
<!-- 빈 상태 -->
<StackPanel x:Name="EmptyState"
Grid.Row="1"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Visibility="Visible">
<TextBlock Text="&#xE8A1;"
FontFamily="Segoe MDL2 Assets" FontSize="40"
Foreground="{DynamicResource SecondaryText}"
HorizontalAlignment="Center" Opacity="0.3"/>
<TextBlock Text="앱을 추가하세요"
FontSize="13"
Foreground="{DynamicResource SecondaryText}"
HorizontalAlignment="Center"
Margin="0,10,0,0" Opacity="0.5"/>
</StackPanel>
</Grid>
<!-- ─── 스냅 선택 팝업 (공유, 코드에서 위치 지정) ──────────────
PlacementTarget은 코드에서 동적으로 설정합니다. -->
<Popup x:Name="SnapPickerPopup"
Placement="Bottom"
AllowsTransparency="True"
StaysOpen="False">
<Border Background="{DynamicResource ItemBackground}"
BorderBrush="{DynamicResource BorderColor}" BorderThickness="1"
CornerRadius="8" Padding="8,6"
MinWidth="160">
<Border.Effect>
<DropShadowEffect BlurRadius="12" ShadowDepth="2" Opacity="0.3" Color="Black" Direction="270"/>
</Border.Effect>
<ContentControl x:Name="SnapOptionsList"/>
</Border>
</Popup>
<!-- ─── 하단 버튼 바 ─────────────────────────────────────────── -->
<Border Grid.Row="3" CornerRadius="0,0,12,12"
Background="{DynamicResource ItemBackground}"
BorderBrush="{DynamicResource BorderColor}" BorderThickness="0,1,0,0"
Padding="12,8">
<Grid>
<!-- 좌측: 앱 추가 버튼 -->
<Border HorizontalAlignment="Left" VerticalAlignment="Center"
CornerRadius="4" Padding="12,5" Cursor="Hand"
MouseLeftButtonUp="BtnAddApp_Click">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#18FFFFFF"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#28FFFFFF"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE710;" FontFamily="Segoe MDL2 Assets" FontSize="12"
Foreground="#5CB85C" VerticalAlignment="Center" Margin="0,0,6,0"/>
<TextBlock Text="앱 추가" FontSize="12"
Foreground="{DynamicResource PrimaryText}"/>
</StackPanel>
</Border>
<!-- 우측: 취소 + 저장 -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
<Border CornerRadius="4" Padding="14,5" Cursor="Hand" Margin="0,0,8,0"
MouseLeftButtonUp="BtnCancel_Click">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#18FFFFFF"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#28FFFFFF"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="취소" FontSize="12"
Foreground="{DynamicResource SecondaryText}"/>
</Border>
<Border x:Name="BtnSave"
CornerRadius="4" Padding="16,5" Cursor="Hand"
Background="{DynamicResource AccentColor}"
MouseLeftButtonUp="BtnSave_Click">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="{DynamicResource AccentColor}"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.85"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE74E;" FontFamily="Segoe MDL2 Assets" FontSize="12"
Foreground="White" VerticalAlignment="Center" Margin="0,0,6,0"/>
<TextBlock Text="저장" FontSize="12" FontWeight="SemiBold"
Foreground="White"/>
</StackPanel>
</Border>
</StackPanel>
</Grid>
</Border>
</Grid>
</Border>
</Window>