Files
AX-Copilot-Codex/.decompiledproj/AxCopilot/Views/SkillGalleryWindow.cs

737 lines
22 KiB
C#

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Effects;
using AxCopilot.Services.Agent;
using Microsoft.Win32;
namespace AxCopilot.Views;
public class SkillGalleryWindow : Window, IComponentConnector
{
private string _selectedCategory = "전체";
internal Border BtnCloseGallery;
internal StackPanel CategoryFilterBar;
internal StackPanel SkillListPanel;
internal TextBlock GalleryStatus;
private bool _contentLoaded;
public SkillGalleryWindow()
{
InitializeComponent();
base.Loaded += delegate
{
BuildCategoryFilter();
RenderSkills();
};
}
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
Point position = e.GetPosition(this);
if (!(((Point)(ref position)).X > base.ActualWidth - 160.0))
{
if (e.ClickCount == 2)
{
base.WindowState = ((base.WindowState != WindowState.Maximized) ? WindowState.Maximized : WindowState.Normal);
}
else
{
DragMove();
}
}
}
private void BtnClose_Click(object sender, MouseButtonEventArgs e)
{
Close();
}
private void BtnAddSkill_Click(object sender, MouseButtonEventArgs e)
{
SkillEditorWindow skillEditorWindow = new SkillEditorWindow
{
Owner = this
};
if (skillEditorWindow.ShowDialog() == true)
{
BuildCategoryFilter();
RenderSkills();
}
}
private void BtnImport_Click(object sender, MouseButtonEventArgs e)
{
Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog
{
Filter = "스킬 패키지 (*.zip)|*.zip",
Title = "가져올 스킬 zip 파일을 선택하세요"
};
if (openFileDialog.ShowDialog() == true)
{
int num = SkillService.ImportSkills(openFileDialog.FileName);
if (num > 0)
{
CustomMessageBox.Show($"스킬 {num}개를 성공적으로 가져왔습니다.", "스킬 가져오기");
BuildCategoryFilter();
RenderSkills();
}
else
{
CustomMessageBox.Show("스킬 가져오기에 실패했습니다.", "스킬 가져오기");
}
}
}
private void BuildCategoryFilter()
{
CategoryFilterBar.Children.Clear();
IReadOnlyList<SkillDefinition> skills = SkillService.Skills;
List<string> list = new string[1] { "전체" }.Concat(skills.Select((SkillDefinition s) => string.IsNullOrEmpty(s.Requires) ? "내장" : "고급 (런타임)").Distinct()).ToList();
string userFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "skills");
if (skills.Any((SkillDefinition s) => s.FilePath.StartsWith(userFolder, StringComparison.OrdinalIgnoreCase)) && !list.Contains("사용자"))
{
list.Add("사용자");
}
foreach (string item in list)
{
Border border = new Border();
border.Tag = item;
border.CornerRadius = new CornerRadius(8.0);
border.Padding = new Thickness(14.0, 5.0, 14.0, 5.0);
border.Margin = new Thickness(0.0, 0.0, 6.0, 0.0);
border.Background = ((item == _selectedCategory) ? new SolidColorBrush(Color.FromRgb(75, 94, 252)) : ((TryFindResource("ItemBackground") as Brush) ?? Brushes.Transparent));
border.Cursor = System.Windows.Input.Cursors.Hand;
Border border2 = border;
border2.Child = new TextBlock
{
Text = item,
FontSize = 12.0,
FontWeight = FontWeights.SemiBold,
Foreground = ((item == _selectedCategory) ? Brushes.White : ((TryFindResource("SecondaryText") as Brush) ?? Brushes.Gray))
};
border2.MouseLeftButtonUp += delegate(object s, MouseButtonEventArgs _)
{
if (s is Border { Tag: string tag })
{
_selectedCategory = tag;
BuildCategoryFilter();
RenderSkills();
}
};
CategoryFilterBar.Children.Add(border2);
}
}
private void RenderSkills()
{
SkillListPanel.Children.Clear();
List<SkillDefinition> list = FilterSkills(SkillService.Skills);
string userFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "skills");
foreach (SkillDefinition item in list)
{
SkillListPanel.Children.Add(BuildSkillCard(item, userFolder));
}
if (list.Count == 0)
{
SkillListPanel.Children.Add(new TextBlock
{
Text = "표시할 스킬이 없습니다.",
FontSize = 13.0,
Foreground = ((TryFindResource("SecondaryText") as Brush) ?? Brushes.Gray),
Margin = new Thickness(0.0, 20.0, 0.0, 0.0),
HorizontalAlignment = System.Windows.HorizontalAlignment.Center
});
}
int count = SkillService.Skills.Count;
int num = SkillService.Skills.Count((SkillDefinition s) => s.IsAvailable);
GalleryStatus.Text = $"총 {count}개 스킬 | 사용 가능 {num}개 | 런타임 필요 {count - num}개";
}
private List<SkillDefinition> FilterSkills(IReadOnlyList<SkillDefinition> skills)
{
string userFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "skills");
string selectedCategory = _selectedCategory;
if (1 == 0)
{
}
List<SkillDefinition> result = selectedCategory switch
{
"내장" => skills.Where((SkillDefinition s) => string.IsNullOrEmpty(s.Requires) && !s.FilePath.StartsWith(userFolder, StringComparison.OrdinalIgnoreCase)).ToList(),
"고급 (런타임)" => skills.Where((SkillDefinition s) => !string.IsNullOrEmpty(s.Requires)).ToList(),
"사용자" => skills.Where((SkillDefinition s) => s.FilePath.StartsWith(userFolder, StringComparison.OrdinalIgnoreCase)).ToList(),
_ => skills.ToList(),
};
if (1 == 0)
{
}
return result;
}
private Border BuildSkillCard(SkillDefinition skill, string userFolder)
{
Brush bgBrush = (TryFindResource("ItemBackground") as Brush) ?? Brushes.Transparent;
Brush foreground = (TryFindResource("PrimaryText") as Brush) ?? Brushes.White;
Brush brush = (TryFindResource("SecondaryText") as Brush) ?? Brushes.Gray;
bool isUser = skill.FilePath.StartsWith(userFolder, StringComparison.OrdinalIgnoreCase);
bool flag = !string.IsNullOrEmpty(skill.Requires);
Border card = new Border
{
Background = bgBrush,
CornerRadius = new CornerRadius(10.0),
Padding = new Thickness(14.0, 10.0, 14.0, 10.0),
Margin = new Thickness(0.0, 0.0, 0.0, 6.0)
};
Grid grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1.0, GridUnitType.Auto)
});
grid.ColumnDefinitions.Add(new ColumnDefinition());
grid.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1.0, GridUnitType.Auto)
});
Border border = new Border
{
Width = 38.0,
Height = 38.0,
CornerRadius = new CornerRadius(10.0),
Background = new SolidColorBrush(Color.FromArgb(48, 75, 94, 252)),
Margin = new Thickness(0.0, 0.0, 12.0, 0.0),
VerticalAlignment = VerticalAlignment.Center
};
border.Child = new TextBlock
{
Text = skill.Icon,
FontFamily = new FontFamily("Segoe MDL2 Assets"),
FontSize = 16.0,
Foreground = (skill.IsAvailable ? new SolidColorBrush(Color.FromRgb(75, 94, 252)) : brush),
HorizontalAlignment = System.Windows.HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
};
Grid.SetColumn(border, 0);
StackPanel stackPanel = new StackPanel
{
VerticalAlignment = VerticalAlignment.Center
};
StackPanel stackPanel2 = new StackPanel
{
Orientation = System.Windows.Controls.Orientation.Horizontal,
Margin = new Thickness(0.0, 0.0, 0.0, 3.0)
};
stackPanel2.Children.Add(new TextBlock
{
Text = "/" + skill.Name,
FontSize = 13.0,
FontWeight = FontWeights.SemiBold,
FontFamily = new FontFamily("Consolas"),
Foreground = (skill.IsAvailable ? new SolidColorBrush(Color.FromRgb(75, 94, 252)) : brush),
Opacity = (skill.IsAvailable ? 1.0 : 0.6),
VerticalAlignment = VerticalAlignment.Center
});
stackPanel2.Children.Add(new TextBlock
{
Text = " " + skill.Label,
FontSize = 12.5,
Foreground = foreground,
VerticalAlignment = VerticalAlignment.Center
});
if (isUser)
{
stackPanel2.Children.Add(MakeBadge("사용자", "#34D399"));
}
else if (flag)
{
stackPanel2.Children.Add(MakeBadge("고급", "#A78BFA"));
}
else
{
stackPanel2.Children.Add(MakeBadge("내장", "#9CA3AF"));
}
if (!skill.IsAvailable)
{
stackPanel2.Children.Add(MakeBadge(skill.UnavailableHint, "#F87171"));
}
stackPanel.Children.Add(stackPanel2);
stackPanel.Children.Add(new TextBlock
{
Text = skill.Description,
FontSize = 11.5,
Foreground = brush,
TextWrapping = TextWrapping.Wrap,
Opacity = (skill.IsAvailable ? 1.0 : 0.6)
});
Grid.SetColumn(stackPanel, 1);
StackPanel actions = new StackPanel
{
Orientation = System.Windows.Controls.Orientation.Horizontal,
VerticalAlignment = VerticalAlignment.Center,
Margin = new Thickness(8.0, 0.0, 0.0, 0.0)
};
actions.Children.Add(MakeActionBtn("\ue70f", "#3B82F6", isUser ? "편집 (시각적 편집기)" : "편집 (파일 열기)", delegate
{
if (isUser)
{
SkillEditorWindow skillEditorWindow = new SkillEditorWindow(skill)
{
Owner = this
};
if (skillEditorWindow.ShowDialog() == true)
{
SkillService.LoadSkills();
BuildCategoryFilter();
RenderSkills();
}
return;
}
try
{
Process.Start(new ProcessStartInfo(skill.FilePath)
{
UseShellExecute = true
});
}
catch (Exception ex)
{
CustomMessageBox.Show("파일을 열 수 없습니다: " + ex.Message, "편집");
}
}));
actions.Children.Add(MakeActionBtn("\ue8c8", "#10B981", "복제", delegate
{
try
{
string text = Path.Combine(userFolder);
if (!Directory.Exists(text))
{
Directory.CreateDirectory(text);
}
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(skill.FilePath);
string text2 = Path.Combine(text, fileNameWithoutExtension + "_copy.skill.md");
int num = 2;
while (File.Exists(text2))
{
text2 = Path.Combine(text, $"{fileNameWithoutExtension}_copy{num++}.skill.md");
}
File.Copy(skill.FilePath, text2);
SkillService.LoadSkills();
BuildCategoryFilter();
RenderSkills();
}
catch (Exception ex)
{
CustomMessageBox.Show("복제 실패: " + ex.Message, "복제");
}
}));
actions.Children.Add(MakeActionBtn("\uede1", "#F59E0B", "내보내기 (.zip)", delegate
{
FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog
{
Description = "내보낼 폴더를 선택하세요"
};
if (folderBrowserDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string text = SkillService.ExportSkill(skill, folderBrowserDialog.SelectedPath);
if (text != null)
{
CustomMessageBox.Show("내보내기 완료:\n" + text, "내보내기");
}
else
{
CustomMessageBox.Show("내보내기에 실패했습니다.", "내보내기");
}
}
}));
if (isUser)
{
actions.Children.Add(MakeActionBtn("\ue74d", "#F87171", "삭제", delegate
{
MessageBoxResult messageBoxResult = CustomMessageBox.Show("스킬 '/" + skill.Name + "'을 삭제하시겠습니까?", "스킬 삭제", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (messageBoxResult != MessageBoxResult.Yes)
{
return;
}
try
{
File.Delete(skill.FilePath);
SkillService.LoadSkills();
BuildCategoryFilter();
RenderSkills();
}
catch (Exception ex)
{
CustomMessageBox.Show("삭제 실패: " + ex.Message, "삭제");
}
}));
}
Grid.SetColumn(actions, 2);
grid.Children.Add(border);
grid.Children.Add(stackPanel);
grid.Children.Add(actions);
card.Child = grid;
card.Cursor = System.Windows.Input.Cursors.Hand;
card.MouseEnter += delegate
{
card.Background = new SolidColorBrush(Color.FromArgb(24, byte.MaxValue, byte.MaxValue, byte.MaxValue));
};
card.MouseLeave += delegate
{
card.Background = bgBrush;
};
card.MouseLeftButtonUp += delegate(object _, MouseButtonEventArgs e)
{
if (e.OriginalSource is FrameworkElement frameworkElement)
{
for (FrameworkElement frameworkElement2 = frameworkElement; frameworkElement2 != null; frameworkElement2 = VisualTreeHelper.GetParent((DependencyObject)(object)frameworkElement2) as FrameworkElement)
{
if (frameworkElement2 == actions)
{
return;
}
}
}
ShowSkillDetail(skill);
};
return card;
}
private Border MakeBadge(string text, string colorHex)
{
Color color = (Color)ColorConverter.ConvertFromString(colorHex);
return new Border
{
Background = new SolidColorBrush(Color.FromArgb(37, color.R, color.G, color.B)),
CornerRadius = new CornerRadius(4.0),
Padding = new Thickness(5.0, 1.0, 5.0, 1.0),
Margin = new Thickness(6.0, 0.0, 0.0, 0.0),
VerticalAlignment = VerticalAlignment.Center,
Child = new TextBlock
{
Text = text,
FontSize = 9.5,
FontWeight = FontWeights.SemiBold,
Foreground = new SolidColorBrush(color)
}
};
}
private Border MakeActionBtn(string icon, string colorHex, string tooltip, Action action)
{
Color col = (Color)ColorConverter.ConvertFromString(colorHex);
Border btn = new Border
{
Width = 28.0,
Height = 28.0,
CornerRadius = new CornerRadius(6.0),
Background = Brushes.Transparent,
Cursor = System.Windows.Input.Cursors.Hand,
Margin = new Thickness(2.0, 0.0, 0.0, 0.0),
ToolTip = tooltip,
Child = new TextBlock
{
Text = icon,
FontFamily = new FontFamily("Segoe MDL2 Assets"),
FontSize = 12.0,
Foreground = new SolidColorBrush(col),
HorizontalAlignment = System.Windows.HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
}
};
btn.MouseEnter += delegate
{
btn.Background = new SolidColorBrush(Color.FromArgb(32, col.R, col.G, col.B));
};
btn.MouseLeave += delegate
{
btn.Background = Brushes.Transparent;
};
btn.MouseLeftButtonUp += delegate
{
action();
};
return btn;
}
private void ShowSkillDetail(SkillDefinition skill)
{
Brush background = (TryFindResource("LauncherBackground") as Brush) ?? Brushes.Black;
Brush fgBrush = (TryFindResource("PrimaryText") as Brush) ?? Brushes.White;
Brush subBrush = (TryFindResource("SecondaryText") as Brush) ?? Brushes.Gray;
Brush background2 = (TryFindResource("ItemBackground") as Brush) ?? Brushes.Transparent;
Brush brush = (TryFindResource("BorderColor") as Brush) ?? Brushes.Gray;
Window popup = new Window
{
Title = "/" + skill.Name,
Width = 580.0,
Height = 480.0,
WindowStyle = WindowStyle.None,
AllowsTransparency = true,
Background = Brushes.Transparent,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Owner = this
};
Border border = new Border
{
Background = background,
CornerRadius = new CornerRadius(12.0),
BorderBrush = brush,
BorderThickness = new Thickness(1.0, 1.0, 1.0, 1.0),
Effect = new DropShadowEffect
{
BlurRadius = 20.0,
ShadowDepth = 4.0,
Opacity = 0.3,
Color = Colors.Black
}
};
Grid grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(44.0)
});
grid.RowDefinitions.Add(new RowDefinition());
Border border2 = new Border
{
CornerRadius = new CornerRadius(12.0, 12.0, 0.0, 0.0),
Background = background2
};
border2.MouseLeftButtonDown += delegate(object _, MouseButtonEventArgs e)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
Point position = e.GetPosition(popup);
if (!(((Point)(ref position)).X > popup.ActualWidth - 50.0))
{
popup.DragMove();
}
};
Grid grid2 = new Grid
{
Margin = new Thickness(16.0, 0.0, 12.0, 0.0)
};
StackPanel stackPanel = new StackPanel
{
Orientation = System.Windows.Controls.Orientation.Horizontal,
VerticalAlignment = VerticalAlignment.Center
};
stackPanel.Children.Add(new TextBlock
{
Text = skill.Icon,
FontFamily = new FontFamily("Segoe MDL2 Assets"),
FontSize = 14.0,
Foreground = new SolidColorBrush(Color.FromRgb(75, 94, 252)),
VerticalAlignment = VerticalAlignment.Center,
Margin = new Thickness(0.0, 1.0, 8.0, 0.0)
});
stackPanel.Children.Add(new TextBlock
{
Text = "/" + skill.Name + " " + skill.Label,
FontSize = 14.0,
FontWeight = FontWeights.SemiBold,
Foreground = fgBrush,
VerticalAlignment = VerticalAlignment.Center
});
grid2.Children.Add(stackPanel);
Border border3 = new Border
{
Width = 28.0,
Height = 28.0,
CornerRadius = new CornerRadius(6.0),
Cursor = System.Windows.Input.Cursors.Hand,
HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Center
};
border3.Child = new TextBlock
{
Text = "\ue8bb",
FontFamily = new FontFamily("Segoe MDL2 Assets"),
FontSize = 10.0,
Foreground = subBrush,
HorizontalAlignment = System.Windows.HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
};
border3.MouseEnter += delegate(object s, System.Windows.Input.MouseEventArgs _)
{
((Border)s).Background = new SolidColorBrush(Color.FromArgb(51, byte.MaxValue, 68, 68));
};
border3.MouseLeave += delegate(object s, System.Windows.Input.MouseEventArgs _)
{
((Border)s).Background = Brushes.Transparent;
};
border3.MouseLeftButtonUp += delegate
{
popup.Close();
};
grid2.Children.Add(border3);
border2.Child = grid2;
Grid.SetRow(border2, 0);
ScrollViewer scrollViewer = new ScrollViewer
{
VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
Padding = new Thickness(20.0, 16.0, 20.0, 16.0)
};
StackPanel stackPanel2 = new StackPanel();
Grid metaGrid = new Grid
{
Margin = new Thickness(0.0, 0.0, 0.0, 14.0)
};
metaGrid.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(80.0)
});
metaGrid.ColumnDefinitions.Add(new ColumnDefinition());
int num = 0;
AddMetaRow("명령어", "/" + skill.Name, num++);
AddMetaRow("라벨", skill.Label, num++);
AddMetaRow("설명", skill.Description, num++);
if (!string.IsNullOrEmpty(skill.Requires))
{
AddMetaRow("런타임", skill.Requires, num++);
}
if (!string.IsNullOrEmpty(skill.AllowedTools))
{
AddMetaRow("허용 도구", skill.AllowedTools, num++);
}
AddMetaRow("상태", skill.IsAvailable ? "✓ 사용 가능" : ("✗ " + skill.UnavailableHint), num++);
AddMetaRow("경로", skill.FilePath, num++);
stackPanel2.Children.Add(metaGrid);
stackPanel2.Children.Add(new Border
{
Height = 1.0,
Background = brush,
Margin = new Thickness(0.0, 4.0, 0.0, 12.0)
});
stackPanel2.Children.Add(new TextBlock
{
Text = "시스템 프롬프트 (미리보기)",
FontSize = 11.0,
FontWeight = FontWeights.SemiBold,
Foreground = subBrush,
Margin = new Thickness(0.0, 0.0, 0.0, 6.0)
});
Border border4 = new Border
{
Background = background2,
CornerRadius = new CornerRadius(8.0),
Padding = new Thickness(12.0, 10.0, 12.0, 10.0)
};
string text = skill.SystemPrompt;
if (text.Length > 2000)
{
text = text.Substring(0, 2000) + "\n\n... (이하 생략)";
}
border4.Child = new TextBlock
{
Text = text,
FontSize = 11.5,
FontFamily = new FontFamily("Consolas, Cascadia Code, Segoe UI"),
Foreground = fgBrush,
TextWrapping = TextWrapping.Wrap,
Opacity = 0.85
};
stackPanel2.Children.Add(border4);
scrollViewer.Content = stackPanel2;
Grid.SetRow(scrollViewer, 1);
grid.Children.Add(border2);
grid.Children.Add(scrollViewer);
border.Child = grid;
popup.Content = border;
popup.ShowDialog();
void AddMetaRow(string label, string value, int row)
{
if (!string.IsNullOrEmpty(value))
{
metaGrid.RowDefinitions.Add(new RowDefinition
{
Height = GridLength.Auto
});
TextBlock element = new TextBlock
{
Text = label,
FontSize = 11.5,
Foreground = subBrush,
Margin = new Thickness(0.0, 2.0, 0.0, 2.0)
};
Grid.SetRow(element, row);
Grid.SetColumn(element, 0);
metaGrid.Children.Add(element);
TextBlock element2 = new TextBlock
{
Text = value,
FontSize = 11.5,
Foreground = fgBrush,
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(0.0, 2.0, 0.0, 2.0)
};
Grid.SetRow(element2, row);
Grid.SetColumn(element2, 1);
metaGrid.Children.Add(element2);
}
}
}
[DebuggerNonUserCode]
[GeneratedCode("PresentationBuildTasks", "10.0.5.0")]
public void InitializeComponent()
{
if (!_contentLoaded)
{
_contentLoaded = true;
Uri resourceLocator = new Uri("/AxCopilot;component/views/skillgallerywindow.xaml", UriKind.Relative);
System.Windows.Application.LoadComponent(this, resourceLocator);
}
}
[DebuggerNonUserCode]
[GeneratedCode("PresentationBuildTasks", "10.0.5.0")]
[EditorBrowsable(EditorBrowsableState.Never)]
void IComponentConnector.Connect(int connectionId, object target)
{
switch (connectionId)
{
case 1:
((Border)target).MouseLeftButtonDown += TitleBar_MouseLeftButtonDown;
break;
case 2:
((Border)target).MouseLeftButtonUp += BtnAddSkill_Click;
break;
case 3:
((Border)target).MouseLeftButtonUp += BtnImport_Click;
break;
case 4:
BtnCloseGallery = (Border)target;
BtnCloseGallery.MouseLeftButtonUp += BtnClose_Click;
break;
case 5:
CategoryFilterBar = (StackPanel)target;
break;
case 6:
SkillListPanel = (StackPanel)target;
break;
case 7:
GalleryStatus = (TextBlock)target;
break;
default:
_contentLoaded = true;
break;
}
}
}