
Browser Cdp
Prepare a Chrome CDP debug endpoint so agent-browser workflows can reuse your real Chrome profile and logged-in sessions.
Overview
Browser CDP is an agent skill for the Build phase that prepares Chrome with DevTools Protocol debugging so agent-browser can reuse your profile and login state.
Install
npx skills add https://github.com/worldwonderer/oh-story-claudecode --skill browser-cdpWhat is this skill?
- Cross-platform Node setup script for Chrome with CDP debugging
- Modes: detect-only, --dry-run, --reset profile, --yes non-interactive, --profile selection
- detect-only emits structured KEY=value status including CDP_STATUS, CDP_URL, CHROME_RUNNING
- Defined exit codes 0–3 for success, errors, user decline, and non-TTY consent
- Copies or refreshes ~/chrome-debug-profile so agents reuse login state
- Exit codes 0–3 documented for success, error, user refusal, and non-TTY consent
- detect-only structured stdout uses KEY=value lines including CDP_STATUS and CDP_URL
Adoption & trust: 2.8k installs on skills.sh; 2.1k GitHub stars; 0/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your browser automation agent cannot access sites you are already logged into because headless Chrome uses an empty profile.
Who is it for?
Solo builders automating QA or internal tools via Claude Code-style agents that must drive a logged-in Chrome on macOS, Windows, or Linux.
Skip if: Production scrape farms, teams forbidden from restarting user Chrome, or workflows that only need static HTTP APIs without a real browser.
When should I use this skill?
Agent-browser or similar tooling needs a CDP-ready Chrome with optional profile copy and readiness detection before automation runs.
What do I get? / Deliverables
Chrome exposes a CDP URL with a copied debug profile so agent-browser sessions run against your authenticated browser context.
- CDP endpoint URL when ready
- Structured detect-only status report
- Configured chrome-debug-profile directory
Recommended Skills
Journey fit
Build/agent-tooling is where you wire browser automation infrastructure before agents run headed or CDP-backed flows. Agent-tooling matches setup scripts that connect coding agents to Chrome DevTools Protocol rather than shipping product UI.
How it compares
Local CDP bridge to your Chrome profile—not Playwright codegen alone and not a hosted remote browser farm.
Common Questions / FAQ
Who is browser-cdp for?
Developers using agent-browser or similar agents who need CDP access to their normal Chrome install and saved logins.
When should I use browser-cdp?
During Build while setting up agent-tooling, before running authenticated UI automation, E2E checks, or scripted flows that depend on an existing Chrome session.
Is browser-cdp safe to install?
The script can kill Chrome processes and copy profile data under your home directory; review SKILL.md and the Security Audits panel on this Prism page before running with --yes in automated agents.
SKILL.md
READMESKILL.md - Browser Cdp
#!/usr/bin/env node // setup-cdp-chrome.js // 准备带有 CDP(Chrome DevTools Protocol)调试功能的 Chrome 环境(跨平台)。 // 通过此脚本,agent-browser 可以复用用户的 Chrome 登录态。 // // 用法: // node setup-cdp-chrome.js [port] [options] // // Options: // --detect-only 只探测当前状态(结构化输出),不做任何修改 // --yes 确认杀死现有 Chrome,跳过交互提示 // --reset 清空 ~/chrome-debug-profile 后重新复制 // --profile <name> 使用指定 Chrome profile(默认: Default) // --dry-run 打印将执行的操作,不实际执行 // // 退出码: // 0 成功 / detect-only 完成 // 1 通用错误(环境缺失、超时等) // 2 用户拒绝(TTY 模式下回答 N) // 3 需要同意但当前为非 TTY 且未传 --yes // // detect-only 结构化输出(stdout,每行 KEY=value): // CDP_STATUS=ready|needs-setup // CDP_URL=... (仅当 ready) // BROWSER=... (仅当 ready) // CHROME_RUNNING=yes|no // CHROME_PID_COUNT=N (仅当 CHROME_RUNNING=yes) "use strict"; const { execSync, spawn } = require("child_process"); const fs = require("fs"); const http = require("http"); const os = require("os"); const path = require("path"); const readline = require("readline"); // --------------------------------------------------------------------------- // 参数解析 // --------------------------------------------------------------------------- function parseArgs(argv) { const flags = { dryRun: false, yes: false, detectOnly: false, reset: false }; let profile = "Default"; let port = null; for (let i = 0; i < argv.length; i++) { const a = argv[i]; switch (a) { case "--dry-run": flags.dryRun = true; break; case "--yes": case "-y": flags.yes = true; break; case "--detect-only": flags.detectOnly = true; break; case "--reset": flags.reset = true; break; case "--profile": profile = argv[++i]; if (!profile) { console.error("❌ --profile 需要一个参数(例如: --profile \"Profile 1\")"); process.exit(1); } break; default: if (/^\d+$/.test(a)) { port = parseInt(a, 10); } else if (a.startsWith("--")) { console.error(`⚠️ 未知参数: ${a}`); } else { console.error(`⚠️ 忽略参数: ${a}`); } } } if (port === null) port = 9222; if (!Number.isInteger(port) || port < 1 || port > 65535) { console.error(`❌ 端口非法: ${port}。必须是 1-65535 的整数。`); process.exit(1); } return { flags, profile, port }; } const ARGS = parseArgs(process.argv.slice(2)); const CDP_PORT = ARGS.port; const PLATFORM = os.platform(); // --------------------------------------------------------------------------- // 平台配置映射 // --------------------------------------------------------------------------- const PLATFORM_CONFIG = { darwin: { chromePaths: [ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", ], profileDir: path.join( os.homedir(), "Library", "Application Support", "Google", "Chrome" ), findChrome() { for (const p of this.chromePaths) if (fs.existsSync(p)) return p; return null; }, listChromePids() { try { const out = execSync("pgrep -x 'Google Chrome'", { encoding: "utf-8" }).trim(); return out.split("\n").map(Number).filter((n) => n > 0); } catch { return []; } }, killChrome() { try { execSync("pkill -9 -x 'Google Chrome'", { stdio: "ignore" }); } catch {} }, }, win32: { chromePaths: [ path.join(process.env["PROGRAMFILES(X86)"] || "", "Google", "Chrome", "Application", "chrome.exe"), path.join(process.env.PROGRAMFILES || "", "Google", "Chrome", "Application", "chrome.exe"), path.join(process.env.LOCALAPPDATA || "", "Google", "Chrome", "Application", "chrome.exe"), ], profileDir: path.join( process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local"), "Google", "Chrome", "User Data" ), findChrome() { for (const p of this.chromePaths) if (p && fs.existsSync(p)) return p; return null; }, listChrom