UNPKG

muggleout

Version:

Transform muggles into terminal wizards / 비개발자를 터미널 마법사로 만들어주는 도구

249 lines (228 loc) 8.12 kB
import chalk from 'chalk'; import ora from 'ora'; import inquirer from 'inquirer'; import { runCommand } from '../utils/runner.js'; import { SudoManager } from '../utils/sudo-manager.js'; // 문제 해결 설정 const fixes = { 'command-not-found': { name: 'command not found 에러', diagnose: async (details) => { const command = extractCommand(details); const solutions = []; if (command === 'brew') { solutions.push({ name: 'Homebrew PATH 재설정', fix: async () => { const arch = process.arch; const brewPath = arch === 'arm64' ? '/opt/homebrew' : '/usr/local'; await runCommand(`echo 'eval "$(${brewPath}/bin/brew shellenv)"' >> ~/.zprofile`); await runCommand('source ~/.zprofile'); } }); solutions.push({ name: 'Homebrew 재설치', fix: async () => { const { installTool } = await import('./install.js'); await installTool('homebrew'); } }); } else if (command === 'node' || command === 'npm') { solutions.push({ name: 'Node.js 설치', fix: async () => { const { installTool } = await import('./install.js'); await installTool('node'); } }); } else { solutions.push({ name: `${command} 설치 (Homebrew 사용)`, fix: async () => { await runCommand(`brew install ${command}`); } }); } return solutions; } }, 'permission-denied': { name: 'Permission denied 에러', diagnose: async (details) => { return [ { name: '파일/폴더 권한 변경', fix: async () => { console.log(chalk.yellow('\n⚠️ 주의: 시스템 파일을 변경하면 위험할 수 있습니다!')); const { path } = await inquirer.prompt([ { type: 'input', name: 'path', message: '권한을 변경할 파일/폴더 경로:', default: '/usr/local', validate: (input) => { // 위험한 경로 차단 const dangerousPaths = ['/', '/System', '/Library', '/bin', '/sbin', '/etc', '/var', '/private']; if (dangerousPaths.includes(input.trim())) { return '❌ 시스템 핵심 폴더는 변경할 수 없습니다!'; } return true; } } ]); console.log(chalk.cyan('\n관리자 권한이 필요합니다. 비밀번호를 입력해주세요:')); console.log(chalk.gray('(비밀번호는 화면에 표시되지 않습니다)\n')); const hasSudo = await SudoManager.requestSudo(`${path} 권한 변경`); if (!hasSudo) { console.log(chalk.yellow('\n권한 변경이 취소되었습니다.')); return; } try { await runCommand(`sudo chown -R $(whoami) ${path}`); console.log(chalk.green(`✅ ${path} 권한이 변경되었습니다!`)); } catch (error) { console.log(chalk.red('\n❌ 권한 변경에 실패했습니다')); console.log(chalk.gray(`오류: ${error.message}`)); } } }, { name: 'npm 전역 디렉토리 변경', fix: async () => { await runCommand('mkdir ~/.npm-global'); await runCommand('npm config set prefix "~/.npm-global"'); await runCommand('echo \'export PATH=~/.npm-global/bin:$PATH\' >> ~/.zprofile'); console.log(chalk.yellow('⚠️ 터미널을 재시작해주세요!')); } } ]; } }, 'slow-terminal': { name: '터미널이 느림', diagnose: async () => { return [ { name: 'Oh My Zsh 플러그인 정리', fix: async () => { console.log(chalk.yellow('🔧 불필요한 플러그인을 제거합니다...')); await runCommand('sed -i.bak \'s/plugins=(.*)/plugins=(git)/\' ~/.zshrc'); console.log(chalk.green('✅ 기본 플러그인만 남겼습니다.')); } }, { name: 'Git 상태 표시 끄기', fix: async () => { await runCommand('git config --global oh-my-zsh.hide-dirty 1'); console.log(chalk.green('✅ Git 상태 표시를 껐습니다.')); } }, { name: 'Powerlevel10k 인스턴트 프롬프트 활성화', fix: async () => { console.log(chalk.blue('💡 p10k configure를 실행하여 "Instant Prompt"를 활성화하세요.')); } } ]; } }, 'install-failed': { name: '설치 실패', diagnose: async () => { return [ { name: 'Homebrew 업데이트 및 정리', fix: async () => { const spinner = ora('Homebrew 업데이트 중...').start(); await runCommand('brew update'); spinner.text = 'Homebrew 정리 중...'; await runCommand('brew cleanup'); spinner.succeed('Homebrew 업데이트 완료!'); } }, { name: 'npm 캐시 정리', fix: async () => { await runCommand('npm cache clean --force'); console.log(chalk.green('✅ npm 캐시를 정리했습니다.')); } }, { name: '시스템 진단 실행', fix: async () => { const { runDoctor } = await import('./doctor.js'); await runDoctor(); } } ]; } } }; // 명령어 추출 function extractCommand(details) { const match = details.match(/command not found:\s*(\w+)/i) || details.match(/(\w+).*not found/i); return match ? match[1] : null; } // 문제 해결 export async function fixIssue(issue) { console.log(chalk.bold('\n🔧 문제 해결사가 도와드릴게요!\n')); // 문제 타입 파악 let issueType = issue; let details = ''; // 자연어 입력 처리 if (!fixes[issue]) { if (issue.includes('not found')) { issueType = 'command-not-found'; details = issue; } else if (issue.includes('permission') || issue.includes('denied')) { issueType = 'permission-denied'; details = issue; } else if (issue.includes('느') || issue.includes('slow')) { issueType = 'slow-terminal'; } else { issueType = 'install-failed'; } } const fixConfig = fixes[issueType]; if (!fixConfig) { console.log(chalk.red('❌ 해당 문제에 대한 해결책을 찾을 수 없습니다.')); console.log(chalk.yellow('💡 "dev-setup doctor"로 시스템을 진단해보세요.')); return; } console.log(chalk.blue(`문제: ${fixConfig.name}`)); // 해결책 찾기 const solutions = await fixConfig.diagnose(details); if (solutions.length === 0) { console.log(chalk.red('❌ 구체적인 해결책을 찾을 수 없습니다.')); return; } // 해결책 선택 const { solution } = await inquirer.prompt([ { type: 'list', name: 'solution', message: '시도할 해결 방법을 선택하세요:', choices: [ ...solutions.map((s, i) => ({ name: s.name, value: i })), { name: '취소', value: -1 } ] } ]); if (solution === -1) { console.log(chalk.gray('취소되었습니다.')); return; } // 해결책 실행 try { await solutions[solution].fix(); console.log(chalk.green('\n✅ 문제 해결을 시도했습니다!')); console.log(chalk.yellow('💡 문제가 계속되면 다른 해결책을 시도해보세요.')); } catch (error) { console.log(chalk.red('\n❌ 해결 중 오류가 발생했습니다:')); console.log(chalk.red(error.message)); } }