UNPKG

jay-code

Version:

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

201 lines (178 loc) 6.17 kB
import { getErrorMessage } from '../../utils/type-guards.js'; /** * Fallback UI Handler - Handles raw mode errors gracefully * Provides alternative UI when Ink/raw mode isn't supported */ import chalk from 'chalk'; import { createCompatibleUI } from './compatible-ui.js'; export interface FallbackOptions { enableUI?: boolean; fallbackMessage?: string; showHelp?: boolean; } /** * Handles raw mode errors and provides fallback UI */ export async function handleRawModeError( error: Error, options: FallbackOptions = {}, ): Promise<void> { const isRawModeError = (error instanceof Error ? error.message : String(error)).includes( 'Raw mode is not supported', ) || (error instanceof Error ? error.message : String(error)).includes('stdin') || (error instanceof Error ? error.message : String(error)).includes('Ink'); if (!isRawModeError) { throw error; // Re-throw if it's not a raw mode error } console.clear(); console.log(chalk.yellow.bold('⚠️ Interactive Mode Not Supported')); console.log(chalk.gray('─'.repeat(50))); console.log(chalk.white('The current terminal environment does not support')); console.log(chalk.white('interactive UI features (raw mode).')); console.log(); console.log(chalk.cyan('Common causes:')); console.log(chalk.gray('• VS Code integrated terminal')); console.log(chalk.gray('• WSL (Windows Subsystem for Linux)')); console.log(chalk.gray('• Native Windows terminals')); console.log(chalk.gray('• CI/CD environments')); console.log(chalk.gray('• Docker containers')); console.log(chalk.gray('• SSH sessions without TTY')); console.log(); if (options.fallbackMessage) { console.log(chalk.blue('ℹ️ '), options.fallbackMessage); console.log(); } if (options.enableUI) { console.log(chalk.green('✅ Launching compatible UI mode...')); console.log(); try { const ui = createCompatibleUI(); await ui.start(); } catch (fallbackError) { console.log(chalk.red('❌ Fallback UI also failed:'), getErrorMessage(fallbackError)); await showBasicInterface(options); } } else { await showBasicInterface(options); } } /** * Shows a basic text-based interface when UI isn't available */ async function showBasicInterface(options: FallbackOptions): Promise<void> { console.log(chalk.green('📋 Available alternatives:')); console.log(); console.log(chalk.white('1. Use CLI commands directly:')); console.log(chalk.gray(' ./jay-code status')); console.log(chalk.gray(' ./jay-code memory list')); console.log(chalk.gray(' ./jay-code sparc modes')); console.log(); console.log(chalk.white('2. Use non-interactive modes:')); console.log(chalk.gray(' ./jay-code start (without --ui)')); console.log(chalk.gray(' ./jay-code swarm "task" --monitor')); console.log(); console.log(chalk.white('3. Use external terminal:')); console.log(chalk.gray(' Run in a standalone terminal application')); console.log(); if (options.showHelp) { console.log(chalk.cyan('💡 For help with any command, use:')); console.log(chalk.gray(' ./jay-code help <command>')); console.log(chalk.gray(' ./jay-code <command> --help')); console.log(); } console.log(chalk.gray('Press Ctrl+C to exit')); // Wait for user to exit await new Promise(() => { process.on('SIGINT', () => { console.log(chalk.green('\n👋 Goodbye!')); process.exit(0); }); }); } /** * Wraps a function to catch and handle raw mode errors */ export function withRawModeFallback<T extends any[], R>( fn: (...args: T) => Promise<R>, fallbackOptions: FallbackOptions = {}, ) { return async (...args: T): Promise<R | void> => { try { return await fn(...args); } catch (error) { if (error instanceof Error) { await handleRawModeError(error, fallbackOptions); } else { throw error; } } }; } /** * Checks if the current environment supports interactive UI */ export function checkUISupport(): { supported: boolean; reason?: string; recommendation?: string; } { // Check if we're in a TTY if (!process.stdin.isTTY) { return { supported: false, reason: 'Not running in a TTY environment', recommendation: 'Use a proper terminal application', }; } // Check if raw mode is available if (typeof process.stdin.setRawMode !== 'function') { return { supported: false, reason: 'Raw mode not available', recommendation: 'Use --no-ui flag or run in external terminal', }; } // Check for VS Code terminal if (process.env.TERM_PROGRAM === 'vscode') { return { supported: false, reason: 'Running in VS Code integrated terminal', recommendation: 'Use VS Code external terminal or standalone terminal', }; } // Check for other problematic environments if (process.env.CI || process.env.GITHUB_ACTIONS) { return { supported: false, reason: 'Running in CI/CD environment', recommendation: 'Use non-interactive mode', }; } return { supported: true }; } /** * Shows UI support information */ export function showUISupport(): void { const support = checkUISupport(); console.log(chalk.cyan.bold('🖥️ UI Support Information')); console.log(chalk.gray('─'.repeat(40))); if (support.supported) { console.log(chalk.green('✅ Interactive UI supported')); console.log(chalk.gray('Your terminal supports all UI features')); } else { console.log(chalk.yellow('⚠️ Limited UI support')); console.log(chalk.gray(`Reason: ${support.reason}`)); if (support.recommendation) { console.log(chalk.blue(`Recommendation: ${support.recommendation}`)); } } console.log(); console.log(chalk.white('Environment details:')); console.log(chalk.gray(`• Terminal: ${process.env.TERM || 'unknown'}`)); console.log(chalk.gray(`• TTY: ${process.stdin.isTTY ? 'yes' : 'no'}`)); console.log(chalk.gray(`• Program: ${process.env.TERM_PROGRAM || 'unknown'}`)); console.log(chalk.gray(`• Platform: ${process.platform}`)); }