UNPKG

jay-code

Version:

Streamlined AI CLI orchestration engine with mathematical rigor and enterprise-grade reliability

1,324 lines (1,189 loc) 37.1 kB
/** * Jay-Code specific MCP tools */ import type { MCPTool, MCPContext, AgentProfile, Task, MemoryEntry } from '../utils/types.js'; import type { ILogger } from '../core/logger.js'; import { getAvailableAgentTypes, getAgentTypeSchema } from '../constants/agent-types.js'; import type { Permissions } from './auth.js'; export interface ClaudeFlowToolContext extends MCPContext { orchestrator?: any; // Reference to orchestrator instance } /** * Enhance tool schema with dynamic agent types */ async function enhanceToolWithAgentTypes(tool: MCPTool): Promise<MCPTool> { const availableTypes = await getAvailableAgentTypes(); // Clone the tool to avoid modifying the original const enhancedTool = JSON.parse(JSON.stringify(tool)); // Find and populate enum fields for agent types function addEnumToAgentTypeFields(obj: any) { if (typeof obj !== 'object' || obj === null) return; for (const [key, value] of Object.entries(obj)) { if (typeof value === 'object' && value !== null) { // Check if this is an agent type field if (key === 'type' || key === 'filterByType' || key === 'assignToAgentType') { const field = value as any; if (field.type === 'string' && field.description?.includes('loaded dynamically from .claude/agents/')) { field.enum = availableTypes; } } addEnumToAgentTypeFields(value); } } } addEnumToAgentTypeFields(enhancedTool.inputSchema); return enhancedTool; } /** * Create all Jay-Code specific MCP tools */ export async function createClaudeFlowTools(logger: ILogger): Promise<MCPTool[]> { const tools = [ // Agent management tools createSpawnAgentTool(logger), createListAgentsTool(logger), createTerminateAgentTool(logger), createGetAgentInfoTool(logger), // Task management tools createCreateTaskTool(logger), createListTasksTool(logger), createGetTaskStatusTool(logger), createCancelTaskTool(logger), createAssignTaskTool(logger), // Memory management tools createQueryMemoryTool(logger), createStoreMemoryTool(logger), createDeleteMemoryTool(logger), createExportMemoryTool(logger), createImportMemoryTool(logger), // System monitoring tools createGetSystemStatusTool(logger), createGetMetricsTool(logger), createHealthCheckTool(logger), // Configuration tools createGetConfigTool(logger), createUpdateConfigTool(logger), createValidateConfigTool(logger), // Workflow tools createExecuteWorkflowTool(logger), createCreateWorkflowTool(logger), createListWorkflowsTool(logger), // Terminal management tools createExecuteCommandTool(logger), createListTerminalsTool(logger), createCreateTerminalTool(logger), ]; // Enhance tools with dynamic agent types const enhancedTools = await Promise.all( tools.map(tool => enhanceToolWithAgentTypes(tool)) ); return enhancedTools; } function createSpawnAgentTool(logger: ILogger): MCPTool { return { name: 'agents/spawn', description: 'Spawn a new Claude agent with specified configuration', inputSchema: { type: 'object', properties: { type: { type: 'string', // Note: enum will be populated dynamically at runtime description: 'Type of specialized agent to spawn (loaded dynamically from .claude/agents/)', }, name: { type: 'string', description: 'Display name for the agent', }, capabilities: { type: 'array', items: { type: 'string' }, description: 'List of capabilities for the agent', }, systemPrompt: { type: 'string', description: 'Custom system prompt for the agent', }, maxConcurrentTasks: { type: 'number', default: 3, description: 'Maximum number of concurrent tasks', }, priority: { type: 'number', default: 5, description: 'Agent priority level (1-10)', }, environment: { type: 'object', description: 'Environment variables for the agent', }, workingDirectory: { type: 'string', description: 'Working directory for the agent', }, }, required: ['type', 'name'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Spawning agent', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const profile: AgentProfile = { id: `agent_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, name: input.name, type: input.type, capabilities: input.capabilities || [], systemPrompt: input.systemPrompt || getDefaultSystemPrompt(input.type), maxConcurrentTasks: input.maxConcurrentTasks || 3, priority: input.priority || 5, environment: input.environment, workingDirectory: input.workingDirectory, }; const sessionId = await context.orchestrator.spawnAgent(profile); return { agentId: profile.id, sessionId, profile, status: 'spawned', timestamp: new Date().toISOString(), }; }, }; } function createListAgentsTool(logger: ILogger): MCPTool { return { name: 'agents/list', description: 'List all active agents in the system', inputSchema: { type: 'object', properties: { includeTerminated: { type: 'boolean', default: false, description: 'Include terminated agents in the list', }, filterByType: { type: 'string', // Note: enum will be populated dynamically at runtime description: 'Filter agents by type (loaded dynamically from .claude/agents/)', }, }, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Listing agents', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const agents = await context.orchestrator.listAgents(); let filteredAgents = agents; if (!input.includeTerminated) { filteredAgents = filteredAgents.filter((agent: any) => agent.status !== 'terminated'); } if (input.filterByType) { filteredAgents = filteredAgents.filter((agent: any) => agent.type === input.filterByType); } return { agents: filteredAgents, count: filteredAgents.length, timestamp: new Date().toISOString(), }; }, }; } function createTerminateAgentTool(logger: ILogger): MCPTool { return { name: 'agents/terminate', description: 'Terminate a specific agent', inputSchema: { type: 'object', properties: { agentId: { type: 'string', description: 'ID of the agent to terminate', }, reason: { type: 'string', description: 'Reason for termination', }, graceful: { type: 'boolean', default: true, description: 'Whether to perform graceful shutdown', }, }, required: ['agentId'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Terminating agent', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } await context.orchestrator.terminateAgent(input.agentId, { reason: input.reason || 'Manual termination', graceful: input.graceful !== false, }); return { agentId: input.agentId, status: 'terminated', reason: input.reason || 'Manual termination', timestamp: new Date().toISOString(), }; }, }; } function createGetAgentInfoTool(logger: ILogger): MCPTool { return { name: 'agents/info', description: 'Get detailed information about a specific agent', inputSchema: { type: 'object', properties: { agentId: { type: 'string', description: 'ID of the agent', }, }, required: ['agentId'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Getting agent info', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const agentInfo = await context.orchestrator.getAgentInfo(input.agentId); if (!agentInfo) { throw new Error(`Agent not found: ${input.agentId}`); } return { agent: agentInfo, timestamp: new Date().toISOString(), }; }, }; } function createCreateTaskTool(logger: ILogger): MCPTool { return { name: 'tasks/create', description: 'Create a new task for execution', inputSchema: { type: 'object', properties: { type: { type: 'string', description: 'Type of task to create', }, description: { type: 'string', description: 'Description of the task', }, priority: { type: 'number', default: 5, description: 'Task priority (1-10)', }, dependencies: { type: 'array', items: { type: 'string' }, description: 'List of task IDs this task depends on', }, assignToAgent: { type: 'string', description: 'Specific agent ID to assign the task to', }, assignToAgentType: { type: 'string', // Note: enum will be populated dynamically at runtime description: 'Type of specialized agent to assign the task to (loaded dynamically from .claude/agents/)', }, input: { type: 'object', description: 'Input data for the task', }, timeout: { type: 'number', description: 'Task timeout in milliseconds', }, }, required: ['type', 'description'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Creating task', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const task: Partial<Task> = { type: input.type, description: input.description, priority: input.priority || 5, dependencies: input.dependencies || [], input: input.input || {}, status: 'pending', createdAt: new Date(), }; const taskId = await context.orchestrator.createTask(task); // Handle assignment if (input.assignToAgent) { await context.orchestrator.assignTask(taskId, input.assignToAgent); } else if (input.assignToAgentType) { await context.orchestrator.assignTaskToType(taskId, input.assignToAgentType); } return { taskId, task: { ...task, id: taskId }, timestamp: new Date().toISOString(), }; }, }; } function createListTasksTool(logger: ILogger): MCPTool { return { name: 'tasks/list', description: 'List tasks with optional filtering', inputSchema: { type: 'object', properties: { status: { type: 'string', enum: ['pending', 'queued', 'assigned', 'running', 'completed', 'failed', 'cancelled'], description: 'Filter by task status', }, agentId: { type: 'string', description: 'Filter by assigned agent ID', }, type: { type: 'string', description: 'Filter by task type', }, limit: { type: 'number', default: 50, description: 'Maximum number of tasks to return', }, offset: { type: 'number', default: 0, description: 'Number of tasks to skip', }, }, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Listing tasks', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const tasks = await context.orchestrator.listTasks({ status: input.status, agentId: input.agentId, type: input.type, limit: input.limit || 50, offset: input.offset || 0, }); return { tasks, count: tasks.length, timestamp: new Date().toISOString(), }; }, }; } function createGetTaskStatusTool(logger: ILogger): MCPTool { return { name: 'tasks/status', description: 'Get detailed status of a specific task', inputSchema: { type: 'object', properties: { taskId: { type: 'string', description: 'ID of the task', }, }, required: ['taskId'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Getting task status', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const task = await context.orchestrator.getTask(input.taskId); if (!task) { throw new Error(`Task not found: ${input.taskId}`); } return { task, timestamp: new Date().toISOString(), }; }, }; } function createCancelTaskTool(logger: ILogger): MCPTool { return { name: 'tasks/cancel', description: 'Cancel a pending or running task', inputSchema: { type: 'object', properties: { taskId: { type: 'string', description: 'ID of the task to cancel', }, reason: { type: 'string', description: 'Reason for cancellation', }, }, required: ['taskId'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Cancelling task', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } await context.orchestrator.cancelTask(input.taskId, input.reason || 'Manual cancellation'); return { taskId: input.taskId, status: 'cancelled', reason: input.reason || 'Manual cancellation', timestamp: new Date().toISOString(), }; }, }; } function createAssignTaskTool(logger: ILogger): MCPTool { return { name: 'tasks/assign', description: 'Assign a task to a specific agent', inputSchema: { type: 'object', properties: { taskId: { type: 'string', description: 'ID of the task to assign', }, agentId: { type: 'string', description: 'ID of the agent to assign the task to', }, }, required: ['taskId', 'agentId'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Assigning task', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } await context.orchestrator.assignTask(input.taskId, input.agentId); return { taskId: input.taskId, agentId: input.agentId, status: 'assigned', timestamp: new Date().toISOString(), }; }, }; } function createQueryMemoryTool(logger: ILogger): MCPTool { return { name: 'memory/query', description: 'Query agent memory with filters and search', inputSchema: { type: 'object', properties: { agentId: { type: 'string', description: 'Filter by agent ID', }, sessionId: { type: 'string', description: 'Filter by session ID', }, type: { type: 'string', enum: ['observation', 'insight', 'decision', 'artifact', 'error'], description: 'Filter by entry type', }, tags: { type: 'array', items: { type: 'string' }, description: 'Filter by tags', }, search: { type: 'string', description: 'Full-text search query', }, startTime: { type: 'string', format: 'date-time', description: 'Filter entries after this time', }, endTime: { type: 'string', format: 'date-time', description: 'Filter entries before this time', }, limit: { type: 'number', default: 50, description: 'Maximum number of entries to return', }, offset: { type: 'number', default: 0, description: 'Number of entries to skip', }, }, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Querying memory', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const query = { agentId: input.agentId, sessionId: input.sessionId, type: input.type, tags: input.tags, search: input.search, startTime: input.startTime ? new Date(input.startTime) : undefined, endTime: input.endTime ? new Date(input.endTime) : undefined, limit: input.limit || 50, offset: input.offset || 0, }; const entries = await context.orchestrator.queryMemory(query); return { entries, count: entries.length, query, timestamp: new Date().toISOString(), }; }, }; } function createStoreMemoryTool(logger: ILogger): MCPTool { return { name: 'memory/store', description: 'Store a new memory entry', inputSchema: { type: 'object', properties: { agentId: { type: 'string', description: 'Agent ID for the memory entry', }, sessionId: { type: 'string', description: 'Session ID for the memory entry', }, type: { type: 'string', enum: ['observation', 'insight', 'decision', 'artifact', 'error'], description: 'Type of memory entry', }, content: { type: 'string', description: 'Content of the memory entry', }, context: { type: 'object', description: 'Context data for the memory entry', }, tags: { type: 'array', items: { type: 'string' }, description: 'Tags for the memory entry', }, parentId: { type: 'string', description: 'Parent memory entry ID', }, }, required: ['agentId', 'sessionId', 'type', 'content'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Storing memory', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const entry: Partial<MemoryEntry> = { agentId: input.agentId, sessionId: input.sessionId, type: input.type, content: input.content, context: input.context || {}, tags: input.tags || [], parentId: input.parentId, timestamp: new Date(), version: 1, }; const entryId = await context.orchestrator.storeMemory(entry); return { entryId, entry: { ...entry, id: entryId }, timestamp: new Date().toISOString(), }; }, }; } function createDeleteMemoryTool(logger: ILogger): MCPTool { return { name: 'memory/delete', description: 'Delete a memory entry', inputSchema: { type: 'object', properties: { entryId: { type: 'string', description: 'ID of the memory entry to delete', }, }, required: ['entryId'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Deleting memory', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } await context.orchestrator.deleteMemory(input.entryId); return { entryId: input.entryId, status: 'deleted', timestamp: new Date().toISOString(), }; }, }; } function createExportMemoryTool(logger: ILogger): MCPTool { return { name: 'memory/export', description: 'Export memory entries to a file', inputSchema: { type: 'object', properties: { format: { type: 'string', enum: ['json', 'csv', 'markdown'], default: 'json', description: 'Export format', }, agentId: { type: 'string', description: 'Filter by agent ID', }, sessionId: { type: 'string', description: 'Filter by session ID', }, startTime: { type: 'string', format: 'date-time', description: 'Export entries after this time', }, endTime: { type: 'string', format: 'date-time', description: 'Export entries before this time', }, }, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Exporting memory', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const exportResult = await context.orchestrator.exportMemory({ format: input.format || 'json', agentId: input.agentId, sessionId: input.sessionId, startTime: input.startTime ? new Date(input.startTime) : undefined, endTime: input.endTime ? new Date(input.endTime) : undefined, }); return { ...exportResult, timestamp: new Date().toISOString(), }; }, }; } function createImportMemoryTool(logger: ILogger): MCPTool { return { name: 'memory/import', description: 'Import memory entries from a file', inputSchema: { type: 'object', properties: { filePath: { type: 'string', description: 'Path to the file to import', }, format: { type: 'string', enum: ['json', 'csv'], default: 'json', description: 'Import format', }, mergeStrategy: { type: 'string', enum: ['skip', 'overwrite', 'version'], default: 'skip', description: 'Strategy for handling duplicate entries', }, }, required: ['filePath'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Importing memory', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const importResult = await context.orchestrator.importMemory({ filePath: input.filePath, format: input.format || 'json', mergeStrategy: input.mergeStrategy || 'skip', }); return { ...importResult, timestamp: new Date().toISOString(), }; }, }; } function createGetSystemStatusTool(logger: ILogger): MCPTool { return { name: 'system/status', description: 'Get comprehensive system status information', inputSchema: { type: 'object', properties: {}, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Getting system status', { sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const status = await context.orchestrator.getSystemStatus(); return { ...status, timestamp: new Date().toISOString(), }; }, }; } function createGetMetricsTool(logger: ILogger): MCPTool { return { name: 'system/metrics', description: 'Get system performance metrics', inputSchema: { type: 'object', properties: { timeRange: { type: 'string', enum: ['1h', '6h', '24h', '7d'], default: '1h', description: 'Time range for metrics', }, }, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Getting system metrics', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const metrics = await context.orchestrator.getMetrics(input.timeRange || '1h'); return { metrics, timeRange: input.timeRange || '1h', timestamp: new Date().toISOString(), }; }, }; } function createHealthCheckTool(logger: ILogger): MCPTool { return { name: 'system/health', description: 'Perform a comprehensive health check', inputSchema: { type: 'object', properties: { deep: { type: 'boolean', default: false, description: 'Perform deep health check including component tests', }, }, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Performing health check', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const healthCheck = await context.orchestrator.performHealthCheck(input.deep || false); return { ...healthCheck, timestamp: new Date().toISOString(), }; }, }; } function createGetConfigTool(logger: ILogger): MCPTool { return { name: 'config/get', description: 'Get current system configuration', inputSchema: { type: 'object', properties: { section: { type: 'string', enum: ['orchestrator', 'terminal', 'memory', 'coordination', 'mcp', 'logging'], description: 'Specific configuration section to retrieve', }, }, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Getting configuration', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const config = await context.orchestrator.getConfig(input.section); return { config, section: input.section, timestamp: new Date().toISOString(), }; }, }; } function createUpdateConfigTool(logger: ILogger): MCPTool { return { name: 'config/update', description: 'Update system configuration', inputSchema: { type: 'object', properties: { section: { type: 'string', enum: ['orchestrator', 'terminal', 'memory', 'coordination', 'mcp', 'logging'], description: 'Configuration section to update', }, config: { type: 'object', description: 'Configuration values to update', }, restart: { type: 'boolean', default: false, description: 'Restart affected components after update', }, }, required: ['section', 'config'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Updating configuration', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const result = await context.orchestrator.updateConfig( input.section, input.config, input.restart || false, ); return { ...result, timestamp: new Date().toISOString(), }; }, }; } function createValidateConfigTool(logger: ILogger): MCPTool { return { name: 'config/validate', description: 'Validate a configuration object', inputSchema: { type: 'object', properties: { config: { type: 'object', description: 'Configuration object to validate', }, }, required: ['config'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Validating configuration', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const validation = await context.orchestrator.validateConfig(input.config); return { ...validation, timestamp: new Date().toISOString(), }; }, }; } function createExecuteWorkflowTool(logger: ILogger): MCPTool { return { name: 'workflow/execute', description: 'Execute a workflow from a file or definition', inputSchema: { type: 'object', properties: { filePath: { type: 'string', description: 'Path to workflow file', }, workflow: { type: 'object', description: 'Inline workflow definition', }, parameters: { type: 'object', description: 'Parameters to pass to the workflow', }, }, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Executing workflow', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } if (!input.filePath && !input.workflow) { throw new Error('Either filePath or workflow must be provided'); } const result = await context.orchestrator.executeWorkflow({ filePath: input.filePath, workflow: input.workflow, parameters: input.parameters || {}, }); return { ...result, timestamp: new Date().toISOString(), }; }, }; } function createCreateWorkflowTool(logger: ILogger): MCPTool { return { name: 'workflow/create', description: 'Create a new workflow definition', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Name of the workflow', }, description: { type: 'string', description: 'Description of the workflow', }, tasks: { type: 'array', items: { type: 'object', properties: { id: { type: 'string' }, type: { type: 'string' }, description: { type: 'string' }, dependencies: { type: 'array', items: { type: 'string' }, }, assignTo: { type: 'string' }, }, required: ['id', 'type', 'description'], }, description: 'List of tasks in the workflow', }, savePath: { type: 'string', description: 'Path to save the workflow file', }, }, required: ['name', 'tasks'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Creating workflow', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const workflow = { name: input.name, description: input.description, tasks: input.tasks, created: new Date().toISOString(), }; const result = await context.orchestrator.createWorkflow(workflow, input.savePath); return { ...result, workflow, timestamp: new Date().toISOString(), }; }, }; } function createListWorkflowsTool(logger: ILogger): MCPTool { return { name: 'workflow/list', description: 'List available workflows', inputSchema: { type: 'object', properties: { directory: { type: 'string', description: 'Directory to search for workflows', }, }, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Listing workflows', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const workflows = await context.orchestrator.listWorkflows(input.directory); return { workflows, count: workflows.length, timestamp: new Date().toISOString(), }; }, }; } function createExecuteCommandTool(logger: ILogger): MCPTool { return { name: 'terminal/execute', description: 'Execute a command in a terminal session', inputSchema: { type: 'object', properties: { command: { type: 'string', description: 'Command to execute', }, args: { type: 'array', items: { type: 'string' }, description: 'Command arguments', }, cwd: { type: 'string', description: 'Working directory for the command', }, env: { type: 'object', description: 'Environment variables', }, timeout: { type: 'number', default: 30000, description: 'Command timeout in milliseconds', }, terminalId: { type: 'string', description: 'Specific terminal ID to use', }, }, required: ['command'], }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Executing command', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const result = await context.orchestrator.executeCommand({ command: input.command, args: input.args, cwd: input.cwd, env: input.env, timeout: input.timeout || 30000, terminalId: input.terminalId, }); return { ...result, timestamp: new Date().toISOString(), }; }, }; } function createListTerminalsTool(logger: ILogger): MCPTool { return { name: 'terminal/list', description: 'List all terminal sessions', inputSchema: { type: 'object', properties: { includeIdle: { type: 'boolean', default: true, description: 'Include idle terminals', }, }, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Listing terminals', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const terminals = await context.orchestrator.listTerminals(input.includeIdle !== false); return { terminals, count: terminals.length, timestamp: new Date().toISOString(), }; }, }; } function createCreateTerminalTool(logger: ILogger): MCPTool { return { name: 'terminal/create', description: 'Create a new terminal session', inputSchema: { type: 'object', properties: { cwd: { type: 'string', description: 'Working directory for the terminal', }, env: { type: 'object', description: 'Environment variables', }, shell: { type: 'string', description: 'Shell to use (bash, zsh, etc.)', }, }, }, handler: async (input: any, context?: ClaudeFlowToolContext) => { logger.info('Creating terminal', { input, sessionId: context?.sessionId }); if (!context?.orchestrator) { throw new Error('Orchestrator not available'); } const terminal = await context.orchestrator.createTerminal({ cwd: input.cwd, env: input.env, shell: input.shell, }); return { terminal, timestamp: new Date().toISOString(), }; }, }; } function getDefaultSystemPrompt(type: string): string { const prompts = { coordinator: 'You are a coordinator agent responsible for planning, delegating, and orchestrating tasks across multiple agents.', researcher: 'You are a research agent specialized in gathering, analyzing, and synthesizing information from various sources.', implementer: 'You are an implementation agent focused on writing code, creating solutions, and executing technical tasks.', analyst: 'You are an analysis agent that identifies patterns, generates insights, and provides data-driven recommendations.', custom: 'You are a specialized agent with custom capabilities defined by your configuration.', }; return prompts[type as keyof typeof prompts] || prompts.custom; }