// Direct browserless CDP access - navigate to GitHub, screenshot QR code const WebSocket = require('/home/node/.openclaw/extensions/openclaw-weixin/node_modules/ws/index.js'); const http = require('http'); const fs = require('fs'); // Create a new browser session async function createSession(url) { return new Promise((resolve, reject) => { const postData = JSON.stringify({ url, headless: true }); const opts = { hostname: 'browserless', port: 3000, path: '/session', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': postData.length } }; const req = http.request(opts, (res) => { let data = ''; res.on('data', c => data += c); res.on('end', () => { try { resolve(JSON.parse(data)); } catch(e) { reject(e); } }); }); req.on('error', reject); req.write(postData); req.end(); }); } // Send CDP command over WebSocket function sendWS(ws, id, method, params) { return new Promise((resolve, reject) => { const msg = JSON.stringify({ id, method, params }); const timeout = setTimeout(() => reject('timeout'), 15000); ws.on('message', (data) => { const resp = JSON.parse(data.toString()); if (resp.id === id) { clearTimeout(timeout); resolve(resp.result); } }); ws.send(msg); }); } async function main() { const text = process.argv[2] || 'https://github.com/login/device'; const outFile = process.argv[3] || '/home/node/.openclaw/workspace/assets/browserless-qr.png'; // Step 1: create session console.log('Creating session at', text); const session = await createSession(text); console.log('Session:', Object.keys(session)); if (session.error) throw new Error(session.error); const wsUrl = session.wsUri || session.webSocketDebuggerUrl; console.log('WS URL:', wsUrl); const ws = new WebSocket(wsUrl); await new Promise((res, rej) => { ws.on('open', res); ws.on('error', rej); }); let id = 1; const send = (method, params) => sendWS(ws, id++, method, params); // Wait for page to load await send('Page.enable'); await send('Runtime.enable'); // Wait for network idle try { await send('Page.waitForNavigation', { waitUntil: 'networkidle2', timeout: 10000 }); } catch(e) { console.log('Nav wait:', e.message); } // Try to find QR code element const qrResult = await send('Runtime.evaluate', { expression: ` (function() { // Try multiple selectors const selectors = [ '.qr-code img', '.qrcode img', '#qr-code img', 'img[alt*="QR"]', 'img[src*="qrcode"]', '.setup-qr-code img', 'div[data-qr] img', '[class*="qr"] img', 'img[class*="qr"]' ]; for (const sel of selectors) { const el = document.querySelector(sel); if (el) return { src: el.src, w: el.width, h: el.height, sel }; } // Fall back to any large image const imgs = Array.from(document.querySelectorAll('img')); for (const img of imgs) { if (img.width > 100 && img.height > 100) { return { src: img.src, w: img.width, h: img.height, sel: 'fallback-large' }; } } // Get all images return imgs.map(img => ({ src: img.src.substring(0, 100), w: img.width, h: img.height, class: img.className })); })() ` }); console.log('QR elements:', JSON.stringify(qrResult.result, null, 2)); // Take screenshot of the page const screenshot = await send('Page.captureScreenshot', { type: 'png' }); const buf = Buffer.from(screenshot.data, 'base64'); fs.writeFileSync(outFile, buf); console.log('Screenshot saved:', buf.length, 'bytes to', outFile); ws.close(); } main().catch(e => { console.error('Error:', e.message); process.exit(1); });