문서형 기본 제공 스킬 노출과 추천 메타데이터를 정리한다
- pptx/docx/report/prd/회의록/주간보고/markdown 변환 스킬에 when_to_use 및 argument-hint 메타를 추가해 자동 추천 품질을 높인다. - 설정 화면과 스킬 갤러리에서 managed 스코프를 기본 제공 스킬로 분리해 배포 자산과 사용자 스킬이 섞여 보이지 않게 한다. - README와 DEVELOPMENT 문서에 2026-04-14 18:37(KST) 기준 작업 이력과 검증 결과를 반영한다. - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_docskills\\ -p:IntermediateOutputPath=obj\\verify_docskills\\ 경고 0 / 오류 0
This commit is contained in:
@@ -668,11 +668,12 @@ public partial class AgentSettingsWindow : Window
|
||||
var groups = new[]
|
||||
{
|
||||
new { Title = "번들 스킬", Items = skills.Where(s => string.Equals(s.SourceScope, "bundled", StringComparison.OrdinalIgnoreCase)).ToList() },
|
||||
new { Title = "기본 제공 스킬", Items = skills.Where(s => string.Equals(s.SourceScope, "managed", StringComparison.OrdinalIgnoreCase)).ToList() },
|
||||
new { Title = "프로젝트 스킬", Items = skills.Where(s => string.Equals(s.SourceScope, "project", StringComparison.OrdinalIgnoreCase)).ToList() },
|
||||
new { Title = "플러그인 스킬", Items = skills.Where(s => string.Equals(s.SourceScope, "plugin", StringComparison.OrdinalIgnoreCase)).ToList() },
|
||||
new { Title = "보조/공용 스킬", Items = skills.Where(s => string.Equals(s.SourceScope, "additional", StringComparison.OrdinalIgnoreCase)).ToList() },
|
||||
new { Title = "레거시 명령 스킬", Items = skills.Where(s => string.Equals(s.SourceScope, "legacy", StringComparison.OrdinalIgnoreCase)).ToList() },
|
||||
new { Title = "사용자/추가 스킬", Items = skills.Where(s => !string.Equals(s.SourceScope, "bundled", StringComparison.OrdinalIgnoreCase) && !string.Equals(s.SourceScope, "project", StringComparison.OrdinalIgnoreCase) && !string.Equals(s.SourceScope, "plugin", StringComparison.OrdinalIgnoreCase) && !string.Equals(s.SourceScope, "additional", StringComparison.OrdinalIgnoreCase) && !string.Equals(s.SourceScope, "legacy", StringComparison.OrdinalIgnoreCase) && string.IsNullOrWhiteSpace(s.Requires)).ToList() },
|
||||
new { Title = "사용자 스킬", Items = skills.Where(s => !string.Equals(s.SourceScope, "bundled", StringComparison.OrdinalIgnoreCase) && !string.Equals(s.SourceScope, "managed", StringComparison.OrdinalIgnoreCase) && !string.Equals(s.SourceScope, "project", StringComparison.OrdinalIgnoreCase) && !string.Equals(s.SourceScope, "plugin", StringComparison.OrdinalIgnoreCase) && !string.Equals(s.SourceScope, "additional", StringComparison.OrdinalIgnoreCase) && !string.Equals(s.SourceScope, "legacy", StringComparison.OrdinalIgnoreCase) && string.IsNullOrWhiteSpace(s.Requires)).ToList() },
|
||||
new { Title = "고급 스킬", Items = skills.Where(s => !string.IsNullOrWhiteSpace(s.Requires) && !string.Equals(s.SourceScope, "project", StringComparison.OrdinalIgnoreCase)).ToList() },
|
||||
};
|
||||
|
||||
|
||||
@@ -654,11 +654,13 @@ public partial class SettingsWindow : Window
|
||||
});
|
||||
|
||||
var bundled = skills.Where(s => string.Equals(s.SourceScope, "bundled", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var managed = skills.Where(s => string.Equals(s.SourceScope, "managed", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var project = skills.Where(s => string.Equals(s.SourceScope, "project", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var plugin = skills.Where(s => string.Equals(s.SourceScope, "plugin", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var additional = skills.Where(s => string.Equals(s.SourceScope, "additional", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var legacy = skills.Where(s => string.Equals(s.SourceScope, "legacy", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var custom = skills.Where(s => !string.Equals(s.SourceScope, "bundled", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(s.SourceScope, "managed", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(s.SourceScope, "project", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(s.SourceScope, "plugin", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(s.SourceScope, "additional", StringComparison.OrdinalIgnoreCase)
|
||||
@@ -673,6 +675,12 @@ public partial class SettingsWindow : Window
|
||||
skillItems.Add(card);
|
||||
}
|
||||
|
||||
if (managed.Count > 0)
|
||||
{
|
||||
var card = CreateSkillGroupCard("기본 제공 스킬", "\uE8FD", "#0EA5E9", managed);
|
||||
skillItems.Add(card);
|
||||
}
|
||||
|
||||
if (project.Count > 0)
|
||||
{
|
||||
var card = CreateSkillGroupCard("프로젝트 스킬", "\uE8F1", "#2563EB", project);
|
||||
@@ -699,7 +707,7 @@ public partial class SettingsWindow : Window
|
||||
|
||||
if (custom.Count > 0)
|
||||
{
|
||||
var card = CreateSkillGroupCard("사용자/추가 스킬", "\uE70F", "#F59E0B", custom);
|
||||
var card = CreateSkillGroupCard("사용자 스킬", "\uE70F", "#F59E0B", custom);
|
||||
skillItems.Add(card);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,20 +73,9 @@ public partial class SkillGalleryWindow : Window
|
||||
var skills = SkillService.Skills;
|
||||
|
||||
var categories = new[] { "전체" }
|
||||
.Concat(skills
|
||||
.Select(s => string.IsNullOrEmpty(s.Requires) ? "내장" : "고급 (런타임)")
|
||||
.Distinct())
|
||||
.Concat(GetSkillCategories(skills))
|
||||
.ToList();
|
||||
|
||||
// 사용자 스킬이 있으면 추가
|
||||
var userFolder = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"AxCopilot", "skills");
|
||||
var hasUser = skills.Any(s =>
|
||||
s.FilePath.StartsWith(userFolder, StringComparison.OrdinalIgnoreCase));
|
||||
if (hasUser && !categories.Contains("사용자"))
|
||||
categories.Add("사용자");
|
||||
|
||||
foreach (var cat in categories)
|
||||
{
|
||||
var btn = new Border
|
||||
@@ -153,16 +142,13 @@ public partial class SkillGalleryWindow : Window
|
||||
|
||||
private List<SkillDefinition> FilterSkills(IReadOnlyList<SkillDefinition> skills)
|
||||
{
|
||||
var userFolder = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"AxCopilot", "skills");
|
||||
|
||||
return _selectedCategory switch
|
||||
{
|
||||
"내장" => skills.Where(s => string.IsNullOrEmpty(s.Requires)
|
||||
&& !s.FilePath.StartsWith(userFolder, StringComparison.OrdinalIgnoreCase)).ToList(),
|
||||
"기본 제공" => skills.Where(IsBuiltInSkill).ToList(),
|
||||
"프로젝트" => skills.Where(s => string.Equals(s.SourceScope, "project", StringComparison.OrdinalIgnoreCase)).ToList(),
|
||||
"플러그인" => skills.Where(s => string.Equals(s.SourceScope, "plugin", StringComparison.OrdinalIgnoreCase)).ToList(),
|
||||
"고급 (런타임)" => skills.Where(s => !string.IsNullOrEmpty(s.Requires)).ToList(),
|
||||
"사용자" => skills.Where(s => s.FilePath.StartsWith(userFolder, StringComparison.OrdinalIgnoreCase)).ToList(),
|
||||
"사용자" => skills.Where(IsUserOwnedSkill).ToList(),
|
||||
_ => skills.ToList(),
|
||||
};
|
||||
}
|
||||
@@ -173,8 +159,11 @@ public partial class SkillGalleryWindow : Window
|
||||
var fgBrush = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
||||
var subBrush = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||||
|
||||
var isUser = skill.FilePath.StartsWith(userFolder, StringComparison.OrdinalIgnoreCase);
|
||||
var isUser = IsUserOwnedSkill(skill);
|
||||
var isAdvanced = !string.IsNullOrEmpty(skill.Requires);
|
||||
var isBuiltIn = IsBuiltInSkill(skill);
|
||||
var isProject = string.Equals(skill.SourceScope, "project", StringComparison.OrdinalIgnoreCase);
|
||||
var isPlugin = string.Equals(skill.SourceScope, "plugin", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var card = new Border
|
||||
{
|
||||
@@ -238,12 +227,18 @@ public partial class SkillGalleryWindow : Window
|
||||
});
|
||||
|
||||
// 소스/유형 뱃지
|
||||
if (isUser)
|
||||
if (isProject)
|
||||
nameRow.Children.Add(MakeBadge("프로젝트", "#2563EB"));
|
||||
else if (isPlugin)
|
||||
nameRow.Children.Add(MakeBadge("플러그인", "#EC4899"));
|
||||
else if (isUser)
|
||||
nameRow.Children.Add(MakeBadge("사용자", "#34D399"));
|
||||
else if (isAdvanced)
|
||||
nameRow.Children.Add(MakeBadge("고급", "#A78BFA"));
|
||||
else if (isBuiltIn)
|
||||
nameRow.Children.Add(MakeBadge("기본 제공", "#0EA5E9"));
|
||||
else
|
||||
nameRow.Children.Add(MakeBadge("내장", "#9CA3AF"));
|
||||
nameRow.Children.Add(MakeBadge("번들", "#9CA3AF"));
|
||||
if (skill.IsSample)
|
||||
nameRow.Children.Add(MakeBadge("예제", "#F59E0B"));
|
||||
|
||||
@@ -402,6 +397,33 @@ public partial class SkillGalleryWindow : Window
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetSkillCategories(IReadOnlyList<SkillDefinition> skills)
|
||||
{
|
||||
if (skills.Any(IsBuiltInSkill))
|
||||
yield return "기본 제공";
|
||||
if (skills.Any(s => string.Equals(s.SourceScope, "project", StringComparison.OrdinalIgnoreCase)))
|
||||
yield return "프로젝트";
|
||||
if (skills.Any(s => string.Equals(s.SourceScope, "plugin", StringComparison.OrdinalIgnoreCase)))
|
||||
yield return "플러그인";
|
||||
if (skills.Any(s => !string.IsNullOrEmpty(s.Requires)))
|
||||
yield return "고급 (런타임)";
|
||||
if (skills.Any(IsUserOwnedSkill))
|
||||
yield return "사용자";
|
||||
}
|
||||
|
||||
private static bool IsBuiltInSkill(SkillDefinition skill) =>
|
||||
string.Equals(skill.SourceScope, "bundled", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(skill.SourceScope, "managed", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private static bool IsUserOwnedSkill(SkillDefinition skill) =>
|
||||
string.Equals(skill.SourceScope, "user", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(skill.SourceScope, "custom", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(skill.SourceScope, "additional", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(skill.SourceScope, "legacy", StringComparison.OrdinalIgnoreCase) ||
|
||||
(!IsBuiltInSkill(skill)
|
||||
&& !string.Equals(skill.SourceScope, "project", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(skill.SourceScope, "plugin", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
private Border MakeActionBtn(string icon, string colorHex, string tooltip, Action action)
|
||||
{
|
||||
var col = (Color)ColorConverter.ConvertFromString(colorHex);
|
||||
|
||||
@@ -3,6 +3,8 @@ name: docx-creator
|
||||
label: Word 문서 생성
|
||||
description: Python을 사용하여 전문적인 Word 문서(.docx)를 생성합니다. 작업 폴더의 양식 파일을 자동 활용합니다.
|
||||
icon: \uE8A5
|
||||
when_to_use: 보고서, 제안서, 공문, 가이드 문서처럼 정식 Word 문서를 새로 만들거나 기존 양식 DOCX를 이어서 작성해야 할 때
|
||||
argument-hint: <문서 종류 또는 목적>
|
||||
allowed-tools:
|
||||
- folder_map
|
||||
- document_read
|
||||
|
||||
@@ -3,6 +3,8 @@ name: markdown-to-doc
|
||||
label: Markdown → 문서 변환
|
||||
description: Markdown 파일을 서식이 적용된 Word(.docx) 또는 PDF 문서로 변환합니다.
|
||||
icon: \uE8A5
|
||||
when_to_use: 이미 정리된 Markdown 초안을 외부 공유용 Word/PDF 문서로 바꿔야 할 때
|
||||
argument-hint: <입력 markdown 파일 또는 출력 형식>
|
||||
allowed-tools:
|
||||
- file_read
|
||||
- file_write
|
||||
|
||||
@@ -3,6 +3,8 @@ name: meeting-minutes
|
||||
label: 회의록 정리
|
||||
description: 회의 내용을 체계적으로 정리하여 회의록을 생성합니다.
|
||||
icon: \uE771
|
||||
when_to_use: 회의 메모, 녹취 정리본, 액션 아이템을 바탕으로 공식 회의록이나 의사결정 기록을 남겨야 할 때
|
||||
argument-hint: <회의 주제>
|
||||
allowed-tools:
|
||||
- file_read
|
||||
- file_write
|
||||
|
||||
@@ -3,6 +3,8 @@ name: pptx-creator
|
||||
label: PPT 프레젠테이션 생성
|
||||
description: Python을 사용하여 전문적인 PowerPoint 프레젠테이션을 생성합니다. 작업 폴더의 양식 파일을 자동 활용합니다.
|
||||
icon: \uE7BE
|
||||
when_to_use: 발표 자료, 제안서 deck, 보고용 슬라이드, 교육용 프레젠테이션을 새로 만들어야 하거나 기존 양식 PPT를 활용해야 할 때
|
||||
argument-hint: <주제 또는 문서 목적>
|
||||
allowed-tools:
|
||||
- folder_map
|
||||
- document_read
|
||||
|
||||
@@ -3,6 +3,8 @@ name: prd-generator
|
||||
label: 요구사항 정의서 (PRD)
|
||||
description: 제품 요구사항 정의서, 유저 스토리, 수용 기준을 체계적으로 생성합니다.
|
||||
icon: \uE8A5
|
||||
when_to_use: 신규 기능, 제품 개선안, PoC 범위를 정리하면서 PRD 초안과 수용 기준이 필요할 때
|
||||
argument-hint: <제품명 또는 기능명>
|
||||
allowed-tools:
|
||||
- file_read
|
||||
- file_write
|
||||
|
||||
@@ -3,6 +3,8 @@ name: report-writer
|
||||
label: 보고서 작성
|
||||
description: 작업 폴더의 데이터를 분석하여 체계적인 업무 보고서를 생성합<EC84B1><ED95A9>다.
|
||||
icon: \uE9F9
|
||||
when_to_use: 파일과 데이터 근거를 바탕으로 주간·월간·현황·분석 보고서를 빠르게 정리해야 할 때
|
||||
argument-hint: <보고 목적 또는 대상>
|
||||
allowed-tools:
|
||||
- folder_map
|
||||
- file_read
|
||||
|
||||
@@ -3,6 +3,8 @@ name: weekly-report
|
||||
label: 주간 보고서
|
||||
description: 작업 폴더의 변경 이력을 기반으로 자동 주간보고 초안을 생성합니다.
|
||||
icon: \uE787
|
||||
when_to_use: 최근 1주일 변경 이력과 작업 상황을 바탕으로 팀/리더 공유용 주간 보고서를 준비할 때
|
||||
argument-hint: <보고 대상 또는 기간>
|
||||
allowed-tools:
|
||||
- git_tool
|
||||
- folder_map
|
||||
|
||||
Reference in New Issue
Block a user