CDP Connection Management #
Robust Chrome DevTools Protocol (CDP) connection system for Aesthetic Computer, designed for VS Code integration and devcontainer environments.
Overview #
The CDP system provides:
- Automatic target discovery - finds aesthetic.computer pages in VS Code
- Smart caching - remembers last connection for fast reconnection
- Connection pooling - reuses connections where possible
- Error resilience - handles disconnections and retries
- Multiple interfaces - Node.js module, CLI tools, and fish shell commands
Quick Start (Inside Devcontainer) #
When running VS Code inside the devcontainer (e.g., via Electron desktop app), CDP is directly accessible:
# List all CDP targets
curl -s http://localhost:9333/json | jq '.[].title'
# Find News webview
curl -s http://localhost:9333/json | jq '.[] | select(.url | contains("news"))'
# Find KidLisp.com editor
curl -s http://localhost:9333/json | jq '.[] | select(.url | contains("kidlisp.com"))'
Target hierarchy for webviews:
type: "page"— VS Code main workbench windowtype: "iframe"— Webview container (parentId = main page)type: "iframe"— Actual content iframe (e.g.,localhost:8888/news.aesthetic.computer)
Connect to the innermost iframe for page control.
Architecture #
┌─────────────────────────────────────────────────────────────┐
│ Windows Host (VS Code) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ VS Code with --remote-debugging-port=9333 │ │
│ │ ├─ Simple Browser: https://localhost:8888/prompt │ │
│ │ ├─ CDP targets exposed on port 9333 │ │
│ │ └─ SSH tunnel forwards to devcontainer │ │
│ └──────────────────────────────────────────────────────┘ │
│ ▲ │
│ │ port 9333 │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ DevContainer (Fedora Linux) │ │
│ │ ├─ artery/cdp.mjs - CDP connection module │ │
│ │ ├─ artery/cdp-cli.mjs - CLI tools │ │
│ │ ├─ dotfiles/fish/functions/ac-cdp.fish - shell cmds │ │
│ │ └─ artery/.cdp-cache.json - cached target │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Components #
1. artery/cdp.mjs - Core Module #
The main CDP connection manager.
import CDP, { createCDP, withCDP } from './artery/cdp.mjs';
// Manual connection
const cdp = new CDP({ targetUrl: 'https://localhost:8888/prompt' });
await cdp.connect();
const result = await cdp.eval('document.title');
cdp.close();
// Auto-connection helper
const cdp = await createCDP();
const result = await cdp.eval('2 + 2');
cdp.close();
// Auto-cleanup wrapper
await withCDP(async (cdp) => {
const title = await cdp.eval('document.title');
console.log(title);
});
Key Methods:
listTargets()- Get all CDP targetsfindAestheticPages()- Find localhost:8888 pagesfindPage(pattern)- Find specific page by URLconnect(target)- Connect to a target (auto-discovers if not provided)eval(expression)- Execute JavaScript in the pagesend(method, params)- Send CDP commandgetPageInfo()- Get page metadatawaitForReady()- Wait for page to loadcacheTarget(target)- Cache target for fast reconnectionloadCachedTarget()- Load cached targetclose()- Disconnect
Options:
const cdp = new CDP({
port: 9333, // CDP port (default: 9333)
targetUrl: 'https://localhost:8888', // URL pattern to find
verbose: true // Enable debug logging
});
2. artery/cdp-cli.mjs - CLI Tools #
Command-line interface for CDP management.
# List all targets
node artery/cdp-cli.mjs list
# Find a specific target
node artery/cdp-cli.mjs find prompt
# Test connection
node artery/cdp-cli.mjs connect
# Evaluate JavaScript
node artery/cdp-cli.mjs eval "document.title"
# Cache current page
node artery/cdp-cli.mjs cache
# Run connection tests
node artery/cdp-cli.mjs test
# Show help
node artery/cdp-cli.mjs help
3. Fish Shell Commands #
Convenient shell functions for CDP management.
# Show status
ac-cdp-status
# List targets
ac-cdp-list
# Find target
ac-cdp-find prompt
# Test connection
ac-cdp-test
# Connect to page
ac-cdp-connect
# Evaluate JS
ac-cdp-eval "document.title"
# Cache target
ac-cdp-cache
# Show help
ac-cdp-help
Usage Examples #
Basic Page Interaction #
import { withCDP } from './artery/cdp.mjs';
await withCDP(async (cdp) => {
// Get page info
const info = await cdp.getPageInfo();
console.log(`Title: ${info.title}`);
console.log(`URL: ${info.url}`);
// Execute code
const result = await cdp.eval(`
document.querySelector('h1')?.textContent
`);
console.log(result);
});
Performance Monitoring #
import { withCDP } from './artery/cdp.mjs';
await withCDP(async (cdp) => {
const metrics = await cdp.eval(`
(() => {
const entries = performance.getEntriesByType('resource');
return {
totalResources: entries.length,
totalDuration: entries.reduce((sum, e) => sum + e.duration, 0),
slowest: entries
.sort((a, b) => b.duration - a.duration)
.slice(0, 5)
.map(e => ({ name: e.name, duration: e.duration }))
};
})()
`);
console.log(metrics);
});
Multi-Target Discovery #
import CDP from './artery/cdp.mjs';
const cdp = new CDP();
const pages = await cdp.findAestheticPages();
console.log(`Found ${pages.length} aesthetic.computer pages:`);
pages.forEach(page => {
console.log(` ${page.url} (${page.type})`);
});
Cached Connection #
import { createCDP } from './artery/cdp.mjs';
// First connection - discovers and caches target
const cdp1 = await createCDP();
await cdp1.eval('console.log("first")');
cdp1.close();
// Second connection - uses cache (faster)
const cdp2 = await createCDP();
await cdp2.eval('console.log("second")');
cdp2.close();
Cache System #
The CDP system caches the last connected target in artery/.cdp-cache.json:
{
"id": "1D22CC826937AB2A7657C4662C203999",
"url": "https://localhost:8888/prompt",
"webSocketDebuggerUrl": "ws://localhost:9333/devtools/page/1D22CC826937AB2A7657C4662C203999",
"timestamp": 1734556800000
}
Cache Behavior:
- Auto-cached on successful connection
- Expires after 5 minutes
- Validated before use (checks if target still exists)
- Fallback to discovery if cache invalid
Manual Cache Management:
# Cache current page
ac-cdp-cache
# Clear cache
rm artery/.cdp-cache.json
# View cache
cat artery/.cdp-cache.json | jq
Error Handling #
The CDP system provides detailed error messages:
import { createCDP } from './artery/cdp.mjs';
try {
const cdp = await createCDP();
await cdp.eval('invalid syntax here');
} catch (err) {
console.error(err.message);
// "Evaluation failed: SyntaxError: Unexpected identifier"
}
Common Errors:
CDP port 9333 not accessible- VS Code not running or tunnel downNo aesthetic.computer pages found- App not open in Simple BrowserConnection timeout- Network issues or wrong portCached target no longer exists- Page closed, will auto-discoverEvaluation failed- JavaScript syntax error in eval()
Integration with Artery #
The existing Artery class now exports the CDP module:
import Artery, { CDP } from './artery/artery.mjs';
// Use Artery's connection (legacy)
const artery = new Artery();
await artery.connect();
const result = await artery.eval('2 + 2');
// Or use CDP directly (simpler)
import { withCDP } from './artery/cdp.mjs';
await withCDP(async (cdp) => {
const result = await cdp.eval('2 + 2');
});
Troubleshooting #
CDP Port Not Accessible #
# Check if port is open
ac-cdp-status
# Check VS Code is running with CDP enabled
# On Windows host, the aesthetic.ps1 script should launch with:
# code --remote-debugging-port=9333
No Aesthetic Pages Found #
# List all targets to see what's available
ac-cdp-list
# Make sure aesthetic.computer is open in Simple Browser
# URL should be https://localhost:8888/...
Connection Timeouts #
# Test connection
ac-cdp-test
# If it fails, check:
# 1. Is VS Code running?
# 2. Is the app loaded in Simple Browser?
# 3. Is the SSH tunnel working? (check aesthetic.ps1)
Cache Issues #
# Clear cache and reconnect
rm artery/.cdp-cache.json
ac-cdp-cache
# Check cache status
ac-cdp-status
Best Practices #
- Use
withCDPfor one-off scripts - auto-cleanup - Cache targets for frequent connections - faster startup
- Check
ac-cdp-statusbefore scripting - verify connectivity - Use verbose mode for debugging -
new CDP({ verbose: true }) - Handle errors gracefully - connection can fail
- Close connections when done - prevent resource leaks
Performance #
First connection (uncached):
- Target discovery: ~50-100ms
- WebSocket handshake: ~50-100ms
- Total: ~100-200ms
Cached connection:
- Cache validation: ~20-30ms
- WebSocket handshake: ~50-100ms
- Total: ~70-130ms
Evaluation overhead:
- Simple eval: ~5-10ms
- Complex eval: ~10-50ms
- DOM queries: ~20-100ms