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

@@ -38,6 +38,16 @@
- `dotnet test --filter "Suite=ReplayStability"`: 14/14 통과.
- `dotnet test`: 379/379 통과.
## 7. 명령/도구 보강 스냅샷 (2026-04-04)
- 슬래시 명령 고도화: `/chrome`, `/mcp`, `/verify`, `/commit`, `/settings`, `/permissions` 하위 동작 정리.
- `/mcp` 상태 라벨 표준화: `Connected`, `NeedsAuth`, `Configured`, `Disconnected`, `Disabled`.
- `/chrome` 런타임 재시도: 초기 probe 실패 시 `/mcp reconnect all` 자동 수행 후 1회 재평가.
- Git 정책 정렬: `git_tool``commit` 비활성 문구 제거(로컬 커밋 경로와 정책 일치).
- `/commit` 부분 커밋 지원: `files:path1,path2 :: 메시지` 형식으로 선택 파일만 stage+commit 가능.
- 테스트 보강:
- `ChatWindowSlashPolicyTests`: 슬래시 파서/검증 프롬프트/MCP 상태 라벨 단위 검증 추가.
- `AgentParityToolsTests`: `git_tool commit` 레거시 비활성 메시지 회귀 방지 테스트 추가.
## 7. 권한 Hook 계약 (P2 마감 기준)
- lifecycle hook 키:
- `__permission_request__` (pre)

View File

@@ -2690,3 +2690,36 @@ else:
| 현재 (v1.6.1) | 스킬 프롬프트에서 양식 자동 감지 안내 | 완료 |
| 다음 | 시스템 프롬프트에 양식 목록 자동 주입 (BuildCoworkSystemPrompt) | 낮음 |
| 장기 | `.ax/templates/` 공용 양식 폴더 + 프로젝트 규칙에서 기본 양식 지정 | 중간 |
---
## 2026-04-04 진행 기록 (AX Agent 명령/도구 보강)
### 1. 슬래시 명령 체계 보강
- `/chrome`: 인자 미입력 시 MCP 런타임 진단, 인자 입력 시 브라우저 작업 실행 경로로 라우팅.
- `/mcp`: `status`, `enable|disable`, `reconnect` 동작 정리 및 상태 라벨 표준화.
- `/settings`: `model|permissions|mcp|theme` 하위 액션 지원.
- `/permissions`: `ask|auto|deny|status` 하위 액션 지원.
- `/verify`: Cowork/Code 탭 전용 검증 프롬프트 경로로 고정.
- `/commit`: 승인 기반 커밋 실행 + `files:path1,path2 :: message` 부분 커밋 지원.
- `/compact`: 수동 컨텍스트 압축 명령 유지 및 slash 팝업 힌트/도움말 반영.
### 2. 도구/권한 정책 정렬
- `GitTool`의 commit 경로에서 레거시 비활성 응답(`커밋 비활성`) 제거.
- 세션 단위 MCP 활성/비활성 오버라이드 적용(영구 설정 미오염).
- `/chrome` 진단 실패 시 `/mcp reconnect all` 자동 1회 재시도 후 상태 재평가.
### 3. 테스트 보강
- `ChatWindowSlashPolicyTests`:
- 슬래시 파서(`ParseGenericAction`, `ParseMcpAction`) 검증.
- `/verify` 시스템 프롬프트 필수 섹션 검증.
- MCP 상태 라벨 매핑 검증.
- `/commit` 입력 파서 검증.
- `AgentParityToolsTests`:
- `git_tool commit` 레거시 비활성 메시지 회귀 방지 테스트 추가.
### 4. 품질 게이트 결과
- `dotnet build AxCopilot.sln` 통과 (경고 0, 오류 0).
- `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj` 통과.
- 기준 시점 전체 테스트: 403 passed, 0 failed.

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