MDC 규칙을 사용하다 보면 예상대로 작동하지 않거나 성능 이슈가 발생할 수 있습니다. 이 가이드에서는 규칙 적용 상태 확인, 충돌 해결, 성능 이슈 진단 등 MDC 관련 문제를 체계적으로 해결하는 방법을 제시합니다.
1. 규칙 적용 상태 확인
규칙 적용 추적 시스템
---
description: Rule application tracking and debugging system
version: "1.2.0"
category: "debugging"
debugMode: true
tags: ["debugging", "tracking", "diagnostics"]
---
# 규칙 적용 추적 시스템
## 🔍 규칙 적용 상태 진단
### 1. 실시간 규칙 모니터링
debug/rule-tracker.ts 파일:
interface RuleApplicationEvent {
ruleId: string;
ruleName: string;
timestamp: Date;
trigger: 'auto' | 'manual' | 'glob-match' | 'agent-request';
context: {
currentFile: string;
workingDirectory: string;
userQuery?: string;
};
applied: boolean;
reason?: string;
executionTime: number;
}
class RuleApplicationTracker {
private events: RuleApplicationEvent[] = [];
private activeRules = new Set<string>();
private debugMode = false;
constructor(debugMode = false) {
this.debugMode = debugMode;
if (debugMode) {
this.enableDetailedLogging();
}
}
trackRuleApplication(event: Omit<RuleApplicationEvent, 'timestamp'>): void {
const fullEvent: RuleApplicationEvent = {
...event,
timestamp: new Date()
};
this.events.push(fullEvent);
if (fullEvent.applied) {
this.activeRules.add(fullEvent.ruleId);
}
if (this.debugMode) {
this.logRuleApplication(fullEvent);
}
// 이벤트 히스토리 제한 (메모리 관리)
if (this.events.length > 1000) {
this.events = this.events.slice(-500);
}
}
private logRuleApplication(event: RuleApplicationEvent): void {
const status = event.applied ? '✅ APPLIED' : '⏭️ SKIPPED';
const trigger = this.formatTrigger(event.trigger);
console.group(`${status} Rule: ${event.ruleName}`);
console.log(`📁 File: ${event.context.currentFile}`);
console.log(`🔧 Trigger: ${trigger}`);
console.log(`⏱️ Execution: ${event.executionTime.toFixed(2)}ms`);
if (!event.applied && event.reason) {
console.log(`❓ Reason: ${event.reason}`);
}
if (event.context.userQuery) {
console.log(`💬 Query: ${event.context.userQuery}`);
}
console.groupEnd();
}
private formatTrigger(trigger: RuleApplicationEvent['trigger']): string {
const triggers = {
'auto': '🤖 Auto Apply',
'manual': '👤 Manual (@rule)',
'glob-match': '🎯 File Pattern Match',
'agent-request': '🧠 AI Agent Request'
};
return triggers[trigger] || trigger;
}
getApplicationHistory(ruleId?: string): RuleApplicationEvent[] {
if (ruleId) {
return this.events.filter(event => event.ruleId === ruleId);
}
return [...this.events];
}
getActiveRules(): string[] {
return Array.from(this.activeRules);
}
generateDiagnosticReport(): DiagnosticReport {
const recent = this.events.slice(-50);
const applied = recent.filter(e => e.applied);
const skipped = recent.filter(e => !e.applied);
return {
summary: {
totalEvents: recent.length,
appliedRules: applied.length,
skippedRules: skipped.length,
averageExecutionTime: this.calculateAverage(applied.map(e => e.executionTime))
},
activeRules: this.getActiveRules(),
frequentlySkipped: this.getFrequentlySkippedRules(skipped),
performanceIssues: this.identifyPerformanceIssues(applied),
recommendations: this.generateRecommendations(recent)
};
}
private getFrequentlySkippedRules(skipped: RuleApplicationEvent[]): Array<{rule: string, count: number, reasons: string[]}> {
const ruleSkipCount = new Map<string, {count: number, reasons: Set<string>}>();
skipped.forEach(event => {
const existing = ruleSkipCount.get(event.ruleId) || {count: 0, reasons: new Set()};
existing.count++;
if (event.reason) existing.reasons.add(event.reason);
ruleSkipCount.set(event.ruleId, existing);
});
return Array.from(ruleSkipCount.entries())
.map(([rule, data]) => ({
rule,
count: data.count,
reasons: Array.from(data.reasons)
}))
.sort((a, b) => b.count - a.count)
.slice(0, 5);
}
private identifyPerformanceIssues(applied: RuleApplicationEvent[]): string[] {
const issues: string[] = [];
const slowRules = applied.filter(e => e.executionTime > 500);
if (slowRules.length > 0) {
issues.push(`${slowRules.length}개 규칙의 실행 시간이 500ms 초과`);
}
const averageTime = this.calculateAverage(applied.map(e => e.executionTime));
if (averageTime > 200) {
issues.push(`평균 규칙 실행 시간이 200ms 초과 (${averageTime.toFixed(2)}ms)`);
}
return issues;
}
private generateRecommendations(events: RuleApplicationEvent[]): string[] {
const recommendations: string[] = [];
const skippedRate = events.filter(e => !e.applied).length / events.length;
if (skippedRate > 0.3) {
recommendations.push('너무 많은 규칙이 건너뛰어집니다. 글롭 패턴이나 조건을 검토하세요.');
}
const slowEvents = events.filter(e => e.executionTime > 300);
if (slowEvents.length > 0) {
recommendations.push('일부 규칙의 실행 시간이 깁니다. 규칙 최적화를 고려하세요.');
}
return recommendations;
}
private calculateAverage(numbers: number[]): number {
return numbers.length > 0 ? numbers.reduce((sum, n) => sum + n, 0) / numbers.length : 0;
}
// 개발자 친화적 디버깅 인터페이스
debug = {
showLastApplied: (count = 10) => {
const applied = this.events.filter(e => e.applied).slice(-count);
console.table(applied.map(e => ({
Rule: e.ruleName,
File: e.context.currentFile.split('/').pop(),
Trigger: e.trigger,
Time: `${e.executionTime.toFixed(2)}ms`
})));
},
showSkipped: (count = 10) => {
const skipped = this.events.filter(e => !e.applied).slice(-count);
console.table(skipped.map(e => ({
Rule: e.ruleName,
File: e.context.currentFile.split('/').pop(),
Reason: e.reason || 'Unknown'
})));
},
findRule: (ruleId: string) => {
const history = this.getApplicationHistory(ruleId);
console.log(`🔍 Rule ${ruleId} 적용 히스토리:`);
console.table(history.map(e => ({
Time: e.timestamp.toLocaleTimeString(),
Applied: e.applied ? '✅' : '❌',
File: e.context.currentFile.split('/').pop(),
Reason: e.reason || '-'
})));
}
};
}
// 전역 트래커 인스턴스
const ruleTracker = new RuleApplicationTracker(
process.env.MDC_DEBUG_MODE === 'true'
);
### 2. 규칙 상태 대시보드
debug/rule-dashboard.ts:
class RuleDashboard {
private tracker: RuleApplicationTracker;
private refreshInterval?: NodeJS.Timeout;
constructor(tracker: RuleApplicationTracker) {
this.tracker = tracker;
}
startRealTimeMonitoring(intervalMs = 5000): void {
this.refreshInterval = setInterval(() => {
this.displayCurrentStatus();
}, intervalMs);
console.log('🚀 실시간 규칙 모니터링 시작됨');
}
stopRealTimeMonitoring(): void {
if (this.refreshInterval) {
clearInterval(this.refreshInterval);
this.refreshInterval = undefined;
}
}
displayCurrentStatus(): void {
console.clear();
console.log('📊 MDC 규칙 상태 대시보드');
console.log('='.repeat(50));
const report = this.tracker.generateDiagnosticReport();
// 요약 정보
console.log('\n📈 요약 통계:');
console.log(` 전체 이벤트: ${report.summary.totalEvents}`);
console.log(` 적용된 규칙: ${report.summary.appliedRules}`);
console.log(` 건너뛴 규칙: ${report.summary.skippedRules}`);
console.log(` 평균 실행 시간: ${report.summary.averageExecutionTime.toFixed(2)}ms`);
// 활성 규칙
console.log('\n⚡ 현재 활성 규칙:');
report.activeRules.forEach(rule => {
console.log(` ✅ ${rule}`);
});
// 자주 건너뛰는 규칙
if (report.frequentlySkipped.length > 0) {
console.log('\n⏭️ 자주 건너뛰는 규칙:');
report.frequentlySkipped.forEach(item => {
console.log(` ❌ ${item.rule} (${item.count}회)`);
item.reasons.forEach(reason => {
console.log(` - ${reason}`);
});
});
}
// 성능 이슈
if (report.performanceIssues.length > 0) {
console.log('\n🐌 성능 이슈:');
report.performanceIssues.forEach(issue => {
console.log(` ⚠️ ${issue}`);
});
}
// 권장사항
if (report.recommendations.length > 0) {
console.log('\n💡 권장사항:');
report.recommendations.forEach(rec => {
console.log(` 📝 ${rec}`);
});
}
console.log(`\n마지막 업데이트: ${new Date().toLocaleTimeString()}`);
}
exportDiagnostics(filename?: string): void {
const report = this.tracker.generateDiagnosticReport();
const history = this.tracker.getApplicationHistory();
const exportData = {
timestamp: new Date().toISOString(),
diagnosticReport: report,
recentHistory: history.slice(-100),
environment: {
nodeVersion: process.version,
platform: process.platform,
workingDirectory: process.cwd()
}
};
const fs = require('fs');
const exportFilename = filename || `mdc-diagnostics-${Date.now()}.json`;
fs.writeFileSync(exportFilename, JSON.stringify(exportData, null, 2));
console.log(`📄 진단 정보가 ${exportFilename}에 저장되었습니다.`);
}
}
2. 충돌 해결 가이드
규칙 간 상충 해결 전략
---
description: Rule conflict resolution strategies
version: "1.4.0"
category: "conflict-resolution"
priority: "high"
---
# 규칙 충돌 해결 전략
## ⚔️ 충돌 유형 및 해결 방법
### 1. 우선순위 충돌 감지
debug/conflict-detector.ts:
interface RuleConflict {
type: 'priority' | 'content' | 'scope' | 'timing';
rules: string[];
description: string;
severity: 'low' | 'medium' | 'high' | 'critical';
resolution: string;
}
class ConflictDetector {
private rules: Map<string, ParsedRule> = new Map();
analyzeRules(ruleFiles: string[]): RuleConflict[] {
const conflicts: RuleConflict[] = [];
// 규칙 파싱
ruleFiles.forEach(file => {
const rule = this.parseRuleFile(file);
this.rules.set(rule.id, rule);
});
// 각 충돌 유형 검사
conflicts.push(...this.detectPriorityConflicts());
conflicts.push(...this.detectContentConflicts());
conflicts.push(...this.detectScopeConflicts());
conflicts.push(...this.detectTimingConflicts());
return conflicts.sort((a, b) => this.getSeverityWeight(b.severity) - this.getSeverityWeight(a.severity));
}
private detectPriorityConflicts(): RuleConflict[] {
const conflicts: RuleConflict[] = [];
const rulesByGlob = new Map<string, ParsedRule[]>();
// 같은 글롭 패턴을 가진 규칙들 그룹화
this.rules.forEach(rule => {
rule.globs.forEach(glob => {
if (!rulesByGlob.has(glob)) {
rulesByGlob.set(glob, []);
}
rulesByGlob.get(glob)!.push(rule);
});
});
// 우선순위 충돌 검사
rulesByGlob.forEach((rules, glob) => {
if (rules.length > 1) {
const alwaysApplyRules = rules.filter(r => r.alwaysApply);
if (alwaysApplyRules.length > 1) {
conflicts.push({
type: 'priority',
rules: alwaysApplyRules.map(r => r.id),
description: `글롭 패턴 "${glob}"에 대해 여러 규칙이 alwaysApply=true로 설정됨`,
severity: 'high',
resolution: 'priority 필드를 추가하거나 하나의 규칙만 alwaysApply=true로 설정'
});
}
}
});
return conflicts;
}
private detectContentConflicts(): RuleConflict[] {
const conflicts: RuleConflict[] = [];
const contentPatterns = new Map<string, string[]>();
// 모순되는 내용 패턴 검사
this.rules.forEach(rule => {
this.extractContentDirectives(rule.content).forEach(directive => {
if (!contentPatterns.has(directive.pattern)) {
contentPatterns.set(directive.pattern, []);
}
contentPatterns.get(directive.pattern)!.push(rule.id);
});
});
// 모순되는 지시사항 검사
const contradictions = [
{ positive: 'use typescript', negative: 'avoid typescript' },
{ positive: 'prefer functional', negative: 'use class-based' },
{ positive: 'enable strict mode', negative: 'disable strict' }
];
contradictions.forEach(({ positive, negative }) => {
const positiveRules = this.findRulesWithContent(positive);
const negativeRules = this.findRulesWithContent(negative);
if (positiveRules.length > 0 && negativeRules.length > 0) {
conflicts.push({
type: 'content',
rules: [...positiveRules, ...negativeRules],
description: `모순되는 지시사항: "${positive}" vs "${negative}"`,
severity: 'medium',
resolution: '더 구체적인 범위 지정하거나 우선순위 명시'
});
}
});
return conflicts;
}
private detectScopeConflicts(): RuleConflict[] {
const conflicts: RuleConflict[] = [];
// 글롭 패턴 중복 검사
const globOverlaps = this.findGlobOverlaps();
globOverlaps.forEach(overlap => {
if (overlap.rules.length > 1) {
const hasConflictingDirectives = this.checkForConflictingDirectives(overlap.rules);
if (hasConflictingDirectives) {
conflicts.push({
type: 'scope',
rules: overlap.rules.map(r => r.id),
description: `글롭 패턴 중복: ${overlap.pattern}`,
severity: 'medium',
resolution: '글롭 패턴을 더 구체적으로 지정하거나 규칙 병합'
});
}
}
});
return conflicts;
}
resolveConflict(conflict: RuleConflict): ConflictResolution {
switch (conflict.type) {
case 'priority':
return this.resolvePriorityConflict(conflict);
case 'content':
return this.resolveContentConflict(conflict);
case 'scope':
return this.resolveScopeConflict(conflict);
case 'timing':
return this.resolveTimingConflict(conflict);
default:
return { success: false, message: 'Unknown conflict type' };
}
}
private resolvePriorityConflict(conflict: RuleConflict): ConflictResolution {
const suggestions = [
'1. 가장 중요한 규칙에만 alwaysApply=true 설정',
'2. priority 필드 추가 (높은 숫자 = 높은 우선순위)',
'3. 글롭 패턴을 더 구체적으로 분리'
];
return {
success: true,
message: '우선순위 충돌 해결 방법',
suggestions,
example: `
---
priority: 10 # 높은 우선순위
alwaysApply: true
---
`
};
}
generateConflictReport(conflicts: RuleConflict[]): string {
let report = '# MDC 규칙 충돌 리포트\n\n';
if (conflicts.length === 0) {
report += '✅ 충돌이 발견되지 않았습니다.\n';
return report;
}
report += `⚠️ 총 ${conflicts.length}개의 충돌이 발견되었습니다.\n\n`;
conflicts.forEach((conflict, index) => {
const severityEmoji = {
low: '🟢',
medium: '🟡',
high: '🟠',
critical: '🔴'
}[conflict.severity];
report += `## ${index + 1}. ${severityEmoji} ${conflict.type.toUpperCase()} 충돌\n\n`;
report += `**설명**: ${conflict.description}\n\n`;
report += `**관련 규칙**: ${conflict.rules.join(', ')}\n\n`;
report += `**해결 방법**: ${conflict.resolution}\n\n`;
report += '---\n\n';
});
return report;
}
}
### 2. 자동 충돌 해결
debug/auto-resolver.ts:
class AutoConflictResolver {
private detector: ConflictDetector;
private resolutionStrategies: Map<string, ResolutionStrategy>;
constructor() {
this.detector = new ConflictDetector();
this.setupResolutionStrategies();
}
private setupResolutionStrategies(): void {
this.resolutionStrategies = new Map([
['priority_conflict', {
canAutoResolve: true,
resolver: this.resolvePriorityConflictAuto.bind(this)
}],
['scope_overlap', {
canAutoResolve: true,
resolver: this.resolveScopeOverlapAuto.bind(this)
}],
['content_contradiction', {
canAutoResolve: false,
resolver: this.suggestContentResolution.bind(this)
}]
]);
}
async resolveConflictsAutomatically(ruleFiles: string[]): Promise<ResolutionResult> {
const conflicts = this.detector.analyzeRules(ruleFiles);
const results: ResolutionResult = {
resolved: [],
requiresManualIntervention: [],
failed: []
};
for (const conflict of conflicts) {
try {
const strategy = this.resolutionStrategies.get(conflict.type);
if (strategy?.canAutoResolve) {
const resolution = await strategy.resolver(conflict);
if (resolution.success) {
results.resolved.push(conflict);
} else {
results.failed.push({ conflict, error: resolution.message });
}
} else {
results.requiresManualIntervention.push(conflict);
}
} catch (error) {
results.failed.push({
conflict,
error: error instanceof Error ? error.message : 'Unknown error'
});
}
}
return results;
}
private async resolvePriorityConflictAuto(conflict: RuleConflict): Promise<{success: boolean, message: string}> {
// 우선순위 자동 할당 로직
const rules = conflict.rules.map(id => this.detector.rules.get(id)!);
// 규칙 특성에 따른 우선순위 자동 결정
rules.forEach((rule, index) => {
const priority = this.calculateRulePriority(rule);
this.updateRulePriority(rule.id, priority);
});
return {
success: true,
message: `${conflict.rules.length}개 규칙의 우선순위가 자동으로 조정되었습니다.`
};
}
private calculateRulePriority(rule: ParsedRule): number {
let priority = 5; // 기본 우선순위
// 보안 관련 규칙은 높은 우선순위
if (rule.content.toLowerCase().includes('security') ||
rule.content.toLowerCase().includes('auth')) {
priority += 5;
}
// 타입 체크 관련 규칙
if (rule.content.toLowerCase().includes('typescript') ||
rule.content.toLowerCase().includes('type')) {
priority += 3;
}
// 글롭 패턴 특수성에 따른 우선순위
const specificityScore = this.calculateGlobSpecificity(rule.globs);
priority += specificityScore;
return Math.min(priority, 10); // 최대 우선순위 10
}
private calculateGlobSpecificity(globs: string[]): number {
// 더 구체적인 글롭 패턴일수록 높은 점수
return globs.reduce((score, glob) => {
const parts = glob.split('/').length;
const hasExtension = glob.includes('.');
const hasNegation = glob.startsWith('!');
return score + parts + (hasExtension ? 2 : 0) + (hasNegation ? 1 : 0);
}, 0) / globs.length;
}
}
3. 성능 이슈 진단
느린 응답 시간 개선 방법
---
description: Performance issue diagnosis and resolution
version: "2.0.0"
category: "performance-debugging"
---
# 성능 이슈 진단 및 해결
## 🐌 느린 응답 시간 분석
### 1. 성능 프로파일러
debug/performance-profiler.ts:
interface PerformanceProfile {
ruleId: string;
phases: {
parsing: number;
loading: number;
processing: number;
application: number;
};
memoryUsage: {
before: number;
after: number;
peak: number;
};
contextSize: {
inputTokens: number;
outputTokens: number;
compressionRatio: number;
};
}
class PerformanceProfiler {
private profiles: Map<string, PerformanceProfile> = new Map();
private isProfileActive = false;
startProfiling(): void {
this.isProfileActive = true;
console.log('🚀 성능 프로파일링 시작됨');
}
stopProfiling(): PerformanceReport {
this.isProfileActive = false;
const report = this.generatePerformanceReport();
console.log('✅ 성능 프로파일링 완료');
return report;
}
profileRule<T>(ruleId: string, operation: () => Promise<T>): Promise<T> {
if (!this.isProfileActive) {
return operation();
}
return this.measurePerformance(ruleId, operation);
}
private async measurePerformance<T>(ruleId: string, operation: () => Promise<T>): Promise<T> {
const startTime = performance.now();
const startMemory = this.getMemoryUsage();
let parseTime = 0;
let loadTime = 0;
let processTime = 0;
let applyTime = 0;
let peakMemory = startMemory;
try {
// 파싱 단계
const parseStart = performance.now();
// 실제 파싱 로직은 operation 내부에서 처리
const parseEnd = performance.now();
parseTime = parseEnd - parseStart;
// 메모리 모니터링
const memoryMonitor = setInterval(() => {
const currentMemory = this.getMemoryUsage();
peakMemory = Math.max(peakMemory, currentMemory);
}, 10);
// 메인 작업 실행
const result = await operation();
clearInterval(memoryMonitor);
const endTime = performance.now();
const endMemory = this.getMemoryUsage();
// 프로파일 저장
this.profiles.set(ruleId, {
ruleId,
phases: {
parsing: parseTime,
loading: loadTime,
processing: processTime,
application: applyTime
},
memoryUsage: {
before: startMemory,
after: endMemory,
peak: peakMemory
},
contextSize: {
inputTokens: 0, // 실제 측정 필요
outputTokens: 0,
compressionRatio: 0
}
});
return result;
} catch (error) {
console.error(`❌ 규칙 ${ruleId} 성능 측정 중 오류:`, error);
throw error;
}
}
private getMemoryUsage(): number {
return process.memoryUsage().heapUsed;
}
analyzeBottlenecks(): BottleneckAnalysis {
const profiles = Array.from(this.profiles.values());
const bottlenecks: BottleneckAnalysis = {
slowestRules: this.findSlowestRules(profiles),
memoryHogs: this.findMemoryIntensiveRules(profiles),
inefficientPatterns: this.findInefficientPatterns(profiles),
recommendations: []
};
bottlenecks.recommendations = this.generatePerformanceRecommendations(bottlenecks);
return bottlenecks;
}
private findSlowestRules(profiles: PerformanceProfile[]): Array<{ruleId: string, totalTime: number, breakdown: any}> {
return profiles
.map(profile => ({
ruleId: profile.ruleId,
totalTime: Object.values(profile.phases).reduce((sum, time) => sum + time, 0),
breakdown: profile.phases
}))
.sort((a, b) => b.totalTime - a.totalTime)
.slice(0, 10);
}
private findMemoryIntensiveRules(profiles: PerformanceProfile[]): Array<{ruleId: string, memoryDelta: number, peakUsage: number}> {
return profiles
.map(profile => ({
ruleId: profile.ruleId,
memoryDelta: profile.memoryUsage.after - profile.memoryUsage.before,
peakUsage: profile.memoryUsage.peak
}))
.filter(item => item.memoryDelta > 1024 * 1024) // 1MB 이상
.sort((a, b) => b.memoryDelta - a.memoryDelta);
}
private generatePerformanceRecommendations(analysis: BottleneckAnalysis): string[] {
const recommendations: string[] = [];
if (analysis.slowestRules.length > 0) {
const slowest = analysis.slowestRules[0];
if (slowest.totalTime > 1000) { // 1초 이상
recommendations.push(`규칙 "${slowest.ruleId}"가 ${slowest.totalTime.toFixed(2)}ms로 매우 느립니다. 최적화가 필요합니다.`);
}
}
if (analysis.memoryHogs.length > 0) {
recommendations.push(`${analysis.memoryHogs.length}개 규칙이 과도한 메모리를 사용합니다. 내용을 압축하거나 분할을 고려하세요.`);
}
return recommendations;
}
exportProfile(filename?: string): void {
const profiles = Array.from(this.profiles.values());
const analysis = this.analyzeBottlenecks();
const exportData = {
timestamp: new Date().toISOString(),
totalRules: profiles.length,
profiles,
analysis,
systemInfo: {
nodeVersion: process.version,
platform: process.platform,
memory: process.memoryUsage()
}
};
const fs = require('fs');
const exportFilename = filename || `mdc-performance-profile-${Date.now()}.json`;
fs.writeFileSync(exportFilename, JSON.stringify(exportData, null, 2));
console.log(`📊 성능 프로파일이 ${exportFilename}에 저장되었습니다.`);
}
}
### 2. 실시간 성능 모니터링
debug/real-time-monitor.ts:
class RealTimePerformanceMonitor {
private metrics: PerformanceMetric[] = [];
private alerts: PerformanceAlert[] = [];
private thresholds: PerformanceThresholds;
private monitoringActive = false;
constructor() {
this.thresholds = {
responseTime: 2000, // 2초
memoryUsage: 100 * 1024 * 1024, // 100MB
ruleLoadTime: 500, // 500ms
contextBuildTime: 300 // 300ms
};
}
startMonitoring(): void {
this.monitoringActive = true;
// 주기적 모니터링
setInterval(() => {
if (this.monitoringActive) {
this.collectMetrics();
this.checkThresholds();
}
}, 1000);
console.log('📊 실시간 성능 모니터링 시작됨');
}
stopMonitoring(): void {
this.monitoringActive = false;
console.log('⏹️ 실시간 성능 모니터링 중지됨');
}
private collectMetrics(): void {
const metric: PerformanceMetric = {
timestamp: Date.now(),
memoryUsage: process.memoryUsage().heapUsed,
cpuUsage: process.cpuUsage(),
activeRules: this.getActiveRulesCount(),
pendingOperations: this.getPendingOperationsCount()
};
this.metrics.push(metric);
// 메트릭 히스토리 제한
if (this.metrics.length > 1000) {
this.metrics = this.metrics.slice(-500);
}
}
private checkThresholds(): void {
const latestMetric = this.metrics[this.metrics.length - 1];
if (!latestMetric) return;
// 메모리 사용량 체크
if (latestMetric.memoryUsage > this.thresholds.memoryUsage) {
this.addAlert({
type: 'memory',
severity: 'high',
message: `메모리 사용량이 임계값을 초과했습니다: ${(latestMetric.memoryUsage / 1024 / 1024).toFixed(2)}MB`,
timestamp: Date.now(),
metric: latestMetric
});
}
// 응답 시간 트렌드 분석
const recentMetrics = this.metrics.slice(-10);
const avgResponseTime = this.calculateAverageResponseTime(recentMetrics);
if (avgResponseTime > this.thresholds.responseTime) {
this.addAlert({
type: 'response_time',
severity: 'medium',
message: `평균 응답 시간이 느림: ${avgResponseTime.toFixed(2)}ms`,
timestamp: Date.now(),
metric: latestMetric
});
}
}
private addAlert(alert: PerformanceAlert): void {
this.alerts.push(alert);
// 심각도에 따른 로깅
switch (alert.severity) {
case 'critical':
console.error('🔴 CRITICAL:', alert.message);
break;
case 'high':
console.warn('🟠 HIGH:', alert.message);
break;
case 'medium':
console.warn('🟡 MEDIUM:', alert.message);
break;
case 'low':
console.info('🟢 LOW:', alert.message);
break;
}
// 알림 히스토리 제한
if (this.alerts.length > 100) {
this.alerts = this.alerts.slice(-50);
}
}
generateRealTimeReport(): RealTimeReport {
const recentMetrics = this.metrics.slice(-60); // 최근 1분
const recentAlerts = this.alerts.slice(-10);
return {
status: this.determineOverallStatus(recentMetrics, recentAlerts),
currentMetrics: this.metrics[this.metrics.length - 1],
trends: this.analyzeTrends(recentMetrics),
recentAlerts,
recommendations: this.generateRealtimeRecommendations(recentMetrics, recentAlerts)
};
}
private determineOverallStatus(metrics: PerformanceMetric[], alerts: PerformanceAlert[]): 'healthy' | 'warning' | 'critical' {
const criticalAlerts = alerts.filter(a => a.severity === 'critical');
const highAlerts = alerts.filter(a => a.severity === 'high');
if (criticalAlerts.length > 0) return 'critical';
if (highAlerts.length > 2) return 'warning';
// 메트릭 기반 상태 판단
const latestMetric = metrics[metrics.length - 1];
if (latestMetric && latestMetric.memoryUsage > this.thresholds.memoryUsage * 0.8) {
return 'warning';
}
return 'healthy';
}
// 개발자 도구 인터페이스
devTools = {
showCurrentStatus: () => {
const report = this.generateRealTimeReport();
console.log('📊 현재 성능 상태:', report.status);
console.log('💾 메모리:', `${(report.currentMetrics.memoryUsage / 1024 / 1024).toFixed(2)}MB`);
console.log('⚡ 활성 규칙:', report.currentMetrics.activeRules);
if (report.recentAlerts.length > 0) {
console.log('🚨 최근 알림:');
report.recentAlerts.forEach(alert => {
console.log(` ${alert.type}: ${alert.message}`);
});
}
},
showTrends: () => {
const report = this.generateRealTimeReport();
console.log('📈 성능 트렌드:');
Object.entries(report.trends).forEach(([key, trend]) => {
const direction = trend > 0 ? '⬆️' : trend < 0 ? '⬇️' : '➡️';
console.log(` ${key}: ${direction} ${trend.toFixed(2)}%`);
});
},
setThreshold: (type: keyof PerformanceThresholds, value: number) => {
this.thresholds[type] = value;
console.log(`⚙️ ${type} 임계값이 ${value}으로 설정되었습니다.`);
}
};
}
4. 일반적인 문제 해결 방법
자주 발생하는 이슈와 해결책
---
description: Common MDC issues and their solutions
version: "1.8.0"
category: "troubleshooting"
---
# 일반적인 MDC 문제 해결 가이드
## 🔧 자주 발생하는 문제들
### 1. 규칙이 적용되지 않는 경우
#### 문제 진단 체크리스트
scripts/diagnose-rule-issues.sh:
#!/bin/bash
echo "🔍 MDC 규칙 문제 진단 시작..."
# 1. 규칙 파일 존재 확인
echo "📁 규칙 파일 확인 중..."
if [ ! -d ".cursor/rules" ]; then
echo "❌ .cursor/rules 디렉터리가 존재하지 않습니다."
echo "💡 해결: mkdir -p .cursor/rules"
exit 1
fi
rule_count=$(find .cursor/rules -name "*.mdc" | wc -l)
echo "📊 발견된 규칙 파일: ${rule_count}개"
if [ $rule_count -eq 0 ]; then
echo "⚠️ 규칙 파일이 없습니다."
echo "💡 해결: .mdc 파일을 .cursor/rules/ 디렉터리에 추가하세요."
fi
# 2. 규칙 구문 검증
echo "✅ 규칙 구문 검증 중..."
for rule_file in .cursor/rules/*.mdc; do
if [ -f "$rule_file" ]; then
# 프론트매터 검증
if ! head -10 "$rule_file" | grep -q "^---$"; then
echo "❌ ${rule_file}: 프론트매터가 누락되었습니다."
fi
# description 필드 확인
if ! grep -q "^description:" "$rule_file"; then
echo "⚠️ ${rule_file}: description 필드가 권장됩니다."
fi
# 글롭 패턴 확인
if grep -q "^globs:" "$rule_file"; then
echo "✅ ${rule_file}: 글롭 패턴 발견"
fi
fi
done
# 3. 파일 매칭 테스트
echo "🎯 현재 파일의 글롭 매칭 테스트..."
current_file=$(pwd | xargs basename)
echo "현재 작업 디렉터리: $current_file"
# 4. 권한 확인
echo "🔐 파일 권한 확인..."
ls -la .cursor/rules/*.mdc 2>/dev/null | head -5
echo "✅ 진단 완료"
#### 해결 방법별 가이드
debug/rule-troubleshooter.ts:
class RuleTroubleshooter {
async diagnoseRuleIssue(ruleId: string): Promise<DiagnosisResult> {
const checks: DiagnosisCheck[] = [
this.checkRuleFileExists,
this.checkRuleSyntax,
this.checkGlobPatterns,
this.checkRuleConditions,
this.checkRulePriority
];
const results: DiagnosisResult = {
ruleId,
status: 'unknown',
issues: [],
solutions: []
};
for (const check of checks) {
try {
const result = await check.call(this, ruleId);
if (!result.passed) {
results.issues.push(result.issue);
results.solutions.push(...result.solutions);
}
} catch (error) {
results.issues.push(`검사 중 오류 발생: ${error}`);
}
}
results.status = results.issues.length === 0 ? 'healthy' : 'issues_found';
return results;
}
private async checkRuleFileExists(ruleId: string): Promise<CheckResult> {
const possiblePaths = [
`.cursor/rules/${ruleId}.mdc`,
`.cursor/rules/${ruleId}/index.mdc`,
`rules/${ruleId}.mdc`
];
const fs = require('fs').promises;
for (const path of possiblePaths) {
try {
await fs.access(path);
return { passed: true };
} catch {}
}
return {
passed: false,
issue: `규칙 파일을 찾을 수 없음: ${ruleId}`,
solutions: [
'파일 경로 확인: .cursor/rules/ 디렉터리에 위치해야 함',
'파일 확장자 확인: .mdc 확장자 사용',
'파일명과 규칙 ID 일치 확인'
]
};
}
private async checkRuleSyntax(ruleId: string): Promise<CheckResult> {
try {
const ruleContent = await this.loadRuleContent(ruleId);
const frontMatterMatch = ruleContent.match(/^---\s*\n([\s\S]*?)\n---/);
if (!frontMatterMatch) {
return {
passed: false,
issue: '프론트매터(---) 구문이 올바르지 않음',
solutions: [
'파일 시작 부분에 --- 추가',
'프론트매터 종료 부분에 --- 추가',
'YAML 구문 검증'
]
};
}
// YAML 파싱 검증
const yaml = require('js-yaml');
try {
yaml.load(frontMatterMatch[1]);
} catch (yamlError) {
return {
passed: false,
issue: `YAML 구문 오류: ${yamlError.message}`,
solutions: [
'YAML 구문 검증기로 확인',
'들여쓰기 확인 (공백 사용)',
'특수 문자 이스케이프 처리'
]
};
}
return { passed: true };
} catch (error) {
return {
passed: false,
issue: `규칙 파일 읽기 실패: ${error}`,
solutions: ['파일 권한 확인', '파일 경로 재확인']
};
}
}
private async checkGlobPatterns(ruleId: string): Promise<CheckResult> {
try {
const rule = await this.parseRule(ruleId);
if (rule.globs && rule.globs.length > 0) {
const invalidGlobs = rule.globs.filter(glob => !this.isValidGlob(glob));
if (invalidGlobs.length > 0) {
return {
passed: false,
issue: `유효하지 않은 글롭 패턴: ${invalidGlobs.join(', ')}`,
solutions: [
'글롭 패턴 구문 확인',
'경로 구분자 통일 (/ 사용)',
'와일드카드 사용법 검토'
]
};
}
// 현재 파일과 매칭 테스트
const currentFile = this.getCurrentFilePath();
const matches = rule.globs.some(glob => this.matchesGlob(currentFile, glob));
if (!matches && rule.alwaysApply !== true) {
return {
passed: false,
issue: `현재 파일이 글롭 패턴과 일치하지 않음: ${currentFile}`,
solutions: [
'글롭 패턴 범위 확장',
'alwaysApply: true 설정 고려',
'현재 파일 경로 확인'
]
};
}
}
return { passed: true };
} catch (error) {
return {
passed: false,
issue: `글롭 패턴 검사 실패: ${error}`,
solutions: ['규칙 파일 구문 확인']
};
}
}
generateTroubleshootingGuide(issues: DiagnosisResult[]): string {
let guide = '# MDC 트러블슈팅 가이드\n\n';
if (issues.length === 0) {
guide += '✅ 모든 규칙이 정상적으로 작동하고 있습니다.\n';
return guide;
}
guide += '## 🔧 발견된 문제점들\n\n';
issues.forEach((issue, index) => {
guide += `### ${index + 1}. 규칙 "${issue.ruleId}"\n\n`;
guide += `**상태**: ${issue.status === 'healthy' ? '✅ 정상' : '❌ 문제 있음'}\n\n`;
if (issue.issues.length > 0) {
guide += '**문제점**:\n';
issue.issues.forEach(problem => {
guide += `- ${problem}\n`;
});
guide += '\n';
}
if (issue.solutions.length > 0) {
guide += '**해결 방법**:\n';
issue.solutions.forEach(solution => {
guide += `- ${solution}\n`;
});
guide += '\n';
}
guide += '---\n\n';
});
guide += this.generateQuickFixSection(issues);
return guide;
}
private generateQuickFixSection(issues: DiagnosisResult[]): string {
let quickFix = '## ⚡ 빠른 해결 방법\n\n';
const commonIssues = this.identifyCommonIssues(issues);
if (commonIssues.missingFrontMatter > 0) {
quickFix += '### 프론트매터 누락\n';
quickFix += '모든 .mdc 파일에 프론트매터 추가:\n';
quickFix += ' find .cursor/rules -name "*.mdc" -exec sed -i "1i---\\ndescription: \\"Rule description\\"\\n---\\n" {} +\n\n';
}
if (commonIssues.invalidGlobs > 0) {
quickFix += '### 글롭 패턴 수정\n';
quickFix += '일반적인 글롭 패턴 예시:\n';
quickFix += ' globs: ["src/**/*.{ts,tsx,js,jsx}"]\n\n';
}
return quickFix;
}
}
### 2. 성능 저하 해결
## 성능 저하 시 체크포인트
### 즉시 확인할 사항
1. **활성 규칙 수**: 20개 이상이면 과도함
2. **규칙 파일 크기**: 각 파일 500줄 이하 권장
3. **메모리 사용량**: 50MB 이상이면 최적화 필요
4. **글롭 패턴 복잡도**: 과도하게 복잡한 패턴 확인
### 성능 개선 스크립트
scripts/optimize-rules.sh:
#!/bin/bash
echo "⚡ MDC 규칙 최적화 시작..."
# 큰 규칙 파일 찾기
echo "📊 큰 규칙 파일 분석 중..."
find .cursor/rules -name "*.mdc" -exec wc -l {} + | sort -nr | head -10
# 사용되지 않는 규칙 찾기
echo "🗑️ 미사용 규칙 정리 중..."
unused_rules=()
for rule in .cursor/rules/*.mdc; do
rule_name=$(basename "$rule" .mdc)
if ! grep -r "@$rule_name" src/ &>/dev/null; then
unused_rules+=("$rule")
fi
done
if [ ${#unused_rules[@]} -gt 0 ]; then
echo "⚠️ 미사용 규칙 발견:"
printf '%s\n' "${unused_rules[@]}"
fi
echo "✅ 최적화 분석 완료"
5. 디버깅 도구 모음
통합 디버깅 인터페이스
debug/mdc-debugger.ts:
class MDCDebugger {
private tracker: RuleApplicationTracker;
private profiler: PerformanceProfiler;
private monitor: RealTimePerformanceMonitor;
private troubleshooter: RuleTroubleshooter;
private conflictDetector: ConflictDetector;
constructor() {
this.tracker = new RuleApplicationTracker(true);
this.profiler = new PerformanceProfiler();
this.monitor = new RealTimePerformanceMonitor();
this.troubleshooter = new RuleTroubleshooter();
this.conflictDetector = new ConflictDetector();
}
// 통합 진단 실행
async runFullDiagnosis(): Promise<ComprehensiveDiagnosis> {
console.log('🔍 MDC 종합 진단 시작...');
const diagnosis: ComprehensiveDiagnosis = {
timestamp: new Date().toISOString(),
ruleApplication: this.tracker.generateDiagnosticReport(),
performance: this.profiler.analyzeBottlenecks(),
conflicts: this.conflictDetector.analyzeRules(this.getAllRuleFiles()),
troubleshooting: await this.runTroubleshootingChecks(),
recommendations: []
};
diagnosis.recommendations = this.generateComprehensiveRecommendations(diagnosis);
console.log('✅ 종합 진단 완료');
return diagnosis;
}
// 대화형 디버깅 세션
startInteractiveSession(): void {
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
console.log('🔧 MDC 대화형 디버깅 세션 시작');
console.log('사용 가능한 명령어:');
console.log(' status - 현재 상태 표시');
console.log(' rules - 활성 규칙 목록');
console.log(' profile - 성능 프로파일링 시작/중지');
console.log(' conflicts - 규칙 충돌 검사');
console.log(' help - 도움말');
console.log(' exit - 종료');
const processCommand = (command: string) => {
const [cmd, ...args] = command.trim().split(' ');
switch (cmd.toLowerCase()) {
case 'status':
this.showStatus();
break;
case 'rules':
this.showActiveRules();
break;
case 'profile':
this.toggleProfiling(args[0]);
break;
case 'conflicts':
this.checkConflicts();
break;
case 'debug':
this.debugRule(args[0]);
break;
case 'help':
this.showHelp();
break;
case 'exit':
console.log('👋 디버깅 세션 종료');
rl.close();
return;
default:
console.log(`❓ 알 수 없는 명령어: ${cmd}`);
console.log('help를 입력하여 사용 가능한 명령어를 확인하세요.');
}
rl.prompt();
};
rl.setPrompt('mdc-debug> ');
rl.prompt();
rl.on('line', processCommand);
}
private showStatus(): void {
console.log('\n📊 현재 MDC 상태:');
const report = this.tracker.generateDiagnosticReport();
console.log(` 활성 규칙: ${report.activeRules.length}개`);
console.log(` 최근 적용: ${report.summary.appliedRules}개`);
console.log(` 건너뛴 규칙: ${report.summary.skippedRules}개`);
console.log(` 평균 실행 시간: ${report.summary.averageExecutionTime.toFixed(2)}ms`);
if (report.performanceIssues.length > 0) {
console.log('\n🐌 성능 이슈:');
report.performanceIssues.forEach(issue => {
console.log(` ⚠️ ${issue}`);
});
}
}
private async debugRule(ruleId: string): Promise<void> {
if (!ruleId) {
console.log('❓ 사용법: debug <rule_id>');
return;
}
console.log(`🔍 규칙 "${ruleId}" 디버깅 중...`);
const diagnosis = await this.troubleshooter.diagnoseRuleIssue(ruleId);
console.log(`\n📋 진단 결과:`);
console.log(` 상태: ${diagnosis.status}`);
if (diagnosis.issues.length > 0) {
console.log('\n❌ 발견된 문제:');
diagnosis.issues.forEach(issue => {
console.log(` • ${issue}`);
});
}
if (diagnosis.solutions.length > 0) {
console.log('\n💡 해결 방법:');
diagnosis.solutions.forEach(solution => {
console.log(` • ${solution}`);
});
}
}
// 디버깅 리포트 생성
generateDebugReport(): string {
const diagnosis = this.runFullDiagnosis();
return `
# MDC 디버깅 리포트
생성 시간: ${new Date().toLocaleString()}
## 요약
- 활성 규칙: ${diagnosis.ruleApplication.activeRules.length}개
- 성능 이슈: ${diagnosis.performance.slowestRules.length}개
- 충돌: ${diagnosis.conflicts.length}개
## 권장사항
${diagnosis.recommendations.map(rec => `- ${rec}`).join('\n')}
## 상세 분석
[상세 내용...]
`.trim();
}
}
// 전역 디버거 인스턴스
const mdcDebugger = new MDCDebugger();
// CLI에서 사용할 수 있는 전역 함수들
global.mdcDebug = {
status: () => mdcDebugger.tracker.debug.showLastApplied(),
conflicts: () => mdcDebugger.checkConflicts(),
profile: () => mdcDebugger.profiler.startProfiling(),
interactive: () => mdcDebugger.startInteractiveSession()
};
이 종합적인 디버깅 및 트러블슈팅 가이드를 통해 MDC 규칙 관련 문제를 체계적으로 진단하고 해결할 수 있습니다. 문제 발생 시 단계별로 접근하여 원인을 파악하고 최적의 해결책을 적용해보시기 바랍니다.