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

1,101 lines 67.3 kB
"use strict"; /** * Enhanced command implementations with full tool integration */ 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.EnhancedCommandManager = void 0; const chalk_1 = __importDefault(require("chalk")); /** * Enhanced command manager that provides access to all system components */ class EnhancedCommandManager { constructor(toolExecutor, sessionManager, fileReferenceManager, setupManager) { this.toolExecutor = toolExecutor; this.sessionManager = sessionManager; this.fileReferenceManager = fileReferenceManager; this.setupManager = setupManager; this.commands = new Map(); this.aliases = new Map(); this.initializeCommands(); } /** * Execute a slash command with full system access */ async executeCommand(input, context) { const parts = input.slice(1).split(' '); const commandName = parts[0] || ''; const args = parts.slice(1); if (!commandName) { return { success: false, error: 'No command specified. Type \'/help\' for available commands.' }; } // Resolve alias const resolvedName = this.aliases.get(commandName) || commandName; const command = this.commands.get(resolvedName); if (!command) { return { success: false, error: `Unknown command: ${commandName}. Type '/help' for available commands.` }; } try { // Enhanced context with system components const enhancedContext = { ...context, toolExecutor: this.toolExecutor, sessionManager: this.sessionManager, fileReferenceManager: this.fileReferenceManager, setupManager: this.setupManager, }; return await command.execute(args, enhancedContext); } catch (error) { return { success: false, error: error instanceof Error ? error.message : String(error) }; } } /** * Get command suggestions for autocomplete */ getCommandSuggestions(partial) { const allNames = [ ...Array.from(this.commands.keys()), ...Array.from(this.aliases.keys()) ]; return allNames .filter(name => name.startsWith(partial)) .sort(); } initializeCommands() { // Enhanced implementations with full system access this.commands.set('help', new EnhancedHelpCommand()); this.commands.set('status', new EnhancedStatusCommand()); this.commands.set('config', new EnhancedConfigCommand()); this.commands.set('tools', new EnhancedToolsCommand()); this.commands.set('hooks', new EnhancedHooksCommand()); this.commands.set('custom', new EnhancedCustomCommand()); this.commands.set('init-commands', new EnhancedInitCommandsCommand()); this.commands.set('setup', new EnhancedSetupCommand()); this.commands.set('history', new EnhancedHistoryCommand()); this.commands.set('continue', new EnhancedContinueCommand()); this.commands.set('memory', new EnhancedMemoryCommand()); this.commands.set('mcp', new EnhancedMcpCommand()); this.commands.set('permissions', new EnhancedPermissionsCommand()); this.commands.set('clear', new EnhancedClearCommand()); this.commands.set('exit', new EnhancedExitCommand()); this.commands.set('version', new EnhancedVersionCommand()); this.commands.set('files', new FilesCommand()); this.commands.set('search', new SearchCommand()); this.commands.set('recent', new RecentCommand()); // Register aliases this.aliases.set('h', 'help'); this.aliases.set('s', 'status'); this.aliases.set('c', 'config'); this.aliases.set('t', 'tools'); this.aliases.set('hist', 'history'); this.aliases.set('cont', 'continue'); this.aliases.set('perms', 'permissions'); this.aliases.set('q', 'exit'); this.aliases.set('quit', 'exit'); this.aliases.set('f', 'files'); } } exports.EnhancedCommandManager = EnhancedCommandManager; class EnhancedHelpCommand { constructor() { this.name = 'help'; this.description = 'Show available commands and usage information'; this.scope = 'builtin'; } async execute(args, context) { const commandName = args[0]; if (commandName) { return this.showCommandHelp(commandName, context); } return this.showGeneralHelp(context); } async showCommandHelp(commandName, _context) { console.log(chalk_1.default.blue(`📚 Help for /${commandName}:`)); console.log(chalk_1.default.gray('Detailed help would be shown here')); return { success: true, output: `Help for ${commandName}` }; } async showGeneralHelp(_context) { const lines = [ chalk_1.default.blue('📚 Available Commands:'), '', chalk_1.default.yellow('System Commands:'), chalk_1.default.cyan(' /help [command]') + chalk_1.default.gray(' - Show help'), chalk_1.default.cyan(' /status') + chalk_1.default.gray(' - System status'), chalk_1.default.cyan(' /config') + chalk_1.default.gray(' - Configuration'), chalk_1.default.cyan(' /version') + chalk_1.default.gray(' - Version info'), chalk_1.default.cyan(' /exit') + chalk_1.default.gray(' - Exit Grok CLI'), '', chalk_1.default.yellow('Development Commands:'), chalk_1.default.cyan(' /tools') + chalk_1.default.gray(' - List available tools'), chalk_1.default.cyan(' /hooks') + chalk_1.default.gray(' - Test hooks'), chalk_1.default.cyan(' /mcp') + chalk_1.default.gray(' - MCP servers'), '', chalk_1.default.yellow('Session Commands:'), chalk_1.default.cyan(' /history') + chalk_1.default.gray(' - Conversation history'), chalk_1.default.cyan(' /continue [id]') + chalk_1.default.gray(' - Continue conversation'), chalk_1.default.cyan(' /memory') + chalk_1.default.gray(' - Memory management and GROK.md files'), chalk_1.default.cyan(' /clear') + chalk_1.default.gray(' - Clear terminal'), '', chalk_1.default.yellow('Workflow Commands:'), chalk_1.default.cyan(' /custom') + chalk_1.default.gray(' - Custom commands'), chalk_1.default.cyan(' /init-commands') + chalk_1.default.gray(' - Initialize genetic dev'), chalk_1.default.cyan(' /setup') + chalk_1.default.gray(' - Project setup'), '', chalk_1.default.yellow('File Commands:'), chalk_1.default.cyan(' /files [pattern]') + chalk_1.default.gray(' - Browse files'), chalk_1.default.cyan(' /search <query>') + chalk_1.default.gray(' - Search files'), chalk_1.default.cyan(' /recent [limit]') + chalk_1.default.gray(' - Recent files'), '', chalk_1.default.blue('💡 Other Features:'), chalk_1.default.gray('• Use @ commands for file reference (@package.json, @recent, @git)'), chalk_1.default.gray('• Use # to add content to memory (#important note)'), chalk_1.default.gray('• GROK.md files auto-load for conversation context'), chalk_1.default.gray('• Use --continue flag to resume conversations'), '', chalk_1.default.blue('🔗 Aliases:'), chalk_1.default.gray('/h → /help, /s → /status, /c → /config, /t → /tools'), chalk_1.default.gray('/hist → /history, /cont → /continue, /q → /exit, /f → /files') ]; console.log(lines.join('\n')); return { success: true, output: 'Help displayed' }; } } class EnhancedStatusCommand { constructor() { this.name = 'status'; this.description = 'Show comprehensive system status'; this.scope = 'builtin'; } async execute(args, context) { const verbose = args.includes('--verbose') || args.includes('-v'); console.log(chalk_1.default.blue('📊 System Status:')); console.log(); // Basic status console.log(chalk_1.default.cyan('Session:'), context.session.id.slice(0, 8)); console.log(chalk_1.default.cyan('Messages:'), context.session.history.length); console.log(chalk_1.default.cyan('Model:'), context.config.model); console.log(chalk_1.default.cyan('Permission Mode:'), context.config.permissions.mode); console.log(chalk_1.default.cyan('Working Directory:'), context.cwd); // API Keys status console.log(); console.log(chalk_1.default.blue('🔑 API Keys:')); console.log(chalk_1.default.cyan('xAI:'), context.config.apiKeys.xai ? chalk_1.default.green('✅ Configured') : chalk_1.default.red('❌ Missing')); console.log(chalk_1.default.cyan('OpenAI:'), context.config.apiKeys.openai ? chalk_1.default.green('✅ Configured') : chalk_1.default.red('❌ Missing')); console.log(chalk_1.default.cyan('Composio:'), context.config.apiKeys.composio ? chalk_1.default.green('✅ Configured') : chalk_1.default.red('❌ Missing')); // Tool status console.log(); console.log(chalk_1.default.blue('🔧 Tools:')); const tools = context.toolExecutor.getRegistry().getAllTools(); console.log(chalk_1.default.cyan('Available Tools:'), tools.length); if (verbose) { tools.forEach(tool => { console.log(` ${chalk_1.default.green('✓')} ${tool.name} - ${tool.description}`); }); } // History status try { const stats = await context.sessionManager.getHistoryStatistics(); console.log(); console.log(chalk_1.default.blue('📚 History:')); console.log(chalk_1.default.cyan('Total Conversations:'), stats.totalConversations); console.log(chalk_1.default.cyan('Total Messages:'), stats.totalMessages); } catch { // History not available } return { success: true, output: 'Status displayed' }; } } class EnhancedToolsCommand { constructor() { this.name = 'tools'; this.description = 'List and manage available tools'; this.scope = 'builtin'; } async execute(args, context) { const subcommand = args[0]; if (subcommand === 'test') { return this.testTool(args[1] || '', context); } const tools = context.toolExecutor.getRegistry().getAllTools(); console.log(chalk_1.default.blue(`🔧 Available Tools (${tools.length}):`)); console.log(); tools.forEach(tool => { console.log(`${chalk_1.default.green('✓')} ${chalk_1.default.cyan(tool.name)} - ${tool.description}`); }); console.log(); console.log(chalk_1.default.gray('Use "/tools test <tool-name>" to test a specific tool')); return { success: true, output: `Listed ${tools.length} tools` }; } async testTool(toolName, context) { if (!toolName) { return { success: false, error: 'Usage: /tools test <tool-name>' }; } console.log(chalk_1.default.blue(`🔧 Testing tool: ${toolName}`)); // Test with safe parameters const testParams = this.getTestParams(toolName); const toolContext = { sessionId: context.session.id, cwd: context.cwd, timestamp: new Date(), }; try { const result = await context.toolExecutor.executeTool(toolName, testParams, toolContext); if (result.success) { console.log(chalk_1.default.green('✅ Tool test successful')); if (result.output) { console.log(chalk_1.default.gray('Output preview:'), result.output.substring(0, 200) + '...'); } } else { console.log(chalk_1.default.red('❌ Tool test failed:'), result.error); } const commandResult = { success: result.success, output: result.output, }; if (result.error) { commandResult.error = result.error; } return commandResult; } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); console.log(chalk_1.default.red('❌ Tool test error:'), errorMsg); return { success: false, error: errorMsg }; } } getTestParams(toolName) { switch (toolName.toLowerCase()) { case 'read': return { file_path: 'package.json' }; case 'bash': return { command: 'echo "test"' }; default: return {}; } } } class EnhancedHistoryCommand { constructor() { this.name = 'history'; this.description = 'Manage conversation history'; this.scope = 'builtin'; } async execute(args, context) { const subcommand = args[0] || 'list'; switch (subcommand) { case 'list': return this.listHistory(args, context); case 'search': return this.searchHistory(args, context); case 'stats': return this.showStats(context); case 'delete': return this.deleteHistory(args, context); case 'help': return this.showHelp(); default: return { success: false, error: `Unknown history command: ${subcommand}` }; } } async listHistory(args, context) { const limit = args[1] ? parseInt(args[1]) || 10 : 10; const conversations = await context.sessionManager.getHistoryManager().getRecentConversations(limit); if (conversations.length === 0) { console.log(chalk_1.default.yellow('No conversation history found')); return { success: true, output: 'No history' }; } console.log(chalk_1.default.blue(`📚 Recent Conversations (${conversations.length}):`)); console.log(); conversations.forEach((conv, index) => { const timeAgo = this.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(); }); return { success: true, output: `Listed ${conversations.length} conversations` }; } async searchHistory(args, context) { const query = args.slice(1).join(' '); if (!query) { return { success: false, error: 'Usage: /history search <query>' }; } const results = await context.sessionManager.searchHistory(query); if (results.length === 0) { console.log(chalk_1.default.yellow(`No conversations found matching "${query}"`)); return { success: true, output: 'No results' }; } console.log(chalk_1.default.blue(`🔍 Search Results for "${query}" (${results.length}):`)); console.log(); results.forEach((conv, index) => { const timeAgo = this.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(); }); return { success: true, output: `Found ${results.length} results` }; } async showStats(context) { const stats = await context.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:'), this.getTimeAgo(stats.oldestConversation)); } if (stats.newestConversation) { console.log(chalk_1.default.cyan('Newest conversation:'), this.getTimeAgo(stats.newestConversation)); } return { success: true, output: 'Statistics displayed' }; } async deleteHistory(args, context) { const sessionId = args[1]; if (!sessionId) { return { success: false, error: 'Usage: /history delete <session-id>' }; } const deleted = await context.sessionManager.deleteFromHistory(sessionId); if (deleted) { console.log(chalk_1.default.green(`✅ Deleted conversation ${sessionId}`)); return { success: true, output: `Deleted ${sessionId}` }; } else { console.log(chalk_1.default.red(`❌ Failed to delete conversation ${sessionId}`)); return { success: false, error: `Failed to delete ${sessionId}` }; } } showHelp() { 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')); return { success: true, output: 'Help displayed' }; } 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'; } } // File management commands using the FileReferenceManager class FilesCommand { constructor() { this.name = 'files'; this.description = 'Browse and explore files'; this.scope = 'builtin'; } async execute(args, context) { const pattern = args[0]; if (!pattern) { // Show file browser help console.log(chalk_1.default.blue('📁 File Browser:')); console.log(); console.log(chalk_1.default.cyan('/files <pattern>') + chalk_1.default.gray(' - Search for files')); console.log(chalk_1.default.cyan('/files recent') + chalk_1.default.gray(' - Show recent files')); console.log(chalk_1.default.cyan('/files git') + chalk_1.default.gray(' - Show git tracked files')); console.log(); console.log(chalk_1.default.gray('Examples:')); console.log(chalk_1.default.gray(' /files package.json')); console.log(chalk_1.default.gray(' /files src/')); console.log(chalk_1.default.gray(' /files recent')); return { success: true, output: 'File browser help displayed' }; } if (pattern === 'recent') { const files = await context.fileReferenceManager.getRecentFiles(15); console.log(chalk_1.default.blue('📁 Recent Files:')); console.log(); files.forEach((file, index) => { const icon = file.isGitTracked ? '📝' : '📄'; const size = this.formatFileSize(file.size); const timeAgo = this.getTimeAgo(file.modified); console.log(`${(index + 1).toString().padStart(2)}. ${icon} ${chalk_1.default.cyan(file.relativePath)} ${chalk_1.default.gray(`(${size}, ${timeAgo})`)}`); }); return { success: true, output: `Listed ${files.length} recent files` }; } if (pattern === 'git') { const files = await context.fileReferenceManager.getGitTrackedFiles(); console.log(chalk_1.default.blue('📝 Git Tracked Files:')); console.log(); files.slice(0, 20).forEach((file, index) => { const size = this.formatFileSize(file.size); console.log(`${(index + 1).toString().padStart(2)}. 📝 ${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 { success: true, output: `Listed ${Math.min(files.length, 20)} git files` }; } // Search for files const files = await context.fileReferenceManager.searchFiles(pattern, { maxResults: 20 }); if (files.length === 0) { console.log(chalk_1.default.yellow(`No files found matching "${pattern}"`)); return { success: true, output: 'No files found' }; } console.log(chalk_1.default.blue(`📁 Found ${files.length} files matching "${pattern}":`)); console.log(); files.forEach((file, index) => { const icon = file.isGitTracked ? '📝' : '📄'; const size = this.formatFileSize(file.size); console.log(`${(index + 1).toString().padStart(2)}. ${icon} ${chalk_1.default.cyan(file.relativePath)} ${chalk_1.default.gray(`(${size})`)}`); }); return { success: true, output: `Found ${files.length} files` }; } 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]; } 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'; } } // Placeholder implementations for other enhanced commands class EnhancedConfigCommand { constructor() { this.name = 'config'; this.description = 'Show and manage configuration'; this.scope = 'builtin'; } async execute(args, context) { if (args[0] === 'show') { console.log(chalk_1.default.blue('⚙️ Full Configuration:')); console.log(JSON.stringify(context.config, null, 2)); } else { console.log(chalk_1.default.blue('⚙️ Configuration Summary:')); console.log(); console.log(chalk_1.default.cyan('Model:'), context.config.model); console.log(chalk_1.default.cyan('Permission Mode:'), context.config.permissions.mode); console.log(chalk_1.default.cyan('Memory Auto-load:'), context.config.memory.autoLoad); console.log(); console.log(chalk_1.default.gray('Use "/config show" for full JSON configuration')); } return { success: true, output: 'Configuration displayed' }; } } class EnhancedHooksCommand { constructor() { this.name = 'hooks'; this.description = 'Test and manage hooks'; this.scope = 'builtin'; } async execute(_args, context) { console.log(chalk_1.default.blue('🔧 Testing hooks...')); // Test tool execution with hooks const toolContext = { sessionId: context.session.id, cwd: context.cwd, timestamp: new Date(), }; try { const result = await context.toolExecutor.executeTool('Read', { file_path: 'package.json' }, toolContext); 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) + '...'); } return { success: true, output: 'Hooks tested' }; } catch (error) { console.log(chalk_1.default.red('Hook test failed:'), error); return { success: false, error: 'Hook test failed' }; } } } // Add other enhanced command implementations... class EnhancedCustomCommand { constructor() { this.name = 'custom'; this.description = 'Manage custom commands'; this.scope = 'builtin'; } async execute(_args, _context) { return { success: true, output: 'Custom command placeholder' }; } } class EnhancedInitCommandsCommand { constructor() { this.name = 'init-commands'; this.description = 'Initialize genetic development commands'; this.scope = 'builtin'; } async execute(_args, _context) { return { success: true, output: 'Init commands placeholder' }; } } class EnhancedSetupCommand { constructor() { this.name = 'setup'; this.description = 'Project setup and configuration'; this.scope = 'builtin'; } async execute(_args, _context) { return { success: true, output: 'Setup placeholder' }; } } class EnhancedContinueCommand { constructor() { this.name = 'continue'; this.description = 'Continue from previous conversation'; this.scope = 'builtin'; } async execute(_args, _context) { return { success: true, output: 'Continue placeholder' }; } } class EnhancedMemoryCommand { constructor() { this.name = 'memory'; this.description = 'Manage memory files and project context'; this.scope = 'builtin'; } async execute(args, context) { const subcommand = args[0] || 'status'; switch (subcommand) { case 'status': return this.showStatus(context); case 'load': return this.loadMemory(context); case 'reload': return this.reloadMemory(context); case 'create': return this.createMemoryFile(args, context); case 'add': return this.addToMemory(args, context); case 'search': return this.searchMemory(args, context); case 'show': return this.showMemoryContent(args, context); case 'clear': return this.clearMemory(context); case 'help': return this.showHelp(); default: return { success: false, error: `Unknown memory command: ${subcommand}. Use '/memory help' for available commands.` }; } } async showStatus(context) { try { const memoryManager = context.memoryManager; if (!memoryManager) { return { success: false, error: 'Memory manager not available' }; } const stats = memoryManager.getMemoryStats(); console.log(chalk_1.default.blue('🧠 Memory Status:')); console.log(); console.log(chalk_1.default.cyan('Total files:'), stats.totalFiles); console.log(chalk_1.default.cyan('User files:'), stats.userFiles); console.log(chalk_1.default.cyan('Project files:'), stats.projectFiles); console.log(chalk_1.default.cyan('Local files:'), stats.localFiles); console.log(chalk_1.default.cyan('Total size:'), this.formatSize(stats.totalSize)); if (stats.totalFiles === 0) { console.log(); console.log(chalk_1.default.yellow('No memory files loaded.')); console.log(chalk_1.default.gray('Use "/memory create" to create a GROK.md file')); } return { success: true, output: `Memory status: ${stats.totalFiles} files loaded` }; } catch (error) { return { success: false, error: `Failed to show memory status: ${error instanceof Error ? error.message : String(error)}` }; } } async loadMemory(context) { try { const memoryManager = context.memoryManager; if (!memoryManager) { return { success: false, error: 'Memory manager not available' }; } await memoryManager.loadMemoryFiles(); const stats = memoryManager.getMemoryStats(); console.log(chalk_1.default.green(`✅ Loaded ${stats.totalFiles} memory files`)); return { success: true, output: `Loaded ${stats.totalFiles} memory files` }; } catch (error) { return { success: false, error: `Failed to load memory: ${error instanceof Error ? error.message : String(error)}` }; } } async reloadMemory(context) { try { const memoryManager = context.memoryManager; if (!memoryManager) { return { success: false, error: 'Memory manager not available' }; } await memoryManager.reloadMemory(); const stats = memoryManager.getMemoryStats(); console.log(chalk_1.default.green(`✅ Reloaded ${stats.totalFiles} memory files`)); return { success: true, output: `Reloaded ${stats.totalFiles} memory files` }; } catch (error) { return { success: false, error: `Failed to reload memory: ${error instanceof Error ? error.message : String(error)}` }; } } async createMemoryFile(args, context) { try { const memoryManager = context.memoryManager; if (!memoryManager) { return { success: false, error: 'Memory manager not available' }; } const filePath = args[1]; // Optional custom path await memoryManager.createMemoryFile(filePath); return { success: true, output: 'Memory file created successfully' }; } catch (error) { return { success: false, error: `Failed to create memory file: ${error instanceof Error ? error.message : String(error)}` }; } } async addToMemory(args, context) { const content = args.slice(1).join(' '); if (!content) { return { success: false, error: 'Usage: /memory add <content>' }; } try { const memoryManager = context.memoryManager; if (!memoryManager) { return { success: false, error: 'Memory manager not available' }; } await memoryManager.addToMemory(content, 'note'); return { success: true, output: 'Content added to memory' }; } catch (error) { return { success: false, error: `Failed to add to memory: ${error instanceof Error ? error.message : String(error)}` }; } } async searchMemory(args, context) { const query = args.slice(1).join(' '); if (!query) { return { success: false, error: 'Usage: /memory search <query>' }; } try { const memoryManager = context.memoryManager; if (!memoryManager) { return { success: false, error: 'Memory manager not available' }; } const results = memoryManager.searchMemory(query); if (results.length === 0) { console.log(chalk_1.default.yellow(`No results found for "${query}"`)); return { success: true, output: 'No results found' }; } console.log(chalk_1.default.blue(`🔍 Search Results for "${query}" (${results.length} files):`)); console.log(); results.forEach((result, index) => { const relativePath = result.file.path.includes(context.cwd) ? result.file.path.replace(context.cwd, '.') : result.file.path; console.log(`${(index + 1).toString().padStart(2)}. ${chalk_1.default.cyan(relativePath)} (${result.file.type})`); result.matches.forEach((match) => { console.log(` Line ${match.line}: ${chalk_1.default.gray(match.content.trim())}`); }); console.log(); }); return { success: true, output: `Found ${results.length} matches` }; } catch (error) { return { success: false, error: `Failed to search memory: ${error instanceof Error ? error.message : String(error)}` }; } } async showMemoryContent(args, context) { try { const memoryManager = context.memoryManager; if (!memoryManager) { return { success: false, error: 'Memory manager not available' }; } const fileType = args[1]; // Optional filter: user, project, local const files = memoryManager.getMemoryFiles(); let filteredFiles = files; if (fileType) { filteredFiles = files.filter((f) => f.type === fileType); } if (filteredFiles.length === 0) { console.log(chalk_1.default.yellow('No memory files to show')); return { success: true, output: 'No memory files' }; } console.log(chalk_1.default.blue(`📄 Memory Files (${filteredFiles.length}):`)); console.log(); filteredFiles.forEach((file, index) => { const relativePath = file.path.includes(context.cwd) ? file.path.replace(context.cwd, '.') : file.path; console.log(`${(index + 1).toString().padStart(2)}. ${chalk_1.default.cyan(relativePath)} (${file.type})`); console.log(` Size: ${this.formatSize(file.content.length)}`); console.log(` Imports: ${file.imports.length > 0 ? file.imports.join(', ') : 'none'}`); console.log(); }); return { success: true, output: `Listed ${filteredFiles.length} memory files` }; } catch (error) { return { success: false, error: `Failed to show memory content: ${error instanceof Error ? error.message : String(error)}` }; } } async clearMemory(context) { try { const memoryManager = context.memoryManager; if (!memoryManager) { return { success: false, error: 'Memory manager not available' }; } memoryManager.clearMemory(); return { success: true, output: 'Memory cleared' }; } catch (error) { return { success: false, error: `Failed to clear memory: ${error instanceof Error ? error.message : String(error)}` }; } } showHelp() { console.log(chalk_1.default.blue('🧠 Memory Commands:')); console.log(); console.log(chalk_1.default.cyan('/memory status') + chalk_1.default.gray(' - Show memory status and statistics')); console.log(chalk_1.default.cyan('/memory load') + chalk_1.default.gray(' - Load memory files from disk')); console.log(chalk_1.default.cyan('/memory reload') + chalk_1.default.gray(' - Reload all memory files')); console.log(chalk_1.default.cyan('/memory create [path]') + chalk_1.default.gray(' - Create new GROK.md file')); console.log(chalk_1.default.cyan('/memory add <content>') + chalk_1.default.gray(' - Add content to memory')); console.log(chalk_1.default.cyan('/memory search <query>') + chalk_1.default.gray(' - Search memory content')); console.log(chalk_1.default.cyan('/memory show [type]') + chalk_1.default.gray(' - Show memory files (user/project/local)')); console.log(chalk_1.default.cyan('/memory clear') + chalk_1.default.gray(' - Clear loaded memory')); console.log(); console.log(chalk_1.default.blue('📝 Examples:')); console.log(chalk_1.default.gray(' /memory create')); console.log(chalk_1.default.gray(' /memory add "Important: Use TypeScript strict mode"')); console.log(chalk_1.default.gray(' /memory search "API key"')); console.log(chalk_1.default.gray(' /memory show project')); return { success: true, output: 'Memory help displayed' }; } formatSize(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; } } class EnhancedMcpCommand { constructor() { this.name = 'mcp'; this.description = 'Manage MCP servers'; this.scope = 'builtin'; } async execute(args, context) { const subcommand = args[0] || 'help'; switch (subcommand) { case 'add': return this.addServer(args, context); case 'list': return this.listServers(args, context); case 'status': return this.showStatus(args, context); case 'connect': return this.connectServer(args, context); case 'disconnect': return this.disconnectServer(args, context); case 'remove': return this.removeServer(args, context); case 'tools': return this.listTools(args, context); case 'test': return this.testTool(args, context); case 'help': return this.showHelp(); default: return { success: false, error: `Unknown MCP command: ${subcommand}. Use '/mcp help' for available commands.` }; } } async addServer(args, context) { if (args.length < 3) { return { success: false, error: 'Usage: /mcp add <name> <command> [args...]' }; } const [, name, command, ...serverArgs] = args; try { // Get MCP client from context (we'll need to add this to the context) const mcpClient = context.mcpClient; if (!mcpClient) { return { success: false, error: 'MCP client not available' }; } // Add the server configuration mcpClient.addServer(name, { command, args: serverArgs.length > 0 ? serverArgs : undefined }); console.log(chalk_1.default.green(`✅ Added MCP server: ${name}`)); console.log(chalk_1.default.gray(`Command: ${command} ${serverArgs.join(' ')}`)); // Try to connect immediately try { await mcpClient.connectServer(name); console.log(chalk_1.default.green(`🔗 Connected to ${name}`)); } catch (error) { console.log(chalk_1.default.yellow(`⚠️ Added server but failed to connect: ${error instanceof Error ? error.message : String(error)}`)); } return { success: true, output: `Added MCP server: ${name}` }; } catch (error) { return { success: false, error: `Failed to add server: ${error instanceof Error ? error.message : String(error)}` }; } } async listServers(args, context) { try { const mcpClient = context.mcpClient; if (!mcpClient) { return { success: false, error: 'MCP client not available' }; } const servers = mcpClient.getAllServers(); if (servers.length === 0) { console.log(chalk_1.default.yellow('No MCP servers configured')); console.log(); console.log(chalk_1.default.gray('Use "/mcp add <name> <command>" to add a server')); return { success: true, output: 'No servers configured' }; } const verbose = args.includes('--verbose') || args.includes('-v'); console.log(chalk_1.default.blue(`🔧 MCP Servers (${servers.length}):`)); console.log(); servers.forEach((server, index) => { const statusIcon = server.status === 'connected' ? '🟢' : server.status === 'connecting' ? '🟡' : server.status === 'error' ? '🔴' : '⚪'; console.log(`${(index + 1).toString().padStart(2)}. ${statusIcon} ${chalk_1.default.cyan(server.name)} ${chalk_1.default.gray(`(${server.status})`)}`); console.log(` ${chalk_1.default.gray(`Command: ${server.config.command}${server.config.args ? ' ' + server.config.args.join(' ') : ''}`)}`); if (verbose && server.status === 'connected') { if (server.tools.length > 0) { console.log(` ${chalk_1.default.gray(`Tools: ${server.tools.join(', ')}`)}`); } if (server.prompts.length > 0) { console.log(` ${chalk_1.default.gray(`Prompts: ${server.prompts.join(', ')}`)}`); } } console.log(); }); const stats = mcpClient.getStats(); console.log(chalk_1.default.blue('📊 Summary:')); console.log(chalk_1.default.cyan(' Connected:'), `${stats.connectedServers}/${stats.totalServers}`); console.log(chalk_1.default.cyan(' Total tools:'), stats.totalTools); console.log(chalk_1.default.cyan(' Total prompts:'), stats.totalPrompts); console.log(chalk_1.default.cyan(' Total resources:'), stats.totalResources); return { success: true, output: `Listed ${servers.length} servers` }; } catch (error) { return { success: false, error: `Failed to list servers: ${error instanceof Error ? error.message : String(error)}` }; } } async showStatus(args, context) { const serverName = args[1]; try { const mcpClient = context.mcpClient; if (!mcpClient) { return { success: false, error: 'MCP client not available' }; } if (serverName) { const server = mcpClient.getServer(serverName); if (!server) { return { success: false, error: `Server ${serverName} not found` }; } console.log(chalk_1.default.blue(`📊 Status for ${serverName}:`)); console.log(); console.log(chalk_1.default.cyan('Status:'), server.status); console.log(chalk_1.default.cyan('Command:'), `${server.config.command}${server.config.args ? ' ' + server.config.args.join(' ') : ''}`); console.log(chalk_1.default.cyan('Tools:'), server.tools.length); console.log(chalk_1.default.cyan('Prompts:'), server.prompts.length); console.log(chalk_1.default.cyan('Resources:'), server.resources.length); if (server.tools.length > 0) { console.log(); console.log(chalk_1.default.blue('🔧 Available Tools:')); server.tools.forEach((tool) => { console.log(` • ${chalk_1.default.cyan(tool.name)} - ${tool.description}`); }); } return { success: true, output: `Status for ${serverName}` }; } else { return this.listServers(['--verbose'], context); } } catch (error) { return { success: false, error: `Failed to show status: ${error instanceof Error ? error.message : String(error)}` }; } } async connectServer(args, context) { const serverName = args[1]; if (!serverName) { return { success: false, error: 'Usage: /mcp connect <server-name>' }; } try { const mcpClient = context.mcpClient; if (!mcpClient) { return { success: false, error: 'MCP client not available' }; } console.log(chalk_1.default.blue(`🔗 Connecting to ${serverName}...`)); await mcpClient.connectServer(serverName); console.log(chalk_1.default.green(`✅ Connected to ${serverName}`)); return { success: true, output: `Connected to ${serverName}` }; } catch (error) { return { success: false, error: `Failed to connect: ${error instanceof Error ? error.message : String(error)}` }; } } async disconnectServer(args, context) { const serverName = args[1]; if (!serverName) { return { success: false, error: 'Usage: /mcp disconnect <server-name>' }; } try { const mcpClient = context.mcpClient; if (!mcpClient) { return { success: false, error: 'MCP client not available' }; } const server = mcpClient.getServer(serverName); if (!server) { return { success: false, error: `Server ${serverName} not found` }; } await server.disconnect(); console.log(chalk_1.default.green(`✅ Disconnected from ${serverName}`)); return { success: true, output: `Disconnected from ${serverName}` }; } catch (error) { return { success: false, error: `Failed to disconnect: ${error instanceof Error ? error.message : String(error)}` }; } } async removeServer(args, context) { const serverName = args[1]; if (!serverName) { return { success: false, error: 'Usage: /mcp remove <server-name>' }; } try { const mcpClient = context.mcpClient; if (!mcpClient) { return { success: false, error: 'MCP client not available' }; } await mcpClient.removeServer(serverName); console.log(chalk_1.default.green(`✅ Removed server: ${serverName}`)); return { success: true, output: `Removed server: ${serverName}` }; } catch (error) { return { success: false, error: `Failed to remove server: ${error instanceof Error ? error.message : String(error)}` }; } } async listTools(_args, context) { try { const mc