Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483#!/usr/bin/env node// 🔍 Explore KidLisp Webview Structure// This script helps discover how to access the KidLisp.com webview through CDP
import WebSocket from 'ws';import http from 'http';
const RESET = '\x1b[0m';const BOLD = '\x1b[1m';const CYAN = '\x1b[36m';const YELLOW = '\x1b[33m';const GREEN = '\x1b[32m';const MAGENTA = '\x1b[35m';
const log = (msg) => console.log(msg);const heading = (msg) => console.log(`\n${MAGENTA}${BOLD}═══ ${msg} ═══${RESET}\n`);const info = (msg) => console.log(`${CYAN}→${RESET} ${msg}`);const success = (msg) => console.log(`${GREEN}✓${RESET} ${msg}`);const data = (label, value) => console.log(`${YELLOW}${label}:${RESET}`, typeof value === 'object' ? JSON.stringify(value, null, 2) : value);
async function findWorkingCDPHost() { const candidates = []; // Check if we're in a container const inContainer = process.env.REMOTE_CONTAINERS === 'true' || process.env.CODESPACES === 'true'; if (!inContainer) { // Not in container - try localhost for (const port of [9333, 9222]) { candidates.push({ host: 'localhost', port }); } } else { // In container - try multiple hosts candidates.push({ host: 'host.docker.internal', port: 9333 }); candidates.push({ host: 'host.docker.internal', port: 9222 }); candidates.push({ host: 'localhost', port: 9333 }); candidates.push({ host: 'localhost', port: 9222 }); candidates.push({ host: '172.17.0.1', port: 9224 }); candidates.push({ host: '172.17.0.1', port: 9223 }); candidates.push({ host: '172.17.0.1', port: 9222 }); } for (const { host, port } of candidates) { try { const works = await new Promise((resolve) => { const req = http.get({ hostname: host, port: port, path: '/json', timeout: 1000, headers: { 'Host': 'localhost' } }, (res) => { let data = ''; res.on('data', (chunk) => data += chunk); res.on('end', () => resolve(data.length > 0)); }); req.on('error', () => resolve(false)); req.on('timeout', () => { req.destroy(); resolve(false); }); }); if (works) return { host, port }; } catch (e) {} } return candidates[0] || { host: 'localhost', port: 9333 };}
async function main() { heading('KidLisp Webview Explorer'); const { host, port } = await findWorkingCDPHost(); info(`Connecting to CDP at ${host}:${port}`); // Get all targets const targetsJson = await new Promise((resolve, reject) => { const req = http.get({ hostname: host, port: port, path: '/json', headers: { 'Host': 'localhost' } }, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => resolve(JSON.parse(data))); }); req.on('error', reject); }); heading('All CDP Targets'); for (const target of targetsJson) { log(`${CYAN}${target.type}${RESET}: ${target.title || target.url?.substring(0, 80)}`); } // Look for the kidlisp.com iframe target specifically const kidlispTarget = targetsJson.find(t => t.type === 'iframe' && t.url && t.url.includes('kidlisp.com') ); if (kidlispTarget) { heading('Found KidLisp.com iframe target!'); data('URL', kidlispTarget.url); data('ID', kidlispTarget.id); data('WebSocket URL', kidlispTarget.webSocketDebuggerUrl); // Connect directly to the kidlisp iframe let kidlispWsUrl = kidlispTarget.webSocketDebuggerUrl; if (kidlispWsUrl.includes('localhost')) { kidlispWsUrl = kidlispWsUrl.replace(/localhost(:\d+)?/, `${host}:${port}`); } info('Connecting directly to KidLisp iframe...'); const kidlispWs = new WebSocket(kidlispWsUrl); await new Promise((resolve, reject) => { kidlispWs.on('open', resolve); kidlispWs.on('error', reject); setTimeout(() => reject(new Error('Timeout')), 5000); }); success('Connected to KidLisp iframe!'); let kidlispMsgId = 1; const kidlispPending = new Map(); kidlispWs.on('message', (data) => { const msg = JSON.parse(data); if (msg.id && kidlispPending.has(msg.id)) { kidlispPending.get(msg.id)(msg); kidlispPending.delete(msg.id); } }); const evalKidlisp = (expr) => new Promise((resolve, reject) => { const id = kidlispMsgId++; const timer = setTimeout(() => reject(new Error('Timeout')), 10000); kidlispPending.set(id, (msg) => { clearTimeout(timer); resolve(msg.result?.result?.value); }); kidlispWs.send(JSON.stringify({ id, method: 'Runtime.evaluate', params: { expression: expr, returnByValue: true } })); }); // Now we can interact directly with the kidlisp.com page! heading('Exploring KidLisp.com page directly'); info('Checking for Monaco editor...'); const hasEditor = await evalKidlisp(`typeof editor !== 'undefined' && editor !== null`); data('Monaco editor available', hasEditor); if (hasEditor) { info('Getting current editor code...'); const code = await evalKidlisp(`editor.getValue()`); data('Current code', code?.substring(0, 200) + (code?.length > 200 ? '...' : '')); info('Checking playback state...'); const state = await evalKidlisp(`({ isPlaying, isPaused, pieceReady })`); data('Playback state', state); } info('Checking UI elements...'); const uiCheck = await evalKidlisp(`({ sendButton: !!document.getElementById('send-button'), stopButton: !!document.getElementById('stop-button'), clearButton: !!document.getElementById('clear-button'), consoleOutput: !!document.getElementById('console-output'), previewIframe: !!document.getElementById('preview-iframe'), themeToggle: !!document.getElementById('theme-toggle') })`); data('UI elements', uiCheck); info('Testing button click...'); const clickResult = await evalKidlisp(` (function() { const btn = document.getElementById('send-button'); if (btn) { return { found: true, disabled: btn.disabled, classes: btn.className }; } return { found: false }; })() `); data('Send button', clickResult); // Test setting code info('Testing code injection...'); const setCodeResult = await evalKidlisp(` (function() { if (typeof editor !== 'undefined') { const oldCode = editor.getValue(); editor.setValue('(ink red)\\n(box 50 50 100)'); const newCode = editor.getValue(); return { success: true, oldLength: oldCode.length, newLength: newCode.length }; } return { success: false, error: 'No editor' }; })() `); data('Set code result', setCodeResult); // Restore original code await evalKidlisp(` (function() { if (typeof editor !== 'undefined') { editor.setValue('(ink lime)\\n(box)'); } })() `); kidlispWs.close(); } // Find workbench const workbenchTarget = targetsJson.find(t => t.type === 'page' && t.url && t.url.includes('workbench.html') ); if (!workbenchTarget) { console.error('Could not find workbench'); process.exit(1); } let wsUrl = workbenchTarget.webSocketDebuggerUrl; if (wsUrl.includes('localhost')) { wsUrl = wsUrl.replace(/localhost(:\d+)?/, `${host}:${port}`); } const ws = new WebSocket(wsUrl); let msgId = 1; const pending = new Map(); ws.on('message', (data) => { const msg = JSON.parse(data); if (msg.id && pending.has(msg.id)) { pending.get(msg.id)(msg); pending.delete(msg.id); } }); await new Promise((resolve, reject) => { ws.on('open', resolve); ws.on('error', reject); setTimeout(() => reject(new Error('Timeout')), 5000); }); success('Connected to workbench'); const evaluate = (expr) => new Promise((resolve, reject) => { const id = msgId++; const timer = setTimeout(() => reject(new Error('Timeout')), 10000); pending.set(id, (msg) => { clearTimeout(timer); resolve(msg.result?.result?.value); }); ws.send(JSON.stringify({ id, method: 'Runtime.evaluate', params: { expression: expr, returnByValue: true } })); }); // Exploration queries heading('Looking for KidLisp webview...'); // 1. Check all iframes info('Checking iframes...'); const iframes = await evaluate(` (function() { const frames = Array.from(document.querySelectorAll('iframe')); return frames.map(f => ({ id: f.id, className: f.className, src: f.src?.substring(0, 100), title: f.title, name: f.name })); })() `); data('Iframes found', iframes); // 2. Check webviews info('Checking webview elements...'); const webviews = await evaluate(` (function() { const wvs = Array.from(document.querySelectorAll('webview')); return wvs.map(w => ({ id: w.id, className: w.className, src: w.src?.substring(0, 100), partition: w.partition })); })() `); data('Webviews found', webviews); // 3. Look for editor tabs / panels with KidLisp info('Checking for KidLisp in tabs/panels...'); const kidlispElements = await evaluate(` (function() { const results = []; // Look for tabs const tabs = Array.from(document.querySelectorAll('.tab')); for (const tab of tabs) { if (tab.textContent?.includes('KidLisp')) { results.push({ type: 'tab', text: tab.textContent, className: tab.className }); } } // Look for panel headers const headers = Array.from(document.querySelectorAll('.pane-header, .title')); for (const h of headers) { if (h.textContent?.includes('KidLisp')) { results.push({ type: 'header', text: h.textContent, className: h.className }); } } // Look for webview containers const containers = Array.from(document.querySelectorAll('[data-webview-id], .webview-container')); for (const c of containers) { results.push({ type: 'webview-container', id: c.getAttribute('data-webview-id') || c.id, className: c.className }); } return results; })() `); data('KidLisp elements', kidlispElements); // 4. Check editor group structure info('Checking editor groups...'); const editorGroups = await evaluate(` (function() { const groups = Array.from(document.querySelectorAll('.editor-group-container')); return groups.map(g => { const title = g.querySelector('.title')?.textContent; const tabs = Array.from(g.querySelectorAll('.tab')).map(t => t.textContent?.trim()); const iframe = g.querySelector('iframe'); return { title, tabs, hasIframe: !!iframe, iframeSrc: iframe?.src?.substring(0, 100) }; }); })() `); data('Editor groups', editorGroups); // 5. Try to find the specific webview iframe for KidLisp info('Searching for KidLisp webview iframe specifically...'); const kidlispWebview = await evaluate(` (function() { // VS Code uses nested iframes for webviews // First, find the webview container const containers = Array.from(document.querySelectorAll('.webview')); for (const container of containers) { // Check if this container's tab/title mentions KidLisp const parent = container.closest('.editor-instance, .editor-container'); const tab = parent?.querySelector('.tab.active'); if (tab?.textContent?.includes('KidLisp')) { // Found it! Get iframe details const iframe = container.querySelector('iframe'); if (iframe) { return { found: true, containerId: container.id, containerClass: container.className, iframeId: iframe.id, iframeSrc: iframe.src, iframeName: iframe.name }; } } } // Alternative: look through all iframes const allIframes = Array.from(document.querySelectorAll('iframe')); for (const iframe of allIframes) { if (iframe.src?.includes('kidlisp') || iframe.name?.includes('kidlisp')) { return { found: true, method: 'direct-iframe-search', iframeId: iframe.id, iframeSrc: iframe.src, iframeName: iframe.name, className: iframe.className }; } } return { found: false }; })() `); data('KidLisp webview', kidlispWebview); // 6. Try to access the webview's contentWindow info('Trying to access webview content...'); const contentAccess = await evaluate(` (function() { const allIframes = Array.from(document.querySelectorAll('iframe')); const results = []; for (const iframe of allIframes) { try { // Try to access contentWindow const hasAccess = !!iframe.contentWindow; const canPostMessage = typeof iframe.contentWindow?.postMessage === 'function'; results.push({ src: iframe.src?.substring(0, 60), hasAccess, canPostMessage, id: iframe.id, name: iframe.name }); } catch (e) { results.push({ src: iframe.src?.substring(0, 60), error: e.message }); } } return results; })() `); data('Content access results', contentAccess); // 7. Look for VS Code's internal webview tracking info('Checking VS Code webview API...'); const webviewApi = await evaluate(` (function() { // Check if we can access webview instances through VS Code internals if (typeof vscode !== 'undefined') { return { hasVscode: true }; } // Check for Monaco internals if (typeof monaco !== 'undefined') { return { hasMonaco: true }; } return { hasVscode: false, hasMonaco: false }; })() `); data('API access', webviewApi); // 8. Try posting a message to find the right iframe info('Broadcasting test message to all iframes...'); const broadcast = await evaluate(` (function() { const allIframes = Array.from(document.querySelectorAll('iframe')); let sent = 0; for (const iframe of allIframes) { try { iframe.contentWindow?.postMessage({ type: 'test:ping' }, '*'); sent++; } catch (e) {} } return { sent, total: allIframes.length }; })() `); data('Broadcast result', broadcast); heading('Summary'); log('Use these findings to build the test harness.'); log('The key is finding the correct iframe and being able to postMessage to it.'); ws.close(); process.exit(0);}
main().catch(err => { console.error('Error:', err); process.exit(1);});