AX Agent 슬래시 명령/도구 정책 정렬 및 개발문서 진행 이력 반영
Some checks failed
Release Gate / gate (push) Has been cancelled

- /chrome: 인자 없는 진단 모드와 실행 라우팅 분리, MCP 재연결 자동 재시도 경로 보강

- /mcp: status/enable/disable/reconnect 명령 정리 및 상태 라벨 표준화

- /settings, /permissions 하위 액션 명확화, /verify·/commit 로컬 실행 흐름 정리

- /commit files:path1,path2 :: message 형태의 부분 커밋 지원 추가

- GitTool commit 경로의 레거시 비활성 응답 제거로 정책 일관성 확보

- ChatWindowSlashPolicyTests 신규 추가 및 AgentParityToolsTests 회귀 방지 테스트 보강

- docs/DEVELOPMENT.md, docs/AGENT_ROADMAP.md에 2026-04-04 진행 기록/스냅샷 반영
This commit is contained in:
2026-04-04 01:06:46 +09:00
parent 9e37aad163
commit 1256fdc43f
6 changed files with 2054 additions and 134 deletions

View File

@@ -200,4 +200,34 @@ public class AgentParityToolsTests
foreach (var name in required)
names.Should().Contain(name);
}
[Fact]
public async Task GitTool_Commit_ShouldNotReturnLegacyDisabledMessage()
{
var workDir = Path.Combine(Path.GetTempPath(), "ax-git-commit-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(workDir);
Directory.CreateDirectory(Path.Combine(workDir, ".git"));
try
{
var context = new AgentContext
{
WorkFolder = workDir,
Permission = "Auto",
OperationMode = "external",
};
var tool = new GitTool();
var result = await tool.ExecuteAsync(
JsonDocument.Parse("""{"action":"commit","args":" "}""").RootElement,
context,
CancellationToken.None);
result.Output.Should().NotContain("비활성 상태");
result.Output.Should().NotContain("향후 버전에서 활성화");
}
finally
{
try { if (Directory.Exists(workDir)) Directory.Delete(workDir, true); } catch { }
}
}
}

View File

@@ -0,0 +1,77 @@
using AxCopilot.Views;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Views;
public class ChatWindowSlashPolicyTests
{
[Fact]
public void BuildVerifySystemPrompt_ShouldContainStructuredSections()
{
var prompt = ChatWindow.BuildVerifySystemPrompt("/verify");
prompt.Should().Contain("[검증결과]");
prompt.Should().Contain("[실행요약]");
prompt.Should().Contain("[변경파일]");
prompt.Should().Contain("[잔여리스크]");
}
[Theory]
[InlineData("/mcp", "status", "")]
[InlineData("enable all", "enable", "all")]
[InlineData("reconnect chrome", "reconnect", "chrome")]
[InlineData("status", "status", "")]
public void ParseMcpAction_ShouldParseExpected(string displayText, string expectedAction, string expectedTarget)
{
var (action, target) = ChatWindow.ParseMcpAction(displayText);
action.Should().Be(expectedAction);
target.Should().Be(expectedTarget);
}
[Theory]
[InlineData("/settings", "open", "")]
[InlineData("model", "model", "")]
[InlineData("ask", "ask", "")]
[InlineData("reconnect all", "reconnect", "all")]
public void ParseGenericAction_ShouldParseExpected(string displayText, string expectedAction, string expectedArgument)
{
var (action, argument) = ChatWindow.ParseGenericAction(displayText, "/settings");
action.Should().Be(expectedAction);
argument.Should().Be(expectedArgument);
}
[Theory]
[InlineData(false, "stdio", true, false, null, "Disabled")]
[InlineData(true, "stdio", false, false, null, "Enabled")]
[InlineData(true, "sse", true, false, null, "Configured")]
[InlineData(true, "stdio", true, false, null, "Disconnected")]
[InlineData(true, "stdio", true, true, 0, "NeedsAuth (도구 0개)")]
[InlineData(true, "stdio", true, true, 3, "Connected (도구 3개)")]
public void ResolveMcpDisplayStatus_ShouldReturnNormalizedLabel(
bool enabled,
string transport,
bool runtimeCheck,
bool connected,
int? toolCount,
string expected)
{
var label = ChatWindow.ResolveMcpDisplayStatus(enabled, transport, runtimeCheck, connected, toolCount);
label.Should().Be(expected);
}
[Theory]
[InlineData("/commit", 0, "")]
[InlineData("feat: 로그인 오류 수정", 0, "feat: 로그인 오류 수정")]
[InlineData("files:src/A.cs, src/B.cs :: feat: 부분 커밋", 2, "feat: 부분 커밋")]
[InlineData("files:src/A.cs,src/A.cs", 1, "")]
public void ParseCommitCommandInput_ShouldParseExpected(string input, int expectedFileCount, string expectedMessage)
{
var (files, message) = ChatWindow.ParseCommitCommandInput(input);
files.Count.Should().Be(expectedFileCount);
message.Should().Be(expectedMessage);
}
}

View File

@@ -8,7 +8,7 @@ namespace AxCopilot.Services.Agent;
/// <summary>
/// Git 버전 관리 도구.
/// 사내 GitHub Enterprise 환경을 고려하여 안전한 Git 작업을 지원합니다.
/// push/force push는 차단되며, 사용자가 직접 수행해야 합니다.
/// push/force push는 차단되며, 사용자가 직접 수행해야 합니다.
/// </summary>
public class GitTool : IAgentTool
{
@@ -126,16 +126,6 @@ public class GitTool : IAgentTool
return ToolResult.Fail("Git 쓰기 권한이 거부되었습니다.");
}
// Git 커밋 — 현재 비활성 (향후 활성화 예정)
// 의사결정 수준에서 무조건 확인을 받더라도, 커밋 자체를 차단합니다.
if (action == "commit")
{
return ToolResult.Fail(
"Git 커밋 기능은 현재 비활성 상태입니다.\n" +
"안전을 위해 커밋은 사용자가 직접 수행하세요.\n" +
"향후 버전에서 활성화될 예정입니다.");
}
// 명령 실행
try
{

File diff suppressed because it is too large Load Diff