UNPKG

wordlift-cli

Version:

WordLift CLI - A customized CLI for WordLift SEO workflows with agent memory system and smart project directory detection

190 lines (156 loc) 6.57 kB
#!/usr/bin/env node /** * WordLift CLI - A customized Gemini CLI for WordLift SEO workflows * @license Apache-2.0 */ const { spawn, execSync } = require('child_process'); const path = require('path'); const fs = require('fs'); // Get the actual working directory where the user ran the command const userWorkingDir = process.cwd(); const packageDir = path.dirname(__dirname); // Set up environment variables - prefer local .gemini if it exists const userGeminiDir = path.join(userWorkingDir, '.gemini'); const configDir = fs.existsSync(userGeminiDir) ? userGeminiDir : path.join(packageDir, '.gemini'); process.env.GEMINI_CONFIG_DIR = configDir; // Ensure WORDLIFT.md is available in the user's working directory function ensureWordLiftContext() { const packageWordLiftFile = path.join(packageDir, 'WORDLIFT.md'); const userWordLiftFile = path.join(userWorkingDir, 'WORDLIFT.md'); const userGeminiDir = path.join(userWorkingDir, '.gemini'); const userSettingsFile = path.join(userGeminiDir, 'settings.json'); // Only copy if user doesn't have their own WORDLIFT.md if (fs.existsSync(packageWordLiftFile) && !fs.existsSync(userWordLiftFile)) { try { fs.copyFileSync(packageWordLiftFile, userWordLiftFile); console.log('\x1b[2m📄 WordLift context file added to your project directory\x1b[0m'); } catch (error) { console.warn('⚠️ Could not copy WORDLIFT.md context file:', error.message); } } // Ensure local .gemini directory with context settings if (!fs.existsSync(userGeminiDir)) { try { fs.mkdirSync(userGeminiDir, { recursive: true }); } catch (error) { console.warn('⚠️ Could not create .gemini directory:', error.message); return; } } // Create or update local settings.json to reference WORDLIFT.md if (!fs.existsSync(userSettingsFile)) { try { // Copy the package settings and modify for local use const packageSettingsFile = path.join(packageDir, '.gemini', 'settings.json'); let packageSettings = {}; if (fs.existsSync(packageSettingsFile)) { packageSettings = JSON.parse(fs.readFileSync(packageSettingsFile, 'utf8')); } // Ensure contextFileName points to local WORDLIFT.md const localSettings = { ...packageSettings, "contextFileName": "WORDLIFT.md" }; fs.writeFileSync(userSettingsFile, JSON.stringify(localSettings, null, 2)); console.log('\x1b[2m⚙️ WordLift configuration added to your project\x1b[0m'); } catch (error) { console.warn('⚠️ Could not create settings.json:', error.message); } } } // Check if this is an interactive session (no arguments) const isInteractiveMode = process.argv.length === 2; // Show WordLift branding for interactive mode if (isInteractiveMode) { console.log('\x1b[2m🤖 Agent WordLift - Your AI SEO Assistant\x1b[0m'); console.log(`\x1b[2m📁 Working directory: ${userWorkingDir}\x1b[0m`); // Ensure WordLift context is available ensureWordLiftContext(); // Start Gemini CLI - ASCII art should already be replaced during installation const geminiProcess = spawn('npx', ['@google/gemini-cli'], { stdio: 'inherit', cwd: userWorkingDir, env: { ...process.env, WORDLIFT_PROJECT_DIR: userWorkingDir, WORDLIFT_PACKAGE_DIR: packageDir, GEMINI_CONFIG_DIR: configDir } }); geminiProcess.on('error', (error) => { console.error('❌ Error running WordLift CLI:', error.message); process.exit(1); }); geminiProcess.on('close', (code) => { process.exit(code); }); return; // Exit early for interactive mode } // For non-interactive commands (with arguments), show branding only for help if (process.argv.includes('--help') || process.argv.includes('-h')) { ensureWordLiftContext(); // Deploy context file for help commands too } // Also ensure context file for version commands if (process.argv.includes('--version') || process.argv.includes('-v')) { ensureWordLiftContext(); // Deploy context file for version commands too } // Ensure WordLift context is available for all modes ensureWordLiftContext(); // Use the standard Gemini CLI from npm const geminiCommand = 'npx'; const geminiArgs = ['@google/gemini-cli']; // Prepare arguments - pass through all command line arguments let userArgs = process.argv.slice(2); // If using -p (prompt mode), ensure MCP servers are allowed and WordLift context is loaded const hasPromptFlag = userArgs.includes('-p') || userArgs.includes('--prompt'); const hasPromptInteractiveFlag = userArgs.includes('-i') || userArgs.includes('--prompt-interactive'); if (hasPromptFlag || hasPromptInteractiveFlag) { // Add allowed MCP server names if not already specified const hasAllowedMcpFlag = userArgs.some(arg => arg.startsWith('--allowed-mcp-server-names')); if (!hasAllowedMcpFlag) { userArgs.push('--allowed-mcp-server-names', 'wordlift'); } // Add YOLO mode for prompt mode to auto-accept actions const hasYoloFlag = userArgs.includes('-y') || userArgs.includes('--yolo'); if (!hasYoloFlag) { userArgs.push('--yolo'); } // Ensure WordLift context is loaded for prompt mode console.log('\x1b[2m🤖 Agent WordLift - Loading SEO specialist context...\x1b[0m'); ensureWordLiftContext(); } const args = [...geminiArgs, ...userArgs]; // Configure stdio for truly non-interactive -p mode let stdioCfg = 'inherit'; if (hasPromptFlag && !hasPromptInteractiveFlag) { // For -p mode, pipe stdin to avoid interactive prompts getting stuck stdioCfg = ['pipe', 'inherit', 'inherit']; } // Spawn the Gemini CLI with WordLift configuration const geminiProcess = spawn(geminiCommand, args, { stdio: stdioCfg, cwd: userWorkingDir, // Run Gemini CLI in the user's working directory env: { ...process.env, WORDLIFT_PROJECT_DIR: userWorkingDir, WORDLIFT_PACKAGE_DIR: packageDir, GEMINI_CONFIG_DIR: configDir } }); // For -p mode, immediately close stdin to prevent hanging on interactive prompts if (hasPromptFlag && !hasPromptInteractiveFlag && geminiProcess.stdin) { geminiProcess.stdin.end(); } geminiProcess.on('error', (error) => { if (error.code === 'ENOENT') { console.error('❌ Gemini CLI not found. Please install it first:'); console.error(' npm install -g @google/gemini-cli'); console.error(' or run: npm run install-deps'); } else { console.error('❌ Error running WordLift CLI:', error.message); } process.exit(1); }); geminiProcess.on('close', (code) => { process.exit(code); });