UNPKG

sf-agent-framework

Version:

AI Agent Orchestration Framework for Salesforce Development - Two-phase architecture with 70% context reduction

1,391 lines (1,217 loc) • 61.2 kB
#!/usr/bin/env node const { Command } = require('commander'); const path = require('path'); const { execSync } = require('child_process'); const { version } = require('../package.json'); const program = new Command(); program .name('sf-agent') .description('SF-Agent Framework CLI for building and managing agents') .version(version); program .command('install') .description('Install SF-Agent Framework agents and tools interactively') .option('-f, --full', 'Install complete SF-Agent Framework') .option('-d, --directory <path>', 'Installation directory') .option( '-i, --ide <ide...>', 'Configure for specific IDE(s) - can specify multiple (cursor, claude-code, windsurf, trae, roo, cline, gemini, github-copilot, other)' ) .action(async (options) => { try { // Use child_process to run the installer - this is more reliable for npm packages const installerPath = path.join(__dirname, 'installer', 'bin', 'sf-agent.js'); // Build the command let cmd = `node "${installerPath}" install`; if (options.full) cmd += ' --full'; if (options.directory) cmd += ` --directory "${options.directory}"`; if (options.ide && options.ide.length > 0) { cmd += ` --ide ${options.ide.join(' ')}`; } // Execute the installer execSync(cmd, { stdio: 'inherit' }); } catch (error) { console.error('Installation failed:', error.message); process.exit(1); } }); // Story-based context engineering commands program .command('shard <document>') .description('Shard planning document into story-sized pieces') .option('-o, --output <dir>', 'Output directory', 'docs/sharded') .option('-v, --verbose', 'Verbose output') .action(async (document, options) => { try { const sharderPath = path.join(__dirname, 'document-sharder.js'); const cmd = `node "${sharderPath}" "${document}" -o "${options.output}"${options.verbose ? ' -v' : ''}`; execSync(cmd, { stdio: 'inherit' }); } catch (error) { console.error('Sharding failed:', error.message); process.exit(1); } }); program .command('story <action> [storyId]') .description('Manage story queue and context') .option('-d, --dir <directory>', 'Story directory', 'docs/stories') .action(async (action, storyId, options) => { try { const queuePath = path.join(__dirname, 'story-queue-manager.js'); let cmd = `node "${queuePath}" ${action}`; if (storyId) cmd += ` ${storyId}`; if (options.dir) cmd += ` -d "${options.dir}"`; execSync(cmd, { stdio: 'inherit' }); } catch (error) { console.error('Story management failed:', error.message); process.exit(1); } }); program .command('validate-story <storyId>') .description('Validate story has complete context for development') .option('--fix', 'Apply auto-fix suggestions') .option('--block', 'Block story if invalid') .action(async (storyId, options) => { console.log(`Validating story ${storyId}...`); // Story validation logic would go here console.log('Story validation complete'); }); program .command('phase <phase>') .description('Switch between planning and development phases') .action(async (phase) => { if (!['planning', 'development'].includes(phase)) { console.error('Phase must be either "planning" or "development"'); process.exit(1); } console.log(`Switching to ${phase} phase...`); console.log(`Context limit: ${phase === 'planning' ? '128k' : '32k'} tokens`); console.log(`Agent mode: ${phase === 'planning' ? 'Rich' : 'Lean'}`); }); program .command('workflow [workflowId]') .description('Start an interactive workflow session') .option('-d, --dir <directory>', 'Workflow directory', 'sf-core/workflows') .option( '-o, --output <directory>', 'Output directory for session files', 'docs/workflow-sessions' ) .option('-v, --verbose', 'Verbose output') .action(async (workflowId, options) => { try { const InteractiveWorkflowPlanner = require('./lib/interactive-workflow-planner'); const planner = new InteractiveWorkflowPlanner(process.cwd()); if (!workflowId) { // List available workflows console.log('\nšŸ“‹ Available Workflows:\n'); const workflows = await planner.listWorkflows(); if (workflows.length === 0) { console.log('No workflows found. Creating default interactive workflow...'); workflowId = 'interactive-project-setup'; } else { workflows.forEach((w) => console.log(` - ${w}`)); console.log('\nRun: sf-agent workflow <workflow-name> to start\n'); return; } } // Start the interactive workflow const result = await planner.startInteractiveWorkflow(workflowId); // Display summary console.log('\nāœ… Workflow Completed!\n'); console.log('Summary:', JSON.stringify(result, null, 2)); // Save session results if output directory specified if (options.output) { const fs = require('fs').promises; const outputPath = path.join(options.output, `${workflowId}-${Date.now()}.json`); await fs.mkdir(options.output, { recursive: true }); await fs.writeFile(outputPath, JSON.stringify(result, null, 2)); console.log(`\nSession saved to: ${outputPath}`); } } catch (error) { console.error('Workflow execution failed:', error.message); process.exit(1); } }); program .command('handoff <action> [handoffId]') .description('Manage agent handoffs (create, accept, complete, status)') .option('--from <agent>', 'Source agent (for create)') .option('--to <agent>', 'Target agent (for create)') .option('--agent <agent>', 'Agent ID (for accept)') .option('--artifacts <paths...>', 'Artifact paths') .option('--notes <text>', 'Notes') .option('--next <agent>', 'Next agent in chain (for complete)') .action(async (action, handoffId, options) => { try { const AgentCollaborationProtocol = require('./lib/agent-collaboration-protocol'); const protocol = new AgentCollaborationProtocol(process.cwd()); await protocol.initialize(); switch (action) { case 'create': if (!options.from || !options.to) { console.error('Error: --from and --to are required for create'); process.exit(1); } const handoff = await protocol.createHandoff({ from: options.from, to: options.to, artifacts: options.artifacts || [], context: { notes: options.notes }, }); console.log(`\nāœ… Handoff created: ${handoff.id}`); console.log(`From: ${handoff.from} → To: ${handoff.to}`); break; case 'accept': if (!handoffId || !options.agent) { console.error('Error: handoffId and --agent are required for accept'); process.exit(1); } const accepted = await protocol.acceptHandoff(handoffId, options.agent); console.log(`\nāœ… Handoff ${handoffId} accepted by ${options.agent}`); console.log(`Artifacts loaded: ${accepted.artifacts.length}`); break; case 'complete': if (!handoffId || !options.agent) { console.error('Error: handoffId and --agent are required for complete'); process.exit(1); } const deliverables = options.artifacts?.map((a) => ({ name: a, content: `Deliverable: ${a}` })) || []; const completed = await protocol.completeHandoff(handoffId, options.agent, deliverables); console.log(`\nāœ… Handoff ${handoffId} completed`); console.log(`Deliverables: ${deliverables.length}`); break; case 'status': if (handoffId) { const status = protocol.getHandoffStatus(handoffId); console.log(`\nHandoff ${handoffId}:`); console.log(JSON.stringify(status, null, 2)); } else { const handoffs = protocol.listActiveHandoffs(options.agent); console.log(`\nActive Handoffs${options.agent ? ` for ${options.agent}` : ''}:`); handoffs.forEach((h) => { console.log(` - ${h.id}: ${h.from} → ${h.to} (${h.status})`); }); } break; case 'metrics': const metrics = protocol.getCollaborationMetrics(); console.log('\nšŸ“Š Collaboration Metrics:'); console.log(JSON.stringify(metrics, null, 2)); break; default: console.error(`Unknown action: ${action}`); console.log('Available actions: create, accept, complete, status, metrics'); process.exit(1); } } catch (error) { console.error('Handoff operation failed:', error.message); process.exit(1); } }); program .command('update') .description('Update existing SF-Agent installation') .option('--force', 'Force update, overwriting modified files') .option('--dry-run', 'Show what would be updated without making changes') .action(async (options) => { try { // Use child_process to run the installer - this is more reliable for npm packages const installerPath = path.join(__dirname, 'installer', 'bin', 'sf-agent.js'); // Build the command let cmd = `node "${installerPath}" update`; if (options.force) cmd += ' --force'; if (options.dryRun) cmd += ' --dry-run'; // Execute the installer execSync(cmd, { stdio: 'inherit' }); } catch (error) { console.error('Update failed:', error.message); process.exit(1); } }); program .command('build') .description('Build web bundles for agents and teams') .option('-a, --agents-only', 'Build only agent bundles') .option('-t, --teams-only', 'Build only team bundles') .option('--no-clean', 'Skip cleaning output directories') .action(async (options) => { const WebBuilder = require('./builders/web-builder'); // Use package root directory instead of current working directory const packageRoot = path.resolve(__dirname, '..'); const builder = new WebBuilder({ rootDir: packageRoot, }); try { if (options.clean) { console.log('Cleaning output directories...'); await builder.cleanOutputDirs(); } if (!options.teamsOnly) { console.log('Building agent bundles...'); await builder.buildAgents(); } if (!options.agentsOnly) { console.log('Building team bundles...'); await builder.buildTeams(); } console.log('Build completed successfully!'); } catch (error) { console.error('Build failed:', error.message); process.exit(1); } }); program .command('list:agents') .description('List all available agents') .action(async () => { const WebBuilder = require('./builders/web-builder'); // Use package root directory instead of current working directory const packageRoot = path.resolve(__dirname, '..'); const builder = new WebBuilder({ rootDir: packageRoot }); const agents = await builder.resolver.listAgents(); console.log('Available agents:'); agents.forEach((agent) => console.log(` - ${agent}`)); }); program .command('validate') .description('Validate agent and team configurations') .action(async () => { const WebBuilder = require('./builders/web-builder'); // Use package root directory instead of current working directory const packageRoot = path.resolve(__dirname, '..'); const builder = new WebBuilder({ rootDir: packageRoot }); try { // Validate by attempting to build all agents and teams const agents = await builder.resolver.listAgents(); const teams = await builder.resolver.listTeams(); console.log('Validating agents...'); for (const agent of agents) { await builder.resolver.resolveAgentDependencies(agent); console.log(` āœ“ ${agent}`); } console.log('\nValidating teams...'); for (const team of teams) { await builder.resolver.resolveTeamDependencies(team); console.log(` āœ“ ${team}`); } console.log('\nAll configurations are valid!'); } catch (error) { console.error('Validation failed:', error.message); process.exit(1); } }); program .command('upgrade') .description('Upgrade a SF-Agent-Method V3 project to V4') .option('-p, --project <path>', 'Path to V3 project (defaults to current directory)') .option('--dry-run', 'Show what would be changed without making changes') .option('--no-backup', 'Skip creating backup (not recommended)') .action(async (options) => { const V3ToV4Upgrader = require('./upgraders/v3-to-v4-upgrader'); const upgrader = new V3ToV4Upgrader(); await upgrader.upgrade({ projectPath: options.project, dryRun: options.dryRun, backup: options.backup, }); }); program .command('mcp:setup') .description('Set up MCP (Model Context Protocol) for your IDE') .option( '-i, --ide <ide>', 'Specific IDE to configure (cursor, claude-code, windsurf, github-copilot, vscode)' ) .option('-a, --all', 'Configure MCP for all supported IDEs') .option('-u, --universal', 'Create universal MCP configuration file') .action(async (options) => { const IdeSetup = require('./installer/lib/ide-setup'); const projectDir = process.cwd(); try { if (options.universal || options.all) { console.log('Creating universal MCP configuration...'); await IdeSetup.createUniversalMCPConfig(projectDir); } if (options.all) { console.log('\nConfiguring MCP for all supported IDEs...'); const ides = ['cursor', 'claude-code', 'windsurf', 'github-copilot', 'vscode']; for (const ide of ides) { console.log(`\nConfiguring ${ide}...`); switch (ide) { case 'cursor': await IdeSetup.setupCursorMCP(projectDir); break; case 'claude-code': await IdeSetup.setupClaudeCodeMCP(projectDir); break; case 'windsurf': await IdeSetup.setupWindsurfMCP(projectDir); break; case 'github-copilot': await IdeSetup.setupGitHubCopilotMCP(projectDir); break; case 'vscode': await IdeSetup.setupVSCodeMCP(projectDir); break; } } } else if (options.ide) { console.log(`Configuring MCP for ${options.ide}...`); switch (options.ide) { case 'cursor': await IdeSetup.setupCursorMCP(projectDir); break; case 'claude-code': await IdeSetup.setupClaudeCodeMCP(projectDir); break; case 'windsurf': await IdeSetup.setupWindsurfMCP(projectDir); break; case 'github-copilot': await IdeSetup.setupGitHubCopilotMCP(projectDir); break; case 'vscode': await IdeSetup.setupVSCodeMCP(projectDir); break; default: console.error(`Unsupported IDE: ${options.ide}`); console.log('Supported IDEs: cursor, claude-code, windsurf, github-copilot, vscode'); process.exit(1); } } else { console.log('Please specify an IDE with --ide or use --all for all IDEs'); console.log('Example: npm run mcp:setup -- --ide cursor'); console.log('Example: npm run mcp:setup -- --all'); } console.log('\nāœ“ MCP setup complete!'); console.log('See sf-core/mcp/MCP-IDE-GUIDE.md for usage instructions'); } catch (error) { console.error('MCP setup failed:', error.message); process.exit(1); } }); program .command('mcp:list') .description('List all available MCP servers in the project') .action(async () => { const IdeSetup = require('./installer/lib/ide-setup'); const projectDir = process.cwd(); const servers = await IdeSetup.discoverMCPServers(projectDir); if (servers.length === 0) { console.log('No MCP servers found in the project.'); console.log('To add MCP servers, create .js files in:'); console.log(' - .sf-core/mcp/servers/'); return; } console.log('Available MCP servers:'); servers.forEach((server) => { console.log(`\n ${server.packName}/${server.serverName}`); console.log(` Path: ${server.relativePath}`); }); console.log(`\nTotal: ${servers.length} MCP servers found`); }); program .command('metrics:record <eventName> [data]') .description('Record a metric event') .action((eventName, data) => { const { recordEvent } = require('./metrics-tracker'); let parsedData = null; if (data) { try { parsedData = JSON.parse(data); } catch (error) { console.error('Invalid JSON data:', error.message); process.exit(1); } } recordEvent(eventName, parsedData); }); program .command('metrics:report') .description('Generate a metrics report') .action(() => { const { generateReport } = require('./metrics-tracker'); generateReport(); }); program .command('visualize:workflow <file>') .description('Generate a Mermaid diagram for a workflow YAML file') .action((file) => { const visualizeWorkflow = require('./workflow-visualizer'); visualizeWorkflow(file); }); program .command('create-agent') .description('Create a new agent interactively') .action(() => { try { execSync('node tools/agent-creator.js', { stdio: 'inherit' }); } catch (error) { console.error('Agent creation failed:', error.message); process.exit(1); } }); program .command('flatten') .description('Flatten the codebase into a single XML file') .action(() => { try { console.log('Flattening codebase...'); execSync('node tools/codebase-flattener.js', { stdio: 'inherit' }); console.log('Codebase flattened successfully!'); } catch (error) { console.error('Codebase flattening failed:', error.message); process.exit(1); } }); // Memory system commands program .command('memory <action>') .description('Manage context memory system (init, store, retrieve, stats, patterns)') .option('--query <text>', 'Query for retrieval') .option('--type <type>', 'Context type') .option('--agent <agent>', 'Agent name') .option('--content <text>', 'Content to store') .option('--limit <number>', 'Limit results', '10') .action(async (action, options) => { try { const ContextMemorySystem = require('./lib/context-memory-system'); const memory = new ContextMemorySystem(process.cwd()); switch (action) { case 'init': await memory.initialize(); console.log('āœ… Memory system initialized'); console.log(`Session ID: ${memory.currentSession.id}`); break; case 'store': await memory.initialize(); const contextId = await memory.storeContext({ type: options.type || 'general', agent: options.agent || 'user', content: options.content || 'Test context', metadata: {}, }); console.log(`āœ… Context stored: ${contextId}`); break; case 'retrieve': await memory.initialize(); const contexts = await memory.retrieveContext(options.query || '', { limit: parseInt(options.limit), }); console.log(`\nšŸ“š Retrieved ${contexts.length} contexts:`); contexts.forEach((c, i) => { console.log(`\n${i + 1}. ${c.id} (${c.type})`); console.log(` Agent: ${c.agent}`); console.log(` Importance: ${c.importance}`); }); break; case 'stats': await memory.initialize(); const stats = memory.getMemoryStats(); console.log('\nšŸ“Š Memory Statistics:'); console.log(JSON.stringify(stats, null, 2)); break; case 'patterns': await memory.initialize(); const patterns = memory.getLearnedPatterns(options.type); console.log(`\nšŸ” Learned Patterns${options.type ? ` (${options.type})` : ''}:`); patterns.forEach((p, i) => { console.log(`\n${i + 1}. ${p.pattern.type}`); console.log(` Frequency: ${p.frequency}`); console.log(` First seen: ${p.first_seen}`); }); break; case 'end': await memory.initialize(); const session = await memory.endSession(); console.log(`āœ… Session ended: ${session.id}`); break; default: console.error(`Unknown action: ${action}`); console.log('Available actions: init, store, retrieve, stats, patterns, end'); } } catch (error) { console.error('Memory operation failed:', error.message); process.exit(1); } }); // ═══════════════════════════════════════════════════════════════════════════ // WORKFLOW TRACK COMMANDS (v4.5.0) // ═══════════════════════════════════════════════════════════════════════════ program .command('workflow:init') .description('Initialize a workflow with intelligent track selection (Quick/Balanced/Enterprise)') .option('-s, --skip-analysis', 'Skip complexity analysis and choose track manually') .option('-t, --track <track>', 'Force specific track (quick, balanced, enterprise)') .option('--non-interactive', 'Run in non-interactive mode with defaults') .action(async (options) => { try { const WorkflowInitializer = require('../sf-core/workflows/workflow-initializer'); const initializer = new WorkflowInitializer(process.cwd()); if (options.track) { // Force specific track console.log(`\nšŸš€ Initializing ${options.track.toUpperCase()} workflow...\n`); const result = await initializer.initializeWorkflow(options.track, { skipAnalysis: true, nonInteractive: options.nonInteractive, }); console.log(`\nāœ… Workflow initialized: ${result.workflowId}`); console.log(`Track: ${result.track}`); console.log(`Session file: ${result.sessionFile}`); } else { // Interactive initialization with analysis const result = await initializer.initialize({ skipAnalysis: options.skipAnalysis, nonInteractive: options.nonInteractive, }); console.log('\nāœ… Workflow initialized successfully!'); console.log(`\nWorkflow ID: ${result.workflowId}`); console.log(`Track: ${result.track}`); console.log(`Complexity: ${result.complexity.score}/100 (${result.complexity.category})`); console.log(`Estimated time: ${result.estimatedTime}`); console.log(`Session file: ${result.sessionFile}\n`); } } catch (error) { console.error('āŒ Workflow initialization failed:', error.message); process.exit(1); } }); program .command('workflow:status') .description('Check current workflow status and progress') .option('-v, --verbose', 'Show detailed status') .action(async (options) => { try { const WorkflowInitializer = require('../sf-core/workflows/workflow-initializer'); const initializer = new WorkflowInitializer(process.cwd()); const status = await initializer.getCurrentWorkflowStatus(); if (!status) { console.log('\nšŸ“‹ No active workflow found.'); console.log('Run "sf-agent workflow:init" to start a new workflow.\n'); return; } console.log('\nšŸ“‹ Current Workflow Status:\n'); console.log(`Workflow ID: ${status.workflowId}`); console.log(`Track: ${status.track} (${status.trackName})`); console.log(`Phase: ${status.currentPhase}`); console.log(`Progress: ${status.progress}%`); console.log(`Started: ${status.startTime}`); if (options.verbose && status.phases) { console.log('\nPhases:'); status.phases.forEach((phase) => { const icon = phase.completed ? 'āœ…' : phase.active ? 'ā³' : 'ā­•'; console.log(` ${icon} ${phase.name} ${phase.completed ? '(completed)' : ''}`); }); } if (status.nextSteps && status.nextSteps.length > 0) { console.log('\nNext Steps:'); status.nextSteps.forEach((step, i) => { console.log(` ${i + 1}. ${step}`); }); } console.log(''); } catch (error) { console.error('āŒ Failed to get workflow status:', error.message); process.exit(1); } }); // ═══════════════════════════════════════════════════════════════════════════ // CONFIGURATION MANAGEMENT COMMANDS (v4.5.0) // ═══════════════════════════════════════════════════════════════════════════ program .command('config:init') .description('Initialize update-safe user configuration') .action(async () => { try { const UpdateSafeConfig = require('../sf-core/utils/update-safe-config'); const configManager = new UpdateSafeConfig(process.cwd()); console.log('\nšŸ”§ Initializing update-safe configuration...\n'); await configManager.initialize(); console.log('\nāœ… Configuration initialized successfully!'); console.log('\nUser config location: .sf-agent/user-config.json'); console.log('Preferences location: .sf-agent/preferences.json'); console.log('Agent overrides: .sf-agent/agent-overrides/\n'); } catch (error) { console.error('āŒ Configuration initialization failed:', error.message); process.exit(1); } }); program .command('config:upgrade') .description('Upgrade configuration while preserving user customizations') .option('--version <version>', 'Target framework version', '4.5.0') .option('--no-backup', 'Skip backup (not recommended)') .action(async (options) => { try { const UpdateSafeConfig = require('../sf-core/utils/update-safe-config'); const configManager = new UpdateSafeConfig(process.cwd()); console.log(`\nšŸ”„ Upgrading configuration to v${options.version}...\n`); const result = await configManager.preserveUserSettings(options.version); console.log('\nāœ… Configuration upgraded successfully!'); if (result.backupLocation) { console.log(`Backup location: ${result.backupLocation}`); } console.log(`Framework version: ${result.version}\n`); } catch (error) { console.error('āŒ Configuration upgrade failed:', error.message); process.exit(1); } }); program .command('config:validate') .description('Validate user configuration') .action(async () => { try { const UpdateSafeConfig = require('../sf-core/utils/update-safe-config'); const configManager = new UpdateSafeConfig(process.cwd()); console.log('\nšŸ” Validating configuration...\n'); const validation = await configManager.validateUserConfig(); if (validation.valid) { console.log('āœ… Configuration is valid!\n'); } else { console.log('āŒ Configuration has issues:\n'); validation.issues.forEach((issue) => { console.log(` āŒ ${issue}`); }); } if (validation.warnings.length > 0) { console.log('\nāš ļø Warnings:'); validation.warnings.forEach((warning) => { console.log(` āš ļø ${warning}`); }); } console.log(''); } catch (error) { console.error('āŒ Configuration validation failed:', error.message); process.exit(1); } }); program .command('config:reset') .description('Reset configuration to defaults') .option('--no-backup', 'Skip backup before reset (not recommended)') .action(async (options) => { try { const UpdateSafeConfig = require('../sf-core/utils/update-safe-config'); const configManager = new UpdateSafeConfig(process.cwd()); console.log('\nāš ļø This will reset your configuration to defaults.\n'); await configManager.resetToDefaults({ backupFirst: options.backup }); console.log('āœ… Configuration reset complete!\n'); } catch (error) { console.error('āŒ Configuration reset failed:', error.message); process.exit(1); } }); // ═══════════════════════════════════════════════════════════════════════════ // AGENT ROLE MATRIX COMMANDS (v4.5.0) // ═══════════════════════════════════════════════════════════════════════════ program .command('agents:roles') .description('Display agent role matrix and collaboration patterns') .option( '-c, --category <category>', 'Filter by category (product, architecture, development, quality, deployment, data, leadership)' ) .option('-p, --pattern <pattern>', 'Show specific collaboration pattern') .action(async (options) => { try { const fs = require('fs-extra'); const yaml = require('js-yaml'); const rolePath = path.join(process.cwd(), 'sf-core', 'config', 'agent-role-matrix.yaml'); const roleMatrix = yaml.load(await fs.readFile(rolePath, 'utf8')); console.log('\nšŸ¤– Agent Role Matrix\n'); console.log(`Framework Version: ${roleMatrix.version}`); console.log(`Last Updated: ${roleMatrix.last_updated}\n`); if (options.category) { // Show specific category const category = roleMatrix.agent_roles[options.category]; if (!category) { console.error(`āŒ Category not found: ${options.category}`); console.log('\nAvailable categories:', Object.keys(roleMatrix.agent_roles).join(', ')); process.exit(1); } console.log(`Category: ${options.category.toUpperCase()}\n`); category.primary_agents.forEach((agent) => { console.log(` • ${agent.id}`); console.log(` Expertise: ${agent.expertise}`); console.log(` Context: ${agent.context}`); console.log(` Responsibilities: ${agent.responsibilities.join(', ')}`); console.log(''); }); } else if (options.pattern) { // Show collaboration pattern const pattern = roleMatrix.collaboration_patterns[options.pattern]; if (!pattern) { console.error(`āŒ Pattern not found: ${options.pattern}`); console.log( '\nAvailable patterns:', Object.keys(roleMatrix.collaboration_patterns).join(', ') ); process.exit(1); } console.log(`Collaboration Pattern: ${options.pattern}\n`); console.log(`Complexity: ${pattern.complexity}`); console.log(`Duration: ${pattern.duration}\n`); console.log('Sequence:'); pattern.sequence.forEach((step, i) => { console.log(` ${i + 1}. ${step.phase}`); console.log(` Agents: ${step.agents.join(', ')}`); if (step.deliverables) { console.log(` Deliverables: ${step.deliverables.join(', ')}`); } }); console.log(''); } else { // Show overview console.log('Agent Categories:\n'); Object.keys(roleMatrix.agent_roles).forEach((category) => { const count = roleMatrix.agent_roles[category].primary_agents.length; console.log(` • ${category}: ${count} agents`); }); console.log('\nCollaboration Patterns:\n'); Object.keys(roleMatrix.collaboration_patterns).forEach((pattern) => { const p = roleMatrix.collaboration_patterns[pattern]; console.log(` • ${pattern} (${p.complexity}, ${p.duration})`); }); console.log('\nšŸ’” Use --category <name> to see agents in a category'); console.log('šŸ’” Use --pattern <name> to see a collaboration pattern\n'); } } catch (error) { console.error('āŒ Failed to load agent role matrix:', error.message); process.exit(1); } }); // ═══════════════════════════════════════════════════════════════════════════ // PREFERENCE MANAGEMENT COMMANDS (v4.5.0) // ═══════════════════════════════════════════════════════════════════════════ program .command('preference:get [category] [key]') .description('Get preference value(s)') .action(async (category, key) => { try { const UpdateSafeConfig = require('../sf-core/utils/update-safe-config'); const configManager = new UpdateSafeConfig(process.cwd()); const preferences = await configManager.loadPreferences(); if (!preferences) { console.log('\nāš ļø No preferences found. Run "sf-agent config:init" first.\n'); return; } if (!category) { // Show all preferences console.log('\nāš™ļø All Preferences:\n'); console.log(JSON.stringify(preferences, null, 2)); console.log(''); } else if (!key) { // Show category if (!preferences[category]) { console.error(`āŒ Category not found: ${category}`); console.log('\nAvailable categories:', Object.keys(preferences).join(', ')); process.exit(1); } console.log(`\nāš™ļø ${category} Preferences:\n`); console.log(JSON.stringify(preferences[category], null, 2)); console.log(''); } else { // Show specific preference if (!preferences[category] || preferences[category][key] === undefined) { console.error(`āŒ Preference not found: ${category}.${key}`); process.exit(1); } console.log(`\n${category}.${key} = ${JSON.stringify(preferences[category][key])}\n`); } } catch (error) { console.error('āŒ Failed to get preference:', error.message); process.exit(1); } }); program .command('preference:set <category> <key> <value>') .description('Set preference value') .action(async (category, key, value) => { try { const UpdateSafeConfig = require('../sf-core/utils/update-safe-config'); const configManager = new UpdateSafeConfig(process.cwd()); // Parse value (handle boolean, number, string) let parsedValue = value; if (value === 'true') parsedValue = true; else if (value === 'false') parsedValue = false; else if (!isNaN(value)) parsedValue = parseFloat(value); await configManager.updatePreference(category, key, parsedValue); } catch (error) { console.error('āŒ Failed to set preference:', error.message); process.exit(1); } }); program .command('agent:override <agentId>') .description('Create or edit agent override file') .option('-c, --content <content>', 'Override content') .option('-f, --file <file>', 'Load content from file') .action(async (agentId, options) => { try { const UpdateSafeConfig = require('../sf-core/utils/update-safe-config'); const fs = require('fs-extra'); const configManager = new UpdateSafeConfig(process.cwd()); let content = ''; if (options.file) { content = await fs.readFile(options.file, 'utf8'); } else if (options.content) { content = options.content; } else { console.log('\nšŸ“ Creating agent override template...\n'); content = `# ${agentId} Override This is a custom override for the ${agentId} agent. ## Custom Instructions Add your custom instructions here... ## Modified Capabilities List any capability modifications... ## Notes - This override will be preserved through framework updates - Override last modified: ${new Date().toISOString()} `; } await configManager.createAgentOverride(agentId, content); console.log(`\nšŸ’” Edit at: .sf-agent/agent-overrides/${agentId}.md\n`); } catch (error) { console.error('āŒ Failed to create agent override:', error.message); process.exit(1); } }); // ═══════════════════════════════════════════════════════════════════════════ // PHASE 2: SCALE-ADAPTIVE FEATURES (v4.5.0) // ═══════════════════════════════════════════════════════════════════════════ // Document Sharding Commands program .command('shard:create <documentPath>') .description('Shard a document into context-aware chunks (90% token savings)') .option( '-s, --strategy <strategy>', 'Sharding strategy (heading-based, function-based, section-based, paragraph-based)' ) .option( '-p, --priority <priority>', 'Default priority (critical, high, medium, low, archive)', 'medium' ) .action(async (documentPath, options) => { try { const DocumentSharder = require('../sf-core/utils/document-sharder'); const sharder = new DocumentSharder(process.cwd()); await sharder.initialize(); const result = await sharder.shardDocument(documentPath, { strategy: options.strategy, priority: options.priority, }); console.log('\nāœ… Document sharded successfully!\n'); console.log(`Shards created: ${result.shards.length}`); console.log(`Original size: ${result.originalTokens.toLocaleString()} tokens`); console.log( `Token savings: ${result.savingsPercentage}% (${result.tokensSaved.toLocaleString()} tokens)\n` ); } catch (error) { console.error('āŒ Sharding failed:', error.message); process.exit(1); } }); program .command('shard:load <documentPath>') .description('Load shards by priority') .option('-p, --priority <level>', 'Max priority level to load (1-5)', '3') .option('-t, --tokens <max>', 'Maximum tokens to load', '10000') .action(async (documentPath, options) => { try { const DocumentSharder = require('../sf-core/utils/document-sharder'); const sharder = new DocumentSharder(process.cwd()); await sharder.initialize(); const result = await sharder.loadShardsByPriority( documentPath, parseInt(options.priority), parseInt(options.tokens) ); console.log('\nšŸ“š Shards loaded:\n'); console.log(`Loaded: ${result.loadedCount} of ${result.totalAvailable} shards`); console.log(`Tokens: ${result.tokensLoaded.toLocaleString()}\n`); if (result.shards.length > 0) { console.log('Loaded shards:'); result.shards.forEach((shard, i) => { console.log(` ${i + 1}. Priority ${shard.priority} - ${shard.tokens} tokens`); }); console.log(''); } } catch (error) { console.error('āŒ Load failed:', error.message); process.exit(1); } }); program .command('shard:stats') .description('Show sharding statistics and savings') .action(async () => { try { const DocumentSharder = require('../sf-core/utils/document-sharder'); const sharder = new DocumentSharder(process.cwd()); await sharder.initialize(); const stats = await sharder.getStats(); console.log('\nšŸ“Š Sharding Statistics\n'); console.log(`Total documents: ${stats.totalDocuments}`); console.log(`Total shards: ${stats.totalShards}`); console.log(`Original tokens: ${stats.totalOriginalTokens.toLocaleString()}`); console.log(`Typical load tokens: ${stats.totalShardedTokens.toLocaleString()}`); console.log(`Token savings: ${stats.savingsPercentage}%\n`); if (stats.documents.length > 0) { console.log('Sharded documents:'); stats.documents.forEach((doc, i) => { console.log(` ${i + 1}. ${doc.path}`); console.log(` Shards: ${doc.shardCount}`); console.log(` Original: ${doc.originalTokens.toLocaleString()} tokens`); }); console.log(''); } } catch (error) { console.error('āŒ Failed to get stats:', error.message); process.exit(1); } }); program .command('shard:cleanup <documentPath>') .description('Remove shards for a document') .action(async (documentPath) => { try { const DocumentSharder = require('../sf-core/utils/document-sharder'); const sharder = new DocumentSharder(process.cwd()); await sharder.initialize(); await sharder.cleanup(documentPath); console.log('āœ… Shards cleaned up successfully\n'); } catch (error) { console.error('āŒ Cleanup failed:', error.message); process.exit(1); } }); // Context Budget Commands program .command('budget:init <model>') .description( 'Initialize context budget for model (claude_opus_4_5, gpt_5_1_instant, gemini_3_pro)' ) .option('-p, --phase <type>', 'Phase type (standard, planning, coding)', 'standard') .action(async (model, options) => { try { const ContextBudgetManager = require('../sf-core/utils/context-budget-manager'); const budgetManager = new ContextBudgetManager(process.cwd()); await budgetManager.initialize(); const budget = budgetManager.allocateBudget(model, options.phase); console.log('āœ… Budget initialized successfully\n'); } catch (error) { console.error('āŒ Budget initialization failed:', error.message); process.exit(1); } }); program .command('budget:status') .description('Check current budget status and usage') .action(async () => { try { const ContextBudgetManager = require('../sf-core/utils/context-budget-manager'); const budgetManager = new ContextBudgetManager(process.cwd()); await budgetManager.initialize(); const status = budgetManager.checkBudgetStatus(); const summary = budgetManager.getLoadedContentSummary(); console.log('\nšŸ’° Context Budget Status\n'); console.log(`Status: ${status.status.toUpperCase()}`); console.log(`Usage: ${status.usagePercent}%`); console.log(`Allocated: ${status.allocated.toLocaleString()} tokens`); console.log(`Used: ${status.used.toLocaleString()} tokens`); console.log(`Available: ${status.available.toLocaleString()} tokens\n`); console.log('Loaded content:'); console.log(` Total items: ${summary.total.count}`); console.log( ` Critical: ${summary.byPriority.critical.count} items (${summary.byPriority.critical.tokens.toLocaleString()} tokens)` ); console.log( ` High: ${summary.byPriority.high.count} items (${summary.byPriority.high.tokens.toLocaleString()} tokens)` ); console.log( ` Medium: ${summary.byPriority.medium.count} items (${summary.byPriority.medium.tokens.toLocaleString()} tokens)` ); console.log( ` Low: ${summary.byPriority.low.count} items (${summary.byPriority.low.tokens.toLocaleString()} tokens)\n` ); } catch (error) { console.error('āŒ Failed to get budget status:', error.message); process.exit(1); } }); program .command('budget:optimize') .description('Optimize context to free up budget') .option( '-s, --strategy <strategy>', 'Optimization strategy (auto, remove-low-priority, shard-large)', 'auto' ) .action(async (options) => { try { const ContextBudgetManager = require('../sf-core/utils/context-budget-manager'); const budgetManager = new ContextBudgetManager(process.cwd()); await budgetManager.initialize(); const result = await budgetManager.optimizeContext(options.strategy); console.log('\nāœ… Context optimized!\n'); result.optimizations.forEach((opt) => { console.log(` • ${opt.action}`); if (opt.tokensFreed) { console.log(` Tokens freed: ${opt.tokensFreed.toLocaleString()}`); } if (opt.files) { console.log(` Files to shard: ${opt.files.length}`); } }); console.log(`\nNew status: ${result.newStatus.status.toUpperCase()}`); console.log(`Available: ${result.newStatus.available.toLocaleString()} tokens\n`); } catch (error) { console.error('āŒ Optimization failed:', error.message); process.exit(1); } }); program .command('budget:recommend') .description('Get budget optimization recommendations') .action(async () => { try { const ContextBudgetManager = require('../sf-core/utils/context-budget-manager'); const budgetManager = new ContextBudgetManager(process.cwd()); await budgetManager.initialize(); const result = await budgetManager.getRecommendations(); console.log('\nšŸ’” Budget Recommendations\n'); console.log(`Current status: ${result.status.toUpperCase()}\n`); if (result.recommendations.length === 0) { console.log('No recommendations - budget is healthy!\n'); return; } result.recommendations.forEach((rec, i) => { console.log(`${i + 1}. [${rec.priority.toUpperCase()}] ${rec.action}`); console.log(` ${rec.description}`); console.log(` Impact: ${rec.impact}`); if (rec.commands) { console.log(` Actions:`); rec.commands.forEach((cmd) => console.log(` - ${cmd}`)); } console.log(''); }); } catch (error) { console.error('āŒ Failed to get recommendations:', error.message); process.exit(1); } }); // Scale-Adaptive Workflow Commands program .command('adaptive:start <track>') .description('Start scale-adaptive workflow') .option('-c, --complexity <score>', 'Project complexity (0-100)', '50') .option('--token-budget <tokens>', 'Token budget override') .option('--time-budget <minutes>', 'Time budget override') .action(async (track, options) => { try { const ScaleAdaptiveEngine = require('../sf-core/workflows/scale-adaptive-engine'); const engine = new ScaleAdaptiveEngine(process.cwd()); await engine.initialize(); const projectInfo = { complexity: parseInt(options.complexity), requiresHighQuality: options.quality === 'high', }; const budgets = {}; if (options.tokenBudget) budgets.tokens = parseInt(options.tokenBudget); if (options.timeBudget) budgets.time = parseInt(options.timeBudget); const session = await engine.startWorkflow(track, projectInfo, budgets); console.log('āœ… Adaptive workflow started successfully!\n'); } catch (error) { console.error('āŒ Failed to start workflow:', error.message); process.exit(1); } }); program .command('adaptive:status') .description('Get scale-adaptive workflow status') .action(async () => { try { const ScaleAdaptiveEngine = require('../sf-core/workflows/scale-adaptive-engine'); const engine = new ScaleAdaptiveEngine(process.cwd()); const metrics = engine.getMetrics(); console.log('\n⚔ Scale-Adaptive Workflow Status\n'); console.log(`Current track: ${metrics.currentTrack}`); console.log(`Current phase: ${metrics.currentPhase}`); console.log(`Adaptations: ${metrics.adaptations}\n`); console.log('Budget status:'); console.log(` Tokens: ${metrics.budgets.tokens.percentUsed.toFixed(1)}% used`); console.log(` Time: ${metrics.budgets.time.percentUsed.toFixed(1)}% used`); console.log(` Cost: ${metrics.budgets.cost.percentUsed.toFixed(1)}% used\n`); if (metrics.adaptationHistory.length > 0) { console.log('Recent adaptations:'); metrics.adaptationHistory.slice(-5).forEach((adapt, i) => { console.log(` ${i + 1}. ${adapt.reason} → ${adapt.action}`); if (adapt.toTrack) { console.log(` Track: ${adapt.fromTrack} → ${adapt.toTrack}`); } }); console.log(''); } } catch (error) { console.error('āŒ Failed to get status:', error.message); process.exit(1); } }); // ═══════════════════════════════════════════════════════════════════════════ // PHASE 3: ADVANCED FEATURES (v4.5.0) // ═══════════════════════════════════════════════════════════════════════════ // Reflection Engine Commands program .command('reflect <output>') .description('Run reflection on agent output (self-correction)') .option('-a, --agent <agent>', 'Agent name', 'unknown') .option('-t, --threshold <score>', 'Quality threshold (0-1)', '0.8') .option('--max-iterations <num>', 'Max reflection iterations', '3') .action(async (output, options) => { try { const ReflectionEngine = require('../sf-core/agents/reflection-engine'); const engine = new ReflectionEngine(process.cwd()); await engine.initialize(); const result = await engine.reflect(output, { agent: options.agent, threshold: parseFloat(options.threshold), maxIterations: parseInt(options.maxIterations), }); if (result.success) { console.log(`\nāœ… Reflection completed successfully!`); console.log(`Final score: ${(result.score * 100).toFixed(1)}%`); console.log(`Iterations: ${result.iterations}\n`); } else { console.log(`\nāš ļø Reflection completed with issues`); console.log(`Score: ${(result.score * 100).toFixed(1)}%`); console.log(`Pending improvements: ${result.improvements?.length || 0}\n`); } } catch (error) { console.error('āŒ Reflection failed:', error.message); process.exit(1); } }); program .command('reflect:history') .description('View reflection history') .option('-l, --limit <num>', 'Limit results', '10') .action(async (options) => { try { const ReflectionEngine = require('../sf-core/agents/reflection-engine'); const engine = new ReflectionEngine(process.cwd()); await engine.initialize(); const history = engine.getHistory(parseInt(options.limit)); if (history.length === 0) { console.log('\nNo reflection history found.\n'); return; } console.log('\nšŸ“œ Reflection History\n'); history.forEach((reflection, i) => { console.log(`${i + 1}. ${reflection.id}`); console.log(` Agent: ${reflection.agent}`); console.log(` Score: ${(reflection.finalScore * 100).toFixed(1)