Compare commits

..
Author SHA1 Message Date
lacvet 998f0c9fd5 코드 탭 컨텍스트 격차를 해소하고 대화 영속 작업 세트를 도입함
- ChatConversation에 CodeWorkingSetSnapshot/진단/시맨틱 요약 상태를 추가하고 AgentLoop가 실행 중 갱신한 작업 세트를 대화에 다시 저장하도록 연결함
- CodeTaskWorkingSetService를 스냅샷 복원/시맨틱 연속성 요약/활성 진단 보호 구조로 확장하고 query assembly에서 working set·semantic summary·workspace bootstrap을 protected evidence로 주입하도록 보강함
- ContextCondenser가 compact 중 MsgId, preview, 토큰 메타데이터를 유지하도록 수정하고 신규 compact marker와 요약 문자열을 영어 안정형으로 정리함
- ChatSessionStateService의 분기 대화가 MsgId와 CodeWorkingSet을 유지하도록 보강하고 관련 회귀 테스트(ChatStorage/ContextCondenser/PreLlmStage/QueryAssembly/WorkingSet)를 추가 및 갱신함
- 검증: dotnet build 경고 0 오류 0, CodeTaskWorkingSetServiceTests|AgentLoopQueryAssemblyServiceTests|AgentQueryContextBuilderTests|ContextCondenserTests|AxAgentExecutionEngineTests|AgentLoopLlmDispatchStageServiceTests|ChatStorageServiceTests 26개 통과, AgentLoopE2ETests 포함 관련 컨텍스트 회귀 56개 통과
2026-04-16 09:01:00 +09:00
lacvet d5dbaa6e4a 코드탭 통계 대시보드 병합 및 빈화면 동기화 보강
외부 작업 로그 기준으로 코드탭 병합 누락분을 검토하고 기존 컨텍스트 영속화 경로는 유지한 채 Code 사용량 대시보드만 선택적으로 병합했습니다.

CodeStatsSummary, CodeStatsAggregator, ChatWindow.CodeStatsPresentation, CodeStatsAggregatorTests를 추가해 세션·메시지·토큰·연속일·모델 사용량 통계를 집계하고 EmptyState에서 개요/모델 히스토리 대시보드를 렌더링하도록 구현했습니다.

ChatWindow.xaml, TranscriptRendering, TopicPresetPresentation, ConversationManagementPresentation, OverlaySettingsPresentation, xaml.cs에 UpdateCodeStatsVisibility 연결을 추가해 탭 전환, 첫 메시지 전송, 프리셋 선택, 대화 삭제 시 빈화면과 대시보드가 일관되게 전환되도록 수정했습니다.

README.md와 docs/DEVELOPMENT.md에 2026-04-16 08:10 (KST) 기준 병합 이력과 검증 결과를 반영했습니다.

검증: verify_code_stats_merge 빌드 경고 0 / 오류 0, verify_code_stats_merge_tests 대상 테스트 56개 통과
2026-04-16 08:12:20 +09:00
lacvet e07b6dbed0 코드 탭 컨텍스트 영속화와 Auto budget 복구 적용
- AxAgentExecutionEngine에서 시스템 프롬프트 중복을 제거하고 structured tool_use/tool_result 전사본을 conversation.Messages로 동기화해 다음 턴과 저장 이력에서도 코드 작업 컨텍스트가 유지되도록 수정
- AgentQueryContextBuilder와 ContextCondenser에 post-compact tool snippet 복원, recent window 확대, tool result 보존 강화 로직을 추가해 장기 코드 실행 중 빌드/파일 근거 손실을 줄임
- MaxContextTokens=0 Auto 모드를 AppSettings, SettingsService 마이그레이션, 설정 UI, 오버레이 UI, 컨텍스트 사용량 표시, LLM 요청 본문에 연결하고 Auto 모드에서는 provider output cap 강제 주입을 제거
- 관련 회귀 테스트와 문서 README/DEVELOPMENT/CODE_CONTEXT_RELIABILITY_PLAN을 갱신하고 깨진 진단 문자열 기대값을 영어 기준으로 정리

검증:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_context_reliability_followup\\ -p:IntermediateOutputPath=obj\\verify_context_reliability_followup\\
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AxAgentExecutionEngineTests|AgentQueryContextBuilderTests|ContextCondenserTests|SettingsServiceTests|AgentLoopDiagnosticsFormatterTests" -p:OutputPath=bin\\verify_context_reliability_followup_tests\\ -p:IntermediateOutputPath=obj\\verify_context_reliability_followup_tests\\
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentLoopQueryAssemblyServiceTests|AgentLoopPreLlmStageServiceTests|AgentLoopLlmRequestPreparationServiceTests|AgentMessageInvariantHelperTests|CodeTaskWorkingSetServiceTests|AgentLoopE2ETests" -p:OutputPath=bin\\verify_context_reliability_followup_tests2\\ -p:IntermediateOutputPath=obj\\verify_context_reliability_followup_tests2\\
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_context_reliability_final\\ -p:IntermediateOutputPath=obj\\verify_context_reliability_final\\
2026-04-16 07:45:36 +09:00
lacvet c6e5abfa50 코드탭 LLM 디스패치 단계를 별도 서비스로 분리
AgentLoopLlmDispatchStageService를 추가해 query_context와 llm_request 로그, 스트리밍 미리보기, read-only prefetch 연결, recovery-capable tool dispatch를 한 단계로 분리했다.

AgentLoopService는 pre-LLM stage 이후 dispatch stage를 호출하는 오케스트레이터 형태로 정리했고 function-calling 미지원 fallback도 staged request를 재사용하도록 보정했다.

StreamingToolExecutionCoordinator와 AgentLoopPreLlmStageService의 깨진 문자열을 영어로 정리하고 AgentLoopLlmDispatchStageServiceTests를 추가했다.

검증: Release build 경고 0 오류 0, 관련 AgentLoop 회귀 테스트 43개 통과
2026-04-16 06:51:00 +09:00
lacvet 1ec529ed1c 코드탭 pre-LLM 단계 결정을 별도 서비스로 분리
- AgentLoopPreLlmStageService를 추가해 thinking summary, Gemini free-tier delay, user prompt submit hook, missing-tool guard, request assembly handoff를 한 단계로 정리함

- AgentLoopService는 pre-LLM stage 결과를 소비하는 형태로 단순화해 history/query assembly 다음 단계가 claw-code처럼 더 선명하게 보이도록 구조를 개선함

- AgentLoopPreLlmStageServiceTests를 추가하고 관련 구조 테스트 60개를 통과시켰으며 dotnet build 경고/오류 0으로 검증함
2026-04-16 02:18:05 +09:00
lacvet 2e1c7be8c3 코드탭 query/history 조립 구조를 단계형 서비스로 분리
- AgentLoopQueryAssemblyService를 추가해 session learning refresh, queued command/query window 준비, code working set supplemental context 부착을 단계형으로 정리함

- AgentLoopService는 orchestration 중심으로 단순화하고 claw-code의 staged query/history 흐름과 비슷하게 책임을 재배치함

- AgentLoopQueryAssemblyServiceTests를 추가하고 SessionLearningCollectorTests를 영어 기준으로 정리했으며 dotnet build 및 targeted dotnet test(56 통과, 경고/오류 0)로 검증함
2026-04-16 02:07:26 +09:00
lacvet f0f1f76f48 코드탭 tool trace 사전 정규화와 인코딩 정리 적용
- AgentMessageInvariantHelper에 전송 직전 structured tool trace 정규화 로직을 추가해 missing tool_result assistant와 orphan tool_result를 plain transcript로 평탄화함

- AgentLoopLlmRequestPreparationService에서 query view를 clone한 뒤 normalization을 적용하고 query_context 로그에 tool_trace_repair 메타를 남기도록 확장함

- SessionLearningCollector와 AgentLoopDiagnosticsFormatter의 깨진 문자열과 주석을 영어 기준으로 정리해 active Code 경로의 mojibake 노출을 줄임

- AgentMessageInvariantHelperTests, AgentLoopLlmRequestPreparationServiceTests를 보강하고 dotnet build 및 targeted dotnet test(34 통과, 경고/오류 0)로 검증함
2026-04-16 01:59:16 +09:00
lacvet 0f64bf3f84 Code 탭 컨텍스트 누적 신뢰성과 작업 연속성을 전면 보강한다
이번 커밋은 Code 탭 장기 실행에서 build/file 근거가 너무 빨리 축약되고, 이전 수정 맥락이 다음 LLM 요청에 안정적으로 누적되지 않던 문제를 해결하기 위한 전면 보강을 담는다.

핵심 수정사항:
- CodeTaskWorkingSetService를 추가해 최근 생성 디렉터리, 최근 읽기/쓰기 파일, 최신 build/test 진단, 다음 복구 초점을 구조화된 working set으로 유지하고 각 반복 요청에 보조 system context로 주입한다.
- AgentQueryContextBuilder와 AgentToolResultBudget에 code profile을 도입해 protected recent window와 tool_result budget을 확장하고 build_run, test_loop, file_read, multi_read, lsp_code_intel, git_tool 같은 고가치 evidence가 기본 탭보다 덜 잘리도록 조정한다.
- AgentLoopIterationPreparationService와 AgentLoopLlmRequestPreparationService를 확장해 query-context options와 supplemental messages를 함께 전달하고, AgentLoopService에서는 Code 탭에서 generic session learnings 대신 working set 중심으로 요청을 구성하도록 변경한다.
- ChatWindow.UtilityPresentation에서 workspace context 첫 부트스트랩을 강화해 .ax-context.md가 아직 없더라도 첫 요청 시점부터 background generation과 language workflow bootstrap hints가 반영되도록 수정한다.
- LlmService.ToolUse에서 historical tool trace sanitization 결과를 assistant flatten/orphan conversion 건수로 요약 로그에 남겨 tool-trace 불변식 문제를 추적 가능하게 만든다.
- 관련 테스트를 추가·갱신해 working set 누적, code profile budget, supplemental message 주입, query-context option 전달을 회귀 고정한다.

검증 결과:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_context_reliability_full\\ -p:IntermediateOutputPath=obj\\verify_context_reliability_full\\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentQueryContextBuilderTests|AgentToolResultBudgetTests|AgentLoopIterationPreparationServiceTests|AgentLoopLlmRequestPreparationServiceTests|CodeTaskWorkingSetServiceTests|AgentLoopCodeQualityTests" -p:OutputPath=bin\\verify_context_reliability_full_tests\\ -p:IntermediateOutputPath=obj\\verify_context_reliability_full_tests\\ : 통과 150
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentLoopE2ETests|AgentMessageInvariantHelperTests" -p:OutputPath=bin\\verify_context_reliability_e2e\\ -p:IntermediateOutputPath=obj\\verify_context_reliability_e2e\\ : 통과 21
2026-04-16 01:45:28 +09:00
lacvet eb884e9263 지침과 문서에 코드 컨텍스트 안정화 계획을 반영한다
- AGENTS.md에 코드 파일 주석 영문화와 인코딩 손상 문자열 정리 규칙을 추가한다.

- 최근 Code 탭 실행 로그를 재분석해 메시지 수 증가 대비 컨텍스트 충실도 저하 원인을 정리한다.

- Code working set, task-aware pruning, tool trace invariant, bootstrap observability를 포함한 장기 수정 계획 문서를 추가한다.

- README와 DEVELOPMENT 문서에 2026-04-16 01:28 KST 기준 분석 결과와 후속 계획을 기록한다.

- 검증: dotnet build src\\AxCopilot\\AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_context_plan_docs\\ -p:IntermediateOutputPath=obj\\verify_context_plan_docs\\ (경고 0 / 오류 0)
2026-04-16 01:20:14 +09:00
lacvet e2278eec24 AX Agent 진행 메시지 폭·정렬 및 인코딩 표시 문제 수정
- 앱 생성 진행/도구/완료 카드에 전용 최대폭을 도입하고 좌측 정렬로 통일
- 라이브 진행 카드와 검증 게이트 문구에서 깨져 보이던 문자열을 정상화
- build_run/process 도구가 Windows 기본 출력 인코딩을 우선 사용하도록 조정
- README와 DEVELOPMENT 문서에 2026-04-16 00:57 (KST) 기준 이력 반영

검증:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_agent_ui_layout_encoding\ -p:IntermediateOutputPath=obj\verify_agent_ui_layout_encoding\ (경고 0 / 오류 0)
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ChatWindowSlashPolicyTests|AgentLoopCodeQualityTests" -p:OutputPath=bin\verify_agent_ui_layout_encoding_tests\ -p:IntermediateOutputPath=obj\verify_agent_ui_layout_encoding_tests\ (통과 194)
2026-04-16 01:02:13 +09:00
lacvet db4ccd5df4 PPT 템플릿 품질 게이트와 manifest 추천 흐름을 고도화한다
- PptxSkill에 template master clone 진단 코드와 Template diagnostics 출력 라인을 추가해 color fallback 원인을 asset missing / clone failure로 구분한다.

- PptQualityGatePolicy와 templates.manifest.json, PptxTemplateManifestCatalog를 확장해 manifest 메타데이터 기반 추천과 원인별 재루프 프롬프트를 연결한다.

- PptQualityGatePolicyTests, PptxTemplateManifestCatalogTests, PptxSkillTemplatePackTests, PptxSkillTemplateDiagnosticsTests를 보강하고 README.md 및 docs/DEVELOPMENT.md 이력을 2026-04-16 00:15 (KST) 기준으로 갱신한다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_ppt_manifest_quality\\ -p:IntermediateOutputPath=obj\\verify_ppt_manifest_quality\\ / dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter PptQualityGatePolicyTests -p:OutputPath=bin\\verify_ppt_manifest_quality_tests\\ -p:IntermediateOutputPath=obj\\verify_ppt_manifest_quality_tests\\ 포함 15건 통과
2026-04-16 00:16:36 +09:00
lacvet 13061fa3ca 스크롤 맨아래 이동 버튼 위치와 입력바 연동 보정
AX Agent의 스크롤 맨아래 이동 FAB가 입력창 아래로 잘려 보이던 문제를 수정했습니다. ChatWindow.xaml에서 버튼을 Grid.RowSpan=2로 옮기고 기본 하단 여백을 높여 메시지 영역과 입력 바를 함께 기준으로 배치되도록 맞췄습니다.

ChatWindow.xaml.cs에는 UpdateScrollToBottomFabPosition()을 추가해 ComposerShell 높이, 입력창 크기 변화, 창 리사이즈 시 FAB 하단 margin을 자동 계산하도록 연결했습니다. 함께 Loaded 구간의 InputBox/InputBorder 이벤트 연결을 null-safe로 정리해 경고 없이 같은 UI 흐름을 유지하도록 보강했습니다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_scroll_to_bottom_fab\ -p:IntermediateOutputPath=obj\verify_scroll_to_bottom_fab\ (경고 0 / 오류 0), dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatWindowSlashPolicyTests -p:OutputPath=bin\verify_scroll_to_bottom_fab_tests\ -p:IntermediateOutputPath=obj\verify_scroll_to_bottom_fab_tests\ (통과 59)
2026-04-16 00:02:50 +09:00
lacvet 5161e46ac2 채팅 본문 폭과 진행 로그 줄바꿈 레이아웃 개선
채팅 본문과 process feed가 큰 창의 오른쪽 여백을 더 활용하도록 반응형 폭 계산을 조정했습니다. 본문 최대폭을 1040, 입력창 폭을 980 기준까지 확장하고 MessageList 최대폭을 함께 늘려 조기 말줄임이 덜 발생하도록 정리했습니다.

process feed 헤더, 실행 이력 요약, 라이브 thinking 줄은 줄바꿈 우선으로 바꾸고 필요한 미리보기 카드에만 ellipsis를 남겼습니다. 입력창 위 StreamMetricsLabel과 PulseDotBar 간격도 다시 맞춰 우측 시간·토큰 표시가 좌측 진행 문구 폭을 과하게 잠식하지 않도록 보정했습니다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_chat_width_wrap\ -p:IntermediateOutputPath=obj\verify_chat_width_wrap\ (경고 0 / 오류 0), dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatStreamingUiPolicyTests^|ChatWindowSlashPolicyTests -p:OutputPath=bin\verify_chat_width_wrap_tests\ -p:IntermediateOutputPath=obj\verify_chat_width_wrap_tests\ (통과 74)
2026-04-15 23:54:50 +09:00
lacvet 6810fb1954 ??? ???? ???? ??? ?? ???? ???? ??? ? ?????? ?? ?? ??
- WPF/MVVM, ASP.NET API, React/Vue/Next, Node, Python API, Spring, Android, Go, Rust CLI, generic solution ??? ProjectScaffold? ???? ???? ????? ???
- Code ?? empty workspace ??? ??? ????? ??? ?? ??? file_write? ?? ???? ??? ????? file_manage/file_write? ?? ?? ???? ???? ???
- AgentLoop ?? ? ProjectLayoutGate? ??? ??? ?? ??? ?? ??? ??? ????? ?? ??? ? ????? ???
- code-scaffold.skill.md? when_to_use? file_manage/file_edit ?????? ??? proactive auto-skill ???? ???
- IntentGate, scaffold profile, code quality ?? ???? ???

?? ??
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_project_scaffold_layout\\ -p:IntermediateOutputPath=obj\\verify_project_scaffold_layout\\ ?? 0 / ?? 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "IntentGateServiceTests|ProjectScaffoldProfileCatalogTests|SkillServiceRuntimePolicyTests|AgentLoopCodeQualityTests" -p:OutputPath=bin\\verify_project_scaffold_layout_tests\\ -p:IntermediateOutputPath=obj\\verify_project_scaffold_layout_tests\\ ?? 183
2026-04-15 23:46:05 +09:00
lacvet 4980113b99 코드 탭 빌드 실패 조기 종료를 복구 경로로 보강하고 다중 오류 파일 조사 유도를 추가한다
- Code 탭의 review 전용 실행 결과 게이트를 bugfix/feature/refactor에도 확대 적용해 build_run/test_loop 실패 후 읽기만 하고 종료되는 회귀를 막음

- balanced/reasoning_first/tool_call_strict 프로파일에 최근 실행 근거 게이트와 실행 성공 게이트 재시도 1회를 부여해 최소 한 번의 수정·재검증 루프를 보장함

- 빌드 로그에서 오류 파일이 여러 개 잡히면 BuildFailureInvestigationPrompt가 multi_read를 우선 쓰도록 유도해 Themes\\ControlStyles.xaml, Themes\\Effects.xaml 같은 동시 오류를 더 빠르게 좁히도록 개선함

- AgentLoopCodeQualityTests에 다중 오류 파일 조사, 코드 작업 실행 게이트 범위, 코드 중심 프로파일 회귀 테스트를 추가함

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal / dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentLoopCodeQualityTests (경고 0 / 오류 0, 134 통과)
2026-04-15 23:06:29 +09:00
lacvet 16e136107c HTML 보고서 레거시 양식 호환을 보강한다
- TemplateService 공통 CSS에 h4/dl/matrix/comparison/board_report/metrics/roadmap 레거시 블록 호환 스타일을 추가해 raw body 기반 HTML 보고서의 뒤쪽 섹션도 동일한 폰트 크기와 카드 양식을 유지하도록 수정

- roadmap 내부 timeline/owner 배지가 전역 timeline 스타일과 충돌하던 문제를 override로 분리하고 다크 모드·모바일 레이아웃까지 함께 정리

- HtmlSkillLegacyBodyCompatibilityTests를 추가하고 dotnet build 및 HtmlSkillLegacyBodyCompatibilityTests|HtmlSkillConsultingSectionsTests 통과로 검증
2026-04-15 22:47:39 +09:00
lacvet e2553a10ae AX Agent background conversation ??? UI ?? ??
?? ??? ?? ??? ?? ?? ?? ??? ??? ?? ?? ?? ???? ??? ????.

ChatStreamingUiPolicy? ?? ??? ??? ActiveConversation ???? ???, ChatWindow? ??? ??? ?? ??? ????.

AgentProgressHintTimer? StreamMetricsLabel? background conversation ????? ??? UI? ?? ??? ??? ????, ?? ???? README/DEVELOPMENT ??? ????.

??: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_background_conversation_live_ui\\ -p:IntermediateOutputPath=obj\\verify_background_conversation_live_ui\\
??: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ChatStreamingUiPolicyTests|AppStateServiceTests" -p:OutputPath=bin\\verify_background_conversation_live_ui_tests\\ -p:IntermediateOutputPath=obj\\verify_background_conversation_live_ui_tests\\
2026-04-15 22:37:13 +09:00
lacvet 82e58bde57 동시 Cowork·Code 실행 시 메인 루프 상태 혼선을 탭별로 분리
Cowork와 Code를 동시에 실행할 때 메인 루프 번호와 라이브 진행 힌트가 서로 섞이던 문제를 수정했다. ChatWindow가 전역 단일 진행 상태를 공유하던 구조를 탭별 현재 run 상태, 진행 스텝, 라이브 힌트, 대기 UI 이벤트로 분리해 현재 탭 기준으로만 렌더링하도록 정리했다.

AppStateService에 탭별 최신 run 상태 추적을 추가하고 ConversationList, TaskSummary, Timeline, V2 라이브 카드가 활성 탭의 run 메타를 읽도록 변경했다. AppStateServiceTests에 탭별 run iteration 분리 회귀 테스트를 추가했고 README와 DEVELOPMENT 문서에도 2026-04-15 22:25 (KST) 기준 이력을 반영했다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_tab_loop_isolation\\ -p:IntermediateOutputPath=obj\\verify_tab_loop_isolation\\ (경고 0 / 오류 0)
검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AppStateServiceTests" -p:OutputPath=bin\\verify_tab_loop_isolation_tests\\ -p:IntermediateOutputPath=obj\\verify_tab_loop_isolation_tests\\ (통과 45)
2026-04-15 22:26:10 +09:00
lacvet 2f74780367 대화목록 상태 심볼을 구체형으로 정리하고 링 표시를 제거
AX Agent 좌측 대화 목록에서 idle/running 심볼이 열린 링처럼 보여 어색하던 문제를 정리했다. ConversationItemTemplate의 상태 배지를 스트로크 기반 Ellipse에서 레이어드 원형 배지로 교체해 한쪽이 비어 보이던 인상을 없앴다.

idle 상태는 중립색 구체와 하이라이트 조합으로, 실행 중 상태는 AccentColor 기반 구체로 보이게 맞췄고 unread completion 점도 같은 시각 언어에 맞춰 외곽 스트로크와 하이라이트를 보강했다. README와 DEVELOPMENT 문서에도 2026-04-15 22:10 (KST) 기준 이력을 반영했다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_conversation_symbol_sphere\\ -p:IntermediateOutputPath=obj\\verify_conversation_symbol_sphere\\ (경고 0 / 오류 0)
2026-04-15 22:12:41 +09:00
lacvet b9fffbe2b2 AX Agent 탭 내 대화 선택 복귀 회귀 수정
- 같은 탭 안에서 다른 대화를 선택할 때 SaveLastConversations로 발생한 SettingsChanged가 UI 전체 갱신을 다시 태우며 현재 선택을 스트리밍 대화로 덮어쓰던 흐름을 차단함
- ChatStreamingUiPolicy에 스트리밍 대화 우선 노출 정책을 분리하고, 사용자가 명시적으로 선택한 대화가 있으면 탭 복귀 후에도 해당 선택을 유지하도록 SwitchToTabConversation 분기를 조정함
- README.md와 docs/DEVELOPMENT.md에 2026-04-15 22:07 (KST) 기준 회귀 원인과 검증 결과를 반영함

검증 결과
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_conversation_selection_persist\ -p:IntermediateOutputPath=obj\verify_conversation_selection_persist\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatStreamingUiPolicyTests|ChatSessionStateServiceTests -p:OutputPath=bin\verify_conversation_selection_persist_tests\ -p:IntermediateOutputPath=obj\verify_conversation_selection_persist_tests\ : 통과 55
2026-04-15 22:08:28 +09:00
lacvet 76afb9d5c8 AX Agent 라이브 진행 문구 지속 표시 회귀 수정
- V2 라이브 진행 카드에 고정 상태 본문/상세/메타 영역을 추가해 실행 로그만 남고 상단 메시지가 비어 보이던 문제를 줄임
- 스트리밍 시작 시 초기 내러티브를 채우고 각 AgentEvent 처리마다 상태 카드를 갱신하도록 정리함
- README.md와 docs/DEVELOPMENT.md에 2026-04-15 22:18 (KST) 기준 변경 이력과 검증 결과를 반영함

검증 결과
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_live_message_persistence2\ -p:IntermediateOutputPath=obj\verify_live_message_persistence2\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatStreamingUiPolicyTests|ChatWindowSlashPolicyTests -p:OutputPath=bin\verify_live_message_persistence_tests\ -p:IntermediateOutputPath=obj\verify_live_message_persistence_tests\ : 통과 69
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_live_message_persistence3\ -p:IntermediateOutputPath=obj\verify_live_message_persistence3\ : 경고 0 / 오류 0
2026-04-15 22:02:55 +09:00
lacvet f8067a1f9b AX Agent 창 제목 고정 및 PPT 품질 재루프 고도화
- 채팅창 Windows 제목을 AX Agent로 고정해 작업 표시줄/Alt+Tab에서 대화 제목이 섞이지 않도록 조정

- Assets/ppt manifest와 템플릿 카탈로그를 추가해 basic100/core100 등 고품질 PPT 자산을 실행 폴더, 소스 루트, AppData 템플릿 폴더에서 안정적으로 탐색하도록 개선

- pptx_create 결과에서 asset missing과 color fallback을 구분해 진단 메시지를 남기고 Cowork에서는 PPT quality/slide alerts/Needs work 기준으로 최대 2회 재생성 루프를 타도록 품질 게이트 추가

- PPT 시스템 프롬프트와 pptx-creator 스킬 지시를 document_plan -> pptx_create 중심으로 정렬

- 검증: dotnet build ...verify_ppt_quality_gate 경고 0/오류 0, dotnet test ...PptxSkillTemplatePackTests|PptxSkillAutoRepairTests|PptxSkillGoldenDeckTests|PptQualityGatePolicyTests|PptxTemplateManifestCatalogTests 통과 12
2026-04-15 21:49:09 +09:00
lacvet 2c48ca211a AX Agent 입력 상단 스트리밍 지표 간격 회귀 수정
- 라이브 진행 Grid를 2열 구조로 바꾸고 시간·토큰 표시를 우측 하단에 다시 배치

- 진행 문구와 입력창이 분리돼 보이던 간격 회귀를 줄이고 입력창 상단 정렬을 복원

- README.md와 docs/DEVELOPMENT.md에 2026-04-15 21:23 (KST) 기준 변경 이력 반영

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_stream_metrics_compact\\ -p:IntermediateOutputPath=obj\\verify_stream_metrics_compact\\ (경고 0 / 오류 0)
2026-04-15 21:23:44 +09:00
lacvet d6a8ab0ddb AX Copilot 아이콘 점유율과 트레이 DPI 프레임을 키운다
작업 표시줄과 트레이에서 AX Copilot 아이콘이 다른 앱보다 작게 보이던 원인은 icon.ico 내부 여백이 커서 실제 도형 점유율이 낮았기 때문이다. 현재 4다이아몬드 계열 형태는 유지한 채 내부 여백을 줄이고 캔버스를 더 넓게 쓰는 새 멀티사이즈 아이콘으로 자산을 재생성했다.

아이콘 생성 경로도 함께 정리했다. tools/IconGenerator는 현재 AX 아이콘 스타일을 기본으로 생성하고 16 20 24 32 40 48 64 128 256 프레임을 포함하도록 바꿨다. src/AxCopilot/Assets/diamond_pixel.svg도 같은 비율로 맞춰 소스 SVG와 실제 ico 자산이 덜 어긋나게 정리했다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_icon_size\ -p:IntermediateOutputPath=obj\verify_icon_size\ / 경고 0 오류 0
검증: System.Drawing.Icon 확인 결과 16 20 24 32 프레임이 요청 크기 그대로 로드됨
2026-04-15 21:20:55 +09:00
lacvet 35e0d0dbbf AX Agent 대화 목록 선택 배경과 심볼 잘림 회귀를 바로잡는다
좌측 대화 목록 선택 카드가 보이지 않던 원인은 ConversationItemTemplate 루트 Border에 Background와 BorderBrush가 로컬값으로 고정되어 스타일 트리거를 이기고 있었기 때문이다. 기본 투명값을 스타일 setter로 옮겨 선택 상태에서 ItemSelectedBackground가 정상 적용되도록 수정했다.

ConversationItemsControl 컨테이너는 가로 Stretch로 맞춰 선택 배경이 행 전체 둥근 카드로 깔리게 했고, idle 심볼은 16x16 그리드와 내부 마진을 적용해 점선 링이 가장자리에서 살짝 잘리던 문제를 줄였다. README와 DEVELOPMENT 문서에도 2026-04-15 21:11 KST 기준으로 원인과 검증 결과를 기록했다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_conversation_list_selection_fix\ -p:IntermediateOutputPath=obj\verify_conversation_list_selection_fix\ / 경고 0 오류 0
검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ConversationItemViewModelTests" -p:OutputPath=bin\verify_conversation_list_selection_fix_tests\ -p:IntermediateOutputPath=obj\verify_conversation_list_selection_fix_tests\ / 통과 3
2026-04-15 21:13:38 +09:00
lacvet 41228ae82e AX Agent 대화 목록 선택 카드와 idle 심볼을 정리한다
좌측 대화 목록 선택 상태가 제목 굵기만 바뀌어 체감이 약하던 문제를 수정했다. ConversationItemTemplate가 ItemSelectedBackground 기반의 둥근 카드 배경을 사용하도록 바꾸고 패딩과 아이콘 영역도 함께 다듬어 선택 항목이 테마에 맞게 한눈에 구분되도록 맞췄다.

실행 중이거나 미확인 완료 상태가 아닌 대화에는 점선 링 형태의 idle 심볼이 보이도록 ShowIdleIndicator 계산 속성과 목록 트리거를 추가했다. 관련 회귀를 ConversationItemViewModelTests로 고정하고 README와 DEVELOPMENT 문서에도 2026-04-15 21:00 KST 기준 변경 이력을 남겼다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_conversation_list_selected_card\ -p:IntermediateOutputPath=obj\verify_conversation_list_selected_card\ / 경고 0 오류 0
검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ConversationItemViewModelTests" -p:OutputPath=bin\verify_conversation_list_selected_card_tests\ -p:IntermediateOutputPath=obj\verify_conversation_list_selected_card_tests\ / 통과 3
2026-04-15 21:04:50 +09:00
lacvet 96e4f80edf 코드 리뷰 회복 흐름과 자동 실행 가드 정비
- 비 Git 작업 폴더에서 git_tool(diff)만 반복 호출하지 않도록 AgentLoop 실패 복구, 우선순위, 태스크 가이드를 code_review(file_review) 대안까지 포함하도록 조정했습니다.

- CodeReviewTool diff_review가 실제 Git 저장소 루트와 Git 실행 가능 여부를 먼저 확인하고, 저장소가 아니거나 Git이 없으면 file_review 대안을 즉시 안내하도록 보강했습니다.

- OpenExternalTool에 사용자 명시 요청 기반 auto-open 차단을 추가하고, Cowork 및 Code 시스템 프롬프트에도 결과물 자동 열기와 미리보기 서버 자동 실행 금지 규칙을 반영했습니다.

- AgentLoopCodeQualityTests, OperationModeReadinessTests를 확장해 비 Git 리뷰 회복 경로와 암묵적 open_external 차단 회귀를 고정했습니다.

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_review_policy_fix\\ -p:IntermediateOutputPath=obj\\verify_review_policy_fix\\ 및 dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentLoopCodeQualityTests,OperationModeReadinessTests -p:OutputPath=bin\\verify_review_policy_fix_tests\\ -p:IntermediateOutputPath=obj\\verify_review_policy_fix_tests\
2026-04-15 20:58:27 +09:00
lacvet 3210440767 대화 목록을 코덱스형 1줄 카드로 정리하고 상태 배지를 추가
선택된 대화는 전체 배경과 테두리를 테마 리소스로 강조하고 제목·시간을 한 줄로 재배치했습니다.

실행 중 링, 미열람 완료 점, 좌측 목록 재클릭 시 이름 변경 진입 제거를 반영했고 ChatWindowSlashPolicyTests로 상태 표시 조건 회귀를 검증했습니다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_conversation_list_refresh\\ -p:IntermediateOutputPath=obj\\verify_conversation_list_refresh\\ / dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatWindowSlashPolicyTests -p:OutputPath=bin\\verify_conversation_list_refresh_tests\\ -p:IntermediateOutputPath=obj\\verify_conversation_list_refresh_tests\
2026-04-15 20:43:37 +09:00
lacvet 5f4a52929b AX Agent 최대 반복 횟수 상한을 500으로 확장
변경 목적:\n- 내부 설정의 최대 에이전트 패스 상한이 100으로 묶여 긴 Code 작업에서 반복 여유가 부족한 문제를 해소합니다.\n\n핵심 수정사항:\n- SettingsViewModel의 MaxAgentIterations 클램프를 1~500으로 상향했습니다.\n- SettingsWindow의 최대 반복 횟수 슬라이더와 안내 문구를 1~500 기준으로 맞추고 값 표시 폭을 넓혔습니다.\n- ChatWindow 오버레이 설정의 슬라이더, 텍스트 입력, 동기화 클램프를 모두 500 기준으로 통일했습니다.\n- AgentSettingsWindow의 로드/저장 파싱 상한도 500으로 맞춰 설정 경로 간 불일치를 제거했습니다.\n- README와 DEVELOPMENT 문서에 2026-04-15 20:19 (KST) 기준 변경 이력과 빌드 검증 결과를 반영했습니다.\n\n검증 결과:\n- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_max_agent_iterations_500\\ -p:IntermediateOutputPath=obj\\verify_max_agent_iterations_500\\\n- 경고 0 / 오류 0
2026-04-15 20:23:02 +09:00
lacvet 939e594de8 입력창 바로 위 시간·토큰 표시 배치 고정
원인: StreamMetricsLabel이 PulseDotBar와 같은 행을 공유해 라이브 진행 문구가 여러 줄로 커질 때 시간·토큰 표시도 위로 떠 보였습니다.

수정: StreamMetricsLabel을 진행 상태 행에서 분리해 입력 영역 바로 앞에 독립 배치했습니다. 이제 라이브 진행 텍스트 높이와 무관하게 시간·토큰 표시가 채팅 입력창 바로 위 오른쪽에 붙어 있습니다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_stream_metrics_anchor\ -p:IntermediateOutputPath=obj\verify_stream_metrics_anchor\ (경고 0 / 오류 0)
2026-04-15 20:17:55 +09:00
lacvet 9ad587d230 컨텍스트 사용량 링 정렬 회귀 수정
원인: 하단 컨텍스트 사용량 트랙은 22x22 원형인데 arc는 center=15, radius=11 하드코딩으로 더 크게 그려져 오른쪽으로 밀려 보였습니다.

수정: TokenUsageTrack과 TokenUsageArc를 같은 크기와 가운데 정렬로 맞추고, 실제 트랙 지름과 스트로크 두께를 기준으로 중심점·반지름을 계산하는 helper를 추가했습니다. 크기 변경 시에도 arc가 다시 그려지도록 캐시 조건도 보강했습니다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_token_ring_alignment\ -p:IntermediateOutputPath=obj\verify_token_ring_alignment\ (경고 0 / 오류 0), dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatWindowSlashPolicyTests -p:OutputPath=bin\verify_token_ring_alignment_tests\ -p:IntermediateOutputPath=obj\verify_token_ring_alignment_tests\ (통과 53)
2026-04-15 20:14:20 +09:00
lacvet bea9335ec0 빠른 win-x64 테스트 빌드용 PowerShell 스크립트 추가
인스톨러와 dist 패키징을 거치지 않고 AxCopilot.csproj만 Release + win-x64로 빌드해 src\AxCopilot\bin\Release\net8.0-windows10.0.17763.0\win-x64 출력물을 빠르게 갱신할 수 있도록 build-quick.ps1를 추가했습니다.

스크립트는 기본적으로 --no-restore 경로를 사용하고, 필요할 때만 -Restore를 수행하며, 잠금 대응용 -StopRunningApp과 정리용 -Clean 옵션을 함께 제공합니다.

검증: powershell -ExecutionPolicy Bypass -File .\build-quick.ps1 실행 성공, dotnet build src/AxCopilot/AxCopilot.csproj -c Release -r win-x64 경고 0 / 오류 0
2026-04-15 20:08:06 +09:00
lacvet 22261579d0 AX Agent 스트리밍 중 탭 전환과 새 대화가 멈추는 저장 루프 회귀 수정
원인: 같은 LastActiveTab·LastConversationIds 상태에서도 ChatSessionStateService.Save가 매번 settings.Save를 호출해 SettingsChanged -> UpdateTabUI -> SwitchToTabConversation -> SaveLastConversations 순환이 계속 발생했습니다. 이 때문에 시간 표시가 0초에 머무르고 탭 전환/새 대화가 즉시 덮어써졌습니다.

수정: ChatSessionStateService는 세션 스냅샷이 실제로 바뀐 경우에만 저장하도록 변경했고, 동일 상태 반복 저장 시 Save와 SettingsChanged가 재발화하지 않도록 테스트를 추가했습니다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_streaming_tab_loop_fix\ -p:IntermediateOutputPath=obj\verify_streaming_tab_loop_fix\ (경고 0 / 오류 0), dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatSessionStateServiceTests|ChatStreamingUiPolicyTests|AxAgentExecutionEngineTests -p:OutputPath=bin\verify_streaming_tab_loop_fix_tests\ -p:IntermediateOutputPath=obj\verify_streaming_tab_loop_fix_tests\ (통과 51)
2026-04-15 20:00:54 +09:00
lacvet f3717cda21 Code 탭 자동 스킬 오탐과 런타임 도구 제한 회귀 수정
원인: proactive auto skill이 실제 매치가 없어도 기본 점수만으로 선택되고, guidance 단계에서 allowed_tools 같은 하드 런타임 정책까지 자동 주입되어 빈 작업 폴더 요청에서 file_write가 빠진 채 종료됐습니다.

수정: SkillService의 proactive skill 점수를 실제 키워드·경로 신호 중심으로 다시 계산하고, auto skill은 guidance만 제공하며 하드 runtime policy는 더 이상 자동 주입하지 않도록 변경했습니다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_auto_skill_runtime_fix\ -p:IntermediateOutputPath=obj\verify_auto_skill_runtime_fix\ (경고 0 / 오류 0), dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter SkillServiceRuntimePolicyTests|FullyQualifiedName~RunAsync_EmptyWorkspace_BlocksExternalFallbackAndRecoversToFileWrite|FullyQualifiedName~RunAsync_EmptyWorkspace_DisallowsSkillManagerAndRecoversToFileWrite -p:OutputPath=bin\verify_auto_skill_runtime_fix_tests\ -p:IntermediateOutputPath=obj\verify_auto_skill_runtime_fix_tests\ (통과 15)
2026-04-15 19:50:35 +09:00
lacvet 8721a0d8c7 AX Agent 상단 라이브 안내 카드 유지 회귀를 수정한다
- 같은 탭에 실행이 살아 있는 동안에는 현재 대화와 실행 대화가 잠깐 어긋나도 상단 라이브 카드와 상태 바를 숨기지 않도록 ChatWindow 스트리밍 분기를 조정함

- ChatStreamingUiPolicy를 추가해 Hidden/ActiveConversation/BackgroundConversation 상태를 분리하고 본문 실행 이력 렌더와 상단 진행 안내 표시를 분리함

- ChatStreamingUiPolicyTests를 추가하고 README.md, docs/DEVELOPMENT.md 이력을 갱신함

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_live_guide_persistence\\ -p:IntermediateOutputPath=obj\\verify_live_guide_persistence\\ (경고 0, 오류 0)

- 검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatStreamingUiPolicyTests|ChatWindowSlashPolicyTests|ChatSessionStateServiceTests|AxAgentExecutionEngineTests -p:OutputPath=bin\\verify_live_guide_persistence_tests\\ -p:IntermediateOutputPath=obj\\verify_live_guide_persistence_tests\\ (통과 98)
2026-04-15 19:35:24 +09:00
lacvet f173e2a63b 같은 탭 대화 전환 중에도 AX Agent 실행이 계속되도록 수정
- 실행 시작 대화를 탭별로 추적해 같은 탭에서 다른 대화로 이동하거나 새 대화를 시작해도 원래 대화에 이벤트와 완료 결과를 저장하도록 정리함
- 탭 복귀 시 진행 중인 대화를 다시 로드하고 백그라운드 실행 저장이 현재 선택 대화 ID를 덮어쓰지 않도록 세션/저장 경로를 보강함
- ChatSessionStateService와 AxAgentExecutionEngine 회귀 테스트를 추가하고 README.md, docs/DEVELOPMENT.md 이력을 갱신함
- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_conversation_background_resume\ -p:IntermediateOutputPath=obj\verify_conversation_background_resume\ (경고 0, 오류 0)
- 검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatSessionStateServiceTests|AxAgentExecutionEngineTests -p:OutputPath=bin\verify_conversation_background_resume_tests\ -p:IntermediateOutputPath=obj\verify_conversation_background_resume_tests\ (통과 39)
2026-04-15 19:24:40 +09:00
lacvet 913b42b2f3 코드탭 로그에서 드러난 대화 저장소 복호화 오탐을 수정한다
- CryptoService 평문 JSON 판별을 UTF-8 디코드 성공과 BOM/공백 제거 후 JSON 시작 문자 확인으로 강화
- 암호문 선행 바이트가 '[' 또는 0xEF인 경우와 UTF-8 BOM 평문 대화 파일 복원 회귀 테스트 추가
- README와 DEVELOPMENT 문서에 2026-04-15 19:12 KST 기준 로그 원인 및 검증 결과 기록

검증:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_chat_storage_fix\\ -p:IntermediateOutputPath=obj\\verify_chat_storage_fix\\
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatStorageServiceTests -p:OutputPath=bin\\verify_chat_storage_fix_tests\\ -p:IntermediateOutputPath=obj\\verify_chat_storage_fix_tests\
2026-04-15 19:05:21 +09:00
lacvet 5ab04bc53e AX Agent 라이브 진행 표시 회귀 복구 및 본문 선택 유지 정리
상단 라이브 진행 카드를 이전 단계형 구조로 복구하고 스트리밍 중 현재 실행 이벤트가 본문 타임라인에 중복 표시되지 않도록 V2 렌더 컷오프를 다시 적용했습니다.

사용자 말풍선은 기존 마크다운 렌더로 되돌려 세로로 깨지던 표시를 해결하고, 어시스턴트 본문과 스트리밍 완료 본문은 계속 드래그 선택/복사가 가능하도록 유지했습니다. 또한 SkillRuntime, allowed_tools, 메인 루프 요청, 읽기 도구 조기 실행 준비, 스트리밍 도구 감지 같은 저신호 내부 문구를 추가 필터링해 화면 노이즈를 줄였습니다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_live_restore\\ -p:IntermediateOutputPath=obj\\verify_live_restore\\ 에서 경고 0 오류 0을 확인했습니다.

검증: AgentLoopCodeQualityTests, AgentStatusNarrativeCatalogTests, AgentProgressSummarySanitizerTests 필터로 dotnet test를 실행해 131개 테스트 통과를 확인했습니다.
2026-04-15 18:56:53 +09:00
lacvet 53838a046b AX Agent ?? ?? ?? ??? ??? ?? ??? ????
- Code ??? ?? ???? ?? ??? ??? ? ?? ?? ???? ???? no-progress ??? ???
- ??? ?? ??? 1~2? ????? ????? ToolCall/ToolResult ?? ??? ?? ????? ????? ???
- ??? Thinking/LLM ?? ??? ??? ???? ??? ?? ?? ??? ??? ??? ????? ????
- Cowork/Code ??? ??? ?? ??? ???? ??? ??? ??? ?? ???? ?
- README.md, docs/DEVELOPMENT.md ??? 2026-04-15 18:30 (KST) ???? ???

??
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_agent_ui_logs\\ -p:IntermediateOutputPath=obj\\verify_agent_ui_logs\\
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentLoopCodeQualityTests|AgentStatusNarrativeCatalogTests|AgentProgressSummarySanitizerTests" -p:OutputPath=bin\\verify_agent_ui_logs_tests\\ -p:IntermediateOutputPath=obj\\verify_agent_ui_logs_tests\\
2026-04-15 18:33:06 +09:00
lacvet 232d5457d5 워크스페이스 복원에 탐색기·메모장 상태와 적응형 실행 간격을 추가한다
- 파일 탐색기 현재 폴더 경로와 메모장 열린 파일 경로를 워크스페이스 스냅샷에 저장하고 복원 경로에 연결
- 브라우저/앱 공용 프로세스 명령줄 파서를 추가하고 패키지형 메모장 실행 fallback을 보강
- 복원 중 새 창 실행 사이에 CPU·메모리 부하 기반 적응형 지연과 설정 UI를 추가
- README와 DEVELOPMENT 개발 이력을 2026-04-15 17:41 (KST) 기준으로 갱신
- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_workspace_app_restore\\ -p:IntermediateOutputPath=obj\\verify_workspace_app_restore\\ 경고 0 오류 0, dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter WorkspaceHandlerTests|ContextManagerTests|SettingsServiceTests -p:OutputPath=bin\\verify_workspace_app_restore_tests\\ -p:IntermediateOutputPath=obj\\verify_workspace_app_restore_tests\\ 54개 통과
2026-04-15 17:45:07 +09:00
lacvet e823ff83e3 워크스페이스 브라우저 상태 복원 경로를 추가하고 설정 및 검증을 정리한다
변경 목적: ~ 워크스페이스 복원 시 창 배치뿐 아니라 브라우저 탭/URL 상태까지 가능한 범위에서 함께 재현하도록 저장/복원 경로를 확장한다.

핵심 수정사항: BrowserWorkspaceStateHelper를 추가해 Chromium/Firefox 계열 창의 프로필 인자, 탭 URL, 활성 탭 인덱스를 수집하고, ContextManager가 브라우저 상태가 저장된 창은 부분 제목 매칭으로 기존 창을 재사용하지 않고 새 브라우저 창을 띄워 동일한 URL 세트를 복원한 뒤 위치와 활성 탭을 맞추도록 변경했다. Launcher 설정에 브라우저 상태 복원 토글을 추가하고 SettingsViewModel 및 설정 UI와 연결했으며, ContextManagerTests와 SettingsServiceTests를 확장했다. README와 DEVELOPMENT 문서에도 2026-04-15 17:26 (KST) 기준 작업 이력과 검증 명령을 반영했다.

검증 결과: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_browser_restore\ -p:IntermediateOutputPath=obj\verify_browser_restore\ 에서 경고 0/오류 0을 확인했고, dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter WorkspaceHandlerTests|ContextManagerTests|SettingsServiceTests -p:OutputPath=bin\verify_browser_restore_workspace_tests\ -p:IntermediateOutputPath=obj\verify_browser_restore_workspace_tests\ 에서 44개 테스트 통과를 확인했다.
2026-04-15 17:28:22 +09:00
lacvet 9344cf83d6 개발 문서를 AX 기준 계획 중심으로 정리하고 비교성 표현을 제거
- README와 DEVELOPMENT, 로드맵 문서에서 비교·모사 뉘앙스가 강한 문구를 AX 기준 설명으로 정리함

- 비교/패리티 성격의 문서를 AX Agent 구조 리뷰, 실행 개선 계획, 품질 계획, 런타임 품질 계획, 도구 커버리지 문서로 재구성함

- 회귀 프롬프트와 보조 개발 문서의 용어를 공통 핵심 명령과 운영 기준 중심으로 정리함

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_docs_cleanup\\ -p:IntermediateOutputPath=obj\\verify_docs_cleanup\\ (경고 0 / 오류 0)
2026-04-15 17:05:30 +09:00
lacvet 964e40718f 런처 워크스페이스 복원 매칭과 ~restore 명령을 보강
변경 목적:
- 런처 ~ 예약어의 창 복원 품질을 점검하고, 같은 exe의 첫 창만 반복 재사용되어 브라우저/다중 창 배치가 꼬이던 문제를 줄입니다.
- 도움말에만 있던 ~restore, ~list 명령을 실제 핸들러 동작과 맞춥니다.

핵심 수정사항:
- ContextManager가 열린 창 후보를 exe + 제목 유사도 기준으로 매칭하고, 이미 다른 스냅샷에 배정된 핸들은 재사용하지 않도록 변경했습니다.
- WorkspaceHandler에 ~restore <이름>, ~list 지원과 최근 저장 순 프로필 목록 복원 액션 정리를 추가했습니다.
- WorkspaceHandlerTests, ContextManagerTests를 추가해 명령 파싱과 창 매칭 우선순위를 회귀 검증합니다.
- README.md, docs/DEVELOPMENT.md에 검토 결과와 검증 이력을 기록했습니다.

검증 결과:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_workspace_restore_review\\ -p:IntermediateOutputPath=obj\\verify_workspace_restore_review\\
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter WorkspaceHandlerTests^|ContextManagerTests -p:OutputPath=bin\\verify_workspace_restore_review_tests\\ -p:IntermediateOutputPath=obj\\verify_workspace_restore_review_tests\\
- 경고 0 / 오류 0, 테스트 6건 통과
2026-04-15 16:54:06 +09:00
lacvet 78b3aa2801 사내 모드 외부 LLM 범위를 테스트와 문서로 고정함
Gemini와 Claude만 외부 LLM 차단 대상으로 유지하고 Ollama와 vLLM은 사내/사외 모두 허용된다는 기준을 회귀 테스트로 추가했다.

깨진 인코딩으로 읽히던 LlmOperationModeTests를 정리하고 README 및 DEVELOPMENT 문서에 정책 정의와 검증 결과를 함께 반영했다.

검증: dotnet build 경고 0 오류 0, LlmOperationModeTests 5건 통과.
2026-04-15 16:41:45 +09:00
lacvet f4351aa0eb 권한 체계를 사내 모드 기준으로 정리하고 실행 단위 승인 범위를 바로잡음
사내 모드에서 process/build_run/open_external 경로의 외부 접근 차단 범위를 강화했습니다. http_tool과 외부 URI 차단에 더해 curl, Invoke-WebRequest 같은 네트워크성 명령과 build_run custom 실행을 내부 정책으로 막아 실제 동작이 정책 선언과 더 가깝게 맞춰지도록 했습니다.

ChatWindow의 '이번 실행 동안 허용' 승인 규칙을 run-scope로 변경했습니다. 탭 실행 시작과 종료 시 승인 캐시를 초기화하고 같은 실행 안에서만 동일 범위 접근을 재질문 없이 재사용하도록 정리해 창 수명 동안 규칙이 남던 문제를 줄였습니다.

권한 건너뛰기 관련 UI/상태 문구를 실제 동작과 맞췄고, OperationModePolicyTests·OperationModeReadinessTests·AgentLoopE2ETests·LlmOperationModeTests를 통해 권한 정책과 사내 모드 차단 회귀를 검증했습니다. dotnet build 경고 0 / 오류 0, 권한 관련 테스트 49건 통과를 확인했습니다.
2026-04-15 16:34:34 +09:00
lacvet 8baeabbb70 권한 경로 해석과 세션 승인 재사용을 워크스페이스 기준으로 정렬
상대 경로 파일 작업에서 권한 팝업과 사내 모드 외부 경로 판정이 워크스페이스가 아니라 프로세스 현재 폴더(dist) 기준으로 해석되면서, 팝업 표시 경로가 틀어지고 '이번 실행 동안 허용'도 raw/absolute 경로 불일치로 재사용되지 않던 문제를 수정했다.

- IAgentTool의 경로 판정에 workspace-aware 해석을 추가해 IsPathAllowed와 IsOutsideWorkspace가 상대 경로를 현재 WorkFolder 기준 절대경로로 비교하도록 변경
- ChatWindow 권한 콜백에서 RuntimeWorkFolderOverride 또는 현재 대화 WorkFolder를 기준으로 대상 경로를 먼저 정규화하고, 자동 승인 재사용, 외부 경로 안내, 권한 팝업 표시, 세션 규칙 저장에 동일 경로를 사용하도록 정리
- OperationModePolicyTests에 사내 모드 BypassPermissions에서도 워크스페이스 하위 상대 경로는 승인 없이 허용되는 회귀 테스트를 추가
- README와 docs/DEVELOPMENT.md에 2026-04-15 16:12 (KST) 기준 작업 이력과 검증 결과를 반영

검증:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_permission_workspace_path\\ -p:IntermediateOutputPath=obj\\verify_permission_workspace_path\\ (경고 0 / 오류 0)
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "OperationModePolicyTests|AgentLoopE2ETests" -p:OutputPath=bin\\verify_permission_workspace_path_tests\\ -p:IntermediateOutputPath=obj\\verify_permission_workspace_path_tests\\ (통과 34)
2026-04-15 16:09:30 +09:00
lacvet 90f92ccee5 라이브 진행 카드 자동 복구 로직 추가
메인 루프2 이후 Cowork/Code 실행 중 채팅창 상단 라이브 진행 카드가 transcript 재렌더링이나 이벤트 타이밍에 따라 사라지던 회귀를 수정했다.

- ChatWindow.LiveProgressPresentation에 EnsureAgentLiveCardVisible를 추가해 라이브 카드 컨테이너가 없거나 transcript에서 떨어졌을 때 즉시 재생성 및 재부착되도록 보강
- ChatWindow.xaml.cs에서 agent event 수신과 live hint 시작 시 eligible 탭이면 항상 라이브 카드 복구를 먼저 수행한 뒤 상태를 갱신하도록 정리
- ChatWindow.V2Rendering에서 부분/전체 렌더 재구성 후 _isStreaming 상태면 라이브 카드를 자동 복원하도록 변경
- README와 docs/DEVELOPMENT.md에 수정 배경, 적용 파일, 검증 결과를 2026-04-15 15:56 (KST) 기준으로 반영

검증:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_live_card_guard\\ -p:IntermediateOutputPath=obj\\verify_live_card_guard\\ (경고 0 / 오류 0)
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ChatWindowSlashPolicyTests" -p:OutputPath=bin\\verify_live_card_guard_tests\\ -p:IntermediateOutputPath=obj\\verify_live_card_guard_tests\\ (통과 49)
2026-04-15 15:58:40 +09:00
lacvet b055138b4a 코드 탭 워크스페이스 권한 정합성 수정 및 회귀 테스트 추가
- AgentLoopService에 RuntimeWorkFolderOverride를 추가해 Code/Cowork 실행이 settings 기본 경로보다 현재 대화 WorkFolder를 우선 사용하도록 정리

- ChatWindow에서 RunAgentLoopAsync 실행 시 conversation.WorkFolder를 루프에 직접 주입하고 사내 모드 권한 안내도 같은 런타임 워크스페이스 기준으로 맞춤

- AgentLoopE2ETests에 워크스페이스 override 우선 적용, 사내 모드 내부 경로 무승인, 외부 경로 승인 강제 회귀를 추가

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_workspace_permission_fix\\ -p:IntermediateOutputPath=obj\\verify_workspace_permission_fix\\ / 경고 0 오류 0

- 검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter FullyQualifiedName~RunAsync_CodeRuntimeWorkspaceOverride_PrefersConversationWorkspaceOverSettingsFolder|FullyQualifiedName~RunAsync_InternalMode_BypassPermissions_AllowsWorkspaceWriteWithoutPrompt|FullyQualifiedName~RunAsync_InternalMode_BypassPermissions_RequestsApprovalForPathOutsideWorkspace|FullyQualifiedName~RunAsync_EmptyWorkspace_BlocksExternalFallbackAndRecoversToFileWrite|FullyQualifiedName~RunAsync_EmptyWorkspace_DisallowsSkillManagerAndRecoversToFileWrite|FullyQualifiedName~RunAsync_TextEmbeddedToolCall_RecoversAndExecutesFileWrite / 통과 6
2026-04-15 15:42:14 +09:00
lacvet 675bdc9595 메인 루프2 이후 사라진 코워크/코드 라이브 카드 복구
메인 루프2 리팩터링 이후 StartLiveAgentProgressHints가 하단 상태 힌트만 시작하고 채팅창 바로 위 V2 라이브 카드를 다시 만들지 않아 Cowork/Code 실행 중 라이브 카드가 보이지 않던 회귀를 수정했다.

- StartLiveAgentProgressHints에서 Cowork/Code 실행 시작 시 ShowAgentLiveCard(runTab)를 다시 호출하도록 복구

- Chat 같은 비대상 탭은 시작 시 기존 라이브 카드를 즉시 정리하도록 보강

- IsAgentLiveCardEligibleTab 헬퍼를 추가해 라이브 카드 대상 탭 판정을 한곳으로 고정

- ChatWindowSlashPolicyTests에 라이브 카드 대상 탭 회귀 테스트 추가

- README.md, docs/DEVELOPMENT.md에 2026-04-15 15:27 (KST) 기준 작업 이력과 검증 결과 반영

검증:

- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_live_card_restore\\ -p:IntermediateOutputPath=obj\\verify_live_card_restore\\ (경고 0 / 오류 0)

- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatWindowSlashPolicyTests -p:OutputPath=bin\\verify_live_card_restore_tests\\ -p:IntermediateOutputPath=obj\\verify_live_card_restore_tests\\ (통과 49)
2026-04-15 15:30:31 +09:00
lacvet 791d172850 코워크 PPT 생성 경로를 공통 품질 루프로 고도화하고 자동 보정 단계를 추가
- Cowork 프롬프트와 direct-creation 탐색 정책에서 PPT 요청은 document_plan을 무조건 선행하지 않고 pptx_create를 우선하도록 조정했습니다.

- DeckPlanningService에 RefineForQuality 루프를 추가해 executive summary, comparison, roadmap, chart, KPI dashboard 슬라이드의 headline, takeaway, verdict, timeline/owner, KPI narrative를 자동 보강하도록 했습니다.

- PptxSkill이 초기 deck review가 약할 때 한 번 더 refined deck을 만들고 실제로 점수와 경고가 개선된 경우에만 최종 렌더링에 반영하도록 수정했습니다.

- DeckPlanningServiceTests와 PptxSkillAutoRepairTests를 확장해 generic PPT 품질 보정 회귀를 고정했습니다.

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_ppt_generic_quality\\ -p:IntermediateOutputPath=obj\\verify_ppt_generic_quality\\ (경고 0 / 오류 0)

- 검증: deck planning, pptx auto repair, golden deck, deck quality review 테스트 통과 14
2026-04-15 15:17:12 +09:00
lacvet 99990b9778 코드 탭 첫 LLM 응답 대기 진단을 강화하고 heartbeat 상태를 노출한다
설치형 환경에서 Code 탭 작업이 오래 걸릴 때 첫 도구 호출 전에 정체되는 구간을 추적할 수 있도록 StreamingToolExecutionCoordinator에 대기 heartbeat와 첫 응답 수신 로그를 추가했다.

첫 응답 전에는 모델 요청 시작, 응답 대기 시간, 첫 응답 수신 시점을 AgentLoopWait 로그와 Thinking 이벤트로 남기고, 이후 응답 지연도 heartbeat로 표시하도록 조정했다. 함께 StreamingToolExecutionCoordinatorTests를 추가해 첫 응답 지연 시 heartbeat가 노출되는 경로와 빠른 응답 시 불필요한 heartbeat가 생기지 않는 경로를 고정했다.

README.md와 docs/DEVELOPMENT.md에 2026-04-15 14:55 (KST) 기준 이력을 반영했고, dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_llm_wait_diag\\ -p:IntermediateOutputPath=obj\\verify_llm_wait_diag\\ 경고 0/오류 0, dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "StreamingToolExecutionCoordinatorTests|AgentLoopLlmRequestPreparationServiceTests|AgentLoopIterationPreparationServiceTests" -p:OutputPath=bin\\verify_llm_wait_diag_tests\\ -p:IntermediateOutputPath=obj\\verify_llm_wait_diag_tests\\ 통과 6을 확인했다.
2026-04-15 14:57:55 +09:00
lacvet d3b6b1a936 코워크 코드 내부설정 컨텍스트 토큰 기본값을 32K로 상향
LlmSettings.MaxContextTokens 기본값을 32768로 조정하고 메인 설정의 컨텍스트 토큰 카드에 32K 선택지를 추가했다.

AgentSettingsWindow의 잘못된 입력 fallback도 32K 기준으로 바꿔 내부설정이 4K로 되돌아가지 않도록 정리했다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_context32k\\ -p:IntermediateOutputPath=obj\\verify_context32k\\ / dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter SettingsServiceTests -p:OutputPath=bin\\verify_context32k_tests\\ -p:IntermediateOutputPath=obj\\verify_context32k_tests\
2026-04-15 14:29:04 +09:00
lacvet b260008663 코드 탭 작업 폴더 동기화 불일치 수정 및 빠른 전송 안정화
작업 폴더 선택 시 현재 대화가 없더라도 Code/Cowork 대화를 즉시 확보하고 WorkFolder를 먼저 기록하도록 보강했다.

새 Code/Cowork 대화가 탭별 최근 작업 폴더를 기본으로 승계하도록 ChatSessionStateService를 조정하고, 현재 폴더 표시도 CodeWorkFolder/CoworkWorkFolder를 우선 사용하도록 맞췄다.

작업 폴더 해제 시 대화 메타데이터와 탭별 저장 폴더를 함께 초기화하도록 정리했다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_workfolder_sync\\ -p:IntermediateOutputPath=obj\\verify_workfolder_sync\\ / dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatSessionStateServiceTests -p:OutputPath=bin\\verify_workfolder_sync_tests\\ -p:IntermediateOutputPath=obj\\verify_workfolder_sync_tests\
2026-04-15 14:18:14 +09:00
lacvet d58cf2c093 AgentLoop ? ?? ???? no-tool ?? ???? ??
broader AgentLoop E2E?? math_eval? hook ?? ?? ????? Chat ?? ??? ???? ??? ??? ?? ?? ???? ??? ?? Cowork ? ???? ????. AgentToolCatalog ?? math_eval? Cowork,Code ????, ?? ??? Skill Runtime Policy ???? ???-?? ??? ??? ??.

AgentLoopService? activeTools.Count == 0 ??? ????. runtimeOverrides.AllowedToolNames? ??? ?? ???? ?? ?? ?? ??? ????, ? ??? ?? ?? ?? ??? ??? ??? ? ?? ???? ????? ??? ??? ?? ??? ???.

README.md? docs/DEVELOPMENT.md? 2026-04-15 14:18 (KST) ?? ??? ????.

??:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_runtime_policy_alignment_build\\ -p:IntermediateOutputPath=obj\\verify_runtime_policy_alignment_build\\ (?? 0 / ?? 0)
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentLoopE2ETests|AgentLoopResponseClassificationServiceTests" -p:OutputPath=bin\\verify_runtime_policy_alignment\\ -p:IntermediateOutputPath=obj\\verify_runtime_policy_alignment\\ (?? 19)
2026-04-15 14:10:38 +09:00
lacvet 4403dc3fc3 ?? ? ? ?? ?? ?? ??? ???? file_write ?? ??? ??
? ?? ???? folder_map, grep, file_read, env_tool, skill_manager, mcp_list_resources ?? ?? ???? ??? ??? AgentLoopCodeRuntimeGuards? ????, ?? ??(C:\ ?) fallback? ?? ? file_write ?? ?? ??? ????? ????.

Code ??? ?? ?? ???? meta tool? ????, direct-creation ????? ?? ??? ?? ??? ?? ???? file_write ?? ???? ????? AgentLoopService? SystemPromptBuilder? ????. ???? ?? <tool_call>? AgentLoopResponseClassificationService?? ??? file_write ??? ???.

AgentLoopE2ETests? AgentLoopResponseClassificationServiceTests? ??? ? ?? ?? ?? fallback ??, skill_manager detour ??, text-embedded file_write ??? ??? ???? README.md? docs/DEVELOPMENT.md? 2026-04-15 14:00 (KST) ?? ??? ????.

??:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_empty_workspace_fix2\\ -p:IntermediateOutputPath=obj\\verify_empty_workspace_fix2\\ (?? 0 / ?? 0)
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "FullyQualifiedName~RunAsync_EmptyWorkspace_BlocksExternalFallbackAndRecoversToFileWrite|FullyQualifiedName~RunAsync_EmptyWorkspace_DisallowsSkillManagerAndRecoversToFileWrite|FullyQualifiedName~RunAsync_TextEmbeddedToolCall_RecoversAndExecutesFileWrite|FullyQualifiedName~Classify_ShouldRecoverToolCallEmbeddedInText" -p:OutputPath=bin\\verify_empty_workspace_fix2_tests\\ -p:IntermediateOutputPath=obj\\verify_empty_workspace_fix2_tests\\ (?? 4)
2026-04-15 14:02:23 +09:00
lacvet f3a31e97b1 AX Agent 진행 이력 파편 메시지 정제 및 렌더링 안정화
- 스트리밍 TextDelta와 Thinking summary에 공통 정제기를 적용해 1, [, file_read] 같은 저품질 파편 문구가 이벤트와 카드에 쌓이지 않도록 개선

- V2 라이브 진행 카드와 이력 렌더링에서 정제된 thinking summary만 표시하고 low-signal 조각은 숨기며 process feed는 안전한 기본 문구로 폴백

- AgentProgressSummarySanitizerTests와 AgentLoopResponseClassificationServiceTests를 추가/확장하고 dotnet build 경고 0 오류 0, 지정 테스트 22건 통과를 확인
2026-04-15 12:51:53 +09:00
lacvet 5e40204e80 AX Agent 상태 메시지 내러티브 고도화 및 코워크/코드 진행 이력 개선
- AgentStatusNarrativeCatalog를 추가해 agent event를 탭(Cowork/Code), 도구 카테고리, 대상 힌트 기준으로 해석하고 상태 메시지/상세 설명/phase label/meta를 한 곳에서 생성하도록 정리함
- ChatWindow의 live pulse 상태, idle 진행 힌트, readable process feed 요약이 동일 narrative 카탈로그를 재사용하도록 변경해 단조로운 도구명 중심 문구를 작업 의도 중심 문구로 치환함
- README, DEVELOPMENT, NEXT_ROADMAP에 2026-04-15 12:14 (KST) 기준 이력과 남은 UX 마감 메모를 반영함

검증 결과
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_status_narrative\\ -p:IntermediateOutputPath=obj\\verify_status_narrative\\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentStatusNarrativeCatalogTests|AgentLoopIterationPreparationServiceTests|AgentToolResultBudgetTests|ChatStorageServiceTests|AgentMessageInvariantHelperTests" -p:OutputPath=bin\\verify_status_narrative_tests\\ -p:IntermediateOutputPath=obj\\verify_status_narrative_tests\\ : 통과 15
2026-04-15 12:15:58 +09:00
lacvet 717d0f2143 SQL 리뷰 계층과 AgentLoop 응답 분해 helper를 추가해 코드 탭 마감 품질을 높임
- SqlReviewService를 추가해 SQL fallback 결과에 review severity, key findings, review checklist를 붙이고 schema migration, seed/reference data, reporting query마다 다른 검토 포인트를 안내하도록 확장했습니다.
- SqlAnalysisService와 CodeLanguageCatalog를 업데이트해 SQL fallback summary와 workflow summary가 rollback notes, dependency order, row-count guard 같은 리뷰 힌트를 직접 포함하도록 보강했습니다.
- AgentLoopResponseClassificationService를 추가해 LLM 응답에서 text/tool_use 분리, no-tool 연속 카운트 계산, thinking summary 생성을 helper로 분리했고 AgentLoopService 본체는 해당 helper를 사용하도록 정리했습니다.
- README, docs/DEVELOPMENT.md, docs/NEXT_ROADMAP.md에 2026-04-15 11:50 (KST) 기준 이력을 반영했습니다.

검증 결과
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_loop_sql_finalize\\ -p:IntermediateOutputPath=obj\\verify_loop_sql_finalize\\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentLoopResponseClassificationServiceTests|AgentLoopLlmRequestPreparationServiceTests|AgentLoopIterationPreparationServiceTests|SqlAnalysisServiceTests|SqlReviewServiceTests|CodeLanguageCatalogTests|WorkspaceContextGeneratorTests" -p:OutputPath=bin\\verify_loop_sql_finalize_tests\\ -p:IntermediateOutputPath=obj\\verify_loop_sql_finalize_tests\\ : 통과 48
2026-04-15 11:51:42 +09:00
lacvet 2a49b1da24 SQL 정적 분석과 PPT·HTML critic을 고도화하고 코드 탭 fallback 문맥을 보강
- SqlAnalysisService에 script intent, dependency, review focus 계산을 추가해 migration/seed/reporting SQL의 위험도와 검토 포인트를 더 정확히 안내하도록 개선했습니다.
- HtmlSkill에 decision_matrix, metric_strip 섹션을 추가하고 ArtifactQualityReviewService/ArtifactRepairGuideService에서 board·strategy 문서의 의사결정 구조와 KPI 연결 부족을 더 정밀하게 진단하도록 강화했습니다.
- DeckQualityReviewService와 DeckRepairGuideService를 확장해 executive summary headline, comparison trade-off, roadmap milestone, chart takeaway, KPI context 부족을 추가로 감지하고 보정 가이드를 반환하도록 정리했습니다.
- WorkspaceContextGenerator와 CodeLanguageCatalog를 업데이트해 SQL 저장소에서 SQL Review Focus와 확장된 workflow summary를 제공하도록 맞췄고, README/DEVELOPMENT/NEXT_ROADMAP에 2026-04-15 11:36 (KST) 기준 이력을 반영했습니다.

검증 결과
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_code_sql_doc_final\\ -p:IntermediateOutputPath=obj\\verify_code_sql_doc_final\\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "SqlDialectDetectorTests|SqlAnalysisServiceTests|CodeLanguageCatalogTests|WorkspaceContextGeneratorTests|ArtifactQualityReviewServiceTests|ArtifactRepairGuideServiceTests|DeckQualityReviewServiceTests|HtmlSkillConsultingSectionsTests" -p:OutputPath=bin\\verify_code_sql_doc_final_tests\\ -p:IntermediateOutputPath=obj\\verify_code_sql_doc_final_tests\\ : 통과 62
2026-04-15 11:38:50 +09:00
lacvet 93c3c647d9 SQL 정적 분석과 PPT·HTML 품질 기준을 강화하고 언어 fallback을 고도화한다
- SQL 전용 정적 분석 계층을 추가해 PostgreSQL/MySQL/SQL Server/SQLite/Oracle 방언 추정, statement kind 분류, object 추출, destructive DDL·broad DML·transaction boundary 위험 감지를 지원한다

- CodeLanguageCatalog의 SQL manifest/build/test/lint 힌트와 fallback summary를 SQL 분석 결과 중심으로 보강해 no-LSP 환경에서도 dialect·risk·next checks를 직접 안내한다

- DeckPlanningService가 구조화된 content 슬라이드를 kpi_dashboard/comparison/roadmap/chart로 자동 승격하고 DeckQualityReviewService·DeckRepairGuideService가 KPI 근거, verdict, owner/timeline, takeaway 부족을 별도 진단·보정한다

- HtmlSkill에 kpi_panel 섹션을 추가하고 ArtifactQualityReviewService·ArtifactRepairGuideService가 board/strategy 문서의 KPI·evidence·decision 연결 부족을 더 정확히 감지하도록 확장한다

- README.md, docs/DEVELOPMENT.md, docs/NEXT_ROADMAP.md에 2026-04-15 11:17 (KST) 기준 작업 이력과 검증 결과를 반영했다

검증 결과

- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_sql_doc_batch\ -p:IntermediateOutputPath=obj\verify_sql_doc_batch\ : 경고 0 / 오류 0

- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter SqlDialectDetectorTests|SqlAnalysisServiceTests|CodeLanguageCatalogTests|DeckPlanningServiceTests|DeckQualityReviewServiceTests|ArtifactQualityReviewServiceTests|ArtifactRepairGuideServiceTests|HtmlSkillConsultingSectionsTests|HtmlSkillGoldenReportTests|PptxSkillGoldenDeckTests -p:OutputPath=bin\verify_sql_doc_batch_tests\ -p:IntermediateOutputPath=obj\verify_sql_doc_batch_tests\ : 통과 47
2026-04-15 11:19:55 +09:00
lacvet f283662d30 AX Agent 루프 마감 복구 규칙을 서비스화하고 회귀 검증을 고정합니다
- AgentLoopService 안에 섞여 있던 도구 미호출 루프/계획 미실행 복구 문구와 재시도 규칙을 AgentLoopNoToolResponseRecoveryService로 분리했습니다.

- probe-only 즉시 복구, 최종 경고 전환, 계획 미실행 재시도 규칙을 별도 테스트로 고정해 루프 마감 품질을 높였습니다.

- README.md, docs/DEVELOPMENT.md, docs/NEXT_ROADMAP.md에 2026-04-15 10:57 (KST) 기준 변경 이력과 검증 결과를 반영했습니다.

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_closeout\\ -p:IntermediateOutputPath=obj\\verify_closeout\\ (경고 0 / 오류 0)

- 검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentLoopNoToolResponseRecoveryServiceTests|AgentLoopIterationPreparationServiceTests|AgentLoopLlmRequestPreparationServiceTests|AgentQueuedCommandProjectorTests|AgentMessageInvariantHelperTests|AgentToolResultBudgetTests|AgentQueryContextBuilderTests|ChatStorageServiceTests|HtmlSkillGoldenReportTests|PptxSkillGoldenDeckTests|DocxSkillGoldenDocumentTests|ExcelSkillGoldenWorkbookTests -p:OutputPath=bin\\verify_closeout_tests\\ -p:IntermediateOutputPath=obj\\verify_closeout_tests\\ (통과 27)
2026-04-15 10:58:47 +09:00
lacvet 48e8c57cf3 ???? ?? ?? ?? ??? ?? fallback ???? ?? ??
- CodeLanguageCatalog? UTF-8 ???? ????? ?? fallback ???? ??? ??? manifest/build/test/lint ?? ?? ??? ????
- WorkspaceContextGenerator? ?? ??? ????? ?? Language Workflow ??? ?????? ??? no-LSP ?????? ?? ??? ?? ??? ?? ???
- AgentLoopLlmRequestPreparationService? ??? ?? tool-call ??? pre-call reminder ?? ??? AgentLoopService?? ???
- CodeLanguageCatalogTests, WorkspaceContextGeneratorTests, AgentLoopLlmRequestPreparationServiceTests? ??? ?? fallback/????/LLM ?? ?? ??? ???
- ??: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_final_batch\\ -p:IntermediateOutputPath=obj\\verify_final_batch\\ (?? 0 / ?? 0)
- ??: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "CodeLanguageCatalogTests|WorkspaceContextGeneratorTests|AgentLoopLlmRequestPreparationServiceTests|AgentLoopIterationPreparationServiceTests|AgentMessageInvariantHelperTests|AgentToolResultBudgetTests|ChatStorageServiceTests|HtmlSkillGoldenReportTests|PptxSkillGoldenDeckTests|DocxSkillGoldenDocumentTests|ExcelSkillGoldenWorkbookTests" -p:OutputPath=bin\\verify_final_batch_tests\\ -p:IntermediateOutputPath=obj\\verify_final_batch_tests\\ (?? 54)
2026-04-15 10:51:44 +09:00
lacvet 91c4dc74c3 에이전트 루프 반복 준비 단계와 tool_result preview 복원 경로를 안정화한다
- AgentLoopIterationPreparationService를 추가해 queued command 투영, tool_result 대기 요약, query view 생성 책임을 AgentLoopService.RunAsync의 반복 진입부에서 분리함
- AgentMessageInvariantHelper의 preview 스냅샷을 explicit id/fingerprint와 synthetic id로 나눠 저장된 preview 우선, fingerprint 재바인딩 차선, synthetic preview 마지막 순서로 복원하도록 정리함
- AgentToolResultBudget이 source query view 기준 snapshot을 먼저 사용하도록 바꿔 source preview가 local synthetic preview에 가려지지 않게 하고 첫 축약 결과도 source message에 다시 저장함
- AgentToolResultBudgetTests와 AgentLoopIterationPreparationServiceTests를 추가/확장해 같은 tool_result의 장기 세션 재사용과 반복 준비 단계 분리를 회귀로 고정함
- README.md와 docs/DEVELOPMENT.md에 2026-04-15 10:34 (KST) 기준 작업 이력과 검증 명령을 반영함

검증 결과
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_loop_pipeline\\ -p:IntermediateOutputPath=obj\\verify_loop_pipeline\\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentQueuedCommandProjectorTests|AgentLoopIterationPreparationServiceTests|AgentMessageInvariantHelperTests|AgentToolResultBudgetTests|AgentQueryContextBuilderTests|ChatStorageServiceTests -p:OutputPath=bin\\verify_loop_pipeline_tests\\ -p:IntermediateOutputPath=obj\\verify_loop_pipeline_tests\\ : 통과 14
2026-04-15 10:35:56 +09:00
lacvet 2c1926356a 문서 품질 critic와 golden 회귀를 고도화해 PPTX·HTML·DOCX·XLSX 마감 품질을 강화한다
- ArtifactQualityReviewService를 확장해 HTML의 board/strategy decision gap, DOCX evidence table·callout 부족, XLSX dashboard trend·variance·sheet summary·headline tile 부족을 개별 이슈로 판정하도록 보강

- ArtifactRepairGuideService와 DeckRepairGuideService를 보강해 decision summary, next steps, evidence table, trend/variance, dashboard tile 등 실제 보강 행동을 바로 제안하는 repair guide를 반환하도록 정리

- ExcelSkill review 입력을 세분화하고 Html/PPT golden 테스트를 strategy brief, PMO steering 시나리오까지 확대해 문서군 golden 회귀 범위를 넓힘

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_finish_batch\\ -p:IntermediateOutputPath=obj\\verify_doc_finish_batch\\ / dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal (ArtifactQualityReviewServiceTests, ArtifactRepairGuideServiceTests, DeckQualityReviewServiceTests, DeckRepairGuideServiceTests, HtmlSkillGoldenReportTests, PptxSkillGoldenDeckTests, DocxSkillGoldenDocumentTests, ExcelSkillGoldenWorkbookTests) -p:OutputPath=bin\\verify_doc_finish_batch_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_finish_batch_tests\
2026-04-15 10:25:44 +09:00
lacvet 06540a0e71 남은 고도화 통합 마감 계획을 문서에 반영한다
목적:
- 남은 문서 포맷, 에이전틱 루프, 개발언어 fallback, 명령/스킬 합성 작업을 한 번에 끝낼 수 있도록 통합 계획을 고정한다.
- 다음 배치부터 그대로 집행할 수 있게 참조 대상, AX 적용 위치, 완료 조건, 품질 판정 기준을 문서에 남긴다.

핵심 수정:
- README.md에 통합 마감 계획 요약과 기준 레퍼런스, 최종 게이트를 추가했다.
- docs/DEVELOPMENT.md에 문서 포맷 최종 마감, AgentLoop/Queue/Context 분리, tool_result replacement state 고정, 개발언어 no-LSP fallback 심화, 명령/스킬 합성 및 릴리즈 게이트 계획을 상세히 기록했다.
- docs/NEXT_ROADMAP.md에 다음 구현 배치의 실행 순서와 품질 판정 기준을 반영했다.

검증 결과:
- 문서 계획 반영 작업으로 코드/바이너리 변경은 없으며, 다음 배치의 구현 기준선 문서 정합성을 맞췄다.
2026-04-15 10:11:42 +09:00
lacvet 8c0aa98408 에이전트 루프 수명주기와 tool_result 복원 품질을 마감한다
목적:
- AgentLoopService 시작/종료 책임을 분리해 루프 본체를 더 얇은 orchestration 구조로 정리한다.
- 장기 세션과 분기 대화에서 tool_result preview가 다른 tool_use_id로 재등장해도 안정적으로 복원되도록 replacement state를 보강한다.
- DOCX/PPTX/XLSX 반환 경로까지 문서 품질 출력 formatter를 통일해 포맷별 quality summary와 repair guide 표현을 일관되게 맞춘다.

핵심 수정:
- AgentLoopRunLifecycle.cs를 추가해 BeginRun/BootstrapRunAsync/FinalizeRun/ResetRunTransientState를 분리하고, AgentLoopService는 해당 helper를 사용하도록 정리했다.
- run 종료 metric에 빈 run id가 기록되던 흐름을 수정해 실제 run id가 유지되도록 고쳤다.
- AgentMessageInvariantHelper에 persisted preview map, fingerprint preview map, tool_use_id 재바인딩 로직을 추가해 저장/재개/분기 이후 preview 복원 품질을 높였다.
- ArtifactQualityOutputFormatter를 DocxSkill, PptxSkill, ExcelSkill 멀티시트 출력 경로까지 연결해 quality summary/repair guide 문자열 조립을 공통 helper로 통일했다.
- AgentMessageInvariantHelperTests에 fingerprint 재바인딩 회귀를 추가했다.
- README.md, docs/DEVELOPMENT.md, docs/NEXT_ROADMAP.md에 2026-04-15 10:05 (KST) 기준 변경 이력을 반영했다.

검증 결과:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_run_finalize\\ -p:IntermediateOutputPath=obj\\verify_run_finalize\\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentCommandQueueTests|AgentQueuedCommandProjectorTests|AgentMessageInvariantHelperTests|AgentQueryContextBuilderTests|ChatStorageServiceTests|PptxSkillGoldenDeckTests|ExcelSkillGoldenWorkbookTests|DocxSkillGoldenDocumentTests|HtmlSkillGoldenReportTests -p:OutputPath=bin\\verify_run_finalize_tests2\\ -p:IntermediateOutputPath=obj\\verify_run_finalize_tests2\\ : 통과 18
2026-04-15 10:07:01 +09:00
lacvet bcb3cc4039 개발언어 워크플로 힌트와 문서 품질 출력 경로를 고도화한다
- CodeLanguageCatalog에 manifest/build/test/lint 조회 API와 workflow summary 조합기를 추가해 no-LSP fallback과 컨텍스트 생성이 같은 힌트 소스를 재사용하도록 정리한다.

- WorkspaceContextGenerator에 Language Workflow 섹션을 추가해 상위 언어의 실행 힌트를 .ax-context.md에 기록하고, HtmlSkill/ExcelSkill은 공통 ArtifactQualityOutputFormatter로 품질 요약과 repair guide를 일관되게 출력하도록 맞춘다.

- README.md, docs/DEVELOPMENT.md, docs/NEXT_ROADMAP.md를 2026-04-15 09:49 (KST) 기준으로 갱신하고, CodeLanguageCatalogTests 및 WorkspaceContextGeneratorTests를 확장해 빌드 경고 0/오류 0과 관련 테스트 35건 통과를 확인한다.
2026-04-15 09:52:36 +09:00
lacvet baafd8280c 에이전트 루프 진단과 문서 golden 회귀를 마감한다
- AgentLoopService의 컨텍스트 압축 완료 메시지와 query-view 요약 문자열 조립을 AgentLoopDiagnosticsFormatter로 분리해 루프 본체의 책임을 더 줄였다.

- ChatStorageService 로드 경로에서 legacy .axchat의 누락된 tool_result preview를 synthetic preview로 즉시 복원하도록 보강했다.

- HTML/DOCX golden 회귀와 legacy 저장 경로 회귀 테스트를 추가해 PPTX/XLSX에 이어 문서 품질 고정 범위를 확대했다.

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_loop_storage_golden\ -p:IntermediateOutputPath=obj\verify_loop_storage_golden\ (경고 0, 오류 0)

- 검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentLoopDiagnosticsFormatterTests|ChatStorageServiceTests|HtmlSkillGoldenReportTests|DocxSkillGoldenDocumentTests|AgentMessageInvariantHelperTests|PptxSkillGoldenDeckTests|ExcelSkillGoldenWorkbookTests -p:OutputPath=bin\verify_loop_storage_golden_tests\ -p:IntermediateOutputPath=obj\verify_loop_storage_golden_tests\ (통과 10)
2026-04-15 09:21:55 +09:00
lacvet 8530ec956a ?? ?? tool_result preview ??? ???? golden workbook ??? ??
?? ??
- ??, ??, ?? ?? tool_result preview? ??? ??? ???? replacement state? ?? ??? ? ??? ??? ?? ??? ??
- XLSX ?? ?? ??? ?? ?? ?? workbook golden ??? ??? summary/dashboard/detail ??? ????? ??

?? ????
- AgentMessageInvariantHelper? synthetic tool_result preview ?? ??? ??? QueryPreviewContent? ?? ?? ?? ??? tool_use_id, tool_name, ??? content/output/error ?? preview? ????? ??
- BuildToolResultPreviewMap? ?? preview? ?? ???? ?? ?? synthetic preview? ?? ??? ??
- AgentMessageInvariantHelperTests? ??? preview? ?? long tool_result? synthetic preview? ???? ??? explicit preview ?? ?? ??? ?? ??
- AgentQueryContextBuilderTests? synthetic preview? query view ?? ? ?? ???? ???? ????? ??
- ExcelSkillGoldenWorkbookTests? ??? summary/dashboard/detail, formula, data validation, conditional formatting? ??? ?? ?? workbook? Needs work: none ? Repair guide: none? ????? ??
- README.md? docs/DEVELOPMENT.md? 2026-04-15 09:36 (KST) ?? ?? ??? ?? ??? ??

?? ??
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_preview_golden_finish\\ -p:IntermediateOutputPath=obj\\verify_preview_golden_finish\\ : ?? 0 / ?? 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentMessageInvariantHelperTests|AgentQueryContextBuilderTests|AgentQueuedCommandProjectorTests|ExcelSkillGoldenWorkbookTests|ExcelSkillDashboardSummaryTests|PptxSkillGoldenDeckTests" -p:OutputPath=bin\\verify_preview_golden_finish_tests\\ -p:IntermediateOutputPath=obj\\verify_preview_golden_finish_tests\\ : ?? 10
2026-04-15 09:11:56 +09:00
lacvet ff29a83039 ???? ?? ? ??? ???? workbook/deck ?? ??? ??
?? ??
- AgentLoopService? ?? ?? ? ?? ??? ?? ??? ??? ?? ??? ? ??? ??? ??? ??
- XLSX dashboard workbook? PPT deck? ?? ?? ??? ??? ?? dashboard, storyline ?? ????? ? ? ????? ??

?? ????
- AgentQueuedCommandProjector? ??? queued command ??? queued_input_interrupt, queue_notification, queue_resume, queued_prompt ?? ???? thinking/user ???? ???? ?? helper? ??
- AgentLoopService? drain? ? ??? ?? switch? ?? ?? projector ??? ???? ??? ???
- ArtifactQualityReviewService? dashboard sheet? KPI, trend, decision ?? ?? ??? ???? workbook review ??? ??
- ArtifactRepairGuideService? ? dashboard ??? core story ?? ?? ???? ????? ??
- DeckQualityReviewService? storyline? Options, Roadmap, Appendix? ????? ?? ????? ?? ? ?? ?? ??? ????? ??
- DeckRepairGuideService? storyline ?? ??? deck storyline ?? ???? ????? ??
- AgentQueuedCommandProjectorTests, DeckQualityReviewServiceTests, ArtifactQualityReviewServiceTests, ArtifactRepairGuideServiceTests, DeckRepairGuideServiceTests? ??? ??? ??
- README.md? docs/DEVELOPMENT.md? 2026-04-15 09:24 (KST) ?? ??? ?? ??? ??

?? ??
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_loop_doc_finish2\\ -p:IntermediateOutputPath=obj\\verify_loop_doc_finish2\\ : ?? 0 / ?? 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentQueuedCommandProjectorTests|AgentCommandQueueTests|ArtifactQualityReviewServiceTests|ArtifactRepairGuideServiceTests|DeckQualityReviewServiceTests|DeckRepairGuideServiceTests|PptxSkillGoldenDeckTests|ExcelSkillDashboardSummaryTests" -p:OutputPath=bin\\verify_loop_doc_finish2_tests\\ -p:IntermediateOutputPath=obj\\verify_loop_doc_finish2_tests\\ : ?? 25
2026-04-15 08:58:19 +09:00
lacvet 918d62b8d5 ?? ?? ??? ?? ??? ??? ???? DOCX ???? ?? ??? ?? ??? ??
?? ??
- ?? ?? ?? critic/repair ?? ?? ??? ??? DOCX/XLSX/HTML/PPT ??? ? ???? ?? ???? ????? ??
- ??? ????? DOCX ?? ??? ? ????? ????? ?? ??? ?? ??? ??

?? ????
- ArtifactQualityReviewService? DOCX ?? ??? cover, ??, ???, header/footer ?? ??? ???? XLSX dashboard workbook? highlight/action, detail navigation, trend/variance formula ?? ??? ??
- ArtifactRepairGuideService? ? ?? ??? ?? ?? ???? ??? ??? ???? HTML/DOCX/XLSX ??? ???? ? ???
- DeckRepairGuideService? appendix/evidence ??? duplicate headline ??? ?? ???? ??? deck ?? ???? ??
- DocxSkill? Repair guide? ??? ?? ????? ???? Executive Summary/Recommendation/Appendix ?? ??? ?? ???? ??
- ArtifactQualityReviewServiceTests, ArtifactRepairGuideServiceTests, DeckRepairGuideServiceTests, DocxSkillTemplateFeaturesTests? ??? ??? ??
- README.md? docs/DEVELOPMENT.md? 2026-04-15 09:05 (KST) ?? ??? ?? ??? ??

?? ??
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_repair_finalize\\ -p:IntermediateOutputPath=obj\\verify_doc_repair_finalize\\ : ?? 0 / ?? 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ArtifactQualityReviewServiceTests|ArtifactRepairGuideServiceTests|DeckRepairGuideServiceTests|DocxSkillTemplateFeaturesTests" -p:OutputPath=bin\\verify_doc_repair_finalize_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_repair_finalize_tests\\ : ?? 11
2026-04-15 08:48:04 +09:00
lacvet 6b3e5e6797 preview 상태 고정과 no-LSP 언어 fallback 마감
목적:
- 긴 세션, compact, query view 생성 시점에도 tool_result preview 축약 상태를 더 안정적으로 유지합니다.
- 격리 환경에서 로컬 LSP 서버가 없더라도 코드 탭이 언어별 정적 분석 힌트를 계속 제공하도록 마감합니다.
- 설정/프롬프트/로드맵 문서까지 현재 구현 상태와 일치시키고 남은 고도화 범위를 정리합니다.

핵심 수정:
- AgentQueryContextBuilder와 ContextCondenser가 query/compact 진입 전에 누락된 tool_result preview를 먼저 복원하도록 정리했습니다.
- AgentToolResultBudget는 sourceMessages가 없는 호출에서도 현재 window의 tool_use_id preview를 재사용하도록 보강했습니다.
- CodeLanguageCatalog에 언어별 manifest/build/test/lint fallback 힌트를 추가하고, LspTool은 LSP 서버 미가동 시 정적 fallback 안내를 반환하도록 변경했습니다.
- SettingsViewModel, SettingsWindow, ChatWindow.SystemPromptBuilder에 Fallback 분석 설명과 LSP 미사용 시 대체 분석 지침을 반영했습니다.
- AgentQueryContextBuilderTests를 새로 추가하고 AgentToolResultBudgetTests, CodeLanguageCatalogTests를 확장했습니다.
- README.md, docs/DEVELOPMENT.md, docs/AGENT_ROADMAP.md, docs/NEXT_ROADMAP.md를 2026-04-15 08:32 (KST) 기준으로 갱신했습니다.

검증:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_loop_lang_finish\\ -p:IntermediateOutputPath=obj\\verify_loop_lang_finish\\
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentToolResultBudgetTests|AgentQueryContextBuilderTests|CodeLanguageCatalogTests|ContextCondenserTests" -p:OutputPath=bin\\verify_loop_lang_finish_tests\\ -p:IntermediateOutputPath=obj\\verify_loop_lang_finish_tests\\ (통과 20)
2026-04-15 08:34:24 +09:00
lacvet 7c138f8ed9 tool_result preview 복원과 슬래시 명령 합성 일원화
목적:
- 긴 세션, 분기, 재시작 이후에도 tool_result preview 축약 상태를 더 안정적으로 유지합니다.
- 슬래시 팔레트와 실제 /토큰 실행 해석이 어긋나지 않도록 built-in command와 skill 우선순위를 같은 규칙으로 맞춥니다.

핵심 수정:
- AgentMessageInvariantHelper에 tool_use_id 기준 preview 맵/복원 helper를 추가했습니다.
- ChatSessionStateService는 분기 대화 생성 시 QueryPreviewContent를 함께 복사하고, 저장된 대화를 다시 열 때 누락된 preview를 복원합니다.
- ChatStorageService는 저장 직전에 누락된 tool_result preview를 먼저 채워 재시작 후 축약 상태가 흔들리지 않게 정리했습니다.
- SlashCommandCatalog에 exact token 충돌 해석용 ResolvePreferredCommand를 추가하고, ChatWindow.ParseSlashCommandAsync가 built-in/skill 후보를 함께 모아 같은 우선순위 규칙으로 실행 대상을 선택하도록 맞췄습니다.
- SlashCommandCatalogTests를 새로 추가하고 ChatSessionStateServiceTests를 확장해 preview 복원과 skill 우선 해석을 회귀 검증했습니다.
- README.md, docs/DEVELOPMENT.md를 2026-04-15 07:16 (KST) 기준으로 갱신했습니다.

검증:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_preview_state\\ -p:IntermediateOutputPath=obj\\verify_preview_state\\
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentToolResultBudgetTests|ChatSessionStateServiceTests" -p:OutputPath=bin\\verify_preview_state_tests\\ -p:IntermediateOutputPath=obj\\verify_preview_state_tests\\ (통과 38)
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_command_resolution\\ -p:IntermediateOutputPath=obj\\verify_command_resolution\\
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "SlashCommandCatalogTests|ChatSessionStateServiceTests|AgentToolResultBudgetTests|AgentCommandQueueTests" -p:OutputPath=bin\\verify_command_resolution_tests\\ -p:IntermediateOutputPath=obj\\verify_command_resolution_tests\\ (통과 50)
2026-04-15 07:18:40 +09:00
lacvet 07fd2267cb 에이전트 큐 우선순위 소비와 tool_result preview 재사용 안정화
목적:
- claude-code 대비 남아 있던 에이전틱 루프/큐/컨텍스트 격차를 줄이기 위한 1차 배치를 반영한다.
- 낮은 우선순위 알림이 같은 턴에 섞여 들어오던 흐름과 tool_result preview가 MsgId에만 묶여 재사용되던 한계를 개선한다.

핵심 수정:
- AgentCommandQueue를 snapshot/peek/dequeue/dequeueAllMatching/dequeuePriorityBatch를 지원하는 우선순위 큐로 재구성했다.
- AgentLoopService가 전체 큐를 한 번에 비우지 않고 같은 우선순위 배치만 소비하도록 조정했다.
- AgentToolResultBudget가 QueryPreviewContent를 tool_use_id 단위로 재사용하도록 확장해 재구성된 tool_result 메시지에서도 동일 preview를 유지한다.
- AgentCommandQueueTests, AgentToolResultBudgetTests를 확장해 priority batch dequeue, predicate matching, tool_use_id preview reuse를 회귀 검증한다.
- README와 DEVELOPMENT 문서에 2026-04-15 07:00 (KST) 기준 이력과 다음 통합 고도화 계획을 반영했다.

검증:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_queue_preview\ -p:IntermediateOutputPath=obj\verify_queue_preview\
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentCommandQueueTests^|AgentToolResultBudgetTests -p:OutputPath=bin\verify_queue_preview_tests\ -p:IntermediateOutputPath=obj\verify_queue_preview_tests"
2026-04-15 07:01:45 +09:00
lacvet f33ee7f7db ???? ???? ?? ????????? ????? ?? ????? 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\\
2026-04-15 00:21:15 +09:00
lacvet 59ec4a1371 문서 repair guide와 목적형 HTML/XLSX 경로를 추가 고도화
- ArtifactRepairGuideService를 추가해 HTML/XLSX/DOCX 품질 리뷰 결과를 Repair guide 형태의 실행 가능한 보정 지침으로 변환
- HtmlSkill, ExcelSkill, DocumentAssemblerTool 출력에 repair guide를 연결해 품질 점수 뒤에 후속 보완 방향을 함께 제공
- Excel dashboard sheet에 dashboard_tiles와 variance_series를 추가해 운영 리뷰형 workbook archetype을 강화
- strategy-brief-html, operating-review-xlsx 번들 스킬을 추가해 목적형 문서 생성 진입점을 확장
- README.md와 docs/DEVELOPMENT.md에 2026-04-14 23:58 (KST) 기준 작업 이력과 검증 명령을 반영

검증 결과
- 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
2026-04-14 23:59:09 +09:00
lacvet e1f6caf11a HTML archetype·Excel dashboard·PPT 골든 회귀를 추가 고도화
- HtmlSkill에 board_report와 strategy_brief 구조화 섹션 타입을 추가해 이사회 보고형/전략 요약형 HTML 산출물 표현력을 확장
- ArtifactQualityReviewService HTML 리뷰에 board-report-panel, strategy-brief-panel 인식과 보완 포인트 규칙을 추가
- Excel dashboard sheet에 KPI, highlights, actions를 함께 렌더링해 executive dashboard 시트 밀도를 강화
- PptxSkillGoldenDeckTests에 strategy deck 회귀 샘플을 추가해 strong 전략 덱 품질 기준을 고정
- README.md와 docs/DEVELOPMENT.md에 2026-04-14 23:32 (KST) 기준 이력과 검증 명령을 반영

검증 결과
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_next5\\ -p:IntermediateOutputPath=obj\\verify_doc_next5\\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ArtifactQualityReviewServiceTests|ExcelSkillDashboardSummaryTests|HtmlSkillConsultingSectionsTests|HtmlSkillPrintFrameTests|DeckQualityReviewServiceTests|PptxSkillGoldenDeckTests|PptxSkillAutoRepairTests|PptxSkillConsultingDeckTests -p:OutputPath=bin\\verify_doc_next5_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_next5_tests\\ : 통과 14
2026-04-14 23:33:23 +09:00
lacvet 116c420bf6 문서 대시보드·DOCX 스타일맵·PPT 골든 회귀를 고도화하고 검증 추가
- ExcelSkill에 summary_sheet 기반 Dashboard 시트 생성을 추가해 Summary -> Dashboard -> Detail 시트 흐름을 지원
- ArtifactQualityReviewService workbook 리뷰에 dashboard 존재 여부를 반영하고 multi-sheet workbook 보완 포인트를 강화
- DocumentAssemblerTool style_map 범위를 cover_subtitle/callout/table_header까지 확장해 템플릿 기반 DOCX 조립 품질을 개선
- Excel/DOCX/PPT 회귀 테스트를 확장하고 PptxSkillGoldenDeckTests를 추가해 strong deck 품질 기준을 고정
- README.md와 docs/DEVELOPMENT.md에 2026-04-14 23:25 (KST) 기준 작업 이력과 검증 명령을 반영

검증 결과
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_next4\\ -p:IntermediateOutputPath=obj\\verify_doc_next4\\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ArtifactQualityReviewServiceTests|DocumentAssemblerStyleMapTests|DocumentAssemblerDocxFeaturesTests|DocumentAssemblerSemanticTests|ExcelSkillDashboardSummaryTests|ExcelSkillSummarySheetTests|ExcelSkillExecutiveSummaryLinkTests|ExcelSkillDataValidationTests|ExcelSkillConditionalFormattingTests|HtmlSkillPrintFrameTests|HtmlSkillConsultingSectionsTests|DeckQualityReviewServiceTests|PptxSkillAutoRepairTests|PptxSkillConsultingDeckTests|PptxSkillGoldenDeckTests -p:OutputPath=bin\\verify_doc_next4_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_next4_tests\\ : 통과 20
2026-04-14 23:26:59 +09:00
lacvet 2e36f2fef1 문서 고도화 다음 단계를 반영해 XLSX·HTML·PPT 품질 게이트를 강화했습니다
핵심 수정사항:
- ExcelSkill summary_sheet에 trend_series를 추가해 Trend Dashboard 블록을 렌더링하고, workbook quality review가 dashboard형 summary 구성을 더 정확히 평가하도록 확장했습니다.
- HtmlSkill은 print=true인데 print_header/print_footer가 없는 경우 기본 print frame을 자동 생성하도록 보강했고, ArtifactQualityReviewService는 print-ready 문서의 frame/decision/evidence/cover 부족을 추가 경고로 반환합니다.
- DeckPlanningService는 comparison, roadmap, executive_summary, kpi_dashboard 슬라이드의 최소 구조를 자동 보정하고, DeckQualityReviewService는 slide-level quality gate를 추가해 긴 headline, 과밀 슬라이드, 옵션 부족, 표/차트 데이터 누락을 Slide N 경고로 요약합니다.
- DeckQualityReviewServiceTests, ExcelSkillDashboardSummaryTests, HtmlSkillPrintFrameTests를 확장해 회귀 검증을 강화했습니다.

검증 결과:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_next3\\ -p:IntermediateOutputPath=obj\\verify_doc_next3\\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "DeckQualityReviewServiceTests|PptxSkillAutoRepairTests|PptxSkillConsultingDeckTests|ExcelSkillDashboardSummaryTests|ExcelSkillSummarySheetTests|HtmlSkillPrintFrameTests|HtmlSkillConsultingSectionsTests|ArtifactQualityReviewServiceTests" -p:OutputPath=bin\\verify_doc_next3_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_next3_tests\\ : 통과 13
2026-04-14 23:16:00 +09:00
lacvet 1edeffa206 문서 고도화 다음 단계를 반영해 엑셀 summary와 DOCX 조립 품질을 끌어올렸습니다
핵심 수정사항:
- ExcelSkill summary_sheet에 decision_summary, scorecards, sheet_summaries를 추가해 dashboard형 summary 시트를 생성하도록 확장했습니다.
- ArtifactQualityReviewService의 workbook 리뷰 입력을 확장해 KPI/decision/detail summary 존재 여부를 품질 점수와 보완 포인트에 반영했습니다.
- DocumentAssemblerTool에 style_map 파라미터를 추가해 template 기반 DOCX 조립에서 title/heading/body 문단 스타일을 실제 Word 스타일로 매핑하도록 개선했습니다.
- DocumentAssemblerStyleMapTests, ExcelSkillDashboardSummaryTests를 추가하고 기존 ArtifactQualityReviewServiceTests를 갱신했습니다.

검증 결과:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_next2\\ -p:IntermediateOutputPath=obj\\verify_doc_next2\\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ArtifactQualityReviewServiceTests|DocumentAssemblerStyleMapTests|DocumentAssemblerDocxFeaturesTests|DocumentAssemblerSemanticTests|ExcelSkillDashboardSummaryTests|ExcelSkillSummarySheetTests|ExcelSkillExecutiveSummaryLinkTests|ExcelSkillDataValidationTests|ExcelSkillConditionalFormattingTests" -p:OutputPath=bin\\verify_doc_next2_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_next2_tests\\ : 통과 11
2026-04-14 23:06:53 +09:00
lacvet 3232db1b12 ?? ?? ?? ???? PPTX ??? ? ?? ??
?? ?? ??? PPTX/DOCX/XLSX/HTML ???? ? ?????, PPTX? ???? ??? ? ???? ?? ???? ? ??? ?? ?? ???? ????.

?? ????:
- ExcelSkill? conditional_formats? ??? ?? ???? ??? ? ?????? OpenXML? ?? ???? workbook quality review? ??
- DocxSkill? style_map? ??? ???? ??/??/?? ???? ?? ?? ParagraphStyleId? ??
- HtmlSkill? print_header/print_footer ?? ?? ???? ???? ArtifactQualityReviewService? ?? ?? ?? ???? ??
- PptxTemplatePackRegistry? PptxSkill template_pack ????? ??? strategy/board/pmo/finance/sales/operating_model ??? ??? ?? ?? ?? ??? ??
- ?????, ????, ?? ???, ??? ?? ?? ?? ???? ???? ?? ?? ?? ???? ???? ???? ??

?? ??:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_next_doc_ppt\\ -p:IntermediateOutputPath=obj\\verify_next_doc_ppt\\ => ?? 0 / ?? 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ArtifactQualityReviewServiceTests|ExcelSkillDataValidationTests|ExcelSkillConditionalFormattingTests|ExcelSkillExecutiveSummaryLinkTests|ExcelSkillSummarySheetTests|DocxSkillTemplateFeaturesTests|DocxSkillStyleMapTests|HtmlSkillConsultingSectionsTests|HtmlSkillPrintFrameTests|DocumentAssemblerDocxFeaturesTests|PptxSkillConsultingDeckTests|PptxSkillAutoRepairTests|PptxSkillTemplatePackTests" -p:OutputPath=bin\\verify_next_doc_ppt_tests\\ -p:IntermediateOutputPath=obj\\verify_next_doc_ppt_tests\\ => ?? 15
2026-04-14 22:54:24 +09:00
lacvet 5607f6391e ?? ??? 3?? DOCX ????XLSX ?? ???HTML ???? ?? ??
- DocumentAssemblerTool? template_path/page_numbers? ??? DOCX ??? ??, ??????????? ?? ??? ??
- ExcelSkill? data_validations? ???? ??/??/?? ?? ??? ?? ??? ?? ?? ?? ??
- HtmlSkill? ArtifactQualityReviewService? decision_summary/evidence_cards ??? ?? ?? ?? ??? ??
- DocumentAssemblerDocxFeaturesTests, HtmlSkillConsultingSectionsTests, ExcelSkillDataValidationTests? ?? ??? ??
- README.md? docs/DEVELOPMENT.md? 2026-04-14 22:28 (KST) ???? ??

??:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_phase_next\\ -p:IntermediateOutputPath=obj\\verify_doc_phase_next\\ (?? 0 / ?? 0)
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "DocumentAssemblerDocxFeaturesTests|DocumentAssemblerSemanticTests|DocumentPlannerWorkbookScaffoldTests|ExcelSkillExecutiveSummaryLinkTests|ExcelSkillSummarySheetTests|ExcelSkillDataValidationTests|HtmlSkillConsultingSectionsTests|DocxSkillTemplateFeaturesTests|DocumentPlannerBusinessDocumentTests" -p:OutputPath=bin\\verify_doc_phase_next_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_phase_next_tests\\ (?? 9)
2026-04-14 22:31:15 +09:00
lacvet 1ad5eea32e ?? planner/assembler ??? 2? ??
?? ??:
- Word/HTML/Excel ?? ?? ??? PPT ??? planner ?? ??? ? ??? ??? ?? ?? ??? ?????.
- ??? ???? document_plan ???? ?? ??? ? ??? xlsx scaffold ??? ?????.

?? ????:
- DocumentPlannerTool? format:xlsx ??? ???? summary_sheet + sheets ??? excel_create scaffold? ????? ??????.
- DocumentPlannerTool? ?? ?? ??? workbook/tracker/dashboard/scorecard ???? ????? ??????.
- DocumentAssemblerTool? DOCX ?? ??? cover_subtitle, TOC, header/footer ??? ???? ?? ???? DOCX ?? ?? ??? ??????.
- DocumentAssemblerTool? HTML ?? ??? ArtifactQualityReviewService? ??? score ?? ?? ??? ????? ??????.
- kpi-workbook ???? document_plan ??? ??? complex workbook ?? ? planner ??? ??? ? ?? ????.
- ?? ?? ???? DocumentPlannerWorkbookScaffoldTests, DocumentAssemblerDocxFeaturesTests? ??????.
- README.md? docs/DEVELOPMENT.md? 2026-04-14 22:14 (KST) ?? ?? ??? ??????.

?? ??:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_planning2\\ -p:IntermediateOutputPath=obj\\verify_doc_planning2\\ : ?? 0 / ?? 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "DocumentPlannerWorkbookScaffoldTests|DocumentAssemblerDocxFeaturesTests|DocumentAssemblerSemanticTests|DocumentPlannerBusinessDocumentTests|ExcelSkillExecutiveSummaryLinkTests|HtmlSkillConsultingSectionsTests|DocxSkillTemplateFeaturesTests" -p:OutputPath=bin\\verify_doc_planning_tests3\\ -p:IntermediateOutputPath=obj\\verify_doc_planning_tests3\\ : ?? 7
2026-04-14 22:15:50 +09:00
lacvet 8571a83ed0 PPT 생성 고도화 3차를 반영하고 deck planning·quality gate를 추가
- DeckPlanningService와 DeckQualityReviewService를 추가해 deck brief 정규화, consulting storyline 보강, 누락된 Executive Summary/Recommendation/Roadmap/Appendix 자동 보강, deck-level 품질 점수와 경고 계산을 지원합니다.

- PptxSkill에 audience/objective/decision_ask/storyline 파라미터를 추가하고, issue_tree/before_after/decision_matrix/risk_heatmap/benefit_waterfall/operating_model/appendix_evidence 레이아웃을 네이티브 슬라이드 타입으로 정규화한 뒤 planning summary와 quality summary를 함께 반환하도록 보강했습니다.

- pptx-creator 및 strategy-deck/board-update/pmo-steering/sales-review-deck/operating-model-deck 번들 스킬을 추가·정리하고, DeckPlanningServiceTests/DeckQualityReviewServiceTests/PptxSkillAutoRepairTests로 회귀 검증을 보강했습니다.

- README.md와 docs/DEVELOPMENT.md에 2026-04-14 21:50, 22:00 (KST) 기준 변경 이력과 검증 결과를 반영했습니다.

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_ppt_phase3\ -p:IntermediateOutputPath=obj\verify_ppt_phase3\ (경고 0 / 오류 0)

- 검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter 'DeckPlanningServiceTests|DeckQualityReviewServiceTests|PptxSkillAutoRepairTests|PptxSkillConsultingDeckTests' -p:OutputPath=bin\verify_ppt_phase3_tests\ -p:IntermediateOutputPath=obj\verify_ppt_phase3_tests\ (통과 5)
2026-04-14 22:01:41 +09:00
lacvet 6c7fba9dff 문서 생성 품질 게이트와 산출물 고도화 2차 반영
공통 ArtifactQualityReviewService를 추가해 HTML, DOCX, XLSX 결과물에 로컬 품질 점수와 보완 포인트를 부여했습니다.

DocxSkill에 template_path, cover_subtitle, cover_meta, toc 흐름을 붙여 템플릿 기반 문서와 커버/목차 생성을 강화했고, Excel summary sheet에는 detail sheet 링크와 workbook review를 연결했습니다. HtmlSkill도 결과 요약에 품질 리뷰를 포함하도록 보강했습니다.

executive-brief, kpi-workbook, board-report-html 번들 스킬을 추가했고, ArtifactQualityReviewServiceTests, DocxSkillTemplateFeaturesTests, ExcelSkillExecutiveSummaryLinkTests를 포함한 관련 테스트를 보강했습니다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_doc_phase2\ -p:IntermediateOutputPath=obj\verify_doc_phase2\ (경고 0 / 오류 0)

검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ArtifactQualityReviewServiceTests|DocxSkillTemplateFeaturesTests|ExcelSkillExecutiveSummaryLinkTests|DocumentAssemblerSemanticTests|DocumentPlannerBusinessDocumentTests|HtmlSkillConsultingSectionsTests|ExcelSkillSummarySheetTests -p:OutputPath=bin\verify_doc_phase2_tests\ -p:IntermediateOutputPath=obj\verify_doc_phase2_tests\ (통과 9)
2026-04-14 21:26:58 +09:00
lacvet d9cb02f3c4 문서 생성 고도화 1차: 네이티브 워드·엑셀·HTML 경로 정렬 및 품질 보강
- Word/Excel/HTML 스킬을 Python 우회 중심에서 AX 네이티브 문서 도구 우선 경로로 재작성했습니다.

- DocumentPlannerTool의 보고서·제안서·분석 문서 아웃라인을 Executive Summary, Business Case, Decision Ask, Appendix 중심의 업무형 구조로 확장했습니다.

- DocumentAssemblerTool의 DOCX 조립 경로에서 표·목록·콜아웃·소제목 같은 HTML/Markdown 구조를 더 보존하도록 개선했습니다.

- ExcelSkill에 summary_sheet를 추가해 KPI·핵심 인사이트·후속 과제를 담은 요약 시트를 상세 데이터 시트 앞에 생성할 수 있게 했습니다.

- HtmlSkill에 comparison, roadmap, matrix 구조화 섹션을 추가하고 sections 중심 호출 스키마를 정리했습니다.

- DocumentAssemblerSemanticTests, ExcelSkillSummarySheetTests, HtmlSkillConsultingSectionsTests, DocumentPlannerBusinessDocumentTests를 추가했습니다.

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_phase1\\ -p:IntermediateOutputPath=obj\\verify_doc_phase1\

- 검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter 문서_고도화_테스트_5건 -p:OutputPath=bin\\verify_doc_phase1_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_phase1_tests\
2026-04-14 21:02:08 +09:00
lacvet 0b6d60e959 에이전트 루프와 코드 언어 지원, PPT 생성 품질을 함께 고도화
- AgentCommandQueue를 도입해 실행 중 추가 입력을 우선순위와 인터럽트 여부까지 포함해 처리하도록 정리함
- AgentToolResultBudget와 AgentQueryContextBuilder에 tool result preview 캐시를 연결해 긴 세션에서 축약 결과 재사용을 안정화함
- CodeLanguageCatalog를 추가해 코드 탭의 내장 언어 지원, 인덱싱 확장자, 시스템 프롬프트 언어 가이드, LSP 언어 판정을 한 카탈로그로 통합함
- 설정의 코드 탭에 지원 언어(LSP)와 코드 탭 기본 지원 언어를 명시적으로 표시하도록 보강함
- DocumentPlannerTool의 presentation 구조를 컨설팅형 스토리라인으로 정리하고, PptxSkill에 executive_summary/recommendation/roadmap/comparison/kpi_dashboard 레이아웃을 추가함
- pptx-creator 스킬을 AX native pptx_create 중심으로 재작성하고, 관련 회귀 테스트를 추가했으며 WorkspaceContextGeneratorTests의 nullable 경고도 정리함

검증 결과
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_impl\\ -p:IntermediateOutputPath=obj\\verify_impl\\
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "CodeLanguageCatalogTests|AgentCommandQueueTests|AgentToolResultBudgetTests|DocumentPlannerPresentationTests|PptxSkillConsultingDeckTests" -p:OutputPath=bin\\verify_impl_tests\\ -p:IntermediateOutputPath=obj\\verify_impl_tests\\
2026-04-14 19:53:39 +09:00
lacvet 946c31e275 AX Agent ?? ?? ??? MCP ?? ??? ???? ??? ??? ??
- MCP ?? ?????? synthetic skill? ???? McpSkillCatalog? ???? ToolRegistry ?? snapshot ?? ??? ???
- managed/user/additional/project/plugin/mcp/legacy ?? source ??, plugin-only ??, source? inline shell trust boundary? SkillService/AppSettings/Settings UI? ???
- SlashCommandCatalog? ChatWindow?? builtin command? skill? ???? ???? ??? ?? ? ????? dedupe?? MCP ???? ? synthetic skill ?? ??? SkillGallery/AgentSettings? ???
- README.md? docs/DEVELOPMENT.md? 2026-04-14 19:13 (KST) ?? ?? ??? ?? ??? ???
- ??: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_phase4\\ -p:IntermediateOutputPath=obj\\verify_phase4\\ (?? 0, ?? 0)
- ??: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "SkillServiceRuntimePolicyTests|SlashCommandCatalogTests|McpSkillCatalogTests" -p:OutputPath=bin\\verify_phase4_tests\\ -p:IntermediateOutputPath=obj\\verify_phase4_tests\\ (?? 17, ?? WorkspaceContextGeneratorTests.cs nullable ?? 1? ??)
2026-04-14 19:15:12 +09:00
lacvet 3747a92c12 분석 로그를 1MB 롤링과 14일 보관 기준으로 정리한다
- app/perf/audit/workflow 로그에 공통 RollingTextLogStore를 적용해 날짜별 파일이 1MB를 넘지 않도록 오래된 내용을 밀어내며 저장한다.

- 공통 로그, 성능 로그, 감사 로그는 14일 보관으로 맞추고 워크플로우 상세 로그는 기존 설정을 따르되 최대 14일 상한을 적용한다.

- RollingTextLogStoreTests 3건을 추가해 파일 크기 상한과 오래된 파일/날짜 디렉터리 정리 동작을 검증한다.

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_logroll\\ -p:IntermediateOutputPath=obj\\verify_logroll\\ 경고 0 / 오류 0

- 검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter RollingTextLogStoreTests -p:OutputPath=bin\\verify_logroll_tests\\ -p:IntermediateOutputPath=obj\\verify_logroll_tests\\ 통과 3 (기존 WorkspaceContextGeneratorTests.cs(76) nullable 경고 1건 유지)
2026-04-14 18:51:55 +09:00
lacvet 4746d2834b 코워크와 코드의 작업 폴더 선택 멈춤을 완화한다
- 작업 폴더 변경 직후 UI 스레드에서 실행되던 스킬 소스 재탐색을 백그라운드 재로드로 분리한다.

- 조건부 스킬 활성화 경로를 재로드와 분리해 첨부 파일 변경처럼 폴더가 바뀌지 않는 경우 불필요한 스킬 재탐색을 줄인다.

- README와 DEVELOPMENT 문서에 2026-04-14 19:02(KST) 기준 작업 이력과 검증 결과를 반영한다.

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_folderpick\\ -p:IntermediateOutputPath=obj\\verify_folderpick\\ 경고 0 / 오류 0
2026-04-14 18:47:04 +09:00
lacvet 77495e6ac1 내부 설정 스킬 탭에 프로젝트 호환 경로 라벨을 추가한다
- AX Agent 내부 설정의 스킬 설명 카드에 .claude/skills/.../SKILL.md 호환 경로를 커스텀 라벨로 노출한다.

- 워크스페이스에 동일 구조가 있으면 AX가 함께 읽는다는 점을 스킬 탭 첫 화면에서 바로 확인할 수 있게 정리한다.

- README와 DEVELOPMENT 문서에 2026-04-14 18:45(KST) 기준 작업 이력과 검증 결과를 반영한다.

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_skilllabel\\ -p:IntermediateOutputPath=obj\\verify_skilllabel\\ 경고 0 / 오류 0
2026-04-14 18:44:33 +09:00
lacvet ac37311e41 문서형 기본 제공 스킬 노출과 추천 메타데이터를 정리한다
- 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
2026-04-14 18:41:20 +09:00
lacvet 8cf025e14d 스킬 정책 제어와 inline shell 안전장치 추가
스킬 시스템 설정에 프로젝트 스킬 탐색, 플러그인 스킬 탐색, 레거시 command 스킬 호환, inline shell 허용 여부와 시간/출력 제한을 추가하고 일반 설정 및 AX Agent 설정 UI에 연결했다.

SkillService는 로드 시그니처에 실제 스킬 파일 수와 최근 수정 시각을 반영하도록 보강해 같은 폴더라도 스킬 파일이 바뀌면 다음 로드 요청에서 자동으로 재탐색되도록 정리했다.

inline shell 실행기는 설정 기반 비활성화, timeout, 최대 출력 길이 제한을 적용하고 스킬 편집기/갤러리는 lazy prompt body 경로와 ReloadFromCurrentSettings()를 사용하도록 맞췄다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_phase4b\\ -p:IntermediateOutputPath=obj\\verify_phase4b\\ (경고 0 / 오류 0)
검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentToolCatalogTests|SkillServiceRuntimePolicyTests" -p:OutputPath=bin\\verify_phase4b_tests\\ -p:IntermediateOutputPath=obj\\verify_phase4b_tests\\ (통과 18, 기존 WorkspaceContextGeneratorTests nullable 경고 1건 유지)
2026-04-14 18:34:05 +09:00
lacvet 1a9b3c4528 스킬 소스 확장과 공통 deny 필터 고도화
프로젝트 상위 경로의 .claude/skills 탐색, 플러그인 스킬 폴더, 보조 스킬 폴더 목록, .claude/commands 기반 레거시 markdown command를 함께 로드하도록 SkillService를 확장했다.

파일형 스킬은 lazy prompt body 캐시를 사용해 실제 호출/미리보기 시점에만 본문을 읽도록 정리했고 arguments + argument-hint를 함께 해석해 위치 인자 치환과 누락 인자 안내를 보강했다.

도구 blanket deny 규칙은 AgentToolCatalog 공통 메서드로 이동해 AgentLoopService와 설정 UI 도구 목록이 같은 노출 정책을 공유하도록 맞췄다.

일반 설정과 AX Agent 설정에는 여러 공용 스킬 폴더를 줄 단위로 연결할 수 있는 additionalSkillFolders 입력을 추가했고 스킬 목록은 번들/프로젝트/플러그인/공용/레거시 source scope별로 더 세분화했다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_phase3\\ -p:IntermediateOutputPath=obj\\verify_phase3\\ (경고 0 / 오류 0)
검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentToolCatalogTests|SkillServiceRuntimePolicyTests" -p:OutputPath=bin\\verify_phase3_tests\\ -p:IntermediateOutputPath=obj\\verify_phase3_tests\\ (통과 18, 기존 WorkspaceContextGeneratorTests nullable 경고 1건 유지)
2026-04-14 18:23:18 +09:00
lacvet b17c865c4e 스킬 런타임 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건 유지)
2026-04-14 18:10:16 +09:00
lacvet 8cb08576d5 AX Agent 도구·스킬 정합성 재구성 및 실행 품질 보강
변경 목적:
- AX Agent의 도구 이름, 내부 설정, 스킬 정책, 실행 루프 사이의 불일치를 줄이고 전체 동작 품질을 높인다.
- claw-code 수준의 일관된 동작 품질을 참고하되 AX 구조에 맞는 고유한 카탈로그·정규화 레이어로 재구성한다.

핵심 수정사항:
- 도구 canonical id, legacy alias, 탭 노출, 설정 카테고리, read-only 분류를 중앙 카탈로그로 통합했다.
- ToolRegistry, AgentLoopService, 병렬 실행 분류, 권한 처리, 훅 처리, 스킬 allowed-tools 해석이 같은 이름 체계를 사용하도록 정리했다.
- Agent 설정/일반 설정/도움말의 도구 카드와 훅 편집기, 스킬 설명을 현재 런타임 구조에 맞게 갱신했다.
- 컨텍스트 압축, intent gate, spawn agents, session learning, model prompt adapter, workspace context 관련 변경과 테스트 추가를 함께 반영했다.
- 문서 이력과 비교/로드맵 문서를 최신 상태로 갱신했다.

검증 결과:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_toolcat\ -p:IntermediateOutputPath=obj\verify_toolcat\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentToolCatalogTests -p:OutputPath=bin\verify_toolcat_tests\ -p:IntermediateOutputPath=obj\verify_toolcat_tests\ : 통과 8
2026-04-14 17:52:46 +09:00
lacvet fa33b98f7e AX Agent 이력 문자열 깨짐 원인 점검 후 배포 산출물 재생성
작업 목적:
- AX Agent 이력 영역에서 완료/오류/토큰 메타가 깨져 보인다는 제보를 기준으로 원인을 점검하고 배포 상태를 다시 맞춘다.

핵심 수정사항:
- ChatWindow.V2AgentEventPresentation.cs와 ChatWindow.SystemPromptBuilder.cs를 점검해 소스 기준 상태를 재확인했다.
- 현재 브랜치 HEAD 기준 소스 해시는 정상 상태와 일치함을 확인했고, 작업 이력 카드/완료 배너 문자열 문제는 재빌드 산출물과 배포본 정합성 관점에서 다시 맞췄다.
- README.md와 docs/DEVELOPMENT.md에 이력 문자열 깨짐 원인 점검 및 복구 내용을 기록했다.
- AxCopilot.exe, AxCopilot_Setup.exe, AxKeyEncryptor 산출물을 다시 생성해 dist 배포본을 최신 상태로 정리했다.

검증 결과:
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\
- 경고 0 / 오류 0
2026-04-12 23:09:01 +09:00
379 changed files with 46564 additions and 9767 deletions
+7
View File
@@ -208,6 +208,13 @@ if (!enabled) return ToolResult.Ok("비활성 상태입니다. 설정에서 활
- 모든 변경 후 `dotnet build` 실행 → **경고 0, 오류 0** 필수
- CS8603 (nullable) 경고 즉시 수정
### 인코딩 / 주석 기준
- **코드 파일 내부 주석은 예외 없이 영어로만 작성**합니다. 새 주석, TODO, XML doc summary, inline comment 모두 동일하게 적용합니다.
- 한글 주석 또는 혼합 언어 주석이 필요한 설명이 있더라도, **코드 파일 안에서는 영어 주석으로 변환**하여 작성합니다. 사용자 안내나 설계 설명이 길게 필요하면 `.md` 문서로 분리합니다.
- 인코딩 문제가 의심되는 파일을 수정할 때는 **깨진 문자열(mojibake), 깨진 주석, 깨진 프롬프트 조각을 그대로 두지 말고 영어로 정리**합니다.
- 특히 `system prompt`, `agent status`, `session memory`, `tool diagnostics`처럼 LLM 컨텍스트에 직접 들어가는 코드 상수 문자열은 깨진 상태로 유지하지 않습니다. 인코딩 오류가 재발하면 해당 코드 파일의 손상된 문자열을 우선 영어로 치환합니다.
- 코드 리뷰/수정 시 인코딩 이상 여부를 함께 확인하고, **주석 때문에 인코딩 리스크가 높다고 판단되면 기존 주석도 영어로 정리**합니다.
### 성능/실행속도 우선 원칙
- 기능 구현 시 가능하면 **개발 단계부터 최적화와 실행 속도**를 함께 고려합니다.
- 동일 품질을 만족하는 구현안이 여러 개라면, **더 가볍고 빠르게 동작하는 구조**를 우선 채택합니다.
+832 -115
View File
File diff suppressed because it is too large Load Diff
+99
View File
@@ -0,0 +1,99 @@
[CmdletBinding()]
param(
[switch]$Restore,
[switch]$Clean,
[switch]$StopRunningApp
)
$ErrorActionPreference = "Stop"
$root = Split-Path -Parent $MyInvocation.MyCommand.Path
$project = Join-Path $root "src\AxCopilot\AxCopilot.csproj"
$assetsFile = Join-Path $root "src\AxCopilot\obj\project.assets.json"
$configuration = "Release"
$runtime = "win-x64"
$targetFramework = "net8.0-windows10.0.17763.0"
$output = Join-Path $root "src\AxCopilot\bin\$configuration\$targetFramework\$runtime"
function Invoke-Dotnet {
param(
[Parameter(Mandatory = $true)]
[string[]]$Arguments
)
Write-Host ("dotnet " + ($Arguments -join " ")) -ForegroundColor DarkGray
& dotnet @Arguments
if ($LASTEXITCODE -ne 0) {
throw "dotnet command failed with exit code $LASTEXITCODE."
}
}
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " AX Copilot - Quick Build (Windows)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
if (-not (Test-Path $project)) {
throw "Project file not found: $project"
}
if ($StopRunningApp) {
$running = Get-Process -Name "AxCopilot" -ErrorAction SilentlyContinue
if ($running) {
Write-Host "[0/3] Stopping running AxCopilot.exe..." -ForegroundColor Yellow
$running | Stop-Process -Force
}
}
if ($Clean) {
Write-Host "[1/3] Cleaning previous quick-build output..." -ForegroundColor Yellow
Invoke-Dotnet -Arguments @(
"clean", $project,
"-c", $configuration,
"-r", $runtime,
"--nologo",
"-v", "minimal"
)
}
$shouldRestore = $Restore -or -not (Test-Path $assetsFile)
if ($shouldRestore) {
Write-Host "[2/3] Restoring NuGet packages..." -ForegroundColor Yellow
Invoke-Dotnet -Arguments @(
"restore", $project,
"-r", $runtime,
"--nologo",
"-v", "minimal"
)
}
Write-Host "[3/3] Building AxCopilot only (no installer, no publish)..." -ForegroundColor Yellow
$buildArgs = @(
"build", $project,
"-c", $configuration,
"-r", $runtime,
"--nologo",
"-v", "minimal",
"-m",
"-p:RunAnalyzersDuringBuild=false"
)
if (-not $shouldRestore) {
$buildArgs += "--no-restore"
}
Invoke-Dotnet -Arguments $buildArgs
Write-Host ""
Write-Host "========================================" -ForegroundColor Green
Write-Host " Quick Build Complete" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host ""
Write-Host ("Output: " + $output) -ForegroundColor Green
Write-Host "Skipped: installer, dist packaging, obfuscation, publish bundle" -ForegroundColor Green
Write-Host ""
Write-Host "Examples:" -ForegroundColor Cyan
Write-Host " .\build-quick.ps1"
Write-Host " .\build-quick.ps1 -StopRunningApp"
Write-Host " .\build-quick.ps1 -Restore -Clean"
+8 -8
View File
@@ -162,35 +162,35 @@ del /q "%~1\*.runtimeconfig.json" 2>nul
exit /b 0
:fail_dist
echo [FAILED] dist ??€????밴쉐 ??쎈솭
echo [FAILED] dist 폴더 생성 실패
goto :end_fail
:fail_app
echo [FAILED] main app publish ??쎈솭
echo [FAILED] main app publish 실패
goto :end_fail
:fail_obfuscation
echo [FAILED] obfuscation ??m€???쎈솭
echo [FAILED] obfuscation 단계 실패
goto :end_fail
:fail_encryptor
echo [FAILED] AxKeyEncryptor publish ??쎈솭
echo [FAILED] AxKeyEncryptor publish 실패
goto :end_fail
:fail_payload
echo [FAILED] payload.zip ??밴쉐 ??쎈솭
echo [FAILED] payload.zip 생성 실패
goto :end_fail
:fail_installer
echo [FAILED] installer build ??쎈솭
echo [FAILED] installer build 실패
goto :end_fail
:fail_installer_copy
echo [FAILED] installer exe 癰귣벊沅???쎈솭
echo [FAILED] installer exe 복사 실패
goto :end_fail
:fail_running
echo [FAILED] running AX Copilot process could not be stopped cleanly
echo [FAILED] 실행 중인 AX Copilot 프로세스를 종료할 수 없습니다
goto :end_fail
:end_fail
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 488 B

Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
-95
View File
@@ -1,95 +0,0 @@
---
name: adr-writer
label: 아키텍처 결정 기록 (ADR)
description: 아키텍처 결정 사항을 표준 ADR 형식으로 문서화합니다.
icon: \uE82D
allowed-tools:
- file_read
- file_write
- folder_map
- grep
- search_codebase
tabs: code
---
아키텍처 결정 사항을 ADR(Architecture Decision Record) 형식으로 문서화하세요.
## ADR이란?
소프트웨어 아키텍처에서 내린 중요한 결정의 배경, 대안, 근거를 기록하는 경량 문서입니다.
미래의 팀원이 "왜 이렇게 결정했는지"를 이해할 수 있게 합니다.
## 워크플로우
1. **결정 사항 확인**: 사용자에게 다음을 파악
- 어떤 결정을 내렸는가 (또는 내려야 하는가)
- 관련 코드/시스템 영역
- 고려한 대안들
2. **코드 분석** (선택): 관련 코드 구조를 읽어 현재 상태 파악
3. **ADR 작성**: 표준 형식으로 문서 생성
4. **파일 저장**: `docs/adr/` 폴더에 번호 형식으로 저장
## ADR 표준 형식
```markdown
# ADR-[번호]: [결정 제목]
**상태**: 제안됨 | 승인됨 | 폐기됨 | 대체됨
**날짜**: YYYY-MM-DD
**결정자**: [이름/팀]
## 맥락 (Context)
어떤 상황에서 이 결정이 필요한가?
- 기술적 배경
- 비즈니스 요구사항
- 제약 조건
## 결정 (Decision)
무엇을 결정했는가?
- 선택한 방안의 구체적 내용
- 적용 범위
## 대안 (Alternatives)
### 대안 1: [이름]
- 장점: ...
- 단점: ...
- 비용/복잡도: ...
### 대안 2: [이름]
- 장점: ...
- 단점: ...
- 비용/복잡도: ...
## 근거 (Rationale)
왜 이 결정을 선택했는가?
- 대안 대비 장점
- 트레이드오프 분석
- 참고 자료/벤치마크
## 결과 (Consequences)
### 긍정적
- ...
### 부정적
- ...
### 리스크
- ...
## 관련 문서
- ADR-[관련번호]: [제목]
- [외부 참고 링크]
```
## 파일 명명 규칙
- 위치: `docs/adr/` (없으면 생성)
- 파일명: `ADR-NNNN-제목-요약.md` (예: `ADR-0001-데이터베이스-선택.md`)
- 번호: 기존 ADR 파일 조회 후 자동 부여
## 규칙
- 결정의 "왜"를 중심으로 작성 (코드를 읽으면 "무엇"은 알 수 있음)
- 대안은 최소 2개 이상 제시
- 트레이드오프를 솔직하게 기록 (완벽한 선택은 없음)
- 짧고 명확하게 (1~2페이지 이내)
- 한국어로 작성
-59
View File
@@ -1,59 +0,0 @@
---
name: api-docs
label: API 문서 생성
description: 코드에서 API 엔드포인트를 분석하여 마크다운/HTML API 문서를 자동 생성합니다.
icon: \uE8A1
allowed-tools:
- folder_map
- grep
- file_read
- file_write
- search_codebase
tabs: code
---
작업 폴더의 소스 코드를 분석하여 API 문서를 생성하세요.
## 분석 대상
- REST API 엔드포인트 (Controller, Route 어노테이션)
- 함수/메서드 시그니처 및 주석
- 요청/응답 모델 (DTO, Schema)
- 인증/권한 요구사항
## 작업 절차
1. `folder_map` — 프로젝트 구조 파악
2. `grep` — API 엔드포인트 패턴 검색 (`[HttpGet]`, `@GetMapping`, `router.get`, `@app.route` 등)
3. `file_read` — 컨트롤러/라우터 파일 분석
4. `grep` — 요청/응답 모델 클래스 검색
5. `file_read` — 모델 구조 분석
6. `file_write` — API 문서 생성
## 출력 형식
마크다운으로 작성하되 다음 구조를 따르세요:
```
# API 문서
## 개요
- Base URL, 인증 방식, 공통 헤더
## 엔드포인트
### [POST] /api/users
- **설명**: 사용자 생성
- **인증**: Bearer Token 필요
- **요청 본문**:
| 필드 | 타입 | 필수 | 설명 |
|------|------|------|------|
| name | string | ✓ | 사용자 이름 |
- **응답**: 201 Created
```json
{ "id": 1, "name": "..." }
```
- **에러 코드**: 400, 401, 409
```
## 주의사항
- 코드에서 실제 확인된 내용만 문서화하세요. 추측하지 마세요.
- 주석이나 Swagger/OpenAPI 어노테이션이 있으면 우선 활용하세요.
- 인증, 페이징, 에러 처리 등 공통 패턴은 별도 섹션으로 정리하세요.
-70
View File
@@ -1,70 +0,0 @@
---
name: batch-rename
label: 파일 일괄 이름 변경
description: 패턴 매칭, 번호 붙이기, 날짜 추가 등 파일 이름을 일괄 변경합니다.
icon: \uE8AC
tabs: cowork
allowed-tools:
- folder_map
- file_read
- file_manage
- clipboard_tool
---
파일 이름을 규칙에 따라 일괄 변경하세요. 변경 전 반드시 미리보기를 제공합니다.
## 작업 절차
1. **대상 파일 스캔**: folder_map으로 작업 폴더의 파일 목록을 수집
2. **이름 변경 규칙 확인**: 사용자에게 다음 옵션을 확인
- 대상 파일 필터 (확장자, 이름 패턴)
- 변경 규칙 (아래 지원 규칙 참조)
- 적용 순서 (이름순, 날짜순, 크기순)
3. **변경 미리보기 생성**: 변경 전/후 이름을 표로 표시
```
| # | 현재 이름 | 변경 후 이름 |
|---|----------------------|----------------------|
| 1 | IMG_20260101_001.jpg | 2026-01-01_001.jpg |
| 2 | IMG_20260101_002.jpg | 2026-01-01_002.jpg |
```
4. **사용자 확인**: 미리보기를 보여주고 진행 여부를 확인
5. **일괄 변경 실행**: file_manage로 파일 이름을 순차 변경
6. **결과 보고**: 변경 성공/실패 건수와 상세 내역을 안내
## 지원 이름 변경 규칙
### 패턴 치환
- **문자열 치환**: "IMG_" → "사진_"
- **정규식 치환**: `(\d{4})(\d{2})(\d{2})` → `$1-$2-$3`
- **대소문자 변환**: 소문자, 대문자, 타이틀 케이스
### 번호 붙이기
- **순번 추가**: `문서_001.pdf`, `문서_002.pdf`, ...
- **시작 번호**: 사용자 지정 (기본: 1)
- **자릿수**: 자동 계산 (파일 수 기준)
- **위치**: 접두사 또는 접미사
### 날짜 추가
- **오늘 날짜**: `보고서_2026-03-30.docx`
- **파일 수정일**: 파일의 실제 수정 날짜 사용
- **날짜 형식**: YYYY-MM-DD, YYYYMMDD, YY.MM.DD
### 정리
- **공백 처리**: 공백 → 언더스코어/하이픈
- **특수문자 제거**: 파일명에서 특수문자 제거
- **확장자 변경**: `.jpeg` → `.jpg`
- **접두사/접미사 추가 또는 제거**
## 충돌 처리
- 변경 후 이름이 이미 존재하면 자동으로 번호 추가 (`_1`, `_2`)
- 충돌 건은 미리보기에서 ⚠️ 표시로 경고
- 원본 파일 덮어쓰기 절대 금지
## 규칙
- **미리보기 없이 직접 변경하지 않음** — 반드시 미리보기 후 사용자 확인
- 하위 폴더 포함 여부는 사용자에게 확인
- 숨김 파일(.으로 시작)은 기본 제외
- 변경 실패 시 이미 변경된 파일은 원복하지 않으므로, 중요한 경우 백업 권장
- 한 번에 1,000개 이상의 파일 변경 시 경고
한국어로 안내하세요.
-74
View File
@@ -1,74 +0,0 @@
---
name: changelog
label: 변경 이력 / 릴리즈 노트
description: Git 커밋 이력에서 자동으로 변경 이력과 릴리즈 노트를 생성합니다.
icon: \uE81C
allowed-tools:
- git_tool
- file_read
- file_write
- html_create
- text_summarize
tabs: code
---
Git 커밋 이력을 분석하여 변경 이력(CHANGELOG) 또는 릴리즈 노트를 생성하세요.
## 워크플로우
1. **이력 조회**: git_tool로 커밋 로그 수집
- 지정 기간 또는 태그 간 커밋
- 커밋 메시지 + 변경 파일 목록
2. **분류**: 커밋을 Conventional Commits 기준으로 분류
3. **Breaking Change 감지**: 시그니처 변경, API 삭제 등 감지
4. **문서 생성**: Markdown 또는 HTML로 출력
## Conventional Commits 분류
| 접두사 | 분류 | 설명 |
|--------|------|------|
| feat | ✨ 신기능 | 새로운 기능 추가 |
| fix | 🐛 버그 수정 | 버그 수정 |
| docs | 📝 문서 | 문서 변경 |
| style | 💄 스타일 | 코드 포맷팅 (동작 변경 없음) |
| refactor | ♻️ 리팩토링 | 코드 리팩토링 |
| perf | ⚡ 성능 | 성능 개선 |
| test | ✅ 테스트 | 테스트 추가/수정 |
| chore | 🔧 기타 | 빌드, 설정 변경 |
| BREAKING | 💥 Breaking | 하위 호환성 깨지는 변경 |
## 출력 형식
### CHANGELOG.md
```markdown
# Changelog
## [1.6.0] - 2026-03-30
### ✨ 신기능
- 멀티패스 문서 생성 엔진 (#123)
- PPT 네이티브 생성 도구
### 🐛 버그 수정
- 탭 전환 시 대화 유실 문제 해결
### 💥 Breaking Changes
- 없음
### 📝 문서
- 개발자 가이드 v1.6.0 업데이트
```
### 릴리즈 노트 (HTML)
사용자 친화적인 형식:
- 주요 변경사항 (스크린샷 포함 가능)
- 개선 사항
- 알려진 이슈
- 업그레이드 가이드
## 규칙
- Conventional Commits 형식이 아닌 커밋도 내용 분석으로 분류
- 중복/사소한 커밋은 병합하여 요약
- Breaking Change는 반드시 별도 섹션으로 강조
- 이슈 번호가 있으면 링크 포함
- 한국어로 작성
-37
View File
@@ -1,37 +0,0 @@
---
name: code-scaffold
label: 코드 스캐폴딩
description: 프로젝트 구조를 분석하고 새 기능의 코드 뼈대를 자동 생성합니다.
icon: \uE943
allowed-tools:
- folder_map
- file_read
- grep
- file_write
- search_codebase
tabs: code
---
작업 폴더의 프로젝트 구조를 분석하고 새 기능의 코드 뼈대를 생성하세요.
다음 도구를 사용하세요:
1. folder_map — 프로젝트 구조 파악
2. file_read — 기존 코드 패턴 분석
3. grep — 코딩 컨벤션 확인
4. file_write — 새 파일 생성
작업 순서:
1. 프로젝트 타입 감지 (언어, 프레임워크, 빌드 시스템)
2. 기존 코드 패턴 분석 (네이밍, 폴더 구조, 임포트 스타일)
3. 사용자 요청에 맞는 코드 뼈대 생성
생성 항목:
- 클래스/모듈 파일 (프로젝트 컨벤션에 맞춰)
- 인터페이스/타입 정의
- 단위 테스트 파일
- 필요한 설정/구성 파일
규칙:
- 기존 프로젝트의 코딩 스타일을 따르세요
- TODO 주석으로 구현이 필요한 부분을 표시하세요
- 한국어 주석을 추가하세요
-72
View File
@@ -1,72 +0,0 @@
---
name: commit-review
label: 커밋 메시지 리뷰
description: Git 커밋 메시지를 Conventional Commits 기준으로 검토하고 개선을 제안합니다.
icon: \uE8CB
allowed-tools:
- process
- git_tool
- file_read
- text_summarize
tabs: code
---
작업 폴더의 최근 Git 커밋 메시지를 검토하고 개선안을 제시하세요.
## 작업 절차
1. `process``git log --oneline -20` 으로 최근 커밋 목록 확인
2. `process``git log --format="%H%n%s%n%b%n---" -10` 으로 상세 메시지 확인
3. `process``git diff HEAD~1` 으로 최신 커밋 변경 내용 확인 (필요 시)
4. 각 커밋을 Conventional Commits 기준으로 분석
5. 결과를 정리하여 출력
## Conventional Commits 규칙
```
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
```
### type 종류
- `feat`: 새 기능
- `fix`: 버그 수정
- `docs`: 문서 변경
- `style`: 포맷팅 (코드 동작 변경 없음)
- `refactor`: 리팩토링
- `perf`: 성능 개선
- `test`: 테스트 추가/수정
- `chore`: 빌드/도구 설정
- `ci`: CI 설정 변경
## 검토 항목
1. **type 적절성**: 변경 내용과 type이 일치하는가
2. **설명 품질**: 50자 이내, 명령형, 명확한 내용
3. **본문 유무**: 복잡한 변경에 "왜" 설명이 있는가
4. **일관성**: 팀 내 커밋 스타일이 통일되어 있는가
5. **Breaking Change**: BREAKING CHANGE 푸터 또는 ! 표기
## 출력 형식
```
## 커밋 메시지 리뷰 결과
### 전체 요약
- 검토 커밋: N개
- 규칙 준수: N개 ✓ / 위반: N개 ✗
### 개별 리뷰
#### abc1234 "Fix login bug"
- ❌ type 없음 → `fix: resolve login authentication failure`
- ❌ 본문 없음 → 원인과 해결 방법 추가 권장
#### def5678 "feat: add user profile page"
- ✅ Conventional Commits 준수
- 💡 scope 추가 권장: `feat(profile): add user profile page`
```
## 주의사항
- 비판이 아닌 건설적 제안을 하세요.
- 팀의 기존 컨벤션이 있으면 그것을 우선 존중하세요.
- 개선된 메시지 예시를 항상 함께 제시하세요.
-51
View File
@@ -1,51 +0,0 @@
---
name: compare
label: 비교 분석표
description: 2개 이상 항목의 비교 분석 매트릭스를 생성합니다.
icon: \uE9D5
allowed-tools:
- html_create
- excel_create
- file_read
- document_read
- chart_create
tabs: all
---
사용자가 요청한 항목들을 체계적으로 비교 분석하는 매트릭스를 생성하세요.
## 워크플로우
1. **비교 대상 확인**: 어떤 항목들을 비교할지 파악
- 제품, 기술, 방안, 서비스, 도구, 프레임워크 등
2. **비교 기준 설정**: 적절한 비교 축을 설계
- 기능, 가격, 성능, 사용성, 확장성, 지원, 보안 등
3. **데이터 수집**: 참고 파일이 있으면 읽어서 반영
4. **분석표 생성**: HTML 또는 Excel로 비교 매트릭스 생성
5. **종합 평가**: 총평 + 추천 의견 제시
## 비교표 구성
### 기본 매트릭스
| 기준 | 항목 A | 항목 B | 항목 C |
|------|--------|--------|--------|
| 기능1 | ✅ 지원 | ⚠ 일부 | ❌ 미지원 |
| 기능2 | ... | ... | ... |
### 점수 비교 (radar 차트 활용)
- 각 항목을 1~10점으로 정량화
- chart_create로 레이더 차트 또는 바 차트 시각화
### 종합 평가
- 장점/단점 요약
- 상황별 추천 (예: "예산이 제한적이면 A, 확장성이 중요하면 B")
## 출력 형식
- **HTML** (권장): 색상 배지, 차트 포함 비주얼 보고서
- **Excel**: 정량 데이터 + 수식 기반 점수표
## 규칙
- 객관적 사실 기반으로 비교 (주관적 판단은 별도 섹션)
- 각 항목의 강점과 약점을 균형 있게 서술
- 출처/근거가 있으면 명시
- 한국어로 작성
-137
View File
@@ -1,137 +0,0 @@
---
name: csv-to-xlsx
label: CSV → Excel 변환
description: CSV 파일을 서식이 완성된 Excel(.xlsx)로 변환합니다. 헤더 고정, 필터, 조건부 서식, 자동 열 너비를 적용합니다.
icon: \uE9F9
allowed-tools:
- folder_map
- file_read
- file_write
- process
- format_convert
- data_pivot
- template_render
tabs: cowork
---
CSV 파일을 전문적인 서식이 적용된 Excel 파일로 변환하세요.
## 실행 경로 선택 (Python 가능/불가)
- 먼저 `process``python --version`을 확인하세요.
- Python 가능: 기존 Python 스크립트 경로로 변환/서식 자동화를 수행하세요.
- Python 불가: `format_convert`로 CSV를 XLSX로 변환하고, `data_pivot`으로 핵심 요약 시트를 구성한 뒤 `file_write`로 사용 안내를 남기세요.
## 사전 준비
먼저 필요한 패키지가 설치되어 있는지 확인하고, 없으면 설치하세요:
```
process: pip install openpyxl pandas
```
## 작업 절차
1. **파일 확인**: folder_map으로 작업 폴더에서 CSV 파일을 탐색
2. **CSV 분석**: file_read로 CSV 파일의 구조(컬럼, 행 수, 인코딩, 구분자) 파악
3. **변환 옵션 확인**: 사용자에게 다음 옵션을 확인
- 헤더 행 고정 여부 (기본: 활성)
- 자동 필터 적용 여부 (기본: 활성)
- 조건부 서식 대상 컬럼 (숫자 컬럼 자동 감지)
- 시트 이름 (기본: 파일명)
4. **Python 스크립트 작성**: file_write로 변환 스크립트 생성
5. **스크립트 실행**: `process`로 Python 스크립트 실행
6. **결과 확인**: 생성된 .xlsx 파일 경로와 요약 정보를 안내
## Python 스크립트 템플릿
```python
import pandas as pd
from openpyxl import load_workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter
from openpyxl.formatting.rule import CellIsRule
# CSV 읽기 (인코딩 자동 감지)
for enc in ['utf-8', 'cp949', 'euc-kr', 'utf-8-sig']:
try:
df = pd.read_csv('input.csv', encoding=enc)
break
except (UnicodeDecodeError, Exception):
continue
# Excel 저장
output_path = 'output.xlsx'
df.to_excel(output_path, index=False, sheet_name='Sheet1')
# 서식 적용
wb = load_workbook(output_path)
ws = wb.active
# 헤더 스타일
header_font = Font(bold=True, color='FFFFFF', size=11)
header_fill = PatternFill(start_color='4472C4', end_color='4472C4', fill_type='solid')
header_align = Alignment(horizontal='center', vertical='center', wrap_text=True)
thin_border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
for col_idx, cell in enumerate(ws[1], 1):
cell.font = header_font
cell.fill = header_fill
cell.alignment = header_align
cell.border = thin_border
# 자동 열 너비
for col_idx in range(1, ws.max_column + 1):
max_length = 0
col_letter = get_column_letter(col_idx)
for row in ws.iter_rows(min_col=col_idx, max_col=col_idx):
for cell in row:
if cell.value:
max_length = max(max_length, len(str(cell.value)))
ws.column_dimensions[col_letter].width = min(max_length + 4, 50)
# 헤더 행 고정 (Freeze Panes)
ws.freeze_panes = 'A2'
# 자동 필터
ws.auto_filter.ref = ws.dimensions
# 숫자 컬럼 조건부 서식 (음수 빨강)
for col_idx in range(1, ws.max_column + 1):
col_letter = get_column_letter(col_idx)
sample_values = [ws.cell(row=r, column=col_idx).value for r in range(2, min(ws.max_row + 1, 12))]
if any(isinstance(v, (int, float)) for v in sample_values if v is not None):
cell_range = f'{col_letter}2:{col_letter}{ws.max_row}'
ws.conditional_formatting.add(cell_range,
CellIsRule(operator='lessThan', formula=['0'],
font=Font(color='FF0000')))
# 데이터 행 줄무늬 (가독성)
light_fill = PatternFill(start_color='D9E2F3', end_color='D9E2F3', fill_type='solid')
for row_idx in range(2, ws.max_row + 1):
for col_idx in range(1, ws.max_column + 1):
cell = ws.cell(row=row_idx, column=col_idx)
cell.border = thin_border
if row_idx % 2 == 0:
cell.fill = light_fill
wb.save(output_path)
print(f'변환 완료: {output_path} ({ws.max_row - 1}× {ws.max_column}열)')
```
## 서식 옵션
- **헤더 스타일**: 파란 배경 + 흰색 굵은 글씨 + 가운데 정렬
- **줄무늬**: 짝수 행 연한 파랑 배경 (가독성 향상)
- **열 너비**: 내용 기준 자동 조정 (최대 50)
- **조건부 서식**: 숫자 컬럼 음수 빨강 표시
- **Freeze Panes**: 헤더 행 고정
- **Auto Filter**: 전체 컬럼 필터 활성화
## 규칙
- 원본 CSV 파일은 수정하지 않음
- 인코딩 자동 감지 (UTF-8 → CP949 → EUC-KR 순)
- 대용량 파일 (100,000행 이상) 경고 후 진행
- 출력 파일명: 원본 파일명 기준 (.csv → .xlsx)
한국어로 안내하세요. 작업 폴더에 Python 스크립트와 결과 파일을 저장하세요.
-56
View File
@@ -1,56 +0,0 @@
---
name: data-convert
label: 데이터 변환기
description: 데이터 포맷 간 변환, 정제, 필터링, 통계 요약을 수행합니다.
icon: \uE8AB
allowed-tools:
- file_read
- file_write
- json_tool
- csv_create
- data_pivot
- excel_create
tabs: cowork
---
데이터 파일의 포맷 변환, 정제, 필터링, 통계 요약을 수행하세요.
## 지원 변환
| 입력 → | JSON | CSV | Excel | Markdown |
|--------|------|-----|-------|----------|
| JSON | — | ✅ | ✅ | ✅ |
| CSV | ✅ | — | ✅ | ✅ |
| Excel | ✅ | ✅ | — | ✅ |
| TSV | ✅ | ✅ | ✅ | ✅ |
## 워크플로우
1. **파일 분석**: 입력 파일의 포맷, 인코딩, 구조 파악
2. **데이터 정제** (선택):
- 빈 행/열 제거
- 중복 제거
- 데이터 타입 정리 (숫자 문자열 → 숫자)
- 결측치 처리 (제거 또는 기본값)
3. **필터링** (선택):
- 조건 기반 행 필터링
- 필요 컬럼만 추출
4. **변환**: 대상 포맷으로 변환
5. **통계 요약**: 기본 통계 제공
## 정제 옵션
- `remove_empty`: 빈 행 제거
- `remove_duplicates`: 중복 행 제거
- `trim`: 공백 제거
- `fill_na`: 결측치 채우기 (값 지정)
## 출력
- 변환된 파일 저장
- 변환 통계 (원본 행 수, 변환 후 행 수, 제거 행 수)
- 컬럼별 기본 통계 (수치 컬럼: 합계, 평균, 최소, 최대)
## 규칙
- 원본 파일은 수정하지 않음 (새 파일로 저장)
- 인코딩: UTF-8 기본 (EUC-KR 옵션)
- 대용량 파일 (10MB 이상) 경고
- 한국어로 안내
-137
View File
@@ -1,137 +0,0 @@
---
name: data-visualize-adv
label: 고급 데이터 시각화
description: Python matplotlib/seaborn을 사용하여 히트맵, 산점도, 상관관계 등 고급 시각화를 생성합니다.
icon: \uE9D9
allowed-tools:
- folder_map
- file_read
- file_write
- process
- data_pivot
- chart_create
- template_render
tabs: cowork
---
데이터를 고급 시각화 차트로 변환하세요.
## 실행 경로 선택 (Python 가능/불가)
- 먼저 `process``python --version`을 확인하세요.
- Python 가능: 기존 matplotlib/seaborn 경로를 사용하세요.
- Python 불가: `data_pivot`으로 통계를 계산하고 `chart_create` + `template_render` + `file_write`로 HTML/SVG 리포트를 생성하세요.
## 사전 준비
필요한 패키지를 설치하세요:
```
process: pip install matplotlib seaborn pandas numpy
```
## 작업 절차
1. **데이터 확인**: 사용자가 제공한 CSV/JSON/Excel 데이터 파일 확인
2. **데이터 로드**: pandas로 데이터 읽기
3. **Python 스크립트 작성**: file_write로 시각화 스크립트 생성
4. **스크립트 실행**: `process`로 실행
5. **결과 확인**: 생성된 차트 이미지 경로를 사용자에게 안내
## 시각화 유형별 템플릿
### 공통 설정
```python
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
# 한글 폰트 설정
plt.rcParams['font.family'] = 'Malgun Gothic'
plt.rcParams['axes.unicode_minus'] = False
sns.set_theme(style='whitegrid', font='Malgun Gothic')
```
### 히트맵 (상관관계 행렬)
```python
df = pd.read_csv('data.csv')
corr = df.select_dtypes(include=[np.number]).corr()
fig, ax = plt.subplots(figsize=(10, 8))
sns.heatmap(corr, annot=True, fmt='.2f', cmap='RdBu_r',
center=0, square=True, linewidths=0.5, ax=ax)
ax.set_title('상관관계 히트맵')
plt.tight_layout()
plt.savefig('heatmap.png', dpi=150)
```
### 산점도 (Scatter Plot)
```python
df = pd.read_csv('data.csv')
fig, ax = plt.subplots(figsize=(10, 8))
sns.scatterplot(data=df, x='col_x', y='col_y', hue='category',
size='value', sizes=(20, 200), alpha=0.7, ax=ax)
ax.set_title('산점도')
plt.tight_layout()
plt.savefig('scatter.png', dpi=150)
```
### 시계열 분석
```python
df = pd.read_csv('data.csv', parse_dates=['date'])
fig, ax = plt.subplots(figsize=(12, 6))
sns.lineplot(data=df, x='date', y='value', hue='category', ax=ax)
ax.set_title('시계열 트렌드')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('timeseries.png', dpi=150)
```
### 분포 비교 (박스플롯 + 바이올린)
```python
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
sns.boxplot(data=df, x='group', y='value', ax=axes[0])
axes[0].set_title('박스플롯')
sns.violinplot(data=df, x='group', y='value', ax=axes[1])
axes[1].set_title('바이올린 플롯')
plt.tight_layout()
plt.savefig('distribution.png', dpi=150)
```
### 다중 차트 대시보드
```python
fig, axes = plt.subplots(2, 2, figsize=(14, 12))
# 좌상: 히트맵
sns.heatmap(corr, annot=True, fmt='.1f', ax=axes[0,0])
# 우상: 산점도
sns.scatterplot(data=df, x='x', y='y', ax=axes[0,1])
# 좌하: 히스토그램
sns.histplot(data=df, x='value', kde=True, ax=axes[1,0])
# 우하: 박스플롯
sns.boxplot(data=df, x='group', y='value', ax=axes[1,1])
fig.suptitle('데이터 분석 대시보드', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.savefig('dashboard.png', dpi=150)
```
### 페어플롯 (변수 간 관계 전체)
```python
g = sns.pairplot(df, hue='category', diag_kind='kde')
g.fig.suptitle('변수 간 관계', y=1.02)
plt.savefig('pairplot.png', dpi=150)
```
## 스타일 옵션
- seaborn 테마: `whitegrid`, `darkgrid`, `white`, `dark`, `ticks`
- 컬러 팔레트: `Set2`, `husl`, `coolwarm`, `RdBu_r`, `viridis`
- 출력 형식: png, svg, pdf
- 해상도: `dpi=150` (기본), `dpi=300` (인쇄용)
한국어로 안내하세요. 작업 폴더에 Python 스크립트와 결과 파일을 저장하세요.
-45
View File
@@ -1,45 +0,0 @@
---
name: data-visualize
label: 데이터 시각화
description: CSV/Excel 데이터를 분석하여 차트가 포함된 HTML 보고서를 생성합니다.
icon: \uE9D9
allowed-tools:
- folder_map
- file_read
- file_write
- data_pivot
- chart_create
- template_render
tabs: cowork
---
작업 폴더의 데이터 파일을 분석하고 시각화 보고서를 생성하세요.
다음 도구를 사용하세요:
1. folder_map — 데이터 파일 탐색
2. file_read — CSV/Excel 데이터 읽기
3. file_write — HTML 시각화 보고서 생성
각화 전략:
1. **데이터 파악**: 컬럼 타입, 결측치, 기본 통계량 확인
2. **적절한 차트 선택**:
- 시계열 → 라인 차트
- 비교 → 바 차트
- 비율 → 파이/도넛 차트
- 분포 → 히스토그램
- 상관관계 → 산점도
3. **HTML 보고서 생성**: 인라인 SVG 또는 CSS 기반 차트 (외부 라이브러리 없이)
보고서 구성:
## 데이터 요약
- 기본 통계 테이블
## 시각화
- 데이터 특성에 맞는 2~4개 차트
- 각 차트에 대한 해석
## 인사이트
- 데이터에서 발견한 주요 패턴
- 이상치 또는 주목할 포인트
한국어로 작성하세요. 차트는 CSS/SVG 기반으로 외부 의존성 없이 생성하세요.
-66
View File
@@ -1,66 +0,0 @@
---
name: db-schema
label: DB 스키마 분석
description: 데이터베이스 스키마를 분석하여 ERD 다이어그램과 테이블 문서를 생성합니다.
icon: \uE968
allowed-tools:
- folder_map
- grep
- file_read
- file_write
- search_codebase
tabs: code
---
작업 폴더의 코드에서 데이터베이스 스키마를 분석하고 문서화하세요.
## 분석 대상
- ORM 모델/엔티티 클래스 (Entity Framework, SQLAlchemy, Sequelize, JPA 등)
- 마이그레이션 파일
- SQL DDL 스크립트 (CREATE TABLE)
- 관계 정의 (FK, Navigation Property)
## 작업 절차
1. `folder_map` — 프로젝트 구조 파악
2. `grep` — 엔티티/모델 클래스 검색 (`DbSet`, `@Entity`, `Model.define`, `CREATE TABLE` 등)
3. `file_read` — 모델 파일 분석 (컬럼, 타입, 관계)
4. `grep` — 인덱스, 제약 조건 검색
5. `file_write` — 스키마 문서 + Mermaid ERD 생성
## 출력 형식
### 테이블 문서
각 테이블에 대해:
```
## Users 테이블
| 컬럼 | 타입 | Null | 기본값 | 설명 |
|------|------|------|--------|------|
| Id | int | NO | AUTO_INCREMENT | PK |
| Name | nvarchar(100) | NO | - | 사용자 이름 |
| CreatedAt | datetime | NO | GETDATE() | 생성일 |
- **인덱스**: IX_Users_Name (Name)
- **관계**: Orders (1:N), Profile (1:1)
```
### Mermaid ERD
```mermaid
erDiagram
Users ||--o{ Orders : "has"
Users ||--|| Profile : "has"
Users {
int Id PK
string Name
datetime CreatedAt
}
Orders {
int Id PK
int UserId FK
decimal Amount
}
```
## 주의사항
- 코드에서 실제 확인된 스키마만 문서화하세요.
- 관계(1:1, 1:N, N:M)를 정확히 파악하세요.
- 마이그레이션이 있으면 최종 상태를 기준으로 작성하세요.
-85
View File
@@ -1,85 +0,0 @@
---
name: dependency-audit
label: 의존성 분석
description: 프로젝트 의존성 그래프를 분석하고 보안 취약점, 라이선스, 업데이트 현황을 보고합니다.
icon: \uE964
allowed-tools:
- file_read
- grep
- folder_map
- glob
- html_create
- process
tabs: code
---
프로젝트의 패키지 의존성을 분석하여 보안, 라이선스, 업데이트 보고서를 생성하세요.
## 워크플로우
1. **패키지 파일 탐지**: glob으로 의존성 파일 검색
- .NET: `*.csproj`, `packages.config`, `Directory.Build.props`
- Node: `package.json`, `package-lock.json`, `yarn.lock`
- Python: `requirements.txt`, `Pipfile`, `pyproject.toml`
- Java: `pom.xml`, `build.gradle`
2. **의존성 목록 추출**: file_read로 파일 파싱
3. **분석 수행**: 각 의존성에 대해 검사
4. **보고서 생성**: html_create로 분석 보고서 생성
## 분석 항목
### 1. 직접 의존성 목록
| 패키지 | 현재 버전 | 최신 버전 | 업데이트 필요 |
|--------|----------|----------|-------------|
| ... | ... | ... | ✅/⚠/❌ |
### 2. 보안 취약점 (알려진 패턴)
- 알려진 취약 버전 패턴 탐지
- 폐기된(deprecated) 패키지 식별
- 유지보수 중단된 패키지 경고
### 3. 라이선스 검사
| 라이선스 | 호환성 | 패키지 |
|---------|--------|--------|
| MIT | ✅ 허용 | lib-a, lib-b |
| GPL-3.0 | ⚠ 주의 | lib-c |
| 상용 | ❌ 검토 필요 | lib-d |
### 4. 의존성 크기 분석
- 패키지별 예상 크기
- 전체 node_modules / NuGet 캐시 크기
- 불필요하게 큰 패키지 식별
### 5. 중복/충돌 검사
- 동일 기능 중복 패키지 (예: lodash + underscore)
- 버전 충돌 가능성
## 프레임워크별 검사 명령
### .NET
```
dotnet list package --outdated
dotnet list package --vulnerable
```
### Node.js
```
npm audit
npm outdated
```
### Python
```
pip list --outdated
pip-audit
```
## 출력
- HTML 보고서: 위험도별 색상 구분, 차트 포함
- 요약: 총 패키지 수, 업데이트 필요 수, 보안 이슈 수, 라이선스 경고 수
## 규칙
- 외부 서버 접속 없이 로컬 파일 분석만 수행
- process 도구 사용 시 `dotnet list` / `npm audit` 등 읽기 전용 명령만
- 패키지를 직접 업데이트하지 않음 (보고서만)
- 한국어로 작성
-109
View File
@@ -1,109 +0,0 @@
---
name: diagram-generator
label: 다이어그램 생성
description: Python matplotlib/graphviz를 사용하여 플로차트, 시퀀스, ER 다이어그램 등을 생성합니다.
icon: \uE9D9
allowed-tools:
- file_read
- file_write
- process
- chart_create
- template_render
tabs: cowork
---
사용자의 요구에 맞는 다이어그램을 Python으로 생성하세요.
## 실행 경로 선택 (Python 가능/불가)
- 먼저 `process``python --version`을 확인하세요.
- Python 가능: 기존 Graphviz/matplotlib 경로를 사용하세요.
- Python 불가: `template_render``file_write`로 Mermaid 기반 다이어그램 문서를 생성하고, 필요 시 `chart_create`로 대체 시각화를 제공하세요.
## 사전 준비
필요한 패키지를 설치하세요:
```
process: pip install matplotlib graphviz
```
시스템에 Graphviz가 설치되어 있어야 합니다 (https://graphviz.org/download/).
## 작업 절차
1. **요구사항 파악**: 다이어그램 유형, 노드/관계, 스타일 확인
2. **Python 스크립트 작성**: file_write로 .py 파일 생성
3. **스크립트 실행**: `process`로 Python 스크립트 실행
4. **결과 확인**: 생성된 이미지 파일 경로를 사용자에게 안내
## 다이어그램 유형별 템플릿
### 플로차트 (Graphviz)
```python
from graphviz import Digraph
dot = Digraph(comment='Flowchart', format='png')
dot.attr(rankdir='TB', fontname='Malgun Gothic')
dot.attr('node', shape='box', style='rounded,filled', fillcolor='#E8F0FE')
dot.node('start', '시작', shape='ellipse', fillcolor='#34A853', fontcolor='white')
dot.node('process1', '데이터 수집')
dot.node('decision', '조건 확인?', shape='diamond', fillcolor='#FBBC04')
dot.node('process2', '처리')
dot.node('end', '종료', shape='ellipse', fillcolor='#EA4335', fontcolor='white')
dot.edge('start', 'process1')
dot.edge('process1', 'decision')
dot.edge('decision', 'process2', label='')
dot.edge('decision', 'end', label='아니오')
dot.edge('process2', 'end')
dot.render('flowchart', cleanup=True)
```
### 시퀀스 다이어그램 (matplotlib)
```python
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig, ax = plt.subplots(1, 1, figsize=(10, 8))
# 액터 라이프라인, 메시지 화살표 등을 matplotlib으로 직접 그리기
ax.set_xlim(0, 10)
ax.set_ylim(0, 10)
ax.invert_yaxis()
ax.axis('off')
plt.savefig('sequence.png', dpi=150, bbox_inches='tight')
```
### ER 다이어그램 (Graphviz)
```python
from graphviz import Graph
er = Graph('ER', format='png', engine='neato')
er.attr('node', shape='box', style='filled', fillcolor='#E8F0FE')
er.node('user', 'User\n─────\nid (PK)\nname\nemail')
er.node('order', 'Order\n─────\nid (PK)\nuser_id (FK)\ntotal')
er.edge('user', 'order', label='1:N')
er.render('er_diagram', cleanup=True)
```
### 조직도 (Graphviz)
```python
from graphviz import Digraph
org = Digraph(format='png')
org.attr(rankdir='TB')
org.attr('node', shape='box', style='rounded,filled', fillcolor='#E3F2FD')
org.node('ceo', 'CEO')
org.node('cto', 'CTO')
org.node('cfo', 'CFO')
org.edges([('ceo', 'cto'), ('ceo', 'cfo')])
org.render('org_chart', cleanup=True)
```
## 스타일 옵션
- 폰트: `fontname='Malgun Gothic'` (한글 지원)
- 색상: HTML 컬러 코드 지원
- 출력 형식: png, svg, pdf
- 레이아웃 엔진: dot(계층), neato(스프링), circo(원형), fdp(포스)
한국어로 안내하세요. 작업 폴더에 Python 스크립트와 결과 파일을 저장하세요.
-109
View File
@@ -1,109 +0,0 @@
---
name: docx-creator
label: Word 문서 생성
description: Python을 사용하여 전문적인 Word 문서(.docx)를 생성합니다. 작업 폴더의 양식 파일을 자동 활용합니다.
icon: \uE8A5
allowed-tools:
- folder_map
- document_read
- file_read
- file_write
- process
- document_assemble
- format_convert
tabs: cowork
---
사용자의 요구에 맞는 전문적인 Word 문서를 Python으로 생성하세요.
## 실행 경로 선택 (Python 가능/불가)
- 먼저 `process``python --version`을 확인하세요.
- Python 가능: 기존 python-docx 경로를 사용하세요.
- Python 불가: `document_assemble`로 문서 본문을 구성하고 `format_convert`로 docx 산출을 시도하세요. 실패 시 Markdown/HTML 결과와 변환 가이드를 함께 제공하세요.
## 사전 준비
먼저 python-docx 패키지가 설치되어 있는지 확인하고, 없으면 설치하세요:
```
process: pip install python-docx
```
## 양식 활용 (템플릿 모드)
작업 폴더에 양식 파일이 있으면 **반드시** 활용하세요:
1. **양식 탐색**: `folder_map`으로 작업 폴더를 스캔하여 `.docx` 파일 확인
2. **양식 후보 판별**:
- 파일명에 "양식", "template", "서식", "표준", "기본" 포함
- 또는 사용자가 명시적으로 "XX 양식으로 작성해줘" 요청
- 또는 사용자가 특정 .docx 파일명을 언급
3. **양식 구조 파악**: `document_read`로 양식 파일의 구조(스타일, 헤더, 섹션)를 먼저 확인
4. **양식 기반 생성**:
```python
doc = Document('양식_보고서.docx') # ← 빈 Document() 대신 양식 로드
# 양식의 스타일, 머리글/바닥글, 로고, 페이지 설정이 자동 상속됨
# 기존 본문 내용을 지우고 새 내용만 추가
for paragraph in doc.paragraphs:
paragraph.clear() # 기존 내용 제거
# 또는 필요에 따라 특정 섹션만 교체
```
5. **양식이 없으면**: 아래 기본 템플릿으로 새 문서 생성
## 작업 절차
1. **요구사항 파악**: 사용자가 원하는 문서의 종류, 구조, 내용을 확인
2. **양식 확인**: folder_map으로 작업 폴더에 양식 .docx 파일이 있는지 확인
3. **Python 스크립트 작성**: file_write로 .py 파일 생성
4. **스크립트 실행**: `process`로 Python 스크립트 실행
5. **결과 확인**: 생성된 .docx 파일 경로를 사용자에게 안내
## Python 스크립트 템플릿
```python
from docx import Document
from docx.shared import Inches, Pt, Cm
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.style import WD_STYLE_TYPE
import os
# 양식 파일 자동 감지
template_keywords = ['양식', 'template', '서식', '표준', '기본']
template_file = None
for f in os.listdir('.'):
if f.endswith('.docx') and any(kw in f.lower() for kw in template_keywords):
template_file = f
break
# 양식이 있으면 활용, 없으면 새 문서
if template_file:
doc = Document(template_file)
print(f'양식 활용: {template_file}')
else:
doc = Document()
# 스타일 설정 (양식이 없을 때만)
style = doc.styles['Normal']
font = style.font
font.name = '맑은 고딕'
font.size = Pt(11)
# 제목
doc.add_heading('문서 제목', level=0)
# 본문
doc.add_paragraph('내용을 여기에 작성합니다.')
# 표
table = doc.add_table(rows=2, cols=3)
table.style = 'Light Grid Accent 1'
# 저장
doc.save('output.docx')
```
## 지원 기능
- 제목/소제목 계층 구조
- 표 (스타일, 병합, 서식)
- 이미지 삽입
- 머리글/바닥글
- 페이지 번호
- 목차
- 글머리 기호/번호 목록
- **양식 파일 기반 스타일 상속** (로고, 헤더, 페이지 설정 자동 유지)
한국어로 안내하세요. 작업 폴더에 Python 스크립트와 결과 파일을 저장하세요.
-55
View File
@@ -1,55 +0,0 @@
---
name: email-draft
label: 비즈니스 이메일 작성
description: 상황과 톤에 맞는 전문적인 비즈니스 이메일 초안을 생성합니다.
icon: \uE715
allowed-tools:
- clipboard_tool
- file_write
tabs: all
---
사용자의 요청에 맞는 전문적인 비즈니스 이메일을 작성하세요.
## 워크플로우
1. 사용자에게 다음 정보를 확인하세요:
- **수신자**: 이름, 직급, 부서 (알고 있다면)
- **목적**: 요청 / 보고 / 안내 / 감사 / 사과 / 협조 / 초대 / 회신
- **핵심 내용**: 전달할 주요 메시지 (1~3가지)
- **톤**: 공식(格式) / 반공식 / 친근
- **언어**: 한국어 / 영어 / 일본어
2. 이메일 초안을 작성합니다:
- 적절한 인사말로 시작
- 핵심 내용은 **굵게** 강조
- 요청 사항은 명확하고 구체적으로
- 마무리 인사와 서명 포함
3. 사용자에게 초안을 보여주고 수정 요청을 받습니다.
4. 최종본을 clipboard_tool로 클립보드에 복사합니다.
## 이메일 구조
```
제목: [간결하고 명확한 제목]
[수신자] 님께,
[인사말]
[본문 - 목적과 핵심 내용]
[요청 사항 또는 다음 단계]
[마무리 인사]
[서명]
```
## 규칙
- 한 문단은 3~4문장을 넘지 않도록 간결하게
- 수동적 표현보다 능동적 표현 선호
- 약어는 처음 사용 시 풀어 쓰기
- 긴급도에 따라 제목에 [긴급], [참고] 등 태그 사용
-152
View File
@@ -1,152 +0,0 @@
---
name: env-setup
label: 프로젝트 환경 설정
description: .gitignore, requirements.txt, .editorconfig 등 프로젝트 환경 설정 파일을 자동 생성합니다.
icon: \uE835
tabs: code
allowed-tools:
- folder_map
- file_read
- file_write
- process
---
프로젝트 유형에 맞는 환경 설정 파일을 자동으로 생성하세요.
## 작업 절차
1. **프로젝트 분석**: folder_map으로 프로젝트 구조를 파악하고 유형 판별
- `.py` 파일 → Python 프로젝트
- `package.json` 또는 `.js/.ts` 파일 → Node.js 프로젝트
- `.csproj` 또는 `.sln` 파일 → .NET 프로젝트
- `pom.xml` 또는 `.java` 파일 → Java 프로젝트
- 복합 프로젝트인 경우 모든 유형을 병합
2. **기존 설정 확인**: 이미 존재하는 설정 파일이 있는지 확인
- 있으면: 내용을 분석하여 누락된 항목만 추가 제안
- 없으면: 새로 생성
3. **생성할 파일 목록 제안**: 사용자에게 생성할 파일 목록을 보여주고 확인
4. **파일 생성**: file_write로 각 설정 파일 생성
5. **결과 안내**: 생성된 파일 목록과 주요 설정 내용 요약
## 프로젝트별 템플릿
### Python 프로젝트
생성 파일: `.gitignore`, `requirements.txt`, `.editorconfig`, `setup.cfg`, `.flake8`
**.gitignore (Python)**:
```
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
.venv/
*.egg-info/
dist/
build/
.eggs/
*.egg
.mypy_cache/
.pytest_cache/
.coverage
htmlcov/
.env
.idea/
.vscode/
*.log
```
**requirements.txt**: 프로젝트에서 import 문을 스캔하여 자동 생성
### Node.js 프로젝트
생성 파일: `.gitignore`, `.editorconfig`, `.nvmrc`, `.prettierrc`
**.gitignore (Node)**:
```
node_modules/
dist/
build/
.env
.env.local
*.log
npm-debug.log*
.DS_Store
coverage/
.nyc_output/
.idea/
.vscode/
*.tgz
```
### .NET 프로젝트
생성 파일: `.gitignore`, `.editorconfig`, `Directory.Build.props`
**.gitignore (.NET)**:
```
bin/
obj/
.vs/
*.user
*.suo
*.cache
packages/
*.nupkg
TestResults/
.idea/
*.DotSettings.user
```
### Java 프로젝트
생성 파일: `.gitignore`, `.editorconfig`
**.gitignore (Java)**:
```
*.class
*.jar
*.war
*.ear
target/
.gradle/
build/
.idea/
*.iml
.settings/
.classpath
.project
out/
```
## 공통 .editorconfig
```ini
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[*.{json,js,ts,jsx,tsx}]
indent_size = 2
[Makefile]
indent_style = tab
```
## 규칙
- 기존 설정 파일이 있으면 덮어쓰지 않고, 누락 항목만 제안
- .env 파일은 생성하지 않음 (보안 — 사용자가 직접 생성)
- 생성 전 파일 목록을 반드시 사용자에게 확인
- 프로젝트 루트에 생성 (하위 폴더에 생성하지 않음)
한국어로 안내하세요.
-63
View File
@@ -1,63 +0,0 @@
---
name: gen-test
label: 테스트 생성기
description: 지정 파일의 단위 테스트를 자동 생성하고 실행하여 커버리지를 분석합니다.
icon: \uE9D5
allowed-tools:
- file_read
- file_write
- test_loop
- grep
- folder_map
- dev_env_detect
- build_run
tabs: code
---
지정된 소스 파일의 단위 테스트를 자동 생성하고 실행하세요.
## 워크플로우
1. **환경 감지**: dev_env_detect로 프로젝트 타입, 테스트 프레임워크 확인
2. **대상 분석**: file_read로 테스트 대상 파일 분석
- 공개 메서드/함수 목록 추출
- 메서드별 입출력 타입 파악
- 의존성 확인 (Mock 필요 여부)
3. **테스트 생성**: 각 메서드에 대해 테스트 케이스 작성
- 정상 케이스 (Happy Path)
- 경계값 (Boundary)
- 예외/에러 케이스
- null/empty 입력
4. **실행 및 검증**: test_loop으로 테스트 실행
5. **결과 보고**: 성공/실패 요약, 커버리지 추정
## 테스트 작성 원칙
### 명명 규칙
- C#: `[메서드명]_[시나리오]_[기대결과]`
- Python: `test_[메서드명]_[시나리오]`
- JavaScript: `should [기대 동작] when [조건]`
### 테스트 구조 (AAA 패턴)
```
Arrange — 테스트 데이터 준비
Act — 대상 메서드 실행
Assert — 결과 검증
```
### 프레임워크별 지원
- C#: xUnit, NUnit, MSTest
- Python: pytest, unittest
- JavaScript: Jest, Mocha, Vitest
- Java: JUnit 5
## 출력
- 테스트 파일 생성 (프로젝트 컨벤션에 맞는 위치)
- 테스트 실행 결과 요약
- 커버리지 추정 (메서드별 테스트 유무)
## 규칙
- 기존 테스트가 있으면 스타일을 따르기
- 외부 의존성은 Mock/Stub 사용
- 테스트 간 독립성 보장 (상태 공유 금지)
- 한국어 주석으로 테스트 의도 설명
-45
View File
@@ -1,45 +0,0 @@
---
name: hook-policy-demo
label: Hook Policy Demo
description: hooks/hook_filters 런타임 정책 적용 예시 스킬입니다.
icon: \uE943
tabs: code
allowed-tools:
- file_read
- file_edit
- grep
- build_run
when_to_use: 코드 수정 후 특정 훅만 pre/post로 선택 적용하고 싶을 때
argument-hint: 대상 파일 경로 또는 변경 목적
context: fork
agent: worker
effort: medium
sample: true
hooks:
file_edit:
pre:
- lint-pre
post:
- verify-post
build_run:
post:
- verify-post
hook_filters: lint-pre@pre@file_edit, verify-post@post@file_edit, verify-post@post@build_run
---
이 스킬은 `hooks`/`hook_filters` 정책을 함께 사용하는 예시입니다.
## 목표
- 수정 전에는 `lint-pre` 훅만 실행
- 수정 후/빌드 후에는 `verify-post` 훅만 실행
## 실행 가이드
1. `grep` + `file_read`로 대상 코드와 관련 호출부를 확인합니다.
2. 필요한 최소 범위만 `file_edit`로 수정합니다.
3. 수정 후 `build_run`으로 빌드/테스트를 실행해 검증합니다.
4. 변경 내용/검증 결과/남은 리스크를 간단히 보고합니다.
## 제약
- `allowed-tools` 목록 외 도구 호출 금지
- 불필요한 전면 리팩토링 금지
- 동일 실패 재시도 전에 원인/대안 먼저 제시
-87
View File
@@ -1,87 +0,0 @@
---
name: image-processor
label: 이미지 처리
description: Python Pillow를 사용하여 이미지 리사이즈, 크롭, 워터마크, 포맷 변환을 수행합니다.
icon: \uEB9F
allowed-tools:
- folder_map
- file_read
- file_write
- process
- image_analyze
- format_convert
- file_manage
tabs: cowork
---
사용자의 요구에 맞게 이미지를 처리하세요.
## 실행 경로 선택 (Python 가능/불가)
- 먼저 `process``python --version`을 확인하세요.
- Python 가능: 기존 Pillow 경로를 사용하세요.
- Python 불가: `image_analyze`로 이미지 상태를 점검하고, `file_manage`/`format_convert`/`file_write`로 가능한 변환 및 수동 처리 지침을 제공하세요.
## 사전 준비
먼저 Pillow 패키지가 설치되어 있지 확인하고, 없으면 설하세요:
```
process: pip install Pillow
```
## 작업 절
1. **요구사항 파악**: 처리할 이미지 파일과 원하는 작업 확인
2. **Python 스크립트 작성**: file_write로 .py 파일 생성
3. **스크립트 실행**: `process`로 Python 스크립 실행
4. **결과 확인**: 처리된 이미지 파일 경로를 사용자에게 안내
## 지원 기능
### 리사이즈
```python
from PIL import Image
img = Image.open('input.png')
img_resized = img.resize((800, 600)) # 고정 크기
# 또는 비율 유지
img.thumbnail((800, 800))
img.save('output.png')
```
### 크롭
```python
img = Image.open('input.png')
cropped = img.crop((left, top, right, bottom))
cropped.save('output.png')
```
### 워터마크
```python
from PIL import Image, ImageDraw, ImageFont
img = Image.open('input.png')
draw = ImageDraw.Draw(img)
draw.text((10, 10), "Watermark", fill=(255, 255, 255, 128))
img.save('output.png')
```
### 포맷 변환
```python
img = Image.open('input.png')
img.save('output.jpg', 'JPEG', quality=85)
img.save('output.webp', 'WEBP', quality=80)
```
### 배치 처리
```python
import glob
for path in glob.glob('*.png'):
img = Image.open(path)
img.thumbnail((800, 800))
img.save(f'resized_{path}')
```
## 추가 기능
- 회전/뒤집기 (rotate, transpose)
- 밝기/대비/선명도 조절 (ImageEnhance)
- 필터 적용 (ImageFilter: BLUR, SHARPEN, CONTOUR)
- 이미지 합성 (Image.paste, Image.alpha_composite)
- EXIF 정보 읽기
한국어로 안내하세요. 작업 폴더에 Python 스크립트와 결과 파일을 저장하세요.
-67
View File
@@ -1,67 +0,0 @@
---
name: impact
label: 변경 영향 분석
description: 코드 변경 시 영향받는 파일, 함수, 테스트를 식별합니다.
icon: \uE946
allowed-tools:
- lsp_code_intel
- grep
- search_codebase
- git_tool
- file_read
- folder_map
tabs: code
---
코드 변경이 미치는 영향 범위를 분석하여 안전한 수정을 도와주세요.
## 워크플로우
1. **변경 대상 확인**: 어떤 파일/함수/클래스를 변경할 예정인지 파악
2. **직접 참조 분석**: lsp_code_intel의 find_references로 직접 호출처 확인
3. **간접 영향 분석**:
- grep으로 문자열 기반 참조 검색
- search_codebase로 의미적 유사 코드 탐색
- 상속/인터페이스 체인 추적
4. **테스트 영향**: 관련 테스트 파일 식별
5. **위험도 평가**: 변경 영향 범위와 위험도 매트릭스 생성
6. **보고서 작성**: 영향 분석 보고서 생성
## 분석 항목
### 직접 영향
- 해당 함수/클래스를 직접 호출하는 코드
- import/using 하는 파일
- 상속받는 클래스
### 간접 영향
- 인터페이스 구현체를 통한 호출
- 리플렉션/동적 호출
- 설정 파일 참조
- UI 바인딩
### 테스트 영향
- 직접 테스트하는 테스트 파일
- 관련 통합 테스트
- 테스트 더블(Mock) 대상 여부
## 출력 형식
### 영향 분석 보고서
| 영향 수준 | 파일 | 관련 함수 | 위험도 | 비고 |
|----------|------|----------|--------|------|
| 🔴 직접 | A.cs | MethodX() | 높음 | 시그니처 변경 시 컴파일 오류 |
| 🟡 간접 | B.cs | MethodY() | 중간 | 동적 호출, 런타임 오류 가능 |
| 🟢 테스트 | A.Tests.cs | Test1() | 낮음 | 테스트 수정 필요 |
### 변경 체크리스트
- [ ] 직접 참조 N개 확인 및 수정
- [ ] 테스트 M개 업데이트
- [ ] 관련 문서 갱신
## 규칙
- 코드를 직접 수정하지 않음 (분석만 수행)
- 가능하면 LSP 기반 정확한 참조 분석 우선
- LSP 불가 시 grep 기반 텍스트 검색으로 대체
- 위험도는 보수적으로 평가 (의심스러우면 높음)
-107
View File
@@ -1,107 +0,0 @@
---
name: json-schema
label: JSON/YAML 스키마 도구
description: JSON 또는 YAML 데이터에서 스키마를 생성하고, 데이터의 유효성을 검증합니다.
icon: \uE943
tabs: code
allowed-tools:
- json_tool
- file_read
- file_write
- clipboard_tool
---
JSON/YAML 샘플 데이터에서 스키마를 추출하거나, 기존 스키마로 데이터를 검증하세요.
## 작업 절차
1. **요청 유형 판별**:
- **스키마 생성**: 샘플 JSON/YAML → JSON Schema 추출
- **스키마 검증**: 데이터 + 스키마 → 유효성 검사
- **스키마 문서화**: 기존 스키마 → 사람이 읽을 수 있는 설명 생성
2. **입력 데이터 확인**: file_read 또는 사용자 입력으로 데이터 로드
3. **스키마 생성 또는 검증 수행**: json_tool로 처리
4. **결과 출력**: 생성된 스키마 또는 검증 결과를 표시
5. **파일 저장**: file_write로 결과를 저장하거나 clipboard_tool로 복사
## 스키마 생성 규칙
### 타입 추론
| JSON 값 | JSON Schema 타입 | 추가 속성 |
|---------|-----------------|----------|
| `"text"` | `string` | — |
| `123` | `integer` | — |
| `1.5` | `number` | — |
| `true` | `boolean` | — |
| `null` | `null` | nullable 처리 |
| `[]` | `array` | items 스키마 |
| `{}` | `object` | properties 스키마 |
### 추론 강화
- **패턴 감지**: 이메일, URL, 날짜, UUID 등은 `format` 속성 추가
- **열거형 감지**: 값의 종류가 적으면 `enum` 으로 제안
- **필수 필드**: 모든 샘플에 존재하는 필드는 `required`로 표시
- **배열 항목**: 배열 내 모든 항목을 분석하여 통합 스키마 생성
### 출력 형식 (JSON Schema Draft 7)
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "사용자 정보",
"description": "사용자 프로필 데이터 스키마",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "사용자 이름"
},
"email": {
"type": "string",
"format": "email",
"description": "이메일 주소"
},
"age": {
"type": "integer",
"minimum": 0,
"maximum": 150,
"description": "나이"
}
},
"required": ["name", "email"],
"additionalProperties": false
}
```
## 검증 결과 형식
검증 결과는 다음과 같이 표시하세요:
```
검증 결과: ❌ 실패 (3건의 오류)
| # | 경로 | 오류 | 기대값 |
|---|------|------|--------|
| 1 | $.email | 필수 필드 누락 | string (required) |
| 2 | $.age | 타입 불일치 | integer (실제: string) |
| 3 | $.tags[2] | 열거형 불일치 | "A", "B", "C" 중 하나 |
```
## 스키마 문서화 형식
기존 스키마를 분석하여 사람이 읽기 쉬운 문서를 생성:
```
## 사용자 정보 스키마
| 필드 | 타입 | 필수 | 설명 | 제약 조건 |
|------|------|------|------|----------|
| name | string | ✅ | 사용자 이름 | — |
| email | string | ✅ | 이메일 주소 | format: email |
| age | integer | — | 나이 | 0~150 |
| tags | array | — | 태그 목록 | items: string |
```
## 규칙
- JSON Schema Draft 7 형식 사용
- 스키마 생성 시 description 필드를 한국어로 작성
- 복수 샘플이 제공되면 모든 샘플을 분석하여 통합 스키마 생성
- 중첩 객체는 재귀적으로 스키마 추출
- 결과는 파일 저장과 클립보드 복사 모두 제공
한국어로 안내하세요.
-69
View File
@@ -1,69 +0,0 @@
---
name: log-analyze
label: 로그 분석기
description: 로그 파일의 패턴을 분석하고 에러를 요약하며 타임라인을 시각화합니다.
icon: \uE9D9
allowed-tools:
- file_read
- grep
- chart_create
- html_create
- data_pivot
- text_summarize
tabs: cowork
---
로그 파일을 분석하여 패턴, 에러, 추세를 파악하고 보고서를 생성하세요.
## 워크플로우
1. **로그 파일 로드**: file_read로 로그 파일 읽기
2. **패턴 분석**:
- grep으로 에러/경고/예외 패턴 검색
- 시간대별 이벤트 빈도 파악
- 반복되는 에러 패턴 식별
3. **통계 생성**: data_pivot으로 집계
4. **시각화**: chart_create로 타임라인 차트 생성
5. **보고서**: html_create로 분석 보고서 생성
## 분석 항목
### 에러 분석
- ERROR, WARN, FATAL, Exception 키워드 추출
- 에러 유형별 발생 빈도
- 최초 발생 시점 및 최근 발생 시점
- 에러 메시지 클러스터링 (유사 에러 그룹화)
### 시간대 분석
- 시간대별 로그 발생 빈도
- 피크 시간대 식별
- 에러 집중 시간대
### 패턴 분석
- 반복 패턴 (주기적 에러)
- 연쇄 에러 (A 에러 후 B 에러 발생 패턴)
- 비정상 패턴 (평소와 다른 로그량)
## 출력 형식
```
## 로그 분석 보고서
- 분석 기간: [시작] ~ [끝]
- 총 로그: N줄
### 에러 요약 (상위 10건)
| 순위 | 에러 유형 | 발생 횟수 | 최근 발생 |
|------|----------|----------|----------|
### 타임라인 차트
[시간대별 이벤트 빈도 차트]
### 상세 분석
[에러별 상세 내용 및 권장 조치]
```
## 지원 로그 형식
- 일반 텍스트 로그 (타임스탬프 자동 감지)
- JSON 로그 (각 줄이 JSON 객체)
- CSV 로그 (헤더 포함)
- syslog 형식
-174
View File
@@ -1,174 +0,0 @@
---
name: markdown-to-doc
label: Markdown → 문서 변환
description: Markdown 파일을 서식이 적용된 Word(.docx) 또는 PDF 문서로 변환합니다.
icon: \uE8A5
allowed-tools:
- file_read
- file_write
- process
- format_convert
- document_assemble
tabs: cowork
---
Markdown 파일을 전문적인 Word 또는 PDF 문서로 변환하세요.
## 실행 경로 선택 (Python 가능/불가)
- 먼저 `process``python --version`을 확인하세요.
- Python 가능: 기존 python-docx 경로를 사용하세요.
- Python 불가: `format_convert`를 우선 사용해 Markdown을 docx/pdf로 변환하고, 변환 제한 시 `file_write`로 보정 가이드를 생성하세요.
## 사전 준비
먼저 필요한 패키지가 설치되어 있는지 확인하고, 없으면 설치하세요:
```
process: pip install python-docx markdown
```
## 작업 절차
1. **Markdown 파일 확인**: file_read로 변환할 Markdown 파일의 내용과 구조를 파악
2. **변환 옵션 확인**: 사용자에게 다음 옵션을 확인
- 출력 형식: Word(.docx) 또는 PDF
- 폰트: 맑은 고딕 (기본) / 사용자 지정
- 여백, 페이지 크기 설정
- 머리글/바닥글 포함 여부
3. **Python 스크립트 작성**: file_write로 변환 스크립트 생성
4. **스크립트 실행**: `process`로 Python 스크립트 실행
5. **결과 확인**: 생성된 문서 파일 경로와 페이지 수를 안내
## 스타일 매핑
| Markdown | Word 스타일 | 설명 |
|----------|------------|------|
| `# 제목` | Heading 1 | 16pt, 굵게 |
| `## 소제목` | Heading 2 | 14pt, 굵게 |
| `### 항목` | Heading 3 | 12pt, 굵게 |
| 본문 텍스트 | Normal | 11pt |
| `**굵게**` | Bold run | 굵게 |
| `*기울임*` | Italic run | 기울임 |
| `` `코드` `` | 코드 스타일 | Consolas, 배경색 |
| `> 인용` | Quote | 들여쓰기 + 왼쪽 테두리 |
| `- 목록` | List Bullet | 글머리 기호 |
| `1. 번호` | List Number | 번호 목록 |
| 표 | Table Grid | 테두리 표 |
| `---` | 페이지 구분 | 가로선 → 페이지 나누기 |
| 코드 블록 | 코드 단락 | Consolas, 회색 배경 |
## Python 스크립트 템플릿
```python
import re
from docx import Document
from docx.shared import Inches, Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn
import markdown
# Markdown 파일 읽기
with open('input.md', 'r', encoding='utf-8') as f:
md_content = f.read()
doc = Document()
# 기본 스타일 설정
style = doc.styles['Normal']
font = style.font
font.name = '맑은 고딕'
font.size = Pt(11)
style.element.rPr.rFonts.set(qn('w:eastAsia'), '맑은 고딕')
# 여백 설정
for section in doc.sections:
section.top_margin = Cm(2.54)
section.bottom_margin = Cm(2.54)
section.left_margin = Cm(3.17)
section.right_margin = Cm(3.17)
# Markdown 파싱 및 변환
lines = md_content.split('\n')
i = 0
while i < len(lines):
line = lines[i]
# 제목 (Heading)
if line.startswith('#'):
level = len(line) - len(line.lstrip('#'))
text = line.lstrip('#').strip()
doc.add_heading(text, level=min(level, 4))
# 코드 블록
elif line.startswith('```'):
code_lines = []
i += 1
while i < len(lines) and not lines[i].startswith('```'):
code_lines.append(lines[i])
i += 1
p = doc.add_paragraph()
run = p.add_run('\n'.join(code_lines))
run.font.name = 'Consolas'
run.font.size = Pt(9)
# 인용
elif line.startswith('>'):
text = line.lstrip('>').strip()
p = doc.add_paragraph(text)
p.paragraph_format.left_indent = Cm(1.27)
# 글머리 기호
elif line.startswith('- ') or line.startswith('* '):
text = line[2:].strip()
doc.add_paragraph(text, style='List Bullet')
# 번호 목록
elif re.match(r'^\d+\.\s', line):
text = re.sub(r'^\d+\.\s', '', line).strip()
doc.add_paragraph(text, style='List Number')
# 가로선 → 페이지 나누기
elif line.strip() in ('---', '***', '___'):
doc.add_page_break()
# 빈 줄
elif line.strip() == '':
pass
# 일반 텍스트
else:
p = doc.add_paragraph()
# 굵게, 기울임 처리
parts = re.split(r'(\*\*.*?\*\*|\*.*?\*|`.*?`)', line)
for part in parts:
if part.startswith('**') and part.endswith('**'):
run = p.add_run(part[2:-2])
run.bold = True
elif part.startswith('*') and part.endswith('*'):
run = p.add_run(part[1:-1])
run.italic = True
elif part.startswith('`') and part.endswith('`'):
run = p.add_run(part[1:-1])
run.font.name = 'Consolas'
run.font.size = Pt(10)
else:
p.add_run(part)
i += 1
# 저장
doc.save('output.docx')
print(f'변환 완료: output.docx ({len(doc.paragraphs)}개 단락)')
```
## 표 변환
Markdown 표가 있으면 Word 표로 변환합니다:
- 헤더 행: 굵게, 배경색 적용
- 셀 정렬: Markdown의 `:---`, `:---:`, `---:` 구문 반영
- 테두리: 전체 셀에 얇은 테두리
## 규칙
- 원본 Markdown 파일은 수정하지 않음
- 인코딩: UTF-8 기본
- 이미지 링크(`![](path)`)는 로컬 파일이면 삽입, URL이면 경로만 표시
- 복잡한 Markdown(수식, 다이어그램)은 지원 범위와 한계를 안내
- 출력 파일명: 원본 파일명 기준 (.md → .docx)
한국어로 안내하세요. 작업 폴더에 Python 스크립트와 결과 파일을 저장하세요.
-45
View File
@@ -1,45 +0,0 @@
---
name: meeting-minutes
label: 회의록 정리
description: 회의 내용을 체계적으로 정리하여 회의록을 생성합니다.
icon: \uE771
allowed-tools:
- file_read
- file_write
- text_summarize
- template_render
tabs: cowork
---
사용자가 제공한 회의 내용(텍스트, 메모, 파일)을 정리하여 체계적인 회의록을 작성하세요.
다음 도구를 사용하세요:
1. file_read — 회의 관련 파일 읽기 (필요 시)
2. file_write — 회의록 파일 생성
회의록 형식:
## 회의 정보
- 일시:
- 참석자:
- 장소/방법:
- 주제:
## 안건 및 논의 내용
각 안건별로:
- **안건**: 주제
- **논의 내용**: 주요 발언 및 의견 정리
- **결정 사항**: 합의된 내용
## 액션 아이템
| 번호 | 담당자 | 내용 | 기한 | 비고 |
|------|--------|------|------|------|
| 1 | - | - | - | - |
## 다음 회의
- 예정일:
- 주요 안건:
규칙:
- 핵심 내용 위주로 간결하게 정리
- 결정 사항과 액션 아이템은 명확하게 기술
- 한국어로 작성
-118
View File
@@ -1,118 +0,0 @@
---
name: ocr-extract
label: OCR 텍스트 추출
description: Python pytesseract를 사용하여 이미지/스캔 문서에서 텍스트를 추출합니다.
icon: \uE8D4
allowed-tools:
- file_read
- file_write
- process
- image_analyze
- text_summarize
tabs: cowork
---
이미지 또는 스캔된 문서에서 텍스트를 추출하세요.
## 실행 경로 선택 (Python 가능/불가)
- 먼저 `process``python --version`을 확인하세요.
- Python 가능: 기존 pytesseract 경로를 사용하세요.
- Python 불가: `image_analyze`로 텍스트 후보를 추출하고 `text_summarize` + `file_write`로 정제본을 제공하세요.
## 사전 준비
1. Tesseract OCR 엔진이 시스템에 설치되어 있어야 합니다.
- Windows: https://github.com/UB-Mannheim/tesseract/wiki 에서 설치
- 한국어 지원: 설치 시 "Korean" 언어 데이터 선택
2. Python 패키지 설치:
```
process: pip install pytesseract Pillow
```
## 작업 절차
1. **이미지 확인**: 사용자가 제공한 이미지 파일 확인
2. **전처리 (선택)**: 이미지 품질이 낮으면 전처리 스크립트 적용
3. **OCR 실행**: pytesseract로 텍스트 추출
4. **결과 저장**: 추출된 텍스트를 파일로 저장하고 사용자에게 안내
## OCR 스크립트 템플릿
### 기본 텍스트 추출
```python
import pytesseract
from PIL import Image
# Windows에서 Tesseract 경로 지정 (필요 시)
# pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
img = Image.open('scan.png')
text = pytesseract.image_to_string(img, lang='kor+eng')
print(text)
with open('extracted.txt', 'w', encoding='utf-8') as f:
f.write(text)
```
### 이미지 전처리 (품질 개선)
```python
from PIL import Image, ImageFilter, ImageEnhance
img = Image.open('scan.png')
# 그레이스케일 변환
img = img.convert('L')
# 대비 향상
enhancer = ImageEnhance.Contrast(img)
img = enhancer.enhance(2.0)
# 선명도 향상
img = img.filter(ImageFilter.SHARPEN)
# 이진화 (흑백)
threshold = 128
img = img.point(lambda x: 255 if x > threshold else 0)
img.save('preprocessed.png')
text = pytesseract.image_to_string(img, lang='kor+eng')
```
### 배치 OCR (여러 이미지)
```python
import glob
import pytesseract
from PIL import Image
results = []
for path in sorted(glob.glob('*.png')):
img = Image.open(path)
text = pytesseract.image_to_string(img, lang='kor+eng')
results.append(f'--- {path} ---\n{text}\n')
with open('all_extracted.txt', 'w', encoding='utf-8') as f:
f.write('\n'.join(results))
```
### 표 영역 추출
```python
import pytesseract
from PIL import Image
img = Image.open('table.png')
# TSV 형식으로 추출 (표 구조 보존)
tsv_data = pytesseract.image_to_data(img, lang='kor+eng', output_type=pytesseract.Output.DATAFRAME)
print(tsv_data)
```
## 지원 언어
- `kor` — 한국어
- `eng` — 영어
- `kor+eng` — 한국어+영어 혼합 (권장)
- `jpn` — 일본어
- `chi_sim` — 중국어 간체
## 팁
- 스캔 해상도 300dpi 이상이면 인식률이 높습니다
- 기울어진 이미지는 `img.rotate()` 로 보정 후 추출하세요
- 손글씨는 인식률이 낮을 수 있습니다
한국어로 안내하세요. 작업 폴더에 Python 스크립트와 결과 파일을 저장하세요.
-59
View File
@@ -1,59 +0,0 @@
---
name: paper-review
label: 논문 분석
description: 논문 또는 기술 문서를 체계적으로 분석하고 핵심 내용을 정리합니다.
icon: \uE736
allowed-tools:
- document_read
- file_read
- file_write
- text_summarize
tabs: cowork
---
사용자가 제공한 논문 또는 기술 문서를 체계적으로 분석하세요.
## 파일 읽기 전략
- **PDF 파일**: 반드시 `document_read` 도구를 사용하세요. 페이지 범위 지정이 가능합니다.
- 먼저 전체 페이지 수를 확인한 후, 초록(1-2페이지)→본문→참고문헌 순으로 읽으세요.
- `file_read`로 PDF를 읽으면 텍스트가 깨질 수 있으므로 사용하지 마세요.
- **텍스트 파일** (.txt, .md, .html 등): `file_read` 도구를 사용하세요.
## 사용 도구
1. document_read — PDF 논문 파일 읽기 (페이지 범위 지정, 초록/참고문헌 추출)
2. file_read — 텍스트 기반 문서 파일 읽기
3. file_write — 분석 보고서 생성
## 분석 항목
## 논문 개요
- 제목, 저자, 발표 연도/학회
- 연구 분야 및 키워드
## 연구 목적 및 배경
- 연구 문제 정의
- 기존 연구의 한계점
## 방법론
- 제안 방법의 핵심 아이디어
- 실험 설계 및 데이터셋
## 주요 결과
- 핵심 실험 결과 (표/수치 인용)
- 기존 방법 대비 개선점
## 한계점 및 향후 연구
- 저자가 인정한 한계
- 발전 가능성
## 실무 적용 가능성
- 우리 업무에 적용할 수 있는 포인트
- 기술 도입 시 고려사항
## 작업 절차
1. 사용자가 파일명을 언급하면 작업 폴더에서 해당 파일을 찾아 읽기
2. PDF인 경우 `document_read`로 초록(1-2p) 먼저 읽어 전체 구조 파악
3. 본문을 페이지 범위별로 나누어 순차 읽기
4. 위 분석 항목에 따라 체계적으로 정리
5. `file_write`로 분석 보고서를 마크다운 파일로 저장
한국어로 작성하고, 전문 용어는 원문과 함께 표기하세요.
-74
View File
@@ -1,74 +0,0 @@
---
name: pdf-processor
label: PDF 처리
description: Python을 사용하여 PDF에서 텍스트/표를 추출하거나 PDF를 생성합니다.
icon: \uE9F9
allowed-tools:
- folder_map
- document_read
- file_read
- file_write
- process
- format_convert
tabs: cowork
---
PDF 파일을 읽거나 새 PDF를 생성하세요.
## 실행 경로 선택 (Python 가능/불가)
- 먼저 `process``python --version`을 확인하세요.
- Python 가능: 기존 pypdf/pdfplumber/reportlab 경로를 사용하세요.
- Python 불가: `document_read`로 텍스트/구조를 추출하고, 생성 작업은 `format_convert` + `file_write` 기반으로 대체하세요.
## 사전 준비
필요한 패키지를 확인하고 설치하세요:
```
process: pip install pypdf pdfplumber reportlab
```
## 작업 절차
### PDF 텍스트 추출
1. **파일 확인**: folder_map으로 PDF 파일 위치 확인
2. **추출 스크립트 작성**: file_write로 Python 스크립트 생성
3. **실행**: `process`로 실행
4. **결과 전달**: 추출된 텍스트를 사용자에게 전달
### PDF 생성
1. **내용 파악**: 사용자가 원하는 문서 내용 확인
2. **생성 스크립트 작성**: file_write로 Python 스크립트 생성
3. **실행 및 확인**: `process`로 실행
## 텍스트 추출 템플릿
```python
import pdfplumber
import json
results = []
with pdfplumber.open('input.pdf') as pdf:
for i, page in enumerate(pdf.pages):
text = page.extract_text() or ''
tables = page.extract_tables() or []
results.append({
'page': i + 1,
'text': text,
'tables': tables,
})
with open('pdf_extracted.json', 'w', encoding='utf-8') as f:
json.dump(results, f, ensure_ascii=False, indent=2)
for r in results:
print(f"--- 페이지 {r['page']} ---")
print(r['text'][:500])
```
## 지원 기능
- 텍스트 추출 (페이지별)
- 표 추출 (구조 보존)
- PDF 병합 / 분할
- PDF 생성 (reportlab)
- 페이지 회전
- 메타데이터 읽기
한국어로 안내하세요. 원본 PDF는 수정하지 마세요.
-94
View File
@@ -1,94 +0,0 @@
---
name: perf-audit
label: 성능 감사
description: 코드 복잡도, 성능 병목, 메모리 이슈를 분석하고 최적화 방안을 제시합니다.
icon: \uE9D9
allowed-tools:
- file_read
- grep
- folder_map
- search_codebase
- glob
- html_create
tabs: code
---
코드베이스의 성능 관련 이슈를 분석하고 최적화 보고서를 생성하세요.
## 워크플로우
1. **프로젝트 분석**: folder_map으로 구조 파악, 언어/프레임워크 식별
2. **복잡도 분석**: 파일별 줄 수, 메서드 크기, 중첩 깊이 측정
3. **성능 안티패턴 탐지**: grep으로 알려진 성능 이슈 패턴 검색
4. **메모리 이슈 탐지**: 리소스 해제 누락, 대용량 할당 패턴
5. **보고서 생성**: html_create로 성능 감사 보고서
## 분석 항목
### 코드 복잡도 지표
- **파일 크기**: 500줄 이상 파일 식별
- **메서드 크기**: 50줄 이상 메서드 식별
- **중첩 깊이**: 4단계 이상 들여쓰기
- **매개변수 수**: 5개 이상 파라미터 메서드
### 성능 안티패턴
#### 데이터베이스
- N+1 쿼리 패턴 (루프 내 DB 호출)
- SELECT * 사용 (불필요한 컬럼 로드)
- 인덱스 미사용 쿼리 힌트
#### 메모리
- IDisposable 미해제 (using 미사용)
- 대용량 문자열 결합 (StringBuilder 미사용)
- 정적 컬렉션 무한 증가
- 이벤트 핸들러 미해제 (메모리 누수)
#### I/O
- 동기 파일 I/O (async 미사용)
- 동기 네트워크 호출
- 불필요한 직렬화/역직렬화
#### 알고리즘
- O(n²) 이상 루프 (중첩 foreach/for)
- 반복 계산 (캐싱 미적용)
- LINQ 체인의 불필요한 ToList()
#### 프론트엔드
- 불필요한 리렌더링 패턴
- 대용량 번들 임포트
- 이미지 최적화 미적용
### .NET 전용 패턴
```
탐지 대상:
- Task.Result / .Wait() (데드락 위험)
- lock 내부 async 호출
- GC.Collect() 직접 호출
- Reflection 반복 사용
- string + string 반복 (루프 내)
```
## 출력 형식
### 성능 감사 보고서
**요약 대시보드**
| 지표 | 값 | 상태 |
|------|-----|------|
| 총 파일 수 | ... | — |
| 대형 파일 (500줄+) | ... | ⚠ |
| 대형 메서드 (50줄+) | ... | ⚠ |
| 성능 안티패턴 | ... | 🔴 |
| 메모리 이슈 | ... | 🟡 |
**상세 이슈 목록**
| 우선순위 | 파일 | 라인 | 이슈 | 영향 | 권장 조치 |
|---------|------|------|------|------|----------|
| 🔴 높음 | ... | ... | N+1 쿼리 | 응답 지연 | 일괄 로드 |
## 규칙
- 코드를 수정하지 않음 (분석 + 보고서만)
- 성능 이슈는 영향도와 수정 난이도를 함께 평가
- 추측보다 패턴 기반 탐지 우선
- 한국어로 작성
-123
View File
@@ -1,123 +0,0 @@
---
name: pptx-creator
label: PPT 프레젠테이션 생성
description: Python을 사용하여 전문적인 PowerPoint 프레젠테이션을 생성합니다. 작업 폴더의 양식 파일을 자동 활용합니다.
icon: \uE7BE
allowed-tools:
- folder_map
- document_read
- file_read
- file_write
- process
- pptx_create
- template_render
tabs: cowork
---
사용자의 요구에 맞는 PowerPoint 프레젠테이션을 Python으로 생성하세요.
## 실행 경로 선택 (Python 가능/불가)
- 먼저 `process``python --version`을 확인하세요.
- Python 가능: 기존 python-pptx 경로를 사용하세요.
- Python 불가: `pptx_create`로 슬라이드 초안을 생성하고 `template_render` + `file_write`로 발표자료 구조를 보강하세요.
## 사전 준비
필요한 패키지를 확인하고 설치하세요:
```
process: pip install python-pptx
```
## 양식 활용 (마스터 슬라이드 템플릿)
작업 폴더에 PPT 양식이 있으면 **반드시** 활용하세요:
1. **양식 탐색**: `folder_map`으로 작업 폴더를 스캔하여 `.pptx` 파일 확인
2. **양식 후보 판별**:
- 파일명에 "양식", "template", "서식", "표준", "기본" 포함
- 또는 사용자가 명시적으로 "XX 양식으로 작성해줘" 요청
- 또는 사용자가 특정 .pptx 파일명을 언급
3. **양식 구조 파악**: `document_read`로 양식의 슬라이드 레이아웃 목록 확인
4. **양식 기반 생성**:
```python
prs = Presentation('양식_발표.pptx')
# 마스터 슬라이드의 배경, 로고, 색 테마, 폰트가 자동 상속
# 기존 슬라이드 제거 후 새 내용 추가
while len(prs.slides) > 0:
rId = prs.slides._sldIdLst[0].rId
prs.part.drop_rel(rId)
del prs.slides._sldIdLst[0]
```
5. **레이아웃 확인** (양식마다 다를 수 있음):
```python
for i, layout in enumerate(prs.slide_layouts):
print(f'{i}: {layout.name}')
```
6. **양식이 없으면**: 아래 기본 템플릿으로 새 프레젠테이션 생성
## 작업 절차
1. **요구사항 파악**: 발표 주제, 슬라이드 수, 스타일 확인
2. **양식 확인**: folder_map으로 작업 폴더에 양식 .pptx 파일이 있는지 확인
3. **스크립트 작성**: file_write로 Python 스크립트 생성
4. **실행**: `process`로 스크립트 실행
5. **결과 안내**: 생성된 .pptx 파일 경로를 사용자에게 전달
## 스크립트 템플릿
```python
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN
import os
# 양식 파일 자동 감지
template_keywords = ['양식', 'template', '서식', '표준', '기본']
template_file = None
for f in os.listdir('.'):
if f.endswith('.pptx') and any(kw in f.lower() for kw in template_keywords):
template_file = f
break
# 양식이 있으면 활용, 없으면 새 프레젠테이션
if template_file:
prs = Presentation(template_file)
# 기존 슬라이드 제거 (마스터/레이아웃은 유지)
while len(prs.slides) > 0:
rId = prs.slides._sldIdLst[0].rId
prs.part.drop_rel(rId)
del prs.slides._sldIdLst[0]
print(f'양식 활용: {template_file}')
print(f'사용 가능한 레이아웃: {[l.name for l in prs.slide_layouts]}')
else:
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
# 제목 슬라이드
slide = prs.slides.add_slide(prs.slide_layouts[0])
slide.shapes.title.text = '프레젠테이션 제목'
if len(slide.placeholders) > 1:
slide.placeholders[1].text = '부제목'
# 내용 슬라이드
slide = prs.slides.add_slide(prs.slide_layouts[1])
slide.shapes.title.text = '섹션 제목'
body = slide.placeholders[1]
body.text = '첫 번째 포인트'
p = body.text_frame.add_paragraph()
p.text = '두 번째 포인트'
prs.save('presentation.pptx')
print('프레젠테이션 생성 완료: presentation.pptx')
```
## 지원 기능
- 제목/내용/빈 슬라이드 레이아웃
- 텍스트 서식 (글꼴, 크기, 색상, 정렬)
- 표 삽입
- 이미지 삽입
- 도형 (사각형, 원, 화살표)
- 차트 (막대, 선, 원형)
- 슬라이드 번호
- 마스터 슬라이드 커스터마이징
- **양식 파일 기반 마스터/레이아웃 상속** (배경, 로고, 색 테마, 폰트 자동 유지)
한국어로 안내하세요. 작업 폴더에 결과 파일을 저장하세요.
-100
View File
@@ -1,100 +0,0 @@
---
name: prd-generator
label: 요구사항 정의서 (PRD)
description: 제품 요구사항 정의서, 유저 스토리, 수용 기준을 체계적으로 생성합니다.
icon: \uE8A5
allowed-tools:
- file_read
- file_write
- html_create
- docx_create
- document_plan
- document_assemble
tabs: cowork
---
제품/기능의 요구사항 정의서(PRD)를 체계적으로 작성하세요.
## 워크플로우
1. **요구사항 수집**: 사용자에게 다음을 확인
- 제품/기능 이름
- 목적과 배경
- 대상 사용자
- 핵심 기능 목록
- 제약 조건 (기술, 일정, 예산)
2. **구조화**: document_plan으로 PRD 개요 설계
3. **상세 작성**: 섹션별 상세 내용 작성
- 유저 스토리 (As a... I want... So that...)
- 수용 기준 (Given... When... Then...)
- 기능 우선순위 (MoSCoW)
4. **문서 생성**: document_assemble 또는 html_create로 최종 문서
## PRD 구조
### 1. 개요
- 제품/기능 이름
- 버전 / 작성일 / 작성자
- 문서 목적
### 2. 배경 및 목적
- 비즈니스 배경
- 해결하려는 문제
- 기대 효과 (정량적 KPI)
### 3. 대상 사용자
- 사용자 페르소나
- 사용 시나리오
- 사용자 여정 맵
### 4. 기능 요구사항
#### 유저 스토리 형식
```
US-001: [기능명]
As a [역할],
I want [기능],
So that [가치].
수용 기준:
- Given [사전 조건], When [행동], Then [기대 결과]
- Given ..., When ..., Then ...
우선순위: Must Have / Should Have / Could Have / Won't Have
```
### 5. 비기능 요구사항
- 성능 (응답 시간, 처리량)
- 보안 (인증, 권한, 암호화)
- 접근성 (WCAG 수준)
- 호환성 (브라우저, OS, 디바이스)
### 6. 기술 제약
- 기술 스택 제한
- 연동 시스템
- 데이터 마이그레이션
### 7. 일정 및 마일스톤
| 마일스톤 | 예정일 | 산출물 |
|---------|--------|--------|
| 설계 완료 | ... | 상세 설계서 |
| 개발 완료 | ... | 릴리즈 빌드 |
| QA 완료 | ... | 테스트 보고서 |
### 8. 성공 지표
- 핵심 KPI 및 측정 방법
- 목표 수치
### 9. 리스크 및 대안
| 리스크 | 영향 | 대안 |
|--------|------|------|
| ... | 높음 | ... |
## 규칙
- 사용자 관점에서 작성 (기술 용어 최소화)
- 유저 스토리는 INVEST 원칙 준수 (Independent, Negotiable, Valuable, Estimable, Small, Testable)
- 수용 기준은 테스트 가능하도록 구체적으로
- 한국어로 작성 (영어 용어 병기 가능)
-72
View File
@@ -1,72 +0,0 @@
---
name: refactor
label: 리팩토링 가이드
description: 코드베이스를 분석하여 리팩토링 포인트를 식별하고 실행 계획을 생성합니다.
icon: \uE90F
allowed-tools:
- search_codebase
- grep
- file_read
- code_review
- folder_map
- lsp_code_intel
tabs: code
# hooks / hook_filters 예시 (옵션):
# hooks:
# file_edit:
# pre:
# - lint-pre
# post: verify-post
# hook_filters: lint-pre@pre@file_edit, verify-post@post@*
---
코드베이스를 분석하여 리팩토링이 필요한 부분을 식별하고 개선 계획을 수립하세요.
## 워크플로우
1. **구조 파악**: folder_map + grep으로 프로젝트 전체 구조 분석
2. **코드 스멜 탐지**:
- 중복 코드 (grep으로 유사 패턴 검색)
- 긴 메서드/클래스 (file_read로 크기 확인)
- 복잡한 조건문 (중첩 if/switch)
- 미사용 코드 (lsp_code_intel로 참조 확인)
3. **의존성 분석**: lsp_code_intel로 참조 관계 파악
4. **우선순위 결정**: 영향도 × 난이도 매트릭스
5. **리팩토링 계획 생성**: 단계별 실행 계획
## 분석 항목
### 코드 스멜 (Code Smells)
- **중복 코드**: 3곳 이상 반복되는 유사 코드
- **거대 클래스**: 500줄 이상의 클래스
- **긴 메서드**: 50줄 이상의 메서드
- **매개변수 과다**: 5개 이상 파라미터
- **의존성 순환**: 상호 참조 관계
- **매직 넘버**: 하드코딩된 숫자/문자열
- **깊은 중첩**: 4단계 이상 들여쓰기
### 리팩토링 기법 (제안)
- Extract Method / Extract Class
- Rename (변수, 메서드, 클래스)
- Move Method / Move Field
- Replace Conditional with Polymorphism
- Introduce Parameter Object
- Remove Dead Code
## 출력 형식
### 리팩토링 보고서
| 우선순위 | 파일 | 이슈 | 제안 | 영향도 | 난이도 |
|---------|------|------|------|--------|--------|
| 🔴 높음 | ... | ... | ... | ★★★ | ★☆☆ |
| 🟡 중간 | ... | ... | ... | ★★☆ | ★★☆ |
### 실행 계획
1. [안전한 변경부터] ...
2. [테스트 추가 후] ...
3. [구조 변경] ...
## 규칙
- 코드를 직접 수정하지 않음 (분석 + 계획만)
- 기존 테스트가 있으면 테스트 커버리지 확인
- 팀 컨벤션/스타일 가이드 존중
-86
View File
@@ -1,86 +0,0 @@
---
name: regex-helper
label: 정규식 도우미
description: 정규식 패턴을 생성하고, 기존 패턴을 해석하며, 테스트 케이스로 검증합니다.
icon: \uE8FD
tabs: code
allowed-tools:
- regex_tool
- clipboard_tool
- file_read
---
사용자의 요구에 맞는 정규식 패턴을 작성하거나, 기존 패턴을 해석하고 테스트하세요.
## 작업 절차
1. **요구사항 파악**: 사용자의 요청 유형을 판별
- **패턴 생성**: "이메일 주소를 찾는 정규식 만들어줘"
- **패턴 해석**: "이 정규식이 무슨 뜻이야? `^[\w.-]+@[\w.-]+\.\w+$`"
- **패턴 테스트**: "이 패턴이 이 문자열에 매칭되는지 확인해줘"
2. **패턴 작성 또는 분석**:
- 생성: 요구사항을 분석하여 정규식 패턴 작성
- 해석: 패턴을 구성 요소별로 분해하여 설명
3. **테스트 수행**: regex_tool로 패턴을 테스트 케이스에 적용
- 매칭되어야 할 문자열 (positive cases)
- 매칭되지 않아야 할 문자열 (negative cases)
4. **결과 설명**: 매칭 결과와 캡처 그룹을 상세히 설명
5. **최적화 제안**: 성능 또는 가독성 개선이 가능하면 대안 제시
## 패턴 생성 가이드
### 자주 사용되는 패턴
| 용도 | 패턴 | 설명 |
|------|------|------|
| 이메일 | `[\w.-]+@[\w.-]+\.\w{2,}` | 기본 이메일 형식 |
| 전화번호 (한국) | `0\d{1,2}-\d{3,4}-\d{4}` | 010-1234-5678 형식 |
| 날짜 (YYYY-MM-DD) | `\d{4}-(?:0[1-9]\|1[0-2])-(?:0[1-9]\|[12]\d\|3[01])` | ISO 날짜 형식 |
| IP 주소 | `(?:\d{1,3}\.){3}\d{1,3}` | IPv4 기본 |
| URL | `https?://[\w.-]+(?:/[\w./?#&=-]*)?` | HTTP/HTTPS URL |
| 한글만 | `[가-힣]+` | 한글 문자 |
| 사업자등록번호 | `\d{3}-\d{2}-\d{5}` | 123-45-67890 형식 |
### 패턴 해석 형식
패턴을 해석할 때는 다음 구조로 설명하세요:
```
패턴: ^(\d{3})-(\d{2})-(\d{5})$
해석:
^ → 문자열 시작
(\d{3}) → 캡처 그룹 1: 숫자 3자리
- → 하이픈 (리터럴)
(\d{2}) → 캡처 그룹 2: 숫자 2자리
- → 하이픈 (리터럴)
(\d{5}) → 캡처 그룹 3: 숫자 5자리
$ → 문자열 끝
```
## 테스트 형식
테스트 결과는 다음 형식으로 표시하세요:
```
패턴: \d{3}-\d{2}-\d{5}
✅ 매칭 성공:
"123-45-67890" → 전체 매칭: "123-45-67890"
"사업자번호: 123-45-67890입니다" → 부분 매칭: "123-45-67890"
❌ 매칭 실패:
"12-345-67890" → 형식 불일치
"abc-de-fghij" → 숫자가 아닌 문자
```
## 플래그 안내
| 플래그 | 설명 |
|--------|------|
| `i` | 대소문자 무시 |
| `m` | 멀티라인 (^$가 각 줄에 적용) |
| `s` | 점(.)이 줄바꿈도 매칭 |
| `g` | 전역 검색 (모든 매칭) |
## 규칙
- 패턴 생성 시 positive/negative 테스트 케이스를 반드시 포함
- 복잡한 패턴은 주석이 포함된 확장 모드(`x`)로 설명
- 캡처 그룹이 있으면 각 그룹의 의미를 설명
- 성능에 민감한 경우 탐욕적/게으른 수량자 선택 이유를 설명
- 최종 패턴은 clipboard_tool로 클립보드에 복사
한국어로 안내하세요.
-96
View File
@@ -1,96 +0,0 @@
---
name: release-note
label: 릴리즈 노트 생성
description: 비개발자 대상의 사용자 친화적인 릴리즈 노트를 자동 생성합니다.
icon: \uE70B
tabs: code
allowed-tools:
- file_read
- file_write
- clipboard_tool
- html_create
---
사용자(비개발자) 대상의 읽기 쉬운 릴리즈 노트를 작성하세요.
## 작업 절차
1. **변경 정보 수집**: 사용자에게 다음 정보를 확인
- 버전 번호 (예: v1.6.0)
- 릴리즈 날짜
- 주요 변경 내용 (기능 추가, 개선, 버그 수정)
- 참고 자료: CHANGELOG, 커밋 이력, 개발 문서 등
2. **내용 분류**: 수집된 변경 사항을 사용자 관점으로 분류
- 기술 용어 → 사용자 언어로 변환
- 내부 리팩토링 등 사용자에게 무관한 항목은 제외
3. **릴리즈 노트 초안 작성**: 아래 템플릿 기반으로 작성
4. **사용자 검토**: 초안을 보여주고 수정 요청 반영
5. **최종 출력**: Markdown, HTML, 또는 텍스트 형식으로 저장
## 릴리즈 노트 템플릿
```markdown
# [제품명] v[버전] 업데이트 안내
안녕하세요. [제품명] v[버전] 업데이트 소식을 안내드립니다.
## 🎉 새로운 기능
- **[기능 이름]**: [사용자가 얻는 혜택 중심으로 1~2문장 설명]
- **[기능 이름]**: [사용자가 얻는 혜택 중심으로 1~2문장 설명]
## ✨ 개선 사항
- **[개선 영역]**: [무엇이 어떻게 좋아졌는지 설명]
- **[개선 영역]**: [무엇이 어떻게 좋아졌는지 설명]
## 🐛 문제 해결
- [사용자가 겪었던 문제]를 해결했습니다.
- [사용자가 겪었던 문제]를 해결했습니다.
## ⚠️ 알려진 이슈
- [현재 알려진 제한 사항이나 이슈]
- [해결 예정 시기 또는 임시 해결 방법]
---
문의 사항이 있으시면 [연락처/채널]로 알려주세요.
감사합니다.
```
## 작성 원칙
### 사용자 언어로 변환
| 개발 용어 (사용 금지) | 사용자 표현 (사용) |
|---------------------|-------------------|
| API 엔드포인트 추가 | 새로운 연동 기능 추가 |
| 메모리 누수 수정 | 장시간 사용 시 느려지는 문제 해결 |
| UI 리팩토링 | 화면 디자인 개선 |
| 캐시 최적화 | 실행 속도 개선 |
| null 참조 오류 수정 | 예기치 않은 오류로 종료되는 문제 해결 |
| 인코딩 이슈 수정 | 한글이 깨져 보이는 문제 해결 |
| 동시성 버그 수정 | 여러 작업 동시 실행 시 오류 발생 문제 해결 |
### 작성 규칙
- **혜택 중심**: "무엇을 했다"가 아닌 "사용자에게 어떤 도움이 되는지" 설명
- **간결**: 한 항목당 1~2문장 이내
- **구체적**: "성능 개선" → "파일 열기 속도가 약 2배 빨라졌습니다"
- **긍정적 톤**: 문제를 "해결했습니다", 기능을 "추가했습니다"
- **이모지 활용**: 섹션별 시각적 구분 (새 기능: 🎉, 개선: ✨, 수정: 🐛, 주의: ⚠️)
## 출력 형식
- **Markdown**: 기본 출력 형식 (.md)
- **HTML**: html_create로 스타일이 적용된 웹 페이지 생성
- **텍스트**: 이메일 본문용 서식 없는 텍스트
- 사용자가 원하는 형식으로 제공
## 규칙
- 내부 기술 구현 세부사항은 노출하지 않음
- 사용자에게 무관한 변경(코드 리팩토링, 테스트 추가 등)은 제외
- Breaking Change가 있으면 "이전 버전과 달라진 점" 섹션 추가
- 업데이트 방법 안내를 포함 (인스톨러 경로, 주의사항)
- 최종 결과는 파일 저장과 클립보드 복사 모두 제공
한국어로 안내하세요.
-41
View File
@@ -1,41 +0,0 @@
---
name: report-writer
label: 보고서 작성
description: 작업 폴더의 데이터를 분석하여 체계적인 업무 보고서를 생성합다.
icon: \uE9F9
allowed-tools:
- folder_map
- file_read
- file_write
- data_pivot
- chart_create
- template_render
- text_summarize
tabs: cowork
---
작업 폴더의 파일과 데이터를 분석하여 업무 보고서를 작성하세요.
다음 도구를 사용하세요:
1. folder_map — 작업 폴더의 파일 구조 파악
2. file_read — 관련 데이터 파일 읽기 (CSV, Excel, 텍스트)
3. file_write — 보고서 파일 생성 (HTML 또는 Markdown)
보고서 구성:
## 제목
- 작성 일시, 작성자 (요청 시)
## 요약 (Executive Summary)
- 핵심 내용을 3줄 이내로 요약
## 본문
- 데이터 기반 분석 결과
- 표/차트를 활용한 시각적 정리
- 주요 발견 사항
## 결론 및 제안
- 결론 요약
- 향후 조치 사항
HTML 보고서 생성 시 현재 적용된 디자인 무드를 반영하세요.
한국어로 작성하세요.
-93
View File
@@ -1,93 +0,0 @@
---
name: security-audit
label: 보안 코드 감사
description: 코드베이스의 보안 취약점을 점검하고 OWASP 기반 보안 보고서를 생성합니다.
icon: \uE72E
allowed-tools:
- file_read
- grep
- folder_map
- search_codebase
- html_create
- glob
tabs: code
---
코드베이스의 보안 취약점을 체계적으로 점검하고 보고서를 생성하세요.
## 워크플로우
1. **스캔 범위 확인**: folder_map으로 프로젝트 구조 파악, 언어/프레임워크 식별
2. **취약점 패턴 탐지**: grep으로 위험 패턴 검색
3. **의존성 분석**: 패키지 파일(package.json, *.csproj, requirements.txt) 읽기
4. **비밀 정보 노출 검사**: API 키, 토큰, 비밀번호 하드코딩 탐지
5. **보고서 생성**: html_create로 보안 감사 보고서 생성
## OWASP Top 10 점검 항목
### A01 — 접근 제어 취약
- 인증 없는 API 엔드포인트
- 하드코딩된 권한 체크
- 관리자 경로 노출
### A02 — 암호화 실패
- 평문 비밀번호 저장
- 약한 해시 알고리즘 (MD5, SHA1)
- HTTP (비HTTPS) 통신
### A03 — 인젝션
- SQL 인젝션 (문자열 결합 쿼리)
- XSS (innerHTML, dangerouslySetInnerHTML)
- 명령 인젝션 (Process.Start, exec, system)
- 경로 순회 (../ 미검증)
### A04 — 불안전한 설계
- 비즈니스 로직 검증 누락
- 레이트 리밋 미적용
### A05 — 보안 설정 오류
- 디버그 모드 활성화 상태
- 기본 자격증명 사용
- 불필요한 포트/서비스 노출
### A07 — 인증 실패
- 약한 비밀번호 정책
- 세션 만료 미설정
- 브루트포스 방어 부재
### A09 — 로깅/모니터링 부족
- 보안 이벤트 미기록
- 민감 정보 로그 출력
## 비밀 정보 탐지 패턴
```
grep 대상 패턴:
- password\s*=\s*["'][^"']+["']
- api[_-]?key\s*=\s*["'][^"']+["']
- secret\s*=\s*["'][^"']+["']
- token\s*=\s*["'][A-Za-z0-9+/=]{20,}["']
- -----BEGIN (RSA |EC )?PRIVATE KEY-----
- AWS_ACCESS_KEY_ID
- AKIA[0-9A-Z]{16}
```
## 출력 형식
### 보안 감사 보고서
| 위험도 | 카테고리 | 파일 | 라인 | 내용 | 권장 조치 |
|--------|---------|------|------|------|----------|
| 🔴 심각 | A03 인젝션 | ... | ... | SQL 문자열 결합 | 파라미터 바인딩 사용 |
| 🟡 경고 | A02 암호화 | ... | ... | MD5 해시 사용 | SHA-256 이상 전환 |
| 🟢 참고 | A09 로깅 | ... | ... | 에러 로깅 미흡 | 보안 이벤트 로깅 추가 |
### 요약 통계
- 심각/경고/참고 건수
- OWASP 카테고리별 분포
- 우선 조치 항목 Top 5
## 규칙
- 코드를 수정하지 않음 (분석 + 보고서만)
- 발견된 비밀 정보는 마스킹하여 보고 (앞 4자만 표시)
- 위험도는 보수적으로 평가
- 한국어로 보고서 작성
-52
View File
@@ -1,52 +0,0 @@
---
name: sql-report
label: SQL 리포트
description: DB 쿼리를 실행하고 결과를 차트화하여 HTML/Excel 보고서로 생성합니다.
icon: \uE968
allowed-tools:
- sql_tool
- chart_create
- excel_create
- html_create
- data_pivot
tabs: cowork
---
데이터베이스에서 쿼리를 실행하고 결과를 시각화된 보고서로 생성하세요.
## 워크플로우
1. **DB 확인**: sql_tool로 테이블 목록 및 스키마 확인
2. **쿼리 작성**: 사용자 요청에 맞는 SQL 쿼리 작성
3. **데이터 조회**: sql_tool로 쿼리 실행
4. **데이터 가공**: data_pivot으로 집계/피벗 (필요 시)
5. **시각화**: chart_create로 차트 생성
6. **보고서**: html_create 또는 excel_create로 최종 보고서 생성
## 쿼리 작성 원칙
- SELECT 쿼리만 실행 (데이터 변경 금지)
- 결과 행 수 제한: LIMIT 1000 (대량 데이터 방지)
- 인덱스 활용 쿼리 작성
- 한글 컬럼명은 alias로 변환
## 보고서 구성
### 1. 데이터 요약
- 조회 조건, 기간, 데이터 건수
- 기본 통계 (합계, 평균, 최대/최소)
### 2. 시각화
- 적절한 차트 유형 자동 선택
- 비교 → 바 차트
- 추세 → 라인 차트
- 비율 → 파이/도넛 차트
### 3. 상세 데이터
- Excel: 원본 데이터 + 서식 + 수식
- HTML: 테이블 + 정렬/필터
## 규칙
- DB 경로는 사용자에게 확인
- 민감 데이터(개인정보) 마스킹 권고
- 쿼리 실행 전 사용자 승인
- 한국어로 보고서 작성
-60
View File
@@ -1,60 +0,0 @@
---
name: translate
label: 번역 + 교정
description: 문서나 텍스트를 번역하고 전문 용어를 보존하며 교정합니다.
icon: \uE8C1
allowed-tools:
- file_read
- file_write
- document_read
- clipboard_tool
tabs: all
---
사용자가 제공한 텍스트 또는 문서를 번역하고 교정하세요.
## 워크플로우
1. **입력 확인**: 텍스트 직접 입력 또는 파일 경로 확인
2. **언어 감지**: 원문 언어를 자동 감지
3. **번역 실행**:
- 원문의 뉘앙스와 문맥을 살려 번역
- 전문 용어는 원어를 괄호 안에 병기: "수율(Yield)"
- 문화적 차이를 고려한 자연스러운 표현 사용
4. **교정**: 번역 결과의 문법, 맞춤법, 어색한 표현 수정
5. **결과 제공**: 번역문 + 주요 용어 대조표
## 번역 원칙
### 정확성
- 원문의 의미를 정확하게 전달
- 숫자, 날짜, 고유명사는 원문 그대로 유지
- 약어는 처음 등장 시 풀어 번역
### 가독성
- 목표 언어의 자연스러운 문체 사용
- 긴 문장은 적절히 분리
- 수동태 → 능동태 변환 (한국어의 경우)
### 전문성
- 분야별 전문 용어 일관 사용
- 동일 용어는 문서 전체에서 통일
- 번역 불가능한 용어는 원어 유지
## 출력 형식
```
## 번역 결과
[번역된 텍스트]
---
## 용어 대조표
| 원문 | 번역 | 비고 |
|------|------|------|
| Yield | 수율 | 반도체 공정 용어 |
```
## 지원 언어
한국어 ↔ 영어 / 일본어 / 중국어 (간/번체) / 독일어 / 프랑스어 / 스페인어
-65
View File
@@ -1,65 +0,0 @@
---
name: weekly-report
label: 주간 보고서
description: 작업 폴더의 변경 이력을 기반으로 자동 주간보고 초안을 생성합니다.
icon: \uE787
allowed-tools:
- git_tool
- folder_map
- file_read
- file_watch
- html_create
- docx_create
- text_summarize
tabs: cowork
---
작업 폴더의 최근 활동을 분석하여 주간 보고서 초안을 자동 생성하세요.
## 워크플로우
1. **활동 수집**:
- git_tool로 최근 7일간 커밋 이력 조회
- file_watch로 최근 변경/생성된 파일 목록 확인
- folder_map으로 프로젝트 구조 파악
2. **내용 분석**:
- 커밋 메시지 분류 (기능 추가, 버그 수정, 리팩토링 등)
- 변경 파일 유형별 분류
- 주요 변경사항 요약
3. **보고서 작성**:
- HTML 또는 Word 형식으로 보고서 생성
- 차트/표로 활동 통계 시각화
## 보고서 구성
### 1. 주간 요약
- 보고 기간: yyyy-MM-dd ~ yyyy-MM-dd
- 주요 성과 (3줄 이내)
### 2. 완료 항목
| 번호 | 구분 | 내용 | 비고 |
|------|------|------|------|
| 1 | 기능 | ... | 커밋 참조 |
### 3. 진행 중 항목
- 현재 작업 중인 사항
- 진척률 (가능하면)
### 4. 이슈 및 리스크
- 지연 사항
- 블로킹 이슈
### 5. 다음 주 계획
- 예정 작업 항목
### 6. 활동 통계 (차트)
- 일별 커밋 수
- 파일 유형별 변경 비율
## 규칙
- 사실 기반으로 작성 (추측 금지)
- Git 이력이 없으면 파일 변경 이력만으로 작성
- 한국어로 작성
- 보고서 톤: 간결하고 전문적
-110
View File
@@ -1,110 +0,0 @@
---
name: xlsx-analyzer
label: Excel 데이터 분석
description: Python을 사용하여 Excel/CSV 데이터를 분석하고 보고서를 생성합니다. 작업 폴더의 양식 파일을 자동 활용합니다.
icon: \uE9F9
allowed-tools:
- folder_map
- document_read
- file_read
- file_write
- process
- data_pivot
- chart_create
- template_render
tabs: cowork
---
작업 폴더의 Excel 또는 CSV 데이터를 Python으로 분석하세요.
## 실행 경로 선택 (Python 가능/불가)
- 먼저 `process``python --version`을 확인하세요.
- Python 가능: 기존 pandas/openpyxl 경로를 사용하세요.
- Python 불가: `data_pivot`으로 분석 요약을 만들고 `chart_create` + `file_write`로 결과 리포트를 생성하세요.
## 사전 준비
필요한 패키지를 확인하고 설치하세요:
```
process: pip install pandas openpyxl
```
## 양식 활용 (Excel 보고서 템플릿)
작업 폴더에 Excel 양식 파일이 있으면 **반드시** 활용하세요:
1. **양식 탐색**: `folder_map`으로 작업 폴더에서 `.xlsx` 파일 목록 확인
2. **양식 후보 판별**:
- 파일명에 "양식", "template", "서식", "표준", "기본", "보고서양식" 포함
- 또는 사용자가 "XX 양식에 맞춰서 작성해줘" 요청
- 또는 사용자가 특정 .xlsx 파일명을 양식으로 지정
3. **양식 구조 파악**: `document_read`로 양식의 시트 구조, 셀 레이아웃 확인
4. **양식 기반 데이터 삽입**:
```python
from openpyxl import load_workbook
wb = load_workbook('양식_보고서.xlsx')
ws = wb.active
# 양식의 서식(셀 병합, 테두리, 글꼴, 색상, 열 너비)이 그대로 유지됨
# 데이터 영역에만 새 값 삽입
ws['B3'] = '분석 결과값'
wb.save('결과_보고서.xlsx')
```
5. **양식이 없으면**: 아래 기본 방식으로 분석 결과 생성
## 작업 절차
1. **데이터 파일 탐색**: folder_map으로 작업 폴더에서 .xlsx, .csv 파일 확인
2. **양식 확인**: 양식 .xlsx 파일이 있는지 확인 (데이터 파일과 양식 파일 구분)
3. **데이터 읽기**: file_read 또는 document_read로 파일 구조 파악
4. **분석 스크립트 작성**: file_write로 Python 분석 스크립트 생성
5. **실행**: `process`로 스크립트 실행
6. **결과 보고**: 분석 결과를 사용자에게 정리하여 전달
## 분석 스크립트 템플릿
```python
import pandas as pd
import json
import os
df = pd.read_excel('data.xlsx') # 또는 pd.read_csv('data.csv')
report = {
'shape': list(df.shape),
'columns': list(df.columns),
'dtypes': {col: str(dtype) for col, dtype in df.dtypes.items()},
'missing': df.isnull().sum().to_dict(),
'describe': df.describe().to_dict(),
}
# 양식 파일로 결과 내보내기
template_keywords = ['양식', 'template', '서식', '표준', '기본']
template_file = None
for f in os.listdir('.'):
if f.endswith('.xlsx') and f != 'data.xlsx' and any(kw in f.lower() for kw in template_keywords):
template_file = f
break
if template_file:
from openpyxl import load_workbook
wb = load_workbook(template_file)
ws = wb.active
# 양식 서식 유지하면서 데이터 삽입
print(f'양식 활용: {template_file}')
# TODO: 양식 구조에 맞게 데이터 삽입 로직 작성
wb.save('결과_보고서.xlsx')
else:
# 양식 없으면 JSON으로 저장
with open('analysis_result.json', 'w', encoding='utf-8') as f:
json.dump(report, f, ensure_ascii=False, indent=2, default=str)
print(json.dumps(report, ensure_ascii=False, indent=2, default=str))
```
## 지원 분석
- 기본 통계 (평균, 중앙값, 표준편차, 분위수)
- 결측치 분석
- 컬럼별 고유값 분포
- 피벗 테이블 / 그룹별 집계
- 시트 간 비교 분석
- 필터링 및 조건부 추출
- 분석 결과를 새 Excel로 내보내기
- **양식 파일 기반 보고서 생성** (셀 서식, 병합, 테두리, 차트 영역 유지)
한국어로 안내하세요. 원본 파일은 수정하지 마세요.
-48
View File
@@ -1,48 +0,0 @@
---
name: yield-analysis
label: 수율 분석
description: 제조/연구 데이터의 수율을 분석하고 개선 포인트를 도출합니다.
icon: \uE9D2
allowed-tools:
- folder_map
- file_read
- file_write
- data_pivot
- chart_create
- text_summarize
- template_render
tabs: cowork
---
작업 폴더의 데이터를 활하여 수율 분석을 수행하세요.
다음 도구를 사용하세요:
1. folder_map — 데이터 파일 탐색
2. file_read — CSV/Excel 데이터 읽기
3. file_write — 분석 보고서 생성
분석 프로세스:
## 데이터 개요
- 분석 대상 데이터셋 설명
- 데이터 기간, 샘플 수, 주요 변수
## 수율 현황
- 전체 수율 통계 (평균, 중앙값, 표준편차)
- 기간별/로트별/공정별 수율 추이
- 목표 수율 대비 달성률
## 불량 분석
- 불량 유형별 분류 및 비율
- 파레토 분석 (상위 불량 원인)
- 시간대/조건별 불량 패턴
## 상관관계 분석
- 주요 공정 변수와 수율의 관계
- 이상치 탐지 및 원인 추정
## 개선 제안
- 수율 향상을 위한 구체적 조치 사항
- 우선순위별 개선 로드맵
- 예상 개선 효과
표와 수치를 적극 활용하세요. 한국어로 작성하세요.
-1
View File
@@ -1 +0,0 @@
[역할] 당신은 회사 업무의 도움을 주는 매우 유능한 비서입니다. 말투는 정중하게 하며, 욕을 해서는 안됩니다.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
+35 -95
View File
@@ -1,106 +1,46 @@
# AX Agent 로드맵 (전면 재작성)
# AX Agent 로드맵
## 1. 보존 이력 (요약만 유지)
- v0.5.0: MCP 연동, 모델 폴백, 대화 분기, 프리뷰/토큰 관리, 에이전트 루프 강화.
- v0.5.1: 고급 스킬 확장, 워크플로우 분석기, 런타임 감지.
- v0.6.0: 멀티패스 문서 생성, 데이터 피벗/템플릿/이미지 분석 계열 도구 확장.
- v0.7.0: Plan Mode, 병렬 도구 실행, 프로젝트 규칙 주입, 테스트 루프 자동화.
- v0.7.1: 도구 실행 후 검증 게이트 강화, 피드백 컨텍스트 개선.
- v0.7.2: 컨텍스트 압축/복원 안정화, UX/성능 보완.
업데이트: 2026-04-15 18:20 (KST)
## 2. 재작성 기준
- 기준 레퍼런스: `claw-code/claw-code-f5a40b86dede580f6543bf8926c9af017eea9409/src`.
- 목표: 동작 순서, 예외/검증 흐름, 세션 내구성에서 동일 품질 달성.
- 원칙: AX 코드 스타일로 재구성(표현/구조 변경), 기능적 동등성 유지.
## 1. 목표
- AX Agent의 실행 신뢰성, 세션 내구성, 결과 품질을 단계적으로 높입니다.
- 비교·모사 표현 대신 실제 참조 모듈 경로와 AX 적용 위치만 문서에 남깁니다.
- 변경 우선순위는 `상태 -> 실행 -> 렌더 -> UX` 순서로 유지합니다.
## 3. 2026 실행 계획 (v0.7.3 ~ v0.8.0)
## 2. 보존 이력
- v0.5.x: MCP, 모델 폴백, 대화 분기, 프리뷰/토큰 관리, 에이전트 루프 기반 구축
- v0.6.0: 문서 생성, 데이터 피벗, 템플릿/이미지 분석 도구군 확장
- v0.7.0 ~ v0.7.2: Plan Mode, 병렬 도구 실행, 검증 게이트, 컨텍스트 압축 안정화
| Phase | 참조 대상 (`claw-code`) | AX 적용 위치 | 완료 조건 | 품질 판정 시나리오 |
## 3. 2026 실행 계획
| Phase | 참조 대상 | AX 적용 위치 | 완료 조건 | 품질 판정 시나리오 |
|---|---|---|---|---|
| A (v0.7.3) Hook/Permission 계약 고도화 | `src/utils/hooks.ts`, `src/utils/hooks/hookEvents.ts`, `src/utils/permissions/PermissionUpdate.ts`, `src/utils/permissions/permissionSetup.ts` | `src/AxCopilot/Services/Agent/AgentHookRunner.cs`, `src/AxCopilot/Services/Agent/AgentLoopService.cs`, `src/AxCopilot/Models/AppSettings.cs`, `src/AxCopilot/ViewModels/SettingsViewModel.cs`, `src/AxCopilot/Views/SettingsWindow.xaml` | Hook JSON 출력(`updatedInput`, `updatedPermissions`, `additionalContext`) 반영 완료. Plain text 훅 하위호환 유지. 훅 실패 비차단 유지. | Pre-hook 입력 변형 적용 시 도구 입력이 실제 변경되는지 검증. 권한 업데이트 후 동일 run 내 권한 판정이 즉시 반영되는지 검증. |
| B (v0.7.4) Plan/Run 상태 내구성 강화 | `src/utils/plans.ts`, `src/utils/sessionStorage.ts` | `src/AxCopilot/Services/ChatSessionStateService.cs`, `src/AxCopilot/Services/TaskRunService.cs`, `src/AxCopilot/Services/TaskRunStore.cs`, `src/AxCopilot/Views/ChatWindow.xaml.cs` | Plan 단계 승인/수정 이력 영속화. 앱 재시작 후 run 재개 시 마지막 실행 지점 정확 복원. 중복 실행/중복 이벤트 0건. | 실행 중 종료 재실행 같은 탭/대화에서 run 상태와 최근 실행 이력이 일치하는지 검증. |
| C (v0.7.5) 세션/이벤트 로그 정규화 | `src/utils/sessionStorage.ts`(이벤트 기록/복원 규약), `src/utils/hooks/hookEvents.ts` | `src/AxCopilot/Models/ChatModels.cs`, `src/AxCopilot/Services/ChatSessionStateService.cs`, `src/AxCopilot/Services/AppStateService.cs` | 이벤트 스키마 정리(도구 호출/결과/권한/훅/요약). replay 순서 불일치 0건. run 단위 요약 리포트 생성 가능 상태. | 동일 세션을 여러 번 로드해도 실행 이력 순서/상태가 변하지 않는지 검증. |
| D (v0.7.6) 명령/도구 선택 정확도 개선 | `src/commands.ts`, `src/Tool.ts` | `src/AxCopilot/Services/Agent/AgentLoopService.cs`, `src/AxCopilot/Services/Agent/AgentLoopParallelExecution.cs`, `src/AxCopilot/Services/LlmService.ToolUse.cs` | 도구 별칭 정규화 규칙 강화. unknown-tool 재시도 루프 방지. 실패 유형별 복구 흐름 표준화. | 오타/별칭/비활성 도구 요청 시 복구 프롬프트로 정상 도구로 수렴하는지 검증. |
| E (v0.8.0) 품질 게이트 최종 정렬 | `src/query.ts`, `src/QueryEngine.ts`(루프 종료/완료 기준), `src/utils/sessionStorage.ts` | `src/AxCopilot/Services/Agent/AgentLoopService.cs`, `src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs`, `src/AxCopilot/Services/Agent/AgentLoopTransitions.cs` | 코드/문서 작업 완료 게이트를 증거 기반으로 고정. 내부 벤치마크 목표 성공률 충족. 완료 응답 근거 누락률 최소화. | 코드수정/문서생성/권한거부/실패복구 혼합 시나리오에서 조기 완료 없이 근거 기반 종료하는지 검증. |
| A (v0.7.3) Hook/Permission 계약 고도화 | `src/utils/hooks.ts`, `src/utils/hooks/hookEvents.ts`, `src/utils/permissions/PermissionUpdate.ts`, `src/utils/permissions/permissionSetup.ts` | `AgentHookRunner.cs`, `AgentLoopService.cs`, `AppSettings.cs`, `SettingsViewModel.cs`, `SettingsWindow.xaml` | Hook JSON 출력(`updatedInput`, `updatedPermissions`, `additionalContext`) 반영, plain text 훅 하위호환 유지, 훅 실패 비차단 유지 | pre-hook 입력 변형과 권한 업데이트가 같은 run 안에서 즉시 적용되는지 검증 |
| B (v0.7.4) Plan/Run 상태 내구성 강화 | `src/utils/plans.ts`, `src/utils/sessionStorage.ts` | `ChatSessionStateService.cs`, `TaskRunService.cs`, `TaskRunStore.cs`, `ChatWindow.xaml.cs` | plan 승인/수정 이력 영속화, 재시작 후 마지막 run 지점 복원, 중복 이벤트 0건 | 실행 중 종료 재실행 같은 탭/대화에서 run 상태와 최근 이력이 일치하는지 검증 |
| C (v0.7.5) 세션/이벤트 로그 정규화 | `src/utils/sessionStorage.ts`, `src/utils/hooks/hookEvents.ts` | `ChatModels.cs`, `ChatSessionStateService.cs`, `AppStateService.cs` | 이벤트 스키마 정리, replay 순서 불일치 0건, run 단위 요약 리포트 생성 가능 | 같은 세션을 여러 번 로드해도 실행 이력 순서상태가 변하지 않는지 검증 |
| D (v0.7.6) 명령/도구 선택 정확도 개선 | `src/commands.ts`, `src/Tool.ts` | `AgentLoopService.cs`, `AgentLoopParallelExecution.cs`, `LlmService.ToolUse.cs` | 도구 별칭 정규화 강화, unknown-tool 재시도 루프 방지, 실패 유형별 복구 표준화 | 오타/별칭/비활성 도구 요청 정상 도구로 수렴하는지 검증 |
| E (v0.8.0) 품질 게이트 정렬 | `src/query.ts`, `src/QueryEngine.ts`, `src/utils/sessionStorage.ts` | `AgentLoopService.cs`, `AgentLoopTransitions.Execution.cs`, `AgentLoopTransitions.cs` | 코드/문서 작업 완료 게이트를 증거 기반으로 고정, 조기 완료 방지 | 코드수정/문서생성/권한거부/복구 혼합 시나리오에서 근거 기반 종료 검증 |
## 4. 공통 검증 규칙
- 모든 단계: `dotnet build` 경고 0/오류 0.
- 고위험 변경: 최소 1개 이상 재현 테스트 추가.
- 운영모드(`internal`/`external`) 보안 정책 위반 0건.
- 모든 단계에서 `dotnet build` 경고 0 / 오류 0
- 고위험 변경마다 최소 1개 이상 재현 테스트 추가
- `internal` / `external` 운영 모드 정책 위반 0건
## 5. 즉시 착수 항목
1. 내부 벤치마크(기본 loop/복구/권한/hook) 결과를 릴리즈 체크리스트에 연동 유지.
2. 세션 replay 안정성(`Suite=ReplayStability`) 전건 통과를 릴리즈 게이트로 운영.
3. 패리티 수치(테스트 통과 수/게이트 상태)를 로드맵 문서 간 동일 문구로 유지.
1. 내부 벤치마크 결과를 릴리즈 체크리스트에 계속 연결
2. `Suite=ReplayStability` 전건 통과를 릴리즈 게이트로 유지
3. 계획/실행/검증 문서 간 수치와 상태 문구를 같은 기준으로 동기화
## 6. 최신 검증 스냅샷 (2026-04-03)
- `dotnet test --filter "Suite=ParityBenchmark"`: 13/13 통과.
- `dotnet test --filter "Suite=ReplayStability"`: 14/14 통과.
- `dotnet test`: 379/379 통과.
## 6. 최신 검증 스냅샷
- 기준 시점: 2026-04-03
- `dotnet test --filter "Suite=ParityBenchmark"`: 13/13 통과
- `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)
- `__permission_granted__` (post)
- `__permission_denied__` (post)
- payload 기준 필드: `runId`, `tool`, `target`, `permission`, `granted`, `reason`.
- 우선순위:
1. Hook `updatedPermissions`가 현재 run의 `AgentContext.ToolPermissions`를 즉시 갱신.
2. 갱신 후 `context.CheckToolPermissionAsync()`로 최종 판정.
3. hook 실패/예외는 non-blocking(권한 흐름 지속).
4. `additionalContext`는 가능한 경로에서 메시지 컨텍스트로 반영.
- 2026-04-04(추가): `/mcp add/remove/reset` 확장, `tool_search` 기반 복구 프롬프트 강화, 슬래시 힌트 밀도(`rich/balanced/simple`) 연동.
- 2026-04-04(추가2): /mcp login/logout 세션 인증 토큰 지원, /mcp status·/chrome 진단에 Auth(Session) 반영.
- 2026-04-04(추가3): 권한 UX 통합(/permissions·/allowed-tools·/settings permissions), 복구 혼합 테스트 보강, 좌측 패널 실패 필터 노출 정책 rich 전용으로 정렬.
- 2026-04-04 20:27 (KST): Added a dedicated AX Agent theme layer and separated in-chat theme selection into style (`claw/codex/slate`) and mode (`system/light/dark`).
- 2026-04-04 18:03 (KST): Added a Codex-style context usage ring to the composer, exposed direct `/compact` execution from the footer, and surfaced Git branch/change status in the Cowork/Code footer when a repository is connected.
- 2026-04-04 18:03 (KST): Simplified the Cowork footer by removing document format/design selectors and moved those defaults into the AX Agent settings page, with output format centered on AI automatic selection.
- 2026-04-04 18:03 (KST): Minimized AX Agent message headers, changed model quick controls to a popup panel, flattened slash command rows into a Codex-style list, and aligned model/permission/template controls to the same dropdown panel language.
- 2026-04-04 18:03 (KST): Expanded the Git branch badge into a dropdown panel, flattened permission/template popups into row-based lists, and made AI message action bars remain visible for the selected message.
- 2026-04-04 18:03 (KST): Flattened the data-usage popup, added Git branch switching/creation inside the dropdown, and surfaced quick model chips so the inline model panel relies less on ComboBox controls.
- 2026-04-04 18:03 (KST): Replaced the visible inline model/service selectors with custom cards and row lists so the AX Agent quick panel more closely follows the Codex/claude-code control feel.
- 2026-04-04 18:03 (KST): Added recent/favorite grouping to the preset popup and enabled right-click pinning so the preset picker better matches Codex-style frequent-use navigation.
- 2026-04-04 18:03 (KST): Added preset search, made selected messages visually persistent, and flattened more of the permission detail popup into row-based information to keep the panel lighter.
- 2026-04-04 18:03 (KST): Switched recent permission-denied actions to flat row actions, exposed Git upstream state in the branch panel, and made inline quick actions read more like custom stateful cards.
- 2026-04-04 19:07 (KST): Unified AX Agent popup panels around the same row-driven language by flattening permission override details, simplifying collapsible section chrome, adding keyboard-friendly row actions, and turning Git change stats into compact pills.
- 2026-04-04 19:07 (KST): Refined message actions into custom pill buttons with visible labels, fixed the custom action template so border visuals render correctly, and tightened composer/footer density so model, preset, token, permission, and Git controls feel like one system.
- 2026-04-04 19:11 (KST): Reworked the AX Agent timeline so execution events render like thin Codex-style inline logs instead of heavy banners, softened older-history loading into an outline pill, and aligned planning cards to the same message-width rhythm.
- 2026-04-04 19:25 (KST): Tightened user/assistant/streaming cards under one density rule by compressing vertical spacing, card padding, header typography, and message meta spacing to a more Codex-like rhythm.
- 2026-04-04 19:25 (KST): Flattened the composer further by reducing input, model, preset, token, and footer control heights so the bottom work area reads more like a single claw-code-style strip.
- 2026-04-04 19:25 (KST): Matched AX Agent overlay quick settings to inline quick settings with the same `label · value` structure, lighter explanatory copy, and unified section naming.
- 2026-04-04 19:48 (KST): Fixed Chat sidebar topic exploration so clicking the left topic entry surfaces the preset cards again, and made preset selection immediately sync category label, conversation metadata, and saved state.
- 2026-04-04 19:48 (KST): Reduced permission/data-usage UI lag by synchronizing conversation settings before persistence, switching popup rows to immediate mouse-down activation, and refreshing overlay status labels in the same turn.
- 2026-04-04 19:48 (KST): Widened the AX Agent message lane, softened the yellow cast of the Claude-style theme preset, aligned the data-usage button with the permission button language, and routed the tray settings entry directly into AX Agent settings when AI is enabled.
- 2026-04-04 20:41 (KST): Permission surface re-aligned to the four claw-code public modes, legacy `질문 없이 진행` exposure removed from AX Agent popups/slash guidance, and the in-chat settings/sidebar information hierarchy simplified to match the lighter Claude/Codex-style layout direction.
- 업데이트: 2026-04-04 22:05 (KST)
- AX Agent 고급 설정 오버레이를 설명형 row + 커스텀 On/Off 선택 구조로 개편하고, 내부 기능명을 사용자 친화 문구로 정리함.
- 업데이트: 2026-04-04 20:58 (KST)
- AX Agent 서비스 설정의 내부 서비스 모델 선택을 등록 모델 칩 기반으로 정리하고, vLLM SSL 우회는 모델 등록/편집 다이얼로그에서만 노출되도록 설정 표면을 축소함.
- 업데이트: 2026-04-04 21:02 (KST)
- composer 컨텍스트 카드를 hover 중심의 간단 표기(`%` + `K/M` 사용량)로 정리하고, 최대 컨텍스트 설정 상한을 1M까지 확장함.
- 업데이트: 2026-04-04 21:02 (KST)
- AX Agent 서비스 설정의 `Gemini/Claude`도 모델 칩 선택 구조로 통일하고, composer 모델 버튼을 `서비스 · 모델` 문법으로 맞춰 설정-실행 흐름의 시각 언어를 정리함.
- 업데이트: 2026-04-04 23:14 (KST)
- 트레이 좌클릭 기본 진입점을 AX Agent로 전환하고, 우클릭 메뉴 상단에 앱 버전 헤더를 추가해 AX Agent 중심 진입 흐름을 강화함.
- 메인 설정 저장 완료 후 열린 AX Agent 창이 즉시 테마/모델/권한/하단 상태줄을 다시 읽어오도록 fan-out 경로를 추가해 설정 반영 지연을 줄임.
- DraftQueue kind 분류를 message/command/steering/direct/followup 기준으로 재정리해 큐 타입과 실제 입력 성격이 더 잘 맞도록 보강함.
- 업데이트: 2026-04-04 23:23 (KST)
- AX Agent가 `SettingsService.SettingsChanged`를 직접 구독하도록 바꿔 메인 설정/AX Agent 설정 어느 경로에서 저장하더라도 테마, 모델, 권한, 데이터 활용, composer, 대기열 UI가 즉시 동일 상태를 반영하도록 fan-out을 통합함.
- AX Agent 설정 저장 경로에서 표현 수준을 무조건 `rich`로 덮어쓰던 로직을 제거해 `풍부하게 / 적절하게 / 간단하게`가 다른 설정 저장 경로에서도 유지되도록 보정함.
- DraftQueue 패널은 `실행 중 / 다음 작업 / 보류 / 완료 / 실패` 개별 섹션 구조로 다시 나눠 현재 실행 흐름과 재시도 대기, 결과 이력을 더 빠르게 파악할 수 있도록 정리함.
- ????: 2026-04-04 23:32 (KST)
- AX Agent ???? ??? ?? tool-result ?? -> microcompact ?? ?? ?? -> ?? ?? ?? 3?? ??? ???, claude-code? staged compact ??? ? ??? ? ?? ??? ?? ????? ???.
- ??? ?? ??, tool_result, ?? ???, ???? ? ???? LLM ?? ?? microcompact_boundary? ?? ??? ?? ?? ?? ?? ?? ?? ??? ??? ???? ?? ??.
## 7. 최근 보강 메모
- 2026-04-04: `/chrome`, `/mcp`, `/verify`, `/commit`, `/settings`, `/permissions` 하위 동작 정리
- 2026-04-04: `/mcp` 상태 라벨 표준화 `/chrome` 런타임 재시도 경로 보강
- 2026-04-04: 전용 AX Agent 테마 레이어 추가, 스타일/모드 분리
- 2026-04-04: 컴포저 컨텍스트 사용량 링, footer 직접 `/compact`, Git 상태 노출 보강
- 2026-04-04: 권한 UX, popup row 언어, 진행 이력 렌더 밀도를 더 가볍게 정리
+91
View File
@@ -0,0 +1,91 @@
# AX Agent 구조 리뷰
업데이트: 2026-04-15 18:20 (KST)
## 1. 목적
- AX Agent의 현재 구조를 실행 엔진, 루프 정책, 세션 저장, transcript 렌더 관점에서 정리합니다.
- 외부 제품 비교 대신 AX 내부 구조와 참조 모듈 흐름만 문서화합니다.
## 2. 현재 구조
### 실행 계층
- `src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs`
- `src/AxCopilot/Services/Agent/AgentLoopService.cs`
- `src/AxCopilot/Services/Agent/StreamingToolExecutionCoordinator.cs`
### 루프 정책 계층
- `src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs`
- `src/AxCopilot/Services/Agent/AgentLoopTransitions.Verification.cs`
- `src/AxCopilot/Services/Agent/AgentLoopTransitions.Documents.cs`
- `src/AxCopilot/Services/Agent/AgentLoopCompactionPolicy.cs`
- `src/AxCopilot/Services/Agent/AgentLoopRuntimeThresholds.cs`
### 세션/상태 계층
- `src/AxCopilot/Services/ChatSessionStateService.cs`
- `src/AxCopilot/Services/ChatStorageService.cs`
- `src/AxCopilot/Services/AppStateService.cs`
- `src/AxCopilot/Models/ChatModels.cs`
### transcript/UI 계층
- `src/AxCopilot/Views/ChatWindow.xaml`
- `src/AxCopilot/Views/ChatWindow.xaml.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptHost.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptRendering.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptRenderPlanner.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptRenderExecution.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptVirtualization.cs`
## 3. 강점
- Chat / Cowork / Code를 하나의 창과 정책 체계 안에서 운영
- 등록 모델별 실행 프로파일과 verification gate 지원
- 문서 생성 계열 fallback과 품질 리뷰가 루프에 결합되어 있음
- 메모리, slash, permissions, queue가 한 세션 상태에 연결되어 있음
## 4. 구조 리스크
1. `ChatWindow.xaml.cs` 책임이 여전히 크고, UI 이벤트와 런타임 상태 조립이 섞여 있습니다.
2. transcript와 status line이 더 단일한 런타임 상태를 기준으로 계산되면 유지보수가 쉬워질 여지가 있습니다.
3. replay/reopen 경로는 안정화가 많이 진행됐지만, 장기 세션에서는 이벤트 정규화 규칙이 더 중요합니다.
4. 설정이 실행 경로를 바꾸는 지점은 사용자용과 개발용 노출 범위를 더 구분할 필요가 있습니다.
## 5. 개선 우선순위
### A. 런타임 상태 단일화
- 참조 모듈: `src/bootstrap/state.ts`, `src/bridge/initReplBridge.ts`
- AX 적용 위치: `ChatWindow.xaml.cs`, `AxAgentExecutionEngine.cs`, `ChatStorageService.cs`
- 완료 조건:
- 현재 턴, queue, retry, 실행 이벤트, 저장 스냅샷이 같은 런타임 상태 모델을 사용
- reopen 뒤 저장 상태와 렌더 결과가 어긋나지 않음
### B. 이벤트 정규화
- 참조 모듈: `src/bridge/sessionRunner.ts`, `src/bridge/bridgeMessaging.ts`
- AX 적용 위치: `AgentLoopService.cs`, `AgentLoopTransitions.cs`, `AppStateService.cs`
- 완료 조건:
- tool start/result/error/progress, permission, retry, complete 이벤트가 안정적인 스키마를 공유
- replay 시 visible banner 중복 0건
### C. timeline 유도 모델 고정
- 참조 모듈: `src/screens/REPL.tsx`, `src/components/Messages.tsx`
- AX 적용 위치: `ChatWindow.xaml`, `ChatWindow.xaml.cs`
- 완료 조건:
- assistant/user message, execution log, compact boundary, queue summary를 하나의 derived timeline에서 생성
- direct imperative bubble injection 제거
### D. status/composer 정리
- 참조 모듈: `src/components/StatusLine.tsx`
- AX 적용 위치: `ChatWindow.xaml`, `ChatWindow.AgentStatusPresentation.cs`
- 완료 조건:
- status strip, queue summary, runtime activity가 debounce된 같은 상태 소스를 사용
- composer는 명시적 줄바꿈 중심으로만 성장
## 6. 검증 기준
- reopen 후 최신 assistant state가 저장 상태와 동일
- retry/regenerate/queue follow-up이 서로 다른 실행 경로로 분기되지 않음
- permission popup, inline ask, plan approval이 transcript 기준으로 닫힘
- `dotnet build` 경고 0 / 오류 0
## 7. 최근 메모
- 2026-04-06 09:36 (KST): 상태 strip 표현과 permission/tool-result 설명 카탈로그를 분리
- 2026-04-06 09:44 (KST): mixed inline interaction rendering을 presentation 파일로 분리
- 2026-04-06 09:58 (KST): Git branch popup과 footer 보조 요약 helper를 분리
- 2026-04-06 10:07 (KST): topic preset 렌더와 선택 흐름을 전용 presentation 파일로 이동
- 2026-04-06 11:52 (KST): permission, tool-result, skill gallery 설명층을 고도화
@@ -0,0 +1,92 @@
# AX Agent 실행 개선 계획
업데이트: 2026-04-15 18:20 (KST)
## 1. 목적
- AX Agent의 실행 신뢰성, 권한 처리 일관성, 세션 복원 품질을 높입니다.
- 외부 제품명 비교 대신 실제 참조 모듈 경로와 AX 적용 위치만 기준으로 관리합니다.
- UI 보정만으로 가리는 수정은 지양하고 `상태 -> 실행 -> 렌더` 순서로 정리합니다.
## 2. 현재 판단
- 실행 엔진과 루프 품질은 안정 구간에 들어왔지만, 장기 세션 복원과 이벤트 정규화는 계속 다듬을 여지가 있습니다.
- 설정이 런타임 경로를 바꾸는 지점은 사용자 설정과 개발자용 실험 설정을 더 분리할 필요가 있습니다.
- transcript, status line, queue 표시는 충분히 가벼워졌지만 상태 계산 소스는 더 단일화해야 합니다.
## 3. 참조 흐름
| 참조 모듈 | AX 적용 위치 | 완료 조건 | 품질 판정 기준 |
|---|---|---|---|
| `src/bootstrap/state.ts` | `src/AxCopilot/Views/ChatWindow.xaml.cs`, `src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs`, `src/AxCopilot/Services/ChatStorageService.cs` | 현재 턴, queue, retry, 실행 이벤트, 저장 스냅샷이 하나의 런타임 상태 모델로 정리 | reopen/retry/queue 후 중복 assistant 카드나 빈 카드가 생기지 않음 |
| `src/bridge/initReplBridge.ts` | `src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs`, `src/AxCopilot/Services/LlmService.cs` | send/regenerate/retry/queued follow-up/slash가 하나의 실행 준비 경로를 통과 | 같은 입력과 설정에서 진입점이 달라도 실행 경로가 흔들리지 않음 |
| `src/bridge/sessionRunner.ts` | `src/AxCopilot/Services/Agent/AgentLoopService.cs`, `src/AxCopilot/Services/Agent/AgentLoopTransitions.cs`, `src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs` | tool start/result/error/progress가 루프 계층에서 한 번만 정규화 | Cowork/Code 장기 실행 중 상태 문구가 과도하게 흔들리지 않음 |
| `src/bridge/bridgeMessaging.ts` | `src/AxCopilot/Views/ChatWindow.xaml.cs`, `src/AxCopilot/Services/Agent/AgentLoopService.cs` | 실행 이벤트와 표시 전용 이벤트를 렌더 이전에 분리 | replay 후 visible banner 중복이 발생하지 않음 |
| `src/screens/REPL.tsx`, `src/components/Messages.tsx`, `src/components/StatusLine.tsx` | `src/AxCopilot/Views/ChatWindow.xaml`, `src/AxCopilot/Views/ChatWindow.xaml.cs` | timeline, composer, status strip이 공통 런타임 상태를 사용 | 리사이즈, queue 연속 실행, retry 후에도 UI가 패치식으로 흔들리지 않음 |
## 4. 실행 단계
### A. 런타임 상태 단일화
- 적용 위치: `ChatWindow.xaml.cs`, `AxAgentExecutionEngine.cs`, `ChatStorageService.cs`
- 완료 조건:
- `Chat`, `Cowork`, `Code`가 같은 런타임 상태 모델을 갱신
- queue, retry, compact 이후 상태가 재오픈 후에도 동일하게 복원
- 품질 기준:
- 같은 대화를 다시 열었을 때 보이는 timeline과 저장 상태가 일치
- queue badge와 최근 실행 이력이 어긋나지 않음
### B. 실행 준비 경로 일원화
- 적용 위치: `AxAgentExecutionEngine.cs`, `LlmService.cs`
- 완료 조건:
- prompt stack assembly, execution mode choice, final commit이 엔진 기준으로 통합
- send/regenerate/retry/slash가 동일 API를 사용
- 품질 기준:
- 같은 탭과 같은 설정에서 실행 경로가 예측 가능
- UI에서 별도 prompt stack을 만들지 않음
### C. 루프 이벤트 정규화
- 적용 위치: `AgentLoopService.cs`, `AgentLoopTransitions.cs`, `AgentLoopTransitions.Execution.cs`
- 완료 조건:
- 권한 요청, 실패, 재시도, 완료 이벤트가 안정적인 스키마를 사용
- bounded activity/event record 기준이 문서화
- 품질 기준:
- 장기 도구 실행 중 상태 flash가 줄고 debug payload 노출이 최소화
### D. timeline 유도 모델 고정
- 적용 위치: `ChatWindow.xaml`, `ChatWindow.xaml.cs`
- 완료 조건:
- assistant/user message, 실행 로그, compact boundary, queue summary가 하나의 derived timeline에서 생성
- 직접 bubble injection 경로 제거
- 품질 기준:
- blank assistant card 0건
- token-only completion 0건
- re-render 뒤 duplicate banner 0건
### E. composer와 status strip 정리
- 적용 위치: `ChatWindow.xaml`, `ChatWindow.xaml.cs`
- 완료 조건:
- composer height는 명시적 줄바꿈 중심으로만 증가
- status strip, queue summary, runtime activity가 debounce된 업데이트를 사용
- 품질 기준:
- resize 이후 입력창이 과하게 커지지 않음
- metadata가 메시지 본문보다 앞서 보이지 않음
### F. 복구/재개/검증 마감
- 적용 위치: `ChatWindow.xaml.cs`, `AxAgentExecutionEngine.cs`, `ChatStorageService.cs`
- 완료 조건:
- reopen after interruption, retry-last, regenerate, manual compact, manual stop, manual resume 시나리오를 모두 통과
- 최신 assistant state와 저장 conversation이 일치
- 품질 기준:
- 복원 후 마지막 상태가 실제 종료 시점과 같음
- 세션 재개 후 추가 오류 전파가 없음
## 5. 검증 기준
- `dotnet build` 경고 0 / 오류 0
- 고위험 변경마다 최소 1개 이상 회귀 테스트 추가
- `internal` / `external` 운영 모드 정책 위반 0건
- reopen, retry, regenerate, queue follow-up, permission, compact 시나리오 수동 점검 유지
## 6. 최신 메모
- 2026-04-05 15:34 (KST): 실행 개선 계획을 실제 참조 모듈 흐름 기준으로 재정리했습니다.
- 2026-04-05 16:55 (KST): 엔진, 채팅 UI, 상태 UX, 설정 연동의 구조적 갭을 분리해 정리했습니다.
- 2026-04-06 09:36 (KST): 상태 strip 표현을 전용 카탈로그로 분리하고 permission/tool-result 설명을 정형화했습니다.
- 2026-04-06 10:07 (KST): topic preset과 사용자 상호작용 렌더 책임을 presentation 파일로 계속 분리했습니다.
- 2026-04-06 11:52 (KST): permission, tool-result, skill gallery 설명층을 더 구체적인 운영 정보 중심으로 보강했습니다.
+78
View File
@@ -0,0 +1,78 @@
# AX Agent 품질 계획
업데이트: 2026-04-15 18:20 (KST)
## 1. 범위
- 명령 처리 흐름
- 권한 / hook 계약
- plan / run 내구성
- 세션 / 로그 관리
- 도구 / 스킬 운영 정합성
## 2. 현재 상태 요약
- 루프 가드와 검증 게이트는 주요 경로에 반영됨
- 병렬 도구 실행, Plan Mode, unknown-tool 복구는 기본 동작 확보
- 세션 재개와 이벤트 replay는 수치 기반 관리 단계로 진입
## 3. 단계별 품질 게이트
### P1 Hook 계약 고도화
- `updatedInput`, `updatedPermissions`, `additionalContext`를 AX 실행 루프에 반영
- 설정 토글로 위험 기능 제어
### P2 세션 / 이벤트 내구성
- run 상태 영속화와 resume 기준 고정
- jsonl 이벤트 필드 표준화와 재생 가능성 확보
### P3 실패 복구 표준화
- unknown-tool, 권한거부, 파라미터 오류를 유형화
- 유형별 복구 프롬프트와 다음 액션 우선순위 고정
### P4 완료 품질 정렬
- 코드/문서 작업별 완료 체크리스트 표준화
- 증거 없는 완료 응답 방지
## 4. 운영 점검 스냅샷
- 도구 레지스트리 등록 수: 65개
- `IAgentTool` 구현 수: 65개
- 내장 스킬 파일 수: 40개
- `allowed-tools` 적용 스킬: 40/40
- 레거시 도구명 `process_run`, `grep_tool` 참조: 0건
- 내부 모드 차단 정책: `http_tool` 전면 차단, `open_external` 외부 URL 차단
## 5. 즉시 보완 항목
1. 스킬 frontmatter 확장 유지: `when_to_use`, `argument-hint`, `model`, `disable-model-invocation`, `user-invocable`, `context`, `agent`, `effort`, `paths`, `shell`
2. `paths` 기반 조건부 활성화 유지
3. 도구 별칭 정규화와 runtime hook filter 적용 유지
4. 위험 자동허용 가드(`process`, `spawn_agent`, `snippet_runner`) 강제 승인 정책 유지
## 6. 내부 벤치마크 기준
| 시나리오 | 기준 테스트 | 합격 기준 |
|---|---|---|
| 기본 Agentic loop | `AgentLoopE2ETests.RunAsync_ExecutesToolCall_AndCompletesWithFinalText` | ToolCall/ToolResult/Complete 이벤트 순서 유효, 최종 응답에 결과 포함 |
| unknown-tool 복구 | `AgentLoopE2ETests.RunAsync_UnknownTool_RecoversAndCompletes` | 오류 후 완료까지 수렴, 반복 실패 루프 없음 |
| Plan Mode 실행 연결 | `AgentLoopE2ETests.RunAsync_PlanModeAlways_EmitsPlanningThenExecutesTool` | 계획 응답 뒤 실제 도구 호출과 최종 결과 생성 |
| 권한 Ask 거부 처리 | `AgentLoopE2ETests.RunAsync_AskPermissionDenied_EmitsPermissionEvents_AndCompletes` | PermissionRequest/PermissionDenied 이벤트 기록 후 안전 종료 |
| Hook 입력 변형 | `AgentLoopE2ETests.RunAsync_PreHookInputMutation_ChangesToolArguments` | pre-hook `updatedInput`이 실제 도구 입력에 반영 |
| Runtime 정책 강제 | `AgentLoopE2ETests.RunAsync_DisallowedTool_ByRuntimePolicy_EmitsPolicyRecoveryError` | 비허용 도구 차단과 정책 복구 경고 후 종료 |
| Hook filter 정합성 | `AgentLoopE2ETests.RunAsync_HookFilters_ExecuteOnlyMatchingHookForToolAndTiming` | 지정 hook만 실행되고 비매칭 hook는 미실행 |
| 별칭 정규화 | `AgentLoopE2ETests.RunAsync_EnterPlanModeAlias_ResolvesAndExecutes` | CamelCase 도구명이 내부 snake_case 도구로 매핑되어 실행 |
| 혼합 복구 내구성 | `AgentLoopE2ETests.RunAsync_MixedRecovery_UnknownToolAndPermissionDenied_TerminatesSafely` | 반복 한도 안에서 안전 종료 |
## 7. replay 안정성 기준
| 시나리오 | 기준 테스트 | 합격 기준 |
|---|---|---|
| 실행 이벤트 정렬/압축 복원 | `ChatSessionStateServiceTests.LoadOrCreateConversation_NormalizesHistoryOrderAndCompactsSize` | ExecutionEvents 400개 상한과 시간순 정렬 유지 |
| run 이력 중복 정규화 | `ChatSessionStateServiceTests.LoadOrCreateConversation_NormalizesAgentRunDuplicatesByRunId` | 동일 `RunId`는 최신 상태 1건으로 축약 |
| terminal 우선 판정 | `TaskRunServiceTests.RestoreRecentFromExecutionEvents_PrefersTerminalEventsWhenTimestampsEqual` | 동시각 이벤트는 terminal 상태 기준으로 복원 |
| active 복원 | `TaskRunServiceTests.RestoreRecentFromExecutionEvents_RebuildsActiveTasksFromNonTerminalEvents` | 중단 후 재개 시 active task 재구성 |
| dangling 정리 | `TaskRunServiceTests.RestoreRecentFromExecutionEvents_CompleteClearsDanglingRunScopedActiveTasks` | Complete 뒤 run 스코프 dangling active task 0건 |
## 8. 배포 체크리스트
1. `dotnet build` 경고 0 / 오류 0
2. `dotnet test` 전체 통과
3. 내부 벤치마크 시나리오 전건 통과
4. `Suite=ReplayStability` 전건 통과
5. `scripts/release-gate.ps1` 실행 결과 기록
+2 -2
View File
@@ -2,13 +2,13 @@
업데이트: 2026-04-08 10:38 (KST)
`claw-code`AX Agent 같은 기준으로 비교하기 위한 공통 회귀 프롬프트 세트입니다.
AX Agent 실행 흐름을 같은 기준으로 점검하기 위한 공통 회귀 프롬프트 세트입니다.
## 사용 규칙
- 루프 정책, transcript 렌더, 권한/계획/진행 UX, queue/compact/reopen 흐름에 영향을 주는 변경 뒤에는 이 문서를 기준으로 최소 1회 점검합니다.
- 모든 항목을 매번 전부 돌릴 필요는 없지만, 바뀐 영역과 맞닿은 묶음은 반드시 확인합니다.
- 결과는 “모양이 똑같은가”보다 “사용자 체감 흐름과 완료 품질이 같은가”를 기준으로 봅니다.
- 결과는 “화면이 비슷한가”보다 “사용자 체감 흐름과 완료 품질이 안정적인가”를 기준으로 봅니다.
## 실패 분류
+50
View File
@@ -0,0 +1,50 @@
# AX Agent 런타임 품질 계획
업데이트: 2026-04-15 18:20 (KST)
## 1. 기준
- 대상 범위: 명령 처리, 권한/훅, plan/run 내구성, 세션/로그 관리
- 문서 목적: AX Agent 런타임 경로의 품질 기준과 마감 조건을 명확히 고정
## 2. 주요 갭
- Hook 출력의 구조화 계약 적용 범위가 일부 경로에 아직 제한적입니다.
- 세션 재개와 이벤트 replay 품질은 시나리오별 편차가 남아 있습니다.
- 도구 선택 실패 뒤 재시도 전략의 메시지와 다음 행동이 완전히 표준화되지는 않았습니다.
## 3. 실행 순서
1. Hook 계약 고도화
2. 세션/이벤트 내구성 정리
3. 실패 복구 메시지 표준화
4. 완료 품질 게이트 고정
## 4. 완료 판정
- 내부 벤치마크 목표 성공률 충족
- 세션 재개/이벤트 재생 오류 0건
- 빌드 경고 0 / 오류 0 유지
## 5. 점검 스냅샷
- 기준 시점: 2026-04-03
- 계획 대비 현재 수준: 약 92~95%
- 테스트 상태: `dotnet test` 374/374 통과
- Hook 계약: 구현 완료 수준
- 세션/이벤트 내구성: 복원/재생 경계 케이스 테스트 반영
- 실패 복구 표준화: unknown-tool/권한/정체 경로 반영
- 완료 품질 게이트: 문서화와 코드 반영 완료
## 6. 관리 대상
1. 도구 계층: 목록, 별칭 정규화, unknown-tool 복구, 선택 정책
2. 스킬 계층: 로더, frontmatter, 파일 기반 운영, 조건부 활성화
3. 훅/권한: pre/post hook 계약, permission update 반영, ask/auto/deny 일관성
4. 세션/상태: run 복원, 이벤트 replay, 중복 억제, resume 신뢰성
5. 계획/실행: plan 승인/수정 이력, 실행 게이트, 조기 완료 방지
6. MCP/외부도구: 연결, 리소스 조회, 실패 복구, internal 정책
7. 설정/UI 연동: 설정값, 실행 코드, UI 반영 동기화
## 7. 다음 순서
1. Agentic loop E2E 시나리오를 회귀 테스트로 계속 고정
2. 벤치마크 합격 기준과 증적을 배포 체크리스트에 연결 유지
3. 수치와 상태 문구를 `README.md`, `docs/DEVELOPMENT.md`, 로드맵 문서와 동기화
## 8. 운영 기준
- 내부 벤치마크와 replay 안정성 테스트는 릴리즈 전 최소 조건으로 유지
- 문서에는 비교·모사 표현보다 AX 기준 완료 조건과 검증 결과만 기록
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-238
View File
@@ -1,238 +0,0 @@
# claude-code / AX Agent 구조 비교 문서
업데이트: 2026-04-09 10:20 (KST)
이 문서는 AX Agent를 `claude-code` 동등 품질 기준으로 유지·검증하기 위한 비교 기준 문서입니다.
실제 비교 대상 저장 폴더명은 `claw-code`이지만, 문서 표기는 `claude-code`로 통일합니다.
## 1. claude-code 구조, 특징 기능, 에이전트 루프
### 1-1. 구조 핵심
`claude-code`는 크게 아래 축으로 나뉩니다.
1. 부트스트랩/세션 상태
- `src/bootstrap/state.ts`
- `src/bridge/initReplBridge.ts`
- `src/bridge/sessionRunner.ts`
2. 메인 REPL/대화 화면
- `src/screens/REPL.tsx`
- `src/components/Messages.tsx`
- `src/components/VirtualMessageList.tsx`
- `src/components/StatusLine.tsx`
3. 도구 실행 계층
- `src/services/tools/toolOrchestration.ts`
- `src/services/tools/StreamingToolExecutor.ts`
4. 메모리/컨텍스트/권한
- `04_작동원리.md`
- `05_메모리와컨텍스트.md`
- `06_권한시스템.md`
- `15_스킬.md`
### 1-2. 특징 기능
`claude-code`의 강점은 기능 개수보다 실행 품질에 있습니다.
- 대화, 도구 실행, 권한, 상태줄이 한 흐름으로 이어진다.
- transcript가 단순 채팅 로그가 아니라 실행 관측 UI 역할을 한다.
- 도구 호출이 응답 후처리가 아니라 루프 자체의 핵심 경로다.
- read-only 도구는 병렬화하고, non-concurrent 도구는 직렬화해 체감 반응성을 높인다.
- 메모리 구조가 `managed / user / project / local` 계층으로 명확하다.
- `CLAUDE.md`, `.claude/rules/*.md`, `paths:` frontmatter, `@include` 같은 규칙 기반 메모리 주입이 강하다.
- 권한 시스템이 `default / acceptEdits / plan / bypassPermissions`와 allow/deny rule로 분리되어 있다.
- skill 시스템이 단순 프롬프트 스니펫이 아니라 재사용 가능한 워크플로우 레이어다.
### 1-3. 에이전트 루프 구조
`claude-code`의 기본 루프는 다음 순서에 가깝습니다.
1. 사용자 메시지 수신
2. 시스템 컨텍스트 조립
- Git 상태
- 메모리 계층
- 현재 날짜/환경
- 사용 가능한 도구/권한 상태
3. 모델 호출
4. tool_use block 감지
5. 권한 판단
6. 도구 실행
7. tool_result를 다시 모델에 투입
8. 필요 시 추가 도구 호출
9. 최종 텍스트 응답 커밋
중요한 점은, 이 루프가 단순히 "LLM 호출 후 도구 실행"이 아니라 `도구를 전제로 설계된 루프`라는 점입니다.
### 1-4. Cowork/Code에서 결과가 잘 나오는 이유
#### 1. 도구 우선 오케스트레이션
- `toolOrchestration.ts`가 tool call을 배치로 나누고
- `StreamingToolExecutor.ts`가 스트리밍 도중에도 도구 실행 준비를 진행합니다.
- read-only/concurrency-safe 도구는 병렬 실행해 첫 반응 시간을 줄입니다.
#### 2. 실행 중 관측성이 높음
- `Messages.tsx`
- `VirtualMessageList.tsx`
- `StatusLine.tsx`
이 구조 덕분에 사용자는 "지금 무엇을 읽고, 무엇을 실행하고, 어디서 멈췄는지"를 계속 볼 수 있습니다.
긴 작업에서도 멈춘 것처럼 느껴지지 않는 이유가 여기 있습니다.
#### 3. 긴 세션을 버티는 transcript 구조
- transcript는 전체 렌더를 계속 다시 그리지 않습니다.
- `VirtualMessageList.tsx` 기준으로 가시 영역 중심 렌더와 스크롤/탐색 보조 구조가 분리되어 있습니다.
- 긴 세션, 많은 도구 호출, 많은 중간 상태에서도 UI 부하가 상대적으로 낮습니다.
#### 4. 메모리와 규칙 주입이 명시적
- `CLAUDE.md`
- `.claude/rules/*.md`
- `paths:`
- `@include`
이 구조 때문에 프로젝트/경로/사용자/관리자 규칙이 프롬프트에 일관되게 들어갑니다.
결과가 흔들릴 때도 "왜 그런 성향이 나왔는지" 추적이 쉽습니다.
### 1-5. 주요 성능과 품질에 영향을 주는 프롬프트 전략
1. 도구를 먼저 쓰게 만드는 직접적인 지시
2. 컨텍스트를 계층화해서 넣음
3. 권한과 도구 사용 범위를 명확히 분리
4. 실행 중간 상태를 계속 보여줘 재시도/복구가 자연스러움
5. read-only tool 병렬화로 초기 탐색 시간을 줄임
6. transcript/상태줄이 실제 실행 관측 수단으로 동작
## 2. AX Agent 구조, 특징 기능, 에이전트 루프
### 2-1. 구조 핵심
현재 AX Agent는 다음 축으로 구성됩니다.
1. 에이전트 실행
- `src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs`
- `src/AxCopilot/Services/Agent/AgentLoopService.cs`
- `src/AxCopilot/Services/Agent/StreamingToolExecutionCoordinator.cs`
2. 루프 정책 분리 계층
- `src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs`
- `src/AxCopilot/Services/Agent/AgentLoopTransitions.Verification.cs`
- `src/AxCopilot/Services/Agent/AgentLoopTransitions.Documents.cs`
- `src/AxCopilot/Services/Agent/AgentLoopCompactionPolicy.cs`
- `src/AxCopilot/Services/Agent/AgentLoopRuntimeThresholds.cs`
3. 메모리 구조
- `src/AxCopilot/Services/AgentMemoryService.cs`
- `src/AxCopilot/Services/Agent/MemoryTool.cs`
4. transcript/UI 구조
- `src/AxCopilot/Views/ChatWindow.xaml.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptHost.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptRendering.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptRenderPlanner.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptRenderExecution.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptVirtualization.cs`
5. 성능/검증 로그
- `src/AxCopilot/Services/AgentPerformanceLogService.cs`
### 2-2. 특징 기능
- Chat / Cowork / Code를 한 창에서 운영
- 등록 모델별 실행 프로파일 지원
- Cowork/Code 전용 agent loop 사용
- 문서 생성 계열 fallback 및 verification gate 지원
- IBM/vLLM/OpenAI 호환 tool-use 경로 대응
- 계층형 메모리 구조 지원
- `/memory` 계열 도구와 설정 UI에서 메모리 관리 가능
- transcript/진행 표시/UI 구조를 `claude-code` 기준으로 계속 분해해온 상태
### 2-3. 에이전트 루프 구조
현재 AX Agent의 루프는 대략 아래 순서입니다.
1. 실행 컨텍스트 구성
2. 사용자 메시지와 시스템 지시 조립
3. LLM 호출
4. tool call 감지
5. `StreamingToolExecutionCoordinator`를 통한 조기 도구 실행/prefetch
6. 도구 결과 재투입
7. verification/document fallback/compact 정책 수행
8. 최종 결과 커밋
9. transcript/status/perf 로그 반영
### 2-4. 현재 구조적 강점
1. 모델 프로파일 기반 제어
2. 계층형 메모리 구조
3. Cowork/Code용 별도 실행 정책
4. 성능 계측 로그
### 2-5. 현재 구조적 약점
1. `ChatWindow.xaml.cs` 책임이 여전히 큼
2. transcript가 아직 완전한 데이터 기반 가상화는 아님
3. 루프 정책이 여전히 서비스 중심
4. tool streaming executor가 독립 계층으로 강화되었지만 결합이 남음
## 3. claude-code와 AX Agent 비교
### 3-1. 전체 비교 요약
| 항목 | claude-code | AX Agent 현재 상태 |
|------|-------------|-------------------|
| 메모리 계층 | 매우 강함 | 많이 근접 |
| tool orchestration | 매우 강함 | 많이 강화됨 |
| transcript 가상화 | 강함 | 부분 근접 |
| 진행 관측성 | 강함 | 많이 근접 |
| 모델 프로파일성 | 단단함 | 프로파일 시스템 도입 완료 |
| 문서 fallback | 비교적 단순/직접적 | 더 많은 정책 보유 |
| 루프 응집도 | 모듈 분리 우수 | 개선 중, 많이 나아짐 |
### 3-2. AX Agent가 이미 따라잡은 부분
1. 메모리 계층 구조
2. 진행 표시 UX
3. 모델별 실행 성향 제어
4. 도구 호출 강화
### 3-3. AX Agent가 아직 더 개선할 수 있는 부분
1. transcript의 진짜 가상화
2. UI 렌더의 data-template화
3. tool executor의 독립성
4. Cowork/Code 실사용 로그 기반 검증 체계
### 3-4. 성능과 결과 품질에 직접 영향이 큰 구조 요소 비교
#### claude-code 쪽 핵심
- read-only tool 병렬화
- streaming executor
- transcript 가상화
- 상태줄/메시지/도구 실행 분리
- 명시적 메모리 계층
- 권한 시스템과 루프의 강한 연결
#### AX Agent 쪽 핵심
- 모델 프로파일
- document/verification/compact 정책 분리
- IBM/vLLM 도구 호출 보강
- transcript host/windowing/virtualization 보강
- WPF 환경 특화 성능 대응
### 3-5. 현 시점 결론
현 시점 AX Agent는 `claude-code` 대비 다음 상태로 보는 것이 적절합니다.
- 구조적 방향성: 거의 동일한 방향
- 메모리/도구/진행 표시: 상당 부분 근접
- transcript/렌더 구조: 아직 한 단계 차이 존재
- 장기 세션 성능: 실제 로그 기반 추가 검증 필요
즉 AX Agent는 더 이상 "기본 구조가 부족한 상태"는 아니고, 이제부터는 `실사용 검증 기반으로 남은 구조 차이를 줄이는 단계`입니다.
## 4. AX 개발 시 이 문서를 어떻게 쓸지
1. Cowork/Code 품질 이슈가 생기면 먼저 `claude-code` 기준 흐름과 비교
2. 구조 리팩터링이 필요할 때 transcript / tool executor / loop policy / memory 중 어디를 건드리는지 먼저 분류
3. 실사용 성능 검증 시 `%APPDATA%\\AxCopilot\\perf` 로그와 loop elapsed, transcript render elapsed, no-tool loop, verification/fallback/compact 비율을 함께 본다
4. 계획 수립 시 항상 참조 파일, AX 적용 위치, 완료 조건, 품질 판정 기준을 같이 적는다
-153
View File
@@ -1,153 +0,0 @@
# CLAW-CODE 품질 동등화 계획 (전면 재작성)
## 1. 기준
- 레퍼런스: `E:\AX Copilot - Codex\claw-code\claw-code-f5a40b86dede580f6543bf8926c9af017eea9409\src`
- 동등화 범위: 명령 처리 흐름, 권한/훅 체계, plan/run 내구성, 세션/로그 관리.
## 2. 보존 이력 (요약만 유지)
- 루프 가드(반복 실패/정체 감지)와 검증 게이트는 이미 AX에 부분 반영.
- 병렬 도구 실행, Plan Mode, Unknown-tool 복구 로직은 반영 완료.
- 세션/이력 안정화는 진행 중.
## 3. 현재 갭
- Hook 출력의 구조화 계약 적용 범위가 제한적.
- 세션 재개/이벤트 replay 품질이 시나리오별 편차 존재.
- 도구 선택 실패 후 재시도 전략의 일관성 부족.
## 4. 단계별 실행
### P1 Hook 계약 고도화
- `updatedInput`, `updatedPermissions`, `additionalContext`를 AX 실행 루프에 반영.
- 설정 토글로 위험 기능 제어.
### P2 세션/이벤트 내구성
- run 상태 영속화와 resume 기준 고정.
- jsonl 이벤트 필드 표준화 및 재생 가능성 확보.
### P3 실패 복구 표준화
- unknown-tool/권한거부/파라미터 오류를 유형화.
- 유형별 복구 프롬프트와 다음 액션 우선순위 고정.
### P4 완료 품질 정렬
- 코드/문서 작업별 완료 체크리스트 표준화.
- 증거 없는 완료 응답 방지.
## 5. 완료 판정
- 내부 벤치마크 시나리오에서 목표 성공률 충족.
- 세션 재개/이벤트 재생 오류 0건.
- 빌드 경고 0/오류 0 유지.
## 6. 2026-04-03 점검 스냅샷
- 기준 시점: 2026-04-03.
- 계획 대비 현재 수준: 약 92~95%.
- 테스트 상태: `dotnet test` 374/374 통과.
- P1 Hook 계약: 구현 완료 수준.
- P2 세션/이벤트 내구성: 구현 완료 수준(복원/재생 경계 케이스 테스트 반영).
- P3 실패 복구 표준화: 구현 완료 수준(unknown-tool/권한/정체/fork 강제 흐름 반영).
- P4 완료 품질 정렬: 구현 완료 수준(게이트 로직 + 벤치마크 기준 문서화 완료).
## 7. 스킬/도구 운영 점검 (2026-04-03)
- 도구 레지스트리 등록 수: 65개 (`ToolRegistry.CreateDefault()` 기준).
- `IAgentTool` 구현 수: 65개. 동적 MCP 래퍼(`McpTool`)는 런타임 등록 구조로 정상.
- 내장 스킬 파일 수: 40개 (`src/AxCopilot/skills/*.skill.md`).
- `allowed-tools` 적용 스킬: 40/40.
- `requires: python` 고정 의존 스킬: 0개(기존 10개에 Python 가능/불가 분기 fallback 경로 반영).
- 레거시 도구명 `process_run` 참조: 0건 (`process`로 정규화).
- 레거시 도구명 `grep_tool` 참조: 0건 (`grep`로 정규화).
- 내부 모드 차단 정책: `http_tool` 전면 차단, `open_external`의 외부 URL 차단.
- 테스트 상태: `dotnet test` 374/374 통과.
## 8. claw-code 소스 직접 비교 결과 (2026-04-03)
- 비교 기준 소스: `claw-code/.../src/tools.ts`, `src/Tool.ts`, `src/skills/loadSkillsDir.ts`, `src/skills/bundled/*.ts`.
- claw-code 도구 상수명: 41개 (`*_TOOL_NAME` 기준).
- AX 도구명: 65개 (`IAgentTool.Name` 기준).
- claw-code 도구명 중 AX alias로 직접 해석되는 항목: 8개 (`Bash/Read/Write/Edit/Glob/Grep/WebFetch/WebSearch`).
- 미해석 항목(33개)은 대부분 제품 철학 차이 영역(예: `EnterPlanMode`, `ExitWorktree`, `TeamCreate`, `TodoWrite`, `ToolSearch`, `REPL`, `Cron*`).
- claw-code 번들 스킬은 코드 등록형 14개(`registerBundledSkill`)이며, AX는 파일 기반 스킬 40개(`*.skill.md`) 중심 구성.
- 번들 스킬 이름 교집합은 0개이며(의도된 차별화), 품질 기준은 "이름 일치"가 아니라 "동작 등가(계획/복구/검증/권한/세션 내구성)"로 판단해야 함.
- claw-code 스킬 메타데이터는 `allowedTools`, `whenToUse`, `model`, `disableModelInvocation`, `userInvocable`, `hooks`, `context`, `agent`, `paths`, `effort`, `shell`까지 지원.
- AX 스킬 메타데이터는 `allowed-tools`, `when_to_use`, `argument-hint`, `model`, `disable-model-invocation`, `user-invocable`, `context`, `agent`, `effort`, `paths`, `shell`, `hooks`, `hook_filters`까지 런타임 연계 확장 완료.
## 9. claw-code 비교 기반 즉시 보완 항목 (반영 상태)
1. 스킬 frontmatter 확장: `when_to_use`, `argument-hint`, `model`, `disable-model-invocation`, `user-invocable`, `context`, `agent`, `effort`, `paths`, `shell` 반영 완료.
2. 스킬 실행 범위 제어: `paths` 기반 조건부 활성화 반영 완료(첨부 파일 경로 매칭 시 동적 활성화).
3. 도구 별칭 정규화: claw-code 기본 도구명군(`WebFetch`, `WebSearch`, `AskUserQuestion`, `LSP`, `ListMcpResourcesTool` 등) AX 내부 도구명으로 매핑 반영 완료.
4. 반영 완료(2026-04-03): `hooks`/`hook_filters` 계약 확장 및 runtime hook 필터링(도구/타이밍 기준) 적용.
5. 반영 완료(2026-04-03): 슬래시 스킬 실행 시 `context/agent/effort/model/disable-model-invocation/allowed-tools/hooks/hook_filters` 메타데이터를 런타임 정책 지시문으로 합성 적용.
6. 반영 완료(2026-04-03): `permissionSetup` 비교 기반으로 위험 자동허용 가드 추가(`process`, `spawn_agent`, `snippet_runner`는 전역 `Auto`에서도 승인 단계 강제).
## 10. 전체 영역 동시 비교 기준 (누락 방지)
1. 도구 계층: 도구 목록, 별칭 정규화, unknown-tool 복구, tool search/선택 정책.
2. 스킬 계층: 로더, frontmatter, 번들/파일 기반 동시 운영, 조건부 활성화.
3. 훅/권한: pre/post hook 계약, permission update 반영, ask/auto/deny 일관성.
4. 세션/상태: run 복원, 이벤트 replay, 중복 이벤트 억제, resume 신뢰성.
5. 계획/실행: plan 승인/수정 이력, 실행 게이트, 조기 완료 방지.
6. MCP/외부도구: 연결/리소스 조회/읽기, 실패 복구, internal 모드 정책.
7. 서브에이전트: spawn/wait 제약, read-only 모드, 결과 회수 구조.
8. 운영/설정/UI 연동: 설정값-실행코드-UI 동기화, 탭별 분기(Cowork/Code) 일치.
## 11. 다음 적용 순서 (전체 영역 병렬 보정)
1. 기본 Agentic loop E2E 시나리오(도구 실행/unknown-tool 복구)를 회귀 테스트로 고정.
2. 벤치마크 합격 기준(시나리오/통과조건/증적)을 문서화하고 배포 체크리스트에 연결. (완료)
3. 최종 마감 시 패리티 문서(수치/상태)와 로드맵 문서를 동기화. (진행 중)
## 12. 내부 벤치마크 기준 (고정)
| 시나리오 | 기준 테스트 | 합격 기준 |
|---|---|---|
| 기본 Agentic loop (도구 호출 → 완료) | `AgentLoopE2ETests.RunAsync_ExecutesToolCall_AndCompletesWithFinalText` | ToolCall/ToolResult/Complete 이벤트가 순서상 유효하고 최종 응답에 계산 결과 포함 |
| unknown-tool 복구 | `AgentLoopE2ETests.RunAsync_UnknownTool_RecoversAndCompletes` | unknown 도구 오류 이벤트 후 완료까지 수렴, 반복 실패 루프 없음 |
| Plan Mode 실행 연결 | `AgentLoopE2ETests.RunAsync_PlanModeAlways_EmitsPlanningThenExecutesTool` | 계획 응답 후 실제 도구 호출이 이어지고 최종 결과 생성 |
| 권한 Ask 거부 처리 | `AgentLoopE2ETests.RunAsync_AskPermissionDenied_EmitsPermissionEvents_AndCompletes` | PermissionRequest/PermissionDenied 이벤트가 기록되고 안전 종료 |
| Hook 입력 변형 반영 | `AgentLoopE2ETests.RunAsync_PreHookInputMutation_ChangesToolArguments` | pre-hook `updatedInput`이 실제 도구 입력에 적용됨 |
| Runtime 정책(`allowed_tools`) 강제 | `AgentLoopE2ETests.RunAsync_DisallowedTool_ByRuntimePolicy_EmitsPolicyRecoveryError` | 비허용 도구 차단 + 정책 복구 경고 후 종료 |
| Hook filter 정합성 | `AgentLoopE2ETests.RunAsync_HookFilters_ExecuteOnlyMatchingHookForToolAndTiming` | 지정된 hook만 실행되고 비매칭 hook는 미실행 |
| claw-code alias(`EnterPlanMode`) 정규화 | `AgentLoopE2ETests.RunAsync_EnterPlanModeAlias_ResolvesAndExecutes` | CamelCase 도구명이 AX 내부 snake_case 도구로 매핑되어 정상 실행 |
| 혼합 복구 내구성 (unknown + 권한 + 대체도구) | `AgentLoopE2ETests.RunAsync_MixedRecovery_UnknownToolAndPermissionDenied_TerminatesSafely` | unknown-tool 오류 후 file_write 경유, math_eval로 수렴하고 반복 한도 내 안전 종료 |
### 벤치마크 배포 체크리스트 연결
1. `dotnet build` 경고 0/오류 0.
2. `dotnet test` 전체 통과 (`374/374` 기준, 증가 시 최신 값으로 동기화).
3. 위 9개 시나리오의 회귀 테스트가 모두 통과.
4. 패리티 수치/상태를 `NEXT_ROADMAP.md`와 동일 문구로 동기화.
5. 릴리즈 전 게이트 스크립트 실행: `powershell -ExecutionPolicy Bypass -File .\scripts\release-gate.ps1`
### 실행 증적 (2026-04-03)
- `dotnet test --filter "Suite=ParityBenchmark"`: 12/12 통과.
- `powershell -ExecutionPolicy Bypass -File .\scripts\release-gate.ps1`: build/replay/full gate 통과.
## 13. 세션 Replay 안정성 기준 (고정)
| 시나리오 | 기준 테스트 | 합격 기준 |
|---|---|---|
| 실행 이벤트 정렬/압축 복원 | `ChatSessionStateServiceTests.LoadOrCreateConversation_NormalizesHistoryOrderAndCompactsSize` | ExecutionEvents 400개 상한 유지 + 시간순 정렬 유지 |
| run 이력 중복 정규화 | `ChatSessionStateServiceTests.LoadOrCreateConversation_NormalizesAgentRunDuplicatesByRunId` | 동일 `RunId` 중복이 최신 상태 1건으로 축약 |
| 동시각 이벤트 종결 우선 판정 | `TaskRunServiceTests.RestoreRecentFromExecutionEvents_PrefersTerminalEventsWhenTimestampsEqual` | Tool/Permission 상태가 terminal 이벤트 기준으로 복원 |
| 비종결 이벤트 active 복원 | `TaskRunServiceTests.RestoreRecentFromExecutionEvents_RebuildsActiveTasksFromNonTerminalEvents` | 중단 후 재개 시 active task 3종(agent/tool/permission) 재구성 |
| run 종료 시 dangling 정리 | `TaskRunServiceTests.RestoreRecentFromExecutionEvents_CompleteClearsDanglingRunScopedActiveTasks` | Complete 이후 run 스코프 active task 잔존 0건 |
| 현재 run 복원 우선순위 | `AppStateServiceTests.RestoreCurrentAgentRun_PrefersRunningExecutionEventOverHistory` | 실행 중 이벤트가 history보다 우선되어 현재 run 복원 |
| recent timeline 재구성 | `AppStateServiceTests.RestoreRecentTasks_RebuildsRecentTaskTimelineFromExecutionEvents` | 도구/권한/에이전트 최근 이력 순서 복원 |
| 권한 거부 후 active 권한 상태 정리 | `AppStateServiceTests.RestoreRecentTasks_PermissionDeniedLeavesNoActivePermissionAfterResume` | PermissionDenied 이후 run 재개 시 active permission 잔존 0건 |
| Hook 타임라인 역순 병합 정합성 | `AppStateServiceTests.ApplyAgentEvent_ReplaysHookTimelineInReverseChronologicalOrder` | Hook 이벤트가 역순 타임라인에서도 시간/의미 순서 보존 |
| 완료 이벤트 우선 정리(병렬 도구) | `TaskRunServiceTests.RestoreRecentFromExecutionEvents_CompleteClearsParallelToolCallsForSameRun` | Complete 도착 시 동일 run의 병렬 도구 active task 즉시 정리 |
### 운영 규칙
1. 위 시나리오는 `Suite=ReplayStability` 테스트 태그로 관리.
2. 릴리즈 전 `Suite=ReplayStability` 전건 통과를 replay 불일치 0건의 최소 조건으로 사용.
### 실행 증적 (2026-04-03)
- `dotnet test --filter "Suite=ReplayStability"`: 12/12 통과.
- `powershell -ExecutionPolicy Bypass -File .\scripts\release-gate.ps1`: `ReplayStability` 포함 게이트 통과.
## 14. 권한 Hook 계약 (P2 마감 기준)
- lifecycle hook 키:
- `__permission_request__` (pre)
- `__permission_granted__` (post)
- `__permission_denied__` (post)
- payload 기준 필드: `runId`, `tool`, `target`, `permission`, `granted`, `reason`.
- 우선순위:
1. Hook `updatedPermissions`가 현재 run의 `AgentContext.ToolPermissions`를 즉시 갱신.
2. 갱신 후 `context.CheckToolPermissionAsync()`로 최종 판정.
3. hook 실패/예외는 non-blocking(권한 흐름 지속).
4. `additionalContext`는 가능한 경로에서 메시지 컨텍스트로 반영.
+389
View File
@@ -0,0 +1,389 @@
# Code Context Reliability Plan
Update: 2026-04-16 09:12 (KST)
- Implemented the remaining continuity gap-closure items that were still open after the earlier staged loop refactor:
- durable conversation-owned `CodeWorkingSetSnapshot`
- semantic Code tool-batch continuity summaries
- compact-safe `MsgId` and preview metadata preservation
- query-context diagnostics for working-set injection, semantic-summary injection, protected diagnostics, compact-boundary use, and legacy-boundary fallback detection
- workspace-context bootstrap injection for Code requests when `.ax-context.md` is already available
- The active implementation now spans:
- `src/AxCopilot/Models/ChatModels.cs`
- `src/AxCopilot/Services/Agent/CodeTaskWorkingSetService.cs`
- `src/AxCopilot/Services/Agent/AgentLoopService.cs`
- `src/AxCopilot/Services/Agent/AgentLoopCodeWorkingSetPersistence.cs`
- `src/AxCopilot/Services/Agent/AgentLoopQueryAssemblyService.cs`
- `src/AxCopilot/Services/Agent/AgentLoopLlmRequestPreparationService.cs`
- `src/AxCopilot/Services/Agent/AgentQueryContextBuilder.cs`
- `src/AxCopilot/Services/Agent/AgentLoopContextReliability.cs`
- `src/AxCopilot/Services/Agent/ContextCondenser.cs`
- `src/AxCopilot/Services/ChatSessionStateService.cs`
- `src/AxCopilot/Views/ChatWindow.xaml.cs`
- Remaining follow-up after this wave is now smaller and mainly optional:
- broaden the workspace bootstrap path from `LoadContext(...)` reuse into a fuller stale-check refresh only if Code runs show it is still needed
- continue cleaning low-traffic legacy mojibake comments and dormant compatibility strings as those files are touched again
- evaluate whether the durable Code working set should surface in future debug tooling or exports
- keep measuring tool-trace repair frequency in longer real Code sessions to confirm the new durable snapshot and semantic summary blocks reduce repair churn
Update: 2026-04-16 07:40 (KST)
- Closed the main gaps that were still open versus the comparison checklist:
- durable structured tool transcript persistence back into `conversation.Messages`
- `MaxContextTokens = 0` Auto mode with model-aware context budget resolution
- snippet-based post-compact tool trace restoration
- repeated system prompt deduplication before each prepared turn
- The active implementation now spans:
- `src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs`
- `src/AxCopilot/Services/Agent/AgentQueryContextBuilder.cs`
- `src/AxCopilot/Services/Agent/ContextCondenser.cs`
- `src/AxCopilot/Models/AppSettings.cs`
- `src/AxCopilot/Services/SettingsService.cs`
- `src/AxCopilot/ViewModels/SettingsViewModel.cs`
- `src/AxCopilot/Views/SettingsWindow.xaml`
- `src/AxCopilot/Views/SettingsWindow.xaml.cs`
- `src/AxCopilot/Views/AgentSettingsWindow.xaml.cs`
- `src/AxCopilot/Views/ChatWindow.xaml`
- `src/AxCopilot/Views/ChatWindow.xaml.cs`
- `src/AxCopilot/Views/ChatWindow.OverlaySettingsPresentation.cs`
- `src/AxCopilot/Views/ChatWindow.ContextUsagePresentation.cs`
- `src/AxCopilot/Services/LlmService.cs`
- `src/AxCopilot/Services/LlmService.ToolUse.cs`
- Remaining follow-up is now narrower:
- consider splitting context budget and output budget into separate user-facing controls if future provider tuning needs it
- continue cleaning legacy mojibake strings in low-traffic diagnostic paths as they are touched
Update: 2026-04-16 06:41 (KST)
- Added `src/AxCopilot/Services/Agent/AgentLoopLlmDispatchStageService.cs` so the LLM dispatch path is now split into:
- history/query assembly
- pre-LLM stage planning
- dispatch/stream stage execution
- tool execution and recovery
- `AgentLoopService` no longer owns the inline stream preview callback or the direct `SendWithToolsWithRecoveryAsync(...)` setup for the primary loop.
- `StreamingToolExecutionCoordinator.cs` was also normalized to English-only active-path status strings so the staged dispatch path no longer reintroduces mojibake text during wait/retry handling.
- Remaining structural gap versus the target `claw-code` shape:
- the `NotSupportedException` / `ToolCallNotSupportedException` fallback branch still lives in `AgentLoopService`
- the next extraction target should be a narrower fallback policy stage so the main loop keeps shrinking toward a pure orchestrator
Update: 2026-04-16 01:37 (KST)
## Background
Recent Code tab runs show that the LLM request payload is still growing over time. In the `2026-04-16 00:46:26` to `00:50:52` run, the request size grew from `messages=7` to `messages=125`. That means the failure mode is not "context does not grow at all." The real problem is context fidelity: detailed evidence that the model still needs is being replaced too quickly by previews, repair notes, and low-signal summaries.
The same log window repeatedly shows:
- `tool_calls/tool mismatch detected - flattening assistant message`
- `orphan tool message detected - converting to user`
- repeated rereads of nearby files after build failures
- shifting build failures such as `MC3089` followed by `CS0017` without a stable working set that preserves what was already changed and what remains broken
In short, the current system grows the raw message count but does not preserve a stable working set for long-running code tasks.
## Current Findings
### 1. Workspace context bootstrap is weak on first load
- AX targets:
- `src/AxCopilot/Views/ChatWindow.UtilityPresentation.cs`
- `src/AxCopilot/Services/Agent/WorkspaceContextGenerator.cs`
- Finding:
- When `.ax-context.md` is missing, the first Code request can return before background workspace-context generation becomes useful.
- Impact:
- Empty-workspace and fresh-project tasks start without a reliable folder or project summary in the early loops.
### 2. Build and file evidence is compacted too aggressively
- AX targets:
- `src/AxCopilot/Services/Agent/AgentToolResultBudget.cs`
- `src/AxCopilot/Services/Agent/ContextCondenser.cs`
- Current values:
- `DefaultSoftCharLimit = 900`
- `DefaultAggregateBudgetChars = 7_500`
- `RecentKeepCount = 6`
- Impact:
- Code tasks lose detailed build, test, and file-read evidence too early and fall back to previews instead of actionable context.
### 3. Session learning is not a durable code working set
- AX targets:
- `src/AxCopilot/Services/Agent/SessionLearningCollector.cs`
- `src/AxCopilot/Services/Agent/AgentLoopService.cs`
- `src/AxCopilot/Views/ChatWindow.SystemPromptBuilder.cs`
- Finding:
- Session learnings are injected every loop, but they are not structured strongly enough to lock in:
- current goal
- current architecture
- changed files
- latest build or test failure
- next repair target
- Impact:
- The model must repeatedly reconstruct project state from noisy history instead of reading a stable code-task memory layer.
### 4. Tool-trace invariant repairs are too common
- AX targets:
- `src/AxCopilot/Services/LlmService.ToolUse.cs`
- `src/AxCopilot/Services/Agent/AgentMessageInvariantHelper.cs`
- `src/AxCopilot/Services/Agent/AgentLoopService.cs`
- Finding:
- The recent logs show repeated mismatch and orphan corrections.
- Impact:
- Even if the total message count grows, the semantic chain between assistant reasoning, tool call, and tool result becomes less reliable.
### 5. There is no Code-specific working-set layer
- AX targets:
- new service required
- injection path should go through:
- `AgentLoopLlmRequestPreparationService`
- `AgentQueryContextBuilder`
- `AgentLoopService`
- Finding:
- The current request mixes raw chat history, session learnings, project context, and workspace context, but it does not maintain a dedicated code-task state ledger.
- Impact:
- Long-running runs become increasingly inconsistent because the model keeps rediscovering facts that should already be fixed in memory.
## External Research Notes
### Anthropic Claude Code memory docs
- Claude Code explicitly documents memory files that are auto-loaded at startup and inspectable via `/memory`.
- Planning implication:
- AX should have a clearly observable memory hierarchy for Code tasks, including what was auto-loaded and why.
- Source:
- [Anthropic Claude Code memory docs](https://docs.anthropic.com/zh-CN/docs/claude-code/memory)
### OpenAI practical guide to building agents
- The guide emphasizes observability, eval baselines, and explicit tool and system design before optimizing agent behavior.
- Planning implication:
- AX should log the exact context sections that enter each Code request, including what was compacted and why.
- Source:
- [OpenAI practical guide to building agents](https://cdn.openai.com/business-guides-and-resources/a-practical-guide-to-building-agents.pdf)
### SWE-Pruner
- The paper argues that task-aware adaptive pruning outperforms naive fixed truncation for coding agents.
- Planning implication:
- AX should protect code-task evidence such as latest build failures and changed-file summaries instead of applying mostly size-based pruning.
- Source:
- [SWE-Pruner: Self-Adaptive Context Pruning for Coding Agents](https://arxiv.org/abs/2601.16746)
## `claude-code` Reference Points
Reference targets:
- `claw-code/claw-code-f5a40b86dede580f6543bf8926c9af017eea9409/src/query.ts`
- `claw-code/claw-code-f5a40b86dede580f6543bf8926c9af017eea9409/src/history.ts`
- `claw-code/en/concepts/memory-context.md`
Observed direction:
- `claude-code` builds a dedicated `messagesForQuery` window.
- It stages compaction through boundary filtering, tool-result budgeting, snip, microcompact, and autocompact.
- It treats memory and post-compaction query windows as first-class parts of the request path.
AX already has similar mechanisms, but the Code flow still lacks stronger working-set preservation and cleaner invariant handling.
## Remediation Plan
### Phase 1. Context observability and bootstrap repair
- Reference targets:
- `claw-code/.../src/query.ts`
- `claw-code/en/concepts/memory-context.md`
- AX targets:
- `src/AxCopilot/Views/ChatWindow.UtilityPresentation.cs`
- `src/AxCopilot/Services/Agent/WorkspaceContextGenerator.cs`
- `src/AxCopilot/Services/Agent/AgentQueryContextBuilder.cs`
- `src/AxCopilot/Services/Agent/AgentLoopLlmRequestPreparationService.cs`
- Work items:
- guarantee workspace-context generation starts even on first miss
- log the exact context sections injected into each request
- add diagnostics for omitted sections
- Done criteria:
- empty-workspace runs show workspace context generation by loop 2
- logs show section names, sizes, and compaction status
- Quality scenario:
- a fresh `E:\code` WPF scaffolding run should show folder and project context in the first two request cycles
### Phase 2. Code working-set memory layer
- Reference targets:
- `claw-code/.../src/query.ts`
- `claw-code/.../src/history.ts`
- Anthropic memory docs
- AX targets:
- new `CodeTaskWorkingSetService`
- `src/AxCopilot/Services/Agent/SessionLearningCollector.cs`
- `src/AxCopilot/Services/Agent/AgentLoopService.cs`
- `src/AxCopilot/Services/Agent/AgentQueryContextBuilder.cs`
- Work items:
- maintain a stable structured ledger with:
- current goal
- selected architecture
- changed files
- latest successful writes
- open diagnostics
- next repair target
- inject it only when changed
- replace superseded failures with the latest active issue
- Done criteria:
- long Code runs keep a single coherent working-set block without noisy duplication
- build and test failures are preserved as part of the working set
- Quality scenario:
- after fixing `MC3089`, the run should still remember the earlier structure change while focusing on the new `CS0017` entry-point failure
### Phase 3. Task-aware pruning and protected evidence
- Reference targets:
- `claw-code/.../src/query.ts`
- SWE-Pruner
- AX targets:
- `src/AxCopilot/Services/Agent/AgentToolResultBudget.cs`
- `src/AxCopilot/Services/Agent/ContextCondenser.cs`
- `src/AxCopilot/Services/Agent/AgentQueryContextBuilder.cs`
- Work items:
- protect:
- latest build error block
- latest test failure block
- current plan or working set
- latest folder tree snapshot
- last N write diffs
- move from pure char-based truncation toward semantic snapshots
- tune compaction rules specifically for Code tasks
- Done criteria:
- active repair evidence survives across loops until superseded
- older noise shrinks without losing the current failure context
- Quality scenario:
- a 30-plus-loop Code run should still preserve the latest failure and target files in the request payload
### Phase 4. Tool-trace invariant hardening
- Reference targets:
- `claw-code/.../src/query.ts`
- `claw-code/.../src/history.ts`
- AX targets:
- `src/AxCopilot/Services/LlmService.ToolUse.cs`
- `src/AxCopilot/Services/Agent/AgentMessageInvariantHelper.cs`
- `src/AxCopilot/Services/Agent/AgentLoopService.cs`
- Work items:
- shift from after-the-fact flattening to pre-request validation and normalization
- classify mismatch and orphan causes and lock them with regression tests
- add a final integrity pass before query submission
- Done criteria:
- standard Code runs approach zero mismatch or orphan repair logs
- assistant, tool, and tool_result chains remain intact end to end
- Quality scenario:
- a 50-loop Code run should complete without repeated tool-trace repair events
### Phase 5. Encoding hygiene and prompt cleanup
- Reference targets:
- Anthropic memory docs
- OpenAI practical guide eval and observability recommendations
- AX targets:
- `src/AxCopilot/Views/ChatWindow.SystemPromptBuilder.cs`
- `src/AxCopilot/Services/Agent/SessionLearningCollector.cs`
- active status, prompt, and catalog files
- `AGENTS.md`
- Work items:
- enforce English-only comments in code files
- rewrite mojibake strings in active prompt paths into English
- add long-run Code evals to catch prompt and status encoding regressions
- Done criteria:
- no broken strings remain in active prompt or status paths
- touched code files keep English comments only
- Quality scenario:
- Windows Korean environments should show readable build, test, and status output without mojibake feedback loops
## Priority
1. Phase 1: bootstrap and observability
2. Phase 2: working-set memory
3. Phase 3: task-aware pruning
4. Phase 4: tool-trace invariants
5. Phase 5: encoding and prompt cleanup
## Expected Outcome
- fewer repeated build-failure loops
- better structural consistency for project generation and large edits
- less drift in long-running Code tasks
- fewer quality losses caused by broken strings and low-signal context replacements
## Latest Delivery
Updated: 2026-04-16 01:41 (KST)
- Delivered in this pass:
- Phase 1 foundation:
- `ChatWindow.UtilityPresentation.cs` now bootstraps workspace context generation on first access and returns language-workflow fallback hints while `.ax-context.md` is still being generated.
- `AgentLoopService.cs` now records `query_context` workflow transitions with query-window, budget, supplemental-context, and working-set summaries.
- Phase 2 foundation:
- `CodeTaskWorkingSetService.cs` adds a Code-only structured ledger for:
- goal
- selected scaffold/profile
- created directories
- recent reads/writes
- latest diagnostics
- next repair focus
- the working set is injected into each Code request as a supplemental `code_working_set` system message.
- Phase 3 foundation:
- `AgentToolResultBudget.cs` and `AgentQueryContextBuilder.cs` now expose a `code` query profile with a larger protected-recent window and larger retained budgets for `build_run`, `test_loop`, `process`, `file_read`, `multi_read`, `lsp_code_intel`, and `git_tool`.
- Phase 4 observability step:
- `LlmService.ToolUse.cs` now logs sanitization counts for flattened assistant tool traces and converted orphan tool messages, so tool-trace repair frequency can be measured per run.
- Remaining follow-up:
- extend pre-request tool-trace validation so the flattening/orphan repair count trends toward zero rather than being logged after repair
- replace more mojibake prompt/status strings in active Code execution paths with English equivalents
Updated: 2026-04-16 01:57 (KST)
- Delivered in this pass:
- Phase 4 partial delivery:
- `AgentMessageInvariantHelper.cs` now normalizes historical tool traces before the request leaves the agent loop.
- structured assistant tool-call messages without matching `tool_result` now flatten into plain assistant transcript text.
- orphan `tool_result` messages now flatten into plain user transcript text instead of relying only on late OpenAI payload repair.
- `AgentLoopLlmRequestPreparationService.cs` clones the query window first, then applies normalization, so request cleanup does not mutate stored conversation history.
- `AgentLoopContextReliability.cs` now logs tool-trace repair counts inside the `query_context` transition for run-by-run observability.
- Phase 5 partial delivery:
- `SessionLearningCollector.cs` was rewritten with English-only comments and English injection text.
- `AgentLoopDiagnosticsFormatter.cs` no longer emits mojibake-prone compaction status text in active Code paths.
- Remaining follow-up:
- measure whether `tool_trace_repair` counts keep trending down in long Code runs after this preflight normalization
- continue replacing older mojibake strings outside the active Code execution path
Updated: 2026-04-16 02:05 (KST)
- Delivered in this pass:
- structural alignment step:
- `AgentLoopQueryAssemblyService.cs` now owns the staged query/history assembly path.
- `PrepareHistory(...)` handles session-learning refresh plus queued-command/query-window preparation.
- `PrepareRequest(...)` handles Code working-set supplemental context and request-message assembly before dispatch.
- `AgentLoopService.cs` now delegates those responsibilities instead of manually stitching them together inline.
- test and encoding hygiene step:
- `AgentLoopQueryAssemblyServiceTests.cs` locks the new staged assembly behavior.
- `SessionLearningCollectorTests.cs` was rewritten to English-only comments and assertions to match the new repository rule.
- Remaining follow-up:
- keep extracting more inline AgentLoop responsibilities into smaller staged services where it improves observability or retry correctness
- continue measuring long Code runs against claw-code-style continuity scenarios
Updated: 2026-04-16 02:13 (KST)
- Delivered in this pass:
- structural alignment step:
- `AgentLoopPreLlmStageService.cs` now owns the iteration decisions immediately before the LLM call.
- the service centralizes:
- thinking-summary selection
- Gemini free-tier delay planning
- user-prompt submit hook fingerprint/payload planning
- missing-tool guard shaping
- request assembly handoff
- `AgentLoopService.cs` now consumes that stage result instead of computing those branches inline.
- test coverage step:
- `AgentLoopPreLlmStageServiceTests.cs` now locks the new pre-LLM decision layer.
- Remaining follow-up:
- continue extracting the actual LLM dispatch / streaming callback branch into a narrower execution service
- compare long-running Code traces against claw-code-style staged transitions and keep reducing inline loop logic
+1755 -582
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -26,8 +26,8 @@
- `skills/*.skill.md` 파일 수: 41
- Slash 명령 매핑 엔트리 수: 85
## 4) claw-code 비교 포인트 (실행 반영 기준)
- claw-code 문서 기준 핵심 slash: `/permissions`, `/mcp` 확인
## 4) 핵심 명령 점검 포인트 (실행 반영 기준)
- 공통 운영 명령 기준: `/permissions`, `/mcp` 확인
- AX 현재 매핑에 `/permissions`, `/allowed-tools`, `/mcp`, `/chrome`, `/compact` 포함
- 다음 보강 우선순위:
1. 수동 시나리오 기반 MCP/Chrome 진단 품질 강화
+1 -1
View File
@@ -8,7 +8,7 @@
## 2. 재작성 기준
- 런처는 AX Agent 실행 품질을 끌어올리는 입력 허브로 재정의.
- claw-code의 명령 중심 워크플로우를 AX Commander UX에 맞게 흡수.
- 명령 중심 워크플로우를 AX Commander UX에 맞게 재구성.
## 3. 2026 실행 계획 (v0.7.3 ~ v0.8.x)
+63 -116
View File
@@ -1,133 +1,80 @@
# AX Copilot 통합 로드맵 (전면 재작성)
# AX Copilot 통합 로드맵
## 1. 보존 이력 (요약만 유지)
- v0.5.x: 에이전트/런처 핵심 기능 확장, MCP/스킬/검증 체계 도입.
- v0.6.0: 문서 생성 및 업무 자동화 도구군 확장.
- v0.7.0~v0.7.2: Plan Mode, 병렬 도구, 검증 게이트 및 안정화 강화.
업데이트: 2026-04-15 18:20 (KST)
## 2. 재작성 목표
- claw-code 수준의 실행 신뢰성, 세션 내구성, 결과 품질 확보.
- AX Copilot 고유 제약(사내 운영모드, WPF UX, 로컬 우선)을 유지한 동등 품질 구현.
## 1. 방향
- AX Copilot 전반의 실행 신뢰성, 세션 내구성, 결과 품질을 함께 끌어올립니다.
- 개발 문서는 비교 보고서가 아니라 AX 기준 계획과 검증 기록으로 유지합니다.
## 3. 마일스톤
## 2. 마일스톤
| 마일스톤 | 참조 대상 (`claw-code`) | AX 적용 위치 | 완료 조건 | 품질 판정 시나리오 |
| 마일스톤 | 참조 대상 | AX 적용 위치 | 완료 조건 | 품질 판정 시나리오 |
|---|---|---|---|---|
| M1 (v0.7.3) Hook 계약 정식화 | `src/utils/hooks.ts`, `src/utils/hooks/hookEvents.ts`, `src/utils/permissions/PermissionUpdate.ts` | `src/AxCopilot/Services/Agent/AgentHookRunner.cs`, `src/AxCopilot/Services/Agent/AgentLoopService.cs`, `src/AxCopilot/Models/AppSettings.cs`, `src/AxCopilot/ViewModels/SettingsViewModel.cs`, `src/AxCopilot/Views/SettingsWindow.xaml` | Hook 출력 계약(`updatedInput`, `updatedPermissions`, `additionalContext`) 반영. 설정값-실행코드-UI 동시 반영. | JSON 훅/텍스트 훅 혼합 환경에서 실행 품질과 하위호환 유지 확인. |
| M2 (v0.7.4~v0.7.5) 세션/로그 내구성 | `src/utils/plans.ts`, `src/utils/sessionStorage.ts` | `src/AxCopilot/Services/ChatSessionStateService.cs`, `src/AxCopilot/Services/TaskRunService.cs`, `src/AxCopilot/Services/TaskRunStore.cs`, `src/AxCopilot/Views/ChatWindow.xaml.cs`, `src/AxCopilot/Models/ChatModels.cs` | Plan/Run 상태 영속화. 이벤트 로그 표준화 replay 안정성 확보. | 앱 재시작/강제종료 후 동일 세션 재개 시 상태/이력 불일치 0건. |
| M3 (v0.7.6) 도구 선택/복구 안정화 | `src/commands.ts`, `src/Tool.ts`, `src/query.ts` | `src/AxCopilot/Services/Agent/AgentLoopService.cs`, `src/AxCopilot/Services/Agent/AgentLoopParallelExecution.cs`, `src/AxCopilot/Services/LlmService.ToolUse.cs` | 도구 선택 실패 루프 억제. 실패 유형별 복구 흐름 정형화. | 오타/비활성/별칭 도구 요청이 반복 실패 없이 정상 경로로 수렴하는지 확인. |
| M4 (v0.8.0) 품질 게이트 최종 정렬 | `src/query.ts`, `src/QueryEngine.ts`, `src/utils/sessionStorage.ts` | `src/AxCopilot/Services/Agent/AgentLoopService.cs`, `src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs`, `src/AxCopilot/Services/Agent/AgentLoopTransitions.cs` | 증거 기반 완료 판정 고정. 내부 벤치마크에서 claw-code 동급 품질 달성. | 코드수정/문서생성/권한거부/복구 혼합 시나리오에서 조기완료 없이 근거 기반 종료 확인. |
| M1 (v0.7.3) Hook 계약 정식화 | `src/utils/hooks.ts`, `src/utils/hooks/hookEvents.ts`, `src/utils/permissions/PermissionUpdate.ts` | `AgentHookRunner.cs`, `AgentLoopService.cs`, `AppSettings.cs`, `SettingsViewModel.cs`, `SettingsWindow.xaml` | Hook 출력 계약(`updatedInput`, `updatedPermissions`, `additionalContext`) 반영, 설정값-실행코드-UI 동시 반영 | JSON 훅/텍스트 훅 혼합 환경에서 실행 품질과 하위호환 유지 |
| M2 (v0.7.4 ~ v0.7.5) 세션/로그 내구성 | `src/utils/plans.ts`, `src/utils/sessionStorage.ts` | `ChatSessionStateService.cs`, `TaskRunService.cs`, `TaskRunStore.cs`, `ChatWindow.xaml.cs`, `ChatModels.cs` | plan/run 상태 영속화, 이벤트 로그 표준화, replay 안정성 확보 | 앱 재시작/강제 종료 후 같은 세션 재개 시 상태 불일치 0건 |
| M3 (v0.7.6) 도구 선택/복구 안정화 | `src/commands.ts`, `src/Tool.ts`, `src/query.ts` | `AgentLoopService.cs`, `AgentLoopParallelExecution.cs`, `LlmService.ToolUse.cs` | 도구 선택 실패 루프 억제, 실패 유형별 복구 흐름 정형화 | 오타/비활성/별칭 도구 요청이 반복 실패 없이 정상 경로로 수렴 |
| M4 (v0.8.0) 품질 게이트 고정 | `src/query.ts`, `src/QueryEngine.ts`, `src/utils/sessionStorage.ts` | `AgentLoopService.cs`, `AgentLoopTransitions.Execution.cs`, `AgentLoopTransitions.cs` | 증거 기반 완료 판정 고정, 릴리즈 게이트 자동화 강화 | 코드수정/문서생성/권한거부/복구 혼합 시나리오에서 조기 완료 없이 종료 |
## 4. 측정 지표
- 반복 실패 루프 발생률.
- 세션 재개 성공률.
- 완료 응답 근거 누락률.
- 빌드/테스트 통과율.
## 3. 측정 지표
- 반복 실패 루프 발생률
- 세션 재개 성공률
- 완료 응답 근거 누락률
- 빌드/테스트 통과율
## 5. 운영 원칙
- `internal` 모드: 외부 유출 경로 차단 우선.
- 신규 기능은 반드시 설정값 연결 + 실제 동작 반영.
- 문서 마스터는 `.md`, HTML은 요청 시만 갱신.
## 4. 운영 원칙
- `internal` 모드에서는 외부 유출 경로 차단 우선
- 신규 기능은 설정값 연결 실제 동작 반영을 함께 완료
- 문서 마스터는 `.md`, HTML은 요청 시만 갱신
## 6. 즉시 실행 백로그
1. Hook 계약 확장 마무리 및 회귀 테스트.
2. 세션 복원 경계조건 테스트 세트 추가.
3. 이벤트 로그 스키마 고정 및 분석 리포트 템플릿 정리.
## 5. 즉시 실행 백로그
1. Hook 계약 확장 마무리 및 회귀 테스트
2. 세션 복원 경계조건 테스트 세트 추가
3. 이벤트 로그 스키마 고정 및 분석 리포트 템플릿 정리
## 7. 2026-04-03 실행 증적 동기화 (M4 포함)
- 기준 시점: 2026-04-03.
- 테스트: `dotnet test` 379/379 통과.
- M1 증적: Hook 계약 필드(`updatedInput`, `updatedPermissions`, `additionalContext`) 반영 경로 구현 완료.
- M2 증적: run 복원/이력 재구성(`RestoreRecentFromExecutionEvents`, `RestoreCurrentAgentRun`, plan 이력 조회) 구현 및 테스트 존재.
- M3 증적: unknown-tool 복구 루프/결정 이벤트 처리 경로 구현 및 테스트 존재.
- M4 증적: 실행 종료 품질 게이트(`CodeQualityGate`, `ExecutionSuccessGate`, `TerminalEvidenceGate`) 반영 및 관련 테스트 존재.
- 스킬/도구 운영 정렬: 40개 스킬 모두 `allowed-tools` 명시 완료, Python 의존 10개는 fallback 분기 적용, 레거시 도구명(`process_run`, `grep_tool`) 참조 제거.
## 6. 실행 증적 기준
- 기준 시점: 2026-04-03
- 전체 테스트: `379/379` 통과
- Hook 계약 필드 반영 경로 구현 완료
- run 복원/이력 재구성 경로 구현 및 테스트 존재
- unknown-tool 복구 루프와 완료 게이트 경로 구현 및 테스트 존재
- 스킬/도구 운영 정렬: `allowed-tools` 전건 명시, Python 의존 경로 fallback 반영, 레거시 도구명 참조 제거
## 8. 남은 마감 항목 (M4 종료 조건)
1. 세션 replay 불일치 0건을 재현 시나리오별 수치로 기록.
2. 위 결과를 배포 전 체크리스트로 고정하고 매 릴리즈마다 수치 동기화.
## 7. 벤치마크 기준
- 기준 문서: `docs/AX_AGENT_QUALITY_PLAN.md`
- 고정 시나리오:
- 기본 loop
- unknown-tool 복구
- plan 연결
- 권한 거부
- hook 입력 변형
- allowed-tools 강제
- hook filter
- 합격 게이트:
- 빌드 경고·오류 0
- 전체 테스트 통과
- 고정 시나리오 회귀 통과
## 9. 벤치마크 고정 기준 (CLAW 패리티 동기화)
- 기준 문서: `docs/CLAW_CODE_PARITY_PLAN.md` 12절.
- 고정 시나리오: 기본 loop / unknown-tool 복구 / plan 연결 / 권한 거부 / hook 입력 변형 / allowed-tools 강제 / hook filter.
- 합격 게이트: 빌드 경고·오류 0 + 전체 테스트 통과 + 고정 시나리오 회귀 통과.
## 8. 실행 프레임
## 10. Replay 안정성 검증 연동
- 기준 문서: `docs/CLAW_CODE_PARITY_PLAN.md` 13절.
- 테스트 태그: `Suite=ReplayStability`.
- 운영 기준: 릴리즈 전 `ReplayStability` 시나리오 전건 통과 시 replay 불일치 0건으로 판정.
- 최신 실행 증적(2026-04-03): `ParityBenchmark 13/13`, `ReplayStability 14/14`, 전체 `379/379`.
- 실행 자동화: `scripts/release-gate.ps1`로 빌드/벤치마크/리플레이/전체 테스트를 일괄 점검.
### 입력 계층
- slash 명령 카탈로그와 매칭 상태를 별도 파일로 분리
- 입력 파싱 변경은 회귀 테스트와 함께 반영
## 11. 권한 Hook 계약 고정 (M1 완료 기준)
- lifecycle hook 키:
- `__permission_request__` (pre)
- `__permission_granted__` (post)
- `__permission_denied__` (post)
- payload 기준 필드: `runId`, `tool`, `target`, `permission`, `granted`, `reason`.
- 실행 우선순위:
1. Hook의 `updatedPermissions`를 현재 run 권한 컨텍스트에 즉시 반영.
2. 반영 후 `CheckToolPermissionAsync()`로 최종 권한 판정 수행.
3. hook 예외/실패는 non-blocking으로 처리하고 권한 흐름은 지속.
4. `additionalContext`는 가능한 경로에서 실행 메시지 컨텍스트에 병합.
### 권한 UX
- 권한 모드 명칭, 설명, 색, 정렬 순서를 단일 소스에서 관리
- 팝업, 상태 배너, 슬래시 출력이 같은 용어를 사용
### 설정 동기화
- Cowork/Code 설정 분기를 실행 코드까지 일치
- 설정 변경 즉시 반영 시나리오를 체크리스트화
### 통합 회귀
- `internal/external`, permission deny/recover, mcp reconnect, compact 수동/자동 흐름을 함께 검증
### 업무형 UI 마감
- 좌측 패널, 컴포저, 권한 팝업 밀도와 탐색 동작을 단순하고 일관된 패턴으로 정리
## 2026-04-04 추가 계획 (Codex/Claude 추격 로드맵 재정렬)
업데이트: 2026-04-04 13:24 (KST)
### 기준 소스
- claw-code/src/commands.ts
- claw-code/src/utils/permissions/PermissionMode.ts
- claw-code/src/components/PromptInput/PromptInput.tsx
### 현재 AX 격차 요약
1. 입력/슬래시/권한 처리 로직이 ChatWindow 단일 파일에 상대적으로 집중되어 변경 파급도가 큼.
2. 설정-런타임-UI 동기화는 기능은 많지만 구조적 분리가 부족해 회귀 리스크가 높음.
3. Agent loop 품질 게이트는 확보됐으나, UI 상호작용 회귀 시나리오와 결합된 자동 검증이 더 필요함.
### 연속 실행 목표 (L1~L5)
- **L1. 입력 계층 모듈화**
- 목표: slash 명령 카탈로그/매칭/선택 상태를 분리해 ChatWindow 결합도 축소
- 완료 기준: slash 관련 핵심 로직을 독립 파일로 분리하고 기존 slash 테스트 통과
- **L2. 권한 UX/로직 단일 카탈로그화**
- 목표: 권한 모드 명칭/설명/색/정렬 순서를 단일 소스에서 제공
- 완료 기준: 팝업/상태 배너/슬래시 출력에서 동일 용어·동일 순서 유지
- **L3. 설정 동기화 강화**
- 목표: Cowork/Code 설정 분기를 실행 코드 경로까지 일치시켜 회귀 감소
- 완료 기준: 설정 변경 즉시 반영 시나리오 체크리스트 전건 통과
- **L4. Agentic loop + UI 결합 회귀 테스트 보강**
- 목표: internal/external, permission deny/recover, mcp reconnect, compact 수동/자동 흐름을 통합 검증
- 완료 기준: 릴리즈 게이트용 통합 테스트 세트 추가 및 통과
- **L5. Codex/Claude형 UI 마감**
- 목표: 좌측 패널/컴포저/권한 팝업 밀도와 탐색 동작을 단순·일관 패턴으로 정리
- 완료 기준: UI 체크리스트 주요 항목 100% 충족 + 빌드 경고/오류 0
### 이번 턴 즉시 반영 (L1 시작)
- ChatWindow의 대형 slash 명령 사전을 SlashCommandCatalog로 분리.
- ChatWindow는 카탈로그 API(MatchBuiltinCommands, TryGetEntry)를 통해 조회하도록 전환.
- 결과: 입력 계층 결합도 감소 + 향후 slash 확장/정리 시 변경 범위 축소.
## 2026-04-04 실행 프레임 고정 (중기 계획)
업데이트: 2026-04-04 14:47 (KST)
### 3축 고정 운영
1. 로직 안정화: 권한/운영모드/compact/모델 연결 경로를 테스트 우선으로 보강.
2. 기능 동등성: claw-code 기준 주요 명령(/compact, /permissions, /mcp, /chrome)을 실행 시나리오로 검증.
3. UX 정렬: 상단/컴포저/팝업 밀도는 로직 안정화 완료 범위 내에서만 단계 반영.
### 이번 사이클 기준 완료 조건
- 빌드: `dotnet build` 경고 0 / 오류 0.
- 핵심 회귀: 운영모드, 권한, slash, 모델연결, compact 관련 필터 테스트 통과.
- 문서: `README.md`, `docs/DEVELOPMENT.md`에 시간 포함 이력 동기화 후 커밋/푸시.
### 이번 사이클 실제 보강 항목
- `ContextCondenserTests` 추가:
- proactive 비활성 시 무변경 확인
- 대용량 tool_result 축약 동작 확인
- `LlmRuntimeOverrideTests` 보강:
- vLLM 암호화 API키 런타임 복호화 검증
- 등록모델/전역 TLS 우회 플래그 합성 규칙 검증
## 9. 최근 진행 메모
- 2026-04-15 08:32 (KST): 루프 품질은 장기 상태 고정과 세분화 중심 과제로 축소
- 2026-04-15 09:49 (KST): 언어별 workflow 주입과 문서 포맷 critic/repair 루프를 다음 우선순위로 정리
- 2026-04-15 10:05 (KST): queued command projector, run lifecycle helper, quality formatter 확장을 다음 배치로 고정
+101
View File
@@ -0,0 +1,101 @@
# 도구 / 슬래시 커버리지 현황
업데이트: 2026-04-15 18:20 (KST)
## 1. 요약
- AX slash count: 85
- 공통 핵심 명령 수: 7
- AX 확장 명령 수: 78
## 2. 공통 핵심 명령
- `/clear`
- `/exit`
- `/help`
- `/init`
- `/mcp`
- `/memory`
- `/permissions`
## 3. AX 확장 명령
- `/add-dir`
- `/advisor`
- `/agents`
- `/allowed-tools`
- `/branch`
- `/btw`
- `/build`
- `/chrome`
- `/color`
- `/commit`
- `/compact`
- `/config`
- `/context`
- `/copy`
- `/cost`
- `/desktop`
- `/diff`
- `/doctor`
- `/effort`
- `/explain`
- `/export`
- `/fast`
- `/feedback`
- `/files`
- `/fix`
- `/heapdump`
- `/hooks`
- `/ide`
- `/init-verifiers`
- `/install-github-app`
- `/install-slack-app`
- `/keybindings`
- `/login`
- `/logout`
- `/mobile`
- `/model`
- `/new`
- `/output-style`
- `/passes`
- `/plan`
- `/plugin`
- `/pr`
- `/pr-comments`
- `/privacy-settings`
- `/rate-limit-options`
- `/release-notes`
- `/reload-plugins`
- `/remote-env`
- `/rename`
- `/reset`
- `/resume`
- `/review`
- `/rewind`
- `/sandbox-toggle`
- `/search`
- `/security-review`
- `/session`
- `/settings`
- `/skills`
- `/stats`
- `/status`
- `/statusline`
- `/stickers`
- `/structure`
- `/summary`
- `/tag`
- `/tasks`
- `/terminal-setup`
- `/test`
- `/theme`
- `/thinkback`
- `/thinkback-play`
- `/translate`
- `/ultrareview`
- `/upgrade`
- `/usage`
- `/verify`
- `/vim`
## 4. 메모
- AX source baseline: `src/AxCopilot/Views/ChatWindow.xaml.cs`
- 이 문서는 비교 보고서가 아니라 현재 AX가 제공하는 명령 범위와 공통 핵심 명령을 확인하기 위한 운영 문서입니다.
-105
View File
@@ -1,105 +0,0 @@
# Tool/Slash Parity Report
Generated: 2026-04-04 02:06:25
## Summary
- AX slash count: 85
- claw-code slash count: 7
- Common: 7
- AX only: 78
- claw-code only: 0
## Common
- /clear
- /exit
- /help
- /init
- /mcp
- /memory
- /permissions
## AX Only
- /add-dir
- /advisor
- /agents
- /allowed-tools
- /branch
- /btw
- /build
- /chrome
- /color
- /commit
- /compact
- /config
- /context
- /copy
- /cost
- /desktop
- /diff
- /doctor
- /effort
- /explain
- /export
- /fast
- /feedback
- /files
- /fix
- /heapdump
- /hooks
- /ide
- /init-verifiers
- /install-github-app
- /install-slack-app
- /keybindings
- /login
- /logout
- /mobile
- /model
- /new
- /output-style
- /passes
- /plan
- /plugin
- /pr
- /pr-comments
- /privacy-settings
- /rate-limit-options
- /release-notes
- /reload-plugins
- /remote-env
- /rename
- /reset
- /resume
- /review
- /rewind
- /sandbox-toggle
- /search
- /security-review
- /session
- /settings
- /skills
- /stats
- /status
- /statusline
- /stickers
- /structure
- /summary
- /tag
- /tasks
- /terminal-setup
- /test
- /theme
- /thinkback
- /thinkback-play
- /translate
- /ultrareview
- /upgrade
- /usage
- /verify
- /vim
## claw-code Only
## Notes
- claw-code source baseline: claw-code/en/quickstart.md
- AX source baseline: src/AxCopilot/Views/ChatWindow.xaml.cs
-523
View File
@@ -1,523 +0,0 @@
# Claw Code Parity Plan (Rewritten)
## Scope
- Align AX Copilot with claw-code quality for loop reliability, permission/hook behavior, and session durability.
## Update
- Updated: 2026-04-05 15:34 (KST)
- Rebased the AX Agent improvement plan on actual `claw-code` runtime files instead of earlier AX snapshots. The reference spine is now `src/bootstrap/state.ts -> src/bridge/initReplBridge.ts -> src/bridge/sessionRunner.ts -> src/screens/REPL.tsx -> src/components/Messages.tsx -> src/components/StatusLine.tsx`.
- AX Agent work should follow that same quality order: state first, execution second, render last. UI-only fixes that bypass state/execution should be treated as temporary.
- Updated: 2026-04-05 16:55 (KST)
- Current estimated parity vs `claw-code`: core execution engine `82%`, main chat UI `68%`, Cowork/Code status UX `63%`, internal settings linkage `88%`, overall AX Agent `74%`.
- Engine-affecting settings should be handled conservatively during parity work. If a setting changes the main execution route, approval flow, or recovery behavior without representing a stable real-world user choice, it should be moved to developer-only UI or removed from user-facing surfaces.
- Updated: 2026-04-06 09:36 (KST)
- Progressed the maintainability track by moving runtime strip styling into `OperationalStatusPresentationCatalog.cs`, expanding permission/tool-result transcript catalogs with typed descriptions, and removing the stale plan-mode presentation branch from permission UI surfaces. The next structural focus remains footer/status/composer presentation slimming and regression ritual enforcement.
- Updated: 2026-04-06 09:44 (KST)
- Continued the maintainability track by splitting mixed inline interaction rendering into `ChatWindow.UserAskPresentation.cs` and `ChatWindow.PlanApprovalPresentation.cs`. This reduces message-type coupling inside the main window and keeps the next focus on footer/composer presentation and regression-routine formalization.
- Updated: 2026-04-06 09:58 (KST)
- Continued the maintainability track by splitting Git branch popup and footer-adjacent summary helpers into `ChatWindow.GitBranchPresentation.cs`, leaving `ChatWindow.FooterPresentation.cs` focused on folder bar state and preset-guide sync only.
- Formalized the regression ritual in `docs/AX_AGENT_REGRESSION_PROMPTS.md` by adding failure classes (`blank-reply`, `duplicate-banner`, `bad-approval-flow`, `queue-drift`, `restore-drift`, `status-noise`) and required prompt bundles per change area.
- Updated: 2026-04-06 10:07 (KST)
- Continued the maintainability track by moving topic preset rendering, custom preset context menus, and topic-selection application flow into `ChatWindow.TopicPresetPresentation.cs`. This reduces mixed preset UI logic inside `ChatWindow.xaml.cs` and keeps the main window closer to orchestration-only responsibility.
- Updated: 2026-04-06 11:52 (KST)
- Continued the tool/permission/skill sophistication track by expanding AX presentation catalogs toward `claw-code` specificity. `PermissionRequestPresentationCatalog.cs` now models action-level permission kinds plus severity/action hints, `ToolResultPresentationCatalog.cs` now models `approval_required`/`partial` result states plus follow-up guidance, and the AX skill gallery now exposes runtime-policy metadata that was previously hidden.
## Preserved History (Summary)
- Core loop guards and post-tool verification gates are already partially implemented.
- Plan Mode, parallel tool execution, and unknown-tool recovery are in place.
- Session restore hardening is ongoing.
## Reference Map
| claw-code reference | AX apply target | completion criteria | quality criteria |
|---|---|---|---|
| `src/bootstrap/state.ts` | `src/AxCopilot/Views/ChatWindow.xaml.cs`, `src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs`, `src/AxCopilot/Services/ChatStorageService.cs` | one canonical runtime/session state for current turn, queue, retry, execution events, and persisted snapshot | reopen/retry/queue flows do not create duplicate or blank assistant messages |
| `src/bridge/initReplBridge.ts` | `src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs`, `src/AxCopilot/Services/LlmService.cs` | send/regenerate/retry/queued follow-up/slash all enter through one prepared-execution path | same input under same settings takes same execution route regardless of entry point |
| `src/bridge/sessionRunner.ts` | `src/AxCopilot/Services/Agent/AgentLoopService.cs`, `src/AxCopilot/Services/Agent/AgentLoopTransitions.cs`, `src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs` | tool start/result/error/progress normalized once inside loop layer | Cowork/Code no longer flash repeated status strings or overshare debug payloads |
| `src/bridge/bridgeMessaging.ts` | `src/AxCopilot/Views/ChatWindow.xaml.cs`, `src/AxCopilot/Services/Agent/AgentLoopService.cs` | inbound execution events separated from display-only events before UI render | execution event replay does not duplicate visible timeline banners |
| `src/screens/REPL.tsx` | `src/AxCopilot/Views/ChatWindow.xaml`, `src/AxCopilot/Views/ChatWindow.xaml.cs` | screen state transitions, queue flow, retry flow, and composer state use shared runtime helpers | window resize, queue chaining, and retry feel stable instead of UI-patched |
| `src/components/Messages.tsx` | `src/AxCopilot/Views/ChatWindow.xaml.cs` | timeline derives from normalized conversation/session state only | no token-only completions, blank cards, or direct injected duplicates |
| `src/components/StatusLine.tsx` | `src/AxCopilot/Views/ChatWindow.xaml`, `src/AxCopilot/Views/ChatWindow.xaml.cs` | status strip computed from debounced runtime state, not multiple imperative refresh calls | metadata stays lightweight and does not overpower message timeline |
## AX Agent Improvement Phases
### Phase A. Runtime State Canonicalization
- Reference: `src/bootstrap/state.ts`
- AX apply location: `src/AxCopilot/Views/ChatWindow.xaml.cs`, `src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs`, `src/AxCopilot/Services/ChatStorageService.cs`
- Completion criteria:
- `Chat`, `Cowork`, `Code` all update one shared runtime/session state model.
- queue, retry, post-compaction, and execution-event state can be restored after reopen.
- Quality criteria:
- reopening a conversation reproduces the same visible timeline without extra assistant cards.
- queue and execution badges remain in sync with the stored conversation.
### Phase B. Prepared Execution Unification
- Reference: `src/bridge/initReplBridge.ts`
- AX apply location: `src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs`, `src/AxCopilot/Services/LlmService.cs`
- Completion criteria:
- prompt stack assembly, execution mode choice, and final assistant commit are engine-owned.
- send/regenerate/retry/queued follow-up/slash flows all call the same preparation API.
- Quality criteria:
- behavior is deterministic per tab/settings combination.
- UI stops building different prompt stacks for the same conversation state.
### Phase C. AgentLoop Event Normalization
- Reference: `src/bridge/sessionRunner.ts`, `src/bridge/bridgeMessaging.ts`
- AX apply location: `src/AxCopilot/Services/Agent/AgentLoopService.cs`, `src/AxCopilot/Services/Agent/AgentLoopTransitions.cs`, `src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs`
- Completion criteria:
- loop events are normalized into bounded activity/event records before UI consumption.
- permission requests, failure states, retries, and completion states use a stable event shape.
- Quality criteria:
- Cowork/Code no longer flash rapidly during long-running tool sequences.
- file path/debug detail remains collapsed by default.
### Phase D. Timeline Render Parity
- Reference: `src/screens/REPL.tsx`, `src/components/Messages.tsx`
- AX apply location: `src/AxCopilot/Views/ChatWindow.xaml`, `src/AxCopilot/Views/ChatWindow.xaml.cs`
- Completion criteria:
- assistant/user messages, execution logs, compact boundaries, and queue summaries are rendered from one derived timeline model.
- direct imperative bubble injection is removed from normal send/regenerate/retry flows.
- Quality criteria:
- no blank assistant cards.
- no token-only completion without visible content.
- no duplicate event banners after re-render.
### Phase E. Composer and Status Strip Simplification
- Reference: `src/screens/REPL.tsx`, `src/components/StatusLine.tsx`
- AX apply location: `src/AxCopilot/Views/ChatWindow.xaml`, `src/AxCopilot/Views/ChatWindow.xaml.cs`
- Completion criteria:
- composer height grows only on explicit line breaks.
- status strip, queue summary, and runtime activity all use debounced runtime updates.
- Chat/Cowork/Code share one responsive width calculation policy.
- Quality criteria:
- resizing feels natural.
- composer does not keep growing after send.
- metadata remains subordinate to the message timeline.
### Phase F. Recovery, Resume, and Verification
- Reference: `src/bootstrap/state.ts`, `src/bridge/sessionRunner.ts`, `src/screens/REPL.tsx`
- AX apply location: `src/AxCopilot/Views/ChatWindow.xaml.cs`, `src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs`, `src/AxCopilot/Services/ChatStorageService.cs`
- Completion criteria:
- reopen after interruption keeps queue, runtime summary, and latest visible assistant state consistent.
- retry-last and regenerate do not depend on mutating `InputBox.Text`.
- all three tabs pass reopen/retry/manual compact/manual stop/manual resume scenarios.
- Quality criteria:
- stored conversation and rendered conversation stay identical after restore.
- final reopened state matches the last completed runtime state.
## Execution Tracks
1. Hook contract parity
- Structured hook output support (`updatedInput`, `updatedPermissions`, `additionalContext`).
- Runtime gating through settings toggles.
2. Session/state parity
- Deterministic run resume rules.
- Stable jsonl event schema + replay compatibility.
3. Recovery parity
- Failure-type classification and standardized retry guidance.
- Reduced repeated wrong-tool loops.
4. Completion parity
- Evidence-based finalization criteria for code/document tasks.
## Done Criteria
- Internal parity scenarios pass target threshold.
- Resume/replay failures: zero.
- `dotnet build` warnings/errors: zero.
## Validation Matrix
- Build: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\`
- Manual scenario 1: Chat send -> answer visible -> retry -> regenerate -> reopen conversation
- Manual scenario 2: Cowork tool run -> progress summary -> completion -> queue next request -> reopen
- Manual scenario 3: Code task with execution log noise -> completion -> compact -> next turn -> reopen
- Manual scenario 4: AX Agent internal settings change -> immediate runtime reflection without layout regression
## Canonical Prompt Set
- Updated: 2026-04-05 22:04 (KST)
- The following prompt set should be used for AX vs `claw-code` parity checks. The goal is not byte-identical output, but equivalent execution route, approval behavior, and artifact/result quality.
- Operational checklist copy: `docs/AX_AGENT_REGRESSION_PROMPTS.md`
1. Chat basic answer
- Prompt: `회의 일정 조정 메일을 정중한 한국어로 써줘`
- Apply to: `Chat`
- Verify: normal reply render, retry/regenerate stability, reopen durability
2. Chat long-form explanation
- Prompt: `RAG와 fine-tuning 차이를 실무 관점으로 7가지로 설명해줘`
- Apply to: `Chat`
- Verify: long response rendering, compaction follow-up continuity
3. Cowork document task
- Prompt: `신규 ERP 도입 제안서 초안을 작성해줘. 목적, 범위, 기대효과, 추진일정 포함`
- Apply to: `Cowork`
- Verify: topic/task preset routing, plan-first execution, actual document-oriented output path
4. Cowork data task
- Prompt: `매출 CSV를 분석해서 월별 추세와 이상치를 요약해줘`
- Apply to: `Cowork`
- Verify: data-analysis tool choice, reduced runtime noise, final summary quality
5. Code bug-fix task
- Prompt: `현재 프로젝트에서 설정 저장 버그 원인 찾고 수정해줘`
- Apply to: `Code`
- Verify: read/search/edit path, diff persistence, reopen consistency
6. Code build/test task
- Prompt: `빌드 오류를 재현하고 수정한 뒤 다시 빌드해줘`
- Apply to: `Code`
- Verify: build/test loop, failure retry, final completion message
7. Queued follow-up
- Prompt sequence:
- `이 창 레이아웃 문제 원인 찾아줘`
- `끝나면 README도 같이 갱신해줘`
- Apply to: `Cowork`, `Code`
- Verify: queue chaining, next-turn pickup without UI mutation
8. Post-compaction continuity
- Prompt: `지금까지 논의한 내용을 5줄로 이어서 정리하고 다음 작업 제안해줘`
- Apply to: `Chat`, `Cowork`, `Code`
- Verify: compact-after-next-turn continuity, no token-only completion
9. Permission approval
- Prompt: `이 파일을 수정해서 저장해줘`
- Apply to: `Code`
- Verify: permission request, approve/reject rendering, final transcript consistency
10. Slash / skill entry
- Prompt: `/bug-hunt src 폴더 잠재 버그 찾아줘`
- Apply to: `Code`
- Verify: slash entry uses the same prepared-execution route as normal send
## Tool / Skill Delta Snapshot
- Updated: 2026-04-05 22:04 (KST)
- AX tool registry count is larger than `claw-code`, but the shape is different.
- AX reference: `src/AxCopilot/Services/Agent/ToolRegistry.cs`
- `claw-code` reference: `src/tools/*`, `src/skills/bundledSkills.ts`
### AX stronger areas
- Document/office generation and conversion (`ExcelSkill`, `DocxSkill`, `PptxSkill`, `DocumentPlannerTool`, `DocumentAssemblerTool`)
- Data/business utilities (`DataPivotTool`, `SqlTool`, `FormatConvertTool`, `TextSummarizeTool`)
- WPF-integrated enterprise UX and Korean workflow presets
### claw-code stronger areas
- Transcript-native tool use / rejection / approval message taxonomy
- Plan approval request/response rendering in the message stream
- Permission and tool-result message consistency
- Bundled skill registry and skill message integration
### Remaining parity target
- Keep AX's richer business/document tool set
- Bring transcript rendering and approval/status UX closer to `claw-code`
## Transcript-First Approval / Ask UX
- Updated: 2026-04-05 18:58 (KST)
- `plan approval` and `user ask` should both resolve inside the transcript first.
- Secondary windows are allowed only as detail surfaces, not as the primary decision flow.
- AX implementation status:
- `plan approval`: transcript-first, detail view via `PlanViewerWindow`
- `user ask`: transcript-first inline question card with choices / direct input / submit
## Tool / Skill UX Parity Follow-up
- Updated: 2026-04-05 19:04 (KST)
- Default transcript should prefer role-oriented badges and readable labels over raw internal tool names.
- AX implementation status:
- tool event badges: simplified to role-first labels
- item naming: normalized into readable Korean labels or `/skill-name` style
- observability panels: permission/background diagnostics reduced outside debug mode
- Remaining quality target:
- move more tool-result and permission-result presentation into smaller message-type-specific helpers, closer to `claw-code` component separation
## Focused Quality Tracks
- Updated: 2026-04-06 09:27 (KST)
- The remaining improvement work should now be managed in three parallel tracks so UX polish, runtime quality, and maintainability do not get mixed together.
### Track 1. User-Facing UI/UX Quality
- Reference:
- `src/components/Messages.tsx`
- `src/components/MessageRow.tsx`
- `src/components/StatusLine.tsx`
- `src/components/PromptInput/PromptInput.tsx`
- `src/components/PromptInput/PromptInputFooter.tsx`
- `src/components/SessionPreview.tsx`
- AX apply target:
- `src/AxCopilot/Views/ChatWindow.xaml`
- `src/AxCopilot/Views/ChatWindow.MessageInteractions.cs`
- `src/AxCopilot/Views/ChatWindow.StatusPresentation.cs`
- `src/AxCopilot/Views/ChatWindow.FooterPresentation.cs`
- `src/AxCopilot/Views/ChatWindow.PreviewPresentation.cs`
- Focus:
- keep transcript text dominant and metadata secondary
- make footer controls read as a task bar, not a settings strip
- unify preview surfaces, chooser popups, and approval cards under one visual language
- reduce visual noise from queue/status/diagnostic surfaces unless the state is actionable
- Completion criteria:
- message rows, footer, preview, and inline approval/question cards feel visually coherent
- chooser popups share the same spacing, hover behavior, and summary-row structure
- footer/status elements appear only when they convey useful state
- Quality criteria:
- a user can understand “what is happening now” from the transcript and footer without opening extra panels
- the interface remains readable under narrow widths without text clipping or layout jitter
### Track 2. LLM / Task Handling Quality
- Reference:
- `src/bootstrap/state.ts`
- `src/bridge/initReplBridge.ts`
- `src/bridge/sessionRunner.ts`
- `src/components/messages/AssistantToolUseMessage.tsx`
- `src/components/messages/PlanApprovalMessage.tsx`
- `src/components/permissions/*`
- AX apply target:
- `src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs`
- `src/AxCopilot/Services/Agent/AgentLoopService.cs`
- `src/AxCopilot/Services/Agent/AgentTranscriptDisplayCatalog.cs`
- `src/AxCopilot/Services/Agent/PermissionRequestPresentationCatalog.cs`
- `src/AxCopilot/Services/Agent/ToolResultPresentationCatalog.cs`
- `src/AxCopilot/Views/ChatWindow.InlineInteractions.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptPolicy.cs`
- Focus:
- keep all entry routes (`send`, `retry`, `regenerate`, `queue`, `slash`) on the same prepared execution path
- distinguish `success / error / reject / cancel / needs-approval` tool results more clearly
- keep plan approval and user-question flows transcript-native by default
- minimize mismatches between execution state and what the user sees in the timeline
- Completion criteria:
- plan/permission/tool-result/question events all have consistent transcript-native lifecycles
- reopen/retry/queue/compact flows preserve the same visible runtime state
- tool failures and permission rejections are clearly distinguishable in transcript rendering
- Quality criteria:
- the same prompt under the same tab/settings uses the same execution route
- users can tell whether the agent succeeded, failed, was blocked, or is waiting for approval without reading raw diagnostics
### Track 3. Maintainability / Extensibility Structure
- Reference:
- `src/components/*` split by role in `claw-code`
- `src/components/messages/*`
- `src/components/permissions/*`
- `src/components/PromptInput/*`
- AX apply target:
- `src/AxCopilot/Views/ChatWindow.xaml.cs`
- `src/AxCopilot/Views/ChatWindow.*.cs`
- `src/AxCopilot/Services/AppStateService.cs`
- `src/AxCopilot/Services/Agent/*.cs`
- Focus:
- continue shrinking `ChatWindow.xaml.cs` toward orchestration-only responsibility
- keep renderer, popup, footer, message-interaction, status, and preview logic in dedicated partials
- centralize presentation rules in catalogs/models instead of scattered UI string/visibility branches
- prepare the codebase for new permission types, new tool classes, and new transcript card types without re-bloating the main window file
- Completion criteria:
- `ChatWindow.xaml.cs` owns orchestration and runtime coordination more than direct UI element construction
- new message/permission/tool card types can be added via presentation catalogs or dedicated partials
- runtime summary and footer/status visibility derive from presentation models rather than ad-hoc branching
- Quality criteria:
- adding a new tool-result or approval type should mostly affect one catalog/renderer area
- future UI polish work should land in dedicated presentation files rather than expanding the main window file again
## Recommended Execution Order
- Updated: 2026-04-06 09:27 (KST)
1. Finish Track 2 consistency first whenever a UX issue is caused by runtime truth mismatch.
2. Apply Track 1 visual cleanup only after the state/message lifecycle is stable for that surface.
3. Fold each stable surface into Track 3 structure immediately so later changes do not reintroduce `ChatWindow.xaml.cs` sprawl.
4. Keep validating against `docs/AX_AGENT_REGRESSION_PROMPTS.md` after each change set, especially for `plan / permission / queue / compact / reopen`.
## Current Snapshot
- Updated: 2026-04-05 19:42 (KST)
- Estimated parity:
- Core engine: `89%`
- Main transcript UI: `96%`
- Cowork/Code runtime UX: `92%`
- Internal settings linkage: `88%`
- Overall AX Agent parity: `93%`
## Remaining Gaps
1. Prompt lifecycle parity
- `claw-code` reference: `src/utils/handlePromptSubmit.ts`, `src/utils/processUserInput/processTextPrompt.ts`
- AX gap:
- `send / retry / regenerate` are mostly unified, but `slash / compact 후 다음 턴 / 일부 queue 후처리`는 아직 `ChatWindow.xaml.cs`에서 UI 상태를 먼저 만지는 구간이 남아 있습니다.
- 목표는 모든 입력 진입점이 `AxAgentExecutionEngine`의 동일한 prepare/execute/finalize 축만 타게 만드는 것입니다.
2. Plan / approval rendering parity
- `claw-code` reference: `src/components/messages/PlanApprovalMessage.tsx`
- AX gap:
- 기본 transcript에서는 compact pill 위주로 줄였지만, 승인/계획 결과 표현이 아직 `Popup/Window + WPF 카드`와 섞여 있습니다.
## Quality Uplift Plan
- Updated: 2026-04-06 00:22 (KST)
- Goal: move AX Agent from parity-oriented stability into `claw-code`-grade maintainability and transcript quality, without copying implementation expression.
### Track 1. Transcript Renderer Decomposition
- `claw-code` references:
- `src/components/Messages.tsx`
- `src/components/MessageRow.tsx`
- `src/components/messages/AssistantToolUseMessage.tsx`
- `src/components/messages/PlanApprovalMessage.tsx`
- AX apply targets:
- `src/AxCopilot/Views/ChatWindow.xaml.cs`
- new partial/helper files under `src/AxCopilot/Views/`
- Completion criteria:
- `plan / permission / ask / tool-result / task-summary` rendering no longer lives as one large block inside `ChatWindow.xaml.cs`
- each transcript concern has a dedicated helper/partial/class boundary
- Quality criteria:
- render changes for one message type do not regress unrelated timeline behavior
- transcript behavior remains stable after reopen / retry / regenerate
### Track 2. Permission Presentation Catalog
- `claw-code` references:
- `src/components/permissions/PermissionRequest.tsx`
- `src/components/permissions/PermissionDialog.tsx`
- tool-specific permission request components under `src/components/permissions/*`
- AX apply targets:
- `src/AxCopilot/Services/Agent/PermissionModeCatalog.cs`
- new `src/AxCopilot/Services/Agent/PermissionRequestPresentationCatalog.cs`
- `src/AxCopilot/Views/ChatWindow.xaml.cs`
- Completion criteria:
- permission request title, subtitle, icon, severity, and choice set are resolved by tool/request type
- file edit / shell / skill / ask-user / web-like permission requests use distinct presentation metadata
- Quality criteria:
- permission prompts feel explicit and predictable
- user can distinguish request type without reading raw tool names or payload
### Track 3. Tool Result Message Taxonomy
- `claw-code` references:
- `src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx`
- `src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx`
- `src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx`
- `src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx`
- AX apply targets:
- new `src/AxCopilot/Services/Agent/ToolResultPresentationCatalog.cs`
- `src/AxCopilot/Views/ChatWindow.TranscriptPolicy.cs`
- `src/AxCopilot/Views/ChatWindow.xaml.cs`
- Completion criteria:
- transcript display rules differ for `success / error / reject / cancel`
- tool-result badges and summaries are resolved from presentation metadata instead of inline ad-hoc branches
- Quality criteria:
- result cards read as stable UX language, not raw execution logs
- failed and rejected tool runs are visually distinct without increasing noise
### Track 4. Plan Approval Transcript-Only Flow
- `claw-code` references:
- `src/components/messages/PlanApprovalMessage.tsx`
- `src/components/messages/UserPlanMessage.tsx`
- AX apply targets:
- `src/AxCopilot/Views/ChatWindow.xaml.cs`
- `src/AxCopilot/Views/PlanViewerWindow.cs`
- Completion criteria:
- default approval / reject / revise flow completes inline in transcript
- `PlanViewerWindow` is detail-only and never required for primary approval flow
- Quality criteria:
- planning feels like part of the conversation, not a modal interruption
- approval history is replayable from persisted conversation state
### Track 5. Runtime Summary Layer
- `claw-code` references:
- `src/components/StatusLine.tsx`
- `src/components/PromptInput/PromptInputFooter.tsx`
- `src/bootstrap/state.ts`
- AX apply targets:
- `src/AxCopilot/Services/AppStateService.cs`
- `src/AxCopilot/Views/ChatWindow.xaml.cs`
- Completion criteria:
- one runtime/status summary model feeds the status line, queue summary, runtime badge, and completion hint
- status rendering no longer depends on scattered imperative refresh branches
- Quality criteria:
- no contradictory or stale runtime badges
- long-running Cowork/Code sessions stay visually calm
### Track 6. Regression Prompt Ritual
- `claw-code` references:
- runtime validation scenarios implied by `sessionRunner`, `Messages`, `StatusLine`, and permission components
- AX apply targets:
- `docs/AX_AGENT_REGRESSION_PROMPTS.md`
- `docs/claw-code-parity-plan.md`
- developer workflow / release checklist
- Completion criteria:
- Chat / Cowork / Code prompt set is treated as mandatory regression for runtime-affecting changes
- each prompt is mapped to a failure class (`blank reply`, `duplicate banner`, `bad approval flow`, `queue drift`, `restore drift`)
- Quality criteria:
- parity claims are based on repeatable checks instead of visual spot-checks
- regressions are easier to catch before release
## Recommended Execution Order
1. Transcript renderer decomposition
2. Permission presentation catalog
3. Tool result taxonomy
4. Plan approval transcript-only flow
5. Runtime summary layer
6. Regression prompt ritual hardening
## Settings and Logic Review
- Updated: 2026-04-06 00:22 (KST)
- Candidate to move to developer-only:
- `FreeTierDelaySeconds`
- `MaxAgentIterations`
- `MaxRetryOnError`
- Keep as runtime-critical user settings:
- `OperationMode`
- `MaxContextTokens`
- `ContextCompactTriggerPercent`
- `EnableProactiveContextCompact`
- `EnableCoworkVerification`
- `EnableCodeVerification`
- code tool exposure toggles
- Rule:
- if a setting changes the main execution route or recovery semantics without representing a stable real-world user choice, move it out of default user-facing surfaces
- 목표는 “본문 우선 + 필요 시 열기” 기준으로 더 단일한 timeline 언어로 수렴시키는 것입니다.
3. Status line / composer parity
- `claw-code` reference: `src/components/StatusLine.tsx`, `src/components/PromptInput/PromptInput.tsx`
- AX gap:
- 하단 상태바와 composer 옵션은 많이 줄었지만, 상태 메타가 여전히 분산돼 있고 일부 토글/빠른 설정이 별도 행으로 남아 있습니다.
- 목표는 transcript 하단의 작업 바 한 축으로 더 압축하는 것입니다.
4. Runtime event density parity
- `claw-code` reference: `src/bridge/sessionRunner.ts`, `src/components/StatusNotices.tsx`
- AX gap:
- non-debug 기본 로그는 줄었지만, 일부 Cowork/Code 이벤트는 여전히 timeline을 자주 흔듭니다.
- 목표는 `permission / tool / error / complete / paused / resumed`를 더 안정된 event shape로 정규화하는 것입니다.
## Settings Review
- Remove candidate:
- `PlanMode`
- current state: 사용자 노출 UI와 저장 경로는 `off` 고정으로 정리됐지만 `AppSettings`, `SettingsViewModel`, `AppStateService` 타입 잔재가 남아 있음
- rationale: 현재 정책이 `off` 고정이라 사용자 선택값이 엔진에 의미 있게 기여하지 않음
- `Code.EnablePlanModeTools`
- current state: UI/저장 경로와 기본값은 `false` 고정으로 정리됐지만 모델/설정 타입에 호환용 잔재가 남아 있음
- rationale: 현재 엔진 정책에서 실제 실행 경로를 더 이상 바꾸지 않음
- Move to developer-only candidate:
- `FreeTierDelaySeconds`
- rationale: 일반 사용자가 조정할 이유가 적고 엔진 지연 정책에 직접 영향
- `MaxAgentIterations`
- `MaxRetryOnError`
- rationale: 핵심 실행 루프 품질에 직접 영향하는 런타임 튜닝값
- Keep as runtime-critical:
- `OperationMode`
- `MaxContextTokens`
- `ContextCompactTriggerPercent`
- `EnableProactiveContextCompact`
- `EnableCoworkVerification`
- `EnableCodeVerification`
- `Code.EnableWorktreeTools / EnableTeamTools / EnableCronTools`
## Known UX / Performance Risks
- Topic preset hover flicker was caused by duplicate hover systems:
- custom hover label
- default WPF `ToolTip`
- AX fix:
- remove default `ToolTip` from topic cards and keep a single hover label path
- Remaining runtime performance review targets:
- `RefreshContextUsageVisual()` frequency
- `BuildTopicButtons()` rebuild frequency
- `OnAgentEvent` timeline churn during long Cowork/Code runs
- compact queue summary still needs one more pass to fully match `claw-code` footer minimalism
## Progress Notes
- 업데이트: 2026-04-06 00:58 (KST)
- transcript renderer 분리 1차 완료
- AX 적용: [ChatWindow.InlineInteractions.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.InlineInteractions.cs), [ChatWindow.TaskSummary.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.TaskSummary.cs)
- 완료 조건: `plan / ask / task-summary` 렌더 helper가 메인 `ChatWindow.xaml.cs` 밖으로 이동
- permission / tool-result presentation catalog 도입
- AX 적용: [PermissionRequestPresentationCatalog.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/PermissionRequestPresentationCatalog.cs), [ToolResultPresentationCatalog.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/ToolResultPresentationCatalog.cs)
- 완료 조건: `AddAgentEventBanner(...)`가 권한/도구 결과 badge 메타를 inline switch가 아니라 catalog에서 해석
- runtime summary 전용 계층 1차 반영
- AX 적용: [AppStateService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/AppStateService.cs)
- 완료 조건: 상태선 UI가 `OperationalStatusPresentationState`를 소비해 strip/runtime badge visibility를 계산
+1 -1
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<TargetFramework>net8.0-windows10.0.17763.0</TargetFramework>
<UseWPF>true</UseWPF>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
@@ -0,0 +1,350 @@
using AxCopilot.Core;
using AxCopilot.Models;
using FluentAssertions;
using System.IO;
using Xunit;
namespace AxCopilot.Tests.Core;
public class ContextManagerTests
{
[Fact]
public void NormalizeWindowTitle_StripsKnownBrowserSuffix()
{
var normalized = ContextManager.NormalizeWindowTitle("Inbox - Google Chrome");
normalized.Should().Be("inbox");
}
[Fact]
public void CalculateTitleMatchScore_ExactTitle_BeatsPartialTitle()
{
var exact = ContextManager.CalculateTitleMatchScore("Inbox - Google Chrome", "Inbox - Google Chrome");
var partial = ContextManager.CalculateTitleMatchScore("Inbox - Google Chrome", "Inbox - Chrome");
exact.Should().BeGreaterThan(partial);
}
[Fact]
public void SelectBestMatchingWindow_PrefersExactTitleAmongSameExe()
{
var snapshot = new WindowSnapshot
{
Exe = @"C:\Program Files\Google\Chrome\Application\chrome.exe",
Title = "Inbox - Google Chrome"
};
var candidates = new[]
{
new ContextManager.WindowCandidate(new IntPtr(1), snapshot.Exe, "Docs - Google Chrome"),
new ContextManager.WindowCandidate(new IntPtr(2), snapshot.Exe, "Inbox - Google Chrome")
};
var selected = ContextManager.SelectBestMatchingWindow(snapshot, candidates);
selected.Should().Be(new IntPtr(2));
}
[Fact]
public void SelectBestMatchingWindow_SkipsAlreadyUsedHandle()
{
var snapshot = new WindowSnapshot
{
Exe = @"C:\Program Files\Google\Chrome\Application\chrome.exe",
Title = "Inbox - Google Chrome"
};
var candidates = new[]
{
new ContextManager.WindowCandidate(new IntPtr(1), snapshot.Exe, "Inbox - Google Chrome")
};
var selected = ContextManager.SelectBestMatchingWindow(snapshot, candidates, new HashSet<IntPtr> { new(1) });
selected.Should().Be(IntPtr.Zero);
}
[Fact]
public void BrowserLaunchPlan_CreatesChromiumWindowWithProfileAndTabs()
{
var state = new BrowserWindowState
{
Kind = "edge",
UserDataDir = @"C:\Users\tester\AppData\Local\Microsoft\Edge\User Data",
ProfileDirectory = "Profile 2",
TabUrls = ["https://example.com", "edge://settings/profiles"]
};
var plan = BrowserWorkspaceStateHelper.CreateLaunchPlan(
@"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
state);
plan.Should().NotBeNull();
plan!.Arguments.Should().ContainInOrder(
"--new-window",
"--user-data-dir=C:\\Users\\tester\\AppData\\Local\\Microsoft\\Edge\\User Data",
"--profile-directory=Profile 2",
"https://example.com",
"edge://settings/profiles");
}
[Fact]
public void BrowserLaunchPlan_CreatesFirefoxWindowWithTabs()
{
var state = new BrowserWindowState
{
Kind = "firefox",
ProfileDirectory = "work-profile",
TabUrls = ["https://www.mozilla.org", "about:newtab"]
};
var plan = BrowserWorkspaceStateHelper.CreateLaunchPlan(
@"C:\Program Files\Mozilla Firefox\firefox.exe",
state);
plan.Should().NotBeNull();
plan!.Arguments.Should().ContainInOrder(
"-P",
"work-profile",
"-new-window",
"https://www.mozilla.org",
"-new-tab",
"about:newtab");
}
[Fact]
public void ShouldLaunchNewWindow_WithBrowserStateAndPartialTitleMatch_ReturnsTrue()
{
var snapshot = new WindowSnapshot
{
Exe = @"C:\Program Files\Google\Chrome\Application\chrome.exe",
Title = "Inbox - Google Chrome",
Browser = new BrowserWindowState
{
Kind = "chrome",
TabUrls = ["https://mail.google.com"]
}
};
var candidate = new ContextManager.WindowCandidate(
new IntPtr(5),
snapshot.Exe,
"Docs - Google Chrome");
BrowserWorkspaceStateHelper.ShouldLaunchNewWindow(snapshot, candidate).Should().BeTrue();
}
[Fact]
public void ShouldLaunchNewWindow_WithBrowserStateAndExactTitleMatch_ReturnsFalse()
{
var snapshot = new WindowSnapshot
{
Exe = @"C:\Program Files\Google\Chrome\Application\chrome.exe",
Title = "Inbox - Google Chrome",
Browser = new BrowserWindowState
{
Kind = "chrome",
TabUrls = ["https://mail.google.com"]
}
};
var candidate = new ContextManager.WindowCandidate(
new IntPtr(5),
snapshot.Exe,
"Inbox - Google Chrome");
BrowserWorkspaceStateHelper.ShouldLaunchNewWindow(snapshot, candidate).Should().BeFalse();
}
[Fact]
public void AppLaunchPlan_CreatesExplorerWindowWithCapturedFolder()
{
using var folder1 = new TempDirectory();
using var folder2 = new TempDirectory();
var state = new AppWindowState
{
Kind = "explorer",
PrimaryPath = folder1.Path,
Paths = [folder1.Path, folder2.Path]
};
var plan = AppWorkspaceStateHelper.CreateLaunchPlan(
@"C:\Windows\explorer.exe",
state);
plan.Should().NotBeNull();
plan!.Arguments.Should().ContainSingle()
.Which.Should().Be(folder1.Path);
}
[Fact]
public void AppLaunchPlan_CreatesNotepadWindowWithCapturedFiles()
{
using var file1 = new TempFile(".txt");
using var file2 = new TempFile(".log");
var state = new AppWindowState
{
Kind = "notepad",
PrimaryPath = file1.Path,
Paths = [file1.Path, file2.Path]
};
var plan = AppWorkspaceStateHelper.CreateLaunchPlan(
@"C:\Windows\System32\notepad.exe",
state);
plan.Should().NotBeNull();
plan!.Arguments.Should().ContainInOrder(file1.Path, file2.Path);
}
[Fact]
public void AppLaunchPlan_UsesSystemExecutableFallbackForPackagedNotepad()
{
using var file1 = new TempFile(".txt");
var state = new AppWindowState
{
Kind = "notepad",
PrimaryPath = file1.Path,
Paths = [file1.Path]
};
var plan = AppWorkspaceStateHelper.CreateLaunchPlan(
@"C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2401.32.0_x64__8wekyb3d8bbwe\Notepad.exe",
state);
plan.Should().NotBeNull();
plan!.FileName.Should().Be("notepad.exe");
}
[Fact]
public void AppShouldLaunchNewWindow_WithCapturedStateAndDifferentTitle_ReturnsTrue()
{
using var folder = new TempDirectory();
var snapshot = new WindowSnapshot
{
Exe = @"C:\Windows\explorer.exe",
Title = "문서 - 파일 탐색기",
AppState = new AppWindowState
{
Kind = "explorer",
PrimaryPath = folder.Path,
Paths = [folder.Path]
}
};
var candidate = new ContextManager.WindowCandidate(
new IntPtr(7),
snapshot.Exe,
"다운로드 - 파일 탐색기");
AppWorkspaceStateHelper.ShouldLaunchNewWindow(snapshot, candidate).Should().BeTrue();
}
[Fact]
public void AppShouldLaunchNewWindow_WithCapturedStateAndExactTitle_ReturnsFalse()
{
var snapshot = new WindowSnapshot
{
Exe = @"C:\Windows\System32\notepad.exe",
Title = "todo.txt - 메모장",
AppState = new AppWindowState
{
Kind = "notepad",
PrimaryPath = @"C:\Temp\todo.txt",
Paths = [@"C:\Temp\todo.txt"]
}
};
var candidate = new ContextManager.WindowCandidate(
new IntPtr(8),
snapshot.Exe,
"todo.txt - 메모장");
AppWorkspaceStateHelper.ShouldLaunchNewWindow(snapshot, candidate).Should().BeFalse();
}
[Fact]
public void CalculateRestoreLaunchDelayMs_Disabled_ReturnsZero()
{
var settings = new LauncherSettings
{
EnableAdaptiveWorkspaceRestoreThrottle = false,
WorkspaceRestoreBaseDelayMs = 250,
WorkspaceRestoreMaxDelayMs = 1200
};
var delay = ContextManager.CalculateRestoreLaunchDelayMs(settings, 85, 92, 3);
delay.Should().Be(0);
}
[Fact]
public void CalculateRestoreLaunchDelayMs_HighLoadIncreasesDelay()
{
var settings = new LauncherSettings
{
EnableAdaptiveWorkspaceRestoreThrottle = true,
WorkspaceRestoreBaseDelayMs = 250,
WorkspaceRestoreMaxDelayMs = 1200
};
var lowLoadDelay = ContextManager.CalculateRestoreLaunchDelayMs(settings, 20, 45, 1);
var highLoadDelay = ContextManager.CalculateRestoreLaunchDelayMs(settings, 88, 91, 4);
lowLoadDelay.Should().Be(250);
highLoadDelay.Should().BeGreaterThan(lowLoadDelay);
highLoadDelay.Should().BeLessOrEqualTo(1200);
}
private sealed class TempFile : IDisposable
{
public TempFile(string extension)
{
Path = System.IO.Path.ChangeExtension(System.IO.Path.GetTempFileName(), extension);
File.WriteAllText(Path, "temp");
}
public string Path { get; }
public void Dispose()
{
try
{
if (File.Exists(Path))
File.Delete(Path);
}
catch
{
// 테스트 정리 실패는 무시합니다.
}
}
}
private sealed class TempDirectory : IDisposable
{
public TempDirectory()
{
Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"axcopilot-test-{Guid.NewGuid():N}");
Directory.CreateDirectory(Path);
}
public string Path { get; }
public void Dispose()
{
try
{
if (Directory.Exists(Path))
Directory.Delete(Path, true);
}
catch
{
// 테스트 정리 실패는 무시합니다.
}
}
}
}
@@ -0,0 +1,64 @@
using AxCopilot.Core;
using AxCopilot.Handlers;
using AxCopilot.Models;
using AxCopilot.Services;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Handlers;
public class WorkspaceHandlerTests
{
[Fact]
public async Task GetItemsAsync_RestoreSubcommand_ReturnsRestoreAction()
{
var settings = new SettingsService();
settings.Settings.Profiles.Add(new WorkspaceProfile
{
Name = "업무",
Windows = new List<WindowSnapshot> { new() { Exe = "chrome.exe", Title = "메일" } },
CreatedAt = new DateTime(2026, 4, 15, 9, 0, 0)
});
var handler = new WorkspaceHandler(new ContextManager(settings), settings);
var items = (await handler.GetItemsAsync("restore 업무", CancellationToken.None)).ToList();
items.Should().ContainSingle();
items[0].Title.Should().Contain("업무");
items[0].Data.Should().BeOfType<WorkspaceAction>();
var action = (WorkspaceAction)items[0].Data!;
action.Type.Should().Be(WorkspaceActionType.Restore);
action.Name.Should().Be("업무");
}
[Fact]
public async Task GetItemsAsync_ListSubcommand_ReturnsSavedProfiles()
{
var settings = new SettingsService();
settings.Settings.Profiles.Add(new WorkspaceProfile
{
Name = "업무",
Windows = new List<WindowSnapshot> { new() { Exe = "chrome.exe", Title = "메일" } },
CreatedAt = new DateTime(2026, 4, 15, 9, 0, 0)
});
settings.Settings.Profiles.Add(new WorkspaceProfile
{
Name = "개발",
Windows = new List<WindowSnapshot> { new() { Exe = "code.exe", Title = "AX Copilot" } },
CreatedAt = new DateTime(2026, 4, 15, 10, 0, 0)
});
var handler = new WorkspaceHandler(new ContextManager(settings), settings);
var items = (await handler.GetItemsAsync("list", CancellationToken.None)).ToList();
items.Should().HaveCount(2);
items[0].Title.Should().Be("~개발");
items[1].Title.Should().Be("~업무");
items.All(item => item.Data is WorkspaceAction action && action.Type == WorkspaceActionType.Restore)
.Should()
.BeTrue();
}
}
@@ -0,0 +1,90 @@
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentCommandQueueTests
{
[Fact]
public void DrainAll_ShouldRespectPriorityThenSequence()
{
var queue = new AgentCommandQueue();
queue.EnqueuePrompt("later", "later");
queue.EnqueuePrompt("next", "next");
queue.EnqueuePrompt("now", "now", requestInterrupt: true);
var drained = queue.DrainAll();
drained.Select(x => x.Content).Should().Equal("now", "next", "later");
drained[0].RequestInterrupt.Should().BeTrue();
}
[Fact]
public void Clear_ShouldRemoveQueuedItems()
{
var queue = new AgentCommandQueue();
queue.EnqueuePrompt("first");
queue.EnqueueNotification("note");
queue.Clear();
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();
}
[Fact]
public void DequeuePriorityBatch_ShouldLeaveLowerPriorityItemsQueued()
{
var queue = new AgentCommandQueue();
queue.EnqueueNotification("later-note");
queue.EnqueuePrompt("next-prompt");
queue.EnqueueSteering("now-steer");
var firstBatch = queue.DequeuePriorityBatch();
var secondBatch = queue.DequeuePriorityBatch();
var thirdBatch = queue.DequeuePriorityBatch();
firstBatch.Select(x => x.Content).Should().Equal("now-steer");
secondBatch.Select(x => x.Content).Should().Equal("next-prompt");
thirdBatch.Select(x => x.Content).Should().Equal("later-note");
}
[Fact]
public void PeekAndDequeueAllMatching_ShouldHonorPredicate()
{
var queue = new AgentCommandQueue();
queue.EnqueueNotification("later-note");
queue.EnqueuePrompt("next-prompt");
queue.EnqueueSteering("now-steer");
var peeked = queue.Peek(x => x.Kind == AgentCommandKind.Notification);
var removed = queue.DequeueAllMatching(x => x.Kind == AgentCommandKind.Notification);
var remaining = queue.DrainAll();
peeked.Should().NotBeNull();
peeked!.Content.Should().Be("later-note");
removed.Select(x => x.Content).Should().Equal("later-note");
remaining.Select(x => x.Content).Should().Equal("now-steer", "next-prompt");
}
}
@@ -63,10 +63,10 @@ public class AgentLoopCodeQualityTests
"bugfix");
prompt.Should().Contain("baseline build/test");
prompt.Should().Contain("grep/glob");
prompt.Should().Contain("grep 또는 glob");
prompt.Should().Contain("build_run");
prompt.Should().Contain("테스트 부재 사실");
prompt.Should().Contain("작업 유형: bugfix");
prompt.Should().Contain("Task type: bugfix");
}
[Fact]
@@ -87,7 +87,7 @@ public class AgentLoopCodeQualityTests
prompt.Should().Contain("grep 또는 glob");
prompt.Should().Contain("테스트 부재 사실");
prompt.Should().Contain("영향 범위가 넓을 가능성");
prompt.Should().Contain("작업 유형: refactor");
prompt.Should().Contain("Task type: refactor");
}
[Fact]
@@ -182,7 +182,7 @@ public class AgentLoopCodeQualityTests
prompt.Should().Contain("spawn_agent");
prompt.Should().Contain("build/test");
prompt.Should().Contain("테스트 부재 사실");
prompt.Should().Contain("재현 조건");
prompt.Should().Contain("symptom is no longer reproducible");
}
[Fact]
@@ -202,8 +202,27 @@ public class AgentLoopCodeQualityTests
false,
"refactor");
featurePrompt.Should().Contain("새 기능 경로");
refactorPrompt.Should().Contain("동작 보존");
featurePrompt.Should().Contain("feature path and caller linkage");
refactorPrompt.Should().Contain("behavior-compatible");
}
[Fact]
public void BuildFailureInvestigationPrompt_PrefersMultiReadWhenBuildOutputMentionsMultipleFiles()
{
var prompt = InvokePrivateStatic<string>(
"BuildFailureInvestigationPrompt",
"build_run",
@"E:\code\MainWindow.xaml.cs",
false,
TaskTypePolicy.FromTaskType("feature"),
"""
E:\code\Themes\ControlStyles.xaml(14,17): error MC4005
E:\code\Themes\Effects.xaml(166,50): error MC3072
""");
prompt.Should().Contain("multi_read");
prompt.Should().Contain(@"Themes\ControlStyles.xaml");
prompt.Should().Contain(@"Themes\Effects.xaml");
}
[Fact]
@@ -219,10 +238,51 @@ public class AgentLoopCodeQualityTests
"bugfix");
message.Should().Contain("Fallback sequence");
message.Should().Contain("file_read -> grep/glob -> git_tool(diff)");
message.Should().Contain("git_tool(diff)");
message.Should().Contain("repro/root-cause");
}
[Fact]
public void BuildFailureReflectionMessage_UsesFileReviewFallbackWhenWorkspaceIsNotGitRepository()
{
var prompt = InvokePrivateStatic<string>(
"BuildFailureReflectionMessage",
"git_tool",
ToolResult.Fail("현재 작업 폴더는 Git 저장소가 아닙니다."),
1,
3,
"review");
prompt.Should().Contain("저장소 컨텍스트");
prompt.Should().Contain("code_review(file_review)");
prompt.Should().NotContain("git_tool(diff) -> targeted tool retry");
}
[Fact]
public void BuildProjectLayoutGatePrompt_CallsForFolderReorganization()
{
var profile = ProjectScaffoldProfileCatalog.Detect(
"Create a C# WPF MVVM desktop app with ResourceDictionary themes",
"Code")!;
var assessment = new ProjectScaffoldLayoutAssessment(
IsSatisfied: false,
MatchedDirectoryCount: 0,
ExistingDirectories: [],
MissingDirectories: ["Views", "ViewModels", "Themes"],
SuspiciousRootFiles: ["MainWindow.xaml", "MainWindowViewModel.cs"]);
var prompt = InvokePrivateStatic<string>(
"BuildProjectLayoutGatePrompt",
profile,
assessment);
prompt.Should().Contain("[System:ProjectLayoutGate]");
prompt.Should().Contain("Views");
prompt.Should().Contain("ViewModels");
prompt.Should().Contain("MainWindow.xaml");
prompt.Should().Contain("file_manage(mkdir/move)");
}
[Fact]
public void BuildFailureNextToolPriorityPrompt_IncludesOrderedPriority()
{
@@ -239,6 +299,33 @@ public class AgentLoopCodeQualityTests
prompt.Should().Contain("고영향 변경");
}
[Theory]
[InlineData("bugfix", true)]
[InlineData("feature", true)]
[InlineData("refactor", true)]
[InlineData("review", true)]
[InlineData("docs", false)]
public void ShouldApplyExecutionResultGate_MatchesCodeExecutionTasks(string taskType, bool expected)
{
var result = InvokePrivateStatic<bool>(
"ShouldApplyExecutionResultGate",
TaskTypePolicy.FromTaskType(taskType));
result.Should().Be(expected);
}
[Theory]
[InlineData("balanced")]
[InlineData("reasoning_first")]
[InlineData("tool_call_strict")]
public void CodeFocusedExecutionProfiles_EnableExecutionRecoveryGates(string profileKey)
{
var policy = ModelExecutionProfileCatalog.Get(profileKey);
policy.RecentExecutionGateMaxRetries.Should().BeGreaterThan(0);
policy.ExecutionSuccessGateMaxRetries.Should().BeGreaterThan(0);
}
[Fact]
public void ComputeAdaptiveMaxRetry_AdjustsByTaskType()
{
@@ -370,7 +457,7 @@ public class AgentLoopCodeQualityTests
prompt.Should().Contain("무엇을 변경했는지");
prompt.Should().Contain("build/test/검증 근거");
prompt.Should().Contain("원인, 수정 내용, 재현/회귀 검증 근거");
prompt.Should().Contain("bug fix");
prompt.Should().Contain("남은 리스크");
}
@@ -394,7 +481,7 @@ public class AgentLoopCodeQualityTests
"bugfix");
guidance.Should().Contain("[System:FailurePatterns]");
guidance.Should().Contain("재현 조건과 원인 연결");
guidance.Should().Contain("reproduction");
guidance.Should().Contain("CS1002");
guidance.Should().Contain("NRE");
}
@@ -603,7 +690,7 @@ public class AgentLoopCodeQualityTests
public void BuildToolCallSignature_IncludesToolAndCanonicalInput()
{
var input = JsonDocument.Parse("""{"path":"src/A.cs","line":10}""").RootElement.Clone();
var call = new LlmService.ContentBlock
var call = new ContentBlock
{
Type = "tool_use",
ToolName = "file_edit",
@@ -641,16 +728,17 @@ public class AgentLoopCodeQualityTests
[Fact]
public void CreateParallelExecutionPlan_DisabledFlagKeepsSequentialOnly()
{
var calls = new List<LlmService.ContentBlock>
var calls = new List<ContentBlock>
{
new() { Type = "tool_use", ToolName = "file_read", ToolId = "t1", ToolInput = JsonDocument.Parse("""{"path":"a.txt"}""").RootElement.Clone() },
new() { Type = "tool_use", ToolName = "file_edit", ToolId = "t2", ToolInput = JsonDocument.Parse("""{"path":"a.txt","old":"a","new":"b"}""").RootElement.Clone() }
};
var plan = InvokePrivateStatic<(bool ShouldRun, List<LlmService.ContentBlock> ParallelBatch, List<LlmService.ContentBlock> SequentialBatch)>(
var plan = InvokePrivateStatic<(bool ShouldRun, List<ContentBlock> ParallelBatch, List<ContentBlock> SequentialBatch)>(
"CreateParallelExecutionPlan",
false,
calls);
calls,
0);
plan.ShouldRun.Should().BeFalse();
plan.ParallelBatch.Should().BeEmpty();
@@ -660,7 +748,7 @@ public class AgentLoopCodeQualityTests
[Fact]
public void CreateParallelExecutionPlan_UsesOnlyReadOnlyPrefixForParallelBatch()
{
var calls = new List<LlmService.ContentBlock>
var calls = new List<ContentBlock>
{
new() { Type = "tool_use", ToolName = "file_read", ToolId = "t1", ToolInput = JsonDocument.Parse("""{"path":"a.txt"}""").RootElement.Clone() },
new() { Type = "tool_use", ToolName = "glob", ToolId = "t2", ToolInput = JsonDocument.Parse("""{"pattern":"*.cs"}""").RootElement.Clone() },
@@ -668,10 +756,11 @@ public class AgentLoopCodeQualityTests
new() { Type = "tool_use", ToolName = "file_read", ToolId = "t4", ToolInput = JsonDocument.Parse("""{"path":"b.txt"}""").RootElement.Clone() }
};
var plan = InvokePrivateStatic<(bool ShouldRun, List<LlmService.ContentBlock> ParallelBatch, List<LlmService.ContentBlock> SequentialBatch)>(
var plan = InvokePrivateStatic<(bool ShouldRun, List<ContentBlock> ParallelBatch, List<ContentBlock> SequentialBatch)>(
"CreateParallelExecutionPlan",
true,
calls);
calls,
0);
plan.ShouldRun.Should().BeTrue();
plan.ParallelBatch.Select(x => x.ToolId).Should().Equal("t1", "t2");
@@ -681,17 +770,18 @@ public class AgentLoopCodeQualityTests
[Fact]
public void CreateParallelExecutionPlan_RecognizesAliasReadOnlyToolInPrefix()
{
var calls = new List<LlmService.ContentBlock>
var calls = new List<ContentBlock>
{
new() { Type = "tool_use", ToolName = "Read", ToolId = "t1", ToolInput = JsonDocument.Parse("""{"path":"a.txt"}""").RootElement.Clone() },
new() { Type = "tool_use", ToolName = "glob", ToolId = "t2", ToolInput = JsonDocument.Parse("""{"pattern":"*.cs"}""").RootElement.Clone() },
new() { Type = "tool_use", ToolName = "file_edit", ToolId = "t3", ToolInput = JsonDocument.Parse("""{"path":"a.txt","old":"a","new":"b"}""").RootElement.Clone() }
};
var plan = InvokePrivateStatic<(bool ShouldRun, List<LlmService.ContentBlock> ParallelBatch, List<LlmService.ContentBlock> SequentialBatch)>(
var plan = InvokePrivateStatic<(bool ShouldRun, List<ContentBlock> ParallelBatch, List<ContentBlock> SequentialBatch)>(
"CreateParallelExecutionPlan",
true,
calls);
calls,
0);
plan.ShouldRun.Should().BeTrue();
plan.ParallelBatch.Select(x => x.ToolId).Should().Equal("t1", "t2");
@@ -778,6 +868,38 @@ public class AgentLoopCodeQualityTests
blocked.Should().BeFalse();
}
[Fact]
public void ShouldBlockRepeatedNoProgressToolLoop_BlocksRepeatedExecutionTools()
{
var blocked = InvokePrivateStatic<bool>(
"ShouldBlockRepeatedNoProgressToolLoop",
"build_run",
6);
var notYet = InvokePrivateStatic<bool>(
"ShouldBlockRepeatedNoProgressToolLoop",
"build_run",
5);
blocked.Should().BeTrue();
notYet.Should().BeFalse();
}
[Fact]
public void ShouldBlockRepeatedNoProgressToolLoop_GivesPollingToolsMoreRoom()
{
var notYet = InvokePrivateStatic<bool>(
"ShouldBlockRepeatedNoProgressToolLoop",
"wait_agents",
6);
var blocked = InvokePrivateStatic<bool>(
"ShouldBlockRepeatedNoProgressToolLoop",
"wait_agents",
7);
notYet.Should().BeFalse();
blocked.Should().BeTrue();
}
[Fact]
public void ShouldRequestDocumentArtifact_RequiresDocsTaskAndMissingArtifact()
{
@@ -878,7 +1000,7 @@ public class AgentLoopCodeQualityTests
response,
"docs",
false,
withoutVerification).Should().BeFalse();
withoutVerification).Should().BeTrue();
InvokePrivateStatic<bool>(
"HasSufficientFinalReportEvidence",
@@ -1168,65 +1290,33 @@ public class AgentLoopCodeQualityTests
[Fact]
public void ResolveNoToolCallResponseThreshold_UsesDefaultAndClamps()
{
InvokePrivateStatic<int>(
"ResolveNoToolCallResponseThreshold",
(string?)null).Should().Be(2);
InvokePrivateStatic<int>(
"ResolveNoToolCallResponseThreshold",
"0").Should().Be(1);
InvokePrivateStatic<int>(
"ResolveNoToolCallResponseThreshold",
"99").Should().Be(6);
AgentLoopRuntimeThresholds.ResolveNoToolCallResponseThreshold(null).Should().Be(2);
AgentLoopRuntimeThresholds.ResolveNoToolCallResponseThreshold("0").Should().Be(1);
AgentLoopRuntimeThresholds.ResolveNoToolCallResponseThreshold("99").Should().Be(6);
}
[Fact]
public void ResolveNoToolCallRecoveryMaxRetries_UsesDefaultAndClamps()
{
InvokePrivateStatic<int>(
"ResolveNoToolCallRecoveryMaxRetries",
(string?)null).Should().Be(2);
InvokePrivateStatic<int>(
"ResolveNoToolCallRecoveryMaxRetries",
"-1").Should().Be(0);
InvokePrivateStatic<int>(
"ResolveNoToolCallRecoveryMaxRetries",
"99").Should().Be(6);
AgentLoopRuntimeThresholds.ResolveNoToolCallRecoveryMaxRetries(null).Should().Be(3);
AgentLoopRuntimeThresholds.ResolveNoToolCallRecoveryMaxRetries("-1").Should().Be(0);
AgentLoopRuntimeThresholds.ResolveNoToolCallRecoveryMaxRetries("99").Should().Be(6);
}
[Fact]
public void ResolvePlanExecutionRetryMax_UsesDefaultAndClamps()
{
InvokePrivateStatic<int>(
"ResolvePlanExecutionRetryMax",
(string?)null).Should().Be(2);
InvokePrivateStatic<int>(
"ResolvePlanExecutionRetryMax",
"-5").Should().Be(0);
InvokePrivateStatic<int>(
"ResolvePlanExecutionRetryMax",
"10").Should().Be(6);
AgentLoopRuntimeThresholds.ResolvePlanExecutionRetryMax(null).Should().Be(2);
AgentLoopRuntimeThresholds.ResolvePlanExecutionRetryMax("-5").Should().Be(0);
AgentLoopRuntimeThresholds.ResolvePlanExecutionRetryMax("10").Should().Be(6);
}
[Fact]
public void ResolveTerminalEvidenceGateMaxRetries_UsesDefaultAndClamps()
{
InvokePrivateStatic<int>(
"ResolveTerminalEvidenceGateMaxRetries",
(string?)null).Should().Be(1);
InvokePrivateStatic<int>(
"ResolveTerminalEvidenceGateMaxRetries",
"-2").Should().Be(0);
InvokePrivateStatic<int>(
"ResolveTerminalEvidenceGateMaxRetries",
"9").Should().Be(3);
AgentLoopRuntimeThresholds.ResolveTerminalEvidenceGateMaxRetries(null).Should().Be(1);
AgentLoopRuntimeThresholds.ResolveTerminalEvidenceGateMaxRetries("-2").Should().Be(0);
AgentLoopRuntimeThresholds.ResolveTerminalEvidenceGateMaxRetries("9").Should().Be(3);
}
[Fact]
@@ -0,0 +1,47 @@
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentLoopDiagnosticsFormatterTests
{
[Fact]
public void BuildCompactionCompleteMessage_ShouldIncludeStageSummaryAndSavedTokens()
{
var result = new ContextCompactionResult
{
BeforeTokens = 18_400,
AfterTokens = 7_900,
};
result.AppliedStages.Add("tool-result");
result.AppliedStages.Add("session-memory");
var message = AgentLoopDiagnosticsFormatter.BuildCompactionCompleteMessage(result);
message.Should().Be("Context compaction complete: tool-result -> session-memory, saved 10.3K tokens");
}
[Fact]
public void BuildQueryViewSummary_ShouldIncludeWindowAndPreviewReuseMetrics()
{
var result = new AgentQueryContextWindowResult
{
Messages = new(),
SourceMessageCount = 34,
ViewMessageCount = 12,
WindowStartIndex = 21,
BoundaryApplied = true,
ToolPairExpanded = true,
PreservedToolPairCount = 2,
TruncatedToolResultCount = 3,
ReusedToolResultPreviewCount = 4,
TokensBeforeBudget = 8_600,
TokensAfterBudget = 6_100,
};
var summary = AgentLoopDiagnosticsFormatter.BuildQueryViewSummary(result);
summary.Should().Be("query-view 34->12, start=21, pairs=2, tool_result_budget=3, tool_result_preview_reuse=4, tokens 8600->6100");
}
}
+306 -21
View File
@@ -26,7 +26,7 @@ public class AgentLoopE2ETests
var settings = BuildLoopSettings(server.Endpoint);
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Chat" };
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Cowork" };
var events = new List<AgentEvent>();
loop.EventOccurred += evt => events.Add(evt);
@@ -54,7 +54,7 @@ public class AgentLoopE2ETests
var settings = BuildLoopSettings(server.Endpoint);
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Chat" };
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Cowork" };
var events = new List<AgentEvent>();
loop.EventOccurred += evt => events.Add(evt);
@@ -74,17 +74,14 @@ public class AgentLoopE2ETests
{
using var server = new FakeOllamaServer(
[
BuildTextOnlyResponse("1. math_eval 도구로 계산\n2. 결과를 검증하고 보고"),
BuildToolCallResponse("math_eval", new { expression = "10/2" }, "계획 실행"),
BuildToolCallResponse("math_eval", new { expression = "10/2" }, "계산 실행"),
BuildTextResponse("완료: 결과는 5"),
]);
var settings = BuildLoopSettings(server.Endpoint);
settings.Settings.Llm.PlanMode = "always";
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Chat" };
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Cowork" };
var events = new List<AgentEvent>();
loop.EventOccurred += evt => events.Add(evt);
@@ -95,7 +92,7 @@ public class AgentLoopE2ETests
]);
result.Should().Contain("5");
server.RequestCount.Should().BeGreaterThanOrEqualTo(3);
server.RequestCount.Should().BeGreaterThanOrEqualTo(2);
events.Should().Contain(e => e.Type == AgentEventType.ToolCall && e.ToolName == "math_eval");
events.Should().Contain(e => e.Type == AgentEventType.Complete);
}
@@ -110,11 +107,12 @@ public class AgentLoopE2ETests
]);
var settings = BuildLoopSettings(server.Endpoint);
settings.Settings.Llm.DefaultAgentPermission = "Ask";
settings.Settings.Llm.DefaultAgentPermission = "Default";
settings.Settings.Llm.FilePermission = "Default";
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Chat" };
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Cowork" };
loop.AskPermissionCallback = (_, _) => Task.FromResult(false);
var events = new List<AgentEvent>();
@@ -169,7 +167,7 @@ public class AgentLoopE2ETests
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Chat" };
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Cowork" };
var events = new List<AgentEvent>();
loop.EventOccurred += evt => events.Add(evt);
@@ -357,8 +355,8 @@ public class AgentLoopE2ETests
{
using var server = new FakeOllamaServer(
[
BuildToolCallResponse("EnterPlanMode", new { }, "plan alias"),
BuildTextResponse("?꾨즺"),
BuildToolCallResponse("MathEval", new { expression = "1+1" }, "alias resolution"),
BuildTextResponse("완료"),
]);
var settings = BuildLoopSettings(server.Endpoint);
@@ -372,12 +370,12 @@ public class AgentLoopE2ETests
var result = await loop.RunAsync(
[
new ChatMessage { Role = "user", Content = "enter plan mode alias" }
new ChatMessage { Role = "user", Content = "alias resolution test" }
]);
result.Should().Contain("?꾨즺");
events.Should().Contain(e => e.Type == AgentEventType.ToolCall && e.ToolName == "enter_plan_mode");
events.Should().Contain(e => e.Type == AgentEventType.ToolResult && e.ToolName == "enter_plan_mode" && e.Success);
result.Should().Contain("완료");
events.Should().Contain(e => e.Type == AgentEventType.ToolCall && e.ToolName == "math_eval");
events.Should().Contain(e => e.Type == AgentEventType.ToolResult && e.ToolName == "math_eval" && e.Success);
}
finally
{
@@ -453,7 +451,6 @@ public class AgentLoopE2ETests
var settings = BuildLoopSettings(server.Endpoint);
settings.Settings.Llm.WorkFolder = tempDir;
settings.Settings.Llm.Code.EnablePlanModeTools = false;
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Code" };
@@ -487,7 +484,8 @@ public class AgentLoopE2ETests
]);
var settings = BuildLoopSettings(server.Endpoint);
settings.Settings.Llm.DefaultAgentPermission = "Ask";
settings.Settings.Llm.DefaultAgentPermission = "Default";
settings.Settings.Llm.FilePermission = "Default";
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
@@ -502,13 +500,288 @@ public class AgentLoopE2ETests
new ChatMessage { Role = "user", Content = "장애가 있어도 복구해서 끝내줘" }
]);
result.Should().Contain("최대 반복");
result.Should().NotBeNullOrWhiteSpace();
events.Should().Contain(e => e.Type == AgentEventType.Error && e.ToolName == "UnknownTool");
events.Should().Contain(e => e.Type == AgentEventType.ToolCall && e.ToolName == "file_write");
events.Should().Contain(e => e.Type == AgentEventType.ToolCall && e.ToolName == "math_eval");
events.Should().Contain(e => e.Type == AgentEventType.ToolResult && e.ToolName == "math_eval" && e.Success);
}
[Fact]
public async Task RunAsync_EmptyWorkspace_BlocksExternalFallbackAndRecoversToFileWrite()
{
var tempDir = Path.Combine(Path.GetTempPath(), "axcopilot-empty-workspace-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tempDir);
try
{
using var server = new FakeOllamaServer(
[
BuildToolCallResponse("folder_map", new { path = ".", depth = 2, include_files = true }, "empty workspace check"),
BuildToolCallResponse("grep", new { pattern = "\\.html$", path = @"C:\\", files_only = true }, "bad external fallback"),
BuildToolCallResponse("file_write", new { path = "index.html", content = "<html><body>clock</body></html>" }, "create file directly"),
BuildTextResponse("완료"),
]);
var settings = BuildLoopSettings(server.Endpoint);
settings.Settings.Llm.WorkFolder = tempDir;
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Code" };
var events = new List<AgentEvent>();
loop.EventOccurred += evt => events.Add(evt);
var result = await loop.RunAsync(
[
new ChatMessage { Role = "user", Content = "실시간으로 시간을 표시하는 웹페이지 만들어줘" }
]);
result.Should().Contain("완료");
File.Exists(Path.Combine(tempDir, "index.html")).Should().BeTrue();
events.Should().Contain(e =>
e.Type == AgentEventType.Error
&& (e.ToolName == "grep" || e.ToolName == "folder_map")
&& e.Summary.Contains("Empty workspace guard blocked", StringComparison.OrdinalIgnoreCase));
events.Should().Contain(e => e.Type == AgentEventType.ToolCall && e.ToolName == "file_write");
events.Should().NotContain(e => e.Type == AgentEventType.PermissionRequest && e.ToolName == "grep");
}
finally
{
try { if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); } catch { }
}
}
[Fact]
public async Task RunAsync_EmptyWorkspace_DisallowsSkillManagerAndRecoversToFileWrite()
{
var tempDir = Path.Combine(Path.GetTempPath(), "axcopilot-empty-workspace-skill-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tempDir);
try
{
using var server = new FakeOllamaServer(
[
BuildToolCallResponse("folder_map", new { path = ".", depth = 2, include_files = true }, "empty workspace check"),
BuildToolCallResponse("skill_manager", new { action = "list" }, "irrelevant meta tool"),
BuildToolCallResponse("file_write", new { path = "index.html", content = "<html><body>ok</body></html>" }, "create file"),
BuildTextResponse("완료"),
]);
var settings = BuildLoopSettings(server.Endpoint);
settings.Settings.Llm.WorkFolder = tempDir;
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Code" };
var events = new List<AgentEvent>();
loop.EventOccurred += evt => events.Add(evt);
var result = await loop.RunAsync(
[
new ChatMessage { Role = "user", Content = "빈 폴더에 index.html 만들어줘" }
]);
result.Should().Contain("완료");
File.Exists(Path.Combine(tempDir, "index.html")).Should().BeTrue();
events.Should().Contain(e => e.Type == AgentEventType.Error && e.ToolName == "skill_manager");
events.Should().Contain(e => e.Type == AgentEventType.ToolCall && e.ToolName == "file_write");
}
finally
{
try { if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); } catch { }
}
}
[Fact]
public async Task RunAsync_TextEmbeddedToolCall_RecoversAndExecutesFileWrite()
{
var tempDir = Path.Combine(Path.GetTempPath(), "axcopilot-text-toolcall-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tempDir);
try
{
using var server = new FakeOllamaServer(
[
BuildRawResponse("""
{
"message": {
"content": "<tool_call>{\"name\":\"file_write\",\"arguments\":{\"path\":\"index.html\",\"content\":\"<html><body>clock</body></html>\"}}</tool_call>\n파일을 작성합니다."
}
}
"""),
BuildTextResponse("완료"),
]);
var settings = BuildLoopSettings(server.Endpoint);
settings.Settings.Llm.WorkFolder = tempDir;
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings) { ActiveTab = "Code" };
var events = new List<AgentEvent>();
loop.EventOccurred += evt => events.Add(evt);
var result = await loop.RunAsync(
[
new ChatMessage { Role = "user", Content = "index.html 파일 만들어줘" }
]);
result.Should().Contain("완료");
File.Exists(Path.Combine(tempDir, "index.html")).Should().BeTrue();
events.Should().Contain(e => e.Type == AgentEventType.ToolCall && e.ToolName == "file_write");
}
finally
{
try { if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); } catch { }
}
}
[Fact]
public async Task RunAsync_CodeRuntimeWorkspaceOverride_PrefersConversationWorkspaceOverSettingsFolder()
{
var settingsDir = Path.Combine(Path.GetTempPath(), "axcopilot-settings-workspace-" + Guid.NewGuid().ToString("N"));
var conversationDir = Path.Combine(Path.GetTempPath(), "axcopilot-conversation-workspace-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(settingsDir);
Directory.CreateDirectory(conversationDir);
try
{
using var server = new FakeOllamaServer(
[
BuildToolCallResponse("file_write", new { path = "index.html", content = "<html><body>override</body></html>" }, "write to conversation workspace"),
BuildTextResponse("?꾨즺"),
]);
var settings = BuildLoopSettings(server.Endpoint);
settings.Settings.Llm.WorkFolder = settingsDir;
settings.Settings.Llm.CodeWorkFolder = settingsDir;
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings)
{
ActiveTab = "Code",
RuntimeWorkFolderOverride = conversationDir,
};
var result = await loop.RunAsync(
[
new ChatMessage { Role = "user", Content = "index.html ?뚯씪 留뚮뱾?댁쨾" }
]);
result.Should().Contain("?꾨즺");
File.Exists(Path.Combine(conversationDir, "index.html")).Should().BeTrue();
File.Exists(Path.Combine(settingsDir, "index.html")).Should().BeFalse();
}
finally
{
try { if (Directory.Exists(settingsDir)) Directory.Delete(settingsDir, true); } catch { }
try { if (Directory.Exists(conversationDir)) Directory.Delete(conversationDir, true); } catch { }
}
}
[Fact]
public async Task RunAsync_InternalMode_BypassPermissions_AllowsWorkspaceWriteWithoutPrompt()
{
var workspaceDir = Path.Combine(Path.GetTempPath(), "axcopilot-internal-workspace-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(workspaceDir);
try
{
using var server = new FakeOllamaServer(
[
BuildToolCallResponse("file_write", new { path = "inside.txt", content = "ok" }, "write inside workspace"),
BuildTextResponse("?꾨즺"),
]);
var settings = BuildLoopSettings(server.Endpoint);
settings.Settings.OperationMode = OperationModePolicy.InternalMode;
settings.Settings.Llm.WorkFolder = workspaceDir;
settings.Settings.Llm.CodeWorkFolder = workspaceDir;
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings)
{
ActiveTab = "Code",
RuntimeWorkFolderOverride = workspaceDir,
};
var promptCount = 0;
loop.AskPermissionCallback = (_, _) =>
{
promptCount++;
return Task.FromResult(false);
};
var result = await loop.RunAsync(
[
new ChatMessage { Role = "user", Content = "inside.txt ?뚯씪 留뚮뱾?댁쨾" }
]);
result.Should().Contain("?꾨즺");
File.Exists(Path.Combine(workspaceDir, "inside.txt")).Should().BeTrue();
promptCount.Should().Be(0);
}
finally
{
try { if (Directory.Exists(workspaceDir)) Directory.Delete(workspaceDir, true); } catch { }
}
}
[Fact]
public async Task RunAsync_InternalMode_BypassPermissions_RequestsApprovalForPathOutsideWorkspace()
{
var workspaceDir = Path.Combine(Path.GetTempPath(), "axcopilot-internal-base-" + Guid.NewGuid().ToString("N"));
var externalDir = Path.Combine(Path.GetTempPath(), "axcopilot-internal-external-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(workspaceDir);
Directory.CreateDirectory(externalDir);
try
{
var externalTarget = Path.Combine(externalDir, "outside.txt");
using var server = new FakeOllamaServer(
[
BuildToolCallResponse("file_write", new { path = externalTarget, content = "blocked" }, "write outside workspace"),
BuildTextResponse("?꾨즺"),
]);
var settings = BuildLoopSettings(server.Endpoint);
settings.Settings.OperationMode = OperationModePolicy.InternalMode;
settings.Settings.Llm.WorkFolder = workspaceDir;
settings.Settings.Llm.CodeWorkFolder = workspaceDir;
using var llm = new LlmService(settings);
using var tools = ToolRegistry.CreateDefault();
var loop = new AgentLoopService(llm, tools, settings)
{
ActiveTab = "Code",
RuntimeWorkFolderOverride = workspaceDir,
};
var promptCount = 0;
var events = new List<AgentEvent>();
loop.EventOccurred += evt => events.Add(evt);
loop.AskPermissionCallback = (_, _) =>
{
promptCount++;
return Task.FromResult(false);
};
var result = await loop.RunAsync(
[
new ChatMessage { Role = "user", Content = "외부 경로에 파일을 써줘" }
]);
result.Should().Contain("?꾨즺");
File.Exists(externalTarget).Should().BeFalse();
promptCount.Should().Be(1);
events.Should().Contain(e =>
(e.Type == AgentEventType.PermissionDenied || e.Type == AgentEventType.Error) &&
e.ToolName == "file_write");
}
finally
{
try { if (Directory.Exists(workspaceDir)) Directory.Delete(workspaceDir, true); } catch { }
try { if (Directory.Exists(externalDir)) Directory.Delete(externalDir, true); } catch { }
}
}
private static SettingsService BuildLoopSettings(string endpoint)
{
var settings = new SettingsService();
@@ -519,10 +792,19 @@ public class AgentLoopE2ETests
settings.Settings.Llm.Model = "test-model";
settings.Settings.Llm.MaxAgentIterations = 6;
settings.Settings.Llm.MaxRetryOnError = 1;
settings.Settings.Llm.PlanMode = "off";
settings.Settings.Llm.EnableToolHooks = false;
settings.Settings.Llm.EnableAutoRouter = false;
settings.Settings.Llm.EnableForkSkillDelegationEnforcement = true;
settings.Settings.Llm.EnableProjectSkillDiscovery = false;
settings.Settings.Llm.EnablePluginSkillDiscovery = false;
settings.Settings.Llm.EnableMcpSkillDiscovery = false;
settings.Settings.Llm.EnableLegacyCommandSkills = false;
settings.Settings.Llm.SkillsFolderPath = "";
settings.Settings.Llm.AdditionalSkillFolders.Clear();
settings.Settings.Llm.FilePermission = "BypassPermissions";
settings.Settings.Llm.DefaultAgentPermission = "BypassPermissions";
settings.Settings.Llm.BlockedPaths.Clear();
settings.Settings.Llm.BlockedExtensions.Clear();
return settings;
}
@@ -566,6 +848,9 @@ public class AgentLoopE2ETests
private static string BuildTextOnlyResponse(string content)
=> BuildTextResponse(content);
private static string BuildRawResponse(string rawJson)
=> rawJson;
private sealed class FakeOllamaServer : IDisposable
{
private readonly HttpListener _listener;
@@ -0,0 +1,93 @@
using AxCopilot.Models;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentLoopIterationPreparationServiceTests
{
[Fact]
public void Prepare_ShouldProjectQueuedCommandsAndBuildUpdatedQueryView()
{
var messages = new List<ChatMessage>
{
new()
{
MsgId = "assistant-1",
Role = "assistant",
Content = "existing assistant message"
}
};
var queue = new AgentCommandQueue();
queue.EnqueueSteering("focus on the changed files", priority: "now", requestInterrupt: true);
queue.EnqueueNotification("low priority note", priority: "later");
var result = AgentLoopIterationPreparationService.Prepare(
messages,
queue,
lastToolResultAtUtc: null,
lastToolResultToolName: null,
utcNow: DateTime.UtcNow);
messages.Should().Contain(message =>
message.MetaKind == "queued_input_interrupt" &&
message.Role == "system");
messages.Should().Contain(message =>
message.MetaKind == "queued_steering" &&
message.Role == "user" &&
message.Content == "focus on the changed files");
result.QueueProjection.Events.Should().Contain(evt =>
evt.Type == AgentEventType.Thinking &&
evt.Summary.Contains("Deferred 1 lower-priority", StringComparison.OrdinalIgnoreCase));
result.QueryView.Messages.Should().Contain(message =>
message.MetaKind == "queued_steering" &&
message.Role == "user");
}
[Fact]
public void Prepare_ShouldForwardCodeQueryOptions()
{
var longContent = new string('Z', 2_200);
var messages = new List<ChatMessage>
{
new()
{
MsgId = "tool-1",
Role = "user",
Content = $$"""{"type":"tool_result","tool_use_id":"call-build","tool_name":"build_run","content":"{{longContent}}"}"""
},
new()
{
MsgId = "assistant-1",
Role = "assistant",
Content = "recent assistant message"
}
};
var result = AgentLoopIterationPreparationService.Prepare(
messages,
new AgentCommandQueue(),
lastToolResultAtUtc: null,
lastToolResultToolName: null,
utcNow: DateTime.UtcNow,
queryOptions: AgentQueryContextBuilder.AgentQueryContextBuildOptions.CreateCodeDefault());
result.QueryView.ProfileName.Should().Be("code");
result.QueryView.ToolResultSoftCharLimit.Should().BeGreaterThan(AgentToolResultBudget.DefaultSoftCharLimit);
}
[Fact]
public void BuildToolResultWaitSummary_ShouldFormatToolNameAndElapsedMilliseconds()
{
var utcNow = DateTime.UtcNow;
var waitSummary = AgentLoopIterationPreparationService.BuildToolResultWaitSummary(
utcNow.AddMilliseconds(-1250),
"file_read",
utcNow);
waitSummary.Should().StartWith("file_read:");
waitSummary.Should().Contain("ms");
}
}
@@ -0,0 +1,206 @@
using System.Text.Json;
using AxCopilot.Models;
using AxCopilot.Services;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentLoopLlmDispatchStageServiceTests
{
private sealed class FakeAgentTool : IAgentTool
{
public string Name { get; init; } = "file_read";
public string Description { get; init; } = "Reads a file";
public ToolParameterSchema Parameters { get; init; } = new();
public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default)
=> Task.FromResult(ToolResult.Ok("ok"));
}
private sealed class FakeToolExecutionCoordinator : IToolExecutionCoordinator
{
public List<ChatMessage>? CapturedMessages { get; private set; }
public IReadOnlyCollection<IAgentTool>? CapturedTools { get; private set; }
public string? CapturedPhaseLabel { get; private set; }
public bool CapturedForceToolCall { get; private set; }
public AgentLoopService.RunState? CapturedRunState { get; private set; }
public int PrefetchCallCount { get; private set; }
public AgentContext? PrefetchContext { get; private set; }
public Func<Func<ToolStreamEvent, Task>?, Func<ContentBlock, Task<ToolPrefetchResult?>>?, Task<List<ContentBlock>>>? DispatchAsync { get; init; }
public Task<ToolPrefetchResult?> TryPrefetchReadOnlyToolAsync(
ContentBlock block,
IReadOnlyCollection<IAgentTool> tools,
AgentContext context,
CancellationToken ct)
{
PrefetchCallCount++;
PrefetchContext = context;
return Task.FromResult<ToolPrefetchResult?>(
new ToolPrefetchResult(ToolResult.Ok("prefetched"), 5, block.ToolName));
}
public async Task<List<ContentBlock>> SendWithToolsWithRecoveryAsync(
List<ChatMessage> messages,
IReadOnlyCollection<IAgentTool> tools,
CancellationToken ct,
string phaseLabel,
AgentLoopService.RunState? runState = null,
bool forceToolCall = false,
Func<ContentBlock, Task<ToolPrefetchResult?>>? prefetchToolCallAsync = null,
Func<ToolStreamEvent, Task>? onStreamEventAsync = null)
{
CapturedMessages = messages;
CapturedTools = tools;
CapturedPhaseLabel = phaseLabel;
CapturedForceToolCall = forceToolCall;
CapturedRunState = runState;
if (DispatchAsync != null)
return await DispatchAsync(onStreamEventAsync, prefetchToolCallAsync);
return [];
}
}
[Fact]
public async Task ExecuteAsync_ShouldDispatchPreparedRequestAndResetRunState()
{
var coordinator = new FakeToolExecutionCoordinator
{
DispatchAsync = (_, _) => Task.FromResult(new List<ContentBlock>
{
new() { Type = "tool_use", ToolName = "file_read", ToolId = "tool-1" }
})
};
var events = new List<(AgentEventType Type, string Tool, string Summary)>();
var service = new AgentLoopLlmDispatchStageService(
coordinator,
block => $"{block.ToolName}:{block.ToolId}",
(type, tool, summary) => events.Add((type, tool, summary)));
var runState = new AgentLoopService.RunState
{
ContextRecoveryAttempts = 2,
TransientLlmErrorRetries = 1,
};
var request = new AgentLoopLlmRequestPreparationResult(
SendMessages:
[
new ChatMessage { Role = "user", Content = "fix the build" }
],
ForceInitialToolCall: true,
InjectedToolReminder: false,
SupplementalMessageCount: 0,
FlattenedStructuredAssistantCount: 0,
ConvertedOrphanToolResultCount: 0,
InjectedCodeWorkingSet: false,
InjectedSemanticSummary: false,
ProtectedActiveDiagnostics: false,
InjectedWorkspaceContext: false);
var result = await service.ExecuteAsync(
new AgentLoopLlmDispatchStageInput(
Iteration: 3,
ConversationId: "conv-1",
RunId: "run-1",
PhaseLabel: "Main loop 3",
CurrentModel: "model-a",
QueryContextDetail: "context=ready",
LlmRequest: request,
ActiveTools: [new FakeAgentTool()],
Context: new AgentContext { WorkFolder = @"E:\code", ActiveTab = "Code" },
RunState: runState),
CancellationToken.None);
result.Blocks.Should().ContainSingle();
coordinator.CapturedMessages.Should().BeSameAs(request.SendMessages);
coordinator.CapturedPhaseLabel.Should().Be("Main loop 3");
coordinator.CapturedForceToolCall.Should().BeTrue();
runState.ContextRecoveryAttempts.Should().Be(0);
runState.TransientLlmErrorRetries.Should().Be(0);
events.Should().BeEmpty();
}
[Fact]
public async Task ExecuteAsync_ShouldEmitStreamPreviewToolReadyAndRetryResetEvents()
{
var coordinator = new FakeToolExecutionCoordinator
{
DispatchAsync = async (onStreamEventAsync, prefetchToolCallAsync) =>
{
using var readInput = JsonDocument.Parse("""{"path":"Views/MainWindow.xaml"}""");
if (prefetchToolCallAsync != null)
{
await prefetchToolCallAsync(new ContentBlock
{
Type = "tool_use",
ToolName = "file_read",
ToolId = "prefetch-1",
ToolInput = readInput.RootElement.Clone(),
});
}
if (onStreamEventAsync != null)
{
await onStreamEventAsync(new ToolStreamEvent(ToolStreamEventKind.TextDelta, "Inspecting WPF files"));
await onStreamEventAsync(new ToolStreamEvent(
ToolStreamEventKind.ToolCallReady,
ToolCall: new ContentBlock
{
Type = "tool_use",
ToolName = "file_manage",
ToolId = "tool-9",
}));
await onStreamEventAsync(new ToolStreamEvent(ToolStreamEventKind.RetryReset, "retry"));
}
return [];
}
};
var events = new List<(AgentEventType Type, string Tool, string Summary)>();
var service = new AgentLoopLlmDispatchStageService(
coordinator,
block => $"{block.ToolName}:{block.ToolId}",
(type, tool, summary) => events.Add((type, tool, summary)));
var request = new AgentLoopLlmRequestPreparationResult(
SendMessages:
[
new ChatMessage { Role = "user", Content = "create WPF shell" }
],
ForceInitialToolCall: false,
InjectedToolReminder: false,
SupplementalMessageCount: 0,
FlattenedStructuredAssistantCount: 0,
ConvertedOrphanToolResultCount: 0,
InjectedCodeWorkingSet: false,
InjectedSemanticSummary: false,
ProtectedActiveDiagnostics: false,
InjectedWorkspaceContext: false);
var context = new AgentContext { WorkFolder = @"E:\code", ActiveTab = "Code" };
await service.ExecuteAsync(
new AgentLoopLlmDispatchStageInput(
Iteration: 1,
ConversationId: "conv-2",
RunId: "run-2",
PhaseLabel: "Main loop 1",
CurrentModel: "model-b",
QueryContextDetail: "context=ready",
LlmRequest: request,
ActiveTools: [new FakeAgentTool(), new FakeAgentTool { Name = "file_manage" }],
Context: context,
RunState: new AgentLoopService.RunState()),
CancellationToken.None);
coordinator.PrefetchCallCount.Should().Be(1);
coordinator.PrefetchContext.Should().BeSameAs(context);
events.Should().Contain(entry => entry.Type == AgentEventType.Thinking && entry.Summary.Contains("Inspecting WPF files"));
events.Should().Contain(entry => entry.Type == AgentEventType.Thinking && entry.Summary.Contains("Streaming tool ready: file_manage:tool-9"));
events.Should().Contain(entry => entry.Type == AgentEventType.Thinking && entry.Summary.Contains("Resetting the streamed partial response before retry."));
}
}
@@ -0,0 +1,119 @@
using AxCopilot.Models;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentLoopLlmRequestPreparationServiceTests
{
[Fact]
public void Prepare_ShouldInjectToolReminderOnFirstForcedCall()
{
var queryMessages = new List<ChatMessage>
{
new()
{
Role = "user",
Content = "inspect the repository"
}
};
var result = AgentLoopLlmRequestPreparationService.Prepare(
queryMessages,
totalToolCalls: 0,
forceInitialToolCallEnabled: true,
injectPreCallToolReminder: true,
noToolCallLoopRetry: 0);
result.ForceInitialToolCall.Should().BeTrue();
result.InjectedToolReminder.Should().BeTrue();
result.SendMessages.Should().HaveCount(2);
result.SendMessages.Last().Content.Should().Contain("[TOOL_REQUIRED]");
}
[Fact]
public void Prepare_ShouldSkipReminderWhenRetryLoopIsAlreadyActive()
{
var queryMessages = new List<ChatMessage>
{
new()
{
Role = "user",
Content = "inspect the repository"
}
};
var result = AgentLoopLlmRequestPreparationService.Prepare(
queryMessages,
totalToolCalls: 0,
forceInitialToolCallEnabled: true,
injectPreCallToolReminder: true,
noToolCallLoopRetry: 1);
result.ForceInitialToolCall.Should().BeTrue();
result.InjectedToolReminder.Should().BeFalse();
result.SendMessages.Should().HaveCount(1);
}
[Fact]
public void Prepare_ShouldAppendSupplementalMessagesBeforeReminder()
{
var queryMessages = new List<ChatMessage>
{
new()
{
Role = "user",
Content = "fix the latest build failure"
}
};
var supplemental = new ChatMessage
{
Role = "system",
MetaKind = "code_working_set",
Content = "[code-working-set]\n- Active diagnostic: MC4005 - Themes/ControlStyles.xaml"
};
var result = AgentLoopLlmRequestPreparationService.Prepare(
queryMessages,
totalToolCalls: 0,
forceInitialToolCallEnabled: true,
injectPreCallToolReminder: true,
noToolCallLoopRetry: 0,
supplementalMessages: [supplemental]);
result.SupplementalMessageCount.Should().Be(1);
result.SendMessages[1].MetaKind.Should().Be("code_working_set");
result.SendMessages.Last().Content.Should().Contain("[TOOL_REQUIRED]");
}
[Fact]
public void Prepare_ShouldNormalizeBrokenHistoricalToolTraceBeforeSend()
{
var queryMessages = new List<ChatMessage>
{
new()
{
Role = "assistant",
Content = """{"_tool_use_blocks":[{"type":"text","text":"Inspecting source"},{"type":"tool_use","id":"call-missing","name":"file_read","input":{"path":"App.xaml"}}]}"""
},
new()
{
Role = "user",
Content = "fix the latest build failure"
}
};
var result = AgentLoopLlmRequestPreparationService.Prepare(
queryMessages,
totalToolCalls: 1,
forceInitialToolCallEnabled: true,
injectPreCallToolReminder: true,
noToolCallLoopRetry: 0);
result.FlattenedStructuredAssistantCount.Should().Be(1);
result.ConvertedOrphanToolResultCount.Should().Be(0);
result.SendMessages[0].Content.Should().Be("Inspecting source\n[previous tool call] file_read");
queryMessages[0].Content.Should().StartWith("{\"_tool_use_blocks\"");
}
}
@@ -0,0 +1,84 @@
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentLoopNoToolResponseRecoveryServiceTests
{
[Fact]
public void BuildNoToolLoopRecovery_ShouldTriggerImmediatelyForProbeOnlyRuns()
{
var result = AgentLoopNoToolResponseRecoveryService.BuildNoToolLoopRecovery(
requiresConcreteArtifactOrEdit: true,
onlyProbeToolsUsed: true,
totalToolCalls: 1,
consecutiveNoToolResponses: 1,
noToolResponseThreshold: 2,
currentRetryCount: 0,
maxRetryCount: 2,
preferredInitialToolSequence: "file_read -> file_edit",
activeToolNames: ["dev_env_detect", "file_read", "file_edit"]);
result.Should().NotBeNull();
result!.NextRetryCount.Should().Be(1);
result.RecoveryContent.Should().Contain("도구를 호출하지 않았습니다");
result.RecoveryContent.Should().Contain("file_read -> file_edit");
result.RecoveryContent.Should().Contain("dev_env_detect, file_read, file_edit");
}
[Fact]
public void BuildNoToolLoopRecovery_ShouldReturnFinalWarningOnLastRetry()
{
var result = AgentLoopNoToolResponseRecoveryService.BuildNoToolLoopRecovery(
requiresConcreteArtifactOrEdit: true,
onlyProbeToolsUsed: false,
totalToolCalls: 0,
consecutiveNoToolResponses: 2,
noToolResponseThreshold: 2,
currentRetryCount: 1,
maxRetryCount: 2,
preferredInitialToolSequence: "file_read -> file_edit",
activeToolNames: ["file_read", "file_edit", "file_read"]);
result.Should().NotBeNull();
result!.NextRetryCount.Should().Be(2);
result.RecoveryContent.Should().Contain("최종 경고");
result.RecoveryContent.Should().Contain("file_read, file_edit");
}
[Fact]
public void BuildPlanExecutionRecovery_ShouldGeneratePlanSpecificRetryPrompt()
{
var result = AgentLoopNoToolResponseRecoveryService.BuildPlanExecutionRecovery(
requiresConcreteArtifactOrEdit: true,
forceToolCallAfterPlan: true,
planStepCount: 3,
totalToolCalls: 0,
currentRetryCount: 0,
maxRetryCount: 2,
preferredInitialToolSequence: "file_read -> file_edit",
activeToolNames: ["file_read", "file_edit", "git_tool"]);
result.Should().NotBeNull();
result!.NextRetryCount.Should().Be(1);
result.RecoveryContent.Should().Contain("계획을 세웠지만 도구를 호출하지 않았습니다");
result.EventSummary.Should().Contain("실행 재시도 1/2");
}
[Fact]
public void BuildPlanExecutionRecovery_ShouldReturnNullWhenRetryIsExhausted()
{
var result = AgentLoopNoToolResponseRecoveryService.BuildPlanExecutionRecovery(
requiresConcreteArtifactOrEdit: true,
forceToolCallAfterPlan: true,
planStepCount: 2,
totalToolCalls: 0,
currentRetryCount: 2,
maxRetryCount: 2,
preferredInitialToolSequence: "file_read -> file_edit",
activeToolNames: ["file_read", "file_edit"]);
result.Should().BeNull();
}
}
@@ -0,0 +1,168 @@
using System.Text.Json;
using AxCopilot.Models;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentLoopPreLlmStageServiceTests
{
private sealed class FakeAgentTool : IAgentTool
{
public string Name { get; init; } = "file_read";
public string Description { get; init; } = "Reads a file";
public ToolParameterSchema Parameters { get; init; } = new();
public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default)
=> Task.FromResult(ToolResult.Ok("ok"));
}
[Fact]
public void Prepare_ShouldPlanFreeTierDelayForGeminiAfterFirstIteration()
{
var result = AgentLoopPreLlmStageService.Prepare(new AgentLoopPreLlmStageInput(
QueryMessages: [new ChatMessage { Role = "user", Content = "inspect" }],
ActiveTools: [new FakeAgentTool()],
CodeWorkingSet: null,
ActiveTab: "Code",
AgentLogLevel: "info",
Iteration: 2,
MaxIterations: 40,
FreeTierMode: true,
ActiveService: "gemini",
FreeTierDelaySeconds: 5,
LatestUserPrompt: "inspect",
LastUserPromptHookFingerprint: null,
RunId: "run-1",
TotalToolCalls: 1,
ForceInitialToolCallEnabled: true,
InjectPreCallToolReminder: true,
NoToolCallLoopRetry: 0,
HasRuntimeOverride: false,
RuntimeAllowedToolCount: 0));
result.FreeTierDelayMilliseconds.Should().Be(5000);
result.FreeTierDelaySummary.Should().Contain("5s");
}
[Fact]
public void Prepare_ShouldEmitUserPromptHookOnlyWhenFingerprintChanges()
{
var unchanged = AgentLoopPreLlmStageService.Prepare(new AgentLoopPreLlmStageInput(
QueryMessages: [new ChatMessage { Role = "user", Content = "fix build" }],
ActiveTools: [new FakeAgentTool()],
CodeWorkingSet: null,
ActiveTab: "Code",
AgentLogLevel: "debug",
Iteration: 1,
MaxIterations: 20,
FreeTierMode: false,
ActiveService: "vllm",
FreeTierDelaySeconds: 0,
LatestUserPrompt: "fix build",
LastUserPromptHookFingerprint: $"{ "fix build".Length}:{ "fix build".GetHashCode()}",
RunId: "run-2",
TotalToolCalls: 0,
ForceInitialToolCallEnabled: true,
InjectPreCallToolReminder: true,
NoToolCallLoopRetry: 0,
HasRuntimeOverride: false,
RuntimeAllowedToolCount: 0));
unchanged.ShouldRunUserPromptSubmitHook.Should().BeFalse();
unchanged.UserPromptSubmitHookPayloadJson.Should().BeNull();
var changed = AgentLoopPreLlmStageService.Prepare(new AgentLoopPreLlmStageInput(
QueryMessages: [new ChatMessage { Role = "user", Content = "fix build" }],
ActiveTools: [new FakeAgentTool()],
CodeWorkingSet: null,
ActiveTab: "Code",
AgentLogLevel: "debug",
Iteration: 1,
MaxIterations: 20,
FreeTierMode: false,
ActiveService: "vllm",
FreeTierDelaySeconds: 0,
LatestUserPrompt: "fix build",
LastUserPromptHookFingerprint: null,
RunId: "run-3",
TotalToolCalls: 0,
ForceInitialToolCallEnabled: true,
InjectPreCallToolReminder: true,
NoToolCallLoopRetry: 0,
HasRuntimeOverride: false,
RuntimeAllowedToolCount: 0));
changed.ShouldRunUserPromptSubmitHook.Should().BeTrue();
changed.UserPromptSubmitHookPayloadJson.Should().Contain("\"runId\":\"run-3\"");
changed.ThinkingSummary.Should().Contain("iteration 1/20");
}
[Fact]
public void Prepare_ShouldReturnRuntimeSpecificMissingToolsFailure()
{
var result = AgentLoopPreLlmStageService.Prepare(new AgentLoopPreLlmStageInput(
QueryMessages: [new ChatMessage { Role = "user", Content = "fix build" }],
ActiveTools: [],
CodeWorkingSet: null,
ActiveTab: "Code",
AgentLogLevel: "info",
Iteration: 1,
MaxIterations: 20,
FreeTierMode: false,
ActiveService: "vllm",
FreeTierDelaySeconds: 0,
LatestUserPrompt: "fix build",
LastUserPromptHookFingerprint: null,
RunId: "run-4",
TotalToolCalls: 0,
ForceInitialToolCallEnabled: true,
InjectPreCallToolReminder: true,
NoToolCallLoopRetry: 0,
HasRuntimeOverride: true,
RuntimeAllowedToolCount: 3));
result.LlmRequest.Should().BeNull();
result.MissingToolsEventSummary.Should().Contain("skill runtime policy");
result.MissingToolsReturnMessage.Should().Contain("allowed-tools");
}
[Fact]
public void Prepare_ShouldBuildLlmRequestWhenToolsExist()
{
var workingSet = new CodeTaskWorkingSetService(
"create WPF shell",
@"E:\code",
"wpf-mvvm",
startedFromEmptyWorkspace: true);
using var mkdirDoc = JsonDocument.Parse("""{"action":"mkdir","paths":["Views","ViewModels"]}""");
workingSet.RecordToolResult("file_manage", mkdirDoc.RootElement.Clone(), ToolResult.Ok("created directories"));
var result = AgentLoopPreLlmStageService.Prepare(new AgentLoopPreLlmStageInput(
QueryMessages: [new ChatMessage { Role = "user", Content = "create WPF shell" }],
ActiveTools: [new FakeAgentTool()],
CodeWorkingSet: workingSet,
ActiveTab: "Code",
AgentLogLevel: "info",
Iteration: 1,
MaxIterations: 30,
FreeTierMode: false,
ActiveService: "vllm",
FreeTierDelaySeconds: 0,
LatestUserPrompt: "create WPF shell",
LastUserPromptHookFingerprint: null,
RunId: "run-5",
TotalToolCalls: 0,
ForceInitialToolCallEnabled: true,
InjectPreCallToolReminder: true,
NoToolCallLoopRetry: 0,
HasRuntimeOverride: false,
RuntimeAllowedToolCount: 0));
result.LlmRequest.Should().NotBeNull();
result.LlmRequest!.SupplementalMessageCount.Should().Be(2);
result.LlmRequest.SendMessages.Should().Contain(message => message.MetaKind == "code_working_set");
result.LlmRequest.SendMessages.Should().Contain(message => message.MetaKind == "code_semantic_summary");
}
}
@@ -0,0 +1,103 @@
using System.Text.Json;
using AxCopilot.Models;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentLoopQueryAssemblyServiceTests
{
[Fact]
public void PrepareHistory_ShouldInjectSessionLearningsForNonCodeTabs()
{
var messages = new List<ChatMessage>
{
new()
{
Role = "user",
Content = "fix the build"
}
};
var collector = new SessionLearningCollector();
collector.TryExtract("build_run", "error CS0246: Missing type", success: false);
var result = AgentLoopQueryAssemblyService.PrepareHistory(
messages,
new AgentCommandQueue(),
lastToolResultAtUtc: null,
lastToolResultToolName: null,
utcNow: DateTime.UtcNow,
isCodeTab: false,
sessionLearnings: collector,
queryOptions: AgentQueryContextBuilder.AgentQueryContextBuildOptions.CreateDefault());
result.RefreshedSessionLearnings.Should().BeTrue();
messages[0].MetaKind.Should().Be("session_learnings");
messages[0].Content.Should().Contain("[System:SessionLearnings]");
result.IterationPreparation.QueryView.Messages.Should().Contain(message => message.MetaKind == "session_learnings");
}
[Fact]
public void PrepareHistory_ShouldSkipSessionLearningsForCodeTabs()
{
var messages = new List<ChatMessage>
{
new()
{
Role = "user",
Content = "fix the build"
}
};
var collector = new SessionLearningCollector();
collector.TryExtract("build_run", "error CS0246: Missing type", success: false);
var result = AgentLoopQueryAssemblyService.PrepareHistory(
messages,
new AgentCommandQueue(),
lastToolResultAtUtc: null,
lastToolResultToolName: null,
utcNow: DateTime.UtcNow,
isCodeTab: true,
sessionLearnings: collector,
queryOptions: AgentQueryContextBuilder.AgentQueryContextBuildOptions.CreateCodeDefault());
result.RefreshedSessionLearnings.Should().BeFalse();
messages.Should().OnlyContain(message => message.MetaKind != "session_learnings");
}
[Fact]
public void PrepareRequest_ShouldAppendWorkingSetMessageForCodeRuns()
{
var queryMessages = new List<ChatMessage>
{
new()
{
Role = "user",
Content = "create the WPF shell"
}
};
var workingSet = new CodeTaskWorkingSetService(
"create the WPF shell",
@"E:\code",
"wpf-mvvm",
startedFromEmptyWorkspace: true);
using var fileManageInput = JsonDocument.Parse("""{"action":"mkdir","paths":["Views","ViewModels","Themes"]}""");
workingSet.RecordToolResult("file_manage", fileManageInput.RootElement.Clone(), ToolResult.Ok("created directories"));
var result = AgentLoopQueryAssemblyService.PrepareRequest(
queryMessages,
workingSet,
totalToolCalls: 0,
forceInitialToolCallEnabled: true,
injectPreCallToolReminder: true,
noToolCallLoopRetry: 0);
result.SupplementalMessageCount.Should().Be(2);
result.SendMessages.Should().Contain(message => message.MetaKind == "code_working_set");
result.SendMessages.Should().Contain(message => message.MetaKind == "code_semantic_summary");
result.InjectedCodeWorkingSet.Should().BeTrue();
result.InjectedSemanticSummary.Should().BeTrue();
result.SendMessages.Last().Content.Should().Contain("[TOOL_REQUIRED]");
}
}
@@ -0,0 +1,88 @@
using AxCopilot.Services;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentLoopResponseClassificationServiceTests
{
[Fact]
public void Classify_ShouldSplitTextAndToolCalls_AndResetNoToolCounter()
{
var blocks = new List<ContentBlock>
{
new() { Type = "text", Text = "I will inspect the repository." },
new() { Type = "tool_use", ToolName = "file_read", ToolId = "tool-1" }
};
var result = AgentLoopResponseClassificationService.Classify(blocks, consecutiveNoToolResponses: 2);
result.TextResponse.Should().Contain("inspect the repository");
result.ToolCalls.Should().HaveCount(1);
result.NextConsecutiveNoToolResponses.Should().Be(0);
result.BuildThinkingSummary().Should().Contain("inspect the repository");
}
[Fact]
public void Classify_ShouldIncrementNoToolCounter_WhenOnlyTextBlocksArePresent()
{
var blocks = new List<ContentBlock>
{
new() { Type = "text", Text = "Plan step one." },
new() { Type = "text", Text = "Plan step two." }
};
var result = AgentLoopResponseClassificationService.Classify(blocks, consecutiveNoToolResponses: 1);
result.ToolCalls.Should().BeEmpty();
result.TextParts.Should().HaveCount(2);
result.NextConsecutiveNoToolResponses.Should().Be(2);
}
[Fact]
public void BuildThinkingSummary_ShouldDropTranscriptArtifacts()
{
var blocks = new List<ContentBlock>
{
new()
{
Type = "text",
Text = """
[이전 도구 호출: file_read]
1.
file_read]
.
"""
},
new() { Type = "tool_use", ToolName = "file_read", ToolId = "tool-1" }
};
var result = AgentLoopResponseClassificationService.Classify(blocks, consecutiveNoToolResponses: 0);
result.BuildThinkingSummary().Should().Be("실제 수정 범위를 다시 확인합니다.");
}
[Fact]
public void Classify_ShouldRecoverToolCallEmbeddedInText()
{
var blocks = new List<ContentBlock>
{
new()
{
Type = "text",
Text = """
<tool_call>{"name":"file_write","arguments":{"path":"index.html","content":"<html>clock</html>"}}</tool_call>
.
"""
}
};
var result = AgentLoopResponseClassificationService.Classify(blocks, consecutiveNoToolResponses: 0);
result.ToolCalls.Should().ContainSingle();
result.ToolCalls[0].ToolName.Should().Be("file_write");
result.TextResponse.Should().Contain("이제 파일을 생성합니다.");
result.TextResponse.Should().NotContain("<tool_call>");
result.NextConsecutiveNoToolResponses.Should().Be(0);
}
}
@@ -0,0 +1,146 @@
using AxCopilot.Models;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentMessageInvariantHelperTests
{
[Fact]
public void NormalizeHistoricalToolTrace_ShouldFlattenAssistantWithMissingToolResult()
{
var messages = new List<ChatMessage>
{
new()
{
Role = "assistant",
Content = """{"_tool_use_blocks":[{"type":"text","text":"Reviewing the project"},{"type":"tool_use","id":"call-missing","name":"file_read","input":{"path":"App.xaml"}}]}"""
}
};
var result = AgentMessageInvariantHelper.NormalizeHistoricalToolTrace(messages);
result.FlattenedAssistantCount.Should().Be(1);
messages[0].Content.Should().Be("Reviewing the project\n[previous tool call] file_read");
}
[Fact]
public void NormalizeHistoricalToolTrace_ShouldConvertOrphanToolResultToPlainUserTranscript()
{
var messages = new List<ChatMessage>
{
new()
{
Role = "user",
Content = """{"type":"tool_result","tool_use_id":"call-orphan","tool_name":"file_read","content":"line1\nline2"}"""
}
};
var result = AgentMessageInvariantHelper.NormalizeHistoricalToolTrace(messages);
result.ConvertedOrphanToolResultCount.Should().Be(1);
messages[0].Content.Should().Be("[previous tool result: file_read]\nline1 line2");
}
[Fact]
public void NormalizeHistoricalToolTrace_ShouldPreserveValidStructuredToolPair()
{
var messages = new List<ChatMessage>
{
new()
{
Role = "assistant",
Content = """{"_tool_use_blocks":[{"type":"text","text":"Reading source"},{"type":"tool_use","id":"call-valid","name":"file_read","input":{"path":"App.xaml"}}]}"""
},
new()
{
Role = "user",
Content = """{"type":"tool_result","tool_use_id":"call-valid","tool_name":"file_read","content":"file content"}"""
}
};
var result = AgentMessageInvariantHelper.NormalizeHistoricalToolTrace(messages);
result.TotalAdjustedCount.Should().Be(0);
messages[0].Content.Should().StartWith("{\"_tool_use_blocks\"");
messages[1].Content.Should().StartWith("{\"type\":\"tool_result\"");
}
[Fact]
public void PopulateMissingToolResultPreviews_ShouldSynthesizePreview_WhenNoStoredPreviewExists()
{
var longContent = string.Join(' ', Enumerable.Repeat("Detailed output row for recovery.", 40));
var messages = new List<ChatMessage>
{
new()
{
MsgId = "tool-result-1",
Role = "user",
Content = $$"""{"type":"tool_result","tool_use_id":"call-synth","tool_name":"file_read","content":"{{longContent}}"}"""
}
};
var changed = AgentMessageInvariantHelper.PopulateMissingToolResultPreviews(messages);
changed.Should().BeTrue();
messages[0].QueryPreviewContent.Should().NotBeNullOrWhiteSpace();
messages[0].QueryPreviewContent.Should().Contain("call-synth");
messages[0].QueryPreviewContent.Should().Contain("...");
messages[0].QueryPreviewContent.Should().NotContain(longContent);
}
[Fact]
public void BuildToolResultPreviewMap_ShouldPreferExplicitPreview_WhenAvailable()
{
var explicitPreview = """{"type":"tool_result","tool_use_id":"call-explicit","tool_name":"file_read","content":"preview"}""";
var messages = new List<ChatMessage>
{
new()
{
MsgId = "tool-result-1",
Role = "user",
Content = """{"type":"tool_result","tool_use_id":"call-explicit","tool_name":"file_read","content":"long output content"}""",
QueryPreviewContent = explicitPreview
},
new()
{
MsgId = "tool-result-2",
Role = "user",
Content = """{"type":"tool_result","tool_use_id":"call-explicit","tool_name":"file_read","content":"another long output content"}"""
}
};
var map = AgentMessageInvariantHelper.BuildToolResultPreviewMap(messages);
map["call-explicit"].Should().Be(explicitPreview);
}
[Fact]
public void PopulateMissingToolResultPreviews_ShouldRebindPreview_WhenFingerprintMatchesDifferentToolUseId()
{
var messages = new List<ChatMessage>
{
new()
{
MsgId = "tool-result-1",
Role = "user",
Content = """{"type":"tool_result","tool_use_id":"call-original","tool_name":"file_read","content":"same long output that should map across sessions"}""",
QueryPreviewContent = """{"type":"tool_result","tool_use_id":"call-original","tool_name":"file_read","content":"stable preview"}"""
},
new()
{
MsgId = "tool-result-2",
Role = "user",
Content = """{"type":"tool_result","tool_use_id":"call-replayed","tool_name":"file_read","content":"same long output that should map across sessions"}"""
}
};
var changed = AgentMessageInvariantHelper.PopulateMissingToolResultPreviews(messages);
changed.Should().BeTrue();
messages[1].QueryPreviewContent.Should().Contain("call-replayed");
messages[1].QueryPreviewContent.Should().Contain("stable preview");
messages[1].QueryPreviewContent.Should().NotContain("call-original");
}
}
@@ -0,0 +1,28 @@
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentProgressSummarySanitizerTests
{
[Fact]
public void IsLowSignalStatusSummary_ReturnsTrueForModelWaitMessages()
{
AgentProgressSummarySanitizer.IsLowSignalStatusSummary(
"수정 단계: 모델 첫 응답을 기다리는 중입니다... (8초)",
"")
.Should()
.BeTrue();
}
[Fact]
public void IsLowSignalStatusSummary_ReturnsFalseForConcreteWorkMessages()
{
AgentProgressSummarySanitizer.IsLowSignalStatusSummary(
"ChatWindow.xaml.cs와 AgentLoopService.cs를 비교해 수정 범위를 정리하고 있습니다.",
"file_read")
.Should()
.BeFalse();
}
}
@@ -0,0 +1,138 @@
using AxCopilot.Models;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentQueryContextBuilderTests
{
[Fact]
public void Build_ShouldPopulateMissingToolResultPreviewBeforeCreatingQueryView()
{
var longContent = new string('Z', 1800);
var sourceMessages = new List<ChatMessage>
{
new()
{
MsgId = "tool-source-1",
Role = "user",
Content = $$"""{"type":"tool_result","tool_use_id":"call-view","tool_name":"file_read","content":"{{longContent}}"}""",
QueryPreviewContent = """{"type":"tool_result","tool_use_id":"call-view","tool_name":"file_read","content":"preview-view"}"""
},
new()
{
MsgId = "tool-source-2",
Role = "user",
Content = $$"""{"type":"tool_result","tool_use_id":"call-view","tool_name":"file_read","content":"{{longContent}}"}"""
},
new()
{
MsgId = "tail-1",
Role = "assistant",
Content = "recent tail"
}
};
var result = AgentQueryContextBuilder.Build(sourceMessages);
sourceMessages[1].QueryPreviewContent.Should().Be(sourceMessages[0].QueryPreviewContent);
result.Messages[1].QueryPreviewContent.Should().Be(sourceMessages[0].QueryPreviewContent);
}
[Fact]
public void Build_ShouldSynthesizeToolResultPreview_WhenNoStoredPreviewExists()
{
var longContent = string.Join(' ', Enumerable.Repeat("long tool output", 120));
var sourceMessages = new List<ChatMessage>
{
new()
{
MsgId = "tool-source-1",
Role = "user",
Content = $$"""{"type":"tool_result","tool_use_id":"call-synth-view","tool_name":"file_read","content":"{{longContent}}"}"""
},
new()
{
MsgId = "tail-1",
Role = "assistant",
Content = "recent tail"
}
};
var result = AgentQueryContextBuilder.Build(sourceMessages);
sourceMessages[0].QueryPreviewContent.Should().NotBeNullOrWhiteSpace();
sourceMessages[0].QueryPreviewContent.Should().Contain("call-synth-view");
result.Messages.Should().Contain(message =>
message.QueryPreviewContent != null &&
message.QueryPreviewContent.Contains("call-synth-view", StringComparison.OrdinalIgnoreCase));
}
[Fact]
public void Build_ShouldExposeCodeProfileMetadata()
{
var sourceMessages = new List<ChatMessage>
{
new()
{
MsgId = "tool-source-1",
Role = "user",
Content = """{"type":"tool_result","tool_use_id":"call-code","tool_name":"build_run","content":"short"}"""
},
new()
{
MsgId = "tail-1",
Role = "assistant",
Content = "recent tail"
}
};
var result = AgentQueryContextBuilder.Build(
sourceMessages,
AgentQueryContextBuilder.AgentQueryContextBuildOptions.CreateCodeDefault());
result.ProfileName.Should().Be("code");
result.ProtectedRecentNonSystemMessages.Should().BeGreaterThan(8);
result.ToolResultAggregateBudgetChars.Should().BeGreaterThan(AgentToolResultBudget.DefaultAggregateBudgetChars);
}
[Fact]
public void Build_ShouldRestoreRecentCompactedToolSnippetsIntoPostCompactContextMessage()
{
var sourceMessages = new List<ChatMessage>
{
new()
{
MsgId = "tool-call-1",
Role = "assistant",
Content = """{"_tool_use_blocks":[{"type":"tool_use","id":"call-restore","name":"file_read","input":{"path":"MainWindow.xaml"}}]}"""
},
new()
{
MsgId = "tool-result-1",
Role = "user",
Content = """{"type":"tool_result","tool_use_id":"call-restore","tool_name":"file_read","content":"<Window Title=\"Preview\" />"}"""
},
new()
{
MsgId = "boundary-1",
Role = "system",
MetaKind = "microcompact_boundary",
Content = "[previous conversation summary]"
},
new()
{
MsgId = "tail-1",
Role = "assistant",
Content = "recent tail"
}
};
var result = AgentQueryContextBuilder.Build(sourceMessages);
var postCompactMessage = result.Messages.Single(message => message.MetaKind == "post_compact_context");
postCompactMessage.Content.Should().Contain("recent compacted tool trace:");
postCompactMessage.Content.Should().Contain("file_read result:");
}
}
@@ -0,0 +1,71 @@
using AxCopilot.Models;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentQueuedCommandProjectorTests
{
[Fact]
public void Project_ShouldCreateInterruptMessageAndDeferredEvent()
{
var now = DateTime.Now;
var commands = new List<AgentQueuedCommand>
{
new(1, AgentCommandKind.Steering, AgentQueuePriority.Now, "steer-now", now, true),
new(2, AgentCommandKind.Notification, AgentQueuePriority.Now, "later-note", now.AddSeconds(1), false),
};
var projection = AgentQueuedCommandProjector.Project(commands, deferredCount: 2);
projection.Messages.Should().ContainSingle(message =>
message.MetaKind == "queued_input_interrupt" &&
message.Role == "system");
projection.Messages.Should().Contain(message =>
message.MetaKind == "queued_steering" &&
message.Role == "user" &&
message.Content == "steer-now");
projection.Messages.Should().Contain(message =>
message.MetaKind == "queue_notification" &&
message.Role == "system" &&
message.Content == "later-note");
projection.Events.Should().Contain(evt =>
evt.Type == AgentEventType.Thinking &&
evt.Summary.Contains("Deferred 2 lower-priority", StringComparison.OrdinalIgnoreCase));
}
[Fact]
public void Project_ShouldMapPermissionResumeAndPromptKindsConsistently()
{
var now = DateTime.Now;
var commands = new List<AgentQueuedCommand>
{
new(1, AgentCommandKind.PermissionContinuation, AgentQueuePriority.Now, "continue-tool", now, true),
new(2, AgentCommandKind.Resume, AgentQueuePriority.Now, "resume-run", now.AddSeconds(1), false),
new(3, AgentCommandKind.Prompt, AgentQueuePriority.Now, "follow-up", now.AddSeconds(2), false),
new(4, AgentCommandKind.UserDecision, AgentQueuePriority.Now, "choose-option-b", now.AddSeconds(3), false),
};
var projection = AgentQueuedCommandProjector.Project(commands, deferredCount: 0);
projection.Messages.Should().Contain(message =>
message.MetaKind == "queue_permission_continuation" &&
message.Role == "system");
projection.Messages.Should().Contain(message =>
message.MetaKind == "queue_resume" &&
message.Role == "system");
projection.Messages.Should().Contain(message =>
message.MetaKind == "queued_prompt" &&
message.Role == "user");
projection.Messages.Should().Contain(message =>
message.MetaKind == "queued_user_decision" &&
message.Role == "user");
projection.Events.Should().Contain(evt =>
evt.Type == AgentEventType.UserMessage &&
evt.Summary == "follow-up");
projection.Events.Should().Contain(evt =>
evt.Type == AgentEventType.Thinking &&
evt.Summary == "continue-tool");
}
}
@@ -0,0 +1,93 @@
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentStatusNarrativeCatalogTests
{
[Fact]
public void BuildFromEvent_ShouldDescribeCodeReadWithTargetDetail()
{
var evt = new AgentEvent
{
Type = AgentEventType.ToolCall,
ToolName = "file_read",
Summary = "관련 파일 읽기",
ToolInput = "{\"path\":\"src/AxCopilot/Views/ChatWindow.xaml.cs\"}"
};
var narrative = AgentStatusNarrativeCatalog.BuildFromEvent(evt, "Code");
narrative.Message.Should().Contain("코드");
narrative.Detail.Should().Contain("ChatWindow.xaml.cs");
narrative.Category.Should().Be("read");
}
[Fact]
public void BuildFromEvent_ShouldExplainPermissionWaitClearly()
{
var evt = new AgentEvent
{
Type = AgentEventType.PermissionRequest,
ToolName = "file_edit",
Summary = "권한 확인 필요: src/AxCopilot/Views/ChatWindow.xaml.cs"
};
var narrative = AgentStatusNarrativeCatalog.BuildFromEvent(evt, "Code");
narrative.Message.Should().Contain("권한");
narrative.Detail.Should().NotBeNullOrWhiteSpace();
narrative.Category.Should().Be("permission");
}
[Fact]
public void BuildIdle_ShouldReflectLastExecutionCategory()
{
var evt = new AgentEvent
{
Type = AgentEventType.ToolResult,
ToolName = "build_run",
Summary = "빌드 결과 확인"
};
var narrative = AgentStatusNarrativeCatalog.BuildIdle(
evt,
"Code",
TimeSpan.FromSeconds(16),
TimeSpan.FromSeconds(24),
pendingPostCompaction: false);
narrative.Message.Should().Contain("실행");
narrative.Detail.Should().Contain("로그");
narrative.Category.Should().Be("execute");
}
[Fact]
public void BuildProgressStepLabel_ShouldPromoteDocumentWorkToReadableSummary()
{
var evt = new AgentEvent
{
Type = AgentEventType.ToolCall,
ToolName = "html_create",
Summary = "html_create 실행"
};
var label = AgentStatusNarrativeCatalog.BuildProgressStepLabel(evt, "문서", "HTML 생성");
label.Should().Contain("문서");
}
[Fact]
public void BuildProgressPhaseMeta_ShouldExposeReadableEditCompletionLabel()
{
var evt = new AgentEvent
{
Type = AgentEventType.ToolResult,
ToolName = "file_edit",
Summary = "파일 수정 완료"
};
AgentStatusNarrativeCatalog.BuildProgressPhaseMeta(evt).Should().Be("수정 완료");
}
}
@@ -40,7 +40,6 @@ public class AgentTabSettingsResolverTests
{
var code = new CodeSettings
{
EnablePlanModeTools = false,
EnableWorktreeTools = true,
EnableTeamTools = false,
EnableCronTools = false,
@@ -0,0 +1,75 @@
using AxCopilot.Models;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentToolCatalogTests
{
[Theory]
[InlineData("git", "git_tool")]
[InlineData("lsp", "lsp_code_intel")]
[InlineData("zip", "zip_tool")]
[InlineData("project_rule", "project_rules")]
[InlineData("snippet_run", "snippet_runner")]
[InlineData("math_tool", "math_eval")]
public void Canonicalize_ShouldNormalizeLegacyToolNames(string input, string expected)
{
AgentToolCatalog.Canonicalize(input).Should().Be(expected);
}
[Fact]
public void CanonicalizePermissionMap_ShouldNormalizeToolKeysAndPatterns()
{
var input = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
["git"] = "ask",
["zip@*.zip"] = "deny",
["project_rule|*.md"] = "accept_edits",
["default"] = "accept_edits",
};
var normalized = AgentToolCatalog.CanonicalizePermissionMap(input);
normalized.Should().ContainKey("git_tool");
normalized.Should().ContainKey("zip_tool@*.zip");
normalized.Should().ContainKey("project_rules|*.md");
normalized.Should().ContainKey("default");
}
[Fact]
public void CanonicalizeHooks_ShouldNormalizeHookTargets()
{
var hooks = new[]
{
new AgentHookEntry { Name = "zip hook", ToolName = "zip" },
new AgentHookEntry { Name = "all hook", ToolName = "*" },
};
var normalized = AgentToolCatalog.CanonicalizeHooks(hooks);
normalized[0].ToolName.Should().Be("zip_tool");
normalized[1].ToolName.Should().Be("*");
}
[Fact]
public void FilterExposureByPermission_ShouldRemoveBlanketDeniedTools()
{
var tools = new[]
{
new { Name = "file_read" },
new { Name = "git_tool" },
new { Name = "build_run" },
};
var permissions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
["git"] = "deny",
["build_run@*.sln"] = "deny",
};
var filtered = AgentToolCatalog.FilterExposureByPermission(tools, tool => tool.Name, permissions);
filtered.Select(tool => tool.Name).Should().BeEquivalentTo(["file_read", "build_run"]);
}
}
@@ -0,0 +1,141 @@
using AxCopilot.Models;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentToolResultBudgetTests
{
[Fact]
public void Apply_ShouldPersistPreviewToSourceAndReuseItOnNextQueryView()
{
var longContent = new string('A', 1400);
var sourceMessages = new List<ChatMessage>
{
new()
{
MsgId = "tool-1",
Role = "user",
Content = $$"""{"type":"tool_result","tool_use_id":"call-1","tool_name":"file_read","content":"{{longContent}}"}"""
},
new()
{
MsgId = "tail-1",
Role = "assistant",
Content = "recent tail"
}
};
var firstWindow = sourceMessages.Select(message => new ChatMessage
{
MsgId = message.MsgId,
Role = message.Role,
Content = message.Content,
QueryPreviewContent = message.QueryPreviewContent,
Timestamp = message.Timestamp
}).ToList();
var first = AgentToolResultBudget.Apply(
firstWindow,
protectedRecentNonSystemMessages: 1,
sourceMessages: sourceMessages);
sourceMessages[0].QueryPreviewContent.Should().NotBeNullOrWhiteSpace();
first.TruncatedCount.Should().Be(1);
var secondWindow = sourceMessages.Select(message => new ChatMessage
{
MsgId = message.MsgId,
Role = message.Role,
Content = message.Content,
QueryPreviewContent = message.QueryPreviewContent,
Timestamp = message.Timestamp
}).ToList();
var second = AgentToolResultBudget.Apply(
secondWindow,
protectedRecentNonSystemMessages: 1,
sourceMessages: sourceMessages);
second.ReusedPreviewCount.Should().Be(1);
secondWindow[0].Content.Should().Be(sourceMessages[0].QueryPreviewContent);
}
[Fact]
public void Apply_ShouldPreserveLargerBuildResultsInCodeMode()
{
var longContent = new string('B', 2_600);
var queryView = new List<ChatMessage>
{
new()
{
MsgId = "tool-build",
Role = "user",
Content = $$"""{"type":"tool_result","tool_use_id":"call-build","tool_name":"build_run","content":"{{longContent}}"}"""
},
new()
{
MsgId = "tail-1",
Role = "assistant",
Content = "recent tail"
}
};
var result = AgentToolResultBudget.Apply(
queryView,
AgentToolResultBudget.CreateCodeOptions(),
sourceMessages: queryView);
result.TruncatedCount.Should().Be(0);
queryView[0].Content.Should().Contain(longContent[..256]);
}
[Fact]
public void Apply_ShouldReusePreviewFingerprintAcrossSessions()
{
var longContent = new string('C', 1700);
var sourceMessages = new List<ChatMessage>
{
new()
{
MsgId = "source-tool",
Role = "user",
Content = $$"""{"type":"tool_result","tool_use_id":"call-original","tool_name":"file_read","content":"{{longContent}}"}""",
QueryPreviewContent = """{"type":"tool_result","tool_use_id":"call-original","tool_name":"file_read","content":"preview-fingerprint"}"""
},
new()
{
MsgId = "tail-1",
Role = "assistant",
Content = "recent tail"
}
};
var queryView = new List<ChatMessage>
{
new()
{
MsgId = "rebuilt-tool",
Role = "user",
Content = $$"""{"type":"tool_result","tool_use_id":"call-replayed","tool_name":"file_read","content":"{{longContent}}"}"""
},
new()
{
MsgId = "tail-2",
Role = "assistant",
Content = "recent tail"
}
};
var result = AgentToolResultBudget.Apply(
queryView,
protectedRecentNonSystemMessages: 1,
sourceMessages: sourceMessages);
result.ReusedPreviewCount.Should().Be(1);
queryView[0].Content.Should().Contain("call-replayed");
queryView[0].Content.Should().Contain("preview-fingerprint");
queryView[0].Content.Should().NotContain("call-original");
}
}

Some files were not shown because too many files have changed in this diff Show More