"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseArgs = exports.main = exports.registerAgentSignalHandlers = exports.isAgentVariantsEnabled = exports.buildAgentDevServerContext = exports.DEFAULT_USER_PORT = exports.DEFAULT_PORT = void 0;
/* eslint-disable no-console */
const child_process_1 = require("child_process");
const dotenv = __importStar(require("dotenv"));
const fs_1 = __importDefault(require("fs"));
const open_1 = __importDefault(require("open"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const index_core_1 = require("./index-core");
const server_1 = require("./server");
const AuthService_1 = require("./services/AuthService");
const AgentSessionService_1 = require("./services/AgentSessionService");
const TerminalAgentRunner_1 = require("./services/TerminalAgentRunner");
const ConfigManager_1 = require("./services/ConfigManager");
const SessionBridgeService_1 = require("./services/SessionBridgeService");
const TelemetryService_1 = require("./services/TelemetryService");
const skillWriter_1 = require("./utils/skillWriter");
const portUtils_1 = require("./utils/portUtils");
const createAgentVariantsOrchestrator_1 = require("./services/createAgentVariantsOrchestrator");
const InlineVariantGenerationService_1 = require("./services/InlineVariantGenerationService");
const log = (0, index_core_1.createLogger)('RivetCLI');
exports.DEFAULT_PORT = 4000;
exports.DEFAULT_USER_PORT = 3000;
/**
 * Builds the dev-server context advertised to the embedded agent UI.
 */
const buildAgentDevServerContext = ({ framework, devServerHost, userDevServerPort, }) => {
    if (framework === 'static' || userDevServerPort === 0) {
        return {
            ownership: 'none',
            host: null,
            port: null,
            startedByRivet: false,
        };
    }
    return {
        ownership: 'external',
        host: devServerHost ?? 'localhost',
        port: userDevServerPort,
        startedByRivet: false,
    };
};
exports.buildAgentDevServerContext = buildAgentDevServerContext;
/**
 * Returns whether embedded agent variants can be offered for this runtime.
 */
const isAgentVariantsEnabled = (options) => !options.noGit;
exports.isAgentVariantsEnabled = isAgentVariantsEnabled;
/**
 * @effect Stops active terminal agent processes before the CLI exits on OS signals.
 */
const registerAgentSignalHandlers = (runner) => {
    const stopAgentChildren = () => runner.stopActiveRuns();
    process.prependOnceListener('SIGINT', stopAgentChildren);
    process.prependOnceListener('SIGTERM', stopAgentChildren);
};
exports.registerAgentSignalHandlers = registerAgentSignalHandlers;
/** Host for production hosted tryout; aligns with `DEMO_PUBLIC_BASE_URL` on Render. */
const DEMO_TRYOUT_PUBLIC_HOST = 'demo.rivet.design';
const isDemoTryoutPublicBaseUrl = (url) => {
    if (!url?.trim()) {
        return false;
    }
    try {
        return new URL(url.trim()).hostname === DEMO_TRYOUT_PUBLIC_HOST;
    }
    catch {
        return false;
    }
};
const main = async (args = process.argv.slice(2)) => {
    try {
        // Check for subcommands first
        const command = args[0];
        // Handle auth commands
        if (command === 'login') {
            await handleLogin();
            return;
        }
        if (command === 'logout') {
            await handleLogout();
            return;
        }
        if (command === 'mcp') {
            const { startMCPServer } = await Promise.resolve().then(() => __importStar(require('./mcp/server')));
            const editorFlagIndex = args.indexOf('--editor');
            const mcpEditor = editorFlagIndex !== -1 ? args[editorFlagIndex + 1] : undefined;
            await startMCPServer(mcpEditor);
            return;
        }
        if (command === 'agent') {
            await handleAgent(args.slice(1));
            return;
        }
        if (command === 'install') {
            await handleInstall(args[1]);
            return;
        }
        if (command === 'update') {
            await handleUpdate();
            return;
        }
        if (command === 'uninstall') {
            await handleUninstall(args[1]);
            return;
        }
        // Parse basic CLI arguments first
        const options = (0, exports.parseArgs)(args);
        // Initialize telemetry
        const telemetry = new TelemetryService_1.TelemetryService({
            enabled: !options.noTelemetry,
            source: 'cli',
        });
        // Load Rivet's own environment variables from its .env.local file (local dev only)
        const rivetEnvPath = path_1.default.resolve(__dirname, '../.env.local');
        if (fs_1.default.existsSync(rivetEnvPath)) {
            dotenv.config({ path: rivetEnvPath });
            log.debug('📝 Loaded Rivet environment variables');
        }
        // Log which LLM configuration is active (env vars may come from .env.local or the host environment)
        if (process.env.RIVET_PROXY_URL) {
            log.debug('🔗 Proxy mode enabled - using remote LLM proxy');
        }
        else if (process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY) {
            log.debug('🤖 Direct mode enabled - using local API keys');
            if (process.env.ANTHROPIC_API_KEY) {
                log.debug('   Anthropic (Claude) API key found');
            }
            if (process.env.OPENAI_API_KEY) {
                log.debug('   OpenAI API key found');
            }
        }
        else {
            log.info('No LLM configuration found - AI features will not work');
            log.debug('   Either set RIVET_PROXY_URL for proxy mode,');
            log.debug('   or ANTHROPIC_API_KEY / OPENAI_API_KEY for direct mode');
        }
        // Set debug logging level if requested
        if (options.debug) {
            process.env.LOG_LEVEL = 'DEBUG';
            (0, index_core_1.setLogLevel)('DEBUG'); // Update existing loggers
            log.debug('🐛 Debug mode enabled - LOG_LEVEL=DEBUG');
        }
        log.info('🎨 Starting Rivet...');
        if (options.help) {
            showHelp();
            return;
        }
        if (options.version) {
            showVersion();
            return;
        }
        const projectDetection = new index_core_1.ProjectDetectionService();
        const projectPath = process.cwd();
        let project;
        let userDevServerPort;
        try {
            // Try to detect with running server
            project = await projectDetection.detectProject(projectPath, options.framework, options.entry, [], options.userPort);
            userDevServerPort = options.userPort || project.devServerPort;
        }
        catch (error) {
            // If user provided an explicit port, we don't need detection to succeed
            if (options.userPort) {
                userDevServerPort = options.userPort;
                project = {
                    id: path_1.default.basename(projectPath),
                    framework: (options.framework || 'nextjs'),
                    path: projectPath,
                    devServerPort: options.userPort,
                    devServerHost: 'localhost',
                    status: 'detected',
                    packageManager: 'npm', // Fallback
                };
            }
            else {
                // Check if this is a "no dev server" error
                const isNoServerError = error instanceof Error &&
                    error.message.includes('No running dev server');
                if (!isNoServerError) {
                    throw error;
                }
                // No dev server detected - tell user to start it
                log.error('❌ No dev server detected.');
                log.error('   Please start your dev server first (e.g., npm run dev), then run rivet again.');
                process.exit(1);
            }
        }
        if (userDevServerPort === undefined) {
            log.error('❌ Could not determine dev server port.');
            process.exit(1);
        }
        // Pick Rivet port as late as possible to avoid another process binding it first (e.g. when desktop spawns CLI).
        let rivetPort = options.rivetPort ?? (await (0, portUtils_1.findAvailablePort)(exports.DEFAULT_PORT));
        // Track session start
        telemetry.trackSessionStart({
            framework: project.framework,
            port: rivetPort,
            userPort: userDevServerPort,
            debugMode: options.debug,
        });
        log.debug(`📡 Connecting to project dev server on port ${userDevServerPort}${options.userPort ? ' (user-specified)' : ' (detected)'}`);
        // Start server; on EADDRINUSE retry with next available port (handles race when desktop or another instance binds first).
        let serverStarted = false;
        let retries = 0;
        const maxRetries = 5;
        while (!serverStarted && retries < maxRetries) {
            const startServerOptions = {
                userPort: userDevServerPort,
                userHost: project.devServerHost,
                framework: project.framework,
                telemetry,
                projectPath,
                staticEntry: project.entryPoint,
                styleFramework: options.styleFramework,
                tailwindConfig: options.tailwindConfig,
                rivetPort,
                skipProcessHandlers: retries > 0,
                isGitEnabled: options.noGit ? false : true,
                demoMode: options.hostedDemoMode
                    ? {
                        enabled: true,
                        allowSessionProvisioning: options.demoNoSessionProvisioning
                            ? false
                            : true,
                        requireSignedInUsers: true,
                        templateProjectPath: options.demoTemplateProject,
                        worktreesRootPath: options.demoWorktreesRoot,
                        sessionTtlMs: options.demoSessionTtlMinutes
                            ? options.demoSessionTtlMinutes * 60 * 1000
                            : undefined,
                        maxActiveSessions: options.demoMaxActiveSessions,
                        baseRivetPort: options.demoBaseRivetPort,
                        publicBaseUrl: options.demoPublicBaseUrl,
                    }
                    : undefined,
            };
            try {
                await (0, server_1.startServer)(startServerOptions);
                serverStarted = true;
            }
            catch (err) {
                const code = err?.code;
                if (code === 'EADDRINUSE' && !options.rivetPort) {
                    retries++;
                    rivetPort = await (0, portUtils_1.findAvailablePort)(rivetPort + 1);
                    log.debug(`Port in use, retrying with port ${rivetPort} (attempt ${retries}/${maxRetries})`);
                }
                else {
                    throw err;
                }
            }
        }
        if (!serverStarted) {
            log.error(`❌ Could not start Rivet server after ${maxRetries} attempts.`);
            process.exit(1);
        }
        log.info(`✅ Rivet server started on http://localhost:${rivetPort}`);
        const useLocalhostRivetUiRootEntrypoint = project.framework === 'static' ||
            options.hostedDemoMode ||
            isDemoTryoutPublicBaseUrl(options.demoPublicBaseUrl ?? process.env.DEMO_PUBLIC_BASE_URL);
        // Check authentication: try CI email sign-in if env set, otherwise OAuth
        const configManager = (0, ConfigManager_1.getConfigManager)();
        let didAuthenticate = false;
        if (!configManager.isAuthenticated()) {
            const e2eEmail = process.env.RIVET_E2E_EMAIL || process.env.RIVET_TEST_EMAIL;
            const e2ePassword = process.env.RIVET_E2E_PASSWORD || process.env.RIVET_TEST_PASSWORD;
            const proxyUrl = process.env.RIVET_PROXY_URL || configManager.getProxyUrl();
            if (e2eEmail && e2ePassword) {
                const authService = new AuthService_1.AuthService(proxyUrl);
                const loginResult = await authService.loginWithEmailPassword(e2eEmail, e2ePassword);
                if (!loginResult.success) {
                    log.error('CI sign-in failed:', loginResult.error || loginResult.message);
                    process.exit(1);
                }
                console.log(`\n✅ Signed in as ${loginResult.user?.email} (CI)`);
                if (loginResult.profile) {
                    console.log(`💰 Balance: $${loginResult.profile.remaining_spend_usd.toFixed(2)}`);
                }
                didAuthenticate = true;
            }
            if (!didAuthenticate) {
                if (process.env.CI === 'true') {
                    console.log('\n❌ E2E auth required: set RIVET_E2E_EMAIL and RIVET_E2E_PASSWORD (or RIVET_TEST_EMAIL and RIVET_TEST_PASSWORD) in repo secrets. Must be e2etest@gmail.com.');
                    process.exit(1);
                }
                console.log('\n🔐 Authentication required');
                console.log('Opening browser for Google login...\n');
                const authService = new AuthService_1.AuthService();
                const oauthRedirectOrigin = useLocalhostRivetUiRootEntrypoint
                    ? `http://localhost:${rivetPort}`
                    : `http://localhost:${rivetPort}/rivet`;
                const loginResult = await authService.loginWithGoogle(oauthRedirectOrigin);
                if (!loginResult.success) {
                    console.log(`\n❌ Authentication failed: ${loginResult.error || loginResult.message}`);
                    process.exit(1);
                }
                console.log(`\n✅ Authenticated as ${loginResult.user?.email}`);
                if (loginResult.profile) {
                    console.log(`💰 Balance: $${loginResult.profile.remaining_spend_usd.toFixed(2)}`);
                }
                didAuthenticate = true;
            }
        }
        // Open browser to Rivet UI (only if we didn't just authenticate, since OAuth already opened it)
        if (!didAuthenticate && !options.noBrowser) {
            const rivetUiPath = useLocalhostRivetUiRootEntrypoint ? '/' : '/rivet';
            await (0, open_1.default)(`http://localhost:${rivetPort}${rivetUiPath}`);
            log.info('🌐 Opened Rivet in your browser');
        }
        log.info(`✅ Rivet connected to your ${project.framework} project`);
        log.info('Press Ctrl+C to stop');
        // Run forever until interrupted
        await new Promise(() => { });
    }
    catch (error) {
        if (error instanceof Error) {
            log.error('❌', error.message);
            if (error.message.includes('No running dev server found')) {
                log.info('\n💡 Make sure to start your dev server first:');
                log.info('   npm run dev    (or)');
                log.info('   yarn dev       (or)');
                log.info('   pnpm dev');
                log.info('\nThen run rivet again.');
            }
        }
        else {
            log.error('❌ An unexpected error occurred:', error);
        }
    }
};
exports.main = main;
const parseArgs = (args) => {
    const options = {};
    for (let i = 0; i < args.length; i++) {
        const arg = args[i];
        switch (arg) {
            case '-h':
            case '--help':
                options.help = true;
                break;
            case '-v':
            case '--version':
                options.version = true;
                break;
            case '--user-port':
                // eslint-disable-next-line no-case-declarations
                const userPortValue = args[++i];
                if (userPortValue && !isNaN(Number(userPortValue))) {
                    options.userPort = Number(userPortValue);
                }
                break;
            case '--rivet-port':
                // eslint-disable-next-line no-case-declarations
                const rivetPortValue = args[++i];
                if (rivetPortValue && !isNaN(Number(rivetPortValue))) {
                    options.rivetPort = Number(rivetPortValue);
                }
                break;
            case '-d':
            case '--debug':
                options.debug = true;
                break;
            case '--no-telemetry':
                options.noTelemetry = true;
                break;
            case '--no-browser':
                options.noBrowser = true;
                break;
            case '--framework':
                // eslint-disable-next-line no-case-declarations
                const frameworkValue = args[++i];
                if (frameworkValue &&
                    ['nextjs', 'vite', 'cra', 'remix', 'svelte', 'static'].includes(frameworkValue)) {
                    options.framework = frameworkValue;
                }
                break;
            case '--entry':
                // eslint-disable-next-line no-case-declarations
                const entryValue = args[++i];
                if (entryValue) {
                    options.entry = entryValue;
                }
                break;
            case '--style-framework':
                // eslint-disable-next-line no-case-declarations
                const styleFrameworkValue = args[++i];
                if (styleFrameworkValue && ['tailwind'].includes(styleFrameworkValue)) {
                    options.styleFramework = styleFrameworkValue;
                }
                break;
            case '--tailwind-config':
                // eslint-disable-next-line no-case-declarations
                const tailwindConfigValue = args[++i];
                if (tailwindConfigValue) {
                    options.tailwindConfig = tailwindConfigValue;
                }
                break;
            case '--claude-bin':
                // eslint-disable-next-line no-case-declarations
                const claudeBinValue = args[++i];
                if (claudeBinValue) {
                    options.claudeBin = claudeBinValue;
                }
                break;
            case '--agent':
                // eslint-disable-next-line no-case-declarations
                const agentValue = args[++i];
                if (agentValue && ['claude', 'codex'].includes(agentValue)) {
                    options.agent = agentValue;
                }
                break;
            case '--agent-bin':
                // eslint-disable-next-line no-case-declarations
                const agentBinValue = args[++i];
                if (agentBinValue) {
                    options.agentBin = agentBinValue;
                }
                break;
            case '--model':
                // eslint-disable-next-line no-case-declarations
                const modelValue = args[++i];
                if (modelValue) {
                    options.model = modelValue;
                }
                break;
            case '--agent-timeout-seconds':
                // eslint-disable-next-line no-case-declarations
                const agentTimeoutSecondsValue = args[++i];
                if (agentTimeoutSecondsValue &&
                    !isNaN(Number(agentTimeoutSecondsValue))) {
                    options.agentTimeoutSeconds = Number(agentTimeoutSecondsValue);
                }
                break;
            // Hosted tryout from the CLI: `--demo-mode` turns on `startServer` demoMode; sibling flags fill that object
            // (template path, worktrees root, TTL, max sessions, child Rivet base port, public base URL). The packaged
            // hosted image uses `src/hosted-demo.ts` env instead of these switches.
            case '--demo-mode':
                options.hostedDemoMode = true;
                break;
            case '--no-git':
                options.noGit = true;
                break;
            case '--demo-allow-anonymous':
                options.demoAllowAnonymous = true;
                break;
            case '--demo-no-session-provisioning':
                options.demoNoSessionProvisioning = true;
                break;
            case '--demo-template-project':
                // eslint-disable-next-line no-case-declarations
                const demoTemplateValue = args[++i];
                if (demoTemplateValue) {
                    options.demoTemplateProject = demoTemplateValue;
                }
                break;
            case '--demo-worktrees-root':
                // eslint-disable-next-line no-case-declarations
                const demoWorktreesRootValue = args[++i];
                if (demoWorktreesRootValue) {
                    options.demoWorktreesRoot = demoWorktreesRootValue;
                }
                break;
            case '--demo-session-ttl-minutes':
                // eslint-disable-next-line no-case-declarations
                const demoSessionTtlValue = args[++i];
                if (demoSessionTtlValue && !isNaN(Number(demoSessionTtlValue))) {
                    options.demoSessionTtlMinutes = Number(demoSessionTtlValue);
                }
                break;
            case '--demo-max-active-sessions':
                // eslint-disable-next-line no-case-declarations
                const demoMaxSessionsValue = args[++i];
                if (demoMaxSessionsValue && !isNaN(Number(demoMaxSessionsValue))) {
                    options.demoMaxActiveSessions = Number(demoMaxSessionsValue);
                }
                break;
            case '--demo-base-rivet-port':
                // eslint-disable-next-line no-case-declarations
                const demoBaseRivetPortValue = args[++i];
                if (demoBaseRivetPortValue &&
                    !isNaN(Number(demoBaseRivetPortValue))) {
                    options.demoBaseRivetPort = Number(demoBaseRivetPortValue);
                }
                break;
            case '--demo-public-base-url':
                // eslint-disable-next-line no-case-declarations
                const demoPublicBaseUrlValue = args[++i];
                if (demoPublicBaseUrlValue) {
                    options.demoPublicBaseUrl = demoPublicBaseUrlValue;
                }
                break;
        }
    }
    return options;
};
exports.parseArgs = parseArgs;
const handleAgent = async (args) => {
    const options = (0, exports.parseArgs)(args);
    const agentHost = '127.0.0.1';
    if (options.help) {
        showHelp();
        return;
    }
    if (options.version) {
        showVersion();
        return;
    }
    const telemetry = new TelemetryService_1.TelemetryService(!options.noTelemetry);
    if (options.debug) {
        process.env.LOG_LEVEL = 'DEBUG';
        (0, index_core_1.setLogLevel)('DEBUG');
        log.debug('🐛 Debug mode enabled - LOG_LEVEL=DEBUG');
    }
    const rivetEnvPath = path_1.default.resolve(__dirname, '../.env.local');
    if (fs_1.default.existsSync(rivetEnvPath)) {
        dotenv.config({ path: rivetEnvPath });
        log.debug('📝 Loaded Rivet environment variables');
    }
    const agentKind = options.agent ?? 'claude';
    const agentLabel = agentKind === 'codex' ? 'Codex' : 'Claude Code';
    console.log(`\n⚠️  Rivet agent mode uses ${agentLabel} bypass permissions.`);
    console.log('Only run this in local projects you trust.\n');
    const projectDetection = new index_core_1.ProjectDetectionService();
    const projectPath = process.cwd();
    let project;
    let userDevServerPort;
    try {
        project = await projectDetection.detectProject(projectPath, options.framework, options.entry, [], options.userPort);
        userDevServerPort = options.userPort || project.devServerPort;
    }
    catch (error) {
        if (options.userPort) {
            userDevServerPort = options.userPort;
            project = {
                id: path_1.default.basename(projectPath),
                framework: (options.framework || 'nextjs'),
                path: projectPath,
                devServerPort: options.userPort,
                devServerHost: 'localhost',
                status: 'detected',
                packageManager: 'npm',
            };
        }
        else {
            const isNoServerError = error instanceof Error &&
                error.message.includes('No running dev server');
            if (!isNoServerError) {
                throw error;
            }
            log.error('❌ No dev server detected.');
            log.error('   Please start your dev server first (e.g., npm run dev), then run rivet agent again.');
            process.exit(1);
        }
    }
    if (userDevServerPort === undefined) {
        log.error('❌ Could not determine dev server port.');
        process.exit(1);
    }
    let rivetPort = options.rivetPort ?? (await (0, portUtils_1.findAvailablePort)(exports.DEFAULT_PORT));
    const bridge = new SessionBridgeService_1.SessionBridgeService();
    const sessionId = bridge.startSession(projectPath);
    const devServerContext = (0, exports.buildAgentDevServerContext)({
        framework: project.framework,
        devServerHost: project.devServerHost,
        userDevServerPort,
    });
    bridge.setDevServerContext(devServerContext);
    bridge.updateDevServerHealth({
        isReachable: devServerContext.ownership === 'none' ? null : true,
        reason: devServerContext.ownership === 'none' ? 'unknown' : 'healthy',
        lastCheckedAt: Date.now(),
    });
    const runner = new TerminalAgentRunner_1.TerminalAgentRunner({
        agent: agentKind,
        agentBin: options.agentBin,
        claudeBin: options.claudeBin,
        model: options.model,
        timeoutSeconds: options.agentTimeoutSeconds ?? TerminalAgentRunner_1.DEFAULT_AGENT_TIMEOUT_SECONDS,
    });
    const areAgentVariantsEnabled = (0, exports.isAgentVariantsEnabled)(options);
    const agentVariantsOrchestrator = areAgentVariantsEnabled
        ? (0, createAgentVariantsOrchestrator_1.createAgentVariantsOrchestrator)({
            bridge,
            telemetry,
            projectPathFallback: projectPath,
        })
        : undefined;
    const inlineVariantService = agentVariantsOrchestrator
        ? new InlineVariantGenerationService_1.InlineVariantGenerationService({
            bridge,
            orchestrator: agentVariantsOrchestrator,
            runner,
        })
        : undefined;
    const agentSession = new AgentSessionService_1.AgentSessionService({
        bridge,
        projectPath,
        runner,
        inlineVariantService,
        worktreeProjectLocator: agentVariantsOrchestrator,
    });
    let serverStarted = false;
    let retries = 0;
    const maxRetries = 5;
    while (!serverStarted && retries < maxRetries) {
        try {
            await (0, server_1.startServer)({
                userPort: userDevServerPort,
                userHost: project.devServerHost,
                framework: project.framework,
                telemetry,
                projectPath,
                staticEntry: project.entryPoint,
                styleFramework: options.styleFramework,
                tailwindConfig: options.tailwindConfig,
                sessionBridge: bridge,
                agentVariantsOrchestrator,
                mcpEditor: agentKind === 'codex' ? 'codex' : 'claude',
                agentApplyMode: 'embedded',
                agentRunController: agentSession,
                rivetPort,
                isGitEnabled: options.noGit ? false : true,
                skipProcessHandlers: retries > 0,
            });
            serverStarted = true;
        }
        catch (err) {
            const code = err?.code;
            if (code === 'EADDRINUSE' && !options.rivetPort) {
                retries++;
                rivetPort = await (0, portUtils_1.findAvailablePort)(rivetPort + 1);
                log.debug(`Port in use, retrying with port ${rivetPort} (attempt ${retries}/${maxRetries})`);
            }
            else {
                throw err;
            }
        }
    }
    if (!serverStarted) {
        log.error(`❌ Could not start Rivet server after ${maxRetries} attempts.`);
        process.exit(1);
    }
    agentSession.start();
    (0, exports.registerAgentSignalHandlers)(runner);
    log.info(`✅ Rivet agent server started on http://${agentHost}:${rivetPort}`);
    log.info(`${runner.getDisplayName()} session: ${agentSession.getContinuousSessionId()}`);
    if (!options.noBrowser) {
        const rivetUiPath = project.framework === 'static' ? '/' : '/rivet';
        await (0, open_1.default)(`http://${agentHost}:${rivetPort}${rivetUiPath}`);
        log.info('🌐 Opened Rivet in your browser');
    }
    log.info(`✅ Rivet agent connected to your ${project.framework} project`);
    log.info(`Bridge session: ${sessionId}`);
    log.info('Press Ctrl+C to stop');
    await new Promise(() => { });
};
const showHelp = () => {
    console.log(`
rivet - Local visual web development tool

USAGE:
  rivet [command] [options]

COMMANDS:
  rivet                 Start Rivet (auto-login if needed)
  rivet agent           Start Rivet with a terminal AI agent applying visual changes
  rivet install claude    Set up Rivet for Claude Code
  rivet install cursor    Set up Rivet for Cursor
  rivet install codex     Set up Rivet for OpenAI Codex CLI
  rivet uninstall claude  Remove Rivet from Claude Code
  rivet uninstall cursor  Remove Rivet from Cursor
  rivet uninstall codex   Remove Rivet from OpenAI Codex CLI
  rivet uninstall all     Remove Rivet from all editors
  rivet update            Update Rivet MCP server for all installed editors
  rivet login           Login with Google
  rivet logout          Logout from Rivet

OPTIONS:
  -h, --help            Show this help message
  -v, --version         Show version number
  --user-port PORT      Port where your dev server is running (default: 3000)
  --rivet-port PORT     Port for Rivet server (default: 4000, or next free if in use)
  -d, --debug           Enable debug logging
  --no-telemetry        Disable anonymous usage analytics (default: enabled)
  --no-browser          Don't automatically open browser (default: enabled)
  --framework TYPE      Override framework detection (nextjs|vite|cra|remix|svelte|static)
  --entry PATH          Entry point for static projects (default: index.html)
  --style-framework TYPE Override design token detection (tailwind)
  --anthropic-api-key KEY Anthropic API key for Claude-based agentic modifications
  --agent TYPE          Terminal agent for rivet agent (claude|codex; default: claude)
  --agent-bin PATH      Terminal agent binary for rivet agent
  --tailwind-config PATH Path to Tailwind config file (e.g., landing/tailwind.config.ts)
  --claude-bin PATH     Claude Code binary for rivet agent (default: claude)
  --model MODEL         Model for rivet agent (uses agent default if omitted)
  --agent-timeout-seconds SECONDS Timeout for each terminal agent run in rivet agent
  --demo-mode            Enable hosted demo mode with session routing
  --no-git               Disable git features for this runtime
  --demo-allow-anonymous Allow unauthenticated demo session creation
  --demo-no-session-provisioning Disable demo session creation endpoint
  --demo-template-project PATH Relative template project for per-session worktrees
  --demo-worktrees-root PATH Directory used for demo worktree creation
  --demo-session-ttl-minutes N Session lifetime in minutes
  --demo-max-active-sessions N Maximum number of active demo sessions
  --demo-base-rivet-port PORT Base port for spawned demo session runtimes
  --demo-public-base-url URL Public base URL used for returned session links

EXAMPLES:
  rivet                             # Start Rivet (port auto-selected), connect to dev server on port 3000
  rivet --user-port 5173            # Connect to Vite dev server on port 5173
  rivet --rivet-port 4000           # Use port 4000 for Rivet (fails if in use)
  rivet --framework static          # Serve static HTML from ./index.html
  rivet --framework static --entry dist/   # Serve static files from ./dist/ directory
  rivet install claude                 # Configure Rivet as a Claude Code MCP server
  rivet install cursor                 # Configure Rivet for Cursor
  rivet install codex                  # Configure Rivet for OpenAI Codex CLI
  rivet uninstall cursor               # Remove Rivet from Cursor
  rivet uninstall all                  # Remove Rivet from all editors
  rivet login                       # Manually login with Google

Make sure your dev server is running first (npm run dev, yarn dev, etc.)
Note: For static HTML projects, use --framework static (no dev server required)
`);
};
const showVersion = () => {
    try {
        const packageJsonPath = path_1.default.join(__dirname, '../package.json');
        const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf8'));
        console.log(`rivet v${packageJson.version}`);
    }
    catch (error) {
        log.error('Could not read version from package.json', error);
    }
};
const MCP_INSTALL_WELCOME = `
Welcome to Rivet!

Rivet is a visual editor for your coding agent. 
`;
const RIVET_ASCII_LOGO = `

****************************************************************************************************
****************************************************************************************************
*******************************+.  :****************************************************************
*******************************:    =*************************************:...=*********************
*******************************+=--=*************************************+.   =*********************
*****************-....... ..:+*-....**:....=*****:....=**:..........-**+..    ....-*****************
*****************-    ....  .+*-   .***:    +***-    -*+.            :*+.         :*****************
*****************-   .+****++**-   .****.   :**+.   :**+    :====:   .***+    =*********************
*****************-   .+********-   .****+.   -+.   :***+             .***+    =*********************
*****************-   .+********-   .*****+.  .:   :****+    .++++==--****+    :+++******************
*****************-   .+********-   .******+.     :******:.           .+***.       =*****************
*****************+++++*********+++++*******+++++++********+++++++++++******+++++++******************
****************************************************************************************************
****************************************************************************************************

`;
/**
 * Handle install command — configure Rivet as an MCP server for the specified editor
 */
const handleInstall = async (editor) => {
    switch (editor) {
        case 'claude':
            console.log(MCP_INSTALL_WELCOME);
            await handleInstallClaude();
            break;
        case 'claude-desktop':
            console.log(MCP_INSTALL_WELCOME);
            await handleInstallClaudeDesktop();
            break;
        case 'cursor':
            console.log(MCP_INSTALL_WELCOME);
            await handleInstallCursor();
            break;
        case 'codex':
            console.log(MCP_INSTALL_WELCOME);
            await handleInstallCodex();
            break;
        default:
            console.log('\nUsage: rivet install <editor>\n');
            console.log('  rivet install claude          Set up for Claude Code');
            console.log('  rivet install claude-desktop  Set up for the Claude desktop app');
            console.log('  rivet install cursor          Set up for Cursor');
            console.log('  rivet install codex           Set up for OpenAI Codex CLI');
            console.log('');
            process.exit(editor ? 1 : 0);
    }
    console.log(RIVET_ASCII_LOGO);
};
/**
 * Register Rivet with Claude Code MCP. Returns true on success, false on failure.
 * Does NOT call process.exit — callers decide how to handle failure.
 */
const registerClaudeMCP = () => {
    const mcpAddCommand = 'claude mcp add --transport stdio --scope user rivet -- npx -y rivet-design@latest mcp --editor claude';
    try {
        const output = (0, child_process_1.execSync)(mcpAddCommand, { stdio: 'pipe', encoding: 'utf8' });
        process.stdout.write(output);
        console.log('✓ Rivet MCP server added to Claude Code');
        return true;
    }
    catch (err) {
        const stderr = err.stderr ?? '';
        if (stderr.includes('already exists')) {
            console.log('✓ Rivet MCP server already registered');
            return true;
        }
        process.stderr.write(stderr);
        console.log('Run manually:', 'claude mcp add --transport stdio --scope user rivet -- npx -y rivet-design@latest mcp --editor claude');
        return false;
    }
};
const handleInstallClaude = async () => {
    console.log('\nSetting up Rivet for Claude Code...\n');
    try {
        (0, child_process_1.execSync)('claude --version', { stdio: 'ignore' });
    }
    catch {
        console.log('Claude Code is not installed or not in your PATH.');
        console.log('Install it: https://claude.ai/download');
        process.exit(1);
    }
    if (!registerClaudeMCP()) {
        process.exit(1);
    }
    const skillResult = (0, skillWriter_1.writeSkillFileIfNeeded)();
    if (skillResult.success) {
        console.log('✓ Rivet skill installed');
    }
    else {
        console.log(`  Warning: could not write skill file to ${path_1.default.join(os_1.default.homedir(), '.claude', 'skills', 'rivet')}: ${skillResult.error}`);
        console.log('  Claude Code will still work with Rivet, but may need manual guidance on tool usage.');
    }
    console.log(`
Next steps:
  1. Start a new Claude Code session
  2. Type /rivet or say "Open Rivet"
`);
};
/**
 * Resolve `npx` to an absolute path using the install-time shell PATH.
 *
 * Why: editors like Claude desktop inherit a sanitized PATH at launch that
 * can put stale node versions (e.g. legacy nvm installs) first, causing
 * `npx` to dispatch to a node so old it can't even `require('node:url')`.
 * Writing the absolute path into the MCP config bypasses that lookup so the
 * editor uses the same `npx` the user has in their interactive shell.
 *
 * Falls back to the literal "npx" with a warning if resolution fails — the
 * prior behavior — so install never hard-blocks on a quirky environment.
 */
const resolveNpxCommand = () => {
    const which = process.platform === 'win32' ? 'where' : 'which';
    try {
        const out = (0, child_process_1.execSync)(`${which} npx`, {
            stdio: ['ignore', 'pipe', 'ignore'],
            encoding: 'utf8',
        });
        // `where` on Windows can return multiple lines (npx, npx.cmd, npx.ps1).
        // Prefer .cmd / .exe over a shebanged shell script so Windows can spawn
        // the resolved path directly.
        const lines = out
            .split(/\r?\n/)
            .map((l) => l.trim())
            .filter((l) => l.length > 0 && fs_1.default.existsSync(l));
        if (lines.length === 0) {
            throw new Error('which returned no usable paths');
        }
        if (process.platform === 'win32') {
            const directlySpawnable = lines.find((l) => /\.(cmd|exe|bat)$/i.test(l));
            return directlySpawnable ?? lines[0];
        }
        return lines[0];
    }
    catch {
        console.log('  Warning: could not resolve `npx` to an absolute path. Falling back to "npx" — if your editor uses an outdated Node, it may fail to start the server.');
        return 'npx';
    }
};
const buildCursorRivetEntry = () => ({
    command: resolveNpxCommand(),
    args: ['-y', 'rivet-design@latest', 'mcp', '--editor', 'cursor'],
});
/**
 * Surface a diagnostic when an existing rivet MCP entry's `command` is an
 * absolute path that no longer exists. Common when the user removes the
 * node version that was resolved at install time. Update rewrites the entry
 * anyway, but the note explains *why* the entry needed refreshing.
 */
const warnIfStaleRivetCommand = (entry, editorLabel) => {
    if (typeof entry !== 'object' || entry === null)
        return;
    const cmd = entry.command;
    if (typeof cmd !== 'string')
        return;
    if (!path_1.default.isAbsolute(cmd))
        return;
    if (fs_1.default.existsSync(cmd))
        return;
    console.log(`  Note: previous Rivet command for ${editorLabel} (${cmd}) no longer exists. Re-resolving.`);
};
const handleInstallCursor = async () => {
    console.log('\nSetting up Rivet for Cursor...\n');
    const cursorDir = path_1.default.join(os_1.default.homedir(), '.cursor');
    if (!fs_1.default.existsSync(cursorDir)) {
        console.log('Cursor does not appear to be installed (~/.cursor not found).');
        console.log('Install it: https://cursor.com');
        process.exit(1);
    }
    const mcpConfigPath = path_1.default.join(cursorDir, 'mcp.json');
    const rivetEntry = buildCursorRivetEntry();
    let config = {};
    if (fs_1.default.existsSync(mcpConfigPath)) {
        const raw = fs_1.default.readFileSync(mcpConfigPath, 'utf8');
        try {
            const parsed = JSON.parse(raw);
            if (parsed !== null &&
                typeof parsed === 'object' &&
                !Array.isArray(parsed)) {
                config = parsed;
            }
            else {
                console.log(`  Error: ${mcpConfigPath} is not a JSON object. Aborting to avoid data loss.`);
                console.log(`  Fix or delete the file manually, then re-run.`);
                process.exit(1);
            }
        }
        catch {
            console.log(`  Error: could not parse ${mcpConfigPath}. Aborting to avoid data loss.`);
            console.log(`  Fix or delete the file manually, then re-run.`);
            process.exit(1);
        }
    }
    // Ensure mcpServers is an object, not some other type
    if (config.mcpServers !== undefined &&
        (typeof config.mcpServers !== 'object' || Array.isArray(config.mcpServers))) {
        console.log(`  Error: mcpServers in ${mcpConfigPath} is not an object. Aborting to avoid data loss.`);
        process.exit(1);
    }
    config.mcpServers = { ...config.mcpServers, rivet: rivetEntry };
    fs_1.default.writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
    console.log(`✓ Rivet MCP server added to ${mcpConfigPath}`);
    console.log(`
Next steps:
  1. Fully restart Cursor
  2. Open a new chat and say "Open Rivet"
`);
};
const buildClaudeDesktopRivetEntry = () => ({
    command: resolveNpxCommand(),
    args: ['-y', 'rivet-design@latest', 'mcp', '--editor', 'claude-desktop'],
});
/**
 * Path to the Claude desktop app's MCP config file.
 * macOS:  ~/Library/Application Support/Claude/claude_desktop_config.json
 * Win:    %APPDATA%\Claude\claude_desktop_config.json
 * Linux:  ~/.config/Claude/claude_desktop_config.json (unofficial, but the
 *         freedesktop default if Anthropic ships a Linux build)
 */
const claudeDesktopConfigPath = () => {
    const home = os_1.default.homedir();
    if (process.platform === 'darwin') {
        return path_1.default.join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
    }
    if (process.platform === 'win32') {
        const appData = process.env.APPDATA ?? path_1.default.join(home, 'AppData', 'Roaming');
        return path_1.default.join(appData, 'Claude', 'claude_desktop_config.json');
    }
    return path_1.default.join(home, '.config', 'Claude', 'claude_desktop_config.json');
};
const handleInstallClaudeDesktop = async () => {
    console.log('\nSetting up Rivet for the Claude desktop app...\n');
    const mcpConfigPath = claudeDesktopConfigPath();
    const claudeDir = path_1.default.dirname(mcpConfigPath);
    if (!fs_1.default.existsSync(claudeDir)) {
        console.log(`Claude desktop does not appear to be installed (${claudeDir} not found).`);
        console.log('Install it: https://claude.ai/download');
        process.exit(1);
    }
    const rivetEntry = buildClaudeDesktopRivetEntry();
    let config = {};
    if (fs_1.default.existsSync(mcpConfigPath)) {
        const raw = fs_1.default.readFileSync(mcpConfigPath, 'utf8');
        try {
            const parsed = JSON.parse(raw);
            if (parsed !== null &&
                typeof parsed === 'object' &&
                !Array.isArray(parsed)) {
                config = parsed;
            }
            else {
                console.log(`  Error: ${mcpConfigPath} is not a JSON object. Aborting to avoid data loss.`);
                console.log(`  Fix or delete the file manually, then re-run.`);
                process.exit(1);
            }
        }
        catch {
            console.log(`  Error: could not parse ${mcpConfigPath}. Aborting to avoid data loss.`);
            console.log(`  Fix or delete the file manually, then re-run.`);
            process.exit(1);
        }
    }
    if (config.mcpServers !== undefined &&
        (typeof config.mcpServers !== 'object' || Array.isArray(config.mcpServers))) {
        console.log(`  Error: mcpServers in ${mcpConfigPath} is not an object. Aborting to avoid data loss.`);
        process.exit(1);
    }
    config.mcpServers = { ...config.mcpServers, rivet: rivetEntry };
    fs_1.default.writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
    console.log(`✓ Rivet MCP server added to ${mcpConfigPath}`);
    console.log(`
Next steps:
  1. Fully quit and reopen the Claude desktop app
  2. Open a new chat and say "Open Rivet"
`);
};
/**
 * Register Rivet with Codex MCP. Returns true on success, false on failure.
 * Does NOT call process.exit — callers decide how to handle failure.
 */
const registerCodexMCP = () => {
    const mcpAddCommand = 'codex mcp add rivet -- npx -y rivet-design@latest mcp --editor codex';
    try {
        (0, child_process_1.execSync)(mcpAddCommand, { stdio: 'inherit' });
        console.log('✓ Rivet MCP server added to Codex');
        return true;
    }
    catch {
        console.log('Run manually:', 'codex mcp add rivet -- npx -y rivet-design@latest mcp --editor codex');
        return false;
    }
};
const handleInstallCodex = async () => {
    console.log('\nSetting up Rivet for OpenAI Codex CLI...\n');
    // Check codex binary
    try {
        (0, child_process_1.execSync)('codex --version', { stdio: 'ignore' });
    }
    catch {
        console.log('Codex CLI is not installed or not in your PATH.');
        console.log('Install it: https://github.com/openai/codex');
        process.exit(1);
    }
    if (!registerCodexMCP()) {
        process.exit(1);
    }
    console.log(`
Next steps:
  1. Start a new Codex session
  2. Say "Open Rivet"
`);
};
const handleUninstallClaude = () => {
    try {
        (0, child_process_1.execSync)('claude --version', { stdio: 'ignore' });
    }
    catch {
        console.log('Claude Code is not installed or not in your PATH — skipping.');
        return false;
    }
    let madeChanges = false;
    try {
        (0, child_process_1.execSync)('claude mcp remove rivet', { stdio: 'pipe' });
        console.log('✓ Rivet MCP server removed from Claude Code');
        madeChanges = true;
    }
    catch {
        console.log('  Rivet was not registered with Claude Code (nothing to remove).');
    }
    // Remove skill file
    const skillDir = path_1.default.join(os_1.default.homedir(), '.claude', 'skills', 'rivet');
    if (fs_1.default.existsSync(skillDir)) {
        fs_1.default.rmSync(skillDir, { recursive: true, force: true });
        console.log('✓ Rivet skill file removed');
        madeChanges = true;
    }
    return madeChanges;
};
const handleUninstallCursor = () => {
    const mcpConfigPath = path_1.default.join(os_1.default.homedir(), '.cursor', 'mcp.json');
    if (!fs_1.default.existsSync(mcpConfigPath)) {
        console.log('  No Cursor MCP config found — nothing to remove.');
        return false;
    }
    try {
        const raw = fs_1.default.readFileSync(mcpConfigPath, 'utf8');
        const config = JSON.parse(raw);
        if (!config.mcpServers || !('rivet' in config.mcpServers)) {
            console.log('  Rivet was not registered with Cursor (nothing to remove).');
            return false;
        }
        delete config.mcpServers['rivet'];
        fs_1.default.writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
        console.log(`✓ Rivet MCP server removed from ${mcpConfigPath}`);
        return true;
    }
    catch {
        console.log(`  Error: could not parse ${mcpConfigPath}. Fix or delete the file manually.`);
        return false;
    }
};
const handleUninstallClaudeDesktop = () => {
    const mcpConfigPath = claudeDesktopConfigPath();
    if (!fs_1.default.existsSync(mcpConfigPath)) {
        console.log('  No Claude desktop MCP config found — nothing to remove.');
        return false;
    }
    try {
        const raw = fs_1.default.readFileSync(mcpConfigPath, 'utf8');
        const config = JSON.parse(raw);
        if (!config.mcpServers || !('rivet' in config.mcpServers)) {
            console.log('  Rivet was not registered with the Claude desktop app (nothing to remove).');
            return false;
        }
        delete config.mcpServers['rivet'];
        fs_1.default.writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
        console.log(`✓ Rivet MCP server removed from ${mcpConfigPath}`);
        return true;
    }
    catch {
        console.log(`  Error: could not parse ${mcpConfigPath}. Fix or delete the file manually.`);
        return false;
    }
};
const handleUninstallCodex = () => {
    try {
        (0, child_process_1.execSync)('codex --version', { stdio: 'ignore' });
    }
    catch {
        console.log('Codex CLI is not installed or not in your PATH — skipping.');
        return false;
    }
    try {
        (0, child_process_1.execSync)('codex mcp remove rivet', { stdio: 'pipe' });
        console.log('✓ Rivet MCP server removed from Codex');
        return true;
    }
    catch {
        console.log('  Rivet was not registered with Codex (nothing to remove).');
        return false;
    }
};
/**
 * Handle uninstall command — remove Rivet MCP server for the specified editor (or all)
 */
const handleUninstall = async (editor) => {
    switch (editor) {
        case 'claude': {
            console.log('\nUninstalling Rivet from Claude Code...\n');
            const changed = handleUninstallClaude();
            if (changed)
                console.log('\nRestart Claude Code to apply changes.\n');
            break;
        }
        case 'claude-desktop': {
            console.log('\nUninstalling Rivet from the Claude desktop app...\n');
            const changed = handleUninstallClaudeDesktop();
            if (changed)
                console.log('\nFully restart the Claude desktop app to apply changes.\n');
            break;
        }
        case 'cursor': {
            console.log('\nUninstalling Rivet from Cursor...\n');
            const changed = handleUninstallCursor();
            if (changed)
                console.log('\nRestart Cursor to apply changes.\n');
            break;
        }
        case 'codex': {
            console.log('\nUninstalling Rivet from OpenAI Codex CLI...\n');
            const changed = handleUninstallCodex();
            if (changed)
                console.log('\nStart a new Codex session to apply changes.\n');
            break;
        }
        case 'all': {
            console.log('\nUninstalling Rivet from all editors...\n');
            const claudeChanged = handleUninstallClaude();
            const claudeDesktopChanged = handleUninstallClaudeDesktop();
            const cursorChanged = handleUninstallCursor();
            const codexChanged = handleUninstallCodex();
            if (claudeChanged ||
                claudeDesktopChanged ||
                cursorChanged ||
                codexChanged) {
                console.log('\nRestart your editor sessions to apply changes.\n');
            }
            break;
        }
        default:
            console.log('\nUsage: rivet uninstall <editor>\n');
            console.log('  rivet uninstall claude          Remove from Claude Code');
            console.log('  rivet uninstall claude-desktop  Remove from the Claude desktop app');
            console.log('  rivet uninstall cursor          Remove from Cursor');
            console.log('  rivet uninstall codex           Remove from OpenAI Codex CLI');
            console.log('  rivet uninstall all             Remove from all editors');
            console.log('');
            process.exit(editor ? 1 : 0);
    }
};
/**
 * Handle update command — re-register Rivet MCP server for all detected editors
 */
const handleUpdate = async () => {
    console.log('\nUpdating Rivet...\n');
    let updatedAny = false;
    // Claude Code — only run if installed; surface re-add failure so we don't leave user without MCP
    let claudeInstalled = false;
    try {
        (0, child_process_1.execSync)('claude --version', { stdio: 'ignore' });
        claudeInstalled = true;
    }
    catch {
        // Claude not installed — skip
    }
    if (claudeInstalled) {
        try {
            (0, child_process_1.execSync)('claude mcp remove rivet', { stdio: 'pipe' });
        }
        catch {
            // not registered, that's fine
        }
        if (registerClaudeMCP()) {
            console.log('✓ Updated Rivet MCP server for Claude Code');
            const skillResult = (0, skillWriter_1.writeSkillFileIfNeeded)();
            if (skillResult.success) {
                console.log('✓ Updated Rivet skill for Claude Code');
            }
            else {
                console.log(`  Warning: could not write skill file (${skillResult.error})`);
            }
            updatedAny = true;
        }
        else {
            console.log('  Failed to re-add Rivet for Claude Code. Run: rivet install claude');
        }
    }
    // Cursor — only update if rivet was already registered
    const cursorMcpPath = path_1.default.join(os_1.default.homedir(), '.cursor', 'mcp.json');
    if (fs_1.default.existsSync(cursorMcpPath)) {
        try {
            const raw = fs_1.default.readFileSync(cursorMcpPath, 'utf8');
            const config = JSON.parse(raw);
            if (config.mcpServers && 'rivet' in config.mcpServers) {
                warnIfStaleRivetCommand(config.mcpServers['rivet'], 'Cursor');
                config.mcpServers['rivet'] = buildCursorRivetEntry();
                fs_1.default.writeFileSync(cursorMcpPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
                console.log('✓ Updated Rivet MCP server for Cursor');
                updatedAny = true;
            }
        }
        catch {
            console.log('  Warning: could not update Cursor MCP config');
        }
    }
    // Claude desktop — only update if rivet was already registered
    const claudeDesktopMcpPath = claudeDesktopConfigPath();
    if (fs_1.default.existsSync(claudeDesktopMcpPath)) {
        try {
            const raw = fs_1.default.readFileSync(claudeDesktopMcpPath, 'utf8');
            const config = JSON.parse(raw);
            if (config.mcpServers && 'rivet' in config.mcpServers) {
                warnIfStaleRivetCommand(config.mcpServers['rivet'], 'the Claude desktop app');
                config.mcpServers['rivet'] = buildClaudeDesktopRivetEntry();
                fs_1.default.writeFileSync(claudeDesktopMcpPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
                console.log('✓ Updated Rivet MCP server for the Claude desktop app');
                updatedAny = true;
            }
        }
        catch {
            console.log('  Warning: could not update Claude desktop MCP config');
        }
    }
    // Codex — remove then re-add so update works when already registered
    try {
        (0, child_process_1.execSync)('codex --version', { stdio: 'ignore' });
        try {
            (0, child_process_1.execSync)('codex mcp remove rivet', { stdio: 'pipe' });
        }
        catch {
            // not registered, that's fine
        }
        if (registerCodexMCP()) {
            console.log('✓ Updated Rivet MCP server for Codex');
            updatedAny = true;
        }
    }
    catch {
        // Codex not installed — skip
    }
    if (!updatedAny) {
        console.log("No editors found to update. Run 'rivet install <editor>' first.");
        console.log('  rivet install claude');
        console.log('  rivet install claude-desktop');
        console.log('  rivet install cursor');
        console.log('  rivet install codex');
    }
    else {
        console.log('\nRestart your editor session to use the latest Rivet.\n');
    }
};
/**
 * Handle login command
 */
const handleLogin = async () => {
    console.log('\n🔐 Rivet Login with Google\n');
    const authService = new AuthService_1.AuthService();
    console.log('Opening browser for Google authentication...');
    const loginResult = await authService.loginWithGoogle();
    if (loginResult.success) {
        console.log(`✅ Logged in as ${loginResult.user?.email}`);
        if (loginResult.profile) {
            console.log(`\n💰 Account Balance:`);
            console.log(`   Remaining: $${loginResult.profile.remaining_spend_usd.toFixed(2)}`);
            console.log(`   Monthly limit: $${loginResult.profile.monthly_limit_usd.toFixed(2)}`);
            console.log(`   Used this month: $${loginResult.profile.current_month_spend_usd.toFixed(6)}`);
        }
        console.log('\nYou can now run: rivet');
        return;
    }
    // Login failed
    console.log(`❌ Login failed: ${loginResult.error || loginResult.message}`);
    process.exit(1);
};
/**
 * Handle logout command
 */
const handleLogout = async () => {
    const configManager = (0, ConfigManager_1.getConfigManager)();
    if (!configManager.isAuthenticated()) {
        console.log('❌ Not currently logged in');
        return;
    }
    const email = configManager.getEmail();
    const authService = new AuthService_1.AuthService();
    await authService.logout();
    console.log(`✅ Logged out ${email ? `(${email})` : ''}`);
};
//# sourceMappingURL=index.js.map