@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
JavaScript
"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