UNPKG

wordlift-cli

Version:

WordLift CLI - Your AI SEO Assistant powered by Google Gemini. Agentic SEO workflows with Agent Skills support, WordLift MCP integration, knowledge graphs, and intelligent content optimization for modern content creators.

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); });