Monorepo for Aesthetic.Computer aesthetic.computer
core artery CDP-SYSTEM.md
11 kB

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:

  1. type: "page" — VS Code main workbench window
  2. type: "iframe" — Webview container (parentId = main page)
  3. 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 targets
  • findAestheticPages() - Find localhost:8888 pages
  • findPage(pattern) - Find specific page by URL
  • connect(target) - Connect to a target (auto-discovers if not provided)
  • eval(expression) - Execute JavaScript in the page
  • send(method, params) - Send CDP command
  • getPageInfo() - Get page metadata
  • waitForReady() - Wait for page to load
  • cacheTarget(target) - Cache target for fast reconnection
  • loadCachedTarget() - Load cached target
  • close() - 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 down
  • No aesthetic.computer pages found - App not open in Simple Browser
  • Connection timeout - Network issues or wrong port
  • Cached target no longer exists - Page closed, will auto-discover
  • Evaluation 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 #

  1. Use withCDP for one-off scripts - auto-cleanup
  2. Cache targets for frequent connections - faster startup
  3. Check ac-cdp-status before scripting - verify connectivity
  4. Use verbose mode for debugging - new CDP({ verbose: true })
  5. Handle errors gracefully - connection can fail
  6. 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

Future Enhancements #