#!/usr/bin/env node
/**
 * Vigthoria CLI - AI-Powered Terminal Coding Assistant
 *
 * Usage:
 *   vigthoria chat              - Start interactive chat
 *   vigthoria edit <file>       - Edit a file with AI assistance
 *   vigthoria generate <desc>   - Generate code from description
 *   vigthoria explain <file>    - Explain code in a file
 *   vigthoria fix <file>        - Fix issues in a file
 *   vigthoria review <file>     - Review code quality
 *   vigthoria login             - Authenticate with Vigthoria
 *   vigthoria config            - Configure settings
 *   vigthoria hub               - Discover & activate API modules
 *   vigthoria workflow          - Manage repeatable VigFlow workflows
 *   vigthoria operator          - Start BMAD operator mode
 */
import { Command } from 'commander';
import { ChatCommand } from './commands/chat.js';
import { EditCommand } from './commands/edit.js';
import { GenerateCommand } from './commands/generate.js';
import { ExplainCommand } from './commands/explain.js';
import { handleLogin, handleLogout, registerAuthCommands, statusAction } from './commands/auth.js';
import { ConfigCommand } from './commands/config.js';
import { ReviewCommand } from './commands/review.js';
import { HubCommand } from './commands/hub.js';
import { MusicCommand } from './commands/music.js';
import { RepoCommand } from './commands/repo.js';
import { DeployCommand } from './commands/deploy.js';
import { BridgeCommand } from './commands/bridge.js';
import { DeviceCommand } from './commands/device.js';
import { WorkflowCommand } from './commands/workflow.js';
import { PreviewCommand } from './commands/preview.js';
import { GameCommand } from './commands/game.js';
import { LegionCommand } from './commands/legion.js';
import { HistoryCommand } from './commands/history.js';
import { ReplayCommand } from './commands/replay.js';
import { ForkCommand } from './commands/fork.js';
import { CancelCommand } from './commands/cancel.js';
import { BackgroundCommand } from './commands/background.js';
import { SecurityCommand } from './commands/security.js';
import { WalletCommand } from './commands/wallet.js';
import { V4Command } from './commands/v4.js';
import { runV4Menu } from './commands/v4-menu.js';
import { Config } from './utils/config.js';
import { Logger, CH } from './utils/logger.js';
import chalk from 'chalk';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { fileURLToPath } from 'url';
import { createHash } from 'crypto';
import axios from 'axios';
import { renderDynamicHelp, selectInteractiveCommand } from './utils/command-menu.js';
import { isIOSEnvironment, resolveClientOsSlug } from './utils/clientManifest.js';
// ESM shim — TypeScript emits ESM under "type": "module", so __dirname
// is not available natively.  Restore the CommonJS-style helper so the
// pre-existing package-discovery logic continues to work unchanged.
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
import { APIClient, sanitizeUserFacingErrorText } from './utils/api.js';
import { getCliStateFile, isOfflineMode, isSafeNpmPackageSpec, isUpdateCheckSuppressed, readCachedLatestVersion, readGatewayPreflightCache, writeCachedLatestVersion, writeGatewayPreflightCache, } from './utils/cli-state.js';
import { applyLocalTestfarmDefaults, isLocalTestfarmMode } from './utils/localTestMode.js';
applyLocalTestfarmDefaults();
// --- Terminal column-width safety clamp -----------------------------------
// Node's `readline` module (used for the interactive chat `> ` prompt and a
// few other prompts) redraws the current input line on every keystroke using
// cursor-position math derived from `process.stdout.columns`. When this CLI
// runs inside a freshly-spawned ConPTY child (e.g. the Vigthoria Workbench's
// embedded terminal pane on Windows), there is a brief window right after
// process start where the console width hasn't been reported yet (or is
// reported as an implausibly small value like 0/1) before the real terminal
// size propagates down to the child process. Because `readline` reads
// `columns` fresh on every redraw (not just once at startup), an early or
// transient bad reading makes it believe the terminal is only 1 column wide,
// so it moves the cursor to a new row (and re-indents) after every single
// typed character -- producing a "staircase" of one-character lines that
// looks exactly like what's reported. This has nothing to do with the host
// terminal's real (correct) width; it's purely readline believing a bad
// number. Clamp `columns`/`rows` to sane floors up front and keep them
// clamped on every real resize event so readline never sees an implausible
// value, regardless of what the host terminal actually reports.
const MIN_TTY_COLUMNS = 30;
const MIN_TTY_ROWS = 4;
function clampStreamSize(stream) {
    if (!stream || !stream.isTTY)
        return;
    if (!Number.isFinite(stream.columns) || (stream.columns ?? 0) < MIN_TTY_COLUMNS) {
        stream.columns = 80;
    }
    if (!Number.isFinite(stream.rows) || (stream.rows ?? 0) < MIN_TTY_ROWS) {
        stream.rows = 24;
    }
}
clampStreamSize(process.stdout);
clampStreamSize(process.stderr);
if (process.stdout.isTTY) {
    process.stdout.on('resize', () => clampStreamSize(process.stdout));
}
if (process.stderr.isTTY) {
    process.stderr.on('resize', () => clampStreamSize(process.stderr));
}
function isApiError(error) {
    return Boolean(error &&
        typeof error === 'object' &&
        typeof error.status === 'number' &&
        typeof error.message === 'string' &&
        typeof error.code === 'string');
}
function getInvokedBinaryName() {
    const executable = process.argv[1] || 'vigthoria';
    return path.basename(executable, path.extname(executable)).toLowerCase();
}
// Get version from package.json dynamically
function getPackageMetadataPaths() {
    return [
        path.join(__dirname, '..', 'package.json'),
        path.join(__dirname, '..', '..', 'package.json'),
        path.join(process.cwd(), 'package.json'),
        path.join(process.cwd(), 'node_modules', 'vigthoria-cli', 'package.json'),
        // Also check global npm paths on Windows
        path.join(process.env.APPDATA || '', 'npm', 'node_modules', 'vigthoria-cli', 'package.json'),
    ];
}
function resolveRunningPackageJsonPath() {
    const candidates = [];
    const scriptArg = process.argv[1];
    if (scriptArg) {
        try {
            const resolvedScript = fs.realpathSync(scriptArg);
            candidates.push(path.join(path.dirname(resolvedScript), '..', 'package.json'));
        }
        catch {
            candidates.push(path.join(path.dirname(scriptArg), '..', 'package.json'));
        }
    }
    candidates.push(path.join(__dirname, '..', 'package.json'));
    for (const candidate of candidates) {
        try {
            if (!fs.existsSync(candidate))
                continue;
            const pkg = JSON.parse(fs.readFileSync(candidate, 'utf8'));
            if (pkg?.name === 'vigthoria-cli')
                return candidate;
        }
        catch {
            // try next candidate
        }
    }
    return null;
}
function getVersion() {
    try {
        const runningPackageJson = resolveRunningPackageJsonPath();
        if (runningPackageJson) {
            const pkg = JSON.parse(fs.readFileSync(runningPackageJson, 'utf8'));
            if (pkg.version)
                return pkg.version;
        }
        for (const p of getPackageMetadataPaths()) {
            if (fs.existsSync(p)) {
                const pkg = JSON.parse(fs.readFileSync(p, 'utf8'));
                if (pkg.name === 'vigthoria-cli') {
                    return pkg.version;
                }
            }
        }
    }
    catch (e) {
        const message = e instanceof Error ? e.message : String(e);
        if (process.env.VIGTHORIA_DEBUG_VERSION === '1') {
            console.error(chalk.gray(`Unable to read package version: ${message}`));
        }
    }
    return '0.0.0';
}
export function validateReleaseMetadata() {
    try {
        const packagePath = getPackageMetadataPaths().find((candidate) => fs.existsSync(candidate));
        if (!packagePath) {
            return false;
        }
        const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
        const packageDir = path.dirname(packagePath);
        const readmePath = path.join(packageDir, 'README.md');
        if (!fs.existsSync(readmePath)) {
            return false;
        }
        const readme = fs.readFileSync(readmePath, 'utf8');
        const bins = pkg.bin && typeof pkg.bin === 'object' ? pkg.bin : {};
        const requiredReadmePhrases = [
            'npm install -g vigthoria-cli',
            'curl -fsSL https://cli.vigthoria.io/install.sh | bash',
            'irm https://cli.vigthoria.io/install.ps1 | iex',
            'vigthoria login',
            'vigthoria chat',
            'vig c',
            'vigthoria edit',
            'vigthoria update',
            'vigthoria doctor',
        ];
        return (pkg.name === 'vigthoria-cli' &&
            typeof pkg.version === 'string' &&
            pkg.description === 'Vigthoria Coder CLI - AI-powered terminal coding assistant' &&
            pkg.main === 'dist/index.js' &&
            bins.vigthoria === 'dist/index.js' &&
            bins.vig === 'dist/index.js' &&
            bins['vigthoria-chat'] === 'dist/index.js' &&
            requiredReadmePhrases.every((phrase) => readme.includes(phrase)));
    }
    catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        if (process.env.VIGTHORIA_DEBUG_VERSION === '1') {
            console.error(chalk.gray(`Release metadata validation failed: ${message}`));
        }
        return false;
    }
}
function compareVersions(v1, v2) {
    const parts1 = v1.split('.').map(Number);
    const parts2 = v2.split('.').map(Number);
    for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
        const p1 = parts1[i] || 0;
        const p2 = parts2[i] || 0;
        if (p1 < p2)
            return -1;
        if (p1 > p2)
            return 1;
    }
    return 0;
}
function maxVersion(...versions) {
    let best = null;
    for (const version of versions) {
        if (!version)
            continue;
        if (!best || compareVersions(version, best) > 0)
            best = version;
    }
    return best;
}
async function fetchNpmLatestVersion() {
    const { execSync } = await import('child_process');
    try {
        // Hard 5s timeout: a slow/blocked path to the public npm registry must
        // never hang the caller (e.g. the Workbench's blocking `vigthoria update`
        // invocation) indefinitely.
        const latest = execSync('npm view vigthoria-cli version', {
            encoding: 'utf8',
            stdio: ['pipe', 'pipe', 'pipe'],
            windowsHide: true,
            timeout: 5000,
        }).trim();
        return latest || null;
    }
    catch {
        return null;
    }
}
const VERSION = getVersion();
const VIGTHORIA_DEFAULT_MANIFEST_URL = process.env.VIGTHORIA_UPDATE_MANIFEST_URL || "https://coder.vigthoria.io/releases/manifest.json";
function resolveManifestEntry(manifest, channel) {
    const normalized = String(channel || 'stable').trim() || 'stable';
    if (manifest.channels && manifest.channels[normalized]) {
        return manifest.channels[normalized];
    }
    const direct = manifest[normalized];
    if (direct && typeof direct === 'object') {
        return direct;
    }
    if (normalized === 'stable') {
        const rootVersion = typeof manifest.version === 'string' ? manifest.version : '';
        const rootUrl = typeof manifest.url === 'string' ? manifest.url : '';
        const rootSha = typeof manifest.sha256 === 'string' ? manifest.sha256 : undefined;
        if (rootVersion && rootUrl) {
            return { version: rootVersion, url: rootUrl, sha256: rootSha };
        }
    }
    return null;
}
async function downloadFile(url, targetPath) {
    const response = await axios.get(url, {
        responseType: 'arraybuffer',
        timeout: 20000,
        maxRedirects: 5,
        validateStatus: (status) => status >= 200 && status < 300,
    });
    fs.writeFileSync(targetPath, Buffer.from(response.data));
}
const TRUSTED_RELEASE_HOSTS = new Set([
    'extension.vigthoria.io',
    'landing.vigthoria.io',
    'coder.vigthoria.io',
    'market.vigthoria.io',
]);
function validateReleaseUrl(rawUrl, allowLocalhost = false) {
    const parsed = new URL(rawUrl);
    const local = parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1' || parsed.hostname === '::1';
    if (parsed.protocol !== 'https:' && !(allowLocalhost && local && parsed.protocol === 'http:')) {
        throw new Error('Release URLs must use HTTPS (HTTP is allowed only for an explicit localhost manifest).');
    }
    if (!TRUSTED_RELEASE_HOSTS.has(parsed.hostname) && !(allowLocalhost && local)) {
        throw new Error(`Untrusted release host: ${parsed.hostname}`);
    }
    return parsed;
}
function sha256File(filePath) {
    const hash = createHash('sha256');
    const data = fs.readFileSync(filePath);
    hash.update(data);
    return hash.digest('hex');
}
async function installGlobalPackageWithNpm(packageSpec) {
    const { execFileSync, execSync } = await import('child_process');
    const attempts = [];
    if (process.platform === 'win32') {
        // First-choice: cmd.exe /c npm — resolves npm.cmd shims on any Windows Node setup
        const comspec = process.env.COMSPEC || 'cmd.exe';
        attempts.push({
            label: 'cmd.exe /c npm',
            command: comspec,
            args: ['/c', 'npm', 'install', '-g', packageSpec],
        });
        const npmExecPath = process.env.npm_execpath;
        if (npmExecPath && fs.existsSync(npmExecPath)) {
            attempts.push({
                label: 'node+npm_execpath',
                command: process.execPath,
                args: [npmExecPath, 'install', '-g', packageSpec],
            });
        }
        try {
            const resolvedNpmCmd = execSync('where npm.cmd', {
                encoding: 'utf8',
                stdio: ['pipe', 'pipe', 'pipe'],
                windowsHide: true,
            }).split(/\r?\n/).map((line) => line.trim()).find(Boolean);
            if (resolvedNpmCmd) {
                attempts.push({
                    label: 'where npm.cmd',
                    command: resolvedNpmCmd,
                    args: ['install', '-g', packageSpec],
                });
            }
        }
        catch {
            // Fall through to generic attempts below.
        }
        attempts.push({
            label: 'npm.cmd',
            command: 'npm.cmd',
            args: ['install', '-g', packageSpec],
        });
        // Last-resort Windows shell fallback for PATH/cmd shim edge-cases.
        attempts.push({
            label: 'npm via shell',
            command: 'npm',
            args: ['install', '-g', packageSpec],
            shell: true,
        });
    }
    else {
        let resolvedNpm = '';
        try {
            resolvedNpm = execSync('which npm', {
                encoding: 'utf8',
                stdio: ['pipe', 'pipe', 'pipe'],
            }).trim();
        }
        catch {
            // Keep resolvedNpm empty and use plain `npm` below.
        }
        attempts.push({
            label: resolvedNpm ? 'which npm' : 'npm',
            command: resolvedNpm || 'npm',
            args: ['install', '-g', packageSpec],
        });
    }
    let lastError = null;
    for (const attempt of attempts) {
        try {
            console.log(chalk.gray(`[update] installer executable: ${attempt.command}${attempt.shell ? ' (shell)' : ''}`));
            execFileSync(attempt.command, attempt.args, {
                stdio: 'inherit',
                windowsHide: true,
                shell: attempt.shell === true,
                // Hard cap so a stalled/hung npm install (registry outage, network
                // issue, etc.) can never block the caller indefinitely - especially
                // important since the Workbench invokes this synchronously.
                timeout: 180000,
            });
            return;
        }
        catch (error) {
            lastError = error;
            const code = error?.code || error?.status || 'unknown';
            console.error(chalk.yellow(`[update] install attempt failed via ${attempt.label}: ${code}`));
        }
    }
    const finalCode = lastError?.code || lastError?.status || 'unknown';
    throw new Error(`Unable to launch npm installer after ${attempts.length} attempt(s). Last error: ${finalCode}`);
}
function renderUpdateBanner(latestVersion) {
    if (compareVersions(latestVersion, '1.4.0') >= 0 && compareVersions(VERSION, '1.4.0') < 0) {
        console.log(chalk.red.bold(`\n${CH.warnEmoji}  SECURITY UPDATE AVAILABLE`));
        console.log(chalk.red(`   Version ${VERSION} has security vulnerabilities.`));
        console.log(chalk.yellow(`   Please update to ${latestVersion} immediately:`));
        console.log(chalk.white.bold('   npm install -g vigthoria-cli@latest\n'));
    }
    else {
        console.log(chalk.yellow(`\n${CH.warnEmoji}  Update available: ${VERSION} -> ${latestVersion}`));
        console.log(chalk.gray('   Run `vigthoria update` to install\n'));
    }
}
// Check for updates quietly on startup. Cached (24 h) so we never block
// startup on `npm view`. Honours VIGTHORIA_OFFLINE / VIGTHORIA_NO_UPDATE_CHECK.
async function checkForUpdatesQuietly() {
    if (isUpdateCheckSuppressed()) {
        return;
    }
    const cached = readCachedLatestVersion();
    if (cached) {
        if (compareVersions(cached, VERSION) > 0) {
            renderUpdateBanner(cached);
        }
        return;
    }
    // Cache miss: probe npm registry in the background, with a hard 5 s
    // timeout. Result is cached for 24 h so subsequent runs are instant.
    try {
        const { execSync } = await import('child_process');
        const npmVersion = execSync('npm view vigthoria-cli version', {
            encoding: 'utf8',
            timeout: 5000,
            stdio: ['pipe', 'pipe', 'pipe'],
            windowsHide: true,
        }).trim();
        if (!npmVersion) {
            return;
        }
        writeCachedLatestVersion(npmVersion);
        if (compareVersions(npmVersion, VERSION) > 0) {
            renderUpdateBanner(npmVersion);
        }
    }
    catch {
        // Network or npm failure should never block CLI; do not cache failure.
    }
}
const VIGTHORIA_GATEWAY_AUTH_FAILURE_MESSAGE = 'Vigthoria Gate way user authentification failed. Please log out and login again.';
function resolveRequestedCommand(argv) {
    for (let i = 2; i < argv.length; i++) {
        const token = String(argv[i] || '').trim();
        if (!token || token.startsWith('-'))
            continue;
        return token;
    }
    return '';
}
function isAuthProtectedCommand(command) {
    const protectedCommands = new Set([
        'chat', 'c', 'chat-resume',
        'agent', 'a', 'operator', 'op',
        'edit', 'e', 'generate', 'g', 'explain', 'x', 'fix', 'f', 'review', 'r',
        'workflow', 'flow', 'hub', 'marketplace', 'deploy', 'host', 'preview', 'device',
        'legion', 'history', 'runs', 'replay', 'fork', 'cancel', 'background', 'bg',
        'repo', 'repository',
    ]);
    return protectedCommands.has(command);
}
async function enforceGatewayAuthSession(config, logger, jsonOutputRequested) {
    if (isLocalTestfarmMode()) {
        return true;
    }
    if (!config.isAuthenticated()) {
        return true;
    }
    const explicitEnvToken = Boolean(process.env.VIGTHORIA_TOKEN || process.env.VIGTHORIA_AUTH_TOKEN);
    // Offline mode disables every outbound preflight call.
    if (isOfflineMode()) {
        return true;
    }
    // Short-lived cache so back-to-back CLI invocations don't re-probe. Never use
    // a cached success when an explicit env token overrides the stored session.
    if (!explicitEnvToken) {
        const cached = readGatewayPreflightCache();
        if (cached === true) {
            return true;
        }
    }
    const api = new APIClient(config, logger);
    try {
        const tokenCheck = await api.validateToken();
        if (!tokenCheck.valid) {
            writeGatewayPreflightCache(false);
            if (jsonOutputRequested) {
                process.exitCode = 1;
                console.log(JSON.stringify({ success: false, error: VIGTHORIA_GATEWAY_AUTH_FAILURE_MESSAGE }, null, 2));
            }
            else {
                console.log(chalk.red(VIGTHORIA_GATEWAY_AUTH_FAILURE_MESSAGE));
            }
            return false;
        }
        writeGatewayPreflightCache(true);
        return true;
    }
    catch {
        if (explicitEnvToken) {
            writeGatewayPreflightCache(false);
            if (jsonOutputRequested) {
                process.exitCode = 1;
                console.log(JSON.stringify({ success: false, error: VIGTHORIA_GATEWAY_AUTH_FAILURE_MESSAGE }, null, 2));
            }
            else {
                console.log(chalk.red(VIGTHORIA_GATEWAY_AUTH_FAILURE_MESSAGE));
            }
            return false;
        }
        // Network or transient backend outages should not be misclassified as auth failure.
        return true;
    }
    finally {
        api.destroy();
    }
}
function scrubMessageForUser(message) {
    try {
        return sanitizeUserFacingErrorText(message) || message;
    }
    catch {
        return message;
    }
}
function normalizeCliError(error) {
    if (error instanceof Error) {
        const extended = error;
        const responseMessage = typeof extended.response?.data?.error === 'string'
            ? extended.response.data.error
            : typeof extended.response?.data?.message === 'string'
                ? extended.response.data.message
                : undefined;
        const rawMessage = responseMessage || extended.message || 'An unexpected CLI error occurred.';
        // Purely local, client-side errors (e.g. "this config path doesn't exist
        // on YOUR machine") can legitimately mention local paths that happen to
        // look like internal server paths (e.g. `/var/www/...`-style directories
        // the user copied/typed themselves). Scrubbing those makes an otherwise
        // actionable message unreadable, so commands that construct their own
        // local filesystem errors can opt out via `skipPathScrub`.
        return {
            message: extended.skipPathScrub ? rawMessage : scrubMessageForUser(rawMessage),
            code: extended.code,
            status: extended.status || extended.statusCode || extended.response?.status,
            details: extended.details || extended.response?.data,
        };
    }
    if (error && typeof error === 'object') {
        const value = error;
        const rawMessage = typeof value.message === 'string' && value.message.trim() ? value.message : 'An unexpected CLI error occurred.';
        return {
            message: scrubMessageForUser(rawMessage),
            code: typeof value.code === 'string' || typeof value.code === 'number' ? value.code : undefined,
            status: typeof value.status === 'number' ? value.status : undefined,
            details: value.details,
        };
    }
    const rawMessage = typeof error === 'string' && error.trim() ? error : 'An unexpected CLI error occurred.';
    return {
        message: scrubMessageForUser(rawMessage),
    };
}
function formatCliError(error, jsonOutputRequested = false) {
    const normalized = normalizeCliError(error);
    if (jsonOutputRequested) {
        return JSON.stringify({ success: false, error: normalized.message, code: normalized.code, status: normalized.status, details: normalized.details }, null, 2);
    }
    const parts = [chalk.red('Error:'), normalized.message];
    if (normalized.code)
        parts.push(chalk.gray(`[${normalized.code}]`));
    if (normalized.status)
        parts.push(chalk.gray(`(HTTP ${normalized.status})`));
    return parts.join(' ');
}
function reportCliError(error, jsonOutputRequested = false) {
    const output = formatCliError(error, jsonOutputRequested);
    if (jsonOutputRequested) {
        console.log(output);
    }
    else {
        console.error(output);
    }
}
function handleFatalCliError(error, jsonOutputRequested = false) {
    reportCliError(error, jsonOutputRequested);
    process.exitCode = 1;
}
let errorHandlersInstalled = false;
export function setupErrorHandlers() {
    if (errorHandlersInstalled) {
        return;
    }
    errorHandlersInstalled = true;
    process.on('unhandledRejection', (reason) => {
        const rejection = reason instanceof Error ? reason : new Error(String(reason || 'Unhandled promise rejection'));
        handleFatalCliError(rejection, process.argv.includes('--json'));
        process.exit(1);
    });
    process.on('uncaughtException', (error) => {
        handleFatalCliError(error, process.argv.includes('--json'));
    });
    process.on('warning', (warning) => {
        if (process.env.VIGTHORIA_DEBUG === '1') {
            reportCliError(warning, process.argv.includes('--json'));
        }
    });
}
export async function main(args) {
    const program = new Command();
    const config = new Config();
    const logger = new Logger();
    const invokedBinaryName = getInvokedBinaryName();
    const argv = [...args];
    const firstArg = argv[2];
    const jsonOutputRequested = argv.includes('--json');
    const directPromptRequested = argv.includes('--prompt') || argv.includes('-P');
    const helpOrVersionRequested = argv.some((token) => token === '--help' || token === '-h' || token === '--version' || token === '-V' ||
        token === 'help' || token === 'version');
    const isLegionCortexRequest = invokedBinaryName === 'vigthoria' && argv[2] === 'legion' && argv.includes('--cortex');
    if (invokedBinaryName === 'vigthoria-chat') {
        const knownCommands = new Set([
            'chat', 'chat-resume', 'agent', 'edit', 'generate', 'explain', 'fix', 'review', 'cancel', 'background', 'bg',
            'hub', 'repo', 'deploy', 'operator', 'workflow', 'flow', 'device', 'security', 'vsec', 'login', 'logout', 'status', 'config', 'update',
            '--help', '-h', '--version', '-V', 'help', 'version',
        ]);
        if (!firstArg || firstArg.startsWith('-') || !knownCommands.has(firstArg)) {
            argv.splice(2, 0, 'chat');
        }
    }
    const requestedCommand = resolveRequestedCommand(argv);
    // Skip gateway JWT auth when running on-server with a service key (e.g., Cortex on-box).
    // The service key is checked by Hyper Loop directly — no user session needed.
    const hasServiceKey = !!(process.env.HYPERLOOP_SERVICE_KEY ||
        process.env.V3_SERVICE_KEY);
    if (!hasServiceKey && !isLegionCortexRequest && requestedCommand && isAuthProtectedCommand(requestedCommand)) {
        const authOk = await enforceGatewayAuthSession(config, logger, jsonOutputRequested);
        if (!authOk) {
            process.exitCode = 1;
            return;
        }
    }
    if (process.env.VIGTHORIA_NO_BANNER !== '1' &&
        !jsonOutputRequested &&
        !directPromptRequested &&
        !helpOrVersionRequested) {
        // process.stdout.columns is not always a reliable indicator of how
        // many columns actually render visually (seen mismatching badly in some
        // embedded/split-pane terminal hosts on Windows) -- cap the box at a
        // conservative width so it never overflows even when the reported
        // column count is larger than the real usable width.
        const terminalWidth = Math.max(36, Number(process.stdout.columns || 80));
        const boxWidth = Math.max(34, Math.min(44, terminalWidth - 8));
        const innerWidth = boxWidth;
        const fit = (text) => {
            const clean = String(text || '').replace(/\s+/g, ' ').trim();
            return clean.length > innerWidth ? `${clean.slice(0, Math.max(1, innerWidth - 1))}…` : clean;
        };
        const center = (text, colour = (value) => value) => {
            const fitted = fit(text);
            const left = Math.max(0, Math.floor((innerWidth - fitted.length) / 2));
            const right = Math.max(0, innerWidth - fitted.length - left);
            return chalk.cyan(CH.dV) + ' '.repeat(left) + colour(fitted) + ' '.repeat(right) + chalk.cyan(CH.dV);
        };
        const titleLine = boxWidth < 48 ? 'VIGTHORIA CLI' : 'VIGTHORIA CLI - AI Coding Assistant';
        const subtitleLine = boxWidth < 48 ? 'AI Coding Assistant' : `Version ${VERSION}`;
        const versionLine = boxWidth < 48 ? `Version ${VERSION}` : '';
        console.log(chalk.cyan(CH.dTl + CH.dH.repeat(boxWidth) + CH.dTr));
        console.log(center(''));
        console.log(center(titleLine, (value) => chalk.bold.white(value)));
        console.log(center(subtitleLine, (value) => chalk.gray(value)));
        if (versionLine) {
            console.log(center(versionLine, (value) => chalk.gray(value)));
        }
        console.log(center(''));
        console.log(chalk.cyan(CH.dBl + CH.dH.repeat(boxWidth) + CH.dBr));
        console.log();
    }
    // Check for updates in background (don't wait).  Skip for JSON / direct
    // prompt / help / version invocations to keep them deterministic.
    if (!isUpdateCheckSuppressed() &&
        !jsonOutputRequested &&
        !directPromptRequested &&
        !helpOrVersionRequested) {
        void checkForUpdatesQuietly();
    }
    program
        .name(invokedBinaryName === 'vigthoria-chat' ? 'vigthoria-chat' : 'vigthoria')
        .description('AI-powered terminal coding assistant for Vigthoria Coder subscribers')
        .version(VERSION);
    // Chat command - Interactive mode (Agent mode is default for best results)
    program
        .command('chat')
        .alias('c')
        .description('Start interactive chat with Vigthoria AI')
        .option('-m, --model <model>', 'Select AI model (agent, code, code-35b, code-9b, balanced, balanced-4b, cloud, ultra)')
        .option('-p, --project <path>', 'Set project context path')
        .option('--new-project [name]', 'Create or use a managed local workspace folder when no --project path is given')
        .option('-a, --agent', 'Enable agentic mode (default: true for best quality)', true)
        .option('--no-agent', 'Disable agentic mode (simple chat only)')
        .option('-r, --resume', 'Resume last session for this project', false)
        .option('--prompt <text>', 'Run a single prompt directly and exit')
        .option('-w, --workflow <selector>', 'Route prompts through a named or explicit VigFlow workflow target')
        .option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
        .option('--auto-approve', 'Auto-approve agent actions (dangerous!)', false)
        .option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
        .action(async (options) => {
        const chat = new ChatCommand(config, logger, program);
        await chat.run({
            model: options.model,
            project: options.project,
            projectProvided: typeof options.project === 'string' && options.project.trim().length > 0,
            newProject: options.newProject,
            agent: options.agent,
            workflow: options.workflow,
            json: options.json,
            autoApprove: options.autoApprove,
            resume: options.resume,
            prompt: options.prompt,
            bridge: options.bridge,
        });
    });
    program
        .command('chat-resume')
        .description('Resume the latest chat session for the current or specified project')
        .option('-m, --model <model>', 'Select AI model (agent, code, code-35b, code-9b, balanced, balanced-4b, cloud, ultra)')
        .option('-p, --project <path>', 'Set project context path')
        .option('--new-project [name]', 'Create or use a managed local workspace folder when no --project path is given')
        .option('-a, --agent', 'Enable agentic mode (default: true for best quality)', true)
        .option('--no-agent', 'Disable agentic mode (simple chat only)')
        .option('--prompt <text>', 'Run a single prompt directly and exit after resuming context')
        .option('-w, --workflow <selector>', 'Route prompts through a named or explicit VigFlow workflow target')
        .option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
        .option('--auto-approve', 'Auto-approve agent actions (dangerous!)', false)
        .option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
        .action(async (options) => {
        const chat = new ChatCommand(config, logger, program);
        await chat.run({
            model: options.model,
            project: options.project,
            projectProvided: typeof options.project === 'string' && options.project.trim().length > 0,
            newProject: options.newProject,
            agent: options.agent,
            workflow: options.workflow,
            json: options.json,
            autoApprove: options.autoApprove,
            resume: true,
            prompt: options.prompt,
            bridge: options.bridge,
        });
    });
    // Agent command - Agentic mode (Vigthoria Autonomous)
    // Uses Vigthoria v3 Code 35B or Vigthoria Cloud for complex tasks
    program
        .command('agent')
        .alias('a')
        .description('Start agentic mode - AI can read/write files, run commands')
        .option('-m, --model <model>', 'Select AI model (agent, code, cloud, ultra)')
        .option('-p, --project <path>', 'Set project context path')
        .option('--new-project [name]', 'Create or use a managed local workspace folder when no --project path is given')
        .option('--prompt <text>', 'Run a single agent prompt directly and exit')
        .option('-w, --workflow <selector>', 'Run the prompt through a named or explicit VigFlow workflow target')
        .option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
        .option('--retry', 'Retry failed tasks from the last agent run in this workspace session', false)
        .option('--continue', 'Continue unfinished tasks from the last agent run in this workspace session', false)
        .option('--auto-approve', 'Auto-approve all actions (dangerous!)', false)
        .option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
        .action(async (options) => {
        const chat = new ChatCommand(config, logger, program);
        await chat.run({
            model: options.model,
            project: options.project,
            projectProvided: typeof options.project === 'string' && options.project.trim().length > 0,
            newProject: options.newProject,
            agent: true,
            operator: false,
            workflow: options.workflow,
            json: options.json,
            autoApprove: options.autoApprove,
            prompt: options.prompt,
            bridge: options.bridge,
            retry: options.retry,
            continue: options.continue,
        });
    });
    program
        .command('operator')
        .alias('op')
        .description('Start BMAD operator mode for infrastructure and system workflows')
        .option('-m, --model <model>', 'Select operator model (code, agent, cloud)')
        .option('-p, --project <path>', 'Set project context path')
        .option('--new-project [name]', 'Create or use a managed local workspace folder when no --project path is given')
        .option('--prompt <text>', 'Run a single operator prompt directly and exit')
        .option('-w, --workflow <selector>', 'Run the prompt through a named or explicit VigFlow workflow target')
        .option('--save-plan', 'Save the completed BMAD plan into VigFlow for rerun and audit', false)
        .option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
        .option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
        .action(async (options) => {
        const chat = new ChatCommand(config, logger, program);
        await chat.run({
            model: options.model,
            project: options.project,
            projectProvided: typeof options.project === 'string' && options.project.trim().length > 0,
            newProject: options.newProject,
            agent: false,
            operator: true,
            workflow: options.workflow,
            savePlan: options.savePlan,
            json: options.json,
            prompt: options.prompt,
            bridge: options.bridge,
        });
    });
    new V4Command(config, logger).register(program);
    program
        .command('v4-menu')
        .description('Internal: interactive V3/V4 agent + provider picker used by the V4 Operating Agent launcher')
        .option('--default-agent <agent>', 'v3 | v4', 'v3')
        .option('--default-provider <provider>', 'cloud | v3_local | byok', 'cloud')
        .option('--byok-api-key <key>', 'Existing BYOK api key', '')
        .option('--byok-base-url <url>', 'Existing BYOK base url', '')
        .option('--byok-model <name>', 'Existing BYOK model', '')
        .requiredOption('--out-file <path>', 'Write JSON selection result to this file')
        .action(async (options) => {
        await runV4Menu({
            defaultAgent: options.defaultAgent,
            defaultProvider: options.defaultProvider,
            byokApiKey: options.byokApiKey,
            byokBaseUrl: options.byokBaseUrl,
            byokModel: options.byokModel,
            outFile: options.outFile,
        });
    });
    program
        .command('bridge')
        .description('Inspect local DevTools Bridge availability for browser debugging tasks')
        .command('status')
        .description('Show live DevTools Bridge status')
        .action(async () => {
        const bridge = new BridgeCommand(config, logger);
        await bridge.status();
    });
    const deviceCommand = program
        .command('device')
        .alias('adb')
        .description('Android Developer Bridge commands via local ADB');
    deviceCommand
        .command('status')
        .description('Show ADB availability and connected Android devices')
        .option('--json', 'Emit JSON output', false)
        .action(async (options) => {
        const device = new DeviceCommand(config, logger);
        await device.status(options);
    });
    deviceCommand
        .command('list')
        .description('List connected Android devices')
        .option('--json', 'Emit JSON output', false)
        .action(async (options) => {
        const device = new DeviceCommand(config, logger);
        await device.list(options);
    });
    deviceCommand
        .command('screenshot')
        .description('Capture a screenshot from an Android device')
        .option('-d, --device <id>', 'ADB device id')
        .option('-o, --output <path>', 'Output PNG path')
        .action(async (options) => {
        const device = new DeviceCommand(config, logger);
        await device.screenshot(options);
    });
    deviceCommand
        .command('install <apk>')
        .description('Install or update an APK on an Android device')
        .option('-d, --device <id>', 'ADB device id')
        .option('--json', 'Emit JSON output', false)
        .action(async (apk, options) => {
        const device = new DeviceCommand(config, logger);
        await device.install(apk, options);
    });
    deviceCommand
        .command('launch <package>')
        .description('Launch an Android app by package name')
        .option('-d, --device <id>', 'ADB device id')
        .option('-a, --activity <activity>', 'Activity class, for example .MainActivity')
        .option('--json', 'Emit JSON output', false)
        .action(async (packageName, options) => {
        const device = new DeviceCommand(config, logger);
        await device.launch(packageName, options);
    });
    deviceCommand
        .command('logs')
        .description('Read Android logcat output')
        .option('-d, --device <id>', 'ADB device id')
        .option('-n, --lines <count>', 'Number of log lines for snapshot mode', '250')
        .option('-f, --follow', 'Follow logcat until interrupted', false)
        .option('--json', 'Emit JSON output for snapshot mode', false)
        .action(async (options) => {
        const device = new DeviceCommand(config, logger);
        await device.logs(options);
    });
    deviceCommand
        .command('tcpip')
        .description('Enable wireless ADB tcpip mode on the selected USB-connected device')
        .option('-d, --device <id>', 'ADB device id')
        .option('-p, --port <port>', 'Wireless ADB port', '5555')
        .option('--json', 'Emit JSON output', false)
        .action(async (options) => {
        const device = new DeviceCommand(config, logger);
        await device.tcpip(options);
    });
    deviceCommand
        .command('connect <address>')
        .description('Connect to a wireless ADB device, for example 192.168.1.30:5555')
        .option('--json', 'Emit JSON output', false)
        .action(async (address, options) => {
        const device = new DeviceCommand(config, logger);
        await device.connect(address, options);
    });
    deviceCommand
        .command('disconnect [address]')
        .description('Disconnect a wireless ADB device')
        .option('--json', 'Emit JSON output', false)
        .action(async (address, options) => {
        const device = new DeviceCommand(config, logger);
        await device.disconnect(address, options);
    });
    deviceCommand.action(async () => {
        const device = new DeviceCommand(config, logger);
        await device.status({});
    });
    // Security command group - Security DevOps scans and fix plans
    const securityCommand = program
        .command('security')
        .alias('vsec')
        .description('Run security scans, scores, and fix plans via Vigthoria MCP security tools');
    securityCommand
        .command('scan')
        .description('Scan project for security issues')
        .option('-d, --dir <path>', 'Directory to scan (default: current directory)')
        .option('--json', 'Emit JSON output', false)
        .action(async (options) => {
        const security = new SecurityCommand(config, logger);
        await security.scan({ dir: options.dir, json: options.json });
    });
    securityCommand
        .command('score')
        .description('Calculate project security score')
        .option('-d, --dir <path>', 'Directory to score (default: current directory)')
        .option('--json', 'Emit JSON output', false)
        .action(async (options) => {
        const security = new SecurityCommand(config, logger);
        await security.score({ dir: options.dir, json: options.json });
    });
    securityCommand
        .command('fix')
        .description('Generate security fix plan')
        .option('-d, --dir <path>', 'Directory to inspect (default: current directory)')
        .option('-i, --issue-id <id>', 'Single issue id to target')
        .option('--apply', 'Request auto-apply mode (safe mode still requires explicit patching)', false)
        .option('--json', 'Emit JSON output', false)
        .action(async (options) => {
        const security = new SecurityCommand(config, logger);
        await security.fix({ dir: options.dir, issueId: options.issueId, apply: options.apply, json: options.json });
    });
    // Edit command - Edit files with AI
    program
        .command('edit <file>')
        .alias('e')
        .description('Edit a file with AI assistance')
        .option('-i, --instruction <text>', 'Editing instruction')
        .option('-m, --model <model>', 'Select AI model', 'code')
        .option('--apply', 'Automatically apply changes without confirmation', false)
        .action(async (file, options) => {
        const edit = new EditCommand(config, logger);
        await edit.run(file, options);
    });
    // Generate command - Generate code
    program
        .command('generate <description>')
        .alias('g')
        .description('Generate code from description')
        .option('-l, --language <lang>', 'Target language (auto-detected from description, or specify: javascript, typescript, python, html, etc.)')
        .option('-o, --output <file>', 'Output file path')
        .option('-m, --model <model>', 'Select AI model', 'code')
        .option('-p, --pro', 'Senior Developer Mode: plan, generate, quality check (recommended)', false)
        .action(async (description, options) => {
        const generate = new GenerateCommand(config, logger);
        await generate.run(description, options);
    });
    // Explain command - Explain code
    program
        .command('explain <file>')
        .alias('x')
        .description('Explain code in a file')
        .option('-l, --lines <range>', 'Line range (e.g., 1-50)')
        .option('-d, --detail <level>', 'Detail level (brief, normal, detailed)', 'normal')
        .action(async (file, options) => {
        const explain = new ExplainCommand(config, logger);
        await explain.run(file, options);
    });
    // Fix command - Fix code issues
    program
        .command('fix [file]')
        .alias('f')
        .description('Fix issues in a file')
        .option('-t, --type <type>', 'Fix type (bugs, style, security, performance)', 'bugs')
        .option('--apply', 'Automatically apply fixes', false)
        .action(async (file, options) => {
        if (!file) {
            logger.error('Usage: vigthoria fix <file> [--type bugs|style|security|performance] [--apply]');
            process.exitCode = 1;
            return;
        }
        const edit = new EditCommand(config, logger);
        await edit.fix(file, options);
    });
    // Review command - Code review
    program
        .command('review <file>')
        .alias('r')
        .description('Review code quality')
        .option('-f, --format <format>', 'Output format (text, json, markdown)', 'text')
        .action(async (file, options) => {
        const review = new ReviewCommand(config, logger);
        await review.run(file, options);
    });
    const workflowCommand = program
        .command('workflow')
        .alias('flow')
        .description('List, instantiate, and run repeatable VigFlow workflows');
    workflowCommand
        .command('templates')
        .alias('catalog')
        .description('List available VigFlow templates')
        .option('-c, --category <category>', 'Filter templates by category')
        .option('-s, --search <query>', 'Search template names, descriptions, and tags')
        .option('--json', 'Emit machine-readable JSON output', false)
        .action(async (options) => {
        const workflow = new WorkflowCommand(config, logger);
        await workflow.templates(options);
    });
    workflowCommand
        .command('list')
        .alias('ls')
        .description('List workflows created for the current account')
        .option('--json', 'Emit machine-readable JSON output', false)
        .action(async (options) => {
        const workflow = new WorkflowCommand(config, logger);
        await workflow.list(options);
    });
    workflowCommand
        .command('use-template <templateId>')
        .description('Create a workflow from a built-in or saved template')
        .option('-n, --name <name>', 'Override the workflow name')
        .option('-v, --variables <json>', 'Template variables as a JSON object')
        .option('--json', 'Emit machine-readable JSON output', false)
        .action(async (templateId, options) => {
        const workflow = new WorkflowCommand(config, logger);
        await workflow.useTemplate(templateId, options);
    });
    workflowCommand
        .command('run <workflowId>')
        .description('Run a workflow immediately')
        .option('-d, --data <json>', 'Execution input data as a JSON object')
        .option('--no-brain', 'Do not attach local Project Brain context to this workflow run')
        .option('--json', 'Emit machine-readable JSON output', false)
        .action(async (workflowId, options) => {
        const workflow = new WorkflowCommand(config, logger);
        await workflow.run(workflowId, options);
    });
    workflowCommand
        .command('status <executionId>')
        .description('Get the current or final status of a workflow execution')
        .option('--no-brain', 'Do not remember this workflow status in local Project Brain')
        .option('--json', 'Emit machine-readable JSON output', false)
        .action(async (executionId, options) => {
        const workflow = new WorkflowCommand(config, logger);
        await workflow.status(executionId, options);
    });
    workflowCommand.action(async () => {
        const workflow = new WorkflowCommand(config, logger);
        await workflow.templates({});
    });
    // ==================== HUB / MARKETPLACE COMMANDS ====================
    // Hub command - Discover and activate API modules
    const hubCommand = program
        .command('hub')
        .alias('marketplace')
        .description('Discover, search, and activate Vigthoria API modules');
    hubCommand
        .command('discover')
        .alias('d')
        .description('Interactive module discovery - find the right APIs for your project')
        .action(async () => {
        const hub = new HubCommand(config, logger);
        await hub.discover();
    });
    hubCommand
        .command('list')
        .alias('ls')
        .description('List all available API modules')
        .option('-c, --category <category>', 'Filter by category (payments, communication, ai, creative, media)')
        .action(async (options) => {
        const hub = new HubCommand(config, logger);
        await hub.list(options);
    });
    hubCommand
        .command('search <query>')
        .alias('find')
        .description('Semantic search for modules (e.g., "generate background music for my app")')
        .action(async (query) => {
        const hub = new HubCommand(config, logger);
        await hub.search(query);
    });
    hubCommand
        .command('activate <module>')
        .alias('enable')
        .description('Activate a module for your API key (enables pay-as-you-go)')
        .action(async (module) => {
        const hub = new HubCommand(config, logger);
        await hub.activate(module);
    });
    hubCommand
        .command('active')
        .description('Show your currently active modules')
        .action(async () => {
        const hub = new HubCommand(config, logger);
        await hub.active();
    });
    hubCommand
        .command('info <module>')
        .alias('details')
        .description('Get detailed information about a module')
        .action(async (module) => {
        const hub = new HubCommand(config, logger);
        await hub.info(module);
    });
    // Default hub action shows discover
    hubCommand.action(async () => {
        const hub = new HubCommand(config, logger);
        await hub.discover();
    });
    const musicCommand = program
        .command('music')
        .alias('audio')
        .description('Generate songs with Vigthoria Music AI / ACE-Step');
    musicCommand
        .command('generate [prompt]')
        .alias('g')
        .description('Queue full-song generation and return a task id')
        .option('--lyrics <text>', 'Provide fixed lyrics instead of auto-writing lyrics')
        .option('--duration <seconds>', 'Song duration in seconds', '120')
        .option('--genre <genre>', 'Music genre', 'pop')
        .option('--language <code>', 'Vocal language', 'en')
        .option('--voice-type <type>', 'Voice type (female, male, mixed)', 'female')
        .option('--style-tags <tags>', 'Additional style tags')
        .option('--voice <path>', 'Upload a local voice reference for cloning')
        .option('--wait', 'Poll until the task reaches a terminal state', false)
        .option('--poll-interval <seconds>', 'Polling interval when --wait is used', '5')
        .option('--json', 'Emit machine-readable JSON output', false)
        .action(async (prompt, options) => {
        const music = new MusicCommand(config, logger);
        await music.generate(prompt, options);
    });
    musicCommand
        .command('status <taskId>')
        .description('Check a queued music generation task')
        .option('--json', 'Emit machine-readable JSON output', false)
        .action(async (taskId, options) => {
        const music = new MusicCommand(config, logger);
        await music.status(taskId, options);
    });
    // ==================== REPO COMMANDS ====================
    // Repo command - Push/Pull projects to/from Vigthoria Community Repository
    const repoCommand = program
        .command('repo')
        .alias('repository')
        .description('Push and pull projects to/from your Vigthoria Community Repository');
    repoCommand
        .command('push [path]')
        .alias('upload')
        .description('Push current or specified project to Vigthoria Community Repository')
        .option('-n, --name <projectName>', 'Project name override for the remote repo')
        .option('-v, --visibility <type>', 'Set visibility (private, restricted, public)', 'private')
        .option('-d, --description <text>', 'Project description')
        .option('-f, --force', 'Overwrite existing project', false)
        .option('-y, --yes', 'Run non-interactively with provided/default values', false)
        .option('--retry <reviewId>', 'Link this corrected push to a repository security review')
        .option('--open-in <engine>', 'After push, open project in engine: shop, visual, game')
        .option('--browser', 'Open result URL in default browser', false)
        .action(async (pathArg, options) => {
        const repo = new RepoCommand(config, logger);
        await repo.push({
            path: pathArg,
            name: options.name,
            visibility: options.visibility,
            description: options.description,
            force: options.force,
            yes: options.yes,
            retry: options.retry
        });
        if (options.openIn) {
            const engine = options.openIn;
            if (!['shop', 'visual', 'game'].includes(engine)) {
                logger.warn(`Unknown engine "${engine}". Use: shop, visual, game`);
            }
            else {
                await repo.openIn(engine, options.name || undefined, { browser: options.browser });
            }
        }
    });
    repoCommand
        .command('review [reviewId]')
        .description('Show repository security review status, findings, and retry guidance')
        .option('--json', 'Emit machine-readable JSON output', false)
        .action(async (reviewId, options) => {
        const repo = new RepoCommand(config, logger);
        await repo.review(reviewId, { json: options.json });
    });
    repoCommand
        .command('pull <name>')
        .alias('download')
        .description('Pull a project from your Vigthoria Community Repository')
        .option('-o, --output <path>', 'Output directory path')
        .option('-f, --force', 'Overwrite existing directory', false)
        .action(async (name, options) => {
        const repo = new RepoCommand(config, logger);
        await repo.pull(name, {
            output: options.output,
            force: options.force
        });
    });
    repoCommand
        .command('list')
        .alias('ls')
        .description('List all your projects in Vigthoria Community Repository')
        .option('-v, --visibility <type>', 'Filter by visibility (private, restricted, public)')
        .action(async (options) => {
        const repo = new RepoCommand(config, logger);
        await repo.list({ visibility: options.visibility });
    });
    repoCommand
        .command('status')
        .description('Show sync status of current project')
        .action(async () => {
        const repo = new RepoCommand(config, logger);
        await repo.status();
    });
    repoCommand
        .command('share <name>')
        .description('Generate a shareable link for a project')
        .option('-e, --expires <duration>', 'Link expiration (e.g., 7d, 24h, 30m)', '7d')
        .action(async (name, options) => {
        const repo = new RepoCommand(config, logger);
        await repo.share(name, { expires: options.expires });
    });
    repoCommand
        .command('delete <name>')
        .alias('rm')
        .description('Remove a project from your Vigthoria Community Repository')
        .action(async (name) => {
        const repo = new RepoCommand(config, logger);
        await repo.delete(name);
    });
    repoCommand
        .command('clone <url>')
        .description('Clone a public project from Vigthoria Community')
        .option('-o, --output <path>', 'Output directory path')
        .option('-f, --force', 'Overwrite existing directory', false)
        .action(async (url, options) => {
        const repo = new RepoCommand(config, logger);
        await repo.clone(url, {
            output: options.output,
            force: options.force
        });
    });
    repoCommand
        .command('open-in <engine> [projectName]')
        .description('Open a Vigthoria Community Repository project in the Shop Engine, Visual Editor, or Gaming Engine')
        .option('--browser', 'Open result URL in default browser', false)
        .option('--shop-id <id>', 'Target shop ID (for shop engine)', 'default')
        .addHelpText('after', `
Examples:
  vigthoria repo open-in shop my-store
  vigthoria repo open-in visual my-website
  vigthoria repo open-in game my-game --browser`)
        .action(async (engine, projectName, options) => {
        if (!['shop', 'visual', 'game'].includes(engine)) {
            logger.error(`Unknown engine "${engine}". Valid options: shop, visual, game`);
            process.exit(1);
        }
        const repo = new RepoCommand(config, logger);
        await repo.openIn(engine, projectName, {
            browser: options.browser,
            shopId: options.shopId
        });
    });
    // Default repo action shows help with available subcommands
    repoCommand.action(() => {
        repoCommand.outputHelp();
    });
    // ==================== BACKGROUND AGENT JOBS ====================
    const backgroundCommand = program
        .command('background')
        .alias('bg')
        .description('Run and manage detached Vigthoria Agent jobs');
    backgroundCommand
        .command('start <prompt...>')
        .description('Start an Agent job in the background and return immediately')
        .option('--workspace <path>', 'Local workspace path', process.cwd())
        .option('--json', 'Emit JSON output', false)
        .action(async (prompt, options) => {
        const bg = new BackgroundCommand(config, logger);
        await bg.start(prompt, options);
    });
    backgroundCommand
        .command('list')
        .alias('ls')
        .description('List recent background jobs')
        .option('--limit <n>', 'Maximum jobs to show', '20')
        .option('--json', 'Emit JSON output', false)
        .action(async (options) => {
        const bg = new BackgroundCommand(config, logger);
        await bg.list({ ...options, limit: Number(options.limit) || 20 });
    });
    backgroundCommand
        .command('status <jobId>')
        .description('Show background job status')
        .option('--json', 'Emit JSON output', false)
        .action(async (jobId, options) => {
        const bg = new BackgroundCommand(config, logger);
        await bg.status(jobId, options);
    });
    backgroundCommand
        .command('apply <jobId>')
        .description('Apply completed background job file changes to the local workspace')
        .option('--workspace <path>', 'Local workspace path', process.cwd())
        .option('--json', 'Emit JSON output', false)
        .action(async (jobId, options) => {
        const bg = new BackgroundCommand(config, logger);
        await bg.apply(jobId, options);
    });
    backgroundCommand
        .command('cancel <jobId>')
        .description('Cancel a running background job')
        .option('--json', 'Emit JSON output', false)
        .action(async (jobId, options) => {
        const bg = new BackgroundCommand(config, logger);
        await bg.cancel(jobId, options);
    });
    backgroundCommand.action(() => {
        backgroundCommand.outputHelp();
    });
    // ==================== DEPLOY COMMANDS ====================
    // Deploy command - Host projects on Vigthoria
    const deployCommand = program
        .command('deploy')
        .alias('host')
        .description('Deploy and host your project on Vigthoria infrastructure');
    deployCommand
        .command('preview')
        .description('Deploy to free preview URL')
        .option('-p, --project <path>', 'Project directory path', process.cwd())
        .action(async (options) => {
        const deploy = new DeployCommand(config, logger);
        await deploy.deployToPreview(options.project);
    });
    deployCommand
        .command('subdomain <name>')
        .description('Deploy to yourname.vigthoria.io')
        .option('-p, --project <path>', 'Project directory path', process.cwd())
        .action(async (name, options) => {
        const deploy = new DeployCommand(config, logger);
        await deploy.deployToSubdomain(name, options.project);
    });
    deployCommand
        .command('custom <domain>')
        .description('Deploy to your custom domain')
        .option('-p, --project <path>', 'Project directory path', process.cwd())
        .action(async (domain, options) => {
        const deploy = new DeployCommand(config, logger);
        await deploy.deployToCustomDomain(domain, options.project);
    });
    deployCommand
        .command('list')
        .alias('ls')
        .description('List all your deployments')
        .action(async () => {
        const deploy = new DeployCommand(config, logger);
        await deploy.list();
    });
    deployCommand
        .command('plans')
        .description('Show hosting plans and pricing')
        .action(async () => {
        const deploy = new DeployCommand(config, logger);
        await deploy.showPlans();
    });
    deployCommand
        .command('status [domain]')
        .description('Check deployment status')
        .action(async (domain) => {
        const deploy = new DeployCommand(config, logger);
        await deploy.status(domain);
    });
    deployCommand
        .command('verify <domain>')
        .description('Verify DNS configuration for custom domain')
        .action(async (domain) => {
        const deploy = new DeployCommand(config, logger);
        await deploy.verify(domain);
    });
    deployCommand
        .command('remove <domain>')
        .alias('rm')
        .description('Remove a deployment')
        .action(async (domain) => {
        const deploy = new DeployCommand(config, logger);
        await deploy.remove(domain);
    });
    // Default deploy action shows interactive wizard
    deployCommand
        .option('-s, --subdomain <name>', 'Deploy to subdomain')
        .option('-d, --domain <domain>', 'Deploy to custom domain')
        .option('-p, --project <path>', 'Project directory path', process.cwd())
        .action(async (options) => {
        const deploy = new DeployCommand(config, logger);
        await deploy.deploy({
            subdomain: options.subdomain,
            domain: options.domain,
            project: options.project
        });
    });
    // ==================== PREVIEW COMMAND ====================
    program
        .command('preview')
        .description('Preview project locally with visual diffs and proof validation')
        .option('-p, --project <path>', 'Project directory path', process.cwd())
        .option('-e, --entry <file>', 'Entry HTML file (auto-detected if omitted)')
        .option('--port <number>', 'Local server port', parseInt)
        .option('--no-open', 'Do not auto-open browser')
        .option('--diff', 'Show consolidated diff of recent agent changes')
        .option('--proof', 'Run Template Service preview gate and persist proof bundle')
        .option('--screenshot', 'Capture screenshot via Puppeteer')
        .action(async (options) => {
        const preview = new PreviewCommand(config, logger);
        await preview.run({
            project: options.project,
            entry: options.entry,
            port: options.port,
            open: options.open,
            diff: options.diff,
            proof: options.proof,
            screenshot: options.screenshot,
        });
    });
    // ==================== GAME COMMAND ====================
    const gameCommand = program.command('game').description('Create, run, and validate Babylon/VGE game projects');
    gameCommand.command('init [name]').description('Create a production-ready client-rendered Babylon/VGE game').option('--engine <engine>', 'Game engine', 'babylon').option('--no-install', 'Create files without installing dependencies').option('--package-manager <manager>', 'npm, pnpm, yarn, or bun').action(async (name, options) => { await new GameCommand(logger).init(name, options); });
    gameCommand.command('run').description('Run the local game development server').option('-p, --project <path>', 'Game project directory', process.cwd()).option('--port <number>', 'Development server port', parseInt).option('--no-open', 'Do not open a browser').option('--package-manager <manager>', 'npm, pnpm, yarn, or bun').action(async (options) => { await new GameCommand(logger).run(options); });
    gameCommand.command('validate').description('Build and validate a Babylon/VGE game project').option('-p, --project <path>', 'Game project directory', process.cwd()).option('--json', 'Print machine-readable validation results').option('--package-manager <manager>', 'npm, pnpm, yarn, or bun').action(async (options) => { await new GameCommand(logger).validate(options); });
    gameCommand.action(() => gameCommand.outputHelp());
    // ==================== LEGION COMMAND ====================
    program
        .command('legion [request]')
        .description('Run parallel tasks via Hyper Loop Legion orchestrator')
        .option('--workers', 'List available Legion workers')
        .option('--status', 'Show Legion infrastructure status')
        .option('--cortex', 'Vigthoria Cortex: maximum intelligence execution')
        .option('--approve', 'Auto-approve Cortex execution prompt')
        .option('--no-approve', 'Require interactive approval before execution')
        .option('--auto-charge', 'Compatibility flag; low balances still require a verified User Hub top-up')
        .option('--plan-only', 'Run Cortex estimator only; do not execute Legion job')
        .option('--force-budget', 'Allow execution when estimated budget exceeds the hard safe-stop ceiling')
        .option('--ignore-preflight', 'Bypass mandatory local preflight checks (no warranty)')
        .option('--speed', 'Enable speed mode (allows optional role skips when convergence is detected)')
        .option('--repro-cmd <command>', 'Local reproduction/preflight command to validate before cloud spend')
        .option('--expect-repro-fail', 'Require repro command to fail (non-zero) before proceeding')
        .option('--models <csv>', 'Comma-separated model IDs to constrain Cortex selection')
        .option('-t, --timeout <seconds>', 'Override Legion execution timeout in seconds (defaults to server policy)')
        .option('-w, --worker <name>', 'Execute a specific worker')
        .option('-p, --project <path>', 'Project directory', process.cwd())
        .action(async (request, options) => {
        const legion = new LegionCommand(config, logger);
        const parsedTimeout = Number.parseInt(String(options.timeout || ''), 10);
        await legion.run(request, {
            workers: options.workers,
            status: options.status,
            cortex: Boolean(options.cortex),
            approve: options.approve,
            noApprove: options.approve === false,
            autoCharge: options.autoCharge,
            planOnly: options.planOnly,
            forceBudget: options.forceBudget,
            ignorePreflight: options.ignorePreflight,
            speed: options.speed,
            reproCmd: options.reproCmd,
            expectReproFail: options.expectReproFail,
            models: options.models,
            timeoutSec: Number.isFinite(parsedTimeout) && parsedTimeout > 0 ? parsedTimeout : undefined,
            worker: options.worker,
            project: options.project,
        });
    });
    // ==================== REPLAY & FORK COMMANDS ====================
    program
        .command('history')
        .alias('runs')
        .description('List recent V3 agent runs')
        .option('-n, --limit <count>', 'Number of runs to show', '20')
        .option('-p, --project <path>', 'Project directory', process.cwd())
        .option('--json', 'Machine-readable JSON output', false)
        .action(async (options) => {
        const history = new HistoryCommand(config, logger);
        await history.run({ limit: parseInt(options.limit, 10) || 20, json: options.json, project: options.project });
    });
    program
        .command('replay <runId>')
        .description('Replay events from a V3 agent run step-by-step')
        .option('-s, --speed <ms>', 'Delay between events in ms', '200')
        .option('-p, --project <path>', 'Project directory', process.cwd())
        .option('--json', 'Machine-readable JSON output', false)
        .action(async (runId, options) => {
        const replay = new ReplayCommand(config, logger);
        await replay.run(runId, { speed: parseInt(options.speed, 10) || 200, json: options.json, project: options.project });
    });
    program
        .command('fork <runId> [message]')
        .description('Fork from an existing V3 agent run with new instructions')
        .option('-e, --event-index <index>', 'Fork from specific event index', '0')
        .option('-p, --project <path>', 'Project directory', process.cwd())
        .option('--json', 'Machine-readable JSON output', false)
        .action(async (runId, message, options) => {
        const fork = new ForkCommand(config, logger);
        await fork.run(runId, message || '', { eventIndex: parseInt(options.eventIndex, 10) || 0, project: options.project, json: options.json });
    });
    program
        .command('cancel [contextId]')
        .description('Cancel an in-flight V3 agent run (by context_id), or use --all to cancel every active run')
        .option('-a, --all', 'Cancel all currently-active runs', false)
        .option('-l, --list', 'List active runs without cancelling', false)
        .option('--json', 'Machine-readable JSON output', false)
        .action(async (contextId, options) => {
        const cancel = new CancelCommand(config, logger);
        await cancel.run(contextId, { all: options.all, list: options.list, json: options.json });
    });
    // ==================== AUTH COMMANDS ====================
    // Auth commands
    program
        .command('login')
        .description('Login to Vigthoria Coder (prompts for credentials when run without flags)')
        .option('-t, --token <token>', 'API token for token-based authentication')
        .option('-e, --email <email>', 'Account email for credential-based login')
        .option('-p, --password <password>', 'Account password for credential-based login')
        .option('--device', 'Use OAuth device flow (requires server support)')
        .action(async (options) => {
        await handleLogin(options);
    });
    program
        .command('logout')
        .description('Logout from Vigthoria Coder')
        .action(async () => {
        await handleLogout(null);
    });
    program
        .command('status')
        .description('Show authentication and subscription status')
        .action(async () => {
        await statusAction();
    });
    registerAuthCommands(program);
    new WalletCommand().register(program);
    program
        .command('doctor')
        .description('Run local Vigthoria CLI diagnostics (no network calls unless --check-api)')
        .option('--check-api', 'Also probe Vigthoria API reachability', false)
        .option('--json', 'Emit machine-readable JSON output', false)
        .action(async (options) => {
        const apiUrl = String(config.get('apiUrl') || 'https://coder.vigthoria.io').replace(/\/$/, '');
        const modelsApiUrl = String(config.get('modelsApiUrl') || 'https://api.vigthoria.io').replace(/\/$/, '');
        const offline = isOfflineMode();
        const updateSuppressed = isUpdateCheckSuppressed();
        const subscription = config.get('subscription') || { plan: null, status: null, expiresAt: null };
        const iosSandbox = isIOSEnvironment();
        const platformSupport = iosSandbox
            ? 'experimental-mobile-terminal-sandbox'
            : process.platform === 'darwin'
                ? 'supported-macos-desktop'
                : process.platform === 'win32' || process.platform === 'linux'
                    ? 'supported-desktop'
                    : 'unsupported';
        const report = {
            cliVersion: VERSION,
            nodeVersion: process.version,
            platform: `${process.platform} ${process.arch}`,
            clientOs: resolveClientOsSlug(),
            platformSupport,
            platformLimitations: iosSandbox
                ? 'Not a native iOS app. Requires an iSH-like Linux terminal with Node.js >=20.19, npm and filesystem access; Workbench and device tooling are unavailable.'
                : null,
            cwd: process.cwd(),
            homeDir: os.homedir(),
            configPath: config.getConfigPath(),
            stateFile: getCliStateFile(),
            apiUrl,
            modelsApiUrl,
            loggedIn: config.isAuthenticated(),
            subscriptionPlan: subscription.plan || null,
            subscriptionStatus: subscription.status || null,
            offlineMode: offline,
            updateCheckSuppressed: updateSuppressed,
            envOverrides: {
                VIGTHORIA_API_URL: process.env.VIGTHORIA_API_URL || null,
                VIGTHORIA_V3_AGENT_URL: process.env.VIGTHORIA_V3_AGENT_URL || null,
                VIGTHORIA_OFFLINE: process.env.VIGTHORIA_OFFLINE || null,
                VIGTHORIA_TOKEN: process.env.VIGTHORIA_TOKEN ? '<set>' : null,
                HYPERLOOP_SERVICE_KEY: process.env.HYPERLOOP_SERVICE_KEY ? '<set>' : null,
                V3_SERVICE_KEY: process.env.V3_SERVICE_KEY ? '<set>' : null,
            },
        };
        if (options.checkApi && !offline) {
            try {
                const probe = await axios.get(`${apiUrl}/api/health`, { timeout: 4000, validateStatus: () => true });
                report.apiHealth = probe.status >= 200 && probe.status < 400 ? 'online' : `status ${probe.status}`;
            }
            catch (error) {
                report.apiHealth = `unreachable (${error.message})`;
            }
            try {
                const probe = await axios.get(`${modelsApiUrl}/health`, { timeout: 4000, validateStatus: () => true });
                report.modelsApiHealth = probe.status >= 200 && probe.status < 400 ? 'online' : `status ${probe.status}`;
            }
            catch (error) {
                report.modelsApiHealth = `unreachable (${error.message})`;
            }
        }
        if (options.json) {
            console.log(JSON.stringify(report, null, 2));
        }
        else {
            console.log(chalk.bold('Vigthoria CLI diagnostics'));
            for (const [key, value] of Object.entries(report)) {
                if (value && typeof value === 'object') {
                    console.log(chalk.gray(`- ${key}:`));
                    for (const [subKey, subVal] of Object.entries(value)) {
                        console.log(chalk.gray(`    - ${subKey}: ${subVal ?? '(none)'}`));
                    }
                }
                else {
                    console.log(chalk.gray(`- ${key}: ${value ?? '(none)'}`));
                }
            }
            if (!options.checkApi) {
                console.log(chalk.gray('\nTip: pass --check-api to verify API reachability.'));
            }
        }
        process.exitCode = 0;
    });
    // Config command
    program
        .command('config')
        .description('Configure Vigthoria CLI settings')
        .option('-s, --set <key=value>', 'Set a configuration value')
        .option('-g, --get <key>', 'Get a configuration value')
        .option('-l, --list', 'List all settings')
        .option('-r, --reset', 'Reset to defaults')
        .action(async (options) => {
        const configCmd = new ConfigCommand(config, logger);
        await configCmd.run(options);
    });
    // Update command - Check for and install updates
    program
        .command('update')
        .alias('upgrade')
        .description('Check for updates and upgrade Vigthoria CLI. Default manifest: https://extension.vigthoria.io/downloads/manifest.json')
        .option('-c, --check', 'Only check for updates, don\'t install')
        .option('-f, --from <target>', 'Install update from npm spec, local .tgz path, or URL')
        .option('-m, --manifest <url>', 'Update manifest URL for server-driven releases')
        .option('--channel <name>', 'Release channel to use from manifest (default: stable)', 'stable')
        .option('--allow-downgrade', 'Allow installing an older version from custom update source')
        .action(async (options) => {
        const updateTarget = typeof options.from === 'string' ? options.from.trim() : '';
        const manifestUrl = typeof options.manifest === 'string' ? options.manifest.trim() : VIGTHORIA_DEFAULT_MANIFEST_URL.trim();
        const channel = typeof options.channel === 'string' ? options.channel.trim() : 'stable';
        const allowDowngrade = !!options.allowDowngrade;
        const gitPackageSpec = 'git+https://market.vigthoria.io/vigthoria/vigthoria-cli.git';
        if (updateTarget) {
            if (!isSafeNpmPackageSpec(updateTarget)) {
                console.error(chalk.red('Refusing to run installer with unsafe package spec.'));
                console.error(chalk.gray('Allowed characters: A-Z a-z 0-9 . _ - / @ : + \\ ='));
                process.exitCode = 1;
                return;
            }
            try {
                if (options.check) {
                    console.log(chalk.cyan(`Update source configured: ${updateTarget}`));
                    console.log(chalk.gray('Run `vigthoria update --from <target>` to install from this source'));
                    return;
                }
                console.log(chalk.cyan(`Installing update from ${updateTarget}...`));
                await installGlobalPackageWithNpm(updateTarget);
                console.log(chalk.green('Update installed successfully'));
                console.log(chalk.gray('Please restart the CLI to use the new version'));
                return;
            }
            catch (error) {
                console.error(chalk.red('Failed to install update from target:'), error.message);
                console.log(chalk.gray(`Try manually: npm install -g ${updateTarget}`));
                process.exitCode = 1;
                return;
            }
        }
        if (isOfflineMode()) {
            console.log(chalk.yellow('Offline mode (VIGTHORIA_OFFLINE=1): skipping update check.'));
            return;
        }
        const currentVersion = VERSION;
        let manifestEntry = null;
        if (manifestUrl) {
            try {
                const explicitLocalManifest = Boolean(options.manifest)
                    && ['localhost', '127.0.0.1', '::1'].includes(new URL(manifestUrl).hostname);
                validateReleaseUrl(manifestUrl, explicitLocalManifest);
                console.log(chalk.cyan(`Checking manifest channel ${channel}...`));
                const response = await axios.get(manifestUrl, {
                    timeout: 10000,
                    maxRedirects: 5,
                    validateStatus: (status) => status >= 200 && status < 300,
                });
                manifestEntry = resolveManifestEntry(response.data || {}, channel);
                if (!manifestEntry?.version || !manifestEntry?.url) {
                    console.log(chalk.yellow(`Manifest has no installable entry for channel ${channel}; will check npm.`));
                    manifestEntry = null;
                }
                else {
                    validateReleaseUrl(manifestEntry.url, explicitLocalManifest);
                    if (!/^[a-f0-9]{64}$/i.test(String(manifestEntry.sha256 || ''))) {
                        console.log(chalk.yellow('Manifest entry has no valid SHA-256 checksum; refusing it and checking npm.'));
                        manifestEntry = null;
                    }
                }
            }
            catch (error) {
                console.log(chalk.yellow(`Manifest check failed: ${error.message}`));
                console.log(chalk.gray('Continuing with npm registry check...'));
            }
        }
        // The release manifest (server-curated, sha256-verified) is the
        // authoritative source of truth for this private CLI. Only fall back
        // to probing the public npm registry when the manifest itself has no
        // usable entry - never let an npm version number override a valid,
        // verified manifest entry (npm install -g against the public registry
        // is slower, unverified, and has previously caused the Workbench's
        // update button to hang for minutes).
        let npmVersion = null;
        if (manifestEntry?.version && manifestEntry?.url) {
            console.log(chalk.gray('Release manifest has a valid entry; skipping public npm registry lookup.'));
        }
        else {
            console.log(chalk.cyan('Checking npm registry...'));
            npmVersion = await fetchNpmLatestVersion();
            if (!npmVersion) {
                console.log(chalk.yellow('Could not read latest version from npm registry.'));
            }
        }
        const effectiveLatest = maxVersion(manifestEntry?.version, npmVersion);
        if (!effectiveLatest) {
            console.error(chalk.red('Unable to determine the latest CLI version from manifest or npm.'));
            process.exitCode = 1;
            return;
        }
        if (!allowDowngrade && compareVersions(effectiveLatest, currentVersion) <= 0) {
            console.log(chalk.green(`You are running the latest version (${currentVersion})`));
            return;
        }
        console.log(chalk.yellow(`Update available: ${currentVersion} -> ${effectiveLatest}`));
        if (manifestEntry?.notes && compareVersions(manifestEntry.version, effectiveLatest) >= 0) {
            console.log(chalk.gray(`   ${manifestEntry.notes}`));
        }
        if (options.check) {
            console.log(chalk.gray('Run `vigthoria update` to install the update'));
            return;
        }
        const manifestIsAuthoritative = Boolean(manifestEntry
            && manifestEntry.url
            && compareVersions(manifestEntry.version, effectiveLatest) >= 0
            && compareVersions(manifestEntry.version, currentVersion) > 0);
        if (manifestIsAuthoritative && manifestEntry) {
            const tmpFile = path.join(os.tmpdir(), `vigthoria-update-${Date.now()}.tgz`);
            try {
                console.log(chalk.cyan(`Downloading release package (${manifestEntry.version})...`));
                await downloadFile(manifestEntry.url, tmpFile);
                const expected = String(manifestEntry.sha256).toLowerCase();
                const actual = sha256File(tmpFile).toLowerCase();
                if (actual !== expected) {
                    console.error(chalk.red('Release checksum verification failed'));
                    console.error(chalk.red(`Expected: ${expected}`));
                    console.error(chalk.red(`Actual:   ${actual}`));
                    process.exitCode = 1;
                    return;
                }
                console.log(chalk.green('Checksum verification passed'));
                console.log(chalk.cyan('Installing update...'));
                await installGlobalPackageWithNpm(tmpFile);
                console.log(chalk.green(`Updated to version ${manifestEntry.version}`));
                console.log(chalk.gray('Please restart the CLI to use the new version'));
                return;
            }
            finally {
                if (fs.existsSync(tmpFile)) {
                    try {
                        fs.unlinkSync(tmpFile);
                    }
                    catch { }
                }
            }
        }
        const npmSpec = npmVersion && compareVersions(npmVersion, currentVersion) > 0
            ? `vigthoria-cli@${npmVersion}`
            : 'vigthoria-cli@latest';
        try {
            console.log(chalk.cyan(`Installing update from npm registry (${npmSpec})...`));
            await installGlobalPackageWithNpm(npmSpec);
            console.log(chalk.green(`Updated to version ${effectiveLatest}`));
            console.log(chalk.gray('Please restart the CLI to use the new version'));
        }
        catch (error) {
            console.error(chalk.red('Failed to install via npm registry:'), error.message);
            try {
                console.log(chalk.cyan('Attempting git package fallback...'));
                await installGlobalPackageWithNpm(gitPackageSpec);
                console.log(chalk.green('Updated via git package fallback'));
                console.log(chalk.gray('Please restart the CLI to use the new version'));
            }
            catch (fallbackError) {
                console.error(chalk.red('Fallback update also failed:'), fallbackError.message);
                console.log(chalk.gray(`Try manually: npm install -g ${npmSpec}`));
                console.log(chalk.gray(`Or: npm install -g ${gitPackageSpec}`));
                process.exitCode = 1;
            }
        }
    });
    // Hyper Loop command alias (maps to legion --status for checklist gate 6.9)
    program
        .command('hyper-loop')
        .description('Hyper Loop Legion orchestrator commands')
        .command('status')
        .description('Show Hyper Loop Legion infrastructure status')
        .action(async () => {
        const legion = new LegionCommand(config, logger);
        await legion.run(undefined, {
            status: true,
            workers: false,
            cortex: false,
            approve: false,
            noApprove: true,
            planOnly: false,
            models: undefined,
            worker: undefined,
            project: process.cwd(),
        });
    });
    // DevTools command alias (maps to bridge for checklist gate 6.12)
    program
        .command('devtools')
        .description('DevTools Bridge commands for browser debugging')
        .command('connect')
        .description('Connect to DevTools Bridge')
        .action(async () => {
        const bridge = new BridgeCommand(config, logger);
        await bridge.status();
    });
    // Init command - Initialize project
    program
        .command('init')
        .description('Initialize Vigthoria in current project')
        .action(async () => {
        const configCmd = new ConfigCommand(config, logger);
        await configCmd.init();
    });
    program
        .command('menu')
        .description('Open the interactive command-family menu')
        .action(async () => {
        const selectedArgs = await selectInteractiveCommand(program);
        if (selectedArgs) {
            await program.parseAsync([args[0], args[1], ...selectedArgs]);
        }
    });
    program
        .command('commands')
        .description('List every CLI command grouped by command family')
        .action(() => {
        console.log(renderDynamicHelp(program));
    });
    try {
        // Default to chat if no command
        if (args.length === 2) {
            const selectedArgs = await selectInteractiveCommand(program);
            if (selectedArgs) {
                await program.parseAsync([args[0], args[1], ...selectedArgs]);
            }
            process.exitCode = 0;
            return;
        }
        await program.parseAsync(args);
        if (process.exitCode === undefined || process.exitCode === 0) {
            process.exitCode = 0;
        }
    }
    catch (error) {
        reportCliError(error, jsonOutputRequested);
        process.exitCode = 1;
    }
}
setupErrorHandlers();
async function bootstrapCli() {
    try {
        await main(process.argv);
    }
    catch (err) {
        handleFatalCliError(err, process.argv.includes('--json'));
        process.exit(1);
    }
}
void (async () => {
    try {
        await bootstrapCli();
    }
    catch (err) {
        handleFatalCliError(err, process.argv.includes('--json'));
        process.exit(1);
    }
})();
export const __cliErrorHandlingReady = true;
