UNPKG

github-mcp-auto-git

Version:

GitHub MCP Auto Git v3.0 - メモリ効率化・統合MCP・モジュール化完了の完全自動Git操作システム

575 lines (570 loc) 27.1 kB
#!/usr/bin/env node import { join } from 'path'; import { promises as fs } from 'fs'; import { watch } from 'chokidar'; import { config } from 'dotenv'; import * as readline from 'readline'; import { GitOperations } from './core/git-operations.js'; import { SetupWizard } from './core/setup-wizard.js'; import { ConstitutionalAIChecker } from './core/constitutional-ai-checker.js'; import { ProjectProgressTracker } from './core/project-progress-tracker.js'; config(); class GitAutoMCP { constructor(configPath) { this.isProcessing = false; this.config = {}; // 一時的な初期化 this.gitOps = {}; // 一時的な初期化 this.configPath = configPath; } async loadConfig(configPath) { const defaultConfig = { enabled: true, triggers: ['save', 'auto'], paths: ['src/**/*', '!node_modules/**'], subAgents: { gitSafetyAnalyzer: { enabled: true, safetyThreshold: 0.85 }, commitMessageGenerator: { enabled: true, language: 'ja', style: 'friendly' }, prManagementAgent: { enabled: true, autoMergeThreshold: 0.85 } }, notifications: { success: true, warnings: true, detailed: false }, github: { owner: process.env.GITHUB_OWNER || '', repo: process.env.GITHUB_REPO || '', token: process.env.GITHUB_TOKEN || '' } }; if (configPath) { try { const { default: userConfig } = await import(configPath); return { ...defaultConfig, ...userConfig }; } catch (error) { console.warn(`設定ファイルの読み込みに失敗しました: ${error}`); } } return defaultConfig; } async initialize() { console.log('🚀 GitHub MCP Auto Git System を初期化しています...'); try { this.config = await this.loadConfig(this.configPath); this.gitOps = new GitOperations(this.config); await this.gitOps.initialize(); if (!this.config.github.token) { console.warn('⚠️ GITHUB_TOKEN が設定されていません。PR機能は無効になります。'); } console.log('✅ 初期化完了'); console.log('📁 監視パターン:', this.config.paths.join(', ')); console.log('🤖 有効なサブエージェント:', this.getEnabledAgents().join(', ')); } catch (error) { console.error('❌ 初期化に失敗しました:', error); process.exit(1); } } async startWatching() { if (!this.config.enabled) { console.log('⏸️ システムが無効になっています'); return; } // インタラクティブな監視パターン設定 await this.configureWatchPatterns(); // PIDファイル作成でプロセス管理 await this.writePidFile(); console.log('👀 ファイル監視を開始します...'); console.log('📁 監視対象:', this.config.paths.join(', ')); this.watcher = watch(this.config.paths, { ignored: [ /node_modules/, '**/*.pid', '.github-auto-git.pid' ], ignoreInitial: true, persistent: true }); this.watcher .on('change', (path) => this.handleFileChange(path, 'change')) .on('add', (path) => this.handleFileChange(path, 'add')) .on('unlink', (path) => this.handleFileChange(path, 'delete')) .on('error', (error) => console.error('❌ ファイル監視エラー:', error)); console.log('✅ ファイル監視が開始されました'); console.log(`📋 PID: ${process.pid} (プロセス監視用)`); console.log('💡 Ctrl+C で停止できます'); // 定期ヘルスチェック開始 this.startHealthCheck(); } async handleFileChange(filePath, type) { if (this.isProcessing) { return; } console.log(`📝 ファイル${type === 'change' ? '変更' : type === 'add' ? '追加' : '削除'}: ${filePath}`); if (this.debounceTimer) { clearTimeout(this.debounceTimer); } this.debounceTimer = setTimeout(async () => { await this.processChanges([filePath]); }, 2000); } async processChanges(files) { if (this.isProcessing) { console.log('⏳ 既に処理中です...'); return; } this.isProcessing = true; try { console.log('\n🔄 Git操作を開始します...'); const result = await this.gitOps.executeGitWorkflow(files, { autoCommit: true, autoPush: this.config.github.token ? true : false, createPR: this.config.subAgents.prManagementAgent.enabled && this.config.github.token ? true : false }); if (result.success) { console.log('\n' + result.message); if (this.config.notifications.detailed && result.details) { this.displayDetailedResult(result); } if (result.warnings && result.warnings.length > 0 && this.config.notifications.warnings) { console.log('\n⚠️ 警告:'); result.warnings.forEach(warning => console.log(` • ${warning}`)); } } else { console.error('\n❌ Git操作が失敗しました:', result.message); if (result.warnings && result.warnings.length > 0) { console.log('\n詳細:'); result.warnings.forEach(warning => console.log(` • ${warning}`)); } } } catch (error) { console.error('❌ 予期しないエラーが発生しました:', error); } finally { this.isProcessing = false; console.log(`\n⏱️ 処理時間: ${Date.now() - (Date.now() - 1000)}ms`); console.log('👀 ファイル監視を継続中...\n'); } } displayDetailedResult(result) { console.log('\n📊 詳細結果:'); if (result.details.safety) { const safety = result.details.safety; console.log(` 🔒 安全性: ${safety.level} (${safety.safetyScore}/100)`); if (safety.risks.length > 0) { console.log(' ⚠️ リスク:'); safety.risks.forEach((risk) => { console.log(` • ${risk.description}`); }); } } if (result.details.commitMessage) { const msg = result.details.commitMessage; console.log(` 📝 コミットタイトル: ${msg.title}`); console.log(` 📋 Conventional: ${msg.conventional}`); } if (result.details.prManagement) { const pr = result.details.prManagement; console.log(` 🔀 マージ戦略: ${pr.mergeStrategy}`); console.log(` 🏷️ ラベル: ${pr.labels.join(', ')}`); if (pr.reviewers.length > 0) { console.log(` 👥 レビュアー: ${pr.reviewers.join(', ')}`); } } } async runOnce(files) { await this.initialize(); await this.processChanges(files); } async stop() { if (this.watcher) { await this.watcher.close(); console.log('⏹️ ファイル監視を停止しました'); } if (this.debounceTimer) { clearTimeout(this.debounceTimer); } // PIDファイルを削除 await this.removePidFile(); } async writePidFile() { try { const pidFile = join(process.cwd(), '.github-auto-git.pid'); await fs.writeFile(pidFile, process.pid.toString()); console.log(`📄 PIDファイル作成: ${pidFile}`); } catch (error) { console.warn('⚠️ PIDファイル作成に失敗:', error); } } async removePidFile() { try { const pidFile = join(process.cwd(), '.github-auto-git.pid'); await fs.unlink(pidFile); console.log('🗑️ PIDファイルを削除しました'); } catch (error) { // PIDファイルが存在しない場合は無視 } } startHealthCheck() { // 30秒ごとにヘルスチェック setInterval(() => { console.log(`💓 ヘルスチェック: ${new Date().toLocaleTimeString()} - 監視中`); }, 30000); } getEnabledAgents() { const agents = []; if (this.config.subAgents.gitSafetyAnalyzer.enabled) agents.push('Git Safety Analyzer'); if (this.config.subAgents.commitMessageGenerator.enabled) agents.push('Commit Message Generator'); if (this.config.subAgents.prManagementAgent.enabled) agents.push('PR Management Agent'); return agents; } async configureWatchPatterns() { const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); console.log('\n🔧 監視設定'); console.log('現在の監視パターン:', this.config.paths.join(', ')); const answer = await this.askQuestion(rl, '\n📁 監視したいフォルダ/ファイルを指定してください:\n' + ' 1. 現在のまま (src/**/*)\n' + ' 2. プロジェクト全体 (**/*)\n' + ' 3. カスタム設定\n' + '選択 (1-3): '); switch (answer) { case '1': // 現在の設定をそのまま使用 break; case '2': this.config.paths = ['**/*', '!node_modules/**', '!.git/**', '!dist/**', '!build/**']; console.log('✅ プロジェクト全体を監視対象に設定しました'); break; case '3': const customPath = await this.askQuestion(rl, 'カスタムパターンを入力してください (例: src/**/*,*.md): '); const patterns = customPath.split(',').map(p => p.trim()).filter(p => p.length > 0); this.config.paths = [...patterns, '!node_modules/**', '!.git/**']; console.log('✅ カスタムパターンを設定しました:', patterns.join(', ')); break; default: console.log('🔄 デフォルト設定を使用します'); break; } rl.close(); } askQuestion(rl, question) { return new Promise((resolve, reject) => { let isCompleted = false; const cleanup = () => { if (!isCompleted) { isCompleted = true; } }; rl.question(question, (answer) => { if (!isCompleted) { cleanup(); resolve(answer.trim()); } }); rl.on('error', (error) => { if (!isCompleted) { cleanup(); reject(error); } }); }); } getStatus() { return { enabled: this.config.enabled, watching: !!this.watcher, processing: this.isProcessing, agents: this.getEnabledAgents(), config: this.config }; } } async function main() { const args = process.argv.slice(2); const command = args[0]; const gitAutoMCP = new GitAutoMCP(); process.on('SIGINT', async () => { console.log('\n🛑 終了シグナルを受信しました...'); await gitAutoMCP.stop(); process.exit(0); }); switch (command) { case 'watch': await gitAutoMCP.initialize(); await gitAutoMCP.startWatching(); break; case 'commit': const files = args.slice(1); await gitAutoMCP.runOnce(files.length > 0 ? files : undefined); break; case 'status': await gitAutoMCP.initialize(); const status = gitAutoMCP.getStatus(); console.log('📊 システム状態:'); console.log(` 有効: ${status.enabled ? '✅' : '❌'}`); console.log(` 監視中: ${status.watching ? '✅' : '❌'}`); console.log(` 処理中: ${status.processing ? '⏳' : '✅'}`); console.log(` エージェント: ${status.agents.join(', ')}`); break; case 'init': console.log('🔧 設定ファイルを作成します...'); const configPath = join(process.cwd(), 'git-auto-mcp.config.js'); const configTemplate = `module.exports = { enabled: true, triggers: ['save', 'auto'], paths: ['src/**/*', '!node_modules/**'], subAgents: { gitSafetyAnalyzer: { enabled: true, safetyThreshold: 0.85 }, commitMessageGenerator: { enabled: true, language: 'ja', style: 'friendly' }, prManagementAgent: { enabled: true, autoMergeThreshold: 0.85 } }, notifications: { success: true, warnings: true, detailed: false }, github: { owner: process.env.GITHUB_OWNER || '', repo: process.env.GITHUB_REPO || '', token: process.env.GITHUB_TOKEN || '' } };`; try { await fs.writeFile(configPath, configTemplate); console.log(`✅ 設定ファイルを作成しました: ${configPath}`); // 詳細なGITHUB_TOKEN設定ガイド console.log('\n🔧 GITHUB_TOKEN 設定ガイド'); console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); console.log('\n📋 ステップ1: GitHubでPersonal Access Tokenを作成'); console.log(' 1. GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)'); console.log(' 2. "Generate new token (classic)" をクリック'); console.log(' 3. Note: "GitHub MCP Auto Git System" など分かりやすい名前'); console.log(' 4. 必要な権限を選択:'); console.log(' ✅ repo (リポジトリ全体へのアクセス)'); console.log(' ✅ workflow (GitHub Actionsワークフロー)'); console.log(' ✅ write:packages (パッケージ書き込み、オプション)'); console.log(' 5. "Generate token" をクリックして保存'); console.log('\n📋 ステップ2: 環境変数を設定'); console.log(' プロジェクトルートに .env ファイルを作成:'); console.log(' '); console.log(' GITHUB_OWNER=your-username # GitHubユーザー名'); console.log(' GITHUB_REPO=your-repository # リポジトリ名'); console.log(' GITHUB_TOKEN=ghp_xxxxxxxxxxxx # 作成したトークン'); console.log(' '); console.log('📋 ステップ3: 動作確認'); console.log(' github-auto-git status で設定確認'); console.log(' GITHUB_TOKEN警告が消えれば設定完了'); console.log('\n🔒 セキュリティ注意事項:'); console.log(' • .env ファイルを .gitignore に追加してください'); console.log(' • トークンは他人と共有しないでください'); console.log(' • 不要になったら GitHub でトークンを削除してください'); console.log('\n💡 その他:'); console.log(' • OpenAI APIキーは不要です(Claude Codeサブエージェント機能を使用)'); console.log(' • GITHUB_TOKENがない場合でもローカルGit操作は可能です'); console.log(' • PR作成・マージ機能のみトークンが必要です'); console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); } catch (error) { console.error('❌ 設定ファイルの作成に失敗しました:', error); } break; case 'token': case 'setup-token': console.log('\n🔧 GITHUB_TOKEN 設定ガイド'); console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); console.log('\n📋 ステップ1: GitHubでPersonal Access Tokenを作成'); console.log(' 1. GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)'); console.log(' 2. "Generate new token (classic)" をクリック'); console.log(' 3. Note: "GitHub MCP Auto Git System" など分かりやすい名前'); console.log(' 4. 必要な権限を選択:'); console.log(' ✅ repo (リポジトリ全体へのアクセス)'); console.log(' ✅ workflow (GitHub Actionsワークフロー)'); console.log(' ✅ write:packages (パッケージ書き込み、オプション)'); console.log(' 5. "Generate token" をクリックして保存'); console.log('\n📋 ステップ2: 環境変数を設定'); console.log(' プロジェクトルートに .env ファイルを作成:'); console.log(' '); console.log(' GITHUB_OWNER=your-username # GitHubユーザー名'); console.log(' GITHUB_REPO=your-repository # リポジトリ名'); console.log(' GITHUB_TOKEN=ghp_xxxxxxxxxxxx # 作成したトークン'); console.log(' '); console.log('📋 ステップ3: 動作確認'); console.log(' github-auto-git status で設定確認'); console.log(' GITHUB_TOKEN警告が消えれば設定完了'); console.log('\n🔒 セキュリティ注意事項:'); console.log(' • .env ファイルを .gitignore に追加してください'); console.log(' • トークンは他人と共有しないでください'); console.log(' • 不要になったら GitHub でトークンを削除してください'); console.log('\n💡 その他:'); console.log(' • OpenAI APIキーは不要です(Claude Codeサブエージェント機能を使用)'); console.log(' • GITHUB_TOKENがない場合でもローカルGit操作は可能です'); console.log(' • PR作成・マージ機能のみトークンが必要です'); console.log('\n🌐 参考リンク:'); console.log(' • GitHub Personal Access Token作成: https://github.com/settings/tokens'); console.log(' • GitHub docs: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token'); console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); break; case 'setup': case 'wizard': console.log('🧙‍♂️ セットアップウィザードを開始します...\n'); const wizard = new SetupWizard(); try { const result = await wizard.run(); if (result.success) { console.log('\n🎉 セットアップが正常に完了しました!'); console.log('github-auto-git watch でファイル監視を開始できます。'); } else { console.log('\n❌ セットアップに失敗しました。'); console.log('手動設定を行うか、github-auto-git init を試してください。'); } } catch (error) { console.error('❌ ウィザード実行エラー:', error); } break; case 'constitutional': case 'check': console.log('🏛️ Constitutional AI Checker を実行します...\n'); const checker = new ConstitutionalAIChecker(); try { const checkResult = await checker.runComprehensiveCheck({ files: args.slice(1).filter(arg => !arg.startsWith('-')), operation: 'manual-check', metadata: { manual: true } }); console.log('\n📊 Constitutional AI Checker 結果:'); console.log(` 総合スコア: ${checkResult.overallScore}/100`); console.log(` Fail Fast: ${checkResult.principleScores.failFast}/100`); console.log(` Be Lazy: ${checkResult.principleScores.beLazy}/100`); console.log(` TypeScript First: ${checkResult.principleScores.typeScriptFirst}/100`); if (checkResult.violations.length > 0) { console.log(`\n⚠️ 検出された違反: ${checkResult.violations.length}件`); checkResult.violations.slice(0, 5).forEach(violation => { console.log(` • [${violation.severity.toUpperCase()}] ${violation.description}`); }); if (checkResult.violations.length > 5) { console.log(` • ... 他 ${checkResult.violations.length - 5} 件`); } } if (checkResult.recommendations.length > 0) { console.log('\n💡 推奨事項:'); checkResult.recommendations.slice(0, 3).forEach(rec => { console.log(` • ${rec}`); }); } console.log(`\n実行時間: ${checkResult.executionTime}ms`); } catch (error) { console.error('❌ Constitutional AI Checker エラー:', error); } break; case 'progress': case 'ppt': console.log('📊 Project Progress Tracker を実行します...\n'); const tracker = new ProjectProgressTracker(); try { const progressResult = await tracker.updateProgress({ type: 'task_completed', description: 'Manual progress check', filesChanged: args.slice(1).filter(arg => !arg.startsWith('-')), impact: 'medium' }); console.log('\n📈 Project Progress Report:'); console.log(` プロジェクト: ${progressResult.metrics.projectName} v${progressResult.metrics.version}`); console.log(` 進捗: ${progressResult.metrics.completedTasks}/${progressResult.metrics.totalTasks} (${progressResult.metrics.completionPercentage}%)`); console.log(` 品質スコア: ${progressResult.metrics.codeQualityScore}/100`); console.log(` テストカバレッジ: ${progressResult.metrics.testCoverage}%`); console.log(` ドキュメント: ${progressResult.metrics.documentationCoverage}%`); console.log('\n📊 Insights:'); console.log(` 生産性: ${progressResult.insights.productivity}`); console.log(` 品質: ${progressResult.insights.quality}`); console.log(` 開発速度: ${progressResult.insights.velocity}`); if (progressResult.insights.recommendations.length > 0) { console.log('\n💡 推奨事項:'); progressResult.insights.recommendations.slice(0, 3).forEach(rec => { console.log(` • ${rec}`); }); } console.log(`\n📄 詳細レポートが生成されました: docs/progress/`); } catch (error) { console.error('❌ Progress Tracker エラー:', error); } break; default: console.log(` 🚀 GitHub MCP Auto Git System 使用方法: github-auto-git setup 🧙‍♂️ インタラクティブセットアップウィザード(推奨) github-auto-git watch ファイル監視を開始 github-auto-git commit [files] 手動でGit操作実行 github-auto-git status システム状態を表示 github-auto-git init 設定ファイルを作成 github-auto-git token GITHUB_TOKEN設定ガイド表示 github-auto-git check [files] 🏛️ Constitutional AI原則チェック実行 github-auto-git progress 📊 Project Progress Tracker実行 サブエージェント機能: 🛡️ Git Safety Analyzer 機密情報・破壊的変更検出 📝 Commit Message Generator 非エンジニア向けメッセージ生成 🔀 PR Management Agent 自動マージ判定・PR管理 🏛️ Constitutional AI Checker 3原則(Fail Fast, Be Lazy, TypeScript First)チェック 📊 Project Progress Tracker 進捗ドキュメント自動管理・インサイト生成 例: # ファイル監視開始(推奨) github-auto-git watch # 特定ファイルを手動コミット github-auto-git commit src/components/Header.tsx # 全変更を手動コミット github-auto-git commit `); break; } } // ESModuleでの実行判定(スクリプトとして直接実行された場合のみ) import { fileURLToPath } from 'url'; const currentFile = fileURLToPath(import.meta.url); const isMainModule = process.argv[1] && (currentFile === process.argv[1] || currentFile.endsWith(process.argv[1]) || process.argv[1].endsWith('github-auto-git')); // グローバルインストール対応 if (isMainModule) { main().catch(error => { console.error('❌ 実行中にエラーが発生しました:', error); process.exit(1); }); } export { GitAutoMCP }; export default GitAutoMCP; //# sourceMappingURL=index-original-671-lines.js.map