스킬 런타임 2차 고도화와 도구 노출 필터 정비
프로젝트 .claude/skills 재귀 로드와 namespaced SKILL.md 파싱을 추가하고 번들/사용자/프로젝트 스킬을 함께 노출하도록 SkillService와 설정 UI를 확장했다. 슬래시 스킬 호출 시 인자 치환, 스킬 폴더 변수 치환, inline shell 실행, when_to_use 기반 자동 스킬 가이드를 실제 ChatWindow 런타임 경로에 연결했다. blanket deny 권한은 모델 노출 전 활성 도구 목록에서 먼저 제외하도록 AgentLoopService를 보강했고 관련 테스트와 README/DEVELOPMENT 문서를 업데이트했다. 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_phase2\\ -p:IntermediateOutputPath=obj\\verify_phase2\\ (경고 0 / 오류 0) 검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentToolCatalogTests|SkillServiceRuntimePolicyTests" -p:OutputPath=bin\\verify_phase2_tests\\ -p:IntermediateOutputPath=obj\\verify_phase2_tests\\ (통과 16, 기존 WorkspaceContextGeneratorTests nullable 경고 1건 유지)
This commit is contained in:
@@ -94,7 +94,9 @@ public partial class SettingsWindow : Window
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Services.Agent.SkillService.EnsureSkillFolder();
|
||||
Services.Agent.SkillService.LoadSkills(app?.SettingsService?.Settings.Llm.SkillsFolderPath);
|
||||
Services.Agent.SkillService.LoadSkills(
|
||||
app?.SettingsService?.Settings.Llm.SkillsFolderPath,
|
||||
ResolveSkillProjectRoot(app?.SettingsService?.Settings.Llm));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -115,6 +117,27 @@ public partial class SettingsWindow : Window
|
||||
};
|
||||
}
|
||||
|
||||
private static string? ResolveSkillProjectRoot(Models.LlmSettings? llm)
|
||||
{
|
||||
if (llm == null)
|
||||
return null;
|
||||
|
||||
var candidates = new[]
|
||||
{
|
||||
llm.CodeWorkFolder,
|
||||
llm.CoworkWorkFolder,
|
||||
llm.WorkFolder
|
||||
};
|
||||
|
||||
foreach (var candidate in candidates)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(candidate) && Directory.Exists(candidate))
|
||||
return candidate.Trim();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void BindIndexProgress()
|
||||
{
|
||||
_indexService = (System.Windows.Application.Current as App)?.IndexService;
|
||||
@@ -616,26 +639,40 @@ public partial class SettingsWindow : Window
|
||||
// 설명
|
||||
skillItems.Add(new TextBlock
|
||||
{
|
||||
Text = "/ 명령으로 호출할 수 있는 스킬 목록입니다. 앱 내장 + 사용자 추가 스킬이 포함됩니다.\n" +
|
||||
"(직접 호출 가능한 스킬과 런타임 정책에 연결되는 스킬을 함께 표시합니다.)",
|
||||
Text = "/ 명령으로 호출할 수 있는 스킬 목록입니다. 번들 스킬, 사용자/추가 스킬, 프로젝트 `.claude/skills`가 함께 포함됩니다.\n" +
|
||||
"(직접 호출 스킬과 자동/조건부 보조 스킬을 함께 표시합니다.)",
|
||||
FontSize = 11,
|
||||
Foreground = new SolidColorBrush(subtleText),
|
||||
Margin = new Thickness(2, 0, 0, 10),
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
});
|
||||
|
||||
// 내장 스킬 / 고급 스킬 분류
|
||||
var builtIn = skills.Where(s => string.IsNullOrEmpty(s.Requires)).ToList();
|
||||
var advanced = skills.Where(s => !string.IsNullOrEmpty(s.Requires)).ToList();
|
||||
var bundled = skills.Where(s => string.Equals(s.SourceScope, "bundled", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var project = skills.Where(s => string.Equals(s.SourceScope, "project", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var custom = skills.Where(s => !string.Equals(s.SourceScope, "bundled", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(s.SourceScope, "project", StringComparison.OrdinalIgnoreCase)
|
||||
&& string.IsNullOrEmpty(s.Requires)).ToList();
|
||||
var advanced = skills.Where(s => !string.IsNullOrEmpty(s.Requires)
|
||||
&& !string.Equals(s.SourceScope, "project", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
// 내장 스킬 카드
|
||||
if (builtIn.Count > 0)
|
||||
if (bundled.Count > 0)
|
||||
{
|
||||
var card = CreateSkillGroupCard("내장 스킬", "\uE768", "#34D399", builtIn);
|
||||
var card = CreateSkillGroupCard("번들 스킬", "\uE768", "#34D399", bundled);
|
||||
skillItems.Add(card);
|
||||
}
|
||||
|
||||
if (project.Count > 0)
|
||||
{
|
||||
var card = CreateSkillGroupCard("프로젝트 스킬", "\uE8F1", "#2563EB", project);
|
||||
skillItems.Add(card);
|
||||
}
|
||||
|
||||
if (custom.Count > 0)
|
||||
{
|
||||
var card = CreateSkillGroupCard("사용자/추가 스킬", "\uE70F", "#F59E0B", custom);
|
||||
skillItems.Add(card);
|
||||
}
|
||||
|
||||
// 고급 스킬 (런타임 의존) 카드
|
||||
if (advanced.Count > 0)
|
||||
{
|
||||
var card = CreateSkillGroupCard("고급 스킬 (런타임 필요)", "\uE9D9", "#A78BFA", advanced);
|
||||
|
||||
Reference in New Issue
Block a user