UNPKG

@xtest-cli/cli

Version:

CLI for xtest.ing - AI-powered test generation platform

191 lines • 7.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.mirrorCommand = void 0; exports.mirror = mirror; const playwright_1 = require("playwright"); const axios_1 = __importDefault(require("axios")); const ws_1 = __importDefault(require("ws")); const commander_1 = require("commander"); const config_1 = require("../utils/config"); exports.mirrorCommand = new commander_1.Command('mirror') .description('Start synchronized browser control - actions mirror between local and cloud') .option('-u, --url <url>', 'Initial URL to navigate to', 'https://google.com') .action(mirror); async function mirror(options) { console.log('šŸ”„ Starting synchronized browser control...\n'); const config = await (0, config_1.getConfig)(); if (!config.apiKey) { console.error('āŒ Not authenticated. Please run "xtest auth" first.'); process.exit(1); } const API_BASE_URL = config.serverUrl; const WS_BASE_URL = config.serverUrl.replace('https://', 'wss://').replace('http://', 'ws://'); const apiClient = axios_1.default.create({ baseURL: API_BASE_URL, headers: { 'Authorization': `Bearer ${config.apiKey}`, 'Content-Type': 'application/json', }, }); let localBrowser = null; let localPage = null; let cloudSessionId = null; let ws = null; let isMirroring = false; try { // Launch local browser console.log('šŸ–„ļø Launching local browser...'); localBrowser = await playwright_1.chromium.launch({ headless: false, args: ['--start-maximized'], }); const context = await localBrowser.newContext({ viewport: null, }); localPage = await context.newPage(); console.log('āœ… Local browser ready'); // Create cloud session console.log('ā˜ļø Creating cloud browser session...'); cloudSessionId = `mirror-${Date.now()}`; try { await apiClient.post('/api/enhanced-browser/create', { sessionId: cloudSessionId, url: 'about:blank', }); console.log('āœ… Cloud browser ready'); } catch (error) { console.error('āŒ Failed to create cloud session:', error.response?.data || error.message); throw error; } // Connect WebSocket for real-time sync ws = new ws_1.default(`${WS_BASE_URL}/ws/cli`, { headers: { 'Authorization': `Bearer ${config.apiKey}`, 'X-Session-ID': cloudSessionId, 'X-CLI-Version': '0.5.2', }, }); ws.on('open', () => { console.log('āœ… Connected to cloud sync'); console.log('\nšŸ”„ Browsers are now synchronized!'); console.log('šŸ“ Actions in local browser will be mirrored to cloud browser'); console.log('🌐 Navigate to any website and interact normally\n'); }); ws.on('error', (error) => { console.error('WebSocket error:', error); }); // Navigate both browsers to initial URL console.log(`šŸ“ Navigating to: ${options.url}`); await localPage.goto(options.url); // Mirror navigation to cloud await apiClient.post('/api/enhanced-browser/navigate', { sessionId: cloudSessionId, url: options.url, }); // Set up mirroring event listeners isMirroring = true; // Intercept and mirror navigation localPage.on('framenavigated', async (frame) => { if (!isMirroring || frame !== localPage?.mainFrame()) return; const url = frame.url(); if (url && url !== 'about:blank') { console.log(`šŸ”„ Mirroring navigation to: ${url}`); try { await apiClient.post('/api/enhanced-browser/navigate', { sessionId: cloudSessionId, url: url, }); } catch (error) { console.error('Failed to mirror navigation:', error); } } }); // Override page methods to intercept actions const originalClick = localPage.click.bind(localPage); localPage.click = async (selector, options) => { if (isMirroring) { console.log(`šŸ”„ Mirroring click on: ${selector}`); try { await apiClient.post('/api/enhanced-browser/click', { sessionId: cloudSessionId, selector: selector, }); } catch (error) { console.error('Failed to mirror click:', error); } } return originalClick(selector, options); }; const originalFill = localPage.fill.bind(localPage); localPage.fill = async (selector, value, options) => { if (isMirroring) { console.log(`šŸ”„ Mirroring input to ${selector}: ${value}`); try { await apiClient.post('/api/enhanced-browser/type', { sessionId: cloudSessionId, selector: selector, text: value, }); } catch (error) { console.error('Failed to mirror input:', error); } } return originalFill(selector, value, options); }; const originalType = localPage.type.bind(localPage); localPage.type = async (selector, text, options) => { if (isMirroring) { console.log(`šŸ”„ Mirroring typing to ${selector}: ${text}`); try { await apiClient.post('/api/enhanced-browser/type', { sessionId: cloudSessionId, selector: selector, text: text, }); } catch (error) { console.error('Failed to mirror typing:', error); } } return originalType(selector, text, options); }; // Keep the process running console.log('\nšŸ’” Tip: Close the browser window or press Ctrl+C to stop mirroring\n'); // Wait for browser context to close (no timeout - wait indefinitely) await context.waitForEvent('close', { timeout: 0 }); console.log('\nšŸ›‘ Browser closed, stopping mirror...'); } catch (error) { console.error('āŒ Error:', error); } finally { // Cleanup isMirroring = false; if (ws) { ws.close(); } if (cloudSessionId) { try { await apiClient.post('/api/enhanced-browser/close', { sessionId: cloudSessionId, }); } catch (error) { // Ignore cleanup errors } } if (localBrowser) { await localBrowser.close(); } console.log('āœ… Cleanup complete'); } } //# sourceMappingURL=mirror.js.map