/** * Enhanced Terminal Service * Integrates modular tool system with intent analysis for agentic chat * * This service provides: * - Modular tool system with registry * - Enhanced intent analysis * - Automatic error handling and output formatting * - Execution history and statistics * - Security checks and validation */ const { ToolRegistry } = require('./tool-base.cjs'); const { ShellTool, StreamingShellTool } = require('./shell-tool.cjs'); const { FileOperationTool } = require('./file-tool.cjs'); const { IntentAnalyzer } = require('./intent-analyzer.cjs'); class EnhancedTerminalService { constructor(config = {}) { this.config = { defaultTimeout: config.defaultTimeout || 30000, maxOutputSize: config.maxOutputSize || 100000, enableSecurity: config.enableSecurity !== false, enableHistory: config.enableHistory !== false, enableTelemetry: config.enableTelemetry !== false, ...config }; // Initialize tool registry this.registry = new ToolRegistry(); // Initialize intent analyzer this.analyzer = new IntentAnalyzer({ tools: [], history: [] }); // Initialize stats this.stats = { totalCommands: 0, successfulCommands: 0, failedCommands: 0, commandByType: {}, avgResponseTime: 0 }; // Setup default tools this.setupDefaultTools(); // Setup middleware this.setupMiddleware(); } /** * Register default tools */ setupDefaultTools() { // Shell command tool this.registry.register(new ShellTool({ defaultTimeout: this.config.defaultTimeout, maxOutputSize: this.config.maxOutputSize })); // Streaming shell for long commands this.registry.register(new StreamingShellTool({ defaultTimeout: this.config.defaultTimeout })); // File operations tool this.registry.register(new FileOperationTool({ maxFileSize: this.config.maxFileSize, allowedPaths: this.config.allowedPaths })); // Update analyzer with available tools this.analyzer.setTools(this.registry.list()); } /** * Setup execution middleware */ setupMiddleware() { // Logging middleware this.registry.use({ before: async (toolName, params) => { console.log(`[EnhancedTerminal] Executing: ${toolName}`, { params: JSON.stringify(params).substring(0, 100) }); }, after: async (toolName, params, result) => { if (result.success) { console.log(`[EnhancedTerminal] Success: ${toolName}`); } else { console.error(`[EnhancedTerminal] Failed: ${toolName}`, result.error?.message); } } }); // Telemetry middleware if (this.config.enableTelemetry) { this.registry.use({ after: async (toolName, params, result) => { this.recordTelemetry(toolName, result); } }); } } /** * Execute a command with automatic intent analysis * * @param {string} input - User input or command * @param {Object} options - Execution options * @returns {Promise} Execution result */ async execute(input, options = {}) { const startTime = Date.now(); try { // Analyze intent const intent = this.analyzer.analyze(input); // Check if intent is valid (has sufficient confidence and a tool) const isValid = intent.confidence > 0.3 && intent.tool; if (!isValid) { return { success: false, output: 'Could not determine command intent', intent: intent, error: 'Invalid intent' }; } // Execute with detected tool const result = await this.registry.execute(intent.tool, intent.parameters); // Learn from execution this.analyzer.learn(input, result); // Update stats this.updateStats(intent.intent, result, Date.now() - startTime); // Format output return { success: result.success, output: result.output, data: result.data, intent: intent, duration: Date.now() - startTime, metadata: result.metadata }; } catch (error) { return { success: false, output: error.message, error: error.message, duration: Date.now() - startTime }; } } /** * Execute a specific tool directly * * @param {string} toolName - Name of tool to execute * @param {Object} parameters - Tool parameters * @returns {Promise} Execution result */ async executeTool(toolName, parameters = {}) { const startTime = Date.now(); try { const result = await this.registry.execute(toolName, parameters); return { success: result.success, output: result.output, data: result.data, duration: Date.now() - startTime, metadata: result.metadata }; } catch (error) { return { success: false, output: error.message, error: error.message, duration: Date.now() - startTime }; } } /** * Execute a shell command directly * * @param {string} command - Shell command to execute * @param {Object} options - Execution options * @returns {Promise} Execution result */ async executeShell(command, options = {}) { return this.executeTool('shell', { command, cwd: options.cwd, timeout: options.timeout, env: options.env }); } /** * Get command suggestions based on history * * @param {string} input - Partial input * @returns {Array} Suggestions */ getSuggestions(input = '') { return this.analyzer.getSuggestions(input); } /** * Get execution history * * @param {Object} options - Query options * @returns {Array} History records */ getHistory(options = {}) { return this.registry.getHistory(options); } /** * Get service statistics * * @returns {Object} Statistics */ getStats() { return { ...this.stats, registry: this.registry.getStats(), tools: this.registry.listMetadata() }; } /** * Get available tools * * @returns {Array} Tool metadata */ getAvailableTools() { return this.registry.listMetadata(); } /** * Add a custom tool * * @param {BaseTool} tool - Tool to register */ addTool(tool) { this.registry.register(tool); this.analyzer.setTools(this.registry.list()); return this; } /** * Update service configuration * * @param {Object} updates - Configuration updates */ updateConfig(updates) { Object.assign(this.config, updates); return this; } /** * Record telemetry data */ recordTelemetry(toolName, result) { // Implementation depends on telemetry system // Could send to analytics service, log file, etc. } /** * Update statistics */ updateStats(intent, result, duration) { this.stats.totalCommands++; if (result.success) { this.stats.successfulCommands++; } else { this.stats.failedCommands++; } this.stats.commandByType[intent] = (this.stats.commandByType[intent] || 0) + 1; // Update average response time const totalDuration = this.stats.avgResponseTime * (this.stats.totalCommands - 1) + duration; this.stats.avgResponseTime = totalDuration / this.stats.totalCommands; } /** * Reset statistics */ resetStats() { this.stats = { totalCommands: 0, successfulCommands: 0, failedCommands: 0, commandByType: {}, avgResponseTime: 0 }; this.registry.clearHistory(); } /** * Health check * * @returns {Object} Health status */ healthCheck() { return { status: 'healthy', tools: this.registry.list().length, uptime: process.uptime(), memory: process.memoryUsage(), stats: this.getStats() }; } /** * Cleanup resources */ async cleanup() { this.registry.clearHistory(); this.resetStats(); } } /** * Factory function to create a service instance */ function createEnhancedTerminalService(config = {}) { return new EnhancedTerminalService(config); } module.exports = { EnhancedTerminalService, createEnhancedTerminalService };