creatrip-agent-rules-builder
Version:
Unified converter for AI coding agent rules across Cursor, Windsurf, and Claude
258 lines • 8.87 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyAgents = verifyAgents;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const comparator_1 = require("./comparator");
const parser_1 = require("../parser");
const AGENTS = [
{
name: "cursor",
type: "cursor-mdc",
getPath: (baseDir, config) => {
const filename = config.cursor?.filename || "rules";
return path.join(baseDir, ".cursor", "rules", `${filename}.mdc`);
},
},
{
name: "windsurf",
type: "standard",
getPath: (baseDir) => path.join(baseDir, ".windsurfrules"),
},
{
name: "claude",
type: "standard",
getPath: (baseDir) => path.join(baseDir, "CLAUDE.md"),
},
];
async function verifyAgent(agentInfo, sourcePath, baseDir) {
try {
const parsedContent = (0, parser_1.parseAgentRulesFile)(sourcePath);
const targetPath = agentInfo.getPath(baseDir, parsedContent.config);
if (!fs.existsSync(targetPath)) {
return {
agent: agentInfo.name,
passed: false,
error: "file not found",
};
}
const targetContent = fs.readFileSync(targetPath, "utf8");
let processedTarget = targetContent;
if (agentInfo.type === "cursor-mdc") {
processedTarget = (0, comparator_1.extractRulesFromMdc)(targetContent);
}
const isEqual = (0, comparator_1.compareContent)(parsedContent.rules, processedTarget);
return {
agent: agentInfo.name,
passed: isEqual,
error: isEqual ? undefined : "content mismatch",
};
}
catch (error) {
return {
agent: agentInfo.name,
passed: false,
error: error instanceof Error ? error.message : "unknown error",
};
}
}
async function verifyLocation(locationPath) {
const sourcePath = path.join(locationPath, "AGENTS.md");
if (!fs.existsSync(sourcePath)) {
throw new Error(`Source file not found: ${sourcePath}`);
}
const results = await Promise.all(AGENTS.map((agent) => verifyAgent(agent, sourcePath, locationPath)));
const location = {
path: locationPath,
status: "pass",
agents: {},
summary: {
total: results.length,
passed: 0,
failed: 0,
},
};
const failedAgents = [];
for (const result of results) {
location.agents[result.agent] = {
passed: result.passed,
error: result.error,
};
if (result.passed) {
location.summary.passed++;
}
else {
location.summary.failed++;
location.status = "fail";
failedAgents.push(result.agent);
}
}
// 패턴 분석 및 diagnosis 추가
const failedCount = failedAgents.length;
if (failedCount === 0) {
location.diagnosis = {
pattern: "all_synced",
action: "none",
};
}
else if (failedCount === results.length) {
location.diagnosis = {
pattern: "all_outdated",
action: "build",
};
}
else if (failedCount === 1) {
location.diagnosis = {
pattern: "single_diverged",
action: "review",
diverged: failedAgents,
};
}
else {
location.diagnosis = {
pattern: "multiple_diverged",
action: "manual",
diverged: failedAgents,
};
}
return location;
}
function findAgentRulesFiles(dir) {
const gitignorePath = path.join(dir, ".gitignore");
let gitignorePatterns = [];
if (fs.existsSync(gitignorePath)) {
const gitignoreContent = fs.readFileSync(gitignorePath, "utf8");
gitignorePatterns = gitignoreContent
.split("\n")
.map((line) => line.trim())
.filter((line) => line && !line.startsWith("#"));
}
const defaultIgnorePatterns = [
"node_modules",
".git",
"dist",
"build",
"out",
".next",
".nuxt",
"coverage",
".nyc_output",
];
const allIgnorePatterns = [
...new Set([...defaultIgnorePatterns, ...gitignorePatterns]),
];
function shouldIgnoreDir(dirPath) {
const dirName = path.basename(dirPath);
const relativePath = path.relative(dir, dirPath);
return allIgnorePatterns.some((pattern) => {
if (pattern.startsWith("/") && pattern.endsWith("/")) {
const cleanPattern = pattern.slice(1, -1);
return (relativePath === cleanPattern ||
relativePath.startsWith(cleanPattern + "/"));
}
if (pattern.startsWith("/")) {
const cleanPattern = pattern.slice(1);
return (relativePath === cleanPattern ||
relativePath.startsWith(cleanPattern + "/"));
}
if (pattern.endsWith("/")) {
const cleanPattern = pattern.slice(0, -1);
return (dirName === cleanPattern ||
relativePath === cleanPattern ||
relativePath.startsWith(cleanPattern + "/"));
}
return dirName === pattern || relativePath === pattern;
});
}
function searchRecursively(currentDir) {
const results = [];
try {
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(currentDir, entry.name);
if (entry.isDirectory()) {
if (!shouldIgnoreDir(fullPath)) {
results.push(...searchRecursively(fullPath));
}
}
else if (entry.name === "AGENTS.md") {
results.push(path.dirname(fullPath));
}
}
}
catch (error) {
// 권한 문제 등으로 읽을 수 없는 디렉토리는 무시
}
return results;
}
return searchRecursively(dir);
}
async function verifyAgents(rootPath, outputFormat, recursive = false) {
let locations = [];
if (recursive) {
// 재귀 모드: 여러 AGENTS.md 파일 찾기
const agentRulesPaths = findAgentRulesFiles(rootPath);
if (agentRulesPaths.length === 0) {
throw new Error(`No AGENTS.md files found in ${rootPath}`);
}
for (const locationPath of agentRulesPaths) {
try {
const result = await verifyLocation(locationPath);
locations.push(result);
}
catch (error) {
// 개별 위치 오류는 스킵하고 계속
console.error(`Error verifying ${locationPath}: ${error}`);
}
}
}
else {
// 단일 디렉토리 모드
const result = await verifyLocation(rootPath);
locations = [result];
}
// 전체 상태 계산
const overallStatus = locations.some((loc) => loc.status === "fail")
? "fail"
: "pass";
return {
status: overallStatus,
locations,
totalLocations: locations.length,
timestamp: new Date().toISOString(),
};
}
//# sourceMappingURL=index.js.map