UNPKG

@webdevtoday/grok-cli

Version:

A sophisticated CLI tool for interacting with xAI Grok 4, featuring conversation history, file reference, custom commands, memory system, and genetic development workflows

837 lines 39.5 kB
#!/usr/bin/env node "use strict"; /** * Grok CLI - Main entry point * A sophisticated CLI tool for interacting with xAI Grok 4 */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.main = main; const commander_1 = require("commander"); const chalk_1 = __importDefault(require("chalk")); const config_1 = require("./core/config"); const session_1 = require("./core/session"); const hooks_1 = require("./core/hooks"); const base_1 = require("./tools/base"); const tools_1 = require("./tools"); const mcp_client_1 = require("./core/mcp-client"); const mcp_1 = require("./tools/mcp"); const memory_1 = require("./core/memory"); const file_reference_1 = require("./core/file-reference"); const setup_1 = require("./core/setup"); const enhanced_commands_1 = require("./core/enhanced-commands"); const permissions_1 = require("./core/permissions"); const package_json_1 = require("../package.json"); const program = new commander_1.Command(); // ASCII Art for Grok CLI const GROK_ASCII = ` ██████╗ ██████╗ ██████╗ ██╗ ██╗ ██╗ ██╗ ██████╗██╗ ██╗ ██╔════╝ ██╔══██╗██╔═══██╗██║ ██╔╝ ██║ ██║ ██╔════╝██║ ██║ ██║ ███╗██████╔╝██║ ██║█████╔╝ ███████║ ██║ ██║ ██║ ██║ ██║██╔══██╗██║ ██║██╔═██╗ ╚════██║ ██║ ██║ ██║ ╚██████╔╝██║ ██║╚██████╔╝██║ ██╗ ██║ ╚██████╗███████╗██║ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝╚═╝ `; async function main() { program .name('grok') .description('A sophisticated CLI tool for interacting with xAI Grok 4') .version(package_json_1.version) .option('--api-key <key>', 'xAI API key (can also use XAI_API_KEY env var)') .option('--dev', 'use OpenAI model for development (requires OPENAI_API_KEY)') .option('--model <model>', 'specify the model to use') .option('--verbose', 'enable verbose logging') .option('--debug', 'enable debug mode') .option('--config <path>', 'path to configuration file') .option('--resume <sessionId>', 'resume a previous session') .option('--continue', 'continue the most recent session') .option('--add-dir <dirs...>', 'additional working directories') .option('--allowed-tools <tools...>', 'tools allowed without permission prompts') .option('--disallowed-tools <tools...>', 'tools that are disallowed') .option('--permission-mode <mode>', 'permission mode: ask, plan, or full') .option('--dangerously-skip-permissions', 'skip all permission prompts (dangerous!)') .option('--print', 'print mode - output response and exit') .option('--output-format <format>', 'output format: text, json, or stream-json'); // Parse command line arguments program.parse(process.argv); const options = program.opts(); try { // Check for first-time setup const setupManager = new setup_1.SetupManager(); let apiKey = null; if (!(await setupManager.hasApiKey())) { console.log(chalk_1.default.blue('🔑 First time setup detected...')); apiKey = await setupManager.setupApiKey(); if (apiKey) { await setupManager.initializeProject(); } } else { apiKey = await setupManager.getApiKey(); } // Load configuration const configManager = config_1.ConfigManager.getInstance(); const config = await configManager.loadConfig(); // Update config with API key from local file if available if (apiKey) { config.apiKeys.xai = apiKey; } // Show ASCII art and welcome message console.log(chalk_1.default.cyan(GROK_ASCII)); console.log(chalk_1.default.green('Chat with Grok 4 in your terminal.')); console.log(chalk_1.default.gray("Type 'exit' to quit or '/help' for commands.")); console.log(); // Show configuration status if (options['verbose'] || options['debug']) { console.log(chalk_1.default.blue('📊 Configuration Status:')); console.log(chalk_1.default.gray(`Model: ${config.model}`)); console.log(chalk_1.default.gray(`Permission Mode: ${config.permissions.mode}`)); console.log(chalk_1.default.gray(`Working Directory: ${process.cwd()}`)); if (config.apiKeys.xai) { console.log(chalk_1.default.green('✅ xAI API key configured')); } else { console.log(chalk_1.default.yellow('⚠️ xAI API key not configured')); } if (config.apiKeys.openai && options['dev']) { console.log(chalk_1.default.green('🚧 Development mode: Using OpenAI')); } console.log(); } // Start interactive mode or execute command if (options['print']) { // TODO: Implement print mode console.log(chalk_1.default.yellow('Print mode not yet implemented')); process.exit(1); } else { // Start interactive REPL await startInteractiveMode(config, options); } } catch (error) { console.error(chalk_1.default.red('❌ Error starting Grok CLI:')); console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error))); if (options['debug']) { console.error(chalk_1.default.gray('Debug information:')); console.error(error); } process.exit(1); } } /** * Start interactive REPL mode */ async function startInteractiveMode(config, options) { const readline = await Promise.resolve().then(() => __importStar(require('readline'))); // Initialize core systems const sessionManager = new session_1.SessionManager(config); const hookManager = new hooks_1.HookManager(config); const toolRegistry = (0, tools_1.setupToolRegistry)(); const permissionManager = new permissions_1.EnhancedPermissionManager(config, process.cwd()); const toolExecutor = new base_1.ToolExecutor(toolRegistry, permissionManager); const fileReferenceManager = new file_reference_1.FileReferenceManager(); const setupManager = new setup_1.SetupManager(); // Initialize MCP client and tool manager const mcpClient = new mcp_client_1.McpClient(); new mcp_1.McpToolManager(toolExecutor, mcpClient); // Auto-manages tool registration // Initialize memory manager const memoryManager = new memory_1.MemoryManager(process.cwd(), config.memory); // Auto-load memory if configured if (config.memory.autoLoad) { try { await memoryManager.loadMemoryFiles(); } catch (error) { console.warn(chalk_1.default.yellow('⚠️ Failed to auto-load memory:'), error instanceof Error ? error.message : String(error)); } } // Initialize command manager with all components const commandManager = new enhanced_commands_1.EnhancedCommandManager(toolExecutor, sessionManager, fileReferenceManager, setupManager); // Connect hook manager to tool executor toolExecutor.setHookManager(hookManager); // Handle continuation from previous session let session; if (options['continue']) { console.log(chalk_1.default.blue('🔄 Continuing from last conversation...')); session = await sessionManager.continueLastConversation(); if (session) { console.log(chalk_1.default.green(`✅ Resumed conversation with ${session.history.length} previous messages`)); } else { console.log(chalk_1.default.yellow('⚠️ No previous conversation found, starting new session')); session = await sessionManager.createSession(); } } else if (options['resume']) { const sessionId = options['resume']; console.log(chalk_1.default.blue(`🔄 Resuming conversation ${sessionId}...`)); session = await sessionManager.continueFromSession(sessionId); if (session) { console.log(chalk_1.default.green(`✅ Resumed conversation with ${session.history.length} previous messages`)); } else { console.log(chalk_1.default.yellow(`⚠️ Conversation ${sessionId} not found, starting new session`)); session = await sessionManager.createSession(); } } else { // Create new session session = await sessionManager.createSession(); } const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: chalk_1.default.blue('You: '), }); console.log(chalk_1.default.gray('🧠 Loading memory files...')); console.log(chalk_1.default.gray('🔧 Initializing hook system...')); console.log(chalk_1.default.gray('🔌 Connecting to MCP servers...')); console.log(chalk_1.default.green(`📝 Session started: ${session.id}`)); console.log(); rl.prompt(); rl.on('line', async (input) => { const trimmedInput = input.trim(); if (trimmedInput.toLowerCase() === 'exit') { console.log(chalk_1.default.green('Goodbye! 👋')); rl.close(); return; } if (trimmedInput.startsWith('/')) { // Handle slash commands using the new command system const commandContext = { session, config, cwd: process.cwd(), mcpClient, // Add MCP client to context memoryManager, // Add memory manager to context }; const result = await commandManager.executeCommand(trimmedInput, commandContext); if (!result.success && result.error) { console.log(chalk_1.default.red(`❌ ${result.error}`)); } } else if (trimmedInput.startsWith('@')) { // Handle file reference commands await handleFileReference(trimmedInput.slice(1), fileReferenceManager, config); } else if (trimmedInput.startsWith('#')) { // Handle memory addition await handleMemoryAddition(trimmedInput.slice(1), memoryManager); } else if (trimmedInput) { // Handle chat message await handleChatMessage(trimmedInput, config, hookManager, session, memoryManager); } rl.prompt(); }); rl.on('close', () => { console.log(chalk_1.default.green('Goodbye! 👋')); process.exit(0); }); } /** * Handle file reference commands */ async function handleFileReference(query, fileManager, _config) { if (!query.trim()) { // Show file reference help console.log(chalk_1.default.blue('📁 File Reference System:')); console.log(); console.log(chalk_1.default.cyan('@<filename>') + chalk_1.default.gray(' - Search for files by name')); console.log(chalk_1.default.cyan('@path/to/file') + chalk_1.default.gray(' - Reference specific file path')); console.log(chalk_1.default.cyan('@recent') + chalk_1.default.gray(' - Show recently modified files')); console.log(chalk_1.default.cyan('@git') + chalk_1.default.gray(' - Show git tracked files')); console.log(chalk_1.default.cyan('@ext:<extension>') + chalk_1.default.gray(' - Show files by extension (e.g., @ext:ts)')); console.log(); console.log(chalk_1.default.gray('Examples:')); console.log(chalk_1.default.gray(' @package.json')); console.log(chalk_1.default.gray(' @src/cli.ts')); console.log(chalk_1.default.gray(' @recent')); console.log(chalk_1.default.gray(' @ext:py')); return; } try { if (query === 'recent') { const recentFiles = await fileManager.getRecentFiles(15); if (recentFiles.length === 0) { console.log(chalk_1.default.yellow('No recent files found')); return; } console.log(chalk_1.default.blue('📁 Recent Files:')); recentFiles.forEach((file, index) => { const timeAgo = getTimeAgo(file.modified); const size = formatFileSize(file.size); const gitIcon = file.isGitTracked ? '📝' : '📄'; console.log(`${index + 1}.`.padStart(3) + ` ${gitIcon} ${chalk_1.default.cyan(file.relativePath)} ${chalk_1.default.gray(`(${size}, ${timeAgo})`)}`); }); return; } if (query === 'git') { const gitFiles = await fileManager.getGitTrackedFiles(); if (gitFiles.length === 0) { console.log(chalk_1.default.yellow('No git tracked files found')); return; } console.log(chalk_1.default.blue('📝 Git Tracked Files:')); gitFiles.slice(0, 20).forEach((file, index) => { const size = formatFileSize(file.size); console.log(`${index + 1}.`.padStart(3) + ` 📝 ${chalk_1.default.cyan(file.relativePath)} ${chalk_1.default.gray(`(${size})`)}`); }); if (gitFiles.length > 20) { console.log(chalk_1.default.gray(`... and ${gitFiles.length - 20} more files`)); } return; } if (query.startsWith('ext:')) { const extension = query.slice(4); const files = await fileManager.getFilesByExtension(extension); if (files.length === 0) { console.log(chalk_1.default.yellow(`No .${extension} files found`)); return; } console.log(chalk_1.default.blue(`📁 .${extension} Files:`)); files.slice(0, 20).forEach((file, index) => { const size = formatFileSize(file.size); const gitIcon = file.isGitTracked ? '📝' : '📄'; console.log(`${index + 1}.`.padStart(3) + ` ${gitIcon} ${chalk_1.default.cyan(file.relativePath)} ${chalk_1.default.gray(`(${size})`)}`); }); if (files.length > 20) { console.log(chalk_1.default.gray(`... and ${files.length - 20} more files`)); } return; } // Search for files const files = await fileManager.searchFiles(query, { maxResults: 15 }); if (files.length === 0) { console.log(chalk_1.default.yellow(`No files found matching "${query}"`)); // Show suggestions const suggestions = await fileManager.getFileSuggestions(query.slice(0, 3)); if (suggestions.length > 0) { console.log(chalk_1.default.gray('Did you mean:')); suggestions.slice(0, 5).forEach(file => { console.log(chalk_1.default.gray(` @${file.relativePath}`)); }); } return; } if (files.length === 1) { // Single file found - show details and content preview const file = files[0]; if (!file) return; console.log(chalk_1.default.blue('📁 File Details:')); console.log(chalk_1.default.cyan(`Path: ${file.relativePath}`)); console.log(chalk_1.default.gray(`Size: ${formatFileSize(file.size)}`)); console.log(chalk_1.default.gray(`Modified: ${getTimeAgo(file.modified)}`)); console.log(chalk_1.default.gray(`Type: ${file.type}`)); if (file.extension) { console.log(chalk_1.default.gray(`Extension: .${file.extension}`)); } console.log(chalk_1.default.gray(`Git tracked: ${file.isGitTracked ? 'Yes' : 'No'}`)); // Show content preview for small text files if (file.type === 'file' && file.size < 10000 && isTextFile(file.extension)) { try { const { readFile } = await Promise.resolve().then(() => __importStar(require('fs-extra'))); const content = await readFile(file.path, 'utf-8'); const lines = content.split('\n'); console.log(); console.log(chalk_1.default.blue('📄 Content Preview:')); lines.slice(0, 10).forEach((line, index) => { console.log(chalk_1.default.gray(`${(index + 1).toString().padStart(3)}: ${line}`)); }); if (lines.length > 10) { console.log(chalk_1.default.gray(`... ${lines.length - 10} more lines`)); } } catch { console.log(chalk_1.default.gray('Unable to preview file content')); } } return; } // Multiple files found - show list console.log(chalk_1.default.blue(`📁 Found ${files.length} files matching "${query}":`)); files.forEach((file, index) => { const size = formatFileSize(file.size); const gitIcon = file.isGitTracked ? '📝' : '📄'; console.log(`${index + 1}.`.padStart(3) + ` ${gitIcon} ${chalk_1.default.cyan(file.relativePath)} ${chalk_1.default.gray(`(${size})`)}`); }); console.log(); console.log(chalk_1.default.gray('Use @<exact-path> to view a specific file')); } catch (error) { console.log(chalk_1.default.red('Error searching files:'), error instanceof Error ? error.message : String(error)); } } /** * Handle memory addition */ async function handleMemoryAddition(content, memoryManager) { if (!content.trim()) { console.log(chalk_1.default.yellow('Usage: #<content to add to memory>')); return; } console.log(chalk_1.default.blue('📝 Adding to memory:'), content); try { await memoryManager.addToMemory(content.trim(), 'note'); console.log(chalk_1.default.green('✅ Added to memory')); } catch (error) { console.error(chalk_1.default.red('❌ Failed to add to memory:'), error instanceof Error ? error.message : String(error)); } } /** * Handle chat messages */ async function handleChatMessage(message, config, hookManager, session, memoryManager) { // Inject memory content if available and auto-load is enabled let enhancedMessage = message; if (memoryManager && config.memory.autoLoad) { const memoryContent = memoryManager.getMemoryContent(); if (memoryContent.trim()) { enhancedMessage = `Context from memory:\n\n${memoryContent}\n\n---\n\nUser message: ${message}`; console.log(chalk_1.default.gray('🧠 Memory context injected')); } } // Execute UserPromptSubmit hooks const userPromptEvent = { sessionId: session.id, transcriptPath: session.transcriptPath, cwd: session.cwd, hookEventName: 'UserPromptSubmit', prompt: enhancedMessage, // Use enhanced message with memory timestamp: new Date(), }; await hookManager.executeHooks('UserPromptSubmit', userPromptEvent); console.log(chalk_1.default.gray('🤖 Processing...')); // TODO: Implement agent chat console.log(chalk_1.default.yellow('Chat functionality not yet implemented')); console.log(chalk_1.default.gray('Your message:'), message); if (memoryManager && config.memory.autoLoad && enhancedMessage !== message) { console.log(chalk_1.default.gray('📊 Enhanced message length:'), enhancedMessage.length, 'characters'); } } /** * Show help information */ /** * Test hooks functionality */ async function testHooks(toolExecutor, session) { console.log(chalk_1.default.blue('🔧 Testing hooks...')); const context = { sessionId: session.id, cwd: session.cwd, timestamp: new Date(), }; // Test tool execution with hooks const result = await toolExecutor.executeTool('Read', { file_path: 'package.json' }, context); console.log(chalk_1.default.green('✅ Hook test result:'), result.success ? 'Success' : 'Failed'); if (result.error) { console.log(chalk_1.default.red('Error:'), result.error); } else if (result.output) { console.log(chalk_1.default.gray('Output preview:'), result.output.substring(0, 100) + '...'); } } /** * Show available tools */ function showTools(toolExecutor) { const tools = toolExecutor.getRegistry().getAllTools(); console.log(chalk_1.default.blue('🔧 Available tools:')); tools.forEach(tool => { console.log(` ${chalk_1.default.green(tool.name)} - ${tool.description}`); }); } /** * Handle custom command management */ async function handleCustomCommands(args, toolExecutor, session) { const subcommand = args[0] || 'list'; const context = { sessionId: session.id, cwd: session.cwd, timestamp: new Date(), }; switch (subcommand) { case 'list': const listResult = await toolExecutor.executeTool('Custom', { action: 'list' }, context); if (listResult.success) { console.log(chalk_1.default.blue('📦 Custom Commands:')); console.log(listResult.output); } else { console.log(chalk_1.default.red('Error:'), listResult.error); } break; case 'run': const commandName = args[1]; if (!commandName) { console.log(chalk_1.default.red('Usage: /custom run <command-name>')); return; } const runResult = await toolExecutor.executeTool('Custom', { action: 'run', name: commandName }, context); if (runResult.success) { console.log(chalk_1.default.green(`✅ Custom command '${commandName}' executed successfully`)); if (runResult.output) { console.log(runResult.output); } } else { console.log(chalk_1.default.red(`❌ Custom command '${commandName}' failed:`), runResult.error); } break; case 'help': console.log(chalk_1.default.blue('📦 Custom Commands Help:')); console.log(); console.log(chalk_1.default.cyan('/custom list') + chalk_1.default.gray(' - List all custom commands')); console.log(chalk_1.default.cyan('/custom run <name>') + chalk_1.default.gray(' - Run a custom command')); console.log(chalk_1.default.cyan('/init-commands') + chalk_1.default.gray(' - Initialize genetic development commands')); console.log(); console.log(chalk_1.default.gray('Custom commands allow you to create shortcuts for complex workflows')); break; default: console.log(chalk_1.default.yellow(`Unknown custom command: ${subcommand}`)); console.log(chalk_1.default.gray("Type '/custom help' for available subcommands")); } } /** * Initialize genetic development commands */ async function initializeGeneticCommands(toolExecutor, session) { console.log(chalk_1.default.blue('🧬 Initializing genetic development commands...')); const context = { sessionId: session.id, cwd: session.cwd, timestamp: new Date(), }; // Import the genetic development commands const { CustomTool } = await Promise.resolve().then(() => __importStar(require('./tools/custom'))); const geneticCommands = CustomTool.getGeneticDevCommands(); let added = 0; let skipped = 0; for (const command of geneticCommands) { const result = await toolExecutor.executeTool('Custom', { action: 'add', command, }, context); if (result.success) { added++; console.log(chalk_1.default.green(`✅ Added: ${command.name}`)); } else if (result.error?.includes('already exists')) { skipped++; console.log(chalk_1.default.yellow(`⚠️ Skipped: ${command.name} (already exists)`)); } else { console.log(chalk_1.default.red(`❌ Failed to add ${command.name}:`), result.error); } } console.log(); console.log(chalk_1.default.blue(`📊 Summary: Added ${added} commands, skipped ${skipped} existing commands`)); console.log(chalk_1.default.gray('Use /custom list to see all available commands')); } /** * Handle history commands */ async function handleHistoryCommand(args, sessionManager) { const subcommand = args[0] || 'list'; switch (subcommand) { case 'list': const limit = args[1] ? parseInt(args[1]) || 10 : 10; const conversations = await sessionManager.getHistoryManager().getRecentConversations(limit); if (conversations.length === 0) { console.log(chalk_1.default.yellow('No conversation history found')); return; } console.log(chalk_1.default.blue(`📚 Recent Conversations (${conversations.length}):`)); console.log(); conversations.forEach((conv, index) => { const timeAgo = getTimeAgo(conv.lastUpdateTime); const messageCount = chalk_1.default.gray(`${conv.messageCount} messages`); const preview = conv.firstMessage.length > 50 ? conv.firstMessage.slice(0, 50) + '...' : conv.firstMessage; console.log(`${(index + 1).toString().padStart(2)}. ${chalk_1.default.cyan(conv.id.slice(0, 8))} ${chalk_1.default.gray(timeAgo)} ${messageCount}`); console.log(` ${chalk_1.default.gray(preview)}`); console.log(); }); break; case 'search': const query = args.slice(1).join(' '); if (!query) { console.log(chalk_1.default.red('Usage: /history search <query>')); return; } const searchResults = await sessionManager.searchHistory(query); if (searchResults.length === 0) { console.log(chalk_1.default.yellow(`No conversations found matching "${query}"`)); return; } console.log(chalk_1.default.blue(`🔍 Search Results for "${query}" (${searchResults.length}):`)); console.log(); searchResults.forEach((conv, index) => { const timeAgo = getTimeAgo(conv.lastUpdateTime); console.log(`${(index + 1).toString().padStart(2)}. ${chalk_1.default.cyan(conv.id.slice(0, 8))} ${chalk_1.default.gray(timeAgo)}`); console.log(` ${chalk_1.default.gray(conv.firstMessage.slice(0, 80))}`); console.log(); }); break; case 'stats': const stats = await sessionManager.getHistoryStatistics(); console.log(chalk_1.default.blue('📊 History Statistics:')); console.log(); console.log(chalk_1.default.cyan('Total conversations:'), stats.totalConversations); console.log(chalk_1.default.cyan('Total messages:'), stats.totalMessages); console.log(chalk_1.default.cyan('Average messages per conversation:'), stats.avgMessagesPerConversation); if (stats.oldestConversation) { console.log(chalk_1.default.cyan('Oldest conversation:'), getTimeAgo(stats.oldestConversation)); } if (stats.newestConversation) { console.log(chalk_1.default.cyan('Newest conversation:'), getTimeAgo(stats.newestConversation)); } break; case 'delete': const sessionId = args[1]; if (!sessionId) { console.log(chalk_1.default.red('Usage: /history delete <session-id>')); return; } const deleted = await sessionManager.deleteFromHistory(sessionId); if (deleted) { console.log(chalk_1.default.green(`✅ Deleted conversation ${sessionId}`)); } else { console.log(chalk_1.default.red(`❌ Failed to delete conversation ${sessionId}`)); } break; case 'help': console.log(chalk_1.default.blue('📚 History Commands:')); console.log(); console.log(chalk_1.default.cyan('/history list [limit]') + chalk_1.default.gray(' - List recent conversations')); console.log(chalk_1.default.cyan('/history search <query>') + chalk_1.default.gray(' - Search conversations')); console.log(chalk_1.default.cyan('/history stats') + chalk_1.default.gray(' - Show history statistics')); console.log(chalk_1.default.cyan('/history delete <id>') + chalk_1.default.gray(' - Delete a conversation')); console.log(); console.log(chalk_1.default.gray('Use conversation IDs to continue or reference specific sessions')); break; default: console.log(chalk_1.default.yellow(`Unknown history command: ${subcommand}`)); console.log(chalk_1.default.gray("Type '/history help' for available subcommands")); } } /** * Handle continue commands */ async function handleContinueCommand(args, sessionManager) { const sessionId = args[0]; if (sessionId) { console.log(chalk_1.default.blue(`🔄 Continuing from conversation ${sessionId}...`)); const session = await sessionManager.continueFromSession(sessionId); if (session) { console.log(chalk_1.default.green(`✅ Continued conversation with ${session.history.length} previous messages`)); } else { console.log(chalk_1.default.red(`❌ Conversation ${sessionId} not found`)); } } else { console.log(chalk_1.default.blue('🔄 Continuing from last conversation...')); const session = await sessionManager.continueLastConversation(); if (session) { console.log(chalk_1.default.green(`✅ Continued conversation with ${session.history.length} previous messages`)); } else { console.log(chalk_1.default.yellow('⚠️ No previous conversation found')); } } } /** * Handle setup commands */ async function handleSetupCommand(args) { const subcommand = args[0] || 'status'; const setupManager = new setup_1.SetupManager(); switch (subcommand) { case 'status': await setupManager.showSetupStatus(); break; case 'api-key': console.log(chalk_1.default.blue('🔑 Setting up API key...')); const apiKey = await setupManager.setupApiKey(); if (apiKey) { console.log(chalk_1.default.green('✅ API key configured successfully')); } break; case 'init': const success = await setupManager.initializeProject(); if (success) { console.log(chalk_1.default.green('✅ Project initialized successfully')); } break; case 'detect': const projectTypes = await setupManager.detectProjectType(); console.log(chalk_1.default.blue('🔍 Detected project types:')); if (projectTypes.length > 0) { projectTypes.forEach(type => { console.log(` ${chalk_1.default.green('✓')} ${type}`); }); } else { console.log(chalk_1.default.gray(' No specific project type detected')); } break; case 'help': console.log(chalk_1.default.blue('🔧 Setup Commands:')); console.log(); console.log(chalk_1.default.cyan('/setup status') + chalk_1.default.gray(' - Show setup status')); console.log(chalk_1.default.cyan('/setup api-key') + chalk_1.default.gray(' - Configure API key')); console.log(chalk_1.default.cyan('/setup init') + chalk_1.default.gray(' - Initialize project')); console.log(chalk_1.default.cyan('/setup detect') + chalk_1.default.gray(' - Detect project type')); console.log(); console.log(chalk_1.default.gray('Setup commands help configure Grok CLI for your project')); break; default: console.log(chalk_1.default.yellow(`Unknown setup command: ${subcommand}`)); console.log(chalk_1.default.gray("Type '/setup help' for available subcommands")); } } /** * Utility functions for file handling */ function formatFileSize(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; } function getTimeAgo(date) { const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffMinutes = Math.floor(diffMs / (1000 * 60)); if (diffDays > 0) return `${diffDays}d ago`; if (diffHours > 0) return `${diffHours}h ago`; if (diffMinutes > 0) return `${diffMinutes}m ago`; return 'just now'; } function isTextFile(extension) { if (!extension) return false; const textExtensions = ['txt', 'md', 'json', 'js', 'ts', 'py', 'html', 'css', 'yml', 'yaml', 'xml', 'csv', 'log', 'sh', 'bash']; return textExtensions.includes(extension.toLowerCase()); } function showHelp() { console.log(chalk_1.default.blue('📚 Available Commands:')); console.log(); console.log(chalk_1.default.cyan('/help') + chalk_1.default.gray(' - Show this help message')); console.log(chalk_1.default.cyan('/status') + chalk_1.default.gray(' - Show system status')); console.log(chalk_1.default.cyan('/config') + chalk_1.default.gray(' - Show configuration')); console.log(chalk_1.default.cyan('/hooks') + chalk_1.default.gray(' - Test hooks functionality')); console.log(chalk_1.default.cyan('/tools') + chalk_1.default.gray(' - Show available tools')); console.log(chalk_1.default.cyan('/custom') + chalk_1.default.gray(' - Manage custom commands')); console.log(chalk_1.default.cyan('/init-commands') + chalk_1.default.gray(' - Initialize genetic dev commands')); console.log(chalk_1.default.cyan('/setup') + chalk_1.default.gray(' - Project setup and configuration')); console.log(chalk_1.default.cyan('/history') + chalk_1.default.gray(' - Manage conversation history')); console.log(chalk_1.default.cyan('/continue [session-id]') + chalk_1.default.gray(' - Continue from last or specific conversation')); console.log(chalk_1.default.cyan('/clear') + chalk_1.default.gray(' - Clear conversation history')); console.log(chalk_1.default.cyan('/memory') + chalk_1.default.gray(' - Edit memory files')); console.log(chalk_1.default.cyan('/mcp') + chalk_1.default.gray(' - Manage MCP servers')); console.log(); console.log(chalk_1.default.blue('💡 Tips:')); console.log(chalk_1.default.gray('• Start with # to add content to memory')); console.log(chalk_1.default.gray('• Use @ to search and reference files (@package.json, @recent, @git)')); console.log(chalk_1.default.gray('• Create custom commands for repeated workflows')); console.log(chalk_1.default.gray('• Use permission modes: ask, plan, auto, full')); console.log(chalk_1.default.gray('• Use --continue to resume your last conversation')); console.log(chalk_1.default.gray('• Type "exit" to quit')); } /** * Show system status */ function showStatus(config) { console.log(chalk_1.default.blue('📊 System Status:')); console.log(); console.log(chalk_1.default.cyan('Model:'), config.model); console.log(chalk_1.default.cyan('Permission Mode:'), config.permissions.mode); console.log(chalk_1.default.cyan('Working Directory:'), process.cwd()); console.log(chalk_1.default.cyan('Memory Auto-load:'), config.memory.autoLoad ? '✅' : '❌'); console.log(); // API Keys status console.log(chalk_1.default.blue('🔑 API Keys:')); console.log(chalk_1.default.cyan('xAI:'), config.apiKeys.xai ? '✅ Configured' : '❌ Missing'); console.log(chalk_1.default.cyan('OpenAI:'), config.apiKeys.openai ? '✅ Configured' : '❌ Missing'); console.log(chalk_1.default.cyan('Composio:'), config.apiKeys.composio ? '✅ Configured' : '❌ Missing'); } /** * Show configuration */ async function showConfig(config) { console.log(chalk_1.default.blue('⚙️ Configuration:')); console.log(JSON.stringify(config, null, 2)); } // Handle uncaught errors process.on('uncaughtException', (error) => { console.error(chalk_1.default.red('❌ Uncaught Exception:'), error); process.exit(1); }); process.on('unhandledRejection', (reason) => { console.error(chalk_1.default.red('❌ Unhandled Rejection:'), reason); process.exit(1); }); // Start the CLI if (require.main === module) { main().catch((error) => { console.error(chalk_1.default.red('❌ Fatal Error:'), error); process.exit(1); }); } //# sourceMappingURL=cli.js.map