UNPKG

claude-flow-tbowman01

Version:

Enterprise-grade AI agent orchestration with ruv-swarm integration (Alpha Release)

206 lines 7.05 kB
import { TerminalCommandError } from '../utils/errors.js'; import { generateId, timeout } from '../utils/helpers.js'; /** * Terminal session wrapper */ export class TerminalSession { terminal; profile; commandTimeout; logger; id; startTime; initialized = false; commandHistory = []; lastCommandTime; outputListeners = new Set(); constructor(terminal, profile, commandTimeout, logger) { this.terminal = terminal; this.profile = profile; this.commandTimeout = commandTimeout; this.logger = logger; this.id = generateId('session'); this.startTime = new Date(); } get lastActivity() { return this.lastCommandTime || this.startTime; } async initialize() { if (this.initialized) { return; } this.logger.debug('Initializing terminal session', { sessionId: this.id, agentId: this.profile.id, }); try { // Set up environment await this.setupEnvironment(); // Run initialization commands await this.runInitializationCommands(); this.initialized = true; this.logger.info('Terminal session initialized', { sessionId: this.id, agentId: this.profile.id, }); } catch (error) { this.logger.error('Failed to initialize terminal session', error); throw error; } } async executeCommand(command) { if (!this.initialized) { throw new TerminalCommandError('Session not initialized'); } if (!this.terminal.isAlive()) { throw new TerminalCommandError('Terminal is not alive'); } this.logger.debug('Executing command', { sessionId: this.id, command: command.substring(0, 100), }); try { // Notify listeners of command this.notifyOutputListeners(`$ ${command}\n`); // Execute with timeout const result = await timeout(this.terminal.executeCommand(command), this.commandTimeout, `Command timeout after ${this.commandTimeout}ms`); // Notify listeners of output this.notifyOutputListeners(result); // Update history this.commandHistory.push(command); this.lastCommandTime = new Date(); this.logger.debug('Command executed successfully', { sessionId: this.id, outputLength: result.length, }); return result; } catch (error) { this.logger.error('Command execution failed', { sessionId: this.id, command, error, }); throw new TerminalCommandError('Command execution failed', { command, error, }); } } async cleanup() { this.logger.debug('Cleaning up terminal session', { sessionId: this.id }); try { // Run cleanup commands await this.runCleanupCommands(); } catch (error) { this.logger.warn('Error during session cleanup', { sessionId: this.id, error, }); } } isHealthy() { if (!this.terminal.isAlive()) { return false; } // Check if terminal is responsive if (this.lastCommandTime) { const timeSinceLastCommand = Date.now() - this.lastCommandTime.getTime(); if (timeSinceLastCommand > 300000) { // 5 minutes // Terminal might be stale, do a health check this.performHealthCheck().catch((error) => { this.logger.warn('Health check failed', { sessionId: this.id, error }); }); } } return true; } getCommandHistory() { return [...this.commandHistory]; } async setupEnvironment() { // Set environment variables const envVars = { CLAUDE_FLOW_SESSION: this.id, CLAUDE_FLOW_AGENT: this.profile.id, CLAUDE_FLOW_AGENT_TYPE: this.profile.type, }; for (const [key, value] of Object.entries(envVars)) { await this.terminal.executeCommand(`export ${key}="${value}"`); } // Set working directory if specified if (this.profile.metadata?.workingDirectory) { await this.terminal.executeCommand(`cd "${this.profile.metadata.workingDirectory}"`); } } async runInitializationCommands() { // Run any profile-specific initialization commands if (this.profile.metadata?.initCommands) { const commands = this.profile.metadata.initCommands; for (const command of commands) { await this.terminal.executeCommand(command); } } // Set up command prompt await this.terminal.executeCommand('export PS1="[claude-flow]$ "'); } async runCleanupCommands() { // Run any profile-specific cleanup commands if (this.profile.metadata?.cleanupCommands) { const commands = this.profile.metadata.cleanupCommands; for (const command of commands) { try { await this.terminal.executeCommand(command); } catch { // Ignore cleanup errors } } } } async performHealthCheck() { try { const result = await timeout(this.terminal.executeCommand('echo "HEALTH_CHECK_OK"'), 5000, 'Health check timeout'); if (!result.includes('HEALTH_CHECK_OK')) { throw new Error('Invalid health check response'); } this.lastCommandTime = new Date(); } catch (error) { throw new Error(`Health check failed: ${error instanceof Error ? error.message : String(error)}`); } } /** * Stream terminal output */ streamOutput(callback) { this.outputListeners.add(callback); // Set up terminal output listener if supported if (this.terminal.addOutputListener) { this.terminal.addOutputListener(callback); } // Return unsubscribe function return () => { this.outputListeners.delete(callback); if (this.terminal.removeOutputListener) { this.terminal.removeOutputListener(callback); } }; } /** * Notify output listeners */ notifyOutputListeners(output) { this.outputListeners.forEach(listener => { try { listener(output); } catch (error) { this.logger.error('Error in output listener', { sessionId: this.id, error }); } }); } } //# sourceMappingURL=session.js.map