creatrip-agent-rules-builder
Version:
Unified converter for AI coding agent rules across Cursor, Windsurf, and Claude
193 lines (170 loc) • 6.55 kB
text/typescript
import { Command } from "commander";
import { verifyAgents } from "../verifiers/index";
import { OutputFormat, VerificationSummary } from "../verifiers/types";
import chalk from "chalk";
export function createVerifyCommand(): Command {
const command = new Command("verify");
command
.description("원본과 생성된 파일들 간의 일관성을 검증합니다")
.option(
"-r, --recursive",
"하위 디렉토리를 재귀적으로 탐색하여 모든 AGENTS.md 검증",
)
.option("--json", "JSON 형식으로 결과 출력")
.option("--quiet", "종료 코드를 제외한 모든 출력 억제")
.action(async (options) => {
const outputFormat: OutputFormat = options.json
? "json"
: options.quiet
? "quiet"
: "human";
const rootPath = process.cwd();
const isRecursive = options.recursive || false;
try {
const results = await verifyAgents(rootPath, outputFormat, isRecursive);
if (outputFormat === "json") {
console.log(JSON.stringify(results, null, 2));
} else if (outputFormat === "human") {
printHumanReadableResults(results, isRecursive);
}
process.exit(results.status === "pass" ? 0 : 1);
} catch (error) {
if (!options.quiet) {
console.error(
chalk.red(
`오류: ${error instanceof Error ? error.message : "알 수 없는 오류"}`,
),
);
}
process.exit(1);
}
});
return command;
}
function printHumanReadableResults(
results: VerificationSummary,
isRecursive: boolean,
): void {
console.log(chalk.blue("에이전트 규칙 일관성 검증 중..."));
if (!isRecursive) {
// 단일 디렉토리 모드 (기존과 동일)
const location = results.locations[0];
// 각 에이전트별 결과 출력
for (const [agentName, result] of Object.entries(location.agents)) {
if (result.passed) {
console.log(chalk.green(`✓ ${agentName}: 동기화됨`));
} else {
const errorMsg =
result.error === "content mismatch"
? "내용 불일치"
: result.error === "file not found"
? "파일 없음"
: result.error || "내용 불일치";
console.log(chalk.red(`✗ ${agentName}: ${errorMsg}`));
}
}
// 패턴 분석 결과 및 권장 사항 출력
if (location.diagnosis) {
console.log(""); // 빈 줄 추가
switch (location.diagnosis.pattern) {
case "all_synced":
console.log(chalk.green("✓ 모든 파일이 동기화되어 있습니다"));
break;
case "all_outdated":
console.log(chalk.yellow("→ 패턴 감지: 모든 파일이 오래됨"));
console.log(chalk.yellow("→ 해결방법: 'agent-rules build' 실행"));
break;
case "single_diverged":
const divergedFile = location.diagnosis.diverged?.[0];
console.log(
chalk.yellow(`→ 패턴 감지: ${divergedFile} 파일만 불일치`),
);
console.log(
chalk.yellow(`→ AGENTS.md를 수정하려던 것이 아닌지 확인하세요`),
);
break;
case "multiple_diverged":
console.log(chalk.yellow("→ 패턴 감지: 여러 파일 불일치"));
console.log(chalk.yellow("→ 수동 검토가 필요합니다"));
break;
}
}
// 최종 결과
console.log(""); // 빈 줄 추가
if (location.status === "pass") {
console.log(chalk.green("✓ 모든 에이전트 검증 성공"));
} else {
console.log(
chalk.red(
`✗ 검증 실패: ${location.summary.total}개 중 ${location.summary.failed}개 불일치`,
),
);
}
} else {
// 재귀 모드
console.log("");
for (const location of results.locations) {
const relativePath = location.path.replace(process.cwd(), "") || "/";
console.log(chalk.cyan(`📁 ${relativePath}`));
// 각 에이전트별 결과 출력
for (const [agentName, result] of Object.entries(location.agents)) {
if (result.passed) {
console.log(chalk.green(` ✓ ${agentName}: 동기화됨`));
} else {
const errorMsg =
result.error === "content mismatch"
? "내용 불일치"
: result.error === "file not found"
? "파일 없음"
: result.error || "내용 불일치";
console.log(chalk.red(` ✗ ${agentName}: ${errorMsg}`));
}
}
// 패턴 분석 결과
if (location.diagnosis && location.diagnosis.pattern !== "all_synced") {
switch (location.diagnosis.pattern) {
case "all_outdated":
console.log(chalk.yellow(" → 패턴 감지: 모든 파일이 오래됨"));
console.log(chalk.yellow(" → 해결방법: 'agent-rules build' 실행"));
break;
case "single_diverged":
const divergedFile = location.diagnosis.diverged?.[0];
console.log(
chalk.yellow(` → 패턴 감지: ${divergedFile} 파일만 불일치`),
);
console.log(
chalk.yellow(` → AGENTS.md를 수정하려던 것이 아닌지 확인하세요`),
);
break;
case "multiple_diverged":
console.log(chalk.yellow(" → 패턴 감지: 여러 파일 불일치"));
console.log(chalk.yellow(" → 수동 검토가 필요합니다"));
break;
}
} else if (location.diagnosis?.pattern === "all_synced") {
console.log(chalk.green(" ✓ 모든 파일이 동기화되어 있습니다"));
}
console.log(""); // 위치 간 구분
}
// 전체 요약
console.log("========================================");
const failedLocations = results.locations.filter(
(loc) => loc.status === "fail",
).length;
if (results.status === "pass") {
console.log(
chalk.green(
`📊 전체 요약: ${results.totalLocations}개 위치 모두 동기화됨`,
),
);
console.log(chalk.green("✓ 검증 성공"));
} else {
console.log(
chalk.yellow(
`📊 전체 요약: ${results.totalLocations}개 위치 중 ${failedLocations}개 불일치`,
),
);
console.log(chalk.red("✗ 검증 실패"));
}
}
}