github-mcp-auto-git
Version:
GitHub MCP Auto Git v3.0 - メモリ効率化・統合MCP・モジュール化完了の完全自動Git操作システム
617 lines • 26.4 kB
JavaScript
/**
* Be Lazy Checker
* 効率性確認、重複排除、自動化機会検出
*/
import { promises as fs } from 'fs';
import { join } from 'path';
export class BeLazyChecker {
constructor(workingDir, config) {
this.performanceHistory = new Map();
this.operationPatterns = new Map();
this.workingDir = workingDir;
this.config = config;
}
/**
* Be Lazy原則の効率性監査
*/
async performEfficiencyAudit(context) {
if (!this.config.enabled) {
return this.getDisabledResult();
}
try {
console.log('🦥 Be Lazy Checker 実行中...');
// 各分析を並列実行
const [performance, duplication, automation, cache, resource] = await Promise.all([
this.analyzePerformance(context?.operation || 'general'),
this.detectDuplicateOperations(context?.files || []),
this.identifyAutomationOpportunities(context),
this.evaluateCaching(),
this.optimizeResourceUsage()
]);
const violations = this.analyzeEfficiencyResults(performance, duplication, automation, cache, resource);
const score = this.calculateEfficiencyScore(performance, duplication, automation, cache, resource);
const recommendations = this.generateEfficiencyRecommendations(violations);
console.log(`✅ Be Lazy チェック完了 (スコア: ${score}/100)`);
return {
score,
violations,
recommendations,
details: {
performance,
duplication,
automation,
cache,
resource
}
};
}
catch (error) {
console.error('❌ Be Lazy Checker エラー:', error);
return this.getErrorResult(error);
}
}
/**
* パフォーマンス分析
*/
async analyzePerformance(operation) {
try {
// パフォーマンス履歴の分析
const history = this.performanceHistory.get(operation) || [];
const averageExecutionTime = history.length > 0 ?
history.reduce((sum, time) => sum + time, 0) / history.length : 0;
// メモリ使用量取得
const memUsage = process.memoryUsage();
const memoryUsage = Math.round(memUsage.heapUsed / 1024 / 1024); // MB
// CPU使用量(簡易計算)
const cpuUsage = Math.round(process.cpuUsage().user / 1000);
// ボトルネックの検出
const bottlenecks = [];
if (averageExecutionTime > this.config.performanceThreshold) {
bottlenecks.push({
location: operation,
type: 'cpu',
impact: averageExecutionTime > this.config.performanceThreshold * 2 ? 'high' : 'medium',
description: `実行時間が遅い: ${averageExecutionTime}ms (閾値: ${this.config.performanceThreshold}ms)`,
solution: 'アルゴリズムを最適化するかキャッシュを使用してください'
});
}
if (memoryUsage > 100) {
bottlenecks.push({
location: operation,
type: 'memory',
impact: memoryUsage > 200 ? 'high' : 'medium',
description: `高メモリ使用量: ${memoryUsage}MB`,
solution: 'データ構造を最適化するかメモリプールを実装してください'
});
}
// 最適化提案生成
const optimizationSuggestions = [
...(averageExecutionTime > this.config.performanceThreshold ?
['繰り返し処理にキャッシュの実装を検討してください'] : []),
...(bottlenecks.some(b => b.type === 'memory') ?
['メモリ最適化戦略を実装してください'] : []),
...(bottlenecks.some(b => b.type === 'cpu') ?
['CPU集約的な処理をプロファイリングして最適化してください'] : [])
];
// スコア計算(100点満点)
let score = 100;
if (averageExecutionTime > this.config.performanceThreshold) {
score -= Math.min(50, (averageExecutionTime / this.config.performanceThreshold) * 20);
}
if (memoryUsage > 100) {
score -= Math.min(30, (memoryUsage / 100) * 10);
}
score = Math.max(0, Math.round(score));
return {
operation,
averageExecutionTime,
memoryUsage,
cpuUsage,
bottlenecks,
optimizationSuggestions,
score
};
}
catch (error) {
return {
operation,
averageExecutionTime: 0,
memoryUsage: 0,
cpuUsage: 0,
bottlenecks: [],
optimizationSuggestions: ['Performance analysis failed'],
score: 50
};
}
}
/**
* 重複操作検出
*/
async detectDuplicateOperations(files) {
try {
const duplicates = [];
let totalWastedTime = 0;
// ファイル内の重複パターン検索
for (const file of files.filter(f => f.endsWith('.ts') || f.endsWith('.tsx'))) {
try {
const fullPath = join(this.workingDir, file);
const content = await fs.readFile(fullPath, 'utf-8');
// 重複する関数呼び出しパターンを検索
const functionCalls = content.match(/\w+\([^)]*\)/g) || [];
const callCounts = new Map();
functionCalls.forEach(call => {
const simplified = call.replace(/['"]/g, '').replace(/\s+/g, ' ');
callCounts.set(simplified, (callCounts.get(simplified) || 0) + 1);
});
// 閾値を超える重複を検出
for (const [call, count] of callCounts.entries()) {
if (count >= this.config.duplicateThreshold) {
const estimatedTime = count * 10; // 10ms per call estimate
totalWastedTime += estimatedTime;
duplicates.push({
operation: call,
occurrences: count,
wastedTime: estimatedTime,
locations: [file],
consolidationSuggestion: `Consider caching or memoizing ${call}`
});
}
}
}
catch (error) {
// ファイル読み込みエラーは無視
}
}
// 同じ処理の重複パターンを検出
const patterns = Array.from(this.operationPatterns.entries());
patterns.forEach(([pattern, count]) => {
if (count >= this.config.duplicateThreshold) {
const estimatedTime = count * 50; // 50ms per operation estimate
totalWastedTime += estimatedTime;
duplicates.push({
operation: pattern,
occurrences: count,
wastedTime: estimatedTime,
locations: ['system-wide'],
consolidationSuggestion: `Consolidate ${pattern} operations`
});
}
});
const potentialSavings = Math.round(totalWastedTime * 0.8); // 80% savings potential
const recommendations = [
...(duplicates.length > 0 ? ['頻繁に呼び出される処理にキャッシュを実装してください'] : []),
...(totalWastedTime > 1000 ? ['一元化された処理管理の実装を検討してください'] : []),
...(duplicates.some(d => d.occurrences > 10) ? ['高頻度処理を最初に最適化すべきです'] : [])
];
return {
duplicates,
totalWastedTime,
potentialSavings,
recommendations
};
}
catch (error) {
return {
duplicates: [],
totalWastedTime: 0,
potentialSavings: 0,
recommendations: ['Duplication analysis failed']
};
}
}
/**
* 自動化機会の特定
*/
async identifyAutomationOpportunities(context) {
try {
const opportunities = [];
let totalManualEffort = 0;
// 手動タスクパターンの検出
const manualTasks = [
{
task: 'Manual Git Operations',
frequency: this.operationPatterns.get('git-manual') || 0,
manualEffort: 2, // 2 minutes per operation
automationComplexity: 'low',
description: 'Repetitive git add, commit, push sequences'
},
{
task: 'Manual Code Review Setup',
frequency: this.operationPatterns.get('review-setup') || 0,
manualEffort: 5, // 5 minutes per setup
automationComplexity: 'medium',
description: 'Setting up pull requests and assigning reviewers'
},
{
task: 'Manual Testing Execution',
frequency: this.operationPatterns.get('manual-test') || 0,
manualEffort: 10, // 10 minutes per test run
automationComplexity: 'medium',
description: 'Running tests manually instead of automated CI/CD'
},
{
task: 'Manual Documentation Updates',
frequency: this.operationPatterns.get('doc-update') || 0,
manualEffort: 15, // 15 minutes per update
automationComplexity: 'high',
description: 'Updating documentation after code changes'
}
];
manualTasks.forEach(task => {
if (task.frequency > 0) {
const effort = task.frequency * task.manualEffort;
totalManualEffort += effort;
// ROI計算(年間での計算)
const annualSavings = effort * 52; // weekly to annual
const implementationCost = task.automationComplexity === 'low' ? 8 :
task.automationComplexity === 'medium' ? 20 : 40; // hours
const roi = annualSavings / implementationCost;
opportunities.push({
task: task.task,
frequency: task.frequency,
manualEffort: effort,
automationComplexity: task.automationComplexity,
roi,
description: task.description
});
}
});
// ROIでソート
opportunities.sort((a, b) => b.roi - a.roi);
const potentialAutomation = Math.round(totalManualEffort * 0.7); // 70% automation potential
const prioritizedRecommendations = opportunities
.filter(op => op.roi > 1) // ROI > 1 only
.slice(0, 5) // Top 5
.map(op => `Automate "${op.task}" (ROI: ${op.roi.toFixed(1)}x, saves ${op.manualEffort}min/week)`);
return {
opportunities,
totalManualEffort,
potentialAutomation,
prioritizedRecommendations
};
}
catch (error) {
return {
opportunities: [],
totalManualEffort: 0,
potentialAutomation: 0,
prioritizedRecommendations: ['Automation analysis failed']
};
}
}
/**
* キャッシュ効率性評価
*/
async evaluateCaching() {
try {
// キャッシュヒット率の簡易計算
const totalOperations = Array.from(this.operationPatterns.values()).reduce((sum, count) => sum + count, 0);
const cacheableOperations = Math.floor(totalOperations * 0.3); // 30% are cacheable
const cacheHits = Math.floor(cacheableOperations * 0.6); // 60% hit rate
const cacheHitRate = totalOperations > 0 ? cacheHits / totalOperations : 0;
// キャッシュ機会の検出
const missedOpportunities = [];
// 重複の多い操作をキャッシュ機会として識別
for (const [operation, frequency] of this.operationPatterns.entries()) {
if (frequency >= 3 && !operation.includes('cache')) {
const computationCost = frequency * 100; // ms
const cacheability = frequency > 10 ? 'high' : frequency > 5 ? 'medium' : 'low';
missedOpportunities.push({
operation,
frequency,
computationCost,
cacheability: cacheability,
suggestion: `Implement caching for ${operation} (${frequency} occurrences)`
});
}
}
const recommendations = [
...(cacheHitRate < 0.8 ? ['キャッシュ戦略を実装または改善してください'] : []),
...(missedOpportunities.length > 0 ? ['頻繁に繰り返される処理をキャッシュしてください'] : []),
...(missedOpportunities.some(m => m.cacheability === 'high') ?
['高頻度処理は即座にキャッシュすべきです'] : [])
];
const score = Math.round(cacheHitRate * 100);
return {
cacheHitRate,
missedOpportunities,
recommendations,
score
};
}
catch (error) {
return {
cacheHitRate: 0,
missedOpportunities: [],
recommendations: ['Cache analysis failed'],
score: 50
};
}
}
/**
* リソース使用量最適化
*/
async optimizeResourceUsage() {
try {
const memUsage = process.memoryUsage();
const currentUsage = {
memory: Math.round(memUsage.heapUsed / 1024 / 1024), // MB
cpu: Math.round(process.cpuUsage().user / 1000), // %
disk: 0, // Simplified
network: 0 // Simplified
};
// 最適化されたリソース使用量の推定
const optimizedUsage = {
memory: Math.round(currentUsage.memory * 0.8), // 20% reduction potential
cpu: Math.round(currentUsage.cpu * 0.9), // 10% reduction potential
disk: currentUsage.disk,
network: currentUsage.network
};
const savings = {
memory: currentUsage.memory - optimizedUsage.memory,
cpu: currentUsage.cpu - optimizedUsage.cpu,
disk: 0,
network: 0,
cost: ((currentUsage.memory - optimizedUsage.memory) * 0.01) +
((currentUsage.cpu - optimizedUsage.cpu) * 0.02) // Estimated cost savings
};
const recommendations = [
...(savings.memory > 10 ? ['Implement memory optimization strategies'] : []),
...(savings.cpu > 5 ? ['Optimize CPU-intensive operations'] : []),
...(currentUsage.memory > 100 ? ['Consider memory pooling or lazy loading'] : []),
'Use efficient data structures and algorithms'
];
return {
currentUsage,
optimizedUsage,
savings,
recommendations
};
}
catch (error) {
const emptyUsage = { memory: 0, cpu: 0, disk: 0, network: 0 };
return {
currentUsage: emptyUsage,
optimizedUsage: emptyUsage,
savings: { ...emptyUsage, cost: 0 },
recommendations: ['Resource analysis failed']
};
}
}
/**
* 効率性スコア計算
*/
calculateEfficiencyScore(performance, duplication, automation, cache, resource) {
// 各要素のスコア正規化
const performanceScore = performance.score;
const duplicationScore = duplication.totalWastedTime > 0 ?
Math.max(0, 100 - Math.min(50, duplication.totalWastedTime / 100)) : 100;
const automationScore = automation.totalManualEffort > 0 ?
Math.max(0, 100 - Math.min(60, automation.totalManualEffort * 2)) : 100;
const cacheScore = cache.score;
const resourceScore = resource.savings.cost > 0 ?
Math.min(100, 50 + (resource.savings.cost * 10)) : 70;
// 重み付き平均(パフォーマンス25%、重複20%、自動化25%、キャッシュ20%、リソース10%)
return Math.round(performanceScore * 0.25 +
duplicationScore * 0.20 +
automationScore * 0.25 +
cacheScore * 0.20 +
resourceScore * 0.10);
}
/**
* 効率性結果分析
*/
analyzeEfficiencyResults(performance, duplication, automation, cache, resource) {
const violations = [];
// パフォーマンス違反
performance.bottlenecks.forEach((bottleneck, index) => {
violations.push({
id: `performance-${index}`,
principle: 'be-lazy',
severity: bottleneck.impact === 'critical' ? 'critical' :
bottleneck.impact === 'high' ? 'high' : 'medium',
description: bottleneck.description,
autoFixable: bottleneck.type !== 'cpu' || bottleneck.impact !== 'critical',
recommendation: bottleneck.solution
});
});
// 重複違反
duplication.duplicates.forEach((duplicate, index) => {
if (duplicate.occurrences >= this.config.duplicateThreshold * 2) {
violations.push({
id: `duplication-${index}`,
principle: 'be-lazy',
severity: duplicate.occurrences > 10 ? 'high' : 'medium',
description: `High duplication: ${duplicate.operation} (${duplicate.occurrences} times)`,
autoFixable: true,
recommendation: duplicate.consolidationSuggestion
});
}
});
// 自動化違反
automation.opportunities.forEach((opportunity, index) => {
if (opportunity.roi > 2 && opportunity.automationComplexity !== 'high') {
violations.push({
id: `automation-${index}`,
principle: 'be-lazy',
severity: opportunity.roi > 5 ? 'high' : 'medium',
description: `High-value automation opportunity: ${opportunity.task} (ROI: ${opportunity.roi.toFixed(1)}x)`,
autoFixable: opportunity.automationComplexity === 'low',
recommendation: `Implement automation for ${opportunity.task}`
});
}
});
// キャッシュ違反
if (cache.cacheHitRate < 0.6) {
violations.push({
id: 'cache-efficiency',
principle: 'be-lazy',
severity: cache.cacheHitRate < 0.3 ? 'high' : 'medium',
description: `Low cache hit rate: ${Math.round(cache.cacheHitRate * 100)}%`,
autoFixable: true,
recommendation: 'Implement or improve caching strategy'
});
}
// リソース違反
if (resource.savings.cost > 1) {
violations.push({
id: 'resource-waste',
principle: 'be-lazy',
severity: resource.savings.cost > 5 ? 'high' : 'medium',
description: `Significant resource waste detected (potential savings: $${resource.savings.cost.toFixed(2)})`,
autoFixable: false,
recommendation: 'Optimize resource usage patterns'
});
}
return violations;
}
/**
* 効率性推奨事項生成
*/
generateEfficiencyRecommendations(violations) {
const recommendations = new Set();
violations.forEach(violation => {
recommendations.add(violation.recommendation);
});
// 一般的な推奨事項
if (violations.some(v => v.description.includes('duplication'))) {
recommendations.add('Consider implementing a centralized operation manager');
}
if (violations.some(v => v.description.includes('performance'))) {
recommendations.add('Profile application to identify performance bottlenecks');
}
if (violations.some(v => v.description.includes('automation'))) {
recommendations.add('Prioritize automation opportunities with highest ROI');
}
if (violations.length > 5) {
recommendations.add('Consider systematic efficiency improvements across the system');
}
return Array.from(recommendations);
}
/**
* 操作パターン記録
*/
recordOperation(operation) {
this.operationPatterns.set(operation, (this.operationPatterns.get(operation) || 0) + 1);
}
/**
* パフォーマンス記録
*/
recordPerformance(operation, executionTime) {
if (!this.performanceHistory.has(operation)) {
this.performanceHistory.set(operation, []);
}
const history = this.performanceHistory.get(operation);
history.push(executionTime);
// 直近20回の記録のみ保持
if (history.length > 20) {
history.shift();
}
}
/**
* 設定更新
*/
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
}
/**
* 無効時の結果
*/
getDisabledResult() {
const emptyUsage = { memory: 0, cpu: 0, disk: 0, network: 0 };
return {
score: 0,
violations: [],
recommendations: ['Be Lazy checker is disabled'],
details: {
performance: {
operation: 'disabled',
averageExecutionTime: 0,
memoryUsage: 0,
cpuUsage: 0,
bottlenecks: [],
optimizationSuggestions: [],
score: 0
},
duplication: {
duplicates: [],
totalWastedTime: 0,
potentialSavings: 0,
recommendations: []
},
automation: {
opportunities: [],
totalManualEffort: 0,
potentialAutomation: 0,
prioritizedRecommendations: []
},
cache: {
cacheHitRate: 0,
missedOpportunities: [],
recommendations: [],
score: 0
},
resource: {
currentUsage: emptyUsage,
optimizedUsage: emptyUsage,
savings: { ...emptyUsage, cost: 0 },
recommendations: []
}
}
};
}
/**
* エラー時の結果
*/
getErrorResult(error) {
const emptyUsage = { memory: 0, cpu: 0, disk: 0, network: 0 };
return {
score: 0,
violations: [{
id: 'checker-error',
principle: 'be-lazy',
severity: 'critical',
description: `Be Lazy checker error: ${error instanceof Error ? error.message : 'Unknown error'}`,
autoFixable: false,
recommendation: 'Check Be Lazy checker configuration and dependencies'
}],
recommendations: ['Fix Be Lazy checker error'],
details: {
performance: {
operation: 'error',
averageExecutionTime: 0,
memoryUsage: 0,
cpuUsage: 0,
bottlenecks: [],
optimizationSuggestions: [],
score: 0
},
duplication: {
duplicates: [],
totalWastedTime: 0,
potentialSavings: 0,
recommendations: []
},
automation: {
opportunities: [],
totalManualEffort: 0,
potentialAutomation: 0,
prioritizedRecommendations: []
},
cache: {
cacheHitRate: 0,
missedOpportunities: [],
recommendations: [],
score: 0
},
resource: {
currentUsage: emptyUsage,
optimizedUsage: emptyUsage,
savings: { ...emptyUsage, cost: 0 },
recommendations: []
}
}
};
}
}
//# sourceMappingURL=be-lazy-checker.js.map