Skip to main content
Glama
post-install.js8.08 kB
#!/usr/bin/env node /** * NPM包安装后脚本 * 检查环境并提供使用指导 */ // const chalk = require('chalk'); // 使用内置颜色输出 const { execSync, spawn } = require('child_process'); const fs = require('fs'); const path = require('path'); const os = require('os'); // 检查是否在MCP运行时(静默模式) const isMCPMode = process.env.MCP_QUIET || process.argv.includes('--mcp-mode'); if (!isMCPMode) { console.log('Configuring Remote Terminal MCP...\n'); } // 获取包安装目录 const packageRoot = path.resolve(__dirname, '..'); const pythonDir = path.join(packageRoot, 'python'); const templatesDir = path.join(packageRoot, 'templates'); const requirementsFile = path.join(packageRoot, 'requirements.txt'); class PostInstaller { constructor() { this.platform = os.platform(); this.errors = []; this.warnings = []; } log(message, type = 'info') { // 在MCP运行时保持静默 const isMCPMode = process.env.MCP_QUIET || process.argv.includes('--mcp-mode'); if (isMCPMode) return; const colors = { info: '\x1b[36m', // cyan success: '\x1b[32m', // green warning: '\x1b[33m', // yellow error: '\x1b[31m', // red reset: '\x1b[0m' }; console.log(`${colors[type]}${message}${colors.reset}`); } checkCommand(command) { try { execSync(`which ${command}`, { stdio: 'ignore' }); return true; } catch { return false; } } async checkPython() { this.log('Checking Python environment...'); const pythonCommands = ['python3', 'python']; let pythonCmd = null; for (const cmd of pythonCommands) { if (this.checkCommand(cmd)) { pythonCmd = cmd; break; } } if (!pythonCmd) { this.errors.push('Python not found. Please install Python 3.6+'); return false; } this.log(`Python found: ${pythonCmd}`, 'success'); return pythonCmd; } async installPythonDeps(pythonCmd) { this.log('Installing Python dependencies...'); try { // Check pip const pipCommands = [`${pythonCmd} -m pip`, 'pip3', 'pip']; let pipCmd = null; for (const cmd of pipCommands) { try { execSync(`${cmd} --version`, { stdio: 'ignore' }); pipCmd = cmd; break; } catch {} } if (!pipCmd) { this.warnings.push('pip not found. Please install pip manually'); return false; } // Install dependencies execSync(`${pipCmd} install -r "${requirementsFile}"`, { stdio: 'inherit', cwd: packageRoot }); this.log('Python dependencies installed successfully', 'success'); return true; } catch (error) { this.warnings.push(`Python dependency installation failed: ${error.message}`); this.log('You may need to manually run: pip install -r requirements.txt', 'warning'); return false; } } async checkTmux() { this.log('Checking tmux...'); if (this.checkCommand('tmux')) { this.log('tmux is installed', 'success'); return true; } const installInstructions = { 'darwin': 'brew install tmux', 'linux': 'sudo apt install tmux # or sudo yum install tmux', 'default': 'Please install tmux for your system' }; const instruction = installInstructions[this.platform] || installInstructions.default; this.warnings.push(`tmux not found. Install with: ${instruction}`); return false; } async setPermissions() { this.log('Setting file permissions...'); try { // Set shell script execution permissions const shellScripts = [ path.join(templatesDir, 'connect_cpu_221.sh') ]; for (const script of shellScripts) { if (fs.existsSync(script)) { fs.chmodSync(script, '755'); } } // Set Python script execution permissions const pythonScripts = [ path.join(pythonDir, 'ssh_manager.py'), path.join(packageRoot, 'index.js') ]; for (const script of pythonScripts) { if (fs.existsSync(script)) { fs.chmodSync(script, '755'); } } this.log('File permissions set successfully', 'success'); return true; } catch (error) { this.warnings.push(`Permission setting failed: ${error.message}`); return false; } } async checkUserConfig() { this.log('Checking user configuration...'); const homeDir = os.homedir(); const configDir = path.join(homeDir, '.remote-terminal'); const userConfig = path.join(configDir, 'config.yaml'); // 只检查是否存在配置,不自动创建 if (fs.existsSync(userConfig)) { this.log('Found existing user configuration', 'success'); this.log(`Configuration location: ${userConfig}`, 'info'); return configDir; } // 确保配置目录存在(但不创建配置文件) if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir, { recursive: true }); this.log(`Configuration directory created: ${configDir}`, 'success'); } this.log('No configuration file found - user will need to create one', 'info'); this.log(`Configuration should be created at: ${userConfig}`, 'info'); return configDir; } async showCompletion() { this.log('\nInstallation completed!\n', 'success'); if (this.errors.length > 0) { this.log('Errors:', 'error'); this.errors.forEach(error => this.log(` • ${error}`, 'error')); this.log(''); } if (this.warnings.length > 0) { this.log('Warnings:', 'warning'); this.warnings.forEach(warning => this.log(` • ${warning}`, 'warning')); this.log(''); } this.log('Next steps:', 'info'); this.log(' 1. Add MCP server to Cursor (see documentation)', 'info'); this.log(' 2. In Cursor, say: "我想新增一个远程服务器"', 'info'); this.log(' 3. AI will guide you through the configuration process', 'info'); this.log(''); this.log('No default configuration file is created to avoid npm update conflicts.', 'info'); this.log('Use the AI assistant in Cursor to create your server configurations.', 'info'); this.log(''); this.log('Documentation: https://github.com/maricoxu/remote-terminal-mcp', 'info'); } async run() { try { const pythonCmd = await this.checkPython(); if (pythonCmd) { await this.installPythonDeps(pythonCmd); } await this.checkTmux(); await this.setPermissions(); await this.checkUserConfig(); await this.showCompletion(); } catch (error) { this.log(`Installation error: ${error.message}`, 'error'); process.exit(1); } } } // 运行安装程序 const installer = new PostInstaller(); installer.run().catch(console.error); module.exports = installer.run;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/maricoxu/remote-terminal-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server