UNPKG

claude-code-company

Version:

Multi-agent tmux coordination system for Claude Code with perfect Unicode support

161 lines (136 loc) 6.56 kB
const readline = require('readline'); const { colors } = require('./config'); const { setupSystem } = require('./setup'); const { chainCommand, destroyPanes } = require('./tasks'); // colors変数の検証 if (!colors || typeof colors !== 'object') { console.error('❌ Error: colors configuration not loaded properly'); process.exit(1); } // 安全な入力取得 function safeRead(prompt) { return new Promise((resolve) => { // 各質問に対して新しいreadlineインスタンスを作成 const rlInstance = readline.createInterface({ input: process.stdin, output: process.stdout }); rlInstance.question(prompt, (answer) => { rlInstance.close(); resolve(answer); }); }); } // 超シンプルメニュー async function interactiveMenu() { try { errorStats.menuCallCount++; errorStats.isMenuActive = true; console.log(`${colors.purple}🎯 Claude Code Company - 超軽量システム${colors.nc}\n`); console.log(`${colors.yellow}📋 基本操作メニュー${colors.nc}`); console.log(` 1) 🔧 setup - tmuxセッション初期化`); console.log(` 2) 📤 send - 指示・報告送信`); console.log(` 3) 🛠️ destroy - pane 0以外を削除`); console.log(` 4) 👋 exit - 終了\n`); const choice = await safeRead(`${colors.green}🎯 選択してください (1-4): ${colors.nc}`); // 入力値の検証と正規化 const normalizedChoice = choice.trim(); if (!normalizedChoice || !/^[1-4]$/.test(normalizedChoice)) { console.log(`${colors.red}❌ 無効な選択: "${choice}". 1-4の数字を入力してください${colors.nc}`); await promptForContinue(); return; } switch (normalizedChoice) { case '1': console.log(`${colors.blue}⚙️ システムセットアップを開始...${colors.nc}`); await setupSystem(3, null, 1); console.log(`${colors.green}✅ セットアップ完了${colors.nc}`); break; case '2': console.log(`\n${colors.yellow}📋 送信先一覧${colors.nc}`); console.log(`${colors.blue}┌─────────────┬────────────────────────────────────────┐${colors.nc}`); console.log(`${colors.blue}│ 送信先 │ 説明 │${colors.nc}`); console.log(`${colors.blue}├─────────────┼────────────────────────────────────────┤${colors.nc}`); console.log(`${colors.blue}${colors.purple}president${colors.blue} │ 統括者(プロジェクト全体を管理) │${colors.nc}`); console.log(`${colors.blue}${colors.cyan}boss1${colors.blue} │ 調整者(タスクを分解してWorkerに分散) │${colors.nc}`); console.log(`${colors.blue}${colors.green}workers${colors.blue} │ 全Worker(並列でタスクを実行) │${colors.nc}`); console.log(`${colors.blue}${colors.green}worker1-3${colors.blue} │ 個別Worker(特定のWorkerに送信) │${colors.nc}`); console.log(`${colors.blue}└─────────────┴────────────────────────────────────────┘${colors.nc}`); console.log(`\n${colors.yellow}💡 ヒント: 送信先は役割に応じて選択してください${colors.nc}\n`); const target = await safeRead(`${colors.cyan}🎯 送信先を入力 (デフォルト: president): ${colors.nc}`); const message = await safeRead(`${colors.cyan}📤 メッセージを入力: ${colors.nc}`); // デフォルト送信先の処理 const finalTarget = target.trim() || 'president'; if (message.trim()) { console.log(`${colors.blue}🔄 メッセージを送信中...${colors.nc}`); await chainCommand(finalTarget, message); console.log(`${colors.green}✨ 送信完了${colors.nc}`); } else { console.log(`${colors.yellow}⚠️ メッセージが必要です${colors.nc}`); } break; case '3': console.log(`${colors.blue}🛠️ pane 0以外を削除中...${colors.nc}`); await destroyPanes(); console.log(`${colors.green}✅ 削除完了${colors.nc}`); break; case '4': console.log(`${colors.green}👋 Goodbye!${colors.nc}`); errorStats.isMenuActive = false; process.exit(0); } // ユーザーにメニュー継続の選択肢を提供 if (normalizedChoice !== '4') { await promptForContinue(); } } catch (error) { errorStats.errorCount++; errorStats.recentErrors.push({ message: error.message, timestamp: new Date().toISOString() }); // 最新10個のエラーのみ保持 if (errorStats.recentErrors.length > 10) { errorStats.recentErrors = errorStats.recentErrors.slice(-10); } console.error(`${colors.red}❌ Menu error: ${error.message}${colors.nc}`); console.log(`${colors.yellow}⚠️ エラーが発生しました。メインメニューに戻りますか?${colors.nc}`); await promptForContinue(); } finally { errorStats.isMenuActive = false; } } // ユーザーに継続の選択肢を提供 async function promptForContinue() { try { const continueChoice = await safeRead(`\n${colors.cyan}🔄 メインメニューに戻りますか? (y/n): ${colors.nc}`); const normalized = continueChoice.trim().toLowerCase(); if (normalized === 'y' || normalized === 'yes' || normalized === '') { console.log(`\n${colors.purple}${'═'.repeat(50)}${colors.nc}`); await interactiveMenu(); } else { console.log(`${colors.green}👋 お疲れ様でした!${colors.nc}`); cleanupRl(); process.exit(0); } } catch (error) { console.error(`${colors.red}❌ Input error: ${error.message}${colors.nc}`); cleanupRl(); process.exit(1); } } // 安全なクリーンアップ function cleanupRl() { // readline instances are managed by safeRead } // エラー統計情報 const errorStats = { errorCount: 0, menuCallCount: 0, isMenuActive: false, recentErrors: [] }; module.exports = { interactiveMenu, cleanupRl };