web-probe-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/state.ts","../src/utils/platform.ts","../src/core/port-manager.ts","../src/core/chrome-launcher.ts","../src/core/output.ts","../src/commands/chrome.ts","../src/core/cdp-client.ts","../src/commands/tabs.ts","../src/commands/inspect.ts","../src/commands/shot.ts","../src/commands/eval.ts","../src/commands/click.ts","../src/commands/type.ts","../src/commands/nav.ts","../src/commands/html.ts","../src/utils/detect-tools.ts","../src/commands/doctor.ts","../src/commands/setup.ts","../src/commands/explore.ts","../src/commands/skill.ts","../src/index.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { homedir } from 'node:os'\n\nexport interface PortState {\n port: number\n pid: number\n startedAt: string\n timeoutMinutes: number\n lastActivityAt: string\n}\n\nconst STATE_DIR = join(homedir(), '.web-probe')\nconst STATE_FILE = join(STATE_DIR, 'state.json')\n\nfunction ensureDir(): void {\n if (!existsSync(STATE_DIR)) {\n mkdirSync(STATE_DIR, { recursive: true })\n }\n}\n\nexport function loadState(): PortState | null {\n try {\n if (!existsSync(STATE_FILE)) return null\n const raw = readFileSync(STATE_FILE, 'utf-8')\n return JSON.parse(raw) as PortState\n } catch {\n return null\n }\n}\n\nexport function saveState(port: number, pid: number, timeoutMinutes = 30): void {\n ensureDir()\n const state: PortState = {\n port,\n pid,\n startedAt: new Date().toISOString(),\n timeoutMinutes,\n lastActivityAt: new Date().toISOString(),\n }\n writeFileSync(STATE_FILE, JSON.stringify(state, null, 2), 'utf-8')\n try {\n chmodSync(STATE_FILE, 0o600)\n } catch {\n // Windows may not support chmod\n }\n}\n\nexport function updateActivity(): void {\n const state = loadState()\n if (!state) return\n state.lastActivityAt = new Date().toISOString()\n ensureDir()\n writeFileSync(STATE_FILE, JSON.stringify(state, null, 2), 'utf-8')\n}\n\nexport function clearState(): void {\n try {\n if (existsSync(STATE_FILE)) {\n unlinkSync(STATE_FILE)\n }\n } catch {\n // ignore\n }\n}\n\nexport function getStateDir(): string {\n return STATE_DIR\n}\n\n/**\n * 检查调试端口是否因超时需要自动关闭。\n * 返回 true 表示已超时并已清理状态,调用方应跳过端口操作。\n */\nexport function checkTimeout(): { expired: boolean; minutesIdle: number } {\n const state = loadState()\n if (!state) return { expired: false, minutesIdle: 0 }\n\n const lastActivity = new Date(state.lastActivityAt).getTime()\n const now = Date.now()\n const minutesIdle = (now - lastActivity) / 1000 / 60\n\n if (minutesIdle >= state.timeoutMinutes) {\n return { expired: true, minutesIdle: Math.round(minutesIdle) }\n }\n\n return { expired: false, minutesIdle: Math.round(minutesIdle) }\n}\n","import { existsSync } from 'node:fs'\nimport { execSync } from 'node:child_process'\nimport { platform } from 'node:os'\n\nexport type Platform = 'darwin' | 'linux' | 'win32'\n\nconst CHROME_PATHS: Record<Platform, string[]> = {\n darwin: [\n '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',\n '/Applications/Chromium.app/Contents/MacOS/Chromium',\n ],\n linux: [\n '/usr/bin/google-chrome',\n '/usr/bin/google-chrome-stable',\n '/usr/bin/chromium-browser',\n '/usr/bin/chromium',\n '/snap/bin/chromium',\n ],\n win32: [\n `${process.env.PROGRAMFILES}\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n `${process.env['PROGRAMFILES(X86)']}\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n `${process.env.LOCALAPPDATA}\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n ],\n}\n\nexport function getPlatform(): Platform {\n return platform() as Platform\n}\n\nexport function findChromePath(): string | null {\n const plat = getPlatform()\n const candidates = CHROME_PATHS[plat] ?? []\n\n for (const p of candidates) {\n if (p && existsSync(p)) return p\n }\n\n try {\n if (plat === 'win32') {\n const result = execSync('where chrome.exe 2>nul', { encoding: 'utf-8' }).trim()\n const first = result.split('\\n')[0]?.trim()\n if (first && existsSync(first)) return first\n } else {\n const result = execSync('which google-chrome 2>/dev/null || which chromium 2>/dev/null', {\n encoding: 'utf-8',\n }).trim()\n if (result) return result\n }\n } catch {\n // not found\n }\n\n return null\n}\n\nexport function getChromeVersion(chromePath: string): string | null {\n const plat = getPlatform()\n try {\n if (plat === 'darwin') {\n const plistPath = chromePath.replace('/MacOS/Google Chrome', '/Info.plist')\n const output = execSync(\n `/usr/libexec/PlistBuddy -c \"Print CFBundleShortVersionString\" \"${plistPath}\" 2>/dev/null`,\n { encoding: 'utf-8' },\n ).trim()\n return output || null\n }\n if (plat === 'win32') {\n const output = execSync(\n `powershell -NoProfile -Command \"(Get-Item '${chromePath}').VersionInfo.FileVersion\"`,\n { encoding: 'utf-8', stdio: 'pipe' },\n ).trim()\n return output || null\n }\n const output = execSync(`\"${chromePath}\" --version 2>/dev/null`, { encoding: 'utf-8' }).trim()\n const match = output.match(/[\\d.]+/)\n return match ? match[0] : null\n } catch {\n return null\n }\n}\n\nexport function getOpenCommand(): string {\n const plat = getPlatform()\n if (plat === 'darwin') return 'open -a'\n if (plat === 'win32') return 'start'\n return 'xdg-open'\n}\n","import { execSync } from 'node:child_process'\nimport { loadState } from './state.js'\nimport { getPlatform } from '../utils/platform.js'\n\nconst PORT_MIN = 20000\nconst PORT_MAX = 29999\n\nexport function generatePort(): number {\n return Math.floor(Math.random() * (PORT_MAX - PORT_MIN + 1)) + PORT_MIN\n}\n\nexport async function verifyPort(port: number): Promise<boolean> {\n try {\n const resp = await fetch(`http://127.0.0.1:${port}/json/version`, {\n signal: AbortSignal.timeout(3000),\n })\n if (!resp.ok) return false\n const data = (await resp.json()) as Record<string, unknown>\n return typeof data['Browser'] === 'string'\n } catch {\n return false\n }\n}\n\nexport function discoverFromProcess(): number | null {\n const plat = getPlatform()\n\n try {\n if (plat === 'win32') {\n const output = execSync(\n 'powershell -NoProfile -Command \"Get-CimInstance Win32_Process -Filter \\\\\"Name=\\'chrome.exe\\'\\\\\" | Select-Object -ExpandProperty CommandLine\"',\n { encoding: 'utf-8', stdio: 'pipe' },\n )\n const match = output.match(/--remote-debugging-port=(\\d+)/)\n if (match) return parseInt(match[1], 10)\n } else {\n const output = execSync(\n \"ps aux | grep -E 'remote-debugging-port=' | grep -v grep\",\n { encoding: 'utf-8' },\n )\n const match = output.match(/--remote-debugging-port=(\\d+)/)\n if (match) return parseInt(match[1], 10)\n }\n } catch {\n // no process found\n }\n return null\n}\n\nexport async function discoverPort(): Promise<number | null> {\n const state = loadState()\n if (state?.port) {\n const valid = await verifyPort(state.port)\n if (valid) return state.port\n }\n\n const fromProcess = discoverFromProcess()\n if (fromProcess) {\n const valid = await verifyPort(fromProcess)\n if (valid) return fromProcess\n }\n\n for (const fallback of [9222, 19222]) {\n const valid = await verifyPort(fallback)\n if (valid) return fallback\n }\n\n return null\n}\n\nexport async function waitForPort(port: number, timeoutMs = 10000): Promise<boolean> {\n const start = Date.now()\n while (Date.now() - start < timeoutMs) {\n if (await verifyPort(port)) return true\n await new Promise((r) => setTimeout(r, 500))\n }\n return false\n}\n","import { spawn, execSync } from 'node:child_process'\nimport { findChromePath, getPlatform } from '../utils/platform.js'\nimport { saveState, loadState, clearState } from './state.js'\nimport { generatePort, waitForPort, verifyPort, discoverPort } from './port-manager.js'\n\nexport interface LaunchResult {\n port: number\n pid: number\n alreadyRunning: boolean\n}\n\nfunction isChromeRunning(): boolean {\n const plat = getPlatform()\n try {\n if (plat === 'darwin') {\n const out = execSync(\"pgrep -f 'Google Chrome' 2>/dev/null || true\", { encoding: 'utf-8' })\n return out.trim().length > 0\n }\n if (plat === 'linux') {\n const out = execSync(\"pgrep -f '(chrome|chromium)' 2>/dev/null || true\", { encoding: 'utf-8' })\n return out.trim().length > 0\n }\n if (plat === 'win32') {\n const out = execSync('tasklist /FI \"IMAGENAME eq chrome.exe\" /NH 2>nul', { encoding: 'utf-8' })\n return out.toLowerCase().includes('chrome.exe')\n }\n return false\n } catch {\n return false\n }\n}\n\nexport async function launchChrome(requestedPort?: number): Promise<LaunchResult> {\n const existingPort = await discoverPort()\n if (existingPort) {\n const state = loadState()\n return {\n port: existingPort,\n pid: state?.pid ?? 0,\n alreadyRunning: true,\n }\n }\n\n const port = requestedPort ?? generatePort()\n const chromePath = findChromePath()\n if (!chromePath) {\n throw new Error('未找到 Chrome 浏览器,请先安装 Google Chrome')\n }\n\n const running = isChromeRunning()\n if (running) {\n throw new Error(\n 'Chrome 已在运行但未开启调试端口。\\n' +\n '请先关闭所有 Chrome 窗口,然后重新运行 web-probe chrome start。\\n' +\n '(无法为已运行的 Chrome 追加调试参数)',\n )\n }\n\n const plat = getPlatform()\n const args = [\n `--remote-debugging-port=${port}`,\n '--no-first-run',\n '--no-default-browser-check',\n ]\n\n const child = spawn(chromePath, args, {\n detached: true,\n stdio: 'ignore',\n shell: plat === 'win32',\n })\n\n child.unref()\n const pid = child.pid ?? 0\n\n const ready = await waitForPort(port, 15000)\n if (!ready) {\n throw new Error(`Chrome 调试端口 ${port} 启动超时(15秒),请检查 Chrome 是否正常运行`)\n }\n\n saveState(port, pid)\n\n return { port, pid, alreadyRunning: false }\n}\n\nexport async function stopChrome(): Promise<{ port: number } | null> {\n const state = loadState()\n if (!state) return null\n\n const { port, pid } = state\n\n if (pid > 0) {\n try {\n process.kill(pid, 'SIGTERM')\n } catch {\n if (getPlatform() === 'win32') {\n try {\n execSync(`taskkill /PID ${pid} /F 2>nul`, { stdio: 'pipe' })\n } catch { /* already gone */ }\n }\n }\n }\n\n clearState()\n return { port }\n}\n\nexport async function getChromeStatus(): Promise<{\n running: boolean\n port?: number\n pid?: number\n startedAt?: string\n}> {\n const state = loadState()\n if (!state) {\n const discovered = await discoverPort()\n if (discovered) {\n return { running: true, port: discovered }\n }\n return { running: false }\n }\n\n const valid = await verifyPort(state.port)\n if (!valid) {\n clearState()\n return { running: false }\n }\n\n return {\n running: true,\n port: state.port,\n pid: state.pid,\n startedAt: state.startedAt,\n }\n}\n","import chalk from 'chalk'\n\nexport function printJSON(data: unknown): void {\n console.log(JSON.stringify(data, null, 2))\n}\n\nexport function printTable(headers: string[], rows: string[][]): void {\n const colWidths = headers.map((h, i) => {\n const maxData = rows.reduce((max, row) => Math.max(max, (row[i] ?? '').length), 0)\n return Math.max(h.length, maxData)\n })\n\n const headerLine = headers.map((h, i) => h.padEnd(colWidths[i])).join(' ')\n console.log(chalk.bold(headerLine))\n\n for (const row of rows) {\n const line = row.map((cell, i) => (cell ?? '').padEnd(colWidths[i])).join(' ')\n console.log(line)\n }\n}\n\nexport function printSuccess(message: string): void {\n console.log(chalk.green('✅ ' + message))\n}\n\nexport function printError(message: string): void {\n console.error(chalk.red('❌ ' + message))\n}\n\nexport function printWarn(message: string): void {\n console.log(chalk.yellow('⚠️ ' + message))\n}\n\nexport function printInfo(message: string): void {\n console.log(chalk.blue('ℹ️ ' + message))\n}\n\nexport function printStatus(label: string, ok: boolean, detail: string): void {\n const badge = ok ? chalk.green('[OK] ') : chalk.yellow('[WARN] ')\n console.log(` ${badge} ${label}${detail ? ` (${detail})` : ''}`)\n}\n\nexport function printHeader(title: string): void {\n console.log()\n console.log(chalk.bold(title))\n console.log()\n}\n\nexport function truncate(str: string, maxLen: number): string {\n if (str.length <= maxLen) return str\n return str.slice(0, maxLen - 3) + '...'\n}\n","import { launchChrome, stopChrome, getChromeStatus } from '../core/chrome-launcher.js'\nimport { printSuccess, printError, printInfo, printJSON } from '../core/output.js'\n\nexport async function chromeStart(options: { port?: string; json?: boolean }): Promise<void> {\n try {\n const port = options.port ? parseInt(options.port, 10) : undefined\n const result = await launchChrome(port)\n\n if (options.json) {\n printJSON(result)\n return\n }\n\n if (result.alreadyRunning) {\n printInfo(`调试端口已开启 (端口 ${result.port})`)\n } else {\n printSuccess(`Chrome 调试端口已启动 (端口 ${result.port}, PID ${result.pid})`)\n }\n } catch (err) {\n if (options.json) {\n printJSON({ error: (err as Error).message })\n process.exitCode = 1\n return\n }\n printError((err as Error).message)\n process.exitCode = 1\n }\n}\n\nexport async function chromeStop(options: { json?: boolean }): Promise<void> {\n const result = await stopChrome()\n\n if (options.json) {\n printJSON(result ? { stopped: true, port: result.port } : { stopped: false })\n return\n }\n\n if (result) {\n printSuccess(`调试端口已关闭 (端口 ${result.port})`)\n printInfo('Chrome 浏览器继续运行,登录状态不受影响')\n } else {\n printInfo('没有活跃的调试端口')\n }\n}\n\nexport async function chromeStatus(options: { json?: boolean }): Promise<void> {\n const status = await getChromeStatus()\n\n if (options.json) {\n printJSON(status)\n return\n }\n\n if (status.running) {\n printSuccess(`调试端口运行中 (端口 ${status.port}${status.pid ? `, PID ${status.pid}` : ''})`)\n if (status.startedAt) {\n printInfo(`启动时间: ${status.startedAt}`)\n }\n } else {\n printInfo('调试端口未运行')\n }\n}\n\nexport async function chromeRestart(options: { json?: boolean }): Promise<void> {\n await stopChrome()\n await chromeStart({ json: options.json })\n}\n","import CDP, { type Client } from 'chrome-remote-interface'\nimport { discoverPort } from './port-manager.js'\nimport { updateActivity } from './state.js'\n\nexport interface Tab {\n id: string\n url: string\n title: string\n type: string\n}\n\nexport interface PageInfo {\n url: string\n title: string\n meta: Record<string, string>\n headings: Array<{ tag: string; text: string }>\n buttons: string[]\n links: Array<{ text: string; href: string }>\n inputs: Array<{ type: string; placeholder: string; name: string }>\n images: number\n frameworks: string[]\n bodyTextPreview: string\n}\n\nasync function getPort(): Promise<number> {\n const port = await discoverPort()\n if (!port) {\n throw new Error(\n '未发现 Chrome 调试端口。请先运行:web-probe chrome start',\n )\n }\n updateActivity()\n return port\n}\n\nexport async function listTabs(): Promise<Tab[]> {\n const port = await getPort()\n const targets = await CDP.List({ port }) as Array<{\n id: string\n url: string\n title: string\n type: string\n }>\n\n return targets\n .filter((t) => t.type === 'page')\n .map((t) => ({\n id: t.id,\n url: t.url,\n title: t.title,\n type: t.type,\n }))\n}\n\nexport function resolveTabId(tabs: Tab[], target: string): Tab | undefined {\n return tabs.find((t) => t.id === target) ??\n tabs.find((t) => t.url.includes(target)) ??\n tabs[parseInt(target, 10)]\n}\n\nasync function connectTab(tabId: string): Promise<Client> {\n const port = await getPort()\n const client = await CDP({ port, target: tabId })\n return client\n}\n\nexport async function evaluateInTab(tabId: string, expression: string): Promise<unknown> {\n const client = await connectTab(tabId)\n try {\n await client.Runtime.enable()\n const result = await client.Runtime.evaluate({\n expression,\n returnByValue: true,\n awaitPromise: true,\n })\n if (result.exceptionDetails) {\n throw new Error(\n result.exceptionDetails.text ??\n result.exceptionDetails.exception?.description ??\n 'JavaScript 执行错误',\n )\n }\n return result.result.value\n } finally {\n await client.close()\n }\n}\n\nexport async function screenshotTab(tabId: string): Promise<Buffer> {\n const client = await connectTab(tabId)\n try {\n await client.Page.enable()\n const { data } = await client.Page.captureScreenshot({ format: 'png' })\n return Buffer.from(data, 'base64')\n } finally {\n await client.close()\n }\n}\n\nexport async function inspectPage(tabId: string): Promise<PageInfo> {\n const expression = `\n (() => {\n const getMeta = () => {\n const metas = {};\n document.querySelectorAll('meta[name], meta[property]').forEach(m => {\n const key = m.getAttribute('name') || m.getAttribute('property');\n if (key) metas[key] = m.getAttribute('content') || '';\n });\n return metas;\n };\n\n const getHeadings = () =>\n [...document.querySelectorAll('h1,h2,h3,h4,h5,h6')].slice(0, 20).map(h => ({\n tag: h.tagName,\n text: h.textContent?.trim().slice(0, 100) || ''\n }));\n\n const getButtons = () =>\n [...document.querySelectorAll('button, [role=\"button\"], input[type=\"submit\"], input[type=\"button\"]')]\n .slice(0, 30)\n .map(b => b.textContent?.trim().slice(0, 50) || b.getAttribute('aria-label') || '')\n .filter(Boolean);\n\n const getLinks = () =>\n [...document.querySelectorAll('a[href]')].slice(0, 30).map(a => ({\n text: (a.textContent?.trim().slice(0, 50) || a.getAttribute('aria-label') || ''),\n href: a.getAttribute('href') || ''\n })).filter(l => l.text);\n\n const getInputs = () =>\n [...document.querySelectorAll('input, textarea, select')].slice(0, 20).map(el => ({\n type: el.tagName.toLowerCase() === 'textarea' ? 'textarea' :\n el.tagName.toLowerCase() === 'select' ? 'select' :\n el.getAttribute('type') || 'text',\n placeholder: el.getAttribute('placeholder') || '',\n name: el.getAttribute('name') || el.getAttribute('id') || ''\n }));\n\n const detectFrameworks = () => {\n const f = [];\n if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__ || document.querySelector('[data-reactroot]')) f.push('React');\n if (window.__VUE__) f.push('Vue');\n if (window.angular || document.querySelector('[ng-app], [data-ng-app]')) f.push('Angular');\n if (document.querySelector('.ant-btn, .ant-layout, .ant-table')) f.push('Ant Design');\n if (document.querySelector('.el-button, .el-table, .el-input')) f.push('Element UI');\n if (document.querySelector('.v-application, .v-btn')) f.push('Vuetify');\n if (document.querySelector('[class*=\"MuiButton\"], [class*=\"MuiPaper\"]')) f.push('Material UI');\n return f;\n };\n\n const bodyText = document.body?.innerText?.trim().slice(0, 500) || '';\n\n return JSON.stringify({\n url: location.href,\n title: document.title,\n meta: getMeta(),\n headings: getHeadings(),\n buttons: getButtons(),\n links: getLinks(),\n inputs: getInputs(),\n images: document.querySelectorAll('img').length,\n frameworks: detectFrameworks(),\n bodyTextPreview: bodyText\n });\n })()\n `\n\n const result = await evaluateInTab(tabId, expression) as string\n return JSON.parse(result) as PageInfo\n}\n\nexport async function clickElement(tabId: string, selector: string): Promise<void> {\n await evaluateInTab(tabId, `\n (() => {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (!el) throw new Error('元素未找到: ' + ${JSON.stringify(selector)});\n el.click();\n return 'clicked';\n })()\n `)\n}\n\nexport async function typeInElement(tabId: string, selector: string, text: string): Promise<void> {\n await evaluateInTab(tabId, `\n (() => {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (!el) throw new Error('元素未找到: ' + ${JSON.stringify(selector)});\n el.focus();\n el.value = ${JSON.stringify(text)};\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n return 'typed';\n })()\n `)\n}\n\nexport async function navigateTab(tabId: string, url: string): Promise<void> {\n const client = await connectTab(tabId)\n try {\n await client.Page.enable()\n await client.Page.navigate({ url })\n await client.Page.loadEventFired()\n } finally {\n await client.close()\n }\n}\n\nexport async function getHTML(tabId: string, selector?: string): Promise<string> {\n if (selector) {\n return (await evaluateInTab(tabId, `\n (() => {\n const el = document.querySelector(${JSON.stringify(selector)});\n return el ? el.outerHTML : null;\n })()\n `)) as string\n }\n return (await evaluateInTab(tabId, 'document.documentElement.outerHTML')) as string\n}\n","import { listTabs } from '../core/cdp-client.js'\nimport { printJSON, printTable, printError, truncate } from '../core/output.js'\n\nexport async function tabsCommand(options: { json?: boolean }): Promise<void> {\n try {\n const tabs = await listTabs()\n\n if (options.json) {\n printJSON(tabs)\n return\n }\n\n if (tabs.length === 0) {\n console.log('没有打开的标签页')\n return\n }\n\n printTable(\n ['ID', 'URL', 'TITLE'],\n tabs.map((t) => [t.id.slice(0, 8), truncate(t.url, 55), truncate(t.title, 40)]),\n )\n } catch (err) {\n if (options.json) {\n printJSON({ error: (err as Error).message })\n process.exitCode = 1\n return\n }\n printError((err as Error).message)\n process.exitCode = 1\n }\n}\n","import { inspectPage, listTabs, resolveTabId } from '../core/cdp-client.js'\nimport { printJSON, printError } from '../core/output.js'\n\nexport async function inspectCommand(target: string, options: { json?: boolean }): Promise<void> {\n try {\n const tabs = await listTabs()\n const tab = resolveTabId(tabs, target)\n if (!tab) {\n throw new Error(`未找到标签页: ${target}\\n使用 web-probe tabs 查看可用标签页`)\n }\n\n const info = await inspectPage(tab.id)\n\n if (options.json !== false) {\n printJSON(info)\n } else {\n printJSON(info)\n }\n } catch (err) {\n if (options.json) {\n printJSON({ error: (err as Error).message })\n process.exitCode = 1\n return\n }\n printError((err as Error).message)\n process.exitCode = 1\n }\n}\n","import { writeFileSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { tmpdir } from 'node:os'\nimport { screenshotTab, listTabs, resolveTabId } from '../core/cdp-client.js'\nimport { printJSON, printSuccess, printError } from '../core/output.js'\n\nasync function shotByUrl(url: string, outputPath?: string): Promise<string> {\n const { chromium } = await import('playwright-core')\n const browser = await chromium.launch({ headless: true })\n try {\n const page = await browser.newPage()\n await page.goto(url, { waitUntil: 'networkidle' })\n const outDir = join(tmpdir(), 'web-probe')\n mkdirSync(outDir, { recursive: true })\n const filename = outputPath ?? join(outDir, `shot-url-${Date.now()}.png`)\n await page.screenshot({ path: filename, fullPage: true })\n return filename\n } finally {\n await browser.close()\n }\n}\n\nexport async function shotCommand(target: string, options: { output?: string; json?: boolean }): Promise<void> {\n try {\n let filePath: string\n\n if (target.startsWith('http://') || target.startsWith('https://')) {\n filePath = await shotByUrl(target, options.output)\n } else {\n const tabs = await listTabs()\n const tab = resolveTabId(tabs, target)\n if (!tab) {\n throw new Error(`未找到标签页: ${target}\\n使用 web-probe tabs 查看可用标签页`)\n }\n\n const buffer = await screenshotTab(tab.id)\n const outDir = join(tmpdir(), 'web-probe')\n mkdirSync(outDir, { recursive: true })\n filePath = options.output ?? join(outDir, `shot-${tab.id.slice(0, 8)}-${Date.now()}.png`)\n writeFileSync(filePath, buffer)\n }\n\n if (options.json) {\n printJSON({ path: filePath })\n } else {\n printSuccess(`截图已保存: ${filePath}`)\n }\n } catch (err) {\n if (options.json) {\n printJSON({ error: (err as Error).message })\n process.exitCode = 1\n return\n }\n printError((err as Error).message)\n process.exitCode = 1\n }\n}\n","import { evaluateInTab, listTabs, resolveTabId } from '../core/cdp-client.js'\nimport { printJSON, printError } from '../core/output.js'\n\nexport async function evalCommand(target: string, javascript: string, options: { json?: boolean }): Promise<void> {\n try {\n const tabs = await listTabs()\n const tab = resolveTabId(tabs, target)\n if (!tab) {\n throw new Error(`未找到标签页: ${target}\\n使用 web-probe tabs 查看可用标签页`)\n }\n\n const result = await evaluateInTab(tab.id, javascript)\n\n if (options.json) {\n printJSON({ result })\n } else {\n if (typeof result === 'string') {\n console.log(result)\n } else {\n printJSON(result)\n }\n }\n } catch (err) {\n if (options.json) {\n printJSON({ error: (err as Error).message })\n process.exitCode = 1\n return\n }\n printError((err as Error).message)\n process.exitCode = 1\n }\n}\n","import { clickElement, listTabs, resolveTabId } from '../core/cdp-client.js'\nimport { printJSON, printSuccess, printError } from '../core/output.js'\n\nexport async function clickCommand(target: string, selector: string, options: { json?: boolean }): Promise<void> {\n try {\n const tabs = await listTabs()\n const tab = resolveTabId(tabs, target)\n if (!tab) {\n throw new Error(`未找到标签页: ${target}\\n使用 web-probe tabs 查看可用标签页`)\n }\n\n await clickElement(tab.id, selector)\n\n if (options.json) {\n printJSON({ success: true, selector })\n } else {\n printSuccess(`已点击: ${selector}`)\n }\n } catch (err) {\n if (options.json) {\n printJSON({ error: (err as Error).message })\n process.exitCode = 1\n return\n }\n printError((err as Error).message)\n process.exitCode = 1\n }\n}\n","import { typeInElement, listTabs, resolveTabId } from '../core/cdp-client.js'\nimport { printJSON, printSuccess, printError } from '../core/output.js'\n\nexport async function typeCommand(\n target: string,\n selector: string,\n text: string,\n options: { json?: boolean },\n): Promise<void> {\n try {\n const tabs = await listTabs()\n const tab = resolveTabId(tabs, target)\n if (!tab) {\n throw new Error(`未找到标签页: ${target}\\n使用 web-probe tabs 查看可用标签页`)\n }\n\n await typeInElement(tab.id, selector, text)\n\n if (options.json) {\n printJSON({ success: true, selector, text })\n } else {\n printSuccess(`已输入: \"${text}\" → ${selector}`)\n }\n } catch (err) {\n if (options.json) {\n printJSON({ error: (err as Error).message })\n process.exitCode = 1\n return\n }\n printError((err as Error).message)\n process.exitCode = 1\n }\n}\n","import { navigateTab, listTabs, resolveTabId } from '../core/cdp-client.js'\nimport { printJSON, printSuccess, printError } from '../core/output.js'\n\nexport async function navCommand(target: string, url: string, options: { json?: boolean }): Promise<void> {\n try {\n const tabs = await listTabs()\n const tab = resolveTabId(tabs, target)\n if (!tab) {\n throw new Error(`未找到标签页: ${target}\\n使用 web-probe tabs 查看可用标签页`)\n }\n\n await navigateTab(tab.id, url)\n\n if (options.json) {\n printJSON({ success: true, url })\n } else {\n printSuccess(`已导航到: ${url}`)\n }\n } catch (err) {\n if (options.json) {\n printJSON({ error: (err as Error).message })\n process.exitCode = 1\n return\n }\n printError((err as Error).message)\n process.exitCode = 1\n }\n}\n","import { getHTML, listTabs, resolveTabId } from '../core/cdp-client.js'\nimport { printJSON, printError } from '../core/output.js'\n\nexport async function htmlCommand(target: string, selector?: string, options?: { json?: boolean }): Promise<void> {\n try {\n const tabs = await listTabs()\n const tab = resolveTabId(tabs, target)\n if (!tab) {\n throw new Error(`未找到标签页: ${target}\\n使用 web-probe tabs 查看可用标签页`)\n }\n\n const html = await getHTML(tab.id, selector)\n\n if (options?.json) {\n printJSON({ html })\n } else {\n console.log(html)\n }\n } catch (err) {\n if (options?.json) {\n printJSON({ error: (err as Error).message })\n process.exitCode = 1\n return\n }\n printError((err as Error).message)\n process.exitCode = 1\n }\n}\n","import { existsSync, mkdirSync, copyFileSync, writeFileSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { homedir } from 'node:os'\n\nexport type SkillFormat = 'skill.md' | 'rules-file' | 'agents-md' | 'instructions-md'\n\nexport interface ToolTarget {\n name: string\n displayName: string\n skillDir: string\n skillFile: string\n format: SkillFormat\n detected: boolean\n installed: boolean\n detectPaths: string[]\n}\n\nfunction checkAnyExists(paths: string[]): boolean {\n return paths.some((p) => existsSync(p))\n}\n\nexport function detectAITools(): ToolTarget[] {\n const home = homedir()\n\n const toolDefs: Array<{\n name: string\n displayName: string\n skillDir: string\n skillFile: string\n format: SkillFormat\n detectPaths: string[]\n }> = [\n {\n name: 'cursor',\n displayName: 'Cursor',\n skillDir: join(home, '.cursor', 'skills', 'web-probe'),\n skillFile: 'SKILL.md',\n format: 'skill.md',\n detectPaths: [\n join(home, '.cursor'),\n join(home, '.cursor', 'skills'),\n ],\n },\n {\n name: 'claude-code',\n displayName: 'Claude Code',\n skillDir: join(home, '.claude', 'skills', 'web-probe'),\n skillFile: 'SKILL.md',\n format: 'skill.md',\n detectPaths: [\n join(home, '.claude'),\n join(home, '.claude', 'skills'),\n ],\n },\n {\n name: 'codex',\n displayName: 'Codex (OpenAI)',\n skillDir: join(home, '.codex', 'skills', 'web-probe'),\n skillFile: 'SKILL.md',\n format: 'skill.md',\n detectPaths: [\n join(home, '.codex'),\n join(home, '.codex', 'skills'),\n ],\n },\n {\n name: 'agents',\n displayName: 'Agents (通用标准)',\n skillDir: join(home, '.agents', 'skills', 'web-probe'),\n skillFile: 'SKILL.md',\n format: 'skill.md',\n detectPaths: [\n join(home, '.agents'),\n join(home, '.agents', 'skills'),\n ],\n },\n {\n name: 'opencode',\n displayName: 'OpenCode',\n skillDir: join(home, '.config', 'opencode', 'skills', 'web-probe'),\n skillFile: 'SKILL.md',\n format: 'skill.md',\n detectPaths: [\n join(home, '.config', 'opencode'),\n join(home, '.config', 'opencode', 'skills'),\n ],\n },\n {\n name: 'windsurf',\n displayName: 'Windsurf',\n skillDir: join(home, '.codeium', 'windsurf'),\n skillFile: 'web-probe-rules.md',\n format: 'rules-file',\n detectPaths: [\n join(home, '.codeium', 'windsurf'),\n join(home, '.codeium'),\n ],\n },\n {\n name: 'copilot',\n displayName: 'GitHub Copilot',\n skillDir: join(home, '.github', 'agents'),\n skillFile: 'web-probe.md',\n format: 'agents-md',\n detectPaths: [\n join(home, '.github'),\n ],\n },\n {\n name: 'trae',\n displayName: 'Trae',\n skillDir: join(home, '.trae', 'rules'),\n skillFile: 'web-probe.md',\n format: 'rules-file',\n detectPaths: [\n join(home, '.trae'),\n ],\n },\n ]\n\n return toolDefs.map((def) => {\n const detected = checkAnyExists(def.detectPaths)\n const installed = existsSync(join(def.skillDir, def.skillFile))\n return { ...def, detected, installed }\n })\n}\n\nexport function installSkill(target: ToolTarget, skillSourcePath: string): void {\n mkdirSync(target.skillDir, { recursive: true })\n const dest = join(target.skillDir, target.skillFile)\n\n if (target.format === 'skill.md') {\n copyFileSync(skillSourcePath, dest)\n } else {\n const content = readFileSync(skillSourcePath, 'utf-8')\n const stripped = content.replace(/^---[\\s\\S]*?---\\n*/m, '')\n writeFileSync(dest, stripped, 'utf-8')\n }\n}\n\nexport function getDetectedToolNames(tools: ToolTarget[]): string[] {\n return tools.filter((t) => t.detected).map((t) => t.displayName)\n}\n\nexport function getInstalledToolNames(tools: ToolTarget[]): string[] {\n return tools.filter((t) => t.installed).map((t) => t.displayName)\n}\n","import { execSync } from 'node:child_process'\nimport { findChromePath, getChromeVersion } from '../utils/platform.js'\nimport { loadState } from '../core/state.js'\nimport { verifyPort } from '../core/port-manager.js'\nimport { detectAITools, type ToolTarget } from '../utils/detect-tools.js'\nimport { printHeader, printStatus, printJSON, printSuccess, printWarn } from '../core/output.js'\n\ninterface DiagResult {\n node: { ok: boolean; version: string }\n npx: { ok: boolean }\n chrome: { ok: boolean; version: string | null; path: string | null }\n cdp: { ok: boolean; port: number | null; pid: number | null }\n playwright: { ok: boolean; version: string | null }\n tools: Array<{ name: string; displayName: string; detected: boolean; installed: boolean }>\n}\n\nasync function diagnose(): Promise<DiagResult> {\n const nodeVersion = process.version\n\n let npxOk = false\n try {\n execSync('npx --version', { encoding: 'utf-8', stdio: 'pipe' })\n npxOk = true\n } catch { /* */ }\n\n const chromePath = findChromePath()\n const chromeVersion = chromePath ? getChromeVersion(chromePath) : null\n\n const state = loadState()\n let cdpOk = false\n if (state?.port) {\n cdpOk = await verifyPort(state.port)\n }\n\n let playwrightVersion: string | null = null\n try {\n playwrightVersion = execSync('npx playwright-core --version 2>/dev/null', {\n encoding: 'utf-8',\n stdio: 'pipe',\n }).trim()\n } catch {\n try {\n const pkg = await import('playwright-core/package.json', { with: { type: 'json' } })\n playwrightVersion = (pkg as { default?: { version?: string } }).default?.version ?? null\n } catch { /* */ }\n }\n\n const aiTools = detectAITools()\n const tools = aiTools.map((t) => ({\n name: t.name,\n displayName: t.displayName,\n detected: t.detected,\n installed: t.installed,\n }))\n\n return {\n node: { ok: true, version: nodeVersion },\n npx: { ok: npxOk },\n chrome: { ok: !!chromePath, version: chromeVersion, path: chromePath },\n cdp: { ok: cdpOk, port: state?.port ?? null, pid: state?.pid ?? null },\n playwright: { ok: !!playwrightVersion, version: playwrightVersion },\n tools,\n }\n}\n\nexport async function doctorCommand(options: { json?: boolean }): Promise<void> {\n const result = await diagnose()\n\n if (options.json) {\n printJSON(result)\n return\n }\n\n printHeader('🔍 web-probe — 环境诊断')\n\n console.log('基础依赖')\n printStatus('Node.js', result.node.ok, result.node.version)\n printStatus('npx', result.npx.ok, result.npx.ok ? '' : '未找到')\n\n console.log()\n console.log('Chrome 浏览器')\n printStatus('Chrome', result.chrome.ok, result.chrome.ok\n ? `已安装${result.chrome.version ? ` (${result.chrome.version})` : ''}`\n : '未找到')\n printStatus('调试端口', result.cdp.ok,\n result.cdp.ok\n ? `已开启 (端口 ${result.cdp.port}, PID ${result.cdp.pid})`\n : '未开启')\n\n console.log()\n console.log('引擎')\n printStatus('Playwright', result.playwright.ok,\n result.playwright.ok ? result.playwright.version ?? '' : '未安装')\n\n console.log()\n console.log('AI 工具 Skill 注入状态')\n const detectedTools = result.tools.filter((t) => t.detected)\n const undetectedTools = result.tools.filter((t) => !t.detected)\n\n if (detectedTools.length > 0) {\n for (const tool of detectedTools) {\n printStatus(tool.displayName, tool.installed,\n tool.installed ? '已注入' : '已检测到,未注入 Skill')\n }\n }\n if (undetectedTools.length > 0) {\n const names = undetectedTools.map((t) => t.displayName).join(', ')\n console.log(` ${' '} ${names} — 未检测到`)\n }\n\n const needsSkill = detectedTools.some((t) => !t.installed)\n console.log()\n const allCore = result.node.ok && result.chrome.ok\n if (allCore) {\n printSuccess('核心组件就绪')\n if (needsSkill) {\n printWarn('部分 AI 工具未注入 Skill,运行 web-probe skill install 进行注入')\n }\n } else {\n printWarn('部分组件缺失,运行 web-probe setup 进行安装')\n }\n}\n","import { existsSync } from 'node:fs'\nimport { execSync } from 'node:child_process'\nimport chalk from 'chalk'\nimport { findChromePath } from '../utils/platform.js'\nimport { printSuccess, printError, printJSON } from '../core/output.js'\n\nfunction step(num: number, total: number, label: string, fn: () => boolean | string): boolean {\n process.stdout.write(`[${num}/${total}] ${label}`)\n try {\n const result = fn()\n if (result === true || typeof result === 'string') {\n console.log(chalk.green(` ✓${typeof result === 'string' ? ` (${result})` : ''}`))\n return true\n }\n console.log(chalk.red(' ✗'))\n return false\n } catch (err) {\n console.log(chalk.red(` ✗ ${(err as Error).message}`))\n return false\n }\n}\n\nexport async function setupCommand(options: { json?: boolean }): Promise<void> {\n if (options.json) {\n const results: Record<string, boolean> = {}\n results.chrome = !!findChromePath()\n try {\n execSync('npx playwright-core --version 2>/dev/null', { stdio: 'pipe' })\n results.playwright = true\n } catch {\n results.playwright = false\n }\n printJSON(results)\n return\n }\n\n console.log()\n console.log(chalk.bold('🚀 web-probe — 一键安装'))\n console.log()\n\n const total = 3\n\n step(1, total, '检测 Chrome...', () => {\n const path = findChromePath()\n if (!path) throw new Error('未找到 Chrome,请先安装')\n return true\n })\n\n step(2, total, '检测 Playwright...', () => {\n try {\n require.resolve('playwright-core')\n return '已安装'\n } catch {\n return '作为 web-probe 依赖已包含'\n }\n })\n\n step(3, total, '检测环境...', () => {\n return true\n })\n\n console.log()\n printSuccess('环境检测完成!')\n console.log()\n console.log(' 运行 ' + chalk.cyan('web-probe skill install') + ' 注入 Skill 到 AI 工具')\n console.log(' 运行 ' + chalk.cyan('web-probe chrome start') + ' 启动 Chrome 调试端口')\n console.log()\n}\n","import { printJSON, printError, printSuccess, printInfo, printHeader } from '../core/output.js'\nimport { findChromePath } from '../utils/platform.js'\n\nasync function loadStagehand(): Promise<typeof import('@browserbasehq/stagehand')> {\n try {\n return await import('@browserbasehq/stagehand')\n } catch {\n throw new Error(\n 'explore 命令需要安装 Stagehand(可选依赖):\\n\\n' +\n ' npm install @browserbasehq/stagehand zod\\n\\n' +\n '同时需要设置 LLM API Key 环境变量:\\n' +\n ' export OPENAI_API_KEY=sk-...\\n' +\n ' # 或 export ANTHROPIC_API_KEY=sk-ant-...',\n )\n }\n}\n\nfunction checkApiKey(): { model: string; provider: string } {\n if (process.env.OPENAI_API_KEY) {\n return { model: 'openai/gpt-4o', provider: 'OpenAI' }\n }\n if (process.env.ANTHROPIC_API_KEY) {\n return { model: 'anthropic/claude-sonnet-4-20250514', provider: 'Anthropic' }\n }\n throw new Error(\n '未检测到 LLM API Key。explore 命令需要 AI 模型驱动。\\n\\n' +\n '请设置以下任一环境变量:\\n' +\n ' export OPENAI_API_KEY=sk-...\\n' +\n ' export ANTHROPIC_API_KEY=sk-ant-...',\n )\n}\n\nexport async function exploreCommand(\n url: string,\n goal?: string,\n options?: { model?: string; json?: boolean; headless?: boolean },\n): Promise<void> {\n try {\n const { Stagehand } = await loadStagehand()\n const { model: defaultModel, provider } = checkApiKey()\n const model = options?.model ?? defaultModel\n const chromePath = findChromePath()\n\n if (!options?.json) {\n printHeader('🔍 web-probe explore — AI 自主探索')\n printInfo(`目标: ${url}`)\n if (goal) printInfo(`任务: ${goal}`)\n printInfo(`模型: ${model} (${provider})`)\n console.log()\n }\n\n const stagehand = new Stagehand({\n env: 'LOCAL',\n modelName: model,\n headless: options?.headless ?? true,\n localBrowserLaunchOptions: {\n executablePath: chromePath ?? undefined,\n },\n })\n\n await stagehand.init()\n const page = stagehand.context.pages()[0]\n await page.goto(url, { waitUntil: 'networkidle' })\n\n const results: Array<{ step: string; data?: unknown }> = []\n\n const observations = await stagehand.observe(\n goal ?? '观察页面上所有可交互的元素和主要内容区域',\n )\n results.push({ step: 'observe', data: observations })\n\n if (goal) {\n try {\n await stagehand.act(goal)\n results.push({ step: 'act', data: { action: goal, success: true } })\n } catch (err) {\n results.push({ step: 'act', data: { action: goal, success: false, error: (err as Error).message } })\n }\n }\n\n const pageInfo = await page.evaluate(() => ({\n url: location.href,\n title: document.title,\n bodyText: document.body?.innerText?.trim().slice(0, 500) ?? '',\n }))\n results.push({ step: 'page_info', data: pageInfo })\n\n await stagehand.close()\n\n if (options?.json) {\n printJSON({ url, goal, model, results })\n } else {\n printSuccess('探索完成')\n console.log()\n for (const r of results) {\n console.log(` [${r.step}]`)\n if (r.data) {\n const lines = JSON.stringify(r.data, null, 2).split('\\n')\n for (const line of lines.slice(0, 15)) {\n console.log(` ${line}`)\n }\n if (lines.length > 15) console.log(` ... (${lines.length - 15} more lines)`)\n }\n console.log()\n }\n }\n } catch (err) {\n if (options?.json) {\n printJSON({ error: (err as Error).message })\n process.exitCode = 1\n return\n }\n printError((err as Error).message)\n process.exitCode = 1\n }\n}\n","import { join, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { existsSync } from 'node:fs'\nimport { createInterface } from 'node:readline'\nimport chalk from 'chalk'\nimport { detectAITools, installSkill, type ToolTarget } from '../utils/detect-tools.js'\nimport { printSuccess, printInfo, printError, printJSON, printWarn } from '../core/output.js'\n\nfunction getSkillSource(): string {\n const currentDir = dirname(fileURLToPath(import.meta.url))\n const candidates = [\n join(currentDir, '..', 'src', 'skill', 'SKILL.md'),\n join(currentDir, 'skill', 'SKILL.md'),\n join(currentDir, '..', 'skill', 'SKILL.md'),\n ]\n for (const p of candidates) {\n if (existsSync(p)) return p\n }\n throw new Error(`Skill 模板文件未找到,搜索路径: ${candidates.join(', ')}`)\n}\n\nasync function askUser(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close()\n resolve(answer.trim())\n })\n })\n}\n\nfunction printToolTable(tools: ToolTarget[]): void {\n console.log()\n console.log(chalk.bold(' # 工具 状态'))\n console.log(' ' + '─'.repeat(45))\n tools.forEach((t, i) => {\n const status = t.installed\n ? chalk.green('已注入 ✓')\n : t.detected\n ? chalk.yellow('已检测到,未注入')\n : chalk.gray('未检测到')\n console.log(` ${String(i + 1).padStart(2)} ${t.displayName.padEnd(18)} ${status}`)\n })\n console.log()\n}\n\nexport async function skillInstallCommand(options: { target?: string; json?: boolean; yes?: boolean }): Promise<void> {\n try {\n const skillSource = getSkillSource()\n const tools = detectAITools()\n\n if (options.target) {\n const tool = tools.find((t) => t.name === options.target)\n if (!tool) {\n const names = tools.map((t) => t.name).join(', ')\n throw new Error(`未知目标: ${options.target},可用: ${names}`)\n }\n installSkill(tool, skillSource)\n if (options.json) {\n printJSON({ installed: [tool.name], path: join(tool.skillDir, tool.skillFile) })\n return\n }\n printSuccess(`Skill 已注入到 ${tool.displayName} (${join(tool.skillDir, tool.skillFile)})`)\n return\n }\n\n const detected = tools.filter((t) => t.detected)\n const notInstalled = detected.filter((t) => !t.installed)\n\n if (options.json) {\n const installed: string[] = []\n for (const tool of detected) {\n installSkill(tool, skillSource)\n installed.push(tool.name)\n }\n printJSON({\n detected: detected.map((t) => t.name),\n installed,\n all_tools: tools.map((t) => ({ name: t.name, detected: t.detected, installed: t.installed })),\n })\n return\n }\n\n console.log()\n console.log(chalk.bold('🔍 web-probe — AI 工具检测'))\n\n printToolTable(tools)\n\n if (detected.length === 0) {\n printWarn('未检测到任何 AI 工具')\n console.log()\n printInfo('可以手动指定目标工具:')\n console.log(` ${chalk.cyan('web-probe skill install --target cursor')}`)\n console.log(` ${chalk.cyan('web-probe skill install --target claude-code')}`)\n console.log()\n console.log(' 可用目标: ' + tools.map((t) => chalk.cyan(t.name)).join(', '))\n console.log()\n return\n }\n\n if (notInstalled.length === 0 && !options.yes) {\n printSuccess('所有检测到的 AI 工具已注入 Skill')\n const answer = await askUser(' 是否重新注入以更新?(y/N) ')\n if (answer.toLowerCase() !== 'y') return\n }\n\n const toInstall = options.yes\n ? detected\n : detected\n\n if (!options.yes && notInstalled.length > 0) {\n const names = notInstalled.map((t) => chalk.cyan(t.displayName)).join(', ')\n console.log(` 检测到 ${notInstalled.length} 个工具未注入: ${names}`)\n const answer = await askUser(' 是否全部注入?(Y/n) ')\n if (answer.toLowerCase() === 'n') return\n }\n\n console.log()\n for (const tool of toInstall) {\n installSkill(tool, skillSource)\n printSuccess(`${tool.displayName} → ${join(tool.skillDir, tool.skillFile)}`)\n }\n\n console.log()\n printSuccess(`已完成 ${toInstall.length} 个工具的 Skill 注入`)\n console.log()\n } catch (err) {\n if (options.json) {\n printJSON({ error: (err as Error).message })\n process.exitCode = 1\n return\n }\n printError((err as Error).message)\n process.exitCode = 1\n }\n}\n","import { Command } from 'commander'\nimport { readFileSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nfunction getVersion(): string {\n try {\n const pkgPath = join(__dirname, '..', 'package.json')\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))\n return pkg.version ?? '0.0.0'\n } catch {\n return '0.0.0'\n }\n}\n\nasync function autoTimeoutCheck(): Promise<void> {\n const { checkTimeout, loadState, clearState } = await import('./core/state.js')\n const { verifyPort } = await import('./core/port-manager.js')\n\n const { expired, minutesIdle } = checkTimeout()\n if (!expired) return\n\n const state = loadState()\n if (!state) return\n\n const stillAlive = await verifyPort(state.port)\n if (stillAlive && state.pid > 0) {\n try {\n process.kill(state.pid, 'SIGTERM')\n } catch { /* already gone */ }\n }\n clearState()\n\n const chalk = (await import('chalk')).default\n console.error(\n chalk.yellow(`⏱️ 调试端口已空闲 ${minutesIdle} 分钟,已自动关闭 (端口 ${state.port})`),\n )\n}\n\nconst program = new Command()\n\nprogram\n .name('web-probe')\n .description('AI 浏览器自动化 CLI 工具')\n .version(getVersion(), '-v, --version')\n .hook('preAction', async () => {\n await autoTimeoutCheck()\n })\n\n// --- chrome 子命令 ---\nconst chrome = program\n .command('chrome')\n .description('Chrome 调试端口管理')\n\nchrome\n .command('start')\n .description('启动 Chrome 调试端口')\n .option('--port <port>', '指定端口(默认随机 20000-29999)')\n .option('--json', 'JSON 格式输出')\n .action(async (opts) => {\n const { chromeStart } = await import('./commands/chrome.js')\n await chromeStart(opts)\n })\n\nchrome\n .command('stop')\n .description('关闭调试端口(不关 Chrome 本体)')\n .option('--json', 'JSON 格式输出')\n .action(async (opts) => {\n const { chromeStop } = await import('./commands/chrome.js')\n await chromeStop(opts)\n })\n\nchrome\n .command('status')\n .description('显示当前调试端口状态')\n .option('--json', 'JSON 格式输出')\n .action(async (opts) => {\n const { chromeStatus } = await import('./commands/chrome.js')\n await chromeStatus(opts)\n })\n\nchrome\n .command('restart')\n .description('重启调试(新随机端口)')\n .option('--json', 'JSON 格式输出')\n .action(async (opts) => {\n const { chromeRestart } = await import('./commands/chrome.js')\n await chromeRestart(opts)\n })\n\n// --- tabs ---\nprogram\n .command('tabs')\n .description('列出所有打开的标签页')\n .option('--json', 'JSON 格式输出')\n .action(async (opts) => {\n const { tabsCommand } = await import('./commands/tabs.js')\n await tabsCommand(opts)\n })\n\n// --- inspect ---\nprogram\n .command('inspect <target>')\n .description('提取页面完整结构(JSON 输出)')\n .option('--json', 'JSON 格式输出', true)\n .action(async (target, opts) => {\n const { inspectCommand } = await import('./commands/inspect.js')\n await inspectCommand(target, opts)\n })\n\n// --- shot ---\nprogram\n .command('shot <target>')\n .description('截图(target 可以是 tabId 或 URL)')\n .option('-o, --output <path>', '指定输出路径')\n .option('--json', 'JSON 格式输出')\n .action(async (target, opts) => {\n const { shotCommand } = await import('./commands/shot.js')\n await shotCommand(target, opts)\n })\n\n// --- eval ---\nprogram\n .command('eval <target> <javascript>')\n .description('在标签页中执行 JavaScript')\n .option('--json', 'JSON 格式输出')\n .action(async (target, javascript, opts) => {\n const { evalCommand } = await import('./commands/eval.js')\n await evalCommand(target, javascript, opts)\n })\n\n// --- click ---\nprogram\n .command('click <target> <selector>')\n .description('点击元素')\n .option('--json', 'JSON 格式输出')\n .action(async (target, selector, opts) => {\n const { clickCommand } = await import('./commands/click.js')\n await clickCommand(target, selector, opts)\n })\n\n// --- type ---\nprogram\n .command('type <target> <selector> <text>')\n .description('在元素中输入文字')\n .option('--json', 'JSON 格式输出')\n .action(async (target, selector, text, opts) => {\n const { typeCommand } = await import('./commands/type.js')\n await typeCommand(target, selector, text, opts)\n })\n\n// --- nav ---\nprogram\n .command('nav <target> <url>')\n .description('导航标签页到新 URL')\n .option('--json', 'JSON 格式输出')\n .action(async (target, url, opts) => {\n const { navCommand } = await import('./commands/nav.js')\n await navCommand(target, url, opts)\n })\n\n// --- html ---\nprogram\n .command('html <target> [selector]')\n .description('提取 HTML 内容')\n .option('--json', 'JSON 格式输出')\n .action(async (target, selector, opts) => {\n const { htmlCommand } = await import('./commands/html.js')\n await htmlCommand(target, selector, opts)\n })\n\n// --- doctor ---\nprogram\n .command('doctor')\n .description('环境诊断(检查所有依赖,输出状态表)')\n .option('--json', 'JSON 格式输出')\n .action(async (opts) => {\n const { doctorCommand } = await import('./commands/doctor.js')\n await doctorCommand(opts)\n })\n\n// --- setup ---\nprogram\n .command('setup')\n .description('一键安装所有依赖 + 配置')\n .option('--json', 'JSON 格式输出')\n .action(async (opts) => {\n const { setupCommand } = await import('./commands/setup.js')\n await setupCommand(opts)\n })\n\n// --- explore ---\nprogram\n .command('explore <url> [goal]')\n .description('AI 自主探索网站(需安装 @browserbasehq/stagehand)')\n .option('--model <model>', 'LLM 模型(默认根据 API Key 自动选择)')\n .option('--no-headless', '显示浏览器窗口')\n .option('--json', 'JSON 格式输出')\n .action(async (url, goal, opts) => {\n const { exploreCommand } = await import('./commands/explore.js')\n await exploreCommand(url, goal, opts)\n })\n\n// --- skill ---\nconst skill = program\n .command('skill')\n .description('Skill 管理')\n\nskill\n .command('install')\n .description('检测 AI 工具并注入 Skill')\n .option('--target <tool>', '指定目标工具 (cursor|claude-code|codex|agents|opencode|windsurf|copilot|trae)')\n .option('-y, --yes', '跳过确认,自动注入所有检测到的工具')\n .option('--json', 'JSON 格式输出')\n .action(async (opts) => {\n const { skillInstallCommand } = await import('./commands/skill.js')\n await skillInstallCommand(opts)\n })\n\nprogram.parse()\n"],"mappings":"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","names":["existsSync","output","execSync","execSync","writeFileSync","mkdirSync","join","existsSync","mkdirSync","writeFileSync","readFileSync","join","homedir","execSync","execSync","chalk","join","existsSync","chalk","readFileSync","join","dirname","fileURLToPath","checkTimeout","loadState","clearState","verifyPort","chalk","chromeStart","chromeStop","chromeStatus","chromeRestart","tabsCommand","inspectCommand","shotCommand","evalCommand","clickCommand","typeCommand","navCommand","htmlCommand","doctorCommand","setupCommand","exploreCommand","skillInstallCommand"]}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "web-probe-cli",
3
+ "version": "0.1.0",
4
+ "description": "AI 浏览器自动化 CLI 工具 — 将 Chrome CDP 管理、页面分析、截图、自动化操作封装为单一命令行入口",
5
+ "type": "module",
6
+ "bin": {
7
+ "web-probe": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist/",
11
+ "src/skill/"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "dev": "tsup --watch",
19
+ "start": "node dist/index.js",
20
+ "typecheck": "tsc --noEmit",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest"
23
+ },
24
+ "keywords": [
25
+ "browser",
26
+ "automation",
27
+ "chrome",
28
+ "cdp",
29
+ "cli",
30
+ "ai",
31
+ "devtools"
32
+ ],
33
+ "license": "MIT",
34
+ "dependencies": {
35
+ "chalk": "^5.6.2",
36
+ "chrome-remote-interface": "^0.34.0",
37
+ "commander": "^14.0.3",
38
+ "playwright-core": "^1.58.2"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^25.5.0",
42
+ "tsup": "^8.5.1",
43
+ "typescript": "^6.0.2",
44
+ "vitest": "^4.1.2"
45
+ }
46
+ }
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: web-probe
3
+ description: "AI 浏览器自动化。操控用户已登录的浏览器、分析网页、截图、执行页面操作时使用。"
4
+ ---
5
+
6
+ # web-probe — AI 浏览器自动化
7
+
8
+ ## 首次使用(每次会话开始前检查)
9
+
10
+ 1. 验证 CLI 是否可用:`web-probe --version`
11
+ - 若报 `command not found` → 安装:`npm i -g web-probe-cli`
12
+ - 或免安装执行:`npx --yes web-probe-cli <command>`
13
+ 2. 检查环境:`web-probe doctor --json`
14
+ - 若 `chrome.ok` 为 false → 提示用户安装 Chrome
15
+ - 若 `cdp.ok` 为 false → 需要先 `web-probe chrome start`
16
+
17
+ ## 操控用户已登录的页面
18
+
19
+ ```
20
+ web-probe chrome start # 1. 启动调试端口
21
+ web-probe tabs --json # 2. 列出标签页,获取 tabId
22
+ web-probe inspect <id> # 3. 提取页面结构
23
+ web-probe shot <id> # 4. 截图
24
+ web-probe chrome stop # 5. 用完关闭
25
+ ```
26
+
27
+ ## 截图新 URL(无需已登录)
28
+
29
+ `web-probe shot https://example.com -o ./screenshot.png`
30
+
31
+ ## 页面操作命令
32
+
33
+ - `web-probe eval <id> "<js>"` — 在页面执行 JavaScript
34
+ - `web-probe click <id> "<selector>"` — 点击元素
35
+ - `web-probe type <id> "<selector>" "<text>"` — 在元素中输入文字
36
+ - `web-probe nav <id> "<url>"` — 导航到新 URL
37
+ - `web-probe html <id> [selector]` — 提取 HTML 内容
38
+
39
+ ## 命令速查
40
+
41
+ | 命令 | 作用 |
42
+ |------|------|
43
+ | `doctor [--json]` | 环境诊断 |
44
+ | `setup` | 一键检测环境 |
45
+ | `chrome start [--port N]` | 启动调试端口(随机端口) |
46
+ | `chrome stop` | 关闭调试端口 |
47
+ | `chrome status` | 查看端口状态 |
48
+ | `tabs [--json]` | 列出标签页 |
49
+ | `inspect <id>` | 提取页面结构 (JSON) |
50
+ | `shot <id\|url> [-o path]` | 截图 |
51
+ | `eval <id> <js>` | 执行 JS |
52
+ | `click <id> <selector>` | 点击 |
53
+ | `type <id> <selector> <text>` | 输入 |
54
+ | `nav <id> <url>` | 导航 |
55
+ | `html <id> [selector]` | 提取 HTML |
56
+
57
+ ## 探索模式 — 自主分析未知页面
58
+
59
+ 当用户要求分析一个不熟悉的页面时,按以下循环操作:
60
+
61
+ ```
62
+ 1. web-probe tabs --json → 找到目标标签页
63
+ 2. web-probe inspect <id> → 获取页面结构概览
64
+ 3. web-probe shot <id> → 截图查看视觉布局
65
+ 4. 根据 inspect 结果决定下一步:
66
+ - 需要更多信息 → web-probe eval <id> "<js>" 提取特定数据
67
+ - 需要进入子页面 → web-probe click <id> "<selector>" 然后重复步骤 2-3
68
+ - 需要填写表单 → web-probe type <id> "<selector>" "<text>"
69
+ - 需要跳转 → web-probe nav <id> "<url>"
70
+ 5. 每次操作后重新 inspect + shot 确认页面状态变化
71
+ 6. 完成后 web-probe chrome stop
72
+ ```
73
+
74
+ 关键原则:
75
+ - 每次操作后都重新 inspect 确认状态,不要盲目连续操作
76
+ - 优先用 inspect 获取结构,只在需要视觉确认时才 shot
77
+ - 遇到动态加载内容,用 eval 执行 `document.readyState` 或等待特定元素出现
78
+
79
+ ## 注意事项
80
+
81
+ - 所有命令加 `--json` 输出 JSON 格式,便于程序解析
82
+ - tabId 来自 `tabs --json` 返回的 `id` 字段
83
+ - 调试端口 30 分钟无活动自动关闭
84
+ - 若未全局安装,可用 `npx --yes web-probe-cli <command>` 替代