???? ???? ?? ????????? ????? ?? ????? PPT ?? ???? ??
??: - ?? ?? ???? ?? ?? ??, ?? ? ?? ?? ??, ?????? ???? ??? ? ?? ?????. - ?? ?? ??? ??? ?? PPT? ?? ??? ?? ???? ?? ????? ????. ?? ????: - AgentCommandQueue? steering, permission continuation, resume, user decision ? ??? ???? AgentLoopService?? ?? ???? ????? ?? - CodeLanguageCatalog? LspClientService? ??? Go, Rust, PHP, Ruby, Kotlin, Swift? ?? LSP ?? ???? ?? - SettingsWindow? SettingsViewModel?? ?? ? ?? ??? ?? ?? / LSP / ?? ???? ????? ?? - WorkspaceContextGenerator? Language Snapshot, Agent Context, Key Manifests ??? ???? .claude/skills, .ax/rules, AXMEMORY.md ??? ?? - DeckRepairGuideService? ???? PptxSkill ??? Deck repair guide? ?? ?? - ?? ?? ???? ?? ???? ?? ? ?? ??: - dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_master_batch\\ -p:IntermediateOutputPath=obj\\verify_master_batch\\ - dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentCommandQueueTests,CodeLanguageCatalogTests,WorkspaceContextGeneratorTests,PptxSkillConsultingDeckTests,DeckRepairGuideServiceTests -p:OutputPath=bin\\verify_master_batch_tests\\ -p:IntermediateOutputPath=obj\\verify_master_batch_tests\\
This commit is contained in:
@@ -1865,3 +1865,12 @@ MIT License
|
|||||||
- 테스트로 [ArtifactRepairGuideServiceTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/ArtifactRepairGuideServiceTests.cs)를 추가했고, [ExcelSkillDashboardSummaryTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/ExcelSkillDashboardSummaryTests.cs), [HtmlSkillConsultingSectionsTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/HtmlSkillConsultingSectionsTests.cs)를 확장해 새 archetype과 repair guide를 회귀 검증했습니다.
|
- 테스트로 [ArtifactRepairGuideServiceTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/ArtifactRepairGuideServiceTests.cs)를 추가했고, [ExcelSkillDashboardSummaryTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/ExcelSkillDashboardSummaryTests.cs), [HtmlSkillConsultingSectionsTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/HtmlSkillConsultingSectionsTests.cs)를 확장해 새 archetype과 repair guide를 회귀 검증했습니다.
|
||||||
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_next6\\ -p:IntermediateOutputPath=obj\\verify_doc_next6\\` 경고 0 / 오류 0
|
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_next6\\ -p:IntermediateOutputPath=obj\\verify_doc_next6\\` 경고 0 / 오류 0
|
||||||
- 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ArtifactQualityReviewServiceTests|ArtifactRepairGuideServiceTests|ExcelSkillDashboardSummaryTests|HtmlSkillConsultingSectionsTests|HtmlSkillPrintFrameTests|DocumentAssemblerStyleMapTests|DocumentAssemblerDocxFeaturesTests|DocumentAssemblerSemanticTests|PptxSkillGoldenDeckTests|DeckQualityReviewServiceTests" -p:OutputPath=bin\\verify_doc_next6_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_next6_tests\\` 통과 17
|
- 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ArtifactQualityReviewServiceTests|ArtifactRepairGuideServiceTests|ExcelSkillDashboardSummaryTests|HtmlSkillConsultingSectionsTests|HtmlSkillPrintFrameTests|DocumentAssemblerStyleMapTests|DocumentAssemblerDocxFeaturesTests|DocumentAssemblerSemanticTests|PptxSkillGoldenDeckTests|DeckQualityReviewServiceTests" -p:OutputPath=bin\\verify_doc_next6_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_next6_tests\\` 통과 17
|
||||||
|
|
||||||
|
업데이트: 2026-04-15 00:19 (KST)
|
||||||
|
- 에이전틱 루프 입력 큐를 확장했습니다. [AgentCommandQueue.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AgentCommandQueue.cs)는 `steering`, `permission continuation`, `resume`, `user decision`까지 분리해서 담을 수 있고, [AgentLoopService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AgentLoopService.cs)는 이를 `queued_steering`, `queue_permission_continuation`, `queue_resume` 메타 메시지로 주입해 실행 중 새 지시와 승인 흐름을 더 안정적으로 다룹니다.
|
||||||
|
- 코드 탭 언어 지원도 넓혔습니다. [CodeLanguageCatalog.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/CodeLanguageCatalog.cs)는 `Go`, `Rust`, `PHP`, `Ruby`, `Kotlin`, `Swift`를 LSP 심화 지원군에 포함하고, [LspClientService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/LspClientService.cs)는 `gopls`, `rust-analyzer`, `intelephense`, `solargraph`, `kotlin-language-server`, `sourcekit-lsp`를 로컬 설치 서버 기준으로 탐지합니다.
|
||||||
|
- 내부 설정의 코드 탭 설명도 보강했습니다. [SettingsWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/SettingsWindow.xaml)과 [SettingsViewModel.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/ViewModels/SettingsViewModel.cs)는 `빠른 선택 언어`, `지원 언어(LSP)`, `코드 탭 기본 지원`을 분리 표기해 격리 환경에서 어떤 수준의 지원이 가능한지 더 명확히 보여줍니다.
|
||||||
|
- 워크스페이스 컨텍스트 생성기도 강화했습니다. [WorkspaceContextGenerator.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/WorkspaceContextGenerator.cs)는 `Language Snapshot`, `Agent Context`, `Key Manifests` 섹션을 추가하고 `.claude/skills`, `.ax/rules`, `AXMEMORY.md`, 주요 manifest 파일을 함께 요약합니다.
|
||||||
|
- PPT는 품질 리뷰 뒤에 바로 실행 가능한 보정 가이드를 붙이도록 [DeckRepairGuideService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/DeckRepairGuideService.cs)를 추가했고, [PptxSkill.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/PptxSkill.cs)는 `Deck repair guide:`를 함께 반환합니다.
|
||||||
|
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_master_batch\\ -p:IntermediateOutputPath=obj\\verify_master_batch\\` 경고 0 / 오류 0
|
||||||
|
- 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentCommandQueueTests|CodeLanguageCatalogTests|WorkspaceContextGeneratorTests|PptxSkillConsultingDeckTests|DeckRepairGuideServiceTests" -p:OutputPath=bin\\verify_master_batch_tests\\ -p:IntermediateOutputPath=obj\\verify_master_batch_tests\\` 통과 35
|
||||||
|
|||||||
@@ -939,3 +939,13 @@ UI ?붿옄???洹쒕え 由ы뙥?좊쭅 ???꾪뿕 ?묒뾽 ??湲곕줉???덉쟾
|
|||||||
- 테스트로 [ArtifactRepairGuideServiceTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/ArtifactRepairGuideServiceTests.cs)를 추가했고, [ExcelSkillDashboardSummaryTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/ExcelSkillDashboardSummaryTests.cs), [HtmlSkillConsultingSectionsTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/HtmlSkillConsultingSectionsTests.cs)를 확장해 archetype과 repair guide를 함께 회귀 검증했습니다.
|
- 테스트로 [ArtifactRepairGuideServiceTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/ArtifactRepairGuideServiceTests.cs)를 추가했고, [ExcelSkillDashboardSummaryTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/ExcelSkillDashboardSummaryTests.cs), [HtmlSkillConsultingSectionsTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/HtmlSkillConsultingSectionsTests.cs)를 확장해 archetype과 repair guide를 함께 회귀 검증했습니다.
|
||||||
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_next6\\ -p:IntermediateOutputPath=obj\\verify_doc_next6\\` 경고 0 / 오류 0
|
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_next6\\ -p:IntermediateOutputPath=obj\\verify_doc_next6\\` 경고 0 / 오류 0
|
||||||
- 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ArtifactQualityReviewServiceTests|ArtifactRepairGuideServiceTests|ExcelSkillDashboardSummaryTests|HtmlSkillConsultingSectionsTests|HtmlSkillPrintFrameTests|DocumentAssemblerStyleMapTests|DocumentAssemblerDocxFeaturesTests|DocumentAssemblerSemanticTests|PptxSkillGoldenDeckTests|DeckQualityReviewServiceTests" -p:OutputPath=bin\\verify_doc_next6_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_next6_tests\\` 통과 17
|
- 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ArtifactQualityReviewServiceTests|ArtifactRepairGuideServiceTests|ExcelSkillDashboardSummaryTests|HtmlSkillConsultingSectionsTests|HtmlSkillPrintFrameTests|DocumentAssemblerStyleMapTests|DocumentAssemblerDocxFeaturesTests|DocumentAssemblerSemanticTests|PptxSkillGoldenDeckTests|DeckQualityReviewServiceTests" -p:OutputPath=bin\\verify_doc_next6_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_next6_tests\\` 통과 17
|
||||||
|
|
||||||
|
업데이트: 2026-04-15 00:19 (KST)
|
||||||
|
- `AgentCommandQueue`를 `Prompt/Notification` 2종에서 `Steering`, `PermissionContinuation`, `Resume`, `UserDecision`까지 포함하는 통합 큐로 확장했습니다. [AgentLoopService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AgentLoopService.cs)는 이를 `queued_steering`, `queue_permission_continuation`, `queue_resume` 메타 메시지로 주입해 실행 중 추가 입력과 승인 후 재개 문맥을 더 안정적으로 반영합니다.
|
||||||
|
- 코드 탭 언어 지원 카탈로그를 확장했습니다. [CodeLanguageCatalog.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/CodeLanguageCatalog.cs)는 `Go`, `Rust`, `PHP`, `Ruby`, `Kotlin`, `Swift`를 LSP 심화 지원군으로 승격했고, [LspClientService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/LspClientService.cs)는 `gopls`, `rust-analyzer`, `intelephense`, `solargraph`, `kotlin-language-server`, `sourcekit-lsp`를 로컬 설치 서버 기준으로 탐지합니다.
|
||||||
|
- 내부 설정의 코드 탭 설명을 더 명시적으로 정리했습니다. [SettingsWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/SettingsWindow.xaml), [SettingsViewModel.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/ViewModels/SettingsViewModel.cs)는 `빠른 선택 언어`, `지원 언어(LSP)`, `코드 탭 기본 지원`을 나눠 보여주도록 보강했습니다.
|
||||||
|
- 워크스페이스 컨텍스트 생성기를 강화했습니다. [WorkspaceContextGenerator.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/WorkspaceContextGenerator.cs)는 `Language Snapshot`, `Agent Context`, `Key Manifests` 섹션을 추가하고 `.claude/skills`, `.ax/rules`, `AXMEMORY.md`, 주요 manifest 파일을 함께 요약합니다.
|
||||||
|
- PPT 품질 보정 가이드도 추가했습니다. [DeckRepairGuideService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/DeckRepairGuideService.cs)는 deck 품질 이슈를 바로 실행 가능한 개선 문장으로 바꾸고, [PptxSkill.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/PptxSkill.cs)는 `Deck repair guide:`를 품질 요약과 함께 반환합니다.
|
||||||
|
- 테스트: [AgentCommandQueueTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/AgentCommandQueueTests.cs), [CodeLanguageCatalogTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/CodeLanguageCatalogTests.cs), [WorkspaceContextGeneratorTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/WorkspaceContextGeneratorTests.cs), [DeckRepairGuideServiceTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/DeckRepairGuideServiceTests.cs), [PptxSkillConsultingDeckTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/PptxSkillConsultingDeckTests.cs)
|
||||||
|
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_master_batch\\ -p:IntermediateOutputPath=obj\\verify_master_batch\\` 경고 0 / 오류 0
|
||||||
|
- 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentCommandQueueTests|CodeLanguageCatalogTests|WorkspaceContextGeneratorTests|PptxSkillConsultingDeckTests|DeckRepairGuideServiceTests" -p:OutputPath=bin\\verify_master_batch_tests\\ -p:IntermediateOutputPath=obj\\verify_master_batch_tests\\` 통과 35
|
||||||
|
|||||||
@@ -31,4 +31,25 @@ public class AgentCommandQueueTests
|
|||||||
|
|
||||||
queue.DrainAll().Should().BeEmpty();
|
queue.DrainAll().Should().BeEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DrainAll_ShouldIncludeSteeringPermissionAndResumeKinds()
|
||||||
|
{
|
||||||
|
var queue = new AgentCommandQueue();
|
||||||
|
queue.EnqueueNotification("later-note");
|
||||||
|
queue.EnqueueResume("resume");
|
||||||
|
queue.EnqueuePermissionContinuation("continue-tool");
|
||||||
|
queue.EnqueueSteering("steer-now");
|
||||||
|
|
||||||
|
var drained = queue.DrainAll();
|
||||||
|
|
||||||
|
drained.Select(x => x.Kind).Should().Equal(
|
||||||
|
AgentCommandKind.Resume,
|
||||||
|
AgentCommandKind.PermissionContinuation,
|
||||||
|
AgentCommandKind.Steering,
|
||||||
|
AgentCommandKind.Notification);
|
||||||
|
drained[0].RequestInterrupt.Should().BeFalse();
|
||||||
|
drained[1].RequestInterrupt.Should().BeTrue();
|
||||||
|
drained[2].RequestInterrupt.Should().BeTrue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ public class CodeLanguageCatalogTests
|
|||||||
[InlineData(".cs", "csharp")]
|
[InlineData(".cs", "csharp")]
|
||||||
[InlineData(".py", "python")]
|
[InlineData(".py", "python")]
|
||||||
[InlineData(".java", "java")]
|
[InlineData(".java", "java")]
|
||||||
[InlineData(".go", null)]
|
[InlineData(".go", "go")]
|
||||||
|
[InlineData(".rs", "rust")]
|
||||||
|
[InlineData(".php", "php")]
|
||||||
[InlineData(".unknown", null)]
|
[InlineData(".unknown", null)]
|
||||||
public void DetectLspLanguageId_ShouldMatchCatalog(string extension, string? expected)
|
public void DetectLspLanguageId_ShouldMatchCatalog(string extension, string? expected)
|
||||||
{
|
{
|
||||||
@@ -33,6 +35,15 @@ public class CodeLanguageCatalogTests
|
|||||||
CodeLanguageCatalog.BuildStaticSupportDescription().Should().Contain("Go");
|
CodeLanguageCatalog.BuildStaticSupportDescription().Should().Contain("Go");
|
||||||
CodeLanguageCatalog.BuildStaticSupportDescription().Should().Contain("Rust");
|
CodeLanguageCatalog.BuildStaticSupportDescription().Should().Contain("Rust");
|
||||||
CodeLanguageCatalog.BuildLspSupportDescription().Should().Contain("C# (.NET)");
|
CodeLanguageCatalog.BuildLspSupportDescription().Should().Contain("C# (.NET)");
|
||||||
CodeLanguageCatalog.BuildLspSupportDescription().Should().NotContain("Go");
|
CodeLanguageCatalog.BuildLspSupportDescription().Should().Contain("Go");
|
||||||
|
CodeLanguageCatalog.BuildLspSupportDescription().Should().Contain("Swift");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void QuickSelectDescription_ShouldRemainFocusedOnUiShortlist()
|
||||||
|
{
|
||||||
|
CodeLanguageCatalog.BuildQuickSelectSupportDescription().Should().Contain("C# (.NET)");
|
||||||
|
CodeLanguageCatalog.BuildQuickSelectSupportDescription().Should().Contain("JavaScript / Vue");
|
||||||
|
CodeLanguageCatalog.BuildQuickSelectSupportDescription().Should().NotContain("Go");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/AxCopilot.Tests/Services/DeckRepairGuideServiceTests.cs
Normal file
38
src/AxCopilot.Tests/Services/DeckRepairGuideServiceTests.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using AxCopilot.Services.Agent;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace AxCopilot.Tests.Services;
|
||||||
|
|
||||||
|
public class DeckRepairGuideServiceTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void BuildGuide_ShouldReturnNone_WhenNoIssues()
|
||||||
|
{
|
||||||
|
var report = new DeckQualityReport(92, ["Includes Recommendation"], [], []);
|
||||||
|
|
||||||
|
var guide = DeckRepairGuideService.BuildGuide(report);
|
||||||
|
|
||||||
|
guide.Should().Be("Deck repair guide: none");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BuildGuide_ShouldTranslateDeckIssuesIntoActionableGuidance()
|
||||||
|
{
|
||||||
|
var report = new DeckQualityReport(
|
||||||
|
61,
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
new DeckReviewIssue("Executive Summary slide is missing.", DeckReviewSeverity.Critical),
|
||||||
|
new DeckReviewIssue("Slide 3: content density is high and should be simplified.", DeckReviewSeverity.Warning),
|
||||||
|
new DeckReviewIssue("Evidence slides such as charts, tables, or comparisons are limited.", DeckReviewSeverity.Warning),
|
||||||
|
],
|
||||||
|
[]);
|
||||||
|
|
||||||
|
var guide = DeckRepairGuideService.BuildGuide(report);
|
||||||
|
|
||||||
|
guide.Should().Contain("Executive Summary");
|
||||||
|
guide.Should().Contain("Reduce text density");
|
||||||
|
guide.Should().Contain("evidence");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -102,6 +102,7 @@ public class PptxSkillConsultingDeckTests
|
|||||||
result.Success.Should().BeTrue();
|
result.Success.Should().BeTrue();
|
||||||
File.Exists(Path.Combine(workDir, "consulting-deck.pptx")).Should().BeTrue();
|
File.Exists(Path.Combine(workDir, "consulting-deck.pptx")).Should().BeTrue();
|
||||||
result.Output.Should().Contain("PPTX");
|
result.Output.Should().Contain("PPTX");
|
||||||
|
result.Output.Should().Contain("Deck repair guide:");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -182,6 +182,30 @@ public class WorkspaceContextGeneratorTests
|
|||||||
|
|
||||||
var result = await WorkspaceContextGenerator.GenerateAsync(tempDir);
|
var result = await WorkspaceContextGenerator.GenerateAsync(tempDir);
|
||||||
result.Should().Contain("Node.js");
|
result.Should().Contain("Node.js");
|
||||||
|
result.Should().Contain("## Key Manifests");
|
||||||
|
result.Should().Contain("Node package");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Directory.Delete(tempDir, recursive: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GenerateAsync_IncludesLanguageSnapshot()
|
||||||
|
{
|
||||||
|
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
|
||||||
|
Directory.CreateDirectory(tempDir);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.WriteAllText(Path.Combine(tempDir, "main.go"), "package main");
|
||||||
|
File.WriteAllText(Path.Combine(tempDir, "worker.go"), "package main");
|
||||||
|
File.WriteAllText(Path.Combine(tempDir, "helper.py"), "print('hi')");
|
||||||
|
|
||||||
|
var result = await WorkspaceContextGenerator.GenerateAsync(tempDir);
|
||||||
|
|
||||||
|
result.Should().Contain("## Language Snapshot");
|
||||||
|
result.Should().Contain("Go:");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -217,10 +241,15 @@ public class WorkspaceContextGeneratorTests
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.WriteAllText(Path.Combine(tempDir, "AGENTS.md"), "Agent rules here");
|
File.WriteAllText(Path.Combine(tempDir, "AGENTS.md"), "Agent rules here");
|
||||||
|
var skillsDir = Path.Combine(tempDir, ".claude", "skills", "deck");
|
||||||
|
Directory.CreateDirectory(skillsDir);
|
||||||
|
File.WriteAllText(Path.Combine(skillsDir, "SKILL.md"), "# skill");
|
||||||
|
|
||||||
var result = await WorkspaceContextGenerator.GenerateAsync(tempDir);
|
var result = await WorkspaceContextGenerator.GenerateAsync(tempDir);
|
||||||
result.Should().Contain("## Existing Context Files");
|
result.Should().Contain("## Existing Context Files");
|
||||||
result.Should().Contain("AGENTS.md");
|
result.Should().Contain("AGENTS.md");
|
||||||
|
result.Should().Contain("## Agent Context");
|
||||||
|
result.Should().Contain(".claude/skills");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ public enum AgentCommandKind
|
|||||||
{
|
{
|
||||||
Prompt,
|
Prompt,
|
||||||
Notification,
|
Notification,
|
||||||
|
Steering,
|
||||||
|
PermissionContinuation,
|
||||||
|
Resume,
|
||||||
|
UserDecision,
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed record AgentQueuedCommand(
|
public sealed record AgentQueuedCommand(
|
||||||
@@ -45,6 +49,18 @@ public sealed class AgentCommandQueue
|
|||||||
public void EnqueueNotification(string content, string priority = "later")
|
public void EnqueueNotification(string content, string priority = "later")
|
||||||
=> Enqueue(AgentCommandKind.Notification, content, priority, requestInterrupt: false);
|
=> Enqueue(AgentCommandKind.Notification, content, priority, requestInterrupt: false);
|
||||||
|
|
||||||
|
public void EnqueueSteering(string content, string priority = "now", bool requestInterrupt = true)
|
||||||
|
=> Enqueue(AgentCommandKind.Steering, content, priority, requestInterrupt);
|
||||||
|
|
||||||
|
public void EnqueuePermissionContinuation(string content, string priority = "now")
|
||||||
|
=> Enqueue(AgentCommandKind.PermissionContinuation, content, priority, requestInterrupt: true);
|
||||||
|
|
||||||
|
public void EnqueueResume(string content, string priority = "now")
|
||||||
|
=> Enqueue(AgentCommandKind.Resume, content, priority, requestInterrupt: false);
|
||||||
|
|
||||||
|
public void EnqueueUserDecision(string content, string priority = "next", bool requestInterrupt = false)
|
||||||
|
=> Enqueue(AgentCommandKind.UserDecision, content, priority, requestInterrupt);
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
while (_now.TryDequeue(out _)) { }
|
while (_now.TryDequeue(out _)) { }
|
||||||
|
|||||||
@@ -49,20 +49,60 @@ public partial class AgentLoopService
|
|||||||
requestInterrupt: IsRunning);
|
requestInterrupt: IsRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>실행 중 사용자 지시 보강 메시지를 우선순위 높게 주입합니다.</summary>
|
||||||
|
public void InjectSteeringMessage(string message, bool requestInterrupt = true)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(message))
|
||||||
|
_pendingCommands.EnqueueSteering(
|
||||||
|
message,
|
||||||
|
IsRunning ? "now" : "next",
|
||||||
|
requestInterrupt: IsRunning && requestInterrupt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>권한 승인 후 이어서 진행할 내용을 큐에 넣습니다.</summary>
|
||||||
|
public void EnqueuePermissionContinuation(string toolName, string? target, string decisionSummary)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(decisionSummary))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var targetLabel = string.IsNullOrWhiteSpace(target) ? "" : $" ({target})";
|
||||||
|
_pendingCommands.EnqueuePermissionContinuation(
|
||||||
|
$"[permission continuation] Continue {toolName}{targetLabel}: {decisionSummary}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>도구 실행 중 참고용 시스템 알림을 큐에 넣습니다.</summary>
|
||||||
|
public void EnqueueNotification(string message, string priority = "later")
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(message))
|
||||||
|
_pendingCommands.EnqueueNotification(message, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>사용자 의사결정 결과를 다음 턴 입력으로 주입합니다.</summary>
|
||||||
|
public void EnqueueUserDecision(string message, bool requestInterrupt = false)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(message))
|
||||||
|
_pendingCommands.EnqueueUserDecision(
|
||||||
|
message,
|
||||||
|
IsRunning ? "next" : "now",
|
||||||
|
requestInterrupt && IsRunning);
|
||||||
|
}
|
||||||
|
|
||||||
private void DrainPendingCommands(List<ChatMessage> messages)
|
private void DrainPendingCommands(List<ChatMessage> messages)
|
||||||
{
|
{
|
||||||
var drained = _pendingCommands.DrainAll();
|
var drained = _pendingCommands.DrainAll();
|
||||||
if (drained.Count == 0)
|
if (drained.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var interruptingPrompts = drained.Count(x => x.Kind == AgentCommandKind.Prompt && x.RequestInterrupt);
|
var interruptingCommands = drained.Count(x =>
|
||||||
if (interruptingPrompts > 0)
|
x.RequestInterrupt &&
|
||||||
|
x.Kind is AgentCommandKind.Prompt or AgentCommandKind.Steering or AgentCommandKind.UserDecision or AgentCommandKind.PermissionContinuation);
|
||||||
|
if (interruptingCommands > 0)
|
||||||
{
|
{
|
||||||
messages.Add(new ChatMessage
|
messages.Add(new ChatMessage
|
||||||
{
|
{
|
||||||
Role = "system",
|
Role = "system",
|
||||||
MetaKind = "queued_input_interrupt",
|
MetaKind = "queued_input_interrupt",
|
||||||
Content = $"[queued input] {interruptingPrompts} new prompt(s) arrived during execution. Prioritize the newest user direction before continuing.",
|
Content = $"[queued input] {interruptingCommands} new instruction(s) arrived during execution. Prioritize the newest user direction before continuing.",
|
||||||
Timestamp = DateTime.Now,
|
Timestamp = DateTime.Now,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -82,6 +122,40 @@ public partial class AgentLoopService
|
|||||||
EmitEvent(AgentEventType.Thinking, "", item.Content);
|
EmitEvent(AgentEventType.Thinking, "", item.Content);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AgentCommandKind.PermissionContinuation:
|
||||||
|
messages.Add(new ChatMessage
|
||||||
|
{
|
||||||
|
Role = "system",
|
||||||
|
MetaKind = "queue_permission_continuation",
|
||||||
|
Content = item.Content,
|
||||||
|
Timestamp = item.CreatedAt,
|
||||||
|
});
|
||||||
|
EmitEvent(AgentEventType.Thinking, "", item.Content);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AgentCommandKind.Resume:
|
||||||
|
messages.Add(new ChatMessage
|
||||||
|
{
|
||||||
|
Role = "system",
|
||||||
|
MetaKind = "queue_resume",
|
||||||
|
Content = item.Content,
|
||||||
|
Timestamp = item.CreatedAt,
|
||||||
|
});
|
||||||
|
EmitEvent(AgentEventType.Thinking, "", item.Content);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AgentCommandKind.Steering:
|
||||||
|
case AgentCommandKind.UserDecision:
|
||||||
|
messages.Add(new ChatMessage
|
||||||
|
{
|
||||||
|
Role = "user",
|
||||||
|
MetaKind = item.Kind == AgentCommandKind.Steering ? "queued_steering" : "queued_user_decision",
|
||||||
|
Content = item.Content,
|
||||||
|
Timestamp = item.CreatedAt,
|
||||||
|
});
|
||||||
|
EmitEvent(AgentEventType.UserMessage, "", item.Content);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
messages.Add(new ChatMessage
|
messages.Add(new ChatMessage
|
||||||
{
|
{
|
||||||
@@ -209,6 +283,8 @@ public partial class AgentLoopService
|
|||||||
{
|
{
|
||||||
// 이미 릴리즈된 상태 — 무시
|
// 이미 릴리즈된 상태 — 무시
|
||||||
}
|
}
|
||||||
|
if (IsRunning)
|
||||||
|
_pendingCommands.EnqueueResume("Execution resumed after pause. Re-evaluate the latest queued context before proceeding.");
|
||||||
EmitEvent(AgentEventType.Resumed, "", "에이전트가 재개되었습니다");
|
EmitEvent(AgentEventType.Resumed, "", "에이전트가 재개되었습니다");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
55
src/AxCopilot/Services/Agent/DeckRepairGuideService.cs
Normal file
55
src/AxCopilot/Services/Agent/DeckRepairGuideService.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
namespace AxCopilot.Services.Agent;
|
||||||
|
|
||||||
|
public static class DeckRepairGuideService
|
||||||
|
{
|
||||||
|
public static string BuildGuide(DeckQualityReport review)
|
||||||
|
{
|
||||||
|
if (review.Issues.Count == 0)
|
||||||
|
return "Deck repair guide: none";
|
||||||
|
|
||||||
|
var actions = new List<string>();
|
||||||
|
foreach (var issue in review.Issues)
|
||||||
|
{
|
||||||
|
var action = issue.Message switch
|
||||||
|
{
|
||||||
|
var message when message.Contains("Executive Summary", StringComparison.OrdinalIgnoreCase)
|
||||||
|
=> "Add or strengthen the Executive Summary with 2-3 evidence-backed takeaways",
|
||||||
|
var message when message.Contains("Recommendation", StringComparison.OrdinalIgnoreCase)
|
||||||
|
=> "Add a clear recommendation or decision request slide near the end of the deck",
|
||||||
|
var message when message.Contains("roadmap", StringComparison.OrdinalIgnoreCase)
|
||||||
|
=> "Add a roadmap slide with phases, owners, and timing",
|
||||||
|
var message when message.Contains("headline is too long", StringComparison.OrdinalIgnoreCase)
|
||||||
|
=> "Tighten slide headlines to one clear message sentence",
|
||||||
|
var message when message.Contains("content density is high", StringComparison.OrdinalIgnoreCase)
|
||||||
|
=> "Reduce text density and convert bullets into cards, visuals, or sharper evidence points",
|
||||||
|
var message when message.Contains("comparison slide", StringComparison.OrdinalIgnoreCase)
|
||||||
|
=> "Expand the comparison slide to show at least two real options and a verdict",
|
||||||
|
var message when message.Contains("chart slide", StringComparison.OrdinalIgnoreCase)
|
||||||
|
=> "Provide chart labels and values or replace the slide with a comparison/evidence layout",
|
||||||
|
var message when message.Contains("table slide", StringComparison.OrdinalIgnoreCase)
|
||||||
|
=> "Provide complete table headers and rows or simplify the slide to key callouts",
|
||||||
|
var message when message.Contains("text-heavy", StringComparison.OrdinalIgnoreCase)
|
||||||
|
=> "Convert text-heavy slides into message-led visuals with fewer bullets",
|
||||||
|
var message when message.Contains("Evidence slides", StringComparison.OrdinalIgnoreCase)
|
||||||
|
=> "Add evidence slides such as charts, tables, appendix evidence, or structured comparisons",
|
||||||
|
var message when message.Contains("placeholder", StringComparison.OrdinalIgnoreCase)
|
||||||
|
=> "Replace placeholder text before export and verify each slide has final copy",
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(action) &&
|
||||||
|
!actions.Contains(action, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
actions.Add(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actions.Count >= 3)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actions.Count == 0)
|
||||||
|
return "Deck repair guide: review slide alerts and reinforce storyline, evidence, and decision ask";
|
||||||
|
|
||||||
|
return "Deck repair guide: " + string.Join(" | ", actions);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1029,7 +1029,10 @@ public class PptxSkill : IAgentTool
|
|||||||
if (!string.IsNullOrWhiteSpace(templatePackName))
|
if (!string.IsNullOrWhiteSpace(templatePackName))
|
||||||
outputParts.Add($"Template pack: {templatePackName}");
|
outputParts.Add($"Template pack: {templatePackName}");
|
||||||
if (deckReview != null)
|
if (deckReview != null)
|
||||||
|
{
|
||||||
outputParts.Add(deckReview.ToToolSummary());
|
outputParts.Add(deckReview.ToToolSummary());
|
||||||
|
outputParts.Add(DeckRepairGuideService.BuildGuide(deckReview));
|
||||||
|
}
|
||||||
return ToolResult.Ok(string.Join("\n", outputParts), fullPath);
|
return ToolResult.Ok(string.Join("\n", outputParts), fullPath);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -84,6 +84,15 @@ internal static class WorkspaceContextGenerator
|
|||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var languageSnapshot = BuildLanguageSnapshot(extDist);
|
||||||
|
if (languageSnapshot.Count > 0)
|
||||||
|
{
|
||||||
|
sb.AppendLine("## Language Snapshot");
|
||||||
|
foreach (var line in languageSnapshot)
|
||||||
|
sb.AppendLine($"- {line}");
|
||||||
|
sb.AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
// 4. 기존 컨텍스트 파일 감지
|
// 4. 기존 컨텍스트 파일 감지
|
||||||
var contextFiles = DetectContextFiles(workFolder);
|
var contextFiles = DetectContextFiles(workFolder);
|
||||||
if (contextFiles.Count > 0)
|
if (contextFiles.Count > 0)
|
||||||
@@ -95,6 +104,24 @@ internal static class WorkspaceContextGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5. README 요약
|
// 5. README 요약
|
||||||
|
var agentContextSummary = DetectAgentContextSummary(workFolder);
|
||||||
|
if (agentContextSummary.Count > 0)
|
||||||
|
{
|
||||||
|
sb.AppendLine("## Agent Context");
|
||||||
|
foreach (var line in agentContextSummary)
|
||||||
|
sb.AppendLine($"- {line}");
|
||||||
|
sb.AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyManifests = DetectKeyManifests(workFolder);
|
||||||
|
if (keyManifests.Count > 0)
|
||||||
|
{
|
||||||
|
sb.AppendLine("## Key Manifests");
|
||||||
|
foreach (var line in keyManifests)
|
||||||
|
sb.AppendLine($"- {line}");
|
||||||
|
sb.AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
var readmeSummary = ExtractReadmeSummary(workFolder);
|
var readmeSummary = ExtractReadmeSummary(workFolder);
|
||||||
if (readmeSummary != null)
|
if (readmeSummary != null)
|
||||||
{
|
{
|
||||||
@@ -328,6 +355,91 @@ internal static class WorkspaceContextGenerator
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<string> DetectAgentContextSummary(string folder)
|
||||||
|
{
|
||||||
|
var lines = new List<string>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var claudeSkillsDir = Path.Combine(folder, ".claude", "skills");
|
||||||
|
if (Directory.Exists(claudeSkillsDir))
|
||||||
|
{
|
||||||
|
var skillFiles = Directory.GetFiles(claudeSkillsDir, "SKILL.md", SearchOption.AllDirectories);
|
||||||
|
if (skillFiles.Length > 0)
|
||||||
|
lines.Add($".claude/skills 호환 스킬 {skillFiles.Length}개 감지");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var axRulesDir = Path.Combine(folder, ".ax", "rules");
|
||||||
|
if (Directory.Exists(axRulesDir))
|
||||||
|
{
|
||||||
|
var ruleFiles = Directory.GetFiles(axRulesDir, "*.md", SearchOption.TopDirectoryOnly);
|
||||||
|
if (ruleFiles.Length > 0)
|
||||||
|
lines.Add($".ax/rules 규칙 {ruleFiles.Length}개 감지");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var memoryFile = Path.Combine(folder, "AXMEMORY.md");
|
||||||
|
if (File.Exists(memoryFile))
|
||||||
|
lines.Add("AXMEMORY.md 메모리 파일 감지");
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> DetectKeyManifests(string folder)
|
||||||
|
{
|
||||||
|
var manifests = new List<string>();
|
||||||
|
var patterns = new (string Pattern, string Label)[]
|
||||||
|
{
|
||||||
|
("*.sln", "Solution"),
|
||||||
|
("*.csproj", ".NET project"),
|
||||||
|
("package.json", "Node package"),
|
||||||
|
("pyproject.toml", "Python project"),
|
||||||
|
("requirements.txt", "Python requirements"),
|
||||||
|
("Cargo.toml", "Rust package"),
|
||||||
|
("go.mod", "Go module"),
|
||||||
|
("pom.xml", "Maven project"),
|
||||||
|
("build.gradle", "Gradle build"),
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var (pattern, label) in patterns)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var matches = Directory.GetFiles(folder, pattern, SearchOption.TopDirectoryOnly)
|
||||||
|
.Select(Path.GetFileName)
|
||||||
|
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||||
|
.Cast<string>()
|
||||||
|
.Take(3)
|
||||||
|
.ToList();
|
||||||
|
if (matches.Count > 0)
|
||||||
|
manifests.Add($"{label}: {string.Join(", ", matches)}");
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
return manifests;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> BuildLanguageSnapshot(List<KeyValuePair<string, int>> extDist)
|
||||||
|
=> extDist
|
||||||
|
.Where(kv => kv.Value > 0)
|
||||||
|
.Select(kv => new { Language = GetLanguageName(kv.Key), kv.Value })
|
||||||
|
.GroupBy(x => x.Language, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(group => new { Language = group.Key, Count = group.Sum(item => item.Value) })
|
||||||
|
.OrderByDescending(x => x.Count)
|
||||||
|
.Take(6)
|
||||||
|
.Select(x => $"{x.Language}: {x.Count} file(s)")
|
||||||
|
.ToList();
|
||||||
|
|
||||||
private static async Task<(string? Branch, string? Remote)> GetGitInfoAsync(
|
private static async Task<(string? Branch, string? Remote)> GetGitInfoAsync(
|
||||||
string folder, CancellationToken ct)
|
string folder, CancellationToken ct)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -119,7 +119,8 @@ public static class CodeLanguageCatalog
|
|||||||
[
|
[
|
||||||
"Preserve package boundaries, error-first flow, and gofmt-style formatting.",
|
"Preserve package boundaries, error-first flow, and gofmt-style formatting.",
|
||||||
"Check interfaces, exported identifiers, and concurrency-sensitive changes together."
|
"Check interfaces, exported identifiers, and concurrency-sensitive changes together."
|
||||||
]),
|
],
|
||||||
|
LspLanguageId: "go"),
|
||||||
new(
|
new(
|
||||||
"rust",
|
"rust",
|
||||||
"Rust",
|
"Rust",
|
||||||
@@ -127,7 +128,8 @@ public static class CodeLanguageCatalog
|
|||||||
[
|
[
|
||||||
"Respect Cargo workspace structure, ownership/borrowing rules, and crate boundaries.",
|
"Respect Cargo workspace structure, ownership/borrowing rules, and crate boundaries.",
|
||||||
"Prefer explicit enums/results and verify compiler diagnostics after edits."
|
"Prefer explicit enums/results and verify compiler diagnostics after edits."
|
||||||
]),
|
],
|
||||||
|
LspLanguageId: "rust"),
|
||||||
new(
|
new(
|
||||||
"php",
|
"php",
|
||||||
"PHP",
|
"PHP",
|
||||||
@@ -135,7 +137,8 @@ public static class CodeLanguageCatalog
|
|||||||
[
|
[
|
||||||
"Follow the framework and autoloading structure already present in the project.",
|
"Follow the framework and autoloading structure already present in the project.",
|
||||||
"Be careful with runtime includes, container wiring, and mixed template/application files."
|
"Be careful with runtime includes, container wiring, and mixed template/application files."
|
||||||
]),
|
],
|
||||||
|
LspLanguageId: "php"),
|
||||||
new(
|
new(
|
||||||
"ruby",
|
"ruby",
|
||||||
"Ruby",
|
"Ruby",
|
||||||
@@ -143,7 +146,8 @@ public static class CodeLanguageCatalog
|
|||||||
[
|
[
|
||||||
"Preserve gem structure, Rails or plain Ruby conventions already used in the repository.",
|
"Preserve gem structure, Rails or plain Ruby conventions already used in the repository.",
|
||||||
"Check dynamic dispatch, concerns/modules, and tests together after edits."
|
"Check dynamic dispatch, concerns/modules, and tests together after edits."
|
||||||
]),
|
],
|
||||||
|
LspLanguageId: "ruby"),
|
||||||
new(
|
new(
|
||||||
"kotlin",
|
"kotlin",
|
||||||
"Kotlin",
|
"Kotlin",
|
||||||
@@ -151,7 +155,8 @@ public static class CodeLanguageCatalog
|
|||||||
[
|
[
|
||||||
"Preserve Gradle structure, package layout, and nullability intent.",
|
"Preserve Gradle structure, package layout, and nullability intent.",
|
||||||
"Be careful with JVM interop boundaries and Android-specific module structure when present."
|
"Be careful with JVM interop boundaries and Android-specific module structure when present."
|
||||||
]),
|
],
|
||||||
|
LspLanguageId: "kotlin"),
|
||||||
new(
|
new(
|
||||||
"swift",
|
"swift",
|
||||||
"Swift",
|
"Swift",
|
||||||
@@ -159,7 +164,8 @@ public static class CodeLanguageCatalog
|
|||||||
[
|
[
|
||||||
"Preserve target structure, Apple framework imports, and protocol-oriented design already in use.",
|
"Preserve target structure, Apple framework imports, and protocol-oriented design already in use.",
|
||||||
"Check app lifecycle and platform-specific behavior after edits."
|
"Check app lifecycle and platform-specific behavior after edits."
|
||||||
]),
|
],
|
||||||
|
LspLanguageId: "swift"),
|
||||||
new(
|
new(
|
||||||
"scala",
|
"scala",
|
||||||
"Scala",
|
"Scala",
|
||||||
@@ -255,6 +261,9 @@ public static class CodeLanguageCatalog
|
|||||||
public static string GetQuickSelectLabel(string? key)
|
public static string GetQuickSelectLabel(string? key)
|
||||||
=> FindByKey(key)?.DisplayName ?? key ?? "Auto";
|
=> FindByKey(key)?.DisplayName ?? key ?? "Auto";
|
||||||
|
|
||||||
|
public static string BuildQuickSelectSupportDescription()
|
||||||
|
=> string.Join(", ", QuickSelectLanguages.Select(x => x.DisplayName));
|
||||||
|
|
||||||
public static string BuildSelectedLanguagePrompt(string? key)
|
public static string BuildSelectedLanguagePrompt(string? key)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(key) || string.Equals(key, "auto", StringComparison.OrdinalIgnoreCase))
|
if (string.IsNullOrWhiteSpace(key) || string.Equals(key, "auto", StringComparison.OrdinalIgnoreCase))
|
||||||
@@ -292,6 +301,9 @@ public static class CodeLanguageCatalog
|
|||||||
public static string BuildStaticSupportDescription()
|
public static string BuildStaticSupportDescription()
|
||||||
=> string.Join(", ", s_all.Select(x => x.DisplayName));
|
=> string.Join(", ", s_all.Select(x => x.DisplayName));
|
||||||
|
|
||||||
|
public static string BuildSupportSummaryDescription()
|
||||||
|
=> $"빠른 선택: {BuildQuickSelectSupportDescription()} | 내장 분석: {BuildStaticSupportDescription()} | LSP 심화 분석: {BuildLspSupportDescription()}";
|
||||||
|
|
||||||
public static string BuildCodeTabSupportDescription()
|
public static string BuildCodeTabSupportDescription()
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ namespace AxCopilot.Services;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Language Server Protocol 클라이언트.
|
/// Language Server Protocol 클라이언트.
|
||||||
/// 외부 언어 서버 프로세스와 JSON-RPC 2.0으로 통신합니다.
|
/// 외부 언어 서버 프로세스와 JSON-RPC 2.0으로 통신합니다.
|
||||||
/// 지원: OmniSharp (C#), typescript-language-server, pyright, clangd
|
/// 지원: OmniSharp (C#), typescript-language-server, pyright/pylsp, clangd, jdtls,
|
||||||
|
/// gopls, rust-analyzer, intelephense, solargraph, kotlin-language-server, sourcekit-lsp
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LspClientService : IDisposable
|
public class LspClientService : IDisposable
|
||||||
{
|
{
|
||||||
@@ -637,6 +638,18 @@ public class LspClientService : IDisposable
|
|||||||
FindCommand("C/C++", new[] { "clangd" }, Array.Empty<string>()),
|
FindCommand("C/C++", new[] { "clangd" }, Array.Empty<string>()),
|
||||||
"java" =>
|
"java" =>
|
||||||
FindCommand("Java", new[] { "jdtls" }, Array.Empty<string>()),
|
FindCommand("Java", new[] { "jdtls" }, Array.Empty<string>()),
|
||||||
|
"go" =>
|
||||||
|
FindCommand("Go", new[] { "gopls" }, Array.Empty<string>()),
|
||||||
|
"rust" =>
|
||||||
|
FindCommand("Rust", new[] { "rust-analyzer" }, Array.Empty<string>()),
|
||||||
|
"php" =>
|
||||||
|
FindCommand("PHP", new[] { "intelephense" }, new[] { "--stdio" }),
|
||||||
|
"ruby" =>
|
||||||
|
FindCommand("Ruby", new[] { "solargraph" }, new[] { "stdio" }),
|
||||||
|
"kotlin" =>
|
||||||
|
FindCommand("Kotlin", new[] { "kotlin-language-server" }, Array.Empty<string>()),
|
||||||
|
"swift" =>
|
||||||
|
FindCommand("Swift", new[] { "sourcekit-lsp" }, Array.Empty<string>()),
|
||||||
_ => (null, Array.Empty<string>())
|
_ => (null, Array.Empty<string>())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -138,9 +138,10 @@ public class SettingsViewModel : INotifyPropertyChanged
|
|||||||
|
|
||||||
/// <summary>CodeSettings 바인딩용 프로퍼티. XAML에서 {Binding Code.EnableLsp} 등으로 접근.</summary>
|
/// <summary>CodeSettings 바인딩용 프로퍼티. XAML에서 {Binding Code.EnableLsp} 등으로 접근.</summary>
|
||||||
public Models.CodeSettings Code => _service.Settings.Llm.Code;
|
public Models.CodeSettings Code => _service.Settings.Llm.Code;
|
||||||
|
public string CodeQuickSelectLanguagesText => CodeLanguageCatalog.BuildQuickSelectSupportDescription();
|
||||||
public string CodeLspSupportedLanguagesText => CodeLanguageCatalog.BuildLspSupportDescription();
|
public string CodeLspSupportedLanguagesText => CodeLanguageCatalog.BuildLspSupportDescription();
|
||||||
public string CodeStaticSupportedLanguagesText => CodeLanguageCatalog.BuildStaticSupportDescription();
|
public string CodeStaticSupportedLanguagesText => CodeLanguageCatalog.BuildStaticSupportDescription();
|
||||||
public string CodeTabSupportSummaryText => CodeLanguageCatalog.BuildCodeTabSupportDescription();
|
public string CodeTabSupportSummaryText => CodeLanguageCatalog.BuildSupportSummaryDescription();
|
||||||
|
|
||||||
// ─── 작업 복사본 ───────────────────────────────────────────────────────
|
// ─── 작업 복사본 ───────────────────────────────────────────────────────
|
||||||
private string _hotkey;
|
private string _hotkey;
|
||||||
|
|||||||
@@ -5448,7 +5448,7 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
<StackPanel HorizontalAlignment="Left" Margin="0,0,60,0">
|
<StackPanel HorizontalAlignment="Left" Margin="0,0,60,0">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Style="{StaticResource RowLabel}" Text="LSP 코드 분석"/>
|
<TextBlock Style="{StaticResource RowLabel}" Text="LSP 코드 분석"/>
|
||||||
<Border Width="16" Height="16" CornerRadius="8" Background="{DynamicResource ItemHoverBackground}" Margin="6,0,0,0" Cursor="Help" VerticalAlignment="Center">
|
<Border Width="16" Height="16" CornerRadius="8" Background="{DynamicResource ItemHoverBackground}" Margin="6,0,0,0" Cursor="Help" VerticalAlignment="Center">
|
||||||
<TextBlock Text="?" FontSize="10" FontWeight="Bold" Foreground="{DynamicResource AccentColor}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
<TextBlock Text="?" FontSize="10" FontWeight="Bold" Foreground="{DynamicResource AccentColor}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
<Border.ToolTip>
|
<Border.ToolTip>
|
||||||
@@ -5466,6 +5466,7 @@
|
|||||||
</Border>
|
</Border>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock Style="{StaticResource RowHint}" Text="언어 서버로 정의 이동, 참조 검색 등 코드 분석을 지원합니다"/>
|
<TextBlock Style="{StaticResource RowHint}" Text="언어 서버로 정의 이동, 참조 검색 등 코드 분석을 지원합니다"/>
|
||||||
|
<TextBlock Style="{StaticResource RowHint}" Margin="0,4,0,0" Text="{Binding CodeQuickSelectLanguagesText, StringFormat=빠른 선택 언어: {0}}"/>
|
||||||
<TextBlock Style="{StaticResource RowHint}" Margin="0,4,0,0" Text="{Binding CodeLspSupportedLanguagesText, StringFormat=지원 언어(LSP): {0}}"/>
|
<TextBlock Style="{StaticResource RowHint}" Margin="0,4,0,0" Text="{Binding CodeLspSupportedLanguagesText, StringFormat=지원 언어(LSP): {0}}"/>
|
||||||
<TextBlock Style="{StaticResource RowHint}" Margin="0,2,0,0" Text="{Binding CodeStaticSupportedLanguagesText, StringFormat=코드 탭 기본 지원: {0}}"/>
|
<TextBlock Style="{StaticResource RowHint}" Margin="0,2,0,0" Text="{Binding CodeStaticSupportedLanguagesText, StringFormat=코드 탭 기본 지원: {0}}"/>
|
||||||
<TextBlock Style="{StaticResource RowHint}" Margin="0,2,0,0" Text="격리 환경에서는 내장 분석과 로컬에 이미 설치된 언어 서버만 활용합니다"/>
|
<TextBlock Style="{StaticResource RowHint}" Margin="0,2,0,0" Text="격리 환경에서는 내장 분석과 로컬에 이미 설치된 언어 서버만 활용합니다"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user