@xtest-cli/cli
Version:
CLI for xtest.ing - AI-powered test generation platform
191 lines ⢠7.5 kB
JavaScript
;
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