@chittyos/mcp
Version: 
ChittyMCP - Model Context Protocol server for ChittyOS ecosystem
430 lines (386 loc) ⢠13.1 kB
JavaScript
/**
 * Branched CLI - Direct terminal interface for branched operations
 */
import { Command } from 'commander';
import chalk from 'chalk';
import inquirer from 'inquirer';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
class BranchedCLI {
  constructor() {
    this.program = new Command();
    this.branches = new Map();
    this.config = this.loadConfig();
    this.setupCLI();
    this.loadBranches();
  }
  loadConfig() {
    const configPath = path.join(__dirname, 'config.json');
    if (fs.existsSync(configPath)) {
      return JSON.parse(fs.readFileSync(configPath, 'utf8'));
    }
    return {
      enabledBranches: ['finance', 'chat', 'code', 'data'],
      defaultBranch: 'finance',
    };
  }
  loadBranches() {
    const branchesDir = path.join(__dirname, 'branches');
    // Load CLI branches (different from MCP branches)
    this.branches.set('finance', {
      commands: {
        portfolio: async (args) => {
          console.log(chalk.blue('š Portfolio Status:'));
          console.log('AAPL: 50 shares @ $175 (+16.67%)');
          console.log('MSFT: 30 shares @ $380 (+26.67%)');
          console.log(chalk.green('Total Value: $20,150'));
        },
        compound: async (args) => {
          const { principal, rate, years } = args;
          const amount = principal * Math.pow(1 + rate/100, years);
          console.log(chalk.yellow(`š° Compound Interest Calculator:`));
          console.log(`Principal: $${principal}`);
          console.log(`Rate: ${rate}%`);
          console.log(`Time: ${years} years`);
          console.log(chalk.green(`Future Value: $${amount.toFixed(2)}`));
        },
        loan: async (args) => {
          const { amount, rate, months } = args;
          const r = rate / 100 / 12;
          const payment = amount * (r * Math.pow(1 + r, months)) / (Math.pow(1 + r, months) - 1);
          console.log(chalk.yellow(`š  Loan Calculator:`));
          console.log(`Amount: $${amount}`);
          console.log(`Rate: ${rate}%`);
          console.log(`Term: ${months} months`);
          console.log(chalk.green(`Monthly Payment: $${payment.toFixed(2)}`));
        },
      },
    });
    this.branches.set('chat', {
      commands: {
        gpt: async (args) => {
          const { message } = args;
          console.log(chalk.cyan('š¤ GPT Response:'));
          console.log(`[Simulated] Response to: "${message}"`);
        },
        claude: async (args) => {
          const { message } = args;
          console.log(chalk.magenta('š Claude Response:'));
          console.log(`[Simulated] Response to: "${message}"`);
        },
        compare: async (args) => {
          const { message } = args;
          console.log(chalk.blue('āļø  Comparing AI Responses:'));
          console.log(chalk.cyan('GPT: [Response would go here]'));
          console.log(chalk.magenta('Claude: [Response would go here]'));
        },
      },
    });
    this.branches.set('code', {
      commands: {
        analyze: async (args) => {
          const { file } = args;
          console.log(chalk.green(`š Analyzing: ${file}`));
          console.log('Lines: 150');
          console.log('Functions: 12');
          console.log('Complexity: Medium');
        },
        generate: async (args) => {
          const { type, name } = args;
          console.log(chalk.yellow(`ā” Generating ${type}: ${name}`));
          console.log('// Generated code would appear here');
        },
        refactor: async (args) => {
          const { file, goal } = args;
          console.log(chalk.blue(`š§ Refactoring ${file}`));
          console.log(`Goal: ${goal || 'improve readability'}`);
        },
      },
    });
    this.branches.set('data', {
      commands: {
        analyze: async (args) => {
          const { data, operation } = args;
          console.log(chalk.cyan(`š Data Analysis (${operation}):`));
          console.log('Result: [Analysis would go here]');
        },
        transform: async (args) => {
          const { input, operation } = args;
          console.log(chalk.yellow(`š Transforming data: ${operation}`));
          console.log('Output: [Transformed data]');
        },
        visualize: async (args) => {
          const { data, type } = args;
          console.log(chalk.green(`š Creating ${type} chart`));
          console.log('[Visualization description]');
        },
      },
    });
  }
  setupCLI() {
    this.program
      .name('mcp')
      .description('Branched CLI for modular operations')
      .version('1.0.0');
    // Main branch router
    this.program
      .command('branch <branch>')
      .description('Switch to a specific branch')
      .action((branch) => {
        if (this.branches.has(branch)) {
          console.log(chalk.green(`ā Switched to ${branch} branch`));
          this.config.defaultBranch = branch;
        } else {
          console.log(chalk.red(`ā Unknown branch: ${branch}`));
          console.log(`Available: ${Array.from(this.branches.keys()).join(', ')}`);
        }
      });
    // Finance branch
    const finance = this.program
      .command('finance')
      .alias('f')
      .description('Financial operations');
    finance
      .command('portfolio')
      .alias('p')
      .description('Show portfolio status')
      .action(() => this.branches.get('finance').commands.portfolio());
    finance
      .command('compound <principal> <rate> <years>')
      .alias('c')
      .description('Calculate compound interest')
      .action((principal, rate, years) => {
        this.branches.get('finance').commands.compound({
          principal: parseFloat(principal),
          rate: parseFloat(rate),
          years: parseFloat(years),
        });
      });
    finance
      .command('loan <amount> <rate> <months>')
      .alias('l')
      .description('Calculate loan payment')
      .action((amount, rate, months) => {
        this.branches.get('finance').commands.loan({
          amount: parseFloat(amount),
          rate: parseFloat(rate),
          months: parseInt(months),
        });
      });
    // Chat branch
    const chat = this.program
      .command('chat')
      .alias('c')
      .description('AI chat operations');
    chat
      .command('gpt <message...>')
      .alias('g')
      .description('Chat with GPT')
      .action((message) => {
        this.branches.get('chat').commands.gpt({
          message: message.join(' '),
        });
      });
    chat
      .command('claude <message...>')
      .alias('c')
      .description('Chat with Claude')
      .action((message) => {
        this.branches.get('chat').commands.claude({
          message: message.join(' '),
        });
      });
    chat
      .command('compare <message...>')
      .alias('vs')
      .description('Compare AI responses')
      .action((message) => {
        this.branches.get('chat').commands.compare({
          message: message.join(' '),
        });
      });
    // Code branch
    const code = this.program
      .command('code')
      .alias('c')
      .description('Code operations');
    code
      .command('analyze <file>')
      .alias('a')
      .description('Analyze code file')
      .action((file) => {
        this.branches.get('code').commands.analyze({ file });
      });
    code
      .command('generate <type> <name>')
      .alias('g')
      .description('Generate code')
      .action((type, name) => {
        this.branches.get('code').commands.generate({ type, name });
      });
    code
      .command('refactor <file>')
      .alias('r')
      .description('Refactor code')
      .option('--goal <goal>', 'Refactoring goal')
      .action((file, options) => {
        this.branches.get('code').commands.refactor({
          file,
          goal: options.goal,
        });
      });
    // Data branch
    const data = this.program
      .command('data')
      .alias('d')
      .description('Data operations');
    data
      .command('analyze <operation>')
      .alias('a')
      .description('Analyze data')
      .option('--data <data>', 'Input data (JSON)')
      .action((operation, options) => {
        this.branches.get('data').commands.analyze({
          operation,
          data: options.data ? JSON.parse(options.data) : [],
        });
      });
    data
      .command('transform <operation>')
      .alias('t')
      .description('Transform data')
      .option('--input <data>', 'Input data')
      .action((operation, options) => {
        this.branches.get('data').commands.transform({
          operation,
          input: options.input,
        });
      });
    // Interactive mode
    this.program
      .command('interactive')
      .alias('i')
      .description('Interactive branch mode')
      .action(async () => {
        await this.interactiveMode();
      });
    // List all branches and commands
    this.program
      .command('list')
      .alias('ls')
      .description('List all branches and commands')
      .action(() => {
        console.log(chalk.bold('\nš³ Available Branches:\n'));
        this.branches.forEach((branch, name) => {
          console.log(chalk.green(`  ${name}:`));
          Object.keys(branch.commands).forEach(cmd => {
            console.log(`    - ${cmd}`);
          });
        });
      });
    // Quick access with dynamic routing
    this.program
      .command('quick <branch>:<command> [args...]')
      .alias('q')
      .description('Quick command execution')
      .action(async (branchCommand, args) => {
        const [branch, command] = branchCommand.split(':');
        if (this.branches.has(branch)) {
          const branchObj = this.branches.get(branch);
          if (branchObj.commands[command]) {
            await branchObj.commands[command](args);
          } else {
            console.log(chalk.red(`Command '${command}' not found in branch '${branch}'`));
          }
        } else {
          console.log(chalk.red(`Branch '${branch}' not found`));
        }
      });
  }
  async interactiveMode() {
    console.log(chalk.bold.cyan('\nšÆ Interactive Branched CLI\n'));
    while (true) {
      const { action } = await inquirer.prompt([
        {
          type: 'list',
          name: 'action',
          message: 'Choose a branch:',
          choices: [
            ...Array.from(this.branches.keys()),
            new inquirer.Separator(),
            'Exit',
          ],
        },
      ]);
      if (action === 'Exit') break;
      const branch = this.branches.get(action);
      const { command } = await inquirer.prompt([
        {
          type: 'list',
          name: 'command',
          message: `Choose a ${action} command:`,
          choices: Object.keys(branch.commands),
        },
      ]);
      // Get command-specific inputs
      const inputs = await this.getCommandInputs(action, command);
      await branch.commands[command](inputs);
      console.log(''); // Add spacing
    }
  }
  async getCommandInputs(branch, command) {
    const inputConfigs = {
      finance: {
        compound: [
          { type: 'number', name: 'principal', message: 'Principal amount:' },
          { type: 'number', name: 'rate', message: 'Interest rate (%):' },
          { type: 'number', name: 'years', message: 'Years:' },
        ],
        loan: [
          { type: 'number', name: 'amount', message: 'Loan amount:' },
          { type: 'number', name: 'rate', message: 'Interest rate (%):' },
          { type: 'number', name: 'months', message: 'Months:' },
        ],
      },
      chat: {
        gpt: [{ type: 'input', name: 'message', message: 'Your message:' }],
        claude: [{ type: 'input', name: 'message', message: 'Your message:' }],
        compare: [{ type: 'input', name: 'message', message: 'Your message:' }],
      },
      code: {
        analyze: [{ type: 'input', name: 'file', message: 'File to analyze:' }],
        generate: [
          { type: 'input', name: 'type', message: 'Type (function/class/component):' },
          { type: 'input', name: 'name', message: 'Name:' },
        ],
        refactor: [
          { type: 'input', name: 'file', message: 'File to refactor:' },
          { type: 'input', name: 'goal', message: 'Goal (optional):' },
        ],
      },
      data: {
        analyze: [
          { type: 'list', name: 'operation', message: 'Operation:', choices: ['mean', 'median', 'summary'] },
          { type: 'input', name: 'data', message: 'Data (JSON array):' },
        ],
        transform: [
          { type: 'list', name: 'operation', message: 'Transform:', choices: ['normalize', 'sort', 'filter'] },
          { type: 'input', name: 'input', message: 'Input data:' },
        ],
      },
    };
    const config = inputConfigs[branch]?.[command];
    if (!config) return {};
    return await inquirer.prompt(config);
  }
  run() {
    this.program.parse();
  }
}
// Run the CLI
const cli = new BranchedCLI();
cli.run();