freshroute-server
Version:
Local development server for FreshRoute extension with API mocking and extended functionality
1,173 lines (986 loc) ⢠89.2 kB
JavaScript
#!/usr/bin/env node
import { Command } from 'commander';
import chalk from 'chalk';
import ora from 'ora';
import open from 'open';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { spawn } from 'child_process';
import fs from 'fs/promises';
import os from 'os';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const packageRoot = join(__dirname, '..');
const program = new Command();
// Package info
const packageInfo = JSON.parse(
await fs.readFile(join(packageRoot, 'package.json'), 'utf8')
);
program
.name('freshroute')
.description('FreshRoute Development Server CLI')
.version(packageInfo.version);
// Start server command
program
.command('start')
.description('Start the FreshRoute development server')
.option('-p, --port <port>', 'HTTP server port', '3001')
.option('-w, --ws-port <port>', 'WebSocket server port', '3002')
.option('-d, --dev', 'Start in development mode with auto-restart')
.option('-s, --silent', 'Run server in background (daemon mode)')
.action(async (options) => {
// Check if server is already running
const isRunning = await checkServerRunning(options.port);
if (isRunning) {
console.log(chalk.yellow(`ā ļø FreshRoute server is already running on port ${options.port}`));
console.log(chalk.blue('š” Use "freshroute stop" to stop the server first'));
return;
}
if (!options.silent) {
console.log(chalk.blue.bold('š Starting FreshRoute Server...'));
}
const serverScript = join(packageRoot, 'server.js');
const env = {
...process.env,
PORT: options.port,
WS_PORT: options.wsPort
};
// Determine stdio mode based on silent flag
const stdio = options.silent ? 'ignore' : 'inherit';
const detached = options.silent;
if (options.dev) {
if (!options.silent) {
console.log(chalk.yellow('š¦ Development mode - auto-restart enabled'));
}
const nodemon = spawn('npx', ['nodemon', serverScript], {
cwd: packageRoot,
env,
stdio,
detached
});
if (options.silent) {
// Save PID for stopping later
await savePID(nodemon.pid, options.port);
nodemon.unref();
console.log(chalk.green(`ā
FreshRoute server started in background on port ${options.port}`));
console.log(chalk.blue(`š Use "freshroute stop" to stop the server`));
}
nodemon.on('error', (error) => {
if (!options.silent) {
console.error(chalk.red('ā Failed to start server:'), error.message);
}
process.exit(1);
});
} else {
const server = spawn('node', [serverScript], {
cwd: packageRoot,
env,
stdio,
detached
});
if (options.silent) {
// Save PID for stopping later
await savePID(server.pid, options.port);
server.unref();
console.log(chalk.green(`ā
FreshRoute server started in background on port ${options.port}`));
console.log(chalk.blue(`š Use "freshroute stop" to stop the server`));
}
server.on('error', (error) => {
if (!options.silent) {
console.error(chalk.red('ā Failed to start server:'), error.message);
}
process.exit(1);
});
}
});
// Stop server command
program
.command('stop')
.description('Stop the FreshRoute development server')
.option('-p, --port <port>', 'HTTP server port to stop', '3001')
.option('--all', 'Stop all running FreshRoute servers')
.action(async (options) => {
const spinner = ora('Stopping FreshRoute server...').start();
try {
if (options.all) {
const stopped = await stopAllServers();
if (stopped > 0) {
spinner.succeed(chalk.green(`ā
Stopped ${stopped} FreshRoute server(s)`));
} else {
spinner.info(chalk.yellow('ā¹ļø No running FreshRoute servers found'));
}
} else {
const stopped = await stopServer(options.port);
if (stopped) {
spinner.succeed(chalk.green(`ā
FreshRoute server stopped (port ${options.port})`));
} else {
spinner.info(chalk.yellow(`ā¹ļø No FreshRoute server running on port ${options.port}`));
}
}
} catch (error) {
spinner.fail(chalk.red(`ā Failed to stop server: ${error.message}`));
process.exit(1);
}
});
// Status command
program
.command('status')
.description('Check FreshRoute server status')
.option('-p, --port <port>', 'HTTP server port to check', '3001')
.action(async (options) => {
const spinner = ora('Checking server status...').start();
try {
const isRunning = await checkServerRunning(options.port);
const pidInfo = await getPIDInfo(options.port);
if (isRunning) {
spinner.succeed(chalk.green(`ā
FreshRoute server is running on port ${options.port}`));
if (pidInfo) {
console.log(chalk.blue(`š Process ID: ${pidInfo.pid}`));
console.log(chalk.blue(`š
Started: ${new Date(pidInfo.startTime).toLocaleString()}`));
}
console.log(chalk.blue(`š Dashboard: http://localhost:${options.port}`));
console.log(chalk.blue(`š Health check: http://localhost:${options.port}/health`));
} else {
spinner.info(chalk.yellow(`ā¹ļø No FreshRoute server running on port ${options.port}`));
console.log(chalk.blue(`š” Start with: freshroute start`));
console.log(chalk.blue(`š” Start in background: freshroute start --silent`));
}
} catch (error) {
spinner.fail(chalk.red(`ā Failed to check status: ${error.message}`));
process.exit(1);
}
});
// Install extension command
program
.command('install-extension')
.description('Install the FreshRoute Chrome extension')
.option('--open-chrome', 'Open Chrome extensions page after extraction')
.action(async (options) => {
console.log(chalk.blue.bold('š¦ Installing FreshRoute Chrome Extension...\n'));
console.log(chalk.yellow('ā¹ļø Important: This extension is designed for DEVELOPMENT use'));
console.log(chalk.yellow(' It will be available when using: ') + chalk.green('freshroute open-chrome'));
console.log(chalk.yellow(' It will NOT appear in your regular Chrome profile\n'));
const spinner = ora('Installing Chrome extension...').start();
try {
// Check if pre-built extension exists
const extensionPath = join(packageRoot, 'extension');
const extensionExists = await fs.access(extensionPath).then(() => true).catch(() => false);
if (!extensionExists) {
spinner.fail(chalk.red('ā Pre-built extension not found in package'));
console.log(chalk.yellow('š” The extension should be included in the npm package'));
console.log(chalk.yellow('š” Try reinstalling: npm install -g freshroute-server'));
return;
}
const { installExtension } = await import('../scripts/install-extension.js');
await installExtension();
spinner.succeed(chalk.green('ā
Extension installed successfully!'));
console.log(chalk.cyan('\nš§ How to use the extension:'));
console.log('1. Start the server: ' + chalk.green('freshroute start'));
console.log('2. Open development Chrome: ' + chalk.green('freshroute open-chrome'));
console.log('3. The extension will be automatically loaded in development mode');
console.log(chalk.yellow('\nā ļø The extension is NOT installed in your regular Chrome profile'));
console.log(chalk.yellow(' Use ') + chalk.green('freshroute open-chrome') + chalk.yellow(' to access it'));
if (options.openChrome) {
console.log(chalk.blue('\nš Opening Chrome development mode...'));
// Import and run open-chrome functionality
const userHome = os.homedir();
const extensionInstallPath = join(userHome, '.freshroute', 'extension');
const tempDir = join(os.tmpdir(), 'chrome-freshroute-dev');
const profileDir = join(tempDir, 'freshroute-dev');
await fs.mkdir(profileDir, { recursive: true });
const platform = process.platform;
let chromeExecutable;
switch (platform) {
case 'darwin':
chromeExecutable = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
break;
case 'win32':
chromeExecutable = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
if (!await fs.access(chromeExecutable).then(() => true).catch(() => false)) {
chromeExecutable = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe';
}
break;
default:
chromeExecutable = 'google-chrome';
}
const chromeFlags = [
`--user-data-dir=${profileDir}`,
`--load-extension=${extensionInstallPath}`,
'--disable-web-security',
'--disable-features=TranslateUI',
'--disable-background-timer-throttling',
'--disable-renderer-backgrounding',
'--disable-backgrounding-occluded-windows',
'--disable-background-networking',
'--disable-sync',
'--disable-default-apps',
'--no-first-run',
'--no-default-browser-check',
'--disable-dev-shm-usage',
'--disable-gpu-sandbox',
'--disable-software-rasterizer',
'--aggressive-cache-discard',
'--memory-pressure-off',
'http://localhost:3001/health'
];
try {
const chromeProcess = spawn(chromeExecutable, chromeFlags, {
detached: true,
stdio: 'ignore'
});
chromeProcess.unref();
console.log(chalk.green('ā
Chrome opened with FreshRoute extension loaded!'));
} catch (error) {
console.log(chalk.red('ā Failed to open Chrome automatically'));
console.log(chalk.yellow('š” Use: freshroute open-chrome'));
}
}
} catch (error) {
spinner.fail(chalk.red(`ā Installation failed: ${error.message}`));
process.exit(1);
}
});
// Manual installation guide command
program
.command('install-manual')
.description('Show instructions for manually installing extension in regular Chrome')
.action(async () => {
console.log(chalk.blue.bold('š§ Manual Installation Guide\n'));
// Check if extension is available
const userHome = os.homedir();
const extensionInstallPath = join(userHome, '.freshroute', 'extension');
const extensionExists = await fs.access(extensionInstallPath).then(() => true).catch(() => false);
if (!extensionExists) {
console.log(chalk.red('ā Extension not found. Run "freshroute install-extension" first.\n'));
return;
}
console.log(chalk.green('š Extension Location:'));
console.log(chalk.gray(' ' + extensionInstallPath + '\n'));
console.log(chalk.yellow('ā ļø Manual Installation (for regular Chrome profile):'));
console.log('1. Open your regular Chrome browser');
console.log('2. Go to: ' + chalk.blue('chrome://extensions/'));
console.log('3. Enable "Developer mode" (toggle in top right)');
console.log('4. Click "Load unpacked" button');
console.log('5. Navigate to and select: ' + chalk.green(extensionInstallPath));
console.log('6. The FreshRoute extension will be installed in your regular profile');
console.log(chalk.cyan('\nšØ Important Notes:'));
console.log('⢠Regular Chrome has CORS restrictions - some features may not work');
console.log('⢠For development, use: ' + chalk.green('freshroute open-chrome') + ' (recommended)');
console.log('⢠The development profile has CORS disabled and better settings');
console.log(chalk.blue('\nš Quick Actions:'));
console.log('⢠Copy path: ' + chalk.gray('pbcopy <<< "' + extensionInstallPath + '"') + ' (macOS)');
console.log('⢠Open folder: ' + chalk.gray('open "' + extensionInstallPath + '"') + ' (macOS)');
try {
// Try to open the folder automatically
if (process.platform === 'darwin') {
const { spawn } = await import('child_process');
spawn('open', [extensionInstallPath], { stdio: 'ignore' });
console.log(chalk.green('\nā
Extension folder opened in Finder'));
}
} catch (error) {
// Ignore errors for folder opening
}
});
// Open Chrome with CORS disabled and dev profile
program
.command('open-chrome')
.description('Open Chrome with CORS disabled and development profile')
.option('--profile <name>', 'Chrome profile name to use', 'freshroute-dev')
.option('--port <port>', 'Server port to connect to', '3001')
.option('--url <url>', 'URL to open initially', 'http://localhost:3001/health')
.option('--debug', 'Show debug information')
.action(async (options) => {
const spinner = ora('Opening Chrome with development settings...').start();
try {
// Create temporary user data directory
const tempDir = join(os.tmpdir(), 'chrome-freshroute-dev');
const profileDir = join(tempDir, options.profile);
// Ensure profile directory exists
await fs.mkdir(profileDir, { recursive: true });
// Chrome executable paths for different platforms
const platform = process.platform;
let chromeExecutable;
switch (platform) {
case 'darwin': // macOS
chromeExecutable = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
break;
case 'win32': // Windows
chromeExecutable = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
// Also try alternative paths
if (!await fs.access(chromeExecutable).then(() => true).catch(() => false)) {
chromeExecutable = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe';
}
break;
case 'linux': // Linux
chromeExecutable = 'google-chrome';
break;
default:
chromeExecutable = 'google-chrome';
}
// Verify Chrome executable exists
if (platform === 'darwin' || platform === 'win32') {
const chromeExists = await fs.access(chromeExecutable).then(() => true).catch(() => false);
if (!chromeExists) {
spinner.fail(chalk.red('ā Chrome executable not found'));
console.log(chalk.yellow(`š” Expected Chrome at: ${chromeExecutable}`));
return;
}
}
spinner.text = 'Starting Chrome with development settings...';
// Chrome flags for development - optimized for performance
const chromeFlags = [
`--user-data-dir=${profileDir}`,
'--disable-web-security',
'--disable-features=TranslateUI',
'--disable-background-timer-throttling',
'--disable-renderer-backgrounding',
'--disable-backgrounding-occluded-windows',
'--disable-background-networking',
'--disable-sync',
'--disable-default-apps',
'--disable-extensions-except',
'--disable-component-extensions-with-background-pages',
'--no-first-run',
'--no-default-browser-check',
'--disable-dev-shm-usage',
'--disable-gpu-sandbox',
'--disable-software-rasterizer',
'--aggressive-cache-discard',
'--memory-pressure-off'
];
// Add URL as last argument
chromeFlags.push(options.url);
spinner.succeed(chalk.green('š Opening Chrome with development settings...'));
if (options.debug) {
console.log(chalk.gray('\nš Debug Information:'));
console.log(`Chrome executable: ${chromeExecutable}`);
console.log(`Profile directory: ${profileDir}`);
console.log(`Chrome flags: ${chromeFlags.slice(0, 10).join(' ')} ...`);
}
console.log(chalk.cyan('\nš§ Chrome Development Settings:'));
console.log('⢠CORS disabled for API testing');
console.log('⢠Separate development profile');
console.log('⢠Performance optimized for development');
console.log('⢠Background processes minimized');
console.log('⢠Extension not auto-loaded (manual loading required)');
console.log(chalk.yellow(`\nš Profile: ${profileDir}`));
console.log(chalk.yellow(`š Opening: ${options.url}`));
// Launch Chrome
const chromeProcess = spawn(chromeExecutable, chromeFlags, {
detached: true,
stdio: 'ignore'
});
chromeProcess.unref();
console.log(chalk.green('\nā
Chrome launched successfully!'));
console.log(chalk.cyan('\nš Chrome opened with development settings:'));
console.log('⢠CORS disabled - API calls will work without CORS issues');
console.log('⢠Development profile - Settings isolated from your main Chrome');
console.log('⢠Performance optimized - Faster startup and reduced memory usage');
console.log(chalk.yellow('\nš§ To use the FreshRoute extension:'));
console.log('1. Go to chrome://extensions/ in the opened browser');
console.log('2. Enable "Developer mode" (toggle in top-right)');
console.log('3. Click "Load unpacked" and select the extension folder');
console.log('4. Or run: ' + chalk.green('freshroute install-manual') + ' for detailed instructions');
console.log(chalk.cyan('\nš” This Chrome instance is separate from your regular Chrome'));
console.log('⢠Your regular Chrome bookmarks/settings are not affected');
console.log('⢠Extensions and settings are isolated to this development profile');
console.log('⢠Close this Chrome window when done developing');
} catch (error) {
spinner.fail(chalk.red(`ā Failed to open Chrome: ${error.message}`));
console.log(chalk.yellow('\nš§ Troubleshooting:'));
console.log('⢠Make sure Chrome is installed');
console.log('⢠Check if Chrome executable path is correct');
console.log('⢠Try running with --debug flag for more info');
if (process.platform === 'darwin') {
console.log('⢠macOS: Chrome should be in /Applications/');
} else if (process.platform === 'win32') {
console.log('⢠Windows: Chrome should be in Program Files');
} else {
console.log('⢠Linux: Install google-chrome package');
}
}
});
// Extension info command
program
.command('extension-info')
.description('Show information about the bundled Chrome extension')
.action(async () => {
try {
const extensionPath = join(packageRoot, 'extension');
const manifestPath = join(extensionPath, 'manifest.json');
const manifestExists = await fs.access(manifestPath).then(() => true).catch(() => false);
if (!manifestExists) {
console.log(chalk.yellow('ā ļø Extension not found in package.'));
console.log(chalk.yellow('š” Try reinstalling: npm install -g freshroute-server'));
return;
}
const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
// Try to read extension info if available
const extensionInfoPath = join(extensionPath, 'extension-info.json');
let extensionInfo = null;
try {
extensionInfo = JSON.parse(await fs.readFile(extensionInfoPath, 'utf8'));
} catch (error) {
// Extension info file not found, that's ok
}
console.log(chalk.blue.bold('\nš¦ FreshRoute Chrome Extension Info:'));
console.log(`Name: ${chalk.green(manifest.name)}`);
console.log(`Version: ${chalk.green(manifest.version)}`);
console.log(`Description: ${chalk.gray(manifest.description)}`);
console.log(`Manifest Version: ${chalk.cyan(manifest.manifest_version)}`);
console.log(`Location: ${chalk.gray(extensionPath)}`);
if (extensionInfo) {
console.log(`Built: ${chalk.gray(new Date(extensionInfo.builtAt).toLocaleString())}`);
console.log(`Pre-built: ${chalk.green(extensionInfo.preBuilt ? 'Yes' : 'No')}`);
}
const stats = await fs.stat(extensionPath);
console.log(`Package Date: ${chalk.gray(stats.mtime.toLocaleString())}`);
// Check if installed
const userHome = os.homedir();
const extensionInstallPath = join(userHome, '.freshroute', 'extension');
const installedExists = await fs.access(extensionInstallPath).then(() => true).catch(() => false);
console.log(`Installed: ${installedExists ? chalk.green('Yes') : chalk.red('No')}`);
if (installedExists) {
console.log(`Install Location: ${chalk.gray(extensionInstallPath)}`);
}
} catch (error) {
console.error(chalk.red(`ā Error reading extension info: ${error.message}`));
}
});
// Open dashboard command
program
.command('dashboard')
.description('Open the FreshRoute dashboard in browser')
.action(async () => {
const url = 'http://localhost:3001/health';
console.log(chalk.blue(`š Opening dashboard: ${url}`));
try {
await open(url);
} catch (error) {
console.error(chalk.red(`ā Failed to open dashboard: ${error.message}`));
console.log(chalk.yellow('Make sure the server is running first: freshroute start'));
}
});
// Setup command
program
.command('setup')
.description('Complete setup: install extension and start server')
.action(async () => {
console.log(chalk.blue.bold('š§ Setting up FreshRoute Development Environment...\n'));
// Check if extension exists in package
const extensionPath = join(packageRoot, 'extension');
const extensionExists = await fs.access(extensionPath).then(() => true).catch(() => false);
if (!extensionExists) {
console.log(chalk.red('ā Pre-built extension not found in package'));
console.log(chalk.yellow('š” Try reinstalling: npm install -g freshroute-server'));
return;
}
console.log(chalk.yellow('ā¹ļø About FreshRoute Extension:'));
console.log('⢠Designed for development with CORS disabled');
console.log('⢠Uses separate Chrome profile for safety');
console.log('⢠Will NOT appear in your regular Chrome browser');
console.log('⢠Access via: ' + chalk.green('freshroute open-chrome') + '\n');
// Install extension
const installSpinner = ora('Installing Chrome extension to development profile...').start();
try {
const { installExtension } = await import('../scripts/install-extension.js');
await installExtension();
installSpinner.succeed('Extension installed successfully');
} catch (error) {
installSpinner.fail(`Extension installation failed: ${error.message}`);
return;
}
const userHome = os.homedir();
const extensionInstallPath = join(userHome, '.freshroute', 'extension');
console.log(chalk.green.bold('\nā
Setup complete!'));
console.log(chalk.cyan('\nš Development Workflow:'));
console.log('1. ' + chalk.green('freshroute start --dev') + ' - Start the development server');
console.log('2. ' + chalk.green('freshroute open-chrome') + ' - Open Chrome with extension & CORS disabled');
console.log('3. Configure mock rules via the extension UI');
console.log('4. Test your application with mocked APIs');
console.log(chalk.blue('\nš Extension Locations:'));
console.log('⢠Development profile: ' + chalk.gray('Auto-loaded via freshroute open-chrome'));
console.log('⢠Manual installation: ' + chalk.gray(extensionInstallPath));
console.log('⢠Regular Chrome: ' + chalk.yellow('Run "freshroute install-manual" for instructions'));
console.log(chalk.yellow('\nā ļø Important:'));
console.log('⢠The extension will NOT appear in your regular Chrome');
console.log('⢠Use ' + chalk.green('freshroute open-chrome') + ' to access it');
console.log('⢠This keeps your regular browsing profile clean and safe');
console.log(chalk.red('⢠Developer mode must be enabled in Chrome for extensions to load'));
console.log(chalk.cyan('\nš§ Next Steps:'));
console.log('1. ' + chalk.green('freshroute enable-dev-mode') + ' - Enable Developer mode in Chrome');
console.log('2. ' + chalk.green('freshroute start --dev') + ' - Start the development server');
console.log('3. ' + chalk.green('freshroute open-chrome') + ' - Open Chrome with extension');
console.log(chalk.gray('\nš” If extension doesn\'t appear, run: ') + chalk.green('freshroute enable-dev-mode'));
});
// Diagnostics command
program
.command('diagnose')
.description('Diagnose extension and Chrome setup issues')
.action(async () => {
console.log(chalk.blue.bold('š FreshRoute Diagnostics\n'));
// Check extension installation
const userHome = os.homedir();
const extensionInstallPath = join(userHome, '.freshroute', 'extension');
const extensionExists = await fs.access(extensionInstallPath).then(() => true).catch(() => false);
console.log(chalk.cyan('š¦ Extension Installation:'));
console.log(`Extension path: ${extensionInstallPath}`);
console.log(`Extension exists: ${extensionExists ? chalk.green('ā') : chalk.red('ā')}`);
if (extensionExists) {
// Check manifest
const manifestPath = join(extensionInstallPath, 'manifest.json');
const manifestExists = await fs.access(manifestPath).then(() => true).catch(() => false);
console.log(`Manifest exists: ${manifestExists ? chalk.green('ā') : chalk.red('ā')}`);
if (manifestExists) {
try {
const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
console.log(`Extension name: ${chalk.green(manifest.name)}`);
console.log(`Extension version: ${chalk.green(manifest.version)}`);
console.log(`Manifest version: ${chalk.green(manifest.manifest_version)}`);
} catch (error) {
console.log(`Manifest error: ${chalk.red(error.message)}`);
}
}
// Check key files
const keyFiles = ['background.js', 'popup.html', 'options.html', 'icons/icon16.png'];
for (const file of keyFiles) {
const filePath = join(extensionInstallPath, file);
const fileExists = await fs.access(filePath).then(() => true).catch(() => false);
console.log(`${file}: ${fileExists ? chalk.green('ā') : chalk.red('ā')}`);
}
}
// Check Chrome installation
console.log(chalk.cyan('\nš Chrome Installation:'));
const platform = process.platform;
let chromeExecutable;
switch (platform) {
case 'darwin':
chromeExecutable = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
break;
case 'win32':
chromeExecutable = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
break;
default:
chromeExecutable = 'google-chrome';
}
console.log(`Platform: ${platform}`);
console.log(`Expected Chrome path: ${chromeExecutable}`);
if (platform === 'darwin' || platform === 'win32') {
const chromeExists = await fs.access(chromeExecutable).then(() => true).catch(() => false);
console.log(`Chrome executable: ${chromeExists ? chalk.green('ā') : chalk.red('ā')}`);
} else {
console.log(`Chrome executable: ${chalk.yellow('? (check with: which google-chrome)')}`);
}
// Check profile directory
console.log(chalk.cyan('\nš Profile Directory:'));
const tempDir = join(os.tmpdir(), 'chrome-freshroute-dev');
const profileDir = join(tempDir, 'freshroute-dev');
const profileExists = await fs.access(profileDir).then(() => true).catch(() => false);
console.log(`Profile path: ${profileDir}`);
console.log(`Profile exists: ${profileExists ? chalk.green('ā') : chalk.yellow('Will be created')}`);
// Check if Chrome is running with the profile
console.log(chalk.cyan('\nš§ Chrome Process Check:'));
try {
const { exec } = await import('child_process');
const { promisify } = await import('util');
const execAsync = promisify(exec);
if (platform === 'darwin') {
const { stdout } = await execAsync('ps aux | grep "chrome-freshroute-dev" | grep -v grep || true');
if (stdout.trim()) {
console.log(`Chrome development process: ${chalk.green('ā Running')}`);
console.log(`Process info: ${chalk.gray(stdout.trim().split('\n')[0])}`);
} else {
console.log(`Chrome development process: ${chalk.yellow('Not running')}`);
}
} else {
console.log(`Chrome development process: ${chalk.yellow('Manual check required')}`);
}
} catch (error) {
console.log(`Chrome development process: ${chalk.yellow('Could not check')}`);
}
// Provide recommendations
console.log(chalk.blue('\nš” Recommendations:'));
if (!extensionExists) {
console.log(chalk.yellow('⢠Run: freshroute install-extension'));
}
if (platform === 'darwin' || platform === 'win32') {
const chromeExists = await fs.access(chromeExecutable).then(() => true).catch(() => false);
if (!chromeExists) {
console.log(chalk.yellow('⢠Install Google Chrome from https://www.google.com/chrome/'));
}
}
console.log(chalk.green('⢠After opening Chrome with freshroute open-chrome:'));
console.log(' - Check chrome://extensions/ in the development browser');
console.log(' - Look for FreshRoute in the extensions list');
console.log(' - Check if Developer mode is enabled');
console.log(' - Look for any error messages in the extension');
console.log(chalk.cyan('\nš Test Commands:'));
console.log('⢠freshroute open-chrome --debug # Open with debug info');
console.log('⢠freshroute extension-info # Show extension details');
console.log('⢠freshroute install-manual # Manual installation guide');
});
// Check extension status command
program
.command('check-extension')
.description('Check if FreshRoute extension is properly loaded in Chrome')
.option('--open-extensions', 'Open Chrome extensions page for manual verification')
.action(async (options) => {
console.log(chalk.blue.bold('š Checking FreshRoute Extension Status...\n'));
// Check extension installation
const userHome = os.homedir();
const extensionPath = join(userHome, '.freshroute', 'extension');
const extensionExists = await fs.access(extensionPath).then(() => true).catch(() => false);
if (!extensionExists) {
console.log(chalk.red('ā Extension not installed'));
console.log(chalk.yellow('š” Run: freshroute setup'));
return;
}
console.log(chalk.green('ā
Extension installed at: ' + extensionPath));
// Check manifest
try {
const manifestPath = join(extensionPath, 'manifest.json');
const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
console.log(chalk.green('ā
Manifest valid: ' + manifest.name + ' v' + manifest.version));
// Check essential files
const essentialFiles = ['background.js', 'popup.html', 'options.html'];
for (const file of essentialFiles) {
const filePath = join(extensionPath, file);
const exists = await fs.access(filePath).then(() => true).catch(() => false);
if (exists) {
console.log(chalk.green('ā
' + file + ' exists'));
} else {
console.log(chalk.red('ā ' + file + ' missing'));
}
}
} catch (error) {
console.log(chalk.red('ā Manifest error: ' + error.message));
return;
}
console.log(chalk.cyan('\nš Chrome Extension Visibility Troubleshooting:\n'));
console.log(chalk.yellow('1. Extension Icon Location:'));
console.log(' ⢠Look for FreshRoute icon in Chrome toolbar (top-right)');
console.log(' ⢠If not visible, click the puzzle piece (š§©) icon');
console.log(' ⢠Pin FreshRoute by clicking the pin icon next to it');
console.log(chalk.yellow('\n2. Extensions Page Check:'));
console.log(' ⢠Go to chrome://extensions/ in your development Chrome');
console.log(' ⢠Look for "FreshRoute" in the list');
console.log(' ⢠It should show as "Enabled"');
console.log(' ⢠If "Errors" shows, click to see details');
console.log(chalk.yellow('\n3. Common Issues & Solutions:'));
console.log(chalk.red(' ⢠Extension not visible? Developer mode is probably DISABLED'));
console.log(chalk.cyan(' Run: freshroute enable-dev-mode'));
console.log(' ⢠Extension disabled? Click the toggle to enable it');
console.log(' ⢠Permission errors? The extension needs broad permissions');
console.log(' ⢠Multiple Chrome windows? Make sure you\'re in the development profile');
console.log(chalk.yellow('\n4. Development Profile vs Regular Chrome:'));
console.log(' ⢠FreshRoute ONLY works in development profile');
console.log(' ⢠Must use: ' + chalk.green('freshroute open-chrome'));
console.log(' ⢠Will NOT appear in regular Chrome browser');
console.log(' ⢠Development profile path: /tmp/chrome-freshroute-dev/');
console.log(chalk.cyan('\nš§ Quick Fixes:\n'));
console.log(chalk.green('Reset Development Profile:'));
console.log(' freshroute open-chrome --new-session --debug');
console.log(chalk.green('\nOpen Extensions Page:'));
console.log(' freshroute check-extension --open-extensions');
console.log(chalk.green('\nManual Verification:'));
console.log(' 1. freshroute open-chrome --debug');
console.log(' 2. In opened Chrome, go to chrome://extensions/');
console.log(' 3. Look for "FreshRoute" in the list');
console.log(' 4. Check if it\'s enabled and has no errors');
if (options.openExtensions) {
console.log(chalk.blue('\nš Opening extensions page in development Chrome...'));
// Open development Chrome with extensions page
const tempDir = join(os.tmpdir(), 'chrome-freshroute-dev');
const profileDir = join(tempDir, 'freshroute-dev');
await fs.mkdir(profileDir, { recursive: true });
const platform = process.platform;
let chromeExecutable;
switch (platform) {
case 'darwin':
chromeExecutable = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
break;
case 'win32':
chromeExecutable = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
if (!await fs.access(chromeExecutable).then(() => true).catch(() => false)) {
chromeExecutable = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe';
}
break;
default:
chromeExecutable = 'google-chrome';
}
const chromeFlags = [
`--user-data-dir=${profileDir}`,
`--load-extension=${extensionPath}`,
'--disable-web-security',
'chrome://extensions/'
];
try {
const chromeProcess = spawn(chromeExecutable, chromeFlags, {
detached: true,
stdio: 'ignore'
});
chromeProcess.unref();
console.log(chalk.green('ā
Chrome opened with extensions page!'));
console.log(chalk.yellow('š” Look for "FreshRoute" in the extensions list'));
} catch (error) {
console.log(chalk.red('ā Failed to open Chrome: ' + error.message));
}
}
console.log(chalk.gray('\nš” Still having issues? Run: freshroute diagnose'));
});
// Enable developer mode command
program
.command('enable-dev-mode')
.description('Enable Chrome Developer mode for extensions (required for FreshRoute)')
.option('--interactive', 'Interactive mode with step-by-step guidance')
.action(async (options) => {
console.log(chalk.blue.bold('š§ Chrome Developer Mode Setup...\n'));
if (options.interactive) {
await interactiveDeveloperModeSetup();
return;
}
console.log(chalk.red.bold('ā ļø IMPORTANT: Developer mode must be MANUALLY enabled'));
console.log(chalk.yellow(' Chrome security prevents automatic enabling\n'));
// Check extension installation
const userHome = os.homedir();
const extensionInstallPath = join(userHome, '.freshroute', 'extension');
const extensionExists = await fs.access(extensionInstallPath).then(() => true).catch(() => false);
if (!extensionExists) {
console.log(chalk.red('ā Extension not installed. Run "freshroute setup" first.'));
return;
}
console.log(chalk.green('ā
Extension found at: ' + extensionInstallPath));
// Open Chrome to extensions page with developer mode instructions
const tempDir = join(os.tmpdir(), 'chrome-freshroute-dev');
const profileDir = join(tempDir, 'freshroute-dev');
await fs.mkdir(profileDir, { recursive: true });
const platform = process.platform;
let chromeExecutable;
switch (platform) {
case 'darwin':
chromeExecutable = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
break;
case 'win32':
chromeExecutable = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
if (!await fs.access(chromeExecutable).then(() => true).catch(() => false)) {
chromeExecutable = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe';
}
break;
default:
chromeExecutable = 'google-chrome';
}
const chromeFlags = [
`--user-data-dir=${profileDir}`,
'--disable-web-security',
'chrome://extensions/'
];
console.log(chalk.cyan('š Opening Chrome Extensions page...\n'));
console.log(chalk.yellow.bold('š EXACT STEPS TO FOLLOW:'));
console.log(chalk.blue('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
console.log(chalk.green('STEP 1: ') + 'Chrome will open to chrome://extensions/');
console.log(chalk.green('STEP 2: ') + chalk.cyan.bold('Look for "Developer mode" in the TOP-RIGHT corner'));
console.log(chalk.green('STEP 3: ') + chalk.yellow.bold('Click the toggle switch to turn it ON'));
console.log(chalk.green('STEP 4: ') + 'New buttons should appear: "Load unpacked", "Pack extension"');
console.log(chalk.green('STEP 5: ') + chalk.cyan.bold('Click "Load unpacked"'));
console.log(chalk.green('STEP 6: ') + 'Navigate to: ' + chalk.magenta(extensionInstallPath));
console.log(chalk.green('STEP 7: ') + 'Select the extension folder and click "Select Folder"');
console.log(chalk.green('STEP 8: ') + chalk.green.bold('FreshRoute should appear in extensions list!'));
console.log(chalk.blue('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
console.log(chalk.red('\nšØ TROUBLESHOOTING IF DEVELOPER MODE TOGGLE IS MISSING:'));
console.log('⢠Your organization might have disabled developer mode');
console.log('⢠Chrome might be managed by enterprise policy');
console.log('⢠Try using a personal Chrome profile instead');
console.log('⢠Check if you\'re in the right Chrome window/profile');
try {
const chromeProcess = spawn(chromeExecutable, chromeFlags, {
detached: true,
stdio: 'ignore'
});
chromeProcess.unref();
console.log(chalk.green('\nā
Chrome opened to extensions page!'));
console.log(chalk.yellow('\nā³ After enabling Developer mode:'));
console.log('⢠Run: ' + chalk.green('freshroute check-extension') + ' to verify');
console.log('⢠Then: ' + chalk.green('freshroute open-chrome --new-session'));
console.log(chalk.blue('\nš” Need more help? Run:'));
console.log(chalk.green('freshroute enable-dev-mode --interactive'));
} catch (error) {
console.log(chalk.red('ā Failed to open Chrome: ' + error.message));
console.log(chalk.yellow('\nš§ Manual Steps:'));
console.log('1. Open Chrome manually');
console.log('2. Type: chrome://extensions/ in address bar');
console.log('3. Enable Developer mode toggle (top-right)');
console.log('4. Click "Load unpacked"');
console.log('5. Select: ' + extensionInstallPath);
}
});
// Interactive developer mode setup function
async function interactiveDeveloperModeSetup() {
console.log(chalk.blue.bold('šÆ Interactive Developer Mode Setup\n'));
const userHome = os.homedir();
const extensionInstallPath = join(userHome, '.freshroute', 'extension');
console.log(chalk.cyan('š Extension location: ') + chalk.gray(extensionInstallPath));
console.log(chalk.yellow('\nš Let\'s check your current Chrome extensions page:'));
console.log('1. Open Chrome manually');
console.log('2. Go to: ' + chalk.blue('chrome://extensions/'));
console.log('3. Look at the TOP-RIGHT corner');
console.log(chalk.cyan('\nā What do you see in the top-right corner?'));
console.log(chalk.green('A) ') + 'A toggle switch labeled "Developer mode" (OFF)');
console.log(chalk.green('B) ') + 'A toggle switch labeled "Developer mode" (ON)');
console.log(chalk.green('C) ') + 'No "Developer mode" toggle at all');
console.log(chalk.green('D) ') + 'Something else / Not sure');
console.log(chalk.blue('\nš Based on what you see:'));
console.log(chalk.yellow('\nš
°ļø If you see "Developer mode" toggle (OFF):'));
console.log(' ā Click it to turn it ON');
console.log(' ā You should see "Load unpacked" button appear');
console.log(' ā Click "Load unpacked"');
console.log(' ā Navigate to: ' + chalk.cyan(extensionInstallPath));
console.log(' ā Select the folder');
console.log(chalk.yellow('\nš
±ļø If Developer mode is already ON:'));
console.log(' ā Click "Load unpacked" button');
console.log(' ā Navigate to: ' + chalk.cyan(extensionInstallPath));
console.log(' ā Select the folder');
console.log(chalk.red('\nš
² If NO "Developer mode" toggle exists:'));
console.log(' ā Your Chrome is managed by organization/enterprise');
console.log(' ā Developer mode is disabled by policy');
console.log(' ā Try: Different Chrome profile');
console.log(' ā Try: Personal Chrome installation');
console.log(' ā Or use: ' + chalk.green('freshroute install-manual') + ' for regular Chrome');
console.log(chalk.yellow('\nš
³ If you\'re not sure:'));
console.log(' ā Take a screenshot of chrome://extensions/');
console.log(' ā Look for a toggle/switch in corners of the page');
console.log(' ā Try refreshing the page (F5)');
console.log(chalk.green('\nšÆ Quick Copy-Paste Path:'));
console.log(chalk.gray(extensionInstallPath));
console.log(chalk.blue('\nš After loading extension, verify with:'));
console.log(chalk.green('freshroute check-extension --open-extensions'));
}
// Debug Chrome setup command
program
.command('debug-chrome')
.description('Debug Chrome configuration and extension loading issues')
.action(async () => {
console.log(chalk.blue.bold('š Chrome Configuration Debug\n'));
const userHome = os.homedir();
const extensionInstallPath = join(userHome, '.freshroute', 'extension');
const tempDir = join(os.tmpdir(), 'chrome-freshroute-dev');
const profileDir = join(tempDir, 'freshroute-dev');
console.log(chalk.cyan('š File System Check:'));
// Check extension
const extensionExists = await fs.access(extensionInstallPath).then(() => true).catch(() => false);
console.log(`Extension directory: ${extensionExists ? chalk.green('ā') : chalk.red('ā')} ${extensionInstallPath}`);
if (extensionExists) {
const manifestExists = await fs.access(join(extensionInstallPath, 'manifest.json')).then(() => true).catch(() => false);
console.log(`Manifest file: ${manifestExists ? chalk.green('ā') : chalk.red('ā')} ${join(extensionInstallPath, 'manifest.json')}`);
if (manifestExists) {
try {
const manifest = JSON.parse(await fs.readFile(join(extensionInstallPath, 'manifest.json'), 'utf8'));
console.log(`Extension name: ${chalk.green(manifest.name)}`);
console.log(`Extension version: ${chalk.green(manifest.version)}`);
console.log(`Manifest version: ${chalk.green(manifest.manifest_version)}`);
} catch (error) {
console.log(`Manifest error: ${chalk.red(error.message)}`);
}
}
}
// Check Chrome profile
const profileExists = await fs.access(profileDir).then(() => true).catch(() => false);
console.log(`Chrome profile: ${profileExists ? chalk.green('ā') : chalk.yellow('ā')} ${profileDir}`);
// Check Chrome executable
const platform = process.platform;
let chromeExecutable;
switch (platform) {
case 'darwin':
chromeExecutable = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
break;
case 'win32':
chromeExecutable = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
if (!await fs.access(chromeExecutable).then(() => true).catch(() => false)) {
chromeExecutable = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe';
}
break;
default:
chromeExecutable = 'google-chrome';
}
const chromeExists = await fs.access(chromeExecutable).then(() => true).catch(() => false);
console.log(`Chrome executable: ${chromeExists ? chalk.green('ā') : chalk.red('ā')} ${chromeExecutable}`);
console.log(chalk.cyan('\nš§ Chrome Policy Check:'));
console.log('Run this in terminal to check Chrome policies:');
console.log(chalk.gray('chrome://policy/ (in Chrome address bar)'));
console.log(chalk.cyan('\nš Common Issues:'));
console.log(chalk.yellow('1. Enterprise/Organization Chrome:'));
console.log(' ⢠Developer mode disabled by IT policy');
console.log(' ⢠Extensions blocked by organization');
console.log(' ⢠Use personal Chrome or different profile');
console.log(chalk.yellow('\n2. Chrome Profile Issues:'));
console.log(' ⢠Multiple Chrome instances running');
console.log(' ⢠Wrong Chrome profile opened');
console.log(' ⢠Profile corruption');
console.log(chalk.yellow('\n3. Extension Issues:'));
console.log(' ⢠Extension files corrupted or missing');
console.log(' ⢠Invalid manifest.json');
console.log(' ⢠Permission issues');
console.log(chalk.cyan('\nšÆ Diagnostic Steps:'));
console.log('1. Go to chrome://version/ to check your Chrome details');
console.log('2. Go to chrome://policy/ to check enterprise policies');
console.log('3. Try chrome://extensions/ in a private/incognito window');
console.log('4. Check if you can enable developer mode in regular Chrome');
console.log(chalk.green('\nš§ Quick Tests:'));
console.log(`Copy this path: ${chalk.cyan(extensionInstallPath)}`);
console.log('1. Open regular Chrome (not dev profile)');
console.log('2. Go to chrome://extensions/');
console.log('3. Try to enable Developer mode there');
console.log('4. If it works, use: ' + chalk.green('freshroute install-manual'));
console.log(chalk.blue('\nš” Alternative Solutions:'));
console.log('⢠' + chalk.green('freshroute install-manual') + ' - Install in regular Chrome profile');
console.log('⢠Use different Chrome installation (personal vs enterprise)');
console.log('⢠Try Chrome Canary or Chromium browser');
});
// Check Chrome policies command
program
.command('check-chrome-policies')
.description('Check if Chrome is managed by organization and blocking extensions')
.action(async () => {
console.log(chalk.blue.bold('š Chrome Organization Policy Check\n'));
const userHome = os.homedir();
const platform = process.platform;
console.log(chalk.cyan('š„ļø System Information:'));
console.log(`Platform: ${platform}`);
console.log(`User: ${userHome}`);
console.log(chalk.cyan('\nš Chrome Policy Locations:'));
let policyLocations = [];
let managedPolicyFound = false;
if (platform === 'darwin') {
policyLocations = [
'/Library/Managed Preferences/com.google.Chrome.plist',
join(userHome, 'Library/Managed Preferences/com.google.Chrome.plist'),
'/Library/Application Support/Google/Chrome/policies',
join(userHome, 'Library/Application Support/Google/Chrome/policies')
];
} else if (platform === 'win32') {
policyLocations = [
'C:\\Program Files\\Google\\Chrome\\Application\\policies',
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\policies'
];
} else {
policyLocations = [
'/etc/opt/chrome/policies',
'/etc/chromium/policies',
join(userHome, '.config/google-chrome/policies')
];
}
for (const policyPath of policyLocations) {
try {
const stats = await fs.stat(policyPath);
console.log(`${chalk.red('šØ')} FOUND: ${policyPath}`);
managedPolicyFound = true;
if (stats.isFile() && policyPath.endsWith('.plist')) {
try {
const content = await fs.readFile(policyPath, 'utf8');
if (content.includes('ExtensionSettings') || content.includes('DeveloperToolsDisabled')) {
console.log(` ${chalk.yellow('Contains extension restrictions')}`);
}
} catch (error) {
console.log(` ${chalk.gray('Unable to read content')}`);
}
}
} catch (error)