@opentiny/webmcp-cli 0.0.8 → 0.0.9

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.
package/dist/bin.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bin.ts","../src/expand-file-refs.ts","../src/parse-run-args.ts","../src/browser.ts","../src/commands/state.ts","../src/commands/run.ts","../src/commands/clipboard.ts","../src/commands/tabs.ts","../package.json"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\nimport { readFileSync } from 'fs'\nimport { resolve } from 'path'\nimport { getFileBaseDir } from './expand-file-refs'\nimport { prepareRunArgsJson } from './parse-run-args'\nimport { stateCommand } from './commands/state'\nimport { runCommand } from './commands/run'\nimport { setClipboard } from './commands/clipboard'\nimport {\n tabsOpenCommand,\n tabsCloseCommand,\n tabsSwitchCommand,\n tabsBackCommand,\n tabsForwardCommand\n} from './commands/tabs'\nimport packageJson from '../package.json'\n\nconst program = new Command()\n\nfunction parseTabId(id?: string): string | undefined {\n if (!id) return undefined\n return id\n}\n\n/** 解析 browserState 返回文本:新格式为纯 JSON;兼容旧前缀 / 尾部告警 */\nfunction tryParseBrowserStateText(text: string): Record<string, unknown> & { content: string } | null {\n const tryParse = (jsonStr: string) => {\n try {\n const parsed = JSON.parse(jsonStr) as Record<string, unknown>\n if (parsed && typeof parsed.content === 'string') {\n return parsed as Record<string, unknown> & { content: string }\n }\n } catch {\n // ignore\n }\n return null\n }\n\n const direct = tryParse(text)\n if (direct) return direct\n\n if (text.startsWith('浏览器状态: ')) {\n let jsonStr = text.substring('浏览器状态: '.length)\n const firstNewline = jsonStr.indexOf('\\n')\n if (firstNewline !== -1) {\n const maybeJson = jsonStr.substring(0, firstNewline)\n if (tryParse(maybeJson)) jsonStr = maybeJson\n }\n return tryParse(jsonStr)\n }\n\n return null\n}\n\nfunction cleanOldLogs(baseDir: string, logDir: string) {\n try {\n // 1. 清理原本根目录下的旧版单文件和旧版日期文件\n const oldLogFile = path.join(baseDir, 'webmcp-cli.log')\n if (fs.existsSync(oldLogFile)) {\n try { fs.unlinkSync(oldLogFile) } catch {}\n }\n if (fs.existsSync(baseDir)) {\n const baseFiles = fs.readdirSync(baseDir)\n for (const file of baseFiles) {\n if (/^webmcp-cli-\\d{4}-\\d{2}-\\d{2}\\.log$/.test(file)) {\n try { fs.unlinkSync(path.join(baseDir, file)) } catch {}\n }\n }\n }\n\n // 2. 清理 logs 目录下超过 7 天的日志\n if (!fs.existsSync(logDir)) return\n const files = fs.readdirSync(logDir)\n const logFilePattern = /^webmcp-cli-(\\d{4}-\\d{2}-\\d{2})\\.log$/\n const now = Date.now()\n const maxAgeMs = 7 * 24 * 60 * 60 * 1000 // 7天\n\n for (const file of files) {\n const match = file.match(logFilePattern)\n if (match) {\n const fileDateStr = match[1]\n const fileDate = new Date(fileDateStr).getTime()\n if (isNaN(fileDate)) continue\n if (now - fileDate > maxAgeMs) {\n try {\n fs.unlinkSync(path.join(logDir, file))\n } catch {\n // 忽略单文件删除失败\n }\n }\n }\n }\n } catch (e) {\n // 忽略清理日志本身的错误\n }\n}\n\nfunction formatLogResult(result: any): string {\n if (result === undefined || result === null) {\n return 'null'\n }\n\n try {\n if (typeof result !== 'object') {\n return String(result)\n }\n\n // 深拷贝 result,防止意外修改原始数据导致控制台输出受影响\n const clone = JSON.parse(JSON.stringify(result))\n let a11yTreeStr = ''\n let searchResultStr = ''\n\n // 检测 page-agent-tool 的 browserState/操作 动作返回\n if (\n clone &&\n Array.isArray(clone.content) &&\n clone.content.length > 0 &&\n clone.content[0] &&\n typeof clone.content[0].text === 'string'\n ) {\n const text = clone.content[0].text\n const browserState = tryParseBrowserStateText(text)\n if (browserState) {\n a11yTreeStr = browserState.content\n // 替换 clone 中的 content 部分,避免在 JSON 序列化时产生超长难读的字符串\n browserState.content = '[Formatted A11y Tree - See details below]'\n clone.content[0].text = JSON.stringify(browserState, null, 2)\n } else if (\n text.includes('A11y Tree 搜索结果') ||\n text.includes('无障碍树搜索结果') ||\n text.includes('无障碍树搜索') ||\n text.includes('命中行') ||\n text.includes('context:')\n ) {\n // 如果是 searchTree 的返回,或者其他可能包含 A11y Tree 搜索结构的多行文本\n searchResultStr = text\n clone.content[0].text = '[Search A11y Tree Result - See details below]'\n }\n }\n\n let out = JSON.stringify(clone, null, 2)\n if (a11yTreeStr) {\n out += `\\n\\n[FORMATTED A11Y TREE]:\\n${a11yTreeStr}`\n }\n if (searchResultStr) {\n out += `\\n\\n[FORMATTED SEARCH RESULT]:\\n${searchResultStr}`\n }\n return out\n } catch (e) {\n // 降级使用标准 stringify\n try {\n return JSON.stringify(result, null, 2)\n } catch {\n return String(result)\n }\n }\n}\n\nfunction writeLog(commandName: string, args: any, result: any, error?: any) {\n try {\n const baseDir = process.env.WEBMCP_WORKSPACE || path.join(os.homedir(), '.webmcp_chrome_profile')\n const logDir = path.join(baseDir, 'logs')\n if (!fs.existsSync(logDir)) {\n fs.mkdirSync(logDir, { recursive: true })\n }\n const todayStr = new Date().toISOString().split('T')[0]\n const logFile = path.join(logDir, `webmcp-cli-${todayStr}.log`)\n\n const timestamp = new Date().toISOString()\n let logText = `========================================\\n`\n logText += `[${timestamp}] COMMAND: ${commandName}\\n`\n logText += `ARGS:\\n${JSON.stringify(args, null, 2)}\\n\\n`\n\n if (error) {\n logText += `ERROR:\\n${error instanceof Error ? error.stack : String(error)}\\n`\n } else if (result) {\n logText += `RESULT:\\n`\n const formattedResult = formatLogResult(result)\n logText += formattedResult.split('\\n').map(line => ` ${line}`).join('\\n') + '\\n'\n } else {\n logText += `RESULT: null\\n`\n }\n logText += `========================================\\n\\n`\n\n fs.appendFileSync(logFile, logText, 'utf-8')\n cleanOldLogs(baseDir, logDir)\n } catch (e) {\n // 忽略日志写入本身的错误,防止阻塞主流程\n }\n}\n\nfunction handleCommandError(error: unknown, commandName: string, args?: any): never {\n const msg = error instanceof Error ? error.message : String(error)\n writeLog(commandName, args, null, error)\n console.error(pc.red(`Error executing ${commandName} command: ${msg}`))\n process.exit(1)\n}\n\nprogram\n .name('webmcp-cli')\n .description('WebMCP CLI for interacting with browser via CDP')\n .version(packageJson.version)\n .option('-w, --workspace <path>', '指定自定义的浏览器工作空间(用户配置目录)路径')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts()\n if (opts.workspace) {\n process.env.WEBMCP_WORKSPACE = opts.workspace\n }\n })\n\nprogram\n .command('state')\n .description('获取浏览器当前页签或指定页签的导航元数据(url、title、webmcpTools、所有页签列表)')\n .option('-t, --tabid <id>', '指定页签的 ID')\n .action(async (options) => {\n const args = { tabid: parseTabId(options.tabid) }\n try {\n const result = await stateCommand(args)\n writeLog('state', args, result)\n console.log(formatLogResult(result))\n } catch (error: unknown) {\n handleCommandError(error, 'state', args)\n }\n })\n\nprogram\n .command('run <toolName> [args...]')\n .description('向指定页签调用指定的 WebMCP 工具执行操作')\n .option('-t, --tabid <id>', '指定页签的 ID')\n .option(\n '-f, --file <path>',\n '从指定 .json 文件读取整个参数(文件内容即为参数 JSON)。\\n' +\n '如需在参数中内联引用文件,使用占位符语法:\\n' +\n ' @file:<path> 读取文件原始文本\\n' +\n ' @base64file:<path> 读取文件并 Base64 编码\\n' +\n '示例:webmcp-cli run mytool \\'{\"content\":\"@base64file:./doc.md\"}\\''\n )\n .action(async (toolName, args, options) => {\n let finalArgsJson = ''\n const rawArgs = { toolName, args, file: options.file, tabid: options.tabid }\n try {\n let fileContent: string | undefined\n let fileBaseDir = process.cwd()\n\n if (options.file) {\n const filePath = resolve(process.cwd(), options.file)\n fileBaseDir = getFileBaseDir(options.file)\n try {\n fileContent = readFileSync(filePath, 'utf-8')\n } catch (e: any) {\n throw new Error(`无法读取文件 \"${filePath}\": ${e.message}`)\n }\n }\n\n finalArgsJson = prepareRunArgsJson(args ?? [], fileContent, fileBaseDir)\n\n const result = await runCommand({\n toolName,\n argsJson: finalArgsJson,\n tabid: parseTabId(options.tabid)\n })\n writeLog('run', { ...rawArgs, finalArgsJson }, result)\n console.log(formatLogResult(result))\n } catch (error: unknown) {\n handleCommandError(error, 'run', { ...rawArgs, finalArgsJson })\n }\n })\n\n\nprogram\n .command('clipboard <content>')\n .description('将内容设置到系统剪贴板')\n .action(async (content) => {\n const args = { content }\n try {\n await setClipboard(content)\n const result = { success: true, message: '内容已设置到系统剪贴板' }\n writeLog('clipboard', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'clipboard', args)\n }\n })\n\nconst tabs = program.command('tabs').description('管理浏览器标签页')\n\ntabs\n .command('open <url>')\n .description('打开新网页')\n .action(async (url) => {\n const args = { url }\n try {\n const result = await tabsOpenCommand(url)\n writeLog('tabs open', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'tabs open', args)\n }\n })\n\ntabs\n .command('close <tabid>')\n .description('关闭指定 tabid 的标签页')\n .action(async (tabid) => {\n const args = { tabid }\n try {\n const result = await tabsCloseCommand(tabid)\n writeLog('tabs close', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'tabs close', args)\n }\n })\n\ntabs\n .command('switch <tabid>')\n .description('激活并切换到指定 tabid 的标签页')\n .action(async (tabid) => {\n const args = { tabid }\n try {\n const result = await tabsSwitchCommand(tabid)\n writeLog('tabs switch', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'tabs switch', args)\n }\n })\n\ntabs\n .command('back [tabid]')\n .description('将当前或指定标签页导航后退一步')\n .action(async (tabid) => {\n const args = { tabid: parseTabId(tabid) }\n try {\n const result = await tabsBackCommand(args.tabid)\n writeLog('tabs back', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'tabs back', args)\n }\n })\n\ntabs\n .command('forward [tabid]')\n .description('将当前或指定标签页导航前进一步')\n .action(async (tabid) => {\n const args = { tabid: parseTabId(tabid) }\n try {\n const result = await tabsForwardCommand(args.tabid)\n writeLog('tabs forward', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'tabs forward', args)\n }\n })\n\nprogram.parse(process.argv)\n","import { readFileSync } from 'fs'\nimport { dirname, isAbsolute, normalize, resolve } from 'path'\nimport { fileURLToPath } from 'url'\n\n/** 匹配完整 JSON 字符串字面量 */\nconst JSON_STRING_LITERAL = /\"(?:[^\"\\\\]|\\\\.)*\"/g\n\n/** 匹配未加引号的 @file: / @base64file: 占位符(路径中可含反斜杠) */\nconst UNQUOTED_FILE_REF = /(?<![\\\\\"])@(base64)?file:([^\\s\"',}\\]]+)/g\n\nconst FILE_REF_PREFIX = /^@(base64)?file:(.+)$/s\n\nexport function resolveFilePath(filePath: string, baseDir: string = process.cwd()): string {\n let normalizedPath = filePath.trim()\n\n if (\n (normalizedPath.startsWith('\"') && normalizedPath.endsWith('\"')) ||\n (normalizedPath.startsWith(\"'\") && normalizedPath.endsWith(\"'\"))\n ) {\n normalizedPath = normalizedPath.slice(1, -1).trim()\n }\n\n if (normalizedPath.startsWith('file://')) {\n normalizedPath = fileURLToPath(normalizedPath)\n }\n\n if (isAbsolute(normalizedPath)) {\n return normalize(normalizedPath)\n }\n\n return resolve(baseDir, normalizedPath)\n}\n\n/**\n * 解码文件路径:仅折叠 JSON 中的 `\\\\`,不把 `\\t`、`\\U` 等当作转义。\n */\nexport function decodeFilePath(rawPath: string): string {\n return rawPath.replace(/\\\\\\\\/g, '\\\\')\n}\n\nfunction readFileRefContent(filePath: string, baseDir: string, base64: boolean): string {\n const absPath = resolveFilePath(filePath, baseDir)\n let content: string\n try {\n content = readFileSync(absPath, 'utf-8')\n } catch (e: any) {\n throw new Error(`无法读取文件引用 \"${filePath}\" (${absPath}): ${e.message}`)\n }\n\n return base64 ? Buffer.from(content, 'utf-8').toString('base64') : content\n}\n\nfunction expandFileRefValue(rawInner: string, baseDir: string): string | null {\n const match = rawInner.match(FILE_REF_PREFIX)\n if (!match) {\n return null\n }\n\n const [, base64Flag, rawPath] = match\n const filePath = decodeFilePath(rawPath)\n const value = readFileRefContent(filePath, baseDir, Boolean(base64Flag))\n return JSON.stringify(value)\n}\n\nfunction expandQuotedFileRefs(argsJson: string, baseDir: string): string {\n return argsJson.replace(JSON_STRING_LITERAL, (jsonStringLiteral) => {\n const rawInner = jsonStringLiteral.slice(1, -1)\n const replacement = expandFileRefValue(rawInner, baseDir)\n return replacement ?? jsonStringLiteral\n })\n}\n\nfunction expandUnquotedFileRefs(argsJson: string, baseDir: string): string {\n return argsJson.replace(UNQUOTED_FILE_REF, (match, base64Flag, filePath) => {\n const value = readFileRefContent(filePath, baseDir, Boolean(base64Flag))\n return JSON.stringify(value)\n })\n}\n\n/**\n * 展开 argsJson 中的文件引用占位符:\n * @file:<path> → 读取文件原始文本内容\n * @base64file:<path> → 读取文件内容并 Base64 编码\n */\nexport function expandFileRefs(argsJson: string, baseDir: string = process.cwd()): string {\n const withQuotedExpanded = expandQuotedFileRefs(argsJson, baseDir)\n return expandUnquotedFileRefs(withQuotedExpanded, baseDir)\n}\n\n/**\n * 确定 `@file` / `@base64file` 相对路径的解析基准目录。\n *\n * 未使用 `-f/--file` 时以 `process.cwd()` 为基准;\n * 使用参数文件时以该文件所在目录为基准,使 `args.json` 内 `./article.md` 等路径\n * 相对于参数文件而非 shell 当前工作目录解析。\n *\n * @example\n * // cwd 为 /home/user/project,执行 webmcp run tool -f test/fixtures/nested/args.json\n * getFileBaseDir('test/fixtures/nested/args.json')\n * // => '/home/user/project/test/fixtures/nested'\n */\nexport function getFileBaseDir(fileOption?: string): string {\n if (!fileOption) {\n return process.cwd()\n }\n return dirname(resolve(process.cwd(), fileOption))\n}\n","import JSON5 from 'json5'\nimport { expandFileRefs } from './expand-file-refs'\n\nexport function cleanJsonString(str: string): string {\n let cleaned = str.trim()\n if (cleaned.startsWith(\"'\") && cleaned.endsWith(\"'\")) {\n cleaned = cleaned.slice(1, -1).trim()\n }\n return cleaned\n}\n\nfunction looksLikeObjectBody(raw: string): boolean {\n return /^(\"?[\\w-]+\"?\\s*:)/.test(raw)\n}\n\n/**\n * 拼接 shell 拆散的参数。\n * 兼容 bash 花括号展开后丢失 `{}` 的情况:title:\"...\", \"content\":\"...\"\n */\nexport function joinShellArgs(args: string[]): string {\n const cleaned = args.map(cleanJsonString)\n const first = cleaned[0] ?? ''\n\n if (first.startsWith('{')) {\n return cleaned.join(' ')\n }\n\n if (looksLikeObjectBody(first)) {\n let joined = cleaned.join(' ')\n if (!joined.startsWith('{')) {\n joined = `{${joined}}`\n }\n if (!joined.endsWith('}')) {\n joined = `${joined}}`\n }\n return joined\n }\n\n return cleaned.join(' ')\n}\n\n/** 在相邻属性之间补逗号:title:\"a\" \"content\":\"b\" → title:\"a\",\"content\":\"b\" */\nexport function insertMissingCommas(raw: string): string {\n return raw.replace(/\"(\\s+)(\"?[\\w-]+\"?\\s*:)/g, '\",$2')\n}\n\n/**\n * 为未加引号的字符串值补引号。\n * 典型 shell 损坏:{title:TinyVue Icon,content:@base64file:./a.md}\n */\nexport function quoteUnquotedStringValues(raw: string): string {\n return raw.replace(\n /([{,]\\s*(?:\"([^\"]+)\"|([\\w-]+))\\s*:\\s*)(?!\"@(?:base64)?file:|\"|true|false|null|-?\\d|\\{|\\[)([^\",}\\]]+?)(?=\\s*[,}])/g,\n (_match, prefix, _quotedKey, _unquotedKey, value: string) => {\n const trimmed = value.trim()\n if (/^-?\\d+(\\.\\d+)?([eE][+-]?\\d+)?$/.test(trimmed)) {\n return prefix + trimmed\n }\n return prefix + JSON.stringify(trimmed)\n }\n )\n}\n\nexport function normalizeShellDamagedJson(raw: string): string {\n let normalized = raw.trim()\n normalized = insertMissingCommas(normalized)\n normalized = quoteUnquotedStringValues(normalized)\n return normalized\n}\n\nexport function buildArgsFromKeyValuePairs(args: string[]): string {\n const obj: Record<string, unknown> = {}\n for (const pair of args) {\n const index = pair.indexOf('=')\n if (index === -1) {\n throw new Error(`无效的参数格式 \"${pair}\"。请使用 key=value,或 JSON / -f 文件。`)\n }\n const key = pair.substring(0, index).trim()\n let val = cleanJsonString(pair.substring(index + 1).trim())\n\n try {\n obj[key] = JSON.parse(val)\n } catch {\n obj[key] = val\n }\n }\n return JSON.stringify(obj)\n}\n\n/**\n * 将用户输入的 JSON / JS 对象字面量解析并规范化为标准 JSON 字符串。\n *\n * 解析顺序:\n * 1. 去除首尾空白及 shell 单引号包裹\n * 2. 使用 JSON5 解析(支持尾随逗号、未加引号的 key 等)\n * 3. 若失败,尝试修复 shell 损坏(缺逗号、未加引号的字符串值)后重试\n *\n * @param raw - 原始参数字符串(可能已被 expandFileRefs 展开 @file 占位符)\n * @returns 规范化后的 JSON 字符串,可直接传给 MCP 工具\n *\n * @example\n * // 标准 JSON\n * parseArgsJson('{\"title\":\"标题\",\"content\":\"正文\"}')\n * // => '{\"title\":\"标题\",\"content\":\"正文\"}'\n *\n * @example\n * // shell 损坏:花括号展开后丢失逗号、值未加引号\n * parseArgsJson('{title:TinyVue Icon,content:\"hello\"}')\n * // => '{\"title\":\"TinyVue Icon\",\"content\":\"hello\"}'\n *\n * @example\n * // bash 单引号包裹(外层引号会被 cleanJsonString 剥除)\n * parseArgsJson('\\'{\"title\":\"标题\"}\\'')\n * // => '{\"title\":\"标题\"}'\n */\nexport function parseArgsJson(raw: string): string {\n const trimmed = cleanJsonString(raw)\n try {\n return JSON.stringify(JSON5.parse(trimmed))\n } catch (firstError) {\n const repaired = normalizeShellDamagedJson(trimmed)\n try {\n return JSON.stringify(JSON5.parse(repaired))\n } catch {\n const hint =\n '提示:bash 中 JSON 必须用单引号包裹,例如 \\'{\"title\":\"标题\",\"content\":\"@base64file:./article.md\"}\\';' +\n '或使用 key=value:title=标题 content=@base64file:./article.md;' +\n '或使用 -f args.json。'\n const message = firstError instanceof Error ? firstError.message : String(firstError)\n throw new Error(`参数不是有效的 JSON 或 JS 对象: ${message}\\n${hint}`)\n }\n }\n}\n\n/**\n * `webmcp run` 命令的入口:从 CLI 参数或文件内容组装最终 JSON 参数字符串,兼容三种情况。\n *\n * 参数来源优先级:`-f/--file` 文件内容 > 命令行 `args`。\n * 命令行支持三种格式(自动识别):\n * - JSON 对象:`{\"title\":\"标题\"}`\n * - shell 拆散的 JSON 片段:`title:\"标题\" \"content\":\"正文\"`(bash 花括号展开后)\n * - key=value:`title=标题 content=@base64file:./article.md`\n *\n * 组装后会调用 expandFileRefs 展开 `@file` / `@base64file` 占位符,再经 parseArgsJson 规范化。\n *\n * @param args - commander 解析后的剩余参数数组\n * @param fileContent - `-f` 指定文件的文本内容;未指定时为 undefined\n * @param baseDir - 解析 `@file` 相对路径的基准目录(`-f` 时为文件所在目录,否则为 cwd)\n * @returns 规范化后的 JSON 字符串\n *\n * @example\n * // CLI: webmcp run publish-article '{\"title\":\"标题\",\"content\":\"@base64file:./article.md\"}'\n * prepareRunArgsJson(['{\"title\":\"标题\",\"content\":\"@base64file:./article.md\"}'], undefined, process.cwd())\n *\n * @example\n * // CLI: webmcp run publish-article title=标题 content=@base64file:./article.md\n * prepareRunArgsJson(['title=标题', 'content=@base64file:./article.md'], undefined, process.cwd())\n *\n * @example\n * // CLI: webmcp run publish-article -f args.json\n * prepareRunArgsJson([], readFileSync('args.json', 'utf-8'), dirname('args.json'))\n */\nexport function prepareRunArgsJson(args: string[], fileContent: string | undefined, baseDir: string): string {\n if (fileContent !== undefined) {\n const trimmed = fileContent.trim()\n if (!trimmed) {\n throw new Error('通过 -f/--file 指定的参数文件内容不能为空')\n }\n const expanded = expandFileRefs(trimmed, baseDir)\n return parseArgsJson(expanded)\n }\n\n if (args.length === 0) {\n // 无参数工具(如 get_article_info)允许省略 args,默认空对象\n return '{}'\n }\n\n const joined = joinShellArgs(args)\n let raw = ''\n if (joined.startsWith('{') || looksLikeObjectBody(joined)) {\n raw = joined\n } else if (args.every((arg) => arg.includes('='))) {\n raw = buildArgsFromKeyValuePairs(args)\n } else {\n raw = joined\n }\n\n if (!raw.trim()) {\n throw new Error('未提供有效参数')\n }\n\n const expanded = expandFileRefs(raw, baseDir)\n return parseArgsJson(expanded)\n}\n","import puppeteer, { Browser, Page } from 'puppeteer-core'\nimport pc from 'picocolors'\nimport fs from 'fs'\nimport os from 'os'\nimport path from 'path'\nimport http from 'http'\nimport { spawn } from 'child_process'\nimport { fileURLToPath } from 'url'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\n\nfunction getCdpPort(): number {\n const raw = process.env.WEBMCP_CDP_PORT\n if (raw) {\n const port = Number.parseInt(raw, 10)\n if (Number.isFinite(port) && port > 0) return port\n }\n return 9222\n}\n\nfunction getWorkspaceDir(): string {\n return process.env.WEBMCP_WORKSPACE || path.join(os.homedir(), '.webmcp_chrome_profile')\n}\n\n/** CI / 自动化测试:无头 + sandbox 关闭,避免 Linux runner 缺 display / 权限问题。\n * WEBMCP_HEADLESS=0 可显式强制有界面(覆盖 CI 环境变量)。\n */\nfunction shouldLaunchHeadless(): boolean {\n if (process.env.WEBMCP_HEADLESS === '0') return false\n return process.env.WEBMCP_HEADLESS === '1' || process.env.CI === 'true' || process.env.CI === '1'\n}\n\n/**\n * 读取 Chrome 写入 user-data-dir 的 DevToolsActivePort 文件,获取该 profile 实际绑定的 CDP 端口。\n * 当默认 CDP 端口(9222,或 WEBMCP_CDP_PORT)被系统上其他工具占用时,Chrome 会静默切换到一个随机可用端口并记录在此文件中。\n * 注意:Chrome 136+ 起该文件在部分版本/场景下可能不再写入,因此这只是辅助检测手段,\n * 不能作为唯一依据,主逻辑仍以直接探测固定端口为准(见 candidateCdpBaseUrls)。\n */\nfunction readActivePortFromProfile(userDataDir: string): number | null {\n try {\n const content = fs.readFileSync(path.join(userDataDir, 'DevToolsActivePort'), 'utf-8')\n const port = parseInt(content.split('\\n')[0].trim(), 10)\n return Number.isFinite(port) && port > 0 ? port : null\n } catch {\n return null\n }\n}\n\n/**\n * 生成某端口下所有需要尝试的 CDP 基础地址。\n *\n * 背景:自 Chrome 136 起,`--remote-debugging-address` 已被忽略/移除(安全加固),\n * CDP 服务器改为固定绑定 \"localhost\" 解析出的回环地址;而不同系统上 \"localhost\" 的\n * DNS 解析顺序不一致(有的优先 IPv4 127.0.0.1,有的优先 IPv6 ::1),我们无法再通过\n * 启动参数强制指定地址族。因此这里显式列出 IPv4、IPv6 字面地址和 \"localhost\" 三种形式,\n * 逐一探测,不对地址族做任何假设,才能在所有平台上稳定探测到实际监听地址。\n */\nfunction candidateCdpBaseUrls(port: number): string[] {\n return [\n `http://127.0.0.1:${port}`,\n `http://[::1]:${port}`,\n `http://localhost:${port}`\n ]\n}\n\nfunction getLastTabIdFilePath(): string {\n return path.join(getWorkspaceDir(), '.last-tab-id')\n}\n\n/** 记录最近一次 tabs open / tabs switch 操作的标签页,供 run 无 -t 时回退定位 */\nexport function setLastActiveTabId(tabid: string): void {\n try {\n const dir = getWorkspaceDir()\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n fs.writeFileSync(getLastTabIdFilePath(), tabid, 'utf-8')\n } catch {\n // 写入失败不阻断主流程\n }\n}\n\nfunction getLastActiveTabId(): string | null {\n try {\n const tabid = fs.readFileSync(getLastTabIdFilePath(), 'utf-8').trim()\n return tabid || null\n } catch {\n return null\n }\n}\n\n/**\n * 使用 Node.js 原生 http 模块发起 GET 请求并返回响应体文本\n * 避免 Node.js fetch 将 localhost 解析为 IPv6 ::1 导致连接 Chrome CDP 失败的问题\n */\nfunction httpGet(url: string, timeoutMs = 1500): Promise<string> {\n return new Promise((resolve, reject) => {\n const req = http.get(url, { timeout: timeoutMs }, (res) => {\n let data = ''\n res.on('data', (chunk: Buffer) => { data += chunk.toString() })\n res.on('end', () => {\n if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {\n resolve(data)\n } else {\n reject(new Error(`HTTP ${res.statusCode}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('request timeout')) })\n })\n}\n\nfunction promiseWithTimeout<T>(promise: Promise<T>, timeoutMs = 5000, errorMsg = 'Operation timed out'): Promise<T> {\n let timeoutId: NodeJS.Timeout\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(errorMsg))\n }, timeoutMs)\n })\n return Promise.race([promise, timeoutPromise]).finally(() => {\n clearTimeout(timeoutId)\n })\n}\n\nasync function checkCdpReady(url: string, retries = 3): Promise<boolean> {\n for (let i = 0; i < retries; i++) {\n try {\n await httpGet(url, 1500)\n return true\n } catch {}\n if (i < retries - 1) {\n await new Promise(r => setTimeout(r, 200))\n }\n }\n return false\n}\n\n/**\n * 找出第一个真正可达的 CDP 地址,避免 Windows 上 localhost 解析为 IPv6 导致 puppeteer 连接失败\n */\nasync function findAvailableCdpUrl(addresses: string[], retries = 2): Promise<string | null> {\n for (const addr of addresses) {\n if (await checkCdpReady(addr, retries)) {\n return addr.replace('/json/version', '')\n }\n }\n return null\n}\n\n/**\n * 通过 Puppeteer 连接已运行的浏览器。\n * 注意:不要在 connect 时使用 targetFilter——在 Windows Edge 上会导致 WebSocket 握手后永久挂起;\n * 页面 target 的筛选在 getPageTargets / getTargetPage 中按需完成。\n */\nasync function connectPuppeteer(browserBaseUrl: string, attempt = 1, maxAttempts = 3): Promise<Browser> {\n try {\n return await promiseWithTimeout(\n puppeteer.connect({ browserURL: browserBaseUrl, defaultViewport: null }),\n 10000,\n `puppeteer.connect to ${browserBaseUrl} timed out`\n )\n } catch (err) {\n if (attempt >= maxAttempts) {\n throw err\n }\n const delayMs = 500 * attempt\n console.log(pc.yellow(`connectBrowser: 第 ${attempt} 次连接失败,${delayMs}ms 后重试...`))\n await new Promise(resolve => setTimeout(resolve, delayMs))\n return connectPuppeteer(browserBaseUrl, attempt + 1, maxAttempts)\n }\n}\n\n\n\ninterface BrowserInfo {\n path: string\n name: string\n}\n\nfunction getDefaultBrowserPath(): BrowserInfo | null {\n // CI / 本地可显式指定可执行文件(browser-actions/setup-chrome 会输出 chrome-path)\n const envPath =\n process.env.CHROME_PATH ||\n process.env.WEBMCP_CHROME_PATH ||\n process.env.PUPPETEER_EXECUTABLE_PATH\n if (envPath && fs.existsSync(envPath)) {\n return { path: envPath, name: 'Chrome' }\n }\n if (envPath) {\n console.log(pc.yellow(`指定的浏览器路径不存在,将回退到自动检测: ${envPath}`))\n }\n\n const platform = os.platform()\n if (platform === 'darwin') {\n // macOS:优先 Chrome,其次 Edge\n const chromePath = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'\n if (fs.existsSync(chromePath)) return { path: chromePath, name: 'Chrome' }\n const edgePath = '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge'\n if (fs.existsSync(edgePath)) return { path: edgePath, name: 'Edge' }\n return null\n } else if (platform === 'win32') {\n // Windows:优先 Chrome,其次 Edge(系统内置路径)\n const chromePaths = [\n process.env.LOCALAPPDATA + '\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n process.env.PROGRAMFILES + '\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n process.env['PROGRAMFILES(X86)'] + '\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe'\n ]\n const foundChrome = chromePaths.find(p => fs.existsSync(p))\n if (foundChrome) return { path: foundChrome, name: 'Chrome' }\n\n // Edge 在 Windows 上的常见路径(包括系统内置的 Edge)\n const edgePaths = [\n process.env.LOCALAPPDATA + '\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n process.env.PROGRAMFILES + '\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n process.env['PROGRAMFILES(X86)'] + '\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n 'C:\\\\Program Files (x86)\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n 'C:\\\\Program Files\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe'\n ]\n const foundEdge = edgePaths.find(p => fs.existsSync(p))\n if (foundEdge) return { path: foundEdge, name: 'Edge' }\n return null\n } else {\n // Linux:优先 Chrome,其次 Chromium,最后 Edge\n const paths: Array<{ p: string; name: string }> = [\n { p: '/usr/bin/google-chrome', name: 'Chrome' },\n { p: '/usr/bin/google-chrome-stable', name: 'Chrome' },\n { p: '/usr/bin/chromium', name: 'Chromium' },\n { p: '/usr/bin/chromium-browser', name: 'Chromium' },\n { p: '/usr/bin/microsoft-edge', name: 'Edge' },\n { p: '/usr/bin/microsoft-edge-stable', name: 'Edge' }\n ]\n const found = paths.find(({ p }) => fs.existsSync(p))\n return found ? { path: found.p, name: found.name } : null\n }\n}\n\nasync function startBrowserInBackground(): Promise<string> {\n const browserInfo = getDefaultBrowserPath()\n if (!browserInfo || !fs.existsSync(browserInfo.path)) {\n throw new Error('无法在系统中找到 Chrome 或 Edge 浏览器的默认安装路径。')\n }\n\n const cdpPort = getCdpPort()\n console.log(pc.yellow(`正在启动后台 ${browserInfo.name} 实例 (端口: ${cdpPort})...`))\n \n // 用户可以通过 --workspace CLI 选项或 WEBMCP_WORKSPACE 环境变量自定义。\n const userDataDir = getWorkspaceDir()\n if (!fs.existsSync(userDataDir)) {\n fs.mkdirSync(userDataDir, { recursive: true })\n }\n\n // 启动前先清除旧的 DevToolsActivePort 记录,避免读取到上一次运行残留的过期端口\n try {\n fs.unlinkSync(path.join(userDataDir, 'DevToolsActivePort'))\n } catch {}\n \n // 注:Chrome 136+ 已不再支持 `--remote-debugging-address` 指定绑定地址(安全加固后被忽略),\n // CDP 服务器固定绑定 \"localhost\" 解析出的回环地址,具体是 IPv4 还是 IPv6 由系统决定,\n // 因此不再传递该参数,探测阶段改为同时尝试 IPv4/IPv6/localhost 三种地址形式。\n const launchArgs = [\n `--remote-debugging-port=${cdpPort}`,\n `--user-data-dir=${userDataDir}`,\n '--no-first-run',\n '--no-default-browser-check'\n ]\n\n if (shouldLaunchHeadless()) {\n launchArgs.push(\n '--headless=new',\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-gpu',\n '--disable-dev-shm-usage'\n )\n }\n\n const child = spawn(\n browserInfo.path,\n launchArgs,\n {\n detached: true,\n stdio: 'ignore'\n }\n )\n\n child.unref() // 让子进程脱离父进程独立运行\n\n // 轮询等待 CDP 端口就绪。优先探测固定的 cdpPort(IPv4/IPv6/localhost 三种地址形式都尝试,\n // 不对地址族做假设);同时也检查 DevToolsActivePort 文件——如果 cdpPort 被其他程序占用,\n // 部分 Chrome 版本会自动切换到随机端口并记录在该文件中,作为额外兜底。\n for (let i = 0; i < 40; i++) {\n const ports = new Set<number>([cdpPort])\n const activePort = readActivePortFromProfile(userDataDir)\n if (activePort) ports.add(activePort)\n\n for (const port of ports) {\n for (const baseUrl of candidateCdpBaseUrls(port)) {\n try {\n await httpGet(`${baseUrl}/json/version`, 1000)\n if (port !== cdpPort) {\n console.log(pc.yellow(`检测到端口 ${cdpPort} 已被其他程序占用,${browserInfo.name} 已自动切换到端口 ${port}。`))\n }\n console.log(pc.green(`${browserInfo.name} 启动并就绪(${baseUrl})。`))\n // 额外等待 500ms,确保 CDP 完全稳定(Mac 首次启动时端口通但连接不稳定)\n await new Promise(resolve => setTimeout(resolve, 500))\n return baseUrl\n } catch {}\n }\n }\n await new Promise(resolve => setTimeout(resolve, 500))\n }\n\n throw new Error(`${browserInfo.name} 启动超时,无法连接到 CDP 端口。`)\n}\n\nexport async function connectBrowser(): Promise<Browser> {\n const userDataDir = getWorkspaceDir()\n const cdpPort = getCdpPort()\n\n // 第一步:找到第一个真正可达的 CDP 地址(IPv4/IPv6/localhost 三种形式都尝试,不假设地址族)。\n // 若本工具专属 profile 上一次运行时因端口冲突被 Chrome 切换到了非默认端口,\n // 优先尝试 DevToolsActivePort 记录的真实端口,避免误判为“未运行”而重复启动新实例。\n const recordedPort = readActivePortFromProfile(userDataDir)\n const versionAddresses = [\n ...(recordedPort && recordedPort !== cdpPort ? candidateCdpBaseUrls(recordedPort).map(u => `${u}/json/version`) : []),\n ...candidateCdpBaseUrls(cdpPort).map(u => `${u}/json/version`)\n ]\n\n const existingUrl = await findAvailableCdpUrl(versionAddresses, 2)\n if (existingUrl) {\n console.log(pc.yellow(`connectBrowser: 检测到端口 ${cdpPort} 已就绪,正在连接 ${existingUrl}...`))\n try {\n const browser = await connectPuppeteer(existingUrl)\n console.log(pc.green(`connectBrowser: 成功连接 ${existingUrl}`))\n return browser\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n throw new Error(\n `无法连接到已在运行的浏览器(${existingUrl}):${msg}。` +\n 'CDP 端口可用,请勿重复启动浏览器;可关闭多余窗口后重试。'\n )\n }\n }\n\n // 第二步:端口无响应,启动新的浏览器实例(使用独立用户数据目录,不影响用户已有浏览器)\n console.log(pc.yellow(`connectBrowser: 端口 ${cdpPort} 无响应,正在启动新的浏览器实例...`))\n let launchedUrl: string\n try {\n launchedUrl = await startBrowserInBackground()\n } catch (launchError: unknown) {\n const msg = launchError instanceof Error ? launchError.message : String(launchError)\n console.error(pc.red(`无法启动浏览器: ${msg}`))\n throw new Error('Browser launch failed.')\n }\n\n // 第三步:使用启动过程中确认过的真实 CDP 地址进行连接\n try {\n console.log(pc.yellow(`connectBrowser: 浏览器已启动,正在连接 ${launchedUrl}...`))\n const browser = await connectPuppeteer(launchedUrl)\n console.log(pc.green(`connectBrowser: 成功连接 ${launchedUrl}`))\n return browser\n } catch {\n throw new Error(`无法连接到浏览器(${launchedUrl}),请检查 Chrome/Edge 是否已安装。`)\n }\n}\n\n\n/**\n * 通过 CDP 获取页面真实的 Chrome target ID(UUID 格式字符串)\n * 供 state.ts 等命令展示 tabs 列表时使用\n */\nexport async function getPageTargetId(page: Page): Promise<string> {\n const session = await page.target().createCDPSession()\n try {\n const { targetInfo } = await session.send('Target.getTargetInfo')\n return targetInfo.targetId\n } finally {\n await session.detach().catch(() => {})\n }\n}\n\nexport function getPageTargets(browser: Browser) {\n return browser.targets().filter(t => {\n try {\n const type = (typeof t.type === 'function' ? t.type() : (t as any).type) || ''\n const url = (typeof t.url === 'function' ? t.url() : (t as any).url) || ''\n return type === 'page' && !url.startsWith('devtools://')\n } catch {\n return false\n }\n })\n}\n\nexport function getTargetIdFromTarget(target: any): string {\n return typeof target._getTargetInfo === 'function'\n ? target._getTargetInfo().targetId\n : (target._targetId || target.targetId || '')\n}\n\nexport function findPageTargetByTabId(browser: Browser, tabid: string) {\n const pageTargets = getPageTargets(browser)\n return pageTargets.find(t => {\n const tid = getTargetIdFromTarget(t)\n return tid === tabid || tid.includes(tabid)\n }) ?? null\n}\n\nexport async function activateTabById(browser: Browser, tabid: string): Promise<void> {\n const target = findPageTargetByTabId(browser, tabid)\n if (!target) {\n throw new Error(`Tab with targetId \"${tabid}\" not found.`)\n }\n\n const realTabId = getTargetIdFromTarget(target)\n const pages = await browser.pages()\n let sessionPage = pages.find(p => !p.url().startsWith('devtools://'))\n if (!sessionPage && pages.length > 0) {\n sessionPage = pages[0]\n }\n if (!sessionPage) {\n sessionPage = await browser.newPage()\n }\n\n const session = await sessionPage.createCDPSession()\n try {\n await session.send('Target.activateTarget', { targetId: realTabId })\n } finally {\n await session.detach().catch(() => {})\n }\n}\n\nexport async function getTargetPage(browser: Browser, tabid?: string): Promise<Page> {\n const pageTargets = getPageTargets(browser)\n\n if (pageTargets.length === 0) {\n const newPage = await browser.newPage()\n await injectWebMCPPolyfillAndTools(newPage)\n return newPage\n }\n\n let targetPage: Page | null = null\n\n if (tabid !== undefined) {\n const target = findPageTargetByTabId(browser, tabid)\n if (!target) {\n throw new Error(`Tab with targetId \"${tabid}\" not found.`)\n }\n targetPage = await target.page()\n } else {\n // 优先使用最近一次 tabs open/switch 记录的标签页(Agent 连续 CLI 调用更可靠)\n const lastTabId = getLastActiveTabId()\n if (lastTabId) {\n const lastTarget = findPageTargetByTabId(browser, lastTabId)\n if (lastTarget) {\n targetPage = await lastTarget.page()\n }\n }\n\n // Chrome 的 /json/list 接口把当前激活 the tab 排在第一位,用它来判断激活 tab\n if (!targetPage) {\n try {\n // 与 connectBrowser 一致:若 Chrome 因端口冲突切到非默认端口,一并探测 DevToolsActivePort\n const workspaceDir = getWorkspaceDir()\n const cdpPort = getCdpPort()\n const recordedPort = readActivePortFromProfile(workspaceDir)\n const ports = recordedPort && recordedPort !== cdpPort ? [recordedPort, cdpPort] : [cdpPort]\n const urls = ports.flatMap((port) => candidateCdpBaseUrls(port).map((u) => `${u}/json/list`))\n let activeTargetId: string | null = null\n for (const url of urls) {\n try {\n const body = await httpGet(url, 1000)\n const targetsData: Array<{ id: string; type: string; url: string }> = JSON.parse(body)\n // 找第一个 type=page 且不是 devtools:// 的 target(Chrome 把激活的排第一)\n const active = targetsData.find(t => t.type === 'page' && !t.url.startsWith('devtools://'))\n if (active) { activeTargetId = active.id; break }\n } catch { /* 忽略,继续试下一个地址 */ }\n }\n\n if (activeTargetId) {\n for (const target of pageTargets) {\n if (getTargetIdFromTarget(target) === activeTargetId) {\n targetPage = await target.page()\n break\n }\n }\n }\n } catch { /* 忽略,使用 fallback */ }\n }\n\n // fallback:取最后一个非 devtools 页面\n if (!targetPage) {\n const lastTarget = pageTargets[pageTargets.length - 1]\n targetPage = await lastTarget.page()\n }\n }\n\n if (!targetPage) {\n throw new Error('无法获取目标页面')\n }\n\n // 注入 polyfill 和域名工具(幂等检查)\n await injectWebMCPPolyfillAndTools(targetPage)\n return targetPage\n}\n\n/**\n * 供 tabs open / back / forward / state / run 等命令调用:仅在尚未注入时注入一次(幂等)。\n * 导航后页面 JS 上下文会清空,`__webmcpcli_init` 自然失效,下次调用会重新注入。\n */\nexport async function injectIntoPage(page: Page): Promise<void> {\n await injectWebMCPPolyfillAndTools(page)\n}\n\nasync function injectWebMCPPolyfillAndTools(page: Page) {\n // 已注入则跳过,避免覆盖 page-agent-tool 闭包内的 refMap\n const polyfillReady = await page.evaluate(() => {\n return !!(window as any).__webmcpcli_init\n }).catch(() => false)\n\n if (!polyfillReady) {\n console.log(pc.cyan('当前页面尚未注入 WebMCP 环境,正在执行自动注入...'))\n\n const injectScriptPath = path.resolve(__dirname, 'inject-bundle.js')\n if (!fs.existsSync(injectScriptPath)) {\n throw new Error(`Cannot find inject-bundle.js at ${injectScriptPath}. Please ensure you run 'pnpm build:inject' first.`)\n }\n\n const scriptContent = fs.readFileSync(injectScriptPath, 'utf-8')\n\n // 注入 WebMCP polyfill\n try {\n await page.evaluate(scriptContent)\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err)\n throw new Error('自动注入脚本执行失败: ' + msg)\n }\n\n // 显式等待 WebMCP 注册接口完全就绪\n await page.waitForFunction(() => {\n const mcp = (navigator as any).modelContext\n return mcp && typeof mcp.registerTool === 'function'\n }, { timeout: 10000 }).catch(() => {\n console.warn('等待 WebMCP registerTool 接口就绪超时,正在继续注入...')\n })\n }\n\n // 无论 polyfill 是否刚注入,都检查域名工具(工具内部有防重复 flag)\n await injectDomainTools(page)\n}\n\nfunction getToolsBundleName(hostname: string): string | null {\n const normalized = hostname.split(':')[0].toLowerCase()\n const toolsDir = path.resolve(__dirname, 'webmcp-tools')\n if (!fs.existsSync(toolsDir)) {\n return null\n }\n let files: string[] = []\n try {\n files = fs.readdirSync(toolsDir)\n } catch {\n return null\n }\n const supportedDomains = files\n .filter(f => f.endsWith('.js'))\n .map(f => f.slice(0, -3))\n\n if (supportedDomains.includes(normalized)) {\n return `webmcp-tools/${normalized}.js`\n }\n for (const domain of supportedDomains) {\n if (normalized.endsWith('.' + domain)) {\n return `webmcp-tools/${domain}.js`\n }\n }\n return null\n}\n\n/**\n * 根据页面域名查找并注入对应的工具 bundle\n * bundle 文件位于 dist/webmcp-tools/{hostname}.js\n * 注意:每个工具 bundle 内部会在 window 上设置 __webmcptools_{domain} flag 防止重复注册,\n * 此处在 JS 层额外做一次快速检查,避免每次都 evaluate 完整脚本带来不必要的 IPC 开销。\n */\nasync function injectDomainTools(page: Page): Promise<void> {\n let hostname: string\n try {\n const url = new URL(page.url())\n hostname = url.hostname\n } catch {\n return // 非 http(s) 页面,跳过\n }\n\n const bundleName = getToolsBundleName(hostname)\n if (!bundleName) {\n return // 没有对应的工具预置,跳过\n }\n\n const toolBundlePath = path.resolve(__dirname, bundleName)\n if (!fs.existsSync(toolBundlePath)) {\n return // 文件不存在,跳过\n }\n\n // 快速检查:若页面已注入,直接返回,省去读文件和 evaluate 的开销\n const bundleKey = bundleName.replace(/^webmcp-tools\\//, '').replace(/\\.js$/, '')\n const flagKey = `__webmcptools_${bundleKey.replace(/[^a-zA-Z0-9]/g, '')}`\n const alreadyInjected = await page.evaluate((key: string) => !!(window as any)[key], flagKey).catch(() => false)\n if (alreadyInjected) {\n return\n }\n\n console.log(pc.cyan(`检测到域名 ${hostname} 有预置工具,正在注入...`))\n\n const toolScript = fs.readFileSync(toolBundlePath, 'utf-8')\n try {\n await page.evaluate(toolScript)\n console.log(pc.green(`已为 ${hostname} 注入预置工具`))\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err)\n // 工具注入失败不阻断主流程,仅打印警告\n console.warn(pc.yellow(`域名工具注入失败 (${hostname}): ${msg}`))\n }\n}\n\n","import { connectBrowser, getTargetPage, getPageTargetId, injectIntoPage } from '../browser'\n\nexport async function stateCommand({ tabid }: { tabid?: string }) {\n const browser = await connectBrowser()\n try {\n const page = await getTargetPage(browser, tabid)\n\n // 1. 尚未注入时注入一次,确保手动打开的页面也能使用工具\n await injectIntoPage(page)\n\n // 2. 在页面上下文中获取导航元数据和已注册的工具列表\n // 不获取 DOM content(由调用方按需通过 browserState 拉取)\n const state = await page.evaluate(async () => {\n const url = document.URL\n const title = document.title\n\n const mcp = (document as any).modelContext || (navigator as any).modelContext\n let webmcpTools: Array<{ name: string; description?: string }> = []\n\n // polyfill 暴露的是 getTools(不是 MCP SDK 的 listTools)\n // 只回传可结构化克隆的字段,避免工具对象上的函数导致 page.evaluate 序列化失败\n if (mcp && typeof mcp.getTools === 'function') {\n try {\n const toolsResult = await mcp.getTools()\n const list = (toolsResult?.tools || toolsResult || []) as Array<{ name?: string; description?: string }>\n webmcpTools = list\n .filter((t) => t && typeof t.name === 'string')\n .map((t) => ({\n name: t.name as string,\n description: typeof t.description === 'string' ? t.description.slice(0, 200) : undefined,\n }))\n } catch {\n webmcpTools = []\n }\n }\n\n return { url, title, webmcpTools }\n })\n\n const activeTabid = await getPageTargetId(page).catch(() => null)\n\n // 3. 获取所有标签页信息(排除 devtools:// 内部页面)\n const pages = await browser.pages()\n const tabs = await Promise.all(\n pages.map(async (p) => {\n const pUrl = p.url()\n if (pUrl.startsWith('devtools://')) return null\n\n const pTitle = await Promise.race([\n p.title().catch(() => 'Unknown'),\n new Promise<string>((resolve) => setTimeout(() => resolve('Unknown'), 500))\n ])\n\n return {\n // 使用真实的 Chrome target ID,而非数组下标\n tabid: await getPageTargetId(p).catch(() => pUrl),\n title: pTitle,\n url: pUrl\n }\n })\n )\n\n return {\n ...state,\n activeTabid,\n tabs: tabs.filter(Boolean)\n }\n } finally {\n await browser.disconnect()\n }\n}\n","import { connectBrowser, getTargetPage, injectIntoPage } from '../browser'\n\nexport async function runCommand({\n toolName,\n argsJson,\n tabid\n}: {\n toolName: string\n argsJson: string\n tabid?: string\n}) {\n const browser = await connectBrowser()\n try {\n const page = await getTargetPage(browser, tabid)\n const urlBefore = page.url()\n\n // 仅在尚未注入时注入一次,保留 page-agent-tool 的 refMap\n await injectIntoPage(page)\n\n // argsJson 已在 bin.ts 中完成 @base64file 展开与 JSON 校验\n const cleanedArgs = argsJson.trim()\n\n let result: any\n try {\n result = await page.evaluate(async (name, inputString) => {\n // @ts-expect-error WebMCP APIs are experimental and not yet in DOM types\n const mcp = document.modelContext || document.modelContext || document.modelContext\n\n if (!mcp || typeof mcp.executeTool !== 'function') {\n throw new Error('当前页面没有注入 WebMCP 环境 (document.modelContext 未找到)')\n }\n\n // executeTool 的第二个参数必须是 JSON 字符串\n const tools = await mcp.getTools();\n const toolObj = tools.find((t: any) => t.name === name);\n if (!toolObj) throw new Error(`Tool ${name} not found`);\n let res = await mcp.executeTool(toolObj, inputString)\n\n // executeTool 的返回值可能是普通对象,也可能是 JSON 字符串\n if (typeof res === 'string') {\n try {\n res = JSON.parse(res)\n } catch {\n // 保留原始字符串\n }\n }\n\n if (res === undefined || res === null) {\n throw new Error('工具 execute 未返回结果,请检查工具实现是否缺少 return')\n }\n\n if (typeof res === 'object' && (res as { success?: boolean }).success === false) {\n const failed = res as { error?: string; message?: string }\n throw new Error(failed.error || failed.message || '工具执行失败')\n }\n\n return res\n }, toolName, cleanedArgs)\n } catch (evalError: unknown) {\n const errMsg = evalError instanceof Error ? evalError.message : String(evalError)\n\n // 识别\"执行上下文已销毁\"错误:这通常是工具执行期间页面发生了正常导航(如发布后跳转)\n // 此时工具实际上已经成功执行,跳转本身就是成功的副作用,不应报错\n const isContextDestroyed =\n errMsg.includes('context was destroyed') ||\n errMsg.includes('Execution context was destroyed') ||\n errMsg.includes('Cannot read properties of null') && errMsg.includes('context')\n\n if (isContextDestroyed) {\n // 等待导航稳定,然后读取新页面 URL\n await new Promise(resolve => setTimeout(resolve, 800))\n let newUrl = ''\n try {\n // 重新读取页面(导航后 JS 上下文虽被销毁,但 page 实例本身的 url() 依然是最新的)\n newUrl = page.url()\n } catch { /* 忽略 */ }\n\n // 如果 URL 已经发生变化,认为是正常导航触发的上下文销毁(工具执行成功)\n if (newUrl && newUrl !== urlBefore) {\n return {\n success: true,\n message: `工具 ${toolName} 执行完成,页面已导航至 ${newUrl}`,\n navigatedTo: newUrl\n }\n }\n // URL 未变化,可能是真正的错误,重新抛出\n }\n\n throw evalError\n }\n\n return result\n } finally {\n await browser.disconnect()\n }\n}\n","import clipboard from 'clipboardy'\n\n/**\n * 将文本设置到系统剪贴板\n * 使用 clipboardy 包,跨平台统一接口,无需手动处理各系统命令\n */\nexport async function setClipboard(content: string): Promise<void> {\n try {\n await clipboard.write(content)\n } catch (error: any) {\n throw new Error(`设置剪贴板失败: ${error.message}`)\n }\n}\n","import {\n connectBrowser,\n getTargetPage,\n injectIntoPage,\n getPageTargetId,\n findPageTargetByTabId,\n activateTabById,\n setLastActiveTabId\n} from '../browser'\n\nfunction normalizeUrl(url: string): string {\n if (!url.startsWith('http://') && !url.startsWith('https://')) {\n return 'https://' + url\n }\n return url\n}\n\nexport async function tabsOpenCommand(url: string) {\n const browser = await connectBrowser()\n try {\n const page = await browser.newPage()\n url = normalizeUrl(url)\n\n await page.goto(url, { waitUntil: 'domcontentloaded' })\n await injectIntoPage(page)\n await new Promise((resolve) => setTimeout(resolve, 500))\n\n let tabid: string | undefined\n try {\n tabid = await getPageTargetId(page)\n await activateTabById(browser, tabid)\n setLastActiveTabId(tabid)\n } catch (e) {\n console.warn('Best-effort tab activation failed:', e)\n }\n\n return {\n success: true,\n tabid,\n url: page.url(),\n title: await page.title().catch(() => '')\n }\n } finally {\n await browser.disconnect()\n }\n}\n\nexport async function tabsCloseCommand(tabid: string) {\n const browser = await connectBrowser()\n try {\n const target = findPageTargetByTabId(browser, tabid)\n if (!target) {\n throw new Error(`Tab with targetId \"${tabid}\" not found.`)\n }\n\n const page = await target.page()\n if (!page) {\n throw new Error(`Tab with targetId \"${tabid}\" not found.`)\n }\n\n const closedTabid = await getPageTargetId(page).catch(() => tabid)\n await page.close()\n\n return {\n success: true,\n tabid: closedTabid\n }\n } finally {\n await browser.disconnect()\n }\n}\n\nexport async function tabsSwitchCommand(tabid: string) {\n const browser = await connectBrowser()\n try {\n await activateTabById(browser, tabid)\n const page = await getTargetPage(browser, tabid)\n\n const realTabid = await getPageTargetId(page)\n setLastActiveTabId(realTabid)\n\n return {\n success: true,\n tabid: realTabid,\n url: page.url(),\n title: await page.title()\n }\n } finally {\n await browser.disconnect()\n }\n}\n\nexport async function tabsBackCommand(tabid?: string) {\n const browser = await connectBrowser()\n try {\n const page = await getTargetPage(browser, tabid)\n const response = await page.goBack()\n\n if (!response) {\n return {\n success: false,\n error: '无法后退:已在历史记录起点',\n tabid: await getPageTargetId(page).catch(() => tabid),\n url: page.url(),\n title: await page.title()\n }\n }\n\n await injectIntoPage(page)\n\n return {\n success: true,\n tabid: await getPageTargetId(page),\n url: page.url(),\n title: await page.title()\n }\n } finally {\n await browser.disconnect()\n }\n}\n\nexport async function tabsForwardCommand(tabid?: string) {\n const browser = await connectBrowser()\n try {\n const page = await getTargetPage(browser, tabid)\n const response = await page.goForward()\n\n if (!response) {\n return {\n success: false,\n error: '无法前进:已在历史记录末尾',\n tabid: await getPageTargetId(page).catch(() => tabid),\n url: page.url(),\n title: await page.title()\n }\n }\n\n await injectIntoPage(page)\n\n return {\n success: true,\n tabid: await getPageTargetId(page),\n url: page.url(),\n title: await page.title()\n }\n } finally {\n await browser.disconnect()\n }\n}\n","{\n \"name\": \"@opentiny/webmcp-cli\",\n \"version\": \"0.0.8\",\n \"type\": \"module\",\n \"description\": \"WebMCP CLI for AI Agents to interact with browser via Puppeteer\",\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"bin\": {\n \"webmcp-cli\": \"./dist/bin.js\"\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"scripts\": {\n \"dev\": \"tsup --watch\",\n \"build:inject\": \"node scripts/build-inject.mjs\",\n \"build\": \"tsup && pnpm run build:inject\",\n \"prepublishOnly\": \"pnpm run build\",\n \"link:global\": \"npm install -g .\",\n \"start\": \"node dist/bin.js\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:browser\": \"vitest run --config vitest.e2e.config.ts\"\n },\n \"keywords\": [\n \"chrome\",\n \"puppeteer\",\n \"cli\"\n ],\n \"license\": \"MIT\",\n \"author\": \"OpenTiny Team\",\n \"engines\": {\n \"node\": \">=16\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"dependencies\": {\n \"@mcp-b/webmcp-polyfill\": \"catalog:\",\n \"@opentiny/next-sdk\": \"workspace:^\",\n \"@page-agent/page-controller\": \"catalog:\",\n \"clipboardy\": \"^5.3.1\",\n \"commander\": \"^11.1.0\",\n \"json5\": \"^2.2.3\",\n \"marked\": \"^15.0.7\",\n \"picocolors\": \"^1.0.0\",\n \"puppeteer-core\": \"^22.0.0\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20.0.0\",\n \"esbuild\": \"^0.25.0\",\n \"tsup\": \"^8.0.2\",\n \"tsx\": \"^4.0.0\",\n \"typescript\": \"^5.3.3\",\n \"vitest\": \"^4.1.10\"\n }\n}\n"],"mappings":"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","names":["import_fs","import_path","import_os","import_picocolors","JSON5","expanded","import_fs","import_path","import_url","path","os","fs","resolve","http","puppeteer","pc","tabs","resolve","resolve","clipboard","resolve","path","fs","os","pc"]}
1
+ {"version":3,"sources":["../src/browser.ts","../package.json","../src/mcp/tools.ts","../src/adapters/cdp-adapter.ts","../src/bridge/protocol.ts","../src/bridge/workspace-manager.ts","../src/bridge/bash-executor.ts","../src/bridge/directory-picker.ts","../src/bridge/bridge-client.ts","../src/adapters/wxt-adapter.ts","../src/bridge/daemon.ts","../src/mcp/server.ts","../src/commands/agent.ts","../src/commands/skills.ts","../src/bin.ts","../src/expand-file-refs.ts","../src/parse-run-args.ts","../src/commands/state.ts","../src/commands/run.ts","../src/commands/clipboard.ts","../src/commands/tabs.ts"],"sourcesContent":["import puppeteer, { Browser, Page } from 'puppeteer-core'\nimport pc from 'picocolors'\nimport fs from 'fs'\nimport os from 'os'\nimport path from 'path'\nimport http from 'http'\nimport { spawn } from 'child_process'\nimport { fileURLToPath } from 'url'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\n\nfunction getCdpPort(): number {\n const raw = process.env.WEBMCP_CDP_PORT\n if (raw) {\n const port = Number.parseInt(raw, 10)\n if (Number.isFinite(port) && port > 0) return port\n }\n return 9222\n}\n\nfunction getWorkspaceDir(): string {\n return process.env.WEBMCP_WORKSPACE || path.join(os.homedir(), '.webmcp_chrome_profile')\n}\n\n/** CI / 自动化测试:无头 + sandbox 关闭,避免 Linux runner 缺 display / 权限问题。\n * WEBMCP_HEADLESS=0 可显式强制有界面(覆盖 CI 环境变量)。\n */\nfunction shouldLaunchHeadless(): boolean {\n if (process.env.WEBMCP_HEADLESS === '0') return false\n return process.env.WEBMCP_HEADLESS === '1' || process.env.CI === 'true' || process.env.CI === '1'\n}\n\n/**\n * 读取 Chrome 写入 user-data-dir 的 DevToolsActivePort 文件,获取该 profile 实际绑定的 CDP 端口。\n * 当默认 CDP 端口(9222,或 WEBMCP_CDP_PORT)被系统上其他工具占用时,Chrome 会静默切换到一个随机可用端口并记录在此文件中。\n * 注意:Chrome 136+ 起该文件在部分版本/场景下可能不再写入,因此这只是辅助检测手段,\n * 不能作为唯一依据,主逻辑仍以直接探测固定端口为准(见 candidateCdpBaseUrls)。\n */\nfunction readActivePortFromProfile(userDataDir: string): number | null {\n try {\n const content = fs.readFileSync(path.join(userDataDir, 'DevToolsActivePort'), 'utf-8')\n const port = parseInt(content.split('\\n')[0].trim(), 10)\n return Number.isFinite(port) && port > 0 ? port : null\n } catch {\n return null\n }\n}\n\n/**\n * 生成某端口下所有需要尝试的 CDP 基础地址。\n *\n * 背景:自 Chrome 136 起,`--remote-debugging-address` 已被忽略/移除(安全加固),\n * CDP 服务器改为固定绑定 \"localhost\" 解析出的回环地址;而不同系统上 \"localhost\" 的\n * DNS 解析顺序不一致(有的优先 IPv4 127.0.0.1,有的优先 IPv6 ::1),我们无法再通过\n * 启动参数强制指定地址族。因此这里显式列出 IPv4、IPv6 字面地址和 \"localhost\" 三种形式,\n * 逐一探测,不对地址族做任何假设,才能在所有平台上稳定探测到实际监听地址。\n */\nfunction candidateCdpBaseUrls(port: number): string[] {\n return [\n `http://127.0.0.1:${port}`,\n `http://[::1]:${port}`,\n `http://localhost:${port}`\n ]\n}\n\nfunction getLastTabIdFilePath(): string {\n return path.join(getWorkspaceDir(), '.last-tab-id')\n}\n\n/** 记录最近一次 tabs open / tabs switch 操作的标签页,供 run 无 -t 时回退定位 */\nexport function setLastActiveTabId(tabid: string): void {\n try {\n const dir = getWorkspaceDir()\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n fs.writeFileSync(getLastTabIdFilePath(), tabid, 'utf-8')\n } catch {\n // 写入失败不阻断主流程\n }\n}\n\nfunction getLastActiveTabId(): string | null {\n try {\n const tabid = fs.readFileSync(getLastTabIdFilePath(), 'utf-8').trim()\n return tabid || null\n } catch {\n return null\n }\n}\n\n/**\n * 使用 Node.js 原生 http 模块发起 GET 请求并返回响应体文本\n * 避免 Node.js fetch 将 localhost 解析为 IPv6 ::1 导致连接 Chrome CDP 失败的问题\n */\nfunction httpGet(url: string, timeoutMs = 1500): Promise<string> {\n return new Promise((resolve, reject) => {\n const req = http.get(url, { timeout: timeoutMs }, (res) => {\n let data = ''\n res.on('data', (chunk: Buffer) => { data += chunk.toString() })\n res.on('end', () => {\n if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {\n resolve(data)\n } else {\n reject(new Error(`HTTP ${res.statusCode}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('request timeout')) })\n })\n}\n\nfunction promiseWithTimeout<T>(promise: Promise<T>, timeoutMs = 5000, errorMsg = 'Operation timed out'): Promise<T> {\n let timeoutId: NodeJS.Timeout\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(errorMsg))\n }, timeoutMs)\n })\n return Promise.race([promise, timeoutPromise]).finally(() => {\n clearTimeout(timeoutId)\n })\n}\n\nasync function checkCdpReady(url: string, retries = 3): Promise<boolean> {\n for (let i = 0; i < retries; i++) {\n try {\n await httpGet(url, 1500)\n return true\n } catch {}\n if (i < retries - 1) {\n await new Promise(r => setTimeout(r, 200))\n }\n }\n return false\n}\n\n/**\n * 找出第一个真正可达的 CDP 地址,避免 Windows 上 localhost 解析为 IPv6 导致 puppeteer 连接失败\n */\nasync function findAvailableCdpUrl(addresses: string[], retries = 2): Promise<string | null> {\n for (const addr of addresses) {\n if (await checkCdpReady(addr, retries)) {\n return addr.replace('/json/version', '')\n }\n }\n return null\n}\n\n/**\n * 通过 Puppeteer 连接已运行的浏览器。\n * 注意:不要在 connect 时使用 targetFilter——在 Windows Edge 上会导致 WebSocket 握手后永久挂起;\n * 页面 target 的筛选在 getPageTargets / getTargetPage 中按需完成。\n */\nasync function connectPuppeteer(browserBaseUrl: string, attempt = 1, maxAttempts = 3): Promise<Browser> {\n try {\n return await promiseWithTimeout(\n puppeteer.connect({ browserURL: browserBaseUrl, defaultViewport: null }),\n 10000,\n `puppeteer.connect to ${browserBaseUrl} timed out`\n )\n } catch (err) {\n if (attempt >= maxAttempts) {\n throw err\n }\n const delayMs = 500 * attempt\n console.log(pc.yellow(`connectBrowser: 第 ${attempt} 次连接失败,${delayMs}ms 后重试...`))\n await new Promise(resolve => setTimeout(resolve, delayMs))\n return connectPuppeteer(browserBaseUrl, attempt + 1, maxAttempts)\n }\n}\n\n\n\ninterface BrowserInfo {\n path: string\n name: string\n}\n\nfunction getDefaultBrowserPath(): BrowserInfo | null {\n // CI / 本地可显式指定可执行文件(browser-actions/setup-chrome 会输出 chrome-path)\n const envPath =\n process.env.CHROME_PATH ||\n process.env.WEBMCP_CHROME_PATH ||\n process.env.PUPPETEER_EXECUTABLE_PATH\n if (envPath && fs.existsSync(envPath)) {\n return { path: envPath, name: 'Chrome' }\n }\n if (envPath) {\n console.log(pc.yellow(`指定的浏览器路径不存在,将回退到自动检测: ${envPath}`))\n }\n\n const platform = os.platform()\n if (platform === 'darwin') {\n // macOS:优先 Chrome,其次 Edge\n const chromePath = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'\n if (fs.existsSync(chromePath)) return { path: chromePath, name: 'Chrome' }\n const edgePath = '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge'\n if (fs.existsSync(edgePath)) return { path: edgePath, name: 'Edge' }\n return null\n } else if (platform === 'win32') {\n // Windows:优先 Chrome,其次 Edge(系统内置路径)\n const chromePaths = [\n process.env.LOCALAPPDATA + '\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n process.env.PROGRAMFILES + '\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n process.env['PROGRAMFILES(X86)'] + '\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe'\n ]\n const foundChrome = chromePaths.find(p => fs.existsSync(p))\n if (foundChrome) return { path: foundChrome, name: 'Chrome' }\n\n // Edge 在 Windows 上的常见路径(包括系统内置的 Edge)\n const edgePaths = [\n process.env.LOCALAPPDATA + '\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n process.env.PROGRAMFILES + '\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n process.env['PROGRAMFILES(X86)'] + '\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n 'C:\\\\Program Files (x86)\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n 'C:\\\\Program Files\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe'\n ]\n const foundEdge = edgePaths.find(p => fs.existsSync(p))\n if (foundEdge) return { path: foundEdge, name: 'Edge' }\n return null\n } else {\n // Linux:优先 Chrome,其次 Chromium,最后 Edge\n const paths: Array<{ p: string; name: string }> = [\n { p: '/usr/bin/google-chrome', name: 'Chrome' },\n { p: '/usr/bin/google-chrome-stable', name: 'Chrome' },\n { p: '/usr/bin/chromium', name: 'Chromium' },\n { p: '/usr/bin/chromium-browser', name: 'Chromium' },\n { p: '/usr/bin/microsoft-edge', name: 'Edge' },\n { p: '/usr/bin/microsoft-edge-stable', name: 'Edge' }\n ]\n const found = paths.find(({ p }) => fs.existsSync(p))\n return found ? { path: found.p, name: found.name } : null\n }\n}\n\nasync function startBrowserInBackground(): Promise<string> {\n const browserInfo = getDefaultBrowserPath()\n if (!browserInfo || !fs.existsSync(browserInfo.path)) {\n throw new Error('无法在系统中找到 Chrome 或 Edge 浏览器的默认安装路径。')\n }\n\n const cdpPort = getCdpPort()\n console.log(pc.yellow(`正在启动后台 ${browserInfo.name} 实例 (端口: ${cdpPort})...`))\n \n // 用户可以通过 --workspace CLI 选项或 WEBMCP_WORKSPACE 环境变量自定义。\n const userDataDir = getWorkspaceDir()\n if (!fs.existsSync(userDataDir)) {\n fs.mkdirSync(userDataDir, { recursive: true })\n }\n\n // 启动前先清除旧的 DevToolsActivePort 记录,避免读取到上一次运行残留的过期端口\n try {\n fs.unlinkSync(path.join(userDataDir, 'DevToolsActivePort'))\n } catch {}\n \n // 注:Chrome 136+ 已不再支持 `--remote-debugging-address` 指定绑定地址(安全加固后被忽略),\n // CDP 服务器固定绑定 \"localhost\" 解析出的回环地址,具体是 IPv4 还是 IPv6 由系统决定,\n // 因此不再传递该参数,探测阶段改为同时尝试 IPv4/IPv6/localhost 三种地址形式。\n const launchArgs = [\n `--remote-debugging-port=${cdpPort}`,\n `--user-data-dir=${userDataDir}`,\n '--no-first-run',\n '--no-default-browser-check'\n ]\n\n if (shouldLaunchHeadless()) {\n launchArgs.push(\n '--headless=new',\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-gpu',\n '--disable-dev-shm-usage'\n )\n }\n\n const child = spawn(\n browserInfo.path,\n launchArgs,\n {\n detached: true,\n stdio: 'ignore'\n }\n )\n\n child.unref() // 让子进程脱离父进程独立运行\n\n // 轮询等待 CDP 端口就绪。优先探测固定的 cdpPort(IPv4/IPv6/localhost 三种地址形式都尝试,\n // 不对地址族做假设);同时也检查 DevToolsActivePort 文件——如果 cdpPort 被其他程序占用,\n // 部分 Chrome 版本会自动切换到随机端口并记录在该文件中,作为额外兜底。\n for (let i = 0; i < 40; i++) {\n const ports = new Set<number>([cdpPort])\n const activePort = readActivePortFromProfile(userDataDir)\n if (activePort) ports.add(activePort)\n\n for (const port of ports) {\n for (const baseUrl of candidateCdpBaseUrls(port)) {\n try {\n await httpGet(`${baseUrl}/json/version`, 1000)\n if (port !== cdpPort) {\n console.log(pc.yellow(`检测到端口 ${cdpPort} 已被其他程序占用,${browserInfo.name} 已自动切换到端口 ${port}。`))\n }\n console.log(pc.green(`${browserInfo.name} 启动并就绪(${baseUrl})。`))\n // 额外等待 500ms,确保 CDP 完全稳定(Mac 首次启动时端口通但连接不稳定)\n await new Promise(resolve => setTimeout(resolve, 500))\n return baseUrl\n } catch {}\n }\n }\n await new Promise(resolve => setTimeout(resolve, 500))\n }\n\n throw new Error(`${browserInfo.name} 启动超时,无法连接到 CDP 端口。`)\n}\n\nexport async function connectBrowser(): Promise<Browser> {\n const userDataDir = getWorkspaceDir()\n const cdpPort = getCdpPort()\n\n // 第一步:找到第一个真正可达的 CDP 地址(IPv4/IPv6/localhost 三种形式都尝试,不假设地址族)。\n // 若本工具专属 profile 上一次运行时因端口冲突被 Chrome 切换到了非默认端口,\n // 优先尝试 DevToolsActivePort 记录的真实端口,避免误判为“未运行”而重复启动新实例。\n const recordedPort = readActivePortFromProfile(userDataDir)\n const versionAddresses = [\n ...(recordedPort && recordedPort !== cdpPort ? candidateCdpBaseUrls(recordedPort).map(u => `${u}/json/version`) : []),\n ...candidateCdpBaseUrls(cdpPort).map(u => `${u}/json/version`)\n ]\n\n const existingUrl = await findAvailableCdpUrl(versionAddresses, 2)\n if (existingUrl) {\n console.log(pc.yellow(`connectBrowser: 检测到端口 ${cdpPort} 已就绪,正在连接 ${existingUrl}...`))\n try {\n const browser = await connectPuppeteer(existingUrl)\n console.log(pc.green(`connectBrowser: 成功连接 ${existingUrl}`))\n return browser\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n throw new Error(\n `无法连接到已在运行的浏览器(${existingUrl}):${msg}。` +\n 'CDP 端口可用,请勿重复启动浏览器;可关闭多余窗口后重试。'\n )\n }\n }\n\n // 第二步:端口无响应,启动新的浏览器实例(使用独立用户数据目录,不影响用户已有浏览器)\n console.log(pc.yellow(`connectBrowser: 端口 ${cdpPort} 无响应,正在启动新的浏览器实例...`))\n let launchedUrl: string\n try {\n launchedUrl = await startBrowserInBackground()\n } catch (launchError: unknown) {\n const msg = launchError instanceof Error ? launchError.message : String(launchError)\n console.error(pc.red(`无法启动浏览器: ${msg}`))\n throw new Error('Browser launch failed.')\n }\n\n // 第三步:使用启动过程中确认过的真实 CDP 地址进行连接\n try {\n console.log(pc.yellow(`connectBrowser: 浏览器已启动,正在连接 ${launchedUrl}...`))\n const browser = await connectPuppeteer(launchedUrl)\n console.log(pc.green(`connectBrowser: 成功连接 ${launchedUrl}`))\n return browser\n } catch {\n throw new Error(`无法连接到浏览器(${launchedUrl}),请检查 Chrome/Edge 是否已安装。`)\n }\n}\n\n\n/**\n * 通过 CDP 获取页面真实的 Chrome target ID(UUID 格式字符串)\n * 供 state.ts 等命令展示 tabs 列表时使用\n */\nexport async function getPageTargetId(page: Page): Promise<string> {\n const session = await page.target().createCDPSession()\n try {\n const { targetInfo } = await session.send('Target.getTargetInfo')\n return targetInfo.targetId\n } finally {\n await session.detach().catch(() => {})\n }\n}\n\nexport function getPageTargets(browser: Browser) {\n return browser.targets().filter(t => {\n try {\n const type = (typeof t.type === 'function' ? t.type() : (t as any).type) || ''\n const url = (typeof t.url === 'function' ? t.url() : (t as any).url) || ''\n return type === 'page' && !url.startsWith('devtools://')\n } catch {\n return false\n }\n })\n}\n\nexport function getTargetIdFromTarget(target: any): string {\n return typeof target._getTargetInfo === 'function'\n ? target._getTargetInfo().targetId\n : (target._targetId || target.targetId || '')\n}\n\nexport function findPageTargetByTabId(browser: Browser, tabid: string) {\n const pageTargets = getPageTargets(browser)\n return pageTargets.find(t => {\n const tid = getTargetIdFromTarget(t)\n return tid === tabid || tid.includes(tabid)\n }) ?? null\n}\n\nexport async function activateTabById(browser: Browser, tabid: string): Promise<void> {\n const target = findPageTargetByTabId(browser, tabid)\n if (!target) {\n throw new Error(`Tab with targetId \"${tabid}\" not found.`)\n }\n\n const realTabId = getTargetIdFromTarget(target)\n const pages = await browser.pages()\n let sessionPage = pages.find(p => !p.url().startsWith('devtools://'))\n if (!sessionPage && pages.length > 0) {\n sessionPage = pages[0]\n }\n if (!sessionPage) {\n sessionPage = await browser.newPage()\n }\n\n const session = await sessionPage.createCDPSession()\n try {\n await session.send('Target.activateTarget', { targetId: realTabId })\n } finally {\n await session.detach().catch(() => {})\n }\n}\n\nexport async function getTargetPage(browser: Browser, tabid?: string): Promise<Page> {\n const pageTargets = getPageTargets(browser)\n\n if (pageTargets.length === 0) {\n const newPage = await browser.newPage()\n await injectWebMCPPolyfillAndTools(newPage)\n return newPage\n }\n\n let targetPage: Page | null = null\n\n if (tabid !== undefined) {\n const target = findPageTargetByTabId(browser, tabid)\n if (!target) {\n throw new Error(`Tab with targetId \"${tabid}\" not found.`)\n }\n targetPage = await target.page()\n } else {\n // 优先使用最近一次 tabs open/switch 记录的标签页(Agent 连续 CLI 调用更可靠)\n const lastTabId = getLastActiveTabId()\n if (lastTabId) {\n const lastTarget = findPageTargetByTabId(browser, lastTabId)\n if (lastTarget) {\n targetPage = await lastTarget.page()\n }\n }\n\n // Chrome 的 /json/list 接口把当前激活 the tab 排在第一位,用它来判断激活 tab\n if (!targetPage) {\n try {\n // 与 connectBrowser 一致:若 Chrome 因端口冲突切到非默认端口,一并探测 DevToolsActivePort\n const workspaceDir = getWorkspaceDir()\n const cdpPort = getCdpPort()\n const recordedPort = readActivePortFromProfile(workspaceDir)\n const ports = recordedPort && recordedPort !== cdpPort ? [recordedPort, cdpPort] : [cdpPort]\n const urls = ports.flatMap((port) => candidateCdpBaseUrls(port).map((u) => `${u}/json/list`))\n let activeTargetId: string | null = null\n for (const url of urls) {\n try {\n const body = await httpGet(url, 1000)\n const targetsData: Array<{ id: string; type: string; url: string }> = JSON.parse(body)\n // 找第一个 type=page 且不是 devtools:// 的 target(Chrome 把激活的排第一)\n const active = targetsData.find(t => t.type === 'page' && !t.url.startsWith('devtools://'))\n if (active) { activeTargetId = active.id; break }\n } catch { /* 忽略,继续试下一个地址 */ }\n }\n\n if (activeTargetId) {\n for (const target of pageTargets) {\n if (getTargetIdFromTarget(target) === activeTargetId) {\n targetPage = await target.page()\n break\n }\n }\n }\n } catch { /* 忽略,使用 fallback */ }\n }\n\n // fallback:取最后一个非 devtools 页面\n if (!targetPage) {\n const lastTarget = pageTargets[pageTargets.length - 1]\n targetPage = await lastTarget.page()\n }\n }\n\n if (!targetPage) {\n throw new Error('无法获取目标页面')\n }\n\n // 注入 polyfill 和域名工具(幂等检查)\n await injectWebMCPPolyfillAndTools(targetPage)\n return targetPage\n}\n\n/**\n * 供 tabs open / back / forward / state / run 等命令调用:仅在尚未注入时注入一次(幂等)。\n * 导航后页面 JS 上下文会清空,`__webmcpcli_init` 自然失效,下次调用会重新注入。\n */\nexport async function injectIntoPage(page: Page): Promise<void> {\n await injectWebMCPPolyfillAndTools(page)\n}\n\nasync function injectWebMCPPolyfillAndTools(page: Page) {\n // 已注入则跳过,避免覆盖 page-agent-tool 闭包内的 refMap\n const polyfillReady = await page.evaluate(() => {\n return !!(window as any).__webmcpcli_init\n }).catch(() => false)\n\n if (!polyfillReady) {\n console.log(pc.cyan('当前页面尚未注入 WebMCP 环境,正在执行自动注入...'))\n\n const injectScriptPath = path.resolve(__dirname, 'inject-bundle.js')\n if (!fs.existsSync(injectScriptPath)) {\n throw new Error(`Cannot find inject-bundle.js at ${injectScriptPath}. Please ensure you run 'pnpm build:inject' first.`)\n }\n\n const scriptContent = fs.readFileSync(injectScriptPath, 'utf-8')\n\n // 注入 WebMCP polyfill\n try {\n await page.evaluate(scriptContent)\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err)\n throw new Error('自动注入脚本执行失败: ' + msg)\n }\n\n // 显式等待 WebMCP 注册接口完全就绪\n await page.waitForFunction(() => {\n const mcp = (navigator as any).modelContext\n return mcp && typeof mcp.registerTool === 'function'\n }, { timeout: 10000 }).catch(() => {\n console.warn('等待 WebMCP registerTool 接口就绪超时,正在继续注入...')\n })\n }\n\n // 无论 polyfill 是否刚注入,都检查域名工具(工具内部有防重复 flag)\n await injectDomainTools(page)\n}\n\nfunction getToolsBundleName(hostname: string): string | null {\n const normalized = hostname.split(':')[0].toLowerCase()\n const toolsDir = path.resolve(__dirname, 'webmcp-tools')\n if (!fs.existsSync(toolsDir)) {\n return null\n }\n let files: string[] = []\n try {\n files = fs.readdirSync(toolsDir)\n } catch {\n return null\n }\n const supportedDomains = files\n .filter(f => f.endsWith('.js'))\n .map(f => f.slice(0, -3))\n\n if (supportedDomains.includes(normalized)) {\n return `webmcp-tools/${normalized}.js`\n }\n for (const domain of supportedDomains) {\n if (normalized.endsWith('.' + domain)) {\n return `webmcp-tools/${domain}.js`\n }\n }\n return null\n}\n\n/**\n * 根据页面域名查找并注入对应的工具 bundle\n * bundle 文件位于 dist/webmcp-tools/{hostname}.js\n * 注意:每个工具 bundle 内部会在 window 上设置 __webmcptools_{domain} flag 防止重复注册,\n * 此处在 JS 层额外做一次快速检查,避免每次都 evaluate 完整脚本带来不必要的 IPC 开销。\n */\nasync function injectDomainTools(page: Page): Promise<void> {\n let hostname: string\n try {\n const url = new URL(page.url())\n hostname = url.hostname\n } catch {\n return // 非 http(s) 页面,跳过\n }\n\n const bundleName = getToolsBundleName(hostname)\n if (!bundleName) {\n return // 没有对应的工具预置,跳过\n }\n\n const toolBundlePath = path.resolve(__dirname, bundleName)\n if (!fs.existsSync(toolBundlePath)) {\n return // 文件不存在,跳过\n }\n\n // 快速检查:若页面已注入,直接返回,省去读文件和 evaluate 的开销\n const bundleKey = bundleName.replace(/^webmcp-tools\\//, '').replace(/\\.js$/, '')\n const flagKey = `__webmcptools_${bundleKey.replace(/[^a-zA-Z0-9]/g, '')}`\n const alreadyInjected = await page.evaluate((key: string) => !!(window as any)[key], flagKey).catch(() => false)\n if (alreadyInjected) {\n return\n }\n\n console.log(pc.cyan(`检测到域名 ${hostname} 有预置工具,正在注入...`))\n\n const toolScript = fs.readFileSync(toolBundlePath, 'utf-8')\n try {\n await page.evaluate(toolScript)\n console.log(pc.green(`已为 ${hostname} 注入预置工具`))\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err)\n // 工具注入失败不阻断主流程,仅打印警告\n console.warn(pc.yellow(`域名工具注入失败 (${hostname}): ${msg}`))\n }\n}\n\n","{\n \"name\": \"@opentiny/webmcp-cli\",\n \"version\": \"0.0.9\",\n \"type\": \"module\",\n \"description\": \"WebMCP CLI for AI Agents to interact with browser via Puppeteer\",\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"bin\": {\n \"webmcp-cli\": \"./dist/bin.js\"\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"scripts\": {\n \"dev\": \"tsup --watch\",\n \"build:inject\": \"node scripts/build-inject.mjs\",\n \"build\": \"tsup && pnpm run build:inject\",\n \"prepublishOnly\": \"pnpm run build\",\n \"link:global\": \"npm install -g .\",\n \"start\": \"node dist/bin.js\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:browser\": \"vitest run --config vitest.e2e.config.ts\"\n },\n \"keywords\": [\n \"chrome\",\n \"puppeteer\",\n \"cli\"\n ],\n \"license\": \"MIT\",\n \"author\": \"OpenTiny Team\",\n \"engines\": {\n \"node\": \">=16\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"dependencies\": {\n \"@mcp-b/webmcp-polyfill\": \"catalog:\",\n \"@modelcontextprotocol/sdk\": \"catalog:\",\n \"@opentiny/next-sdk\": \"workspace:^\",\n \"@page-agent/page-controller\": \"catalog:\",\n \"clipboardy\": \"^5.3.1\",\n \"commander\": \"^11.1.0\",\n \"json5\": \"^2.2.3\",\n \"marked\": \"^15.0.7\",\n \"picocolors\": \"^1.0.0\",\n \"puppeteer-core\": \"^22.0.0\",\n \"ws\": \"^8.18.0\",\n \"zod\": \"^3.23.0\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20.0.0\",\n \"@types/ws\": \"^8.5.10\",\n \"esbuild\": \"^0.25.0\",\n \"tsup\": \"^8.0.2\",\n \"tsx\": \"^4.0.0\",\n \"typescript\": \"^5.3.3\",\n \"vitest\": \"^4.1.10\"\n }\n}\n","/**\n * MCP 工具 Schema 定义(统一层)\n *\n * 工具名称与描述在 CDP 和 WXT 两种模式下保持一致。\n * 底层实现由 bin.ts 根据 --mode 路由到对应 adapter。\n */\n\nimport { z } from 'zod'\n\n// ─── 通用工具(两种模式均支持) ──────────────────────────────────────────────\n\nexport const BrowserStateInput = z.object({\n tabId: z.union([z.string(), z.number()]).optional().describe(\n '目标 tab ID。CDP 模式为 target UUID 字符串;WXT 模式为 Chrome tab ID 数值。不传时使用当前活跃 tab。'\n )\n})\n\nexport const BrowserToolCallInput = z.object({\n toolName: z\n .string()\n .describe('页面 WebMCP 工具名称(可从 browser_state 返回的 webmcpTools 列表中获取)'),\n toolArgs: z.record(z.unknown()).optional().describe('工具参数,与工具的 inputSchema 对齐'),\n tabId: z.union([z.string(), z.number()]).optional().describe('目标 tab ID,不传时使用当前活跃 tab')\n})\n\nexport const BrowserTabsOpenInput = z.object({\n url: z\n .string()\n .url()\n .refine((val) => /^https?:\\/\\//i.test(val), { message: '只允许打开 http 或 https 协议的 URL' })\n .describe('要打开的 URL(仅支持 http/https 协议)')\n})\n\nexport const BrowserTabsCloseInput = z.object({\n tabId: z.union([z.string(), z.number()]).optional().describe(\n '要关闭的 tab ID,不传时关闭当前活跃 tab'\n )\n})\n\nexport const BrowserTabsSwitchInput = z.object({\n tabId: z.union([z.string(), z.number()]).describe(\n '要切换到的 tab ID(可从 browser_state 返回的 tabs 列表中获取)'\n ),\n activateVisible: z\n .boolean()\n .optional()\n .describe('是否在前台显式切换 Chrome 可见活动标签(仅 WXT 模式有效,默认 false)')\n})\n\nexport const BrowserTabsNavInput = z.object({\n tabId: z.union([z.string(), z.number()]).optional().describe('目标 tab ID,不传时使用当前活跃 tab')\n})\n\n// ─── WXT 专属工具 ──────────────────────────────────────────────────────────\n\nexport const BrowserSubAgentRunInput = z.object({\n instruction: z.string().describe('要委托给 Tiny Robot 子代理执行的高层自然语言任务指令'),\n tabId: z.number().optional().describe('目标 tab ID,不传时使用当前活跃 tab'),\n maxSteps: z.number().min(1).max(20).optional().describe('最大自主规划执行步数(默认 8,最大 20)')\n})\n\nexport const BrowserSkillsListInput = z.object({}).describe('获取当前浏览器扩展中已注册的所有 Skills 技能元数据列表')\n\nexport const BrowserSkillsReadInput = z.object({\n name: z.string().describe('要读取的技能名称(可从 browser_skills_list 返回的列表中获取)')\n})\n","/**\n * CdpBrowserAdapter\n *\n * 基于 Puppeteer + CDP 协议实现的 BrowserAdapter,\n * 复用现有 browser.ts 的连接逻辑和 commands/ 下的实现。\n */\n\nimport type { Browser } from 'puppeteer-core'\nimport {\n connectBrowser,\n getTargetPage,\n injectIntoPage,\n getPageTargetId,\n activateTabById,\n setLastActiveTabId\n} from '../browser.js'\nimport type { BrowserAdapter, BrowserStateResult, TabsOptions } from './interface.js'\n\nexport class CdpBrowserAdapter implements BrowserAdapter {\n private browser: Browser | null = null\n\n private async getBrowser(): Promise<Browser> {\n if (!this.browser) {\n this.browser = await connectBrowser()\n }\n return this.browser\n }\n\n async getState(tabId?: string | number): Promise<BrowserStateResult> {\n const browser = await this.getBrowser()\n const tabIdStr = tabId != null ? String(tabId) : undefined\n const page = await getTargetPage(browser, tabIdStr)\n await injectIntoPage(page)\n\n const state = await page.evaluate(async () => {\n const url = document.URL\n const title = document.title\n const mcp = (document as any).modelContext || (navigator as any).modelContext\n let webmcpTools: Array<{ name: string; description?: string }> = []\n if (mcp && typeof mcp.getTools === 'function') {\n try {\n const toolsResult = await mcp.getTools()\n const list = (toolsResult?.tools || toolsResult || []) as Array<{ name?: string; description?: string }>\n webmcpTools = list\n .filter((t) => t && typeof t.name === 'string')\n .map((t) => ({\n name: t.name as string,\n description: typeof t.description === 'string' ? t.description.slice(0, 200) : undefined\n }))\n } catch {\n webmcpTools = []\n }\n }\n return { url, title, webmcpTools }\n })\n\n const activeTabId = await getPageTargetId(page).catch(() => null)\n const pages = await browser.pages()\n const tabs = await Promise.all(\n pages.map(async (p) => {\n const pUrl = p.url()\n if (pUrl.startsWith('devtools://')) return null\n const pTitle = await Promise.race([\n p.title().catch(() => 'Unknown'),\n new Promise<string>((resolve) => setTimeout(() => resolve('Unknown'), 500))\n ])\n return {\n tabId: await getPageTargetId(p).catch(() => pUrl),\n title: pTitle,\n url: pUrl\n }\n })\n )\n\n return {\n ...state,\n activeTabId: activeTabId ?? undefined,\n tabs: tabs.filter(Boolean) as BrowserStateResult['tabs']\n }\n }\n\n async callTool(toolName: string, args: Record<string, unknown>, tabId?: string | number): Promise<unknown> {\n const browser = await this.getBrowser()\n const tabIdStr = tabId != null ? String(tabId) : undefined\n const page = await getTargetPage(browser, tabIdStr)\n const urlBefore = page.url()\n await injectIntoPage(page)\n\n const argsJson = JSON.stringify(args)\n try {\n const result = await page.evaluate(\n async (name, inputString) => {\n // @ts-expect-error WebMCP APIs are experimental\n const mcp = document.modelContext || navigator.modelContext\n if (!mcp || typeof mcp.executeTool !== 'function') {\n throw new Error('当前页面没有注入 WebMCP 环境 (document.modelContext 未找到)')\n }\n const tools = await mcp.getTools()\n const toolObj = tools.find((t: any) => t.name === name)\n if (!toolObj) throw new Error(`Tool ${name} not found`)\n let res = await mcp.executeTool(toolObj, inputString)\n if (typeof res === 'string') {\n try {\n res = JSON.parse(res)\n } catch {\n /* 保留原始字符串 */\n }\n }\n if (res === undefined || res === null) {\n throw new Error('工具 execute 未返回结果')\n }\n if (typeof res === 'object' && (res as { success?: boolean }).success === false) {\n const failed = res as { error?: string; message?: string }\n throw new Error(failed.error || failed.message || '工具执行失败')\n }\n return res\n },\n toolName,\n argsJson\n )\n return result\n } catch (evalError: unknown) {\n const errMsg = evalError instanceof Error ? evalError.message : String(evalError)\n const isContextDestroyed =\n errMsg.includes('context was destroyed') ||\n errMsg.includes('Execution context was destroyed') ||\n (errMsg.includes('Cannot read properties of null') && errMsg.includes('context'))\n\n if (isContextDestroyed) {\n await new Promise((resolve) => setTimeout(resolve, 800))\n const newUrl = page.url()\n if (newUrl && newUrl !== urlBefore) {\n return { success: true, message: `工具 ${toolName} 执行完成,页面已导航至 ${newUrl}`, navigatedTo: newUrl }\n }\n }\n throw evalError\n }\n }\n\n async tabs(action: 'open' | 'close' | 'switch' | 'back' | 'forward', options: TabsOptions): Promise<unknown> {\n const browser = await this.getBrowser()\n const tabIdStr = options.tabId != null ? String(options.tabId) : undefined\n\n switch (action) {\n case 'open': {\n if (!options.url) throw new Error('tabs open 需要 url 参数')\n const page = await browser.newPage()\n await page.goto(options.url)\n await injectIntoPage(page)\n const tabId = await getPageTargetId(page)\n setLastActiveTabId(tabId)\n return { success: true, tabId, url: options.url }\n }\n case 'close': {\n const page = await getTargetPage(browser, tabIdStr)\n await page.close()\n return { success: true }\n }\n case 'switch': {\n if (!tabIdStr) throw new Error('tabs switch 需要 tabId 参数')\n await activateTabById(browser, tabIdStr)\n setLastActiveTabId(tabIdStr)\n return { success: true, tabId: tabIdStr }\n }\n case 'back': {\n const page = await getTargetPage(browser, tabIdStr)\n await page.goBack()\n return { success: true }\n }\n case 'forward': {\n const page = await getTargetPage(browser, tabIdStr)\n await page.goForward()\n return { success: true }\n }\n }\n }\n\n async dispose(): Promise<void> {\n if (this.browser) {\n await this.browser.disconnect().catch(() => {})\n this.browser = null\n }\n }\n}\n","/**\n * WebSocket 桥接核心协议常量与类型定义\n *\n * 供 CLI(@opentiny/webmcp-cli)与浏览器扩展端(tiny-robot-wxt)共享复用。\n */\n\n/** 默认本地 WebSocket 桥接服务端口 */\nexport const DEFAULT_WS_PORT = 18999\n\n/** 协议版本号:主版本号(major)不兼容时两端均拒绝握手 */\nexport const PROTOCOL_VERSION = '1.1.0'\n\n/** WebSocket 关闭状态码定义(4000~4999 私有保留区间) */\nexport const WS_CLOSE_CODE = {\n /** 被新接入的扩展连接平滑替换(旧连接触发退避重连) */\n REPLACED: 4000,\n /** 认证未通过(未提供 Token、Token 错误或 HMAC 签名校验失败) */\n UNAUTHORIZED: 4001,\n /** 协议主版本号不匹配 */\n PROTOCOL_MISMATCH: 4002\n} as const\n\nexport type WsCloseCode = (typeof WS_CLOSE_CODE)[keyof typeof WS_CLOSE_CODE]\n\n/** JSON-RPC 业务错误码定义 */\nexport const BRIDGE_ERROR_CODE = {\n /** 请求执行超时 */\n REQUEST_TIMEOUT: -32000,\n /** 命令执行超时 */\n EXECUTION_TIMEOUT: -32001,\n /** 命令或系统操作执行失败 */\n EXECUTION_FAILED: -32002,\n /** 无效参数(如 command 为空) */\n INVALID_PARAMS: -32602,\n /** 不支持的方法 */\n METHOD_NOT_FOUND: -32601,\n /** 扩展尚未连接至桥接服务 */\n EXTENSION_NOT_CONNECTED: -32051,\n /** 侧边栏尚未就绪或已关闭 */\n SIDEPANEL_NOT_READY: -32050\n} as const\n\nexport type BridgeErrorCode = (typeof BRIDGE_ERROR_CODE)[keyof typeof BRIDGE_ERROR_CODE]\n\n/** 核心 JSON-RPC 方法名常量 */\nexport const BRIDGE_METHODS = {\n TOOL_CALL: 'tool/call',\n SUB_AGENT_RUN: 'sub_agent/run',\n BROWSER_TABS: 'browser/tabs',\n BROWSER_STATE: 'browser/state',\n SKILLS_LIST: 'skills/list',\n SKILLS_GET: 'skills/get',\n SKILLS_READ_RESOURCE: 'skills/read_resource',\n SYSTEM_BASH: 'system/bash',\n SYSTEM_PICK_DIRECTORY: 'system/pick_directory'\n} as const\n\nexport type BridgeMethod = (typeof BRIDGE_METHODS)[keyof typeof BRIDGE_METHODS]\n","import path from 'node:path'\nimport os from 'node:os'\nimport fs from 'node:fs'\n\nexport const WORKSPACES_ROOT = path.join(os.homedir(), '.robot-wxt', 'workspaces')\n\nexport interface WorkspaceResolveParams {\n cwd?: string\n workspacePath?: string\n conversationId?: string\n}\n\nexport class BashInvalidParamsError extends Error {\n readonly code = 'INVALID_PARAMS' as const\n\n constructor(message: string = '参数错误') {\n super(message)\n this.name = 'BashInvalidParamsError'\n }\n}\n\nfunction resolveBaseWorkspace(params: WorkspaceResolveParams): string {\n if (params.workspacePath && typeof params.workspacePath === 'string' && params.workspacePath.trim()) {\n const trimmedWs = params.workspacePath.trim()\n return path.isAbsolute(trimmedWs) ? trimmedWs : path.resolve(os.homedir(), trimmedWs)\n }\n\n if (params.conversationId && typeof params.conversationId === 'string' && params.conversationId.trim()) {\n // 过滤路径分隔符、保留特殊字符以及点号,杜绝路径穿越\n const safeId = params.conversationId.trim().replace(/[/\\\\?%*:|\"<>.]/g, '_')\n const sessionDir = path.resolve(WORKSPACES_ROOT, safeId || 'default')\n\n // 严格校验必须位于 WORKSPACES_ROOT 之下\n const relative = path.relative(WORKSPACES_ROOT, sessionDir)\n if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {\n return path.join(WORKSPACES_ROOT, 'default')\n }\n return sessionDir\n }\n\n return path.join(WORKSPACES_ROOT, 'default')\n}\n\n/**\n * 按照优先级解析 Bash 执行目标工作目录,并强制实施安全边界收敛:\n * 1. 确定当前会话基准工作空间:优先采用已绑定的 workspacePath,次选基于 conversationId 的专属隔离沙箱,缺省回退至默认沙箱\n * 2. 严格收敛 cwd:若传入 cwd,必须位于基准工作空间内部(允许相对子路径或处于基准路径下的绝对路径);\n * 杜绝路径穿越(..)或逃逸到系统根目录等未授权位置,越界时抛出 BashInvalidParamsError。\n */\nexport function resolveWorkspaceDir(params: WorkspaceResolveParams = {}): string {\n const baseDir = resolveBaseWorkspace(params)\n\n if (!fs.existsSync(baseDir)) {\n try {\n fs.mkdirSync(baseDir, { recursive: true, mode: 0o755 })\n } catch {\n // ignore\n }\n }\n\n if (!params.cwd || typeof params.cwd !== 'string' || !params.cwd.trim()) {\n return baseDir\n }\n\n const trimmedCwd = params.cwd.trim()\n const targetDir = path.isAbsolute(trimmedCwd) ? path.resolve(trimmedCwd) : path.resolve(baseDir, trimmedCwd)\n\n const relative = path.relative(baseDir, targetDir)\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n throw new BashInvalidParamsError(`目标执行路径超出已授权工作空间安全边界: ${trimmedCwd}`)\n }\n\n return targetDir\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { spawn } from 'node:child_process'\nimport { resolveWorkspaceDir, BashInvalidParamsError } from './workspace-manager.js'\n\nexport { BashInvalidParamsError }\n\nexport interface ExecBashParams {\n command: string\n cwd?: string\n workspacePath?: string\n conversationId?: string\n timeoutMs?: number\n env?: Record<string, string>\n maxBuffer?: number\n}\n\nexport interface ExecBashResult {\n stdout: string\n stderr: string\n exitCode: number | null\n signal: NodeJS.Signals | null\n durationMs: number\n truncated?: boolean\n}\n\nexport class BashTimeoutError extends Error {\n readonly code = 'TIMEOUT' as const\n readonly timeoutMs: number\n\n constructor(timeoutMs: number) {\n super(`命令执行超时 (${timeoutMs / 1000}s)`)\n this.name = 'BashTimeoutError'\n this.timeoutMs = timeoutMs\n }\n}\n\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst MAX_TIMEOUT_MS = 600_000 // 最大执行超时 10 分钟,避免超出 Node.js setTimeout 32 位有符号整数上限 (2147483647) 导致立即触发\nconst DEFAULT_MAX_BUFFER = 512 * 1024 // 512KB\n\nlet cachedShell: string | null = null\n\nfunction findWindowsBash(): string | null {\n // 1. 检查 PATH 中是否存在 bash.exe\n const pathDirs = (process.env.PATH || '').split(path.delimiter)\n for (const dir of pathDirs) {\n if (!dir) continue\n const candidate = path.join(dir, 'bash.exe')\n try {\n if (fs.existsSync(candidate)) return candidate\n } catch {\n // 忽略\n }\n }\n\n // 2. 检查常见 Git for Windows 与系统级 bash 安装路径\n const localAppData = process.env.LOCALAPPDATA || ''\n const programFiles = process.env.ProgramFiles || 'C:\\\\Program Files'\n const programFilesX86 = process.env['ProgramFiles(x86)'] || 'C:\\\\Program Files (x86)'\n const programW6432 = process.env.ProgramW6432 || programFiles\n\n const commonGitBashPaths = [\n path.join(programFiles, 'Git', 'bin', 'bash.exe'),\n path.join(programFiles, 'Git', 'usr', 'bin', 'bash.exe'),\n path.join(programW6432, 'Git', 'bin', 'bash.exe'),\n path.join(programFilesX86, 'Git', 'bin', 'bash.exe'),\n path.join(localAppData, 'Programs', 'Git', 'bin', 'bash.exe'),\n path.join(localAppData, 'Programs', 'Git', 'usr', 'bin', 'bash.exe'),\n path.join(process.env.SystemRoot || 'C:\\\\Windows', 'System32', 'bash.exe')\n ]\n\n for (const candidate of commonGitBashPaths) {\n try {\n if (fs.existsSync(candidate)) return candidate\n } catch {\n // 忽略\n }\n }\n return null\n}\n\n/**\n * 跨平台解析可用的 Bash/Shell 路径:\n * - POSIX (macOS/Linux): 优先读取 process.env.SHELL,兜底 /bin/bash\n * - Windows: 优先探测系统中真实的 bash.exe(PATH、Git for Windows 常见安装目录、WSL),\n * 若存在则能 100% 完美执行原生 Bash 脚本;若未安装,降级回退至 powershell.exe(具备常用 Unix 别名)\n */\nexport function resolveShell(forcePlatform?: string): string {\n const currentPlatform = forcePlatform || process.platform\n if (!forcePlatform && cachedShell) {\n return cachedShell\n }\n\n if (currentPlatform !== 'win32') {\n const posixShell = process.env.SHELL || '/bin/bash'\n if (!forcePlatform) cachedShell = posixShell\n return posixShell\n }\n\n const winBash = findWindowsBash()\n if (winBash) {\n if (!forcePlatform) cachedShell = winBash\n return winBash\n }\n\n // 次选:PowerShell(自带 ls, cat, pwd, rm, cp 等常用 Unix 别名)\n const fallback = 'powershell.exe'\n if (!forcePlatform) cachedShell = fallback\n return fallback\n}\n\n/**\n * 跨平台杀死子进程树,防止 Windows 或 POSIX 下产生孤儿后台进程\n */\nfunction killProcessTree(child: ReturnType<typeof spawn>): void {\n if (process.platform === 'win32' && child.pid) {\n try {\n spawn('taskkill', ['/pid', String(child.pid), '/T', '/F'], {\n windowsHide: true,\n stdio: 'ignore'\n })\n } catch {\n child.kill('SIGKILL')\n }\n } else {\n child.kill('SIGTERM')\n setTimeout(() => {\n try {\n child.kill('SIGKILL')\n } catch {\n // ignore\n }\n }, 2000)\n }\n}\n\nexport async function executeBash(params: ExecBashParams): Promise<ExecBashResult> {\n const trimmedCommand = params.command?.trim()\n if (!trimmedCommand) {\n throw new BashInvalidParamsError('命令不能为空')\n }\n\n // 拦截明显的高危系统破坏性命令(针对系统关键根路径的非受控删除或资源耗尽攻击)\n if (\n /rm\\s+(-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\\s+|--recursive\\s+--force\\s+)\\s*(\\/|~|\\$HOME|\\/\\*)\\s*$/i.test(\n trimmedCommand\n ) ||\n /:\\(\\)\\s*\\{\\s*:\\s*\\|\\s*:\\s*&\\s*\\}\\s*;\\s*:/i.test(trimmedCommand)\n ) {\n throw new BashInvalidParamsError('安全拦截:禁止在宿主机执行针对系统关键根路径的高危破坏性命令')\n }\n\n const cwd = resolveWorkspaceDir({\n cwd: params.cwd,\n workspacePath: params.workspacePath,\n conversationId: params.conversationId\n })\n\n const normalizedTimeoutMs =\n typeof params.timeoutMs === 'number' && Number.isFinite(params.timeoutMs) && params.timeoutMs > 0\n ? Math.min(params.timeoutMs, MAX_TIMEOUT_MS)\n : DEFAULT_TIMEOUT_MS\n const { env = {}, maxBuffer = DEFAULT_MAX_BUFFER } = params\n\n const startTime = Date.now()\n const shell = resolveShell()\n\n return new Promise((resolve, reject) => {\n const stdoutChunks: Buffer[] = []\n let stdoutBytes = 0\n const stderrChunks: Buffer[] = []\n let stderrBytes = 0\n let truncated = false\n let isKilled = false\n\n const child = spawn(trimmedCommand, {\n shell,\n cwd,\n env: { ...process.env, ...env },\n windowsHide: true\n })\n\n const killTimeoutTimer = setTimeout(() => {\n isKilled = true\n killProcessTree(child)\n reject(new BashTimeoutError(normalizedTimeoutMs))\n }, normalizedTimeoutMs)\n\n child.stdout.on('data', (chunk: Buffer) => {\n if (stdoutBytes < maxBuffer) {\n const remaining = maxBuffer - stdoutBytes\n if (chunk.length <= remaining) {\n stdoutChunks.push(chunk)\n stdoutBytes += chunk.length\n } else {\n stdoutChunks.push(chunk.subarray(0, remaining))\n stdoutBytes += remaining\n truncated = true\n }\n } else {\n truncated = true\n }\n })\n\n child.stderr.on('data', (chunk: Buffer) => {\n if (stderrBytes < maxBuffer) {\n const remaining = maxBuffer - stderrBytes\n if (chunk.length <= remaining) {\n stderrChunks.push(chunk)\n stderrBytes += chunk.length\n } else {\n stderrChunks.push(chunk.subarray(0, remaining))\n stderrBytes += remaining\n truncated = true\n }\n } else {\n truncated = true\n }\n })\n\n child.on('error', (err) => {\n clearTimeout(killTimeoutTimer)\n reject(err)\n })\n\n child.on('close', (exitCode, signal) => {\n clearTimeout(killTimeoutTimer)\n if (isKilled) return\n const stdout = Buffer.concat(stdoutChunks).toString('utf8').trim()\n const stderr = Buffer.concat(stderrChunks).toString('utf8').trim()\n resolve({\n stdout,\n stderr,\n exitCode,\n signal,\n durationMs: Date.now() - startTime,\n ...(truncated ? { truncated: true } : {})\n })\n })\n })\n}\n","import { spawn } from 'node:child_process'\n\nexport interface PickDirectoryOptions {\n title?: string\n defaultPath?: string\n}\n\n/**\n * 唤起宿主机操作系统原生的文件夹选择弹窗,返回用户选择的绝对路径。\n * 若用户取消返回 null;选择器不可用或异常退出时抛出带原因的错误。\n */\nexport async function pickDirectory(optionsOrTitle?: PickDirectoryOptions | string): Promise<string | null> {\n const options: PickDirectoryOptions =\n typeof optionsOrTitle === 'string' ? { title: optionsOrTitle } : optionsOrTitle || {}\n\n const title = options.title || '请选择工作空间文件夹'\n const defaultPath =\n options.defaultPath && typeof options.defaultPath === 'string' ? options.defaultPath.trim() : undefined\n const platform = process.platform\n\n if (platform === 'darwin') {\n return pickDirectoryMac(title, defaultPath)\n }\n if (platform === 'win32') {\n return pickDirectoryWindows(title, defaultPath)\n }\n return pickDirectoryLinux(title, defaultPath)\n}\n\nfunction pickDirectoryMac(title: string, defaultPath?: string): Promise<string | null> {\n const safeTitle = title.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')\n const defaultClause = defaultPath\n ? ` default location POSIX file \"${defaultPath.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`\n : ''\n const appleScript = `POSIX path of (choose folder with prompt \"${safeTitle}\"${defaultClause})`\n\n return new Promise((resolve, reject) => {\n const child = spawn('osascript', ['-e', appleScript], {\n stdio: ['ignore', 'pipe', 'pipe']\n })\n let stdout = ''\n let stderr = ''\n child.stdout?.on('data', (d: Buffer) => {\n stdout += d.toString()\n })\n child.stderr?.on('data', (d: Buffer) => {\n stderr += d.toString()\n })\n child.on('close', (code: number | null) => {\n if (code === 0) {\n const selected = stdout.trim()\n resolve(selected || null)\n return\n }\n // 用户在 macOS 弹窗中点击取消时,osascript 返回 exitCode 1 且包含 User canceled (-128)\n if (code === 1 && (stderr.includes('User canceled') || stderr.includes('-128') || !stderr.trim())) {\n resolve(null)\n return\n }\n reject(new Error(`唤起系统文件夹选择器失败: ${stderr.trim() || `退出码 ${code}`}`))\n })\n child.on('error', (err) => {\n reject(new Error(`唤起系统文件夹选择器失败: ${err.message}`))\n })\n })\n}\n\n/**\n * 转义 PowerShell 双引号字符串中的特殊字符:\n * PowerShell 双引号字符串使用反引号转义特殊字符(` -> ``, \" -> `\", $ -> `$)\n */\nexport function escapePowerShellString(str: string): string {\n return str.replace(/`/g, '``').replace(/\"/g, '`\"').replace(/\\$/g, '`$')\n}\n\nfunction pickDirectoryWindows(title: string, defaultPath?: string): Promise<string | null> {\n // 使用 IFileOpenDialog COM 接口(Windows Vista+ 原生文件夹选择器)。\n // 不能用 FolderBrowserDialog:Node.js 以 CREATE_NO_WINDOW 启动子进程时,\n // WinForms ShowDialog() 拿不到桌面上下文,对话框永久阻塞直到超时。\n // IFileOpenDialog 通过 Shell COM 调用,父窗口传 IntPtr.Zero 即可正常弹出。\n const safeTitle = escapePowerShellString(title)\n const safeDefaultPath = escapePowerShellString(defaultPath ?? '')\n\n // 用内联 C# 通过 COM interop 调用 IFileOpenDialog,避免 WinForms 消息循环依赖\n const psScript = `\n$code = @'\nusing System;\nusing System.Runtime.InteropServices;\n\n[ComImport, Guid(\"D57C7288-D4AD-4768-BE02-9D969532D960\"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\ninterface IFileOpenDialog {\n [PreserveSig] int Show(IntPtr hwnd);\n void SetFileTypes(uint cFileTypes, IntPtr rgFilterSpec);\n void SetFileTypeIndex(uint iFileType);\n void GetFileTypeIndex(out uint piFileType);\n void Advise(IntPtr pfde, out uint pdwCookie);\n void Unadvise(uint dwCookie);\n void SetOptions(uint fos);\n void GetOptions(out uint pfos);\n void SetDefaultFolder(IntPtr psi);\n void SetFolder(IntPtr psi);\n void GetFolder(out IntPtr ppsi);\n void GetCurrentSelection(out IntPtr ppsi);\n void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);\n void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);\n void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);\n void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);\n void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);\n void GetResult(out IntPtr ppsi);\n void AddPlace(IntPtr psi, int fdap);\n void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);\n void Close(int hr);\n void SetClientGuid([In] ref Guid guid);\n void ClearClientData();\n void SetFilter(IntPtr pFilter);\n void GetResults(out IntPtr ppenum);\n void GetSelectedItems(out IntPtr ppsai);\n}\n\n[ComImport, Guid(\"43826D1E-E718-42EE-BC55-A1E261C37BFE\"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\ninterface IShellItem {\n void BindToHandler(IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv);\n void GetParent(out IShellItem ppsi);\n void GetDisplayName(uint sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);\n void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);\n void Compare(IShellItem psi, uint hint, out int piOrder);\n}\n\npublic static class FolderPicker {\n [DllImport(\"shell32.dll\", CharSet = CharSet.Unicode)]\n static extern int SHCreateItemFromParsingName(string pszPath, IntPtr pbc, [In] ref Guid riid, out IntPtr ppv);\n\n // FOS_PICKFOLDERS = 0x20, FOS_FORCEFILESYSTEM = 0x40\n const uint FOS_PICKFOLDERS = 0x00000020;\n const uint FOS_FORCEFILESYSTEM = 0x00000040;\n\n public static string Pick(string title, string defaultPath) {\n var clsid = new Guid(\"DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7\");\n var riid = new Guid(\"D57C7288-D4AD-4768-BE02-9D969532D960\");\n var obj = Activator.CreateInstance(Type.GetTypeFromCLSID(clsid));\n var dialog = (IFileOpenDialog)obj;\n dialog.SetOptions(FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM);\n dialog.SetTitle(title);\n if (!string.IsNullOrEmpty(defaultPath)) {\n var riidShellItem = new Guid(\"43826D1E-E718-42EE-BC55-A1E261C37BFE\");\n IntPtr psi;\n if (SHCreateItemFromParsingName(defaultPath, IntPtr.Zero, ref riidShellItem, out psi) == 0) {\n dialog.SetFolder(psi);\n Marshal.Release(psi);\n }\n }\n int hr = dialog.Show(IntPtr.Zero);\n if (hr != 0) return null; // 用户取消 (HRESULT_FROM_WIN32(ERROR_CANCELLED) = 0x800704C7)\n IntPtr ppsi;\n dialog.GetResult(out ppsi);\n var shellItem = (IShellItem)Marshal.GetTypedObjectForIUnknown(ppsi, typeof(IShellItem));\n string path;\n shellItem.GetDisplayName(0x80058000, out path); // SIGDN_FILESYSPATH\n Marshal.Release(ppsi);\n return path;\n }\n}\n'@\nAdd-Type -TypeDefinition $code\n$result = [FolderPicker]::Pick(\"${safeTitle}\", \"${safeDefaultPath}\")\nif ($result) { Write-Output $result }\n`\n\n return new Promise((resolve, reject) => {\n // 隐藏 PowerShell 控制台窗口:\n // 1. -WindowStyle Hidden 指示 PowerShell 不展示宿主控制台\n // 2. windowsHide: true 阻止 Windows 为子进程弹出黑色的终端窗口\n // IFileOpenDialog 通过系统 Shell COM 独立展示于桌面上,不受控制台隐藏影响\n const child = spawn('powershell', ['-STA', '-NoProfile', '-WindowStyle', 'Hidden', '-Command', psScript], {\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true\n })\n let stdout = ''\n let stderr = ''\n child.stdout?.on('data', (d: Buffer) => {\n stdout += d.toString()\n })\n child.stderr?.on('data', (d: Buffer) => {\n stderr += d.toString()\n })\n child.on('close', (code: number | null) => {\n if (code === 0) {\n const selected = stdout.trim()\n resolve(selected || null)\n return\n }\n reject(new Error(`PowerShell 文件夹选择器执行失败: ${stderr.trim() || `退出码 ${code}`}`))\n })\n child.on('error', (err) => {\n reject(new Error(`唤起 PowerShell 文件夹选择器失败: ${err.message}`))\n })\n })\n}\n\nfunction pickDirectoryLinux(title: string, defaultPath?: string): Promise<string | null> {\n const args = ['--file-selection', '--directory', `--title=${title}`]\n if (defaultPath) {\n args.push(`--filename=${defaultPath}`)\n }\n\n return new Promise((resolve, reject) => {\n const child = spawn('zenity', args, {\n stdio: ['ignore', 'pipe', 'pipe']\n })\n let stdout = ''\n let stderr = ''\n child.stdout?.on('data', (d: Buffer) => {\n stdout += d.toString()\n })\n child.stderr?.on('data', (d: Buffer) => {\n stderr += d.toString()\n })\n child.on('close', (code: number | null) => {\n if (code === 0) {\n const selected = stdout.trim()\n resolve(selected || null)\n return\n }\n // zenity 用户点击取消退出码为 1\n if (code === 1) {\n resolve(null)\n return\n }\n reject(new Error(`zenity 目录选择器异常退出 (退出码 ${code}): ${stderr.trim()}`))\n })\n child.on('error', (err: any) => {\n if (err?.code === 'ENOENT') {\n reject(new Error('未检测到 zenity 目录选择器,请先在系统中安装 zenity (例如: sudo apt install zenity)'))\n return\n }\n reject(new Error(`唤起 zenity 目录选择器失败: ${err.message}`))\n })\n })\n}\n","/**\n * ExtensionBridgeClient (支持 Server 模式与 Client 模式自适应)\n *\n * 架构角色:\n * 1. Server 模式:作为 WebSocket 服务端(127.0.0.1:18999),接收 Chrome 扩展连入;\n * - 维持与 Chrome 扩展的单一活跃长连接,支持新实例平滑替换;\n * - 支持本地临时 CLI Client 连入并发起 RPC 请求,透明转发至当前连接的浏览器实例。\n * 2. Client 模式:当 18999 端口已被占(例如常驻的 MCP Server 正在运行),自动作为 Client 连入现有服务发送 RPC 请求,无需争抢端口。\n */\n\nimport { WebSocketServer, WebSocket as WsClient, type WebSocket } from 'ws'\nimport { EventEmitter } from 'node:events'\nimport { randomUUID, randomBytes, createHmac, createHash, timingSafeEqual } from 'node:crypto'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\n\nimport { DEFAULT_WS_PORT, PROTOCOL_VERSION, WS_CLOSE_CODE, BRIDGE_ERROR_CODE, BRIDGE_METHODS } from './protocol.js'\nimport { executeBash, BashTimeoutError, BashInvalidParamsError } from './bash-executor.js'\nimport { pickDirectory } from './directory-picker.js'\n\nexport { PROTOCOL_VERSION, BRIDGE_ERROR_CODE }\n\nconst WS_PORT = DEFAULT_WS_PORT\nconst REQUEST_TIMEOUT_MS = 30_000\nconst HANDSHAKE_TIMEOUT_MS = 5_000\nconst WS_OPEN = 1\n\n/** 存储凭据路径(权限设置为 0600,仅当前宿主系统用户有权读取) */\nconst TOKEN_FILE_DIR = path.join(os.homedir(), '.robot-wxt')\nconst TOKEN_FILE_PATH = path.join(TOKEN_FILE_DIR, 'bridge-token')\n\n/** 从显式指定参数、环境变量或 0600 本地凭据文件读取认证 Token,若不存在则生成并持久化 */\nexport function resolveOrCreateAuthToken(explicitToken?: string): string {\n if (explicitToken && explicitToken.trim()) {\n const token = explicitToken.trim()\n try {\n if (!fs.existsSync(TOKEN_FILE_DIR)) {\n fs.mkdirSync(TOKEN_FILE_DIR, { mode: 0o700, recursive: true })\n }\n fs.writeFileSync(TOKEN_FILE_PATH, token, { mode: 0o600, encoding: 'utf8' })\n } catch {\n // ignore\n }\n return token\n }\n if (process.env.ROBOT_WXT_BRIDGE_TOKEN) {\n return process.env.ROBOT_WXT_BRIDGE_TOKEN.trim()\n }\n try {\n if (fs.existsSync(TOKEN_FILE_PATH)) {\n const existing = fs.readFileSync(TOKEN_FILE_PATH, 'utf8').trim()\n if (existing) return existing\n }\n } catch {\n // ignore\n }\n\n const newToken = randomBytes(32).toString('hex')\n try {\n if (!fs.existsSync(TOKEN_FILE_DIR)) {\n fs.mkdirSync(TOKEN_FILE_DIR, { mode: 0o700, recursive: true })\n }\n fs.writeFileSync(TOKEN_FILE_PATH, newToken, { mode: 0o600, encoding: 'utf8' })\n } catch {\n // 权限受限或受限环境安全降级\n }\n return newToken\n}\n\n/** 从版本字符串解析 major 号 */\nfunction parseMajorVersion(v: string): number {\n return parseInt(v.split('.')[0] ?? '0', 10)\n}\n\n/**\n * 派生共享密钥:SHA-256(token + \":\" + hmacSalt)\n */\nexport function deriveSharedSecret(tokenOrExtensionId: string, hmacSalt: string): Buffer {\n return createHash('sha256').update(`${tokenOrExtensionId}:${hmacSalt}`).digest()\n}\n\n/** 计算 HMAC-SHA256 签名,返回 hex 字符串 */\nexport function computeHmac(secret: Buffer, challenge: string): string {\n return createHmac('sha256', secret).update(challenge).digest('hex')\n}\n\n/** 常量时间比较两个 HMAC 签名,杜绝时序攻击 */\nexport function verifyHmacConstantTime(actualHex: string | undefined, expectedHex: string): boolean {\n if (!actualHex || typeof actualHex !== 'string') return false\n try {\n const actualBuf = Buffer.from(actualHex, 'hex')\n const expectedBuf = Buffer.from(expectedHex, 'hex')\n if (actualBuf.length !== expectedBuf.length) return false\n return timingSafeEqual(actualBuf, expectedBuf)\n } catch {\n return false\n }\n}\n\n/** 获取跨平台的强制释放端口命令指引 */\nexport function getKillPortHint(port: number): string {\n if (process.platform === 'win32') {\n return `netstat -ano | findstr :${port} (找到 PID 后执行: taskkill /pid <PID> /T /F)`\n }\n return `lsof -ti:${port} | xargs kill -9`\n}\n\nexport type JsonRpcMethod =\n | 'browser/state'\n | 'tool/call'\n | 'browser/tabs'\n | 'sub_agent/run'\n | 'skills/list'\n | 'skills/get'\n | 'skills/read_resource'\n\nexport interface JsonRpcRequest {\n jsonrpc: '2.0'\n id: string\n method: JsonRpcMethod\n params: Record<string, unknown>\n}\n\nexport interface JsonRpcResponse {\n jsonrpc: '2.0'\n id: string\n result?: unknown\n error?: { code: number; message: string; data?: unknown }\n}\n\ntype PendingRequest = {\n resolve: (value: unknown) => void\n reject: (reason: Error) => void\n timer: ReturnType<typeof setTimeout>\n}\n\ninterface SocketAuthState {\n authenticated: boolean\n challenge: string\n hmacSalt: string\n clientType?: 'extension' | 'cli-client'\n timer: ReturnType<typeof setTimeout>\n}\n\ninterface ForwardedRequestInfo {\n socket: WebSocket\n originalId: string | number\n progressToken?: string | number\n timer?: ReturnType<typeof setTimeout>\n}\n\nexport class ExtensionBridgeClient extends EventEmitter {\n private wss: WebSocketServer | null = null\n private extensionSocket: WebSocket | null = null\n private clientSocket: WebSocket | null = null\n private forwardedRequests = new Map<string, ForwardedRequestInfo>()\n private pending = new Map<string, PendingRequest>()\n private socketAuthStates = new Map<WebSocket, SocketAuthState>()\n private destroyed = false\n private idCounter = 0\n private isClientMode = false\n private readonly explicitAuthToken?: string\n private authToken: string\n\n constructor(\n private readonly port: number = WS_PORT,\n authToken?: string\n ) {\n super()\n this.explicitAuthToken = authToken\n this.authToken = authToken ?? resolveOrCreateAuthToken()\n }\n\n /** 获取当前服务端使用的认证 Token */\n get currentAuthToken(): string {\n return this.authToken\n }\n\n /** 获取当前激活的 Socket */\n private _getActiveSocket(): WebSocket | null {\n if (this.isClientMode && this.clientSocket) {\n return this.clientSocket.readyState === WS_OPEN ? this.clientSocket : null\n }\n if (this.extensionSocket && this.extensionSocket.readyState === WS_OPEN) {\n return this.extensionSocket\n }\n return null\n }\n\n /** 是否已有就绪的扩展连接(或作为 Client 已连接到 Server) */\n get isConnected(): boolean {\n return this._getActiveSocket() != null\n }\n\n /** 等待扩展连接或作为客户端连入服务就绪 */\n async waitForReady(timeoutMs: number = 5000): Promise<boolean> {\n if (this.isConnected) return true\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n cleanup()\n resolve(this.isConnected)\n }, timeoutMs)\n const cleanup = () => {\n clearTimeout(timer)\n this.off('connected', onConnected)\n }\n const onConnected = () => {\n cleanup()\n resolve(true)\n }\n this.on('connected', onConnected)\n })\n }\n\n /**\n * 静态探测目标端口的桥接服务状态\n */\n static async probe(\n port: number = WS_PORT,\n authToken?: string,\n timeoutMs: number = 800\n ): Promise<{ running: boolean; authed: boolean; error?: string }> {\n const client = new ExtensionBridgeClient(port, authToken)\n try {\n const res = await client._probeExistingServer(timeoutMs)\n if (client.clientSocket) {\n try {\n client.clientSocket.close(1000, 'Probe finished')\n } catch {\n // ignore\n }\n }\n if (res.success) {\n return { running: true, authed: true }\n }\n if (res.error) {\n const isAuthError =\n res.error.message.includes('HMAC') ||\n res.error.message.includes('认证失败') ||\n res.error.message.includes('Unauthorized')\n if (isAuthError) {\n return { running: true, authed: false, error: res.error.message }\n }\n return { running: false, authed: false, error: res.error.message }\n }\n return { running: false, authed: false }\n } finally {\n client.destroy()\n }\n }\n\n /**\n * 自动探测模式:\n * 优先尝试连接已存在的 18999 服务;连接不上时退回启动本机的 WebSocketServer。\n */\n async startAuto(probeTimeoutMs: number = 800): Promise<void> {\n if (this.destroyed) return\n\n const probe = await this._probeExistingServer(probeTimeoutMs)\n if (probe.success) {\n // 成功作为 Client 连入已存在的服务\n return\n }\n\n if (probe.error) {\n // 端口上有服务但认证失败或异常,绝不能再调用 this.connect() 去抢端口\n throw probe.error\n }\n\n // 无已有服务(ECONNREFUSED 等),启动本地 Server\n this.connect()\n }\n\n private async _probeExistingServer(timeoutMs: number): Promise<{ success: boolean; error?: Error }> {\n return new Promise((resolve) => {\n let settled = false\n let connectionEstablished = false\n let authFailedReason: string | null = null\n const ws = new WsClient(`ws://127.0.0.1:${this.port}`)\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true\n try {\n ws.terminate()\n } catch {\n // ignore\n }\n if (authFailedReason) {\n resolve({\n success: false,\n error: new Error(\n `本地桥接服务(127.0.0.1:${this.port})正在运行,但 HMAC 认证失败:${authFailedReason}。\\n` +\n `请确认当前 CLI 使用的 Token 与该服务一致,或终止占用进程(可执行: ${getKillPortHint(this.port)})。`\n )\n })\n } else if (connectionEstablished) {\n resolve({\n success: false,\n error: new Error(\n `本地 127.0.0.1:${this.port} 已被占用且无响应(可能不是有效桥接服务),请先终止占用进程(可执行: ${getKillPortHint(this.port)})。`\n )\n })\n } else {\n resolve({ success: false })\n }\n }\n }, timeoutMs)\n\n ws.on('open', () => {\n connectionEstablished = true\n })\n\n ws.on('close', (code, reason) => {\n const reasonStr = reason ? reason.toString() : ''\n if (code === WS_CLOSE_CODE.UNAUTHORIZED || reasonStr.includes('Unauthorized') || reasonStr.includes('HMAC')) {\n authFailedReason = reasonStr || 'Token 认证被拒绝 (HMAC verification failed)'\n }\n if (!settled && authFailedReason) {\n settled = true\n clearTimeout(timer)\n resolve({\n success: false,\n error: new Error(\n `本地桥接服务(127.0.0.1:${this.port})正在运行,但 HMAC 认证失败:${authFailedReason}。\\n` +\n `请确认当前 CLI 使用的 Token 与该服务一致,或终止占用进程(可执行: ${getKillPortHint(this.port)})。`\n )\n })\n }\n })\n\n ws.on('message', (data) => {\n try {\n const msg = JSON.parse(data.toString())\n // 收到挑战时自动回复 cli-client 认证(附带 HMAC 签名)\n if (msg.type === 'BRIDGE_CHALLENGE' && msg.challenge && msg.hmacSalt) {\n connectionEstablished = true\n const secret = deriveSharedSecret(this.authToken, msg.hmacSalt)\n const hmac = computeHmac(secret, msg.challenge)\n ws.send(\n JSON.stringify({\n type: 'BRIDGE_AUTH',\n clientType: 'cli-client',\n challenge: msg.challenge,\n hmac\n })\n )\n return\n }\n\n // 握手确认通过\n if (msg.type === 'BRIDGE_AUTH_OK' && !settled) {\n settled = true\n clearTimeout(timer)\n this.isClientMode = true\n this.clientSocket = ws\n this._bindClientSocket(ws)\n this.emit('connected')\n resolve({ success: true })\n }\n } catch {\n // ignore\n }\n })\n\n ws.once('error', (err: any) => {\n if (!settled) {\n settled = true\n clearTimeout(timer)\n try {\n ws.terminate()\n } catch {\n // ignore\n }\n if (err?.code === 'ECONNREFUSED' || err?.message?.includes('ECONNREFUSED')) {\n resolve({ success: false })\n } else {\n resolve({\n success: false,\n error: new Error(`连接本地 127.0.0.1:${this.port} 失败: ${err?.message || err}`)\n })\n }\n }\n })\n })\n }\n\n private _bindClientSocket(ws: WebSocket): void {\n ws.on('message', (data) => {\n let msg: any\n try {\n msg = JSON.parse(data.toString())\n } catch {\n return\n }\n\n if (msg.type === 'BRIDGE_CHALLENGE' || msg.type === 'BRIDGE_AUTH_OK') {\n return\n }\n\n // 处理子代理进度推送事件\n if (msg.method === 'notification/sub_agent_progress') {\n this.emit('progress', msg.params)\n return\n }\n\n const pending = this.pending.get(String(msg.id))\n if (!pending) return\n this.pending.delete(String(msg.id))\n clearTimeout(pending.timer)\n\n if (msg.error) {\n pending.reject(new Error(`[${msg.error.code}] ${msg.error.message}`))\n } else {\n pending.resolve(msg.result)\n }\n })\n\n ws.on('close', () => {\n this.clientSocket = null\n this.emit('disconnected')\n this._rejectAllPending('与服务的连接已断开')\n })\n }\n\n /** 启动 WebSocket 服务端,等待 Chrome 扩展(Offscreen Document)连入 */\n connect(): void {\n if (this.destroyed) return\n if (this.wss) return\n\n try {\n this.wss = new WebSocketServer({\n port: this.port,\n host: '127.0.0.1',\n verifyClient: (info, callback) => {\n const origin = info.origin || info.req.headers.origin\n if (origin) {\n // 浏览器端来源校验:仅允许浏览器扩展(chrome-extension:// 或 moz-extension://)\n const isAllowedExtension =\n origin.startsWith('chrome-extension://') ||\n origin.startsWith('moz-extension://') ||\n origin.startsWith('extension://')\n if (!isAllowedExtension) {\n callback(false, 403, 'Forbidden origin: only browser extensions are allowed')\n return\n }\n }\n // 本地无 Origin 的进程(Node.js / CLI 进程)或合法扩展允许接入,后续须完成握手\n callback(true)\n }\n })\n } catch (err) {\n this.emit('error', err)\n return\n }\n\n this.wss.on('listening', () => {\n this.emit('listening')\n })\n\n this.wss.on('error', (err: any) => {\n if (err?.code === 'EADDRINUSE') {\n process.stderr.write(\n `[webmcp-cli] ⚠️ 端口 ${this.port} 已被占用,请先终止占用该端口的旧进程(可执行: ${getKillPortHint(this.port)})\\n`\n )\n }\n this.emit('error', err)\n })\n\n this.wss.on('connection', (socket) => {\n // 1. 初始化握手状态\n const challenge = randomUUID()\n const hmacSalt = randomBytes(16).toString('hex')\n const authState: SocketAuthState = {\n authenticated: false,\n challenge,\n hmacSalt,\n timer: setTimeout(() => {\n if (!authState.authenticated) {\n try {\n socket.close(WS_CLOSE_CODE.UNAUTHORIZED, 'Handshake timeout')\n } catch {\n // ignore\n }\n }\n }, HANDSHAKE_TIMEOUT_MS)\n }\n this.socketAuthStates.set(socket, authState)\n\n // 2. 下发挑战(附带 hmacSalt 和协议版本)\n try {\n socket.send(\n JSON.stringify({\n type: 'BRIDGE_CHALLENGE',\n challenge,\n hmacSalt,\n protocolVersion: PROTOCOL_VERSION\n })\n )\n } catch {\n // ignore\n }\n\n socket.on('message', async (data) => {\n await this.handleSocketMessage(socket, data)\n })\n\n socket.on('close', () => {\n const auth = this.socketAuthStates.get(socket)\n if (auth?.timer) clearTimeout(auth.timer)\n this.socketAuthStates.delete(socket)\n\n // 清理所有由该 socket 发起的待处理转发请求映射\n for (const [reqId, fwdInfo] of this.forwardedRequests.entries()) {\n if (fwdInfo.socket === socket) {\n if (fwdInfo.timer) clearTimeout(fwdInfo.timer)\n this.forwardedRequests.delete(reqId)\n }\n }\n\n if (socket === this.extensionSocket) {\n this.extensionSocket = null\n this.emit('disconnected')\n for (const [reqId, fwdInfo] of this.forwardedRequests.entries()) {\n if (fwdInfo.timer) clearTimeout(fwdInfo.timer)\n try {\n if (fwdInfo.socket.readyState === WS_OPEN) {\n fwdInfo.socket.send(\n JSON.stringify({\n jsonrpc: '2.0',\n id: fwdInfo.originalId,\n error: {\n code: BRIDGE_ERROR_CODE.EXTENSION_NOT_CONNECTED,\n message: 'Chrome 扩展连接已断开'\n }\n })\n )\n }\n } catch {}\n this.forwardedRequests.delete(reqId)\n }\n this._rejectAllPending('WebSocket 连接已断开')\n }\n })\n\n socket.on('error', () => {\n // close 会随后触发\n })\n })\n\n this.wss.on('error', (err) => {\n this.emit('error', err)\n })\n }\n\n private async handleSocketMessage(socket: WebSocket, data: any): Promise<void> {\n let msg: any\n try {\n msg = JSON.parse(data.toString())\n } catch {\n return\n }\n\n const currentAuth = this.socketAuthStates.get(socket)\n if (!currentAuth || !currentAuth.authenticated) {\n await this.handleHandshake(socket, currentAuth, msg)\n return\n }\n\n if (msg.type === 'KEEP_ALIVE' || msg.type === 'WS_BRIDGE_KEEP_ALIVE') {\n return\n }\n\n if (msg.method && msg.id) {\n if (socket === this.extensionSocket) {\n await this.handleExtensionSystemRpc(socket, msg)\n return\n }\n await this.handleForwardRpc(socket, msg)\n return\n }\n\n if (msg.method && !msg.id) {\n this.handleProgressNotification(msg)\n return\n }\n\n if (msg.id) {\n this.handleIncomingResponse(msg)\n }\n }\n\n private verifyHandshakeHmac(currentAuth: SocketAuthState, hmac?: string): boolean {\n if (!currentAuth.hmacSalt || !hmac) return false\n\n const secret = deriveSharedSecret(this.authToken, currentAuth.hmacSalt)\n const expectedHmac = computeHmac(secret, currentAuth.challenge)\n if (verifyHmacConstantTime(hmac, expectedHmac)) {\n return true\n }\n\n if (!this.explicitAuthToken) {\n const diskToken = resolveOrCreateAuthToken()\n if (diskToken && diskToken !== this.authToken) {\n const diskSecret = deriveSharedSecret(diskToken, currentAuth.hmacSalt)\n const diskExpectedHmac = computeHmac(diskSecret, currentAuth.challenge)\n if (verifyHmacConstantTime(hmac, diskExpectedHmac)) {\n this.authToken = diskToken\n return true\n }\n }\n }\n\n return false\n }\n\n private async handleHandshake(socket: WebSocket, currentAuth: SocketAuthState | undefined, msg: any): Promise<void> {\n if (!currentAuth || msg.type !== 'BRIDGE_AUTH' || msg.challenge !== currentAuth.challenge) {\n try {\n socket.close(WS_CLOSE_CODE.UNAUTHORIZED, 'Unauthorized: Handshake failed')\n } catch {}\n return\n }\n\n const clientVersion = typeof msg.protocolVersion === 'string' ? msg.protocolVersion : PROTOCOL_VERSION\n if (parseMajorVersion(clientVersion) !== parseMajorVersion(PROTOCOL_VERSION)) {\n try {\n socket.close(\n WS_CLOSE_CODE.PROTOCOL_MISMATCH,\n `Protocol version mismatch: server=${PROTOCOL_VERSION}, client=${clientVersion}`\n )\n } catch {}\n return\n }\n\n const verified = this.verifyHandshakeHmac(currentAuth, msg.hmac)\n\n if (!verified) {\n const tokenFingerprint = this.authToken ? `${this.authToken.slice(0, 6)}...` : 'none'\n process.stderr.write(\n `[webmcp-cli] HMAC 验证失败,拒绝连接. client extensionId=${msg.extensionId}, server authTokenFingerprint=${tokenFingerprint}\\n`\n )\n try {\n socket.close(WS_CLOSE_CODE.UNAUTHORIZED, 'Unauthorized: HMAC verification failed')\n } catch {}\n return\n }\n\n clearTimeout(currentAuth.timer)\n currentAuth.authenticated = true\n currentAuth.clientType = msg.clientType\n\n if (msg.clientType === 'extension') {\n if (this.extensionSocket && this.extensionSocket !== socket) {\n try {\n this.extensionSocket.close(WS_CLOSE_CODE.REPLACED, 'Replaced by new connection')\n } catch {}\n }\n this.extensionSocket = socket\n this.emit('connected')\n }\n\n try {\n socket.send(\n JSON.stringify({\n type: 'BRIDGE_AUTH_OK',\n clientType: msg.clientType\n })\n )\n } catch {}\n }\n\n private async handleForwardRpc(socket: WebSocket, msg: any): Promise<void> {\n let targetSocket = this._getActiveSocket()\n if (!targetSocket) {\n await new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, 6000)\n this.once('connected', () => {\n clearTimeout(timer)\n resolve()\n })\n })\n targetSocket = this._getActiveSocket()\n }\n\n if (!targetSocket) {\n socket.send(\n JSON.stringify({\n jsonrpc: '2.0',\n id: msg.id,\n error: {\n code: BRIDGE_ERROR_CODE.EXTENSION_NOT_CONNECTED,\n message:\n 'Chrome 扩展尚未连接到本地桥接服务。请确保浏览器已启动,且在侧边栏中开启了「本地 WebSocket 桥接」开关。'\n }\n })\n )\n return\n }\n\n const internalId = `fwd_${++this.idCounter}_${Date.now()}`\n const timeoutMs = msg.method === 'sub_agent/run' ? 180_000 : REQUEST_TIMEOUT_MS\n\n const timer = setTimeout(() => {\n const fwd = this.forwardedRequests.get(internalId)\n if (!fwd) return\n this.forwardedRequests.delete(internalId)\n try {\n if (fwd.socket.readyState === WS_OPEN) {\n fwd.socket.send(\n JSON.stringify({\n jsonrpc: '2.0',\n id: fwd.originalId,\n error: {\n code: BRIDGE_ERROR_CODE.REQUEST_TIMEOUT,\n message: `请求转发至 Chrome 扩展超时 (${timeoutMs / 1000}s)`\n }\n })\n )\n }\n } catch {}\n }, timeoutMs)\n\n this.forwardedRequests.set(internalId, {\n socket,\n originalId: msg.id,\n progressToken: msg.params?.progressToken as string | number | undefined,\n timer\n })\n const outgoingMsg = { ...msg, id: internalId }\n targetSocket.send(JSON.stringify(outgoingMsg))\n }\n\n private sendJsonRpcResponse(\n socket: WebSocket,\n response: { id: any; result?: any; error?: { code: number; message: string } }\n ): void {\n if (socket.readyState === WS_OPEN) {\n socket.send(JSON.stringify({ jsonrpc: '2.0', ...response }))\n }\n }\n\n private formatSystemRpcError(err: any): { code: number; message: string } {\n if (err instanceof BashInvalidParamsError || err?.code === 'INVALID_PARAMS' || err?.message === '命令不能为空') {\n return { code: BRIDGE_ERROR_CODE.INVALID_PARAMS, message: err?.message || '参数错误' }\n }\n if (\n err instanceof BashTimeoutError ||\n err?.code === 'TIMEOUT' ||\n (typeof err?.message === 'string' && err.message.includes('超时'))\n ) {\n return { code: BRIDGE_ERROR_CODE.EXECUTION_TIMEOUT, message: err?.message || '命令执行超时' }\n }\n return { code: BRIDGE_ERROR_CODE.EXECUTION_FAILED, message: err?.message || '执行失败' }\n }\n\n private readonly systemRpcHandlers: Record<string, (params: any) => Promise<any>> = Object.assign(\n Object.create(null),\n {\n [BRIDGE_METHODS.SYSTEM_BASH]: async (params: any) => {\n return executeBash(params || {})\n },\n [BRIDGE_METHODS.SYSTEM_PICK_DIRECTORY]: async (params: any) => {\n const selectedPath = await pickDirectory({\n title: (params?.title as string) || undefined,\n defaultPath: (params?.defaultPath as string) || undefined\n })\n return {\n path: selectedPath,\n selectedPath,\n canceled: selectedPath === null\n }\n }\n }\n )\n\n private async handleExtensionSystemRpc(socket: WebSocket, msg: any): Promise<void> {\n const { id, method, params } = msg\n const handler =\n typeof method === 'string' && Object.prototype.hasOwnProperty.call(this.systemRpcHandlers, method)\n ? this.systemRpcHandlers[method]\n : undefined\n\n if (!handler || typeof handler !== 'function') {\n this.sendJsonRpcResponse(socket, {\n id,\n error: {\n code: BRIDGE_ERROR_CODE.METHOD_NOT_FOUND,\n message: `不支持的方法: ${method}`\n }\n })\n return\n }\n\n try {\n const result = await handler(params)\n this.sendJsonRpcResponse(socket, { id, result })\n } catch (err: any) {\n this.sendJsonRpcResponse(socket, { id, error: this.formatSystemRpcError(err) })\n }\n }\n\n private handleProgressNotification(msg: any): void {\n const token = msg.params?.progressToken\n if (token != null) {\n for (const [, reqInfo] of this.forwardedRequests) {\n if (reqInfo.progressToken === token) {\n try {\n if (reqInfo.socket.readyState === WS_OPEN) {\n reqInfo.socket.send(JSON.stringify(msg))\n }\n } catch {}\n }\n }\n }\n this.emit('progress', msg.params)\n }\n\n private handleIncomingResponse(msg: any): void {\n const fwdInfo = this.forwardedRequests.get(String(msg.id))\n if (fwdInfo) {\n if (fwdInfo.timer) clearTimeout(fwdInfo.timer)\n this.forwardedRequests.delete(String(msg.id))\n try {\n if (fwdInfo.socket.readyState === WS_OPEN) {\n fwdInfo.socket.send(\n JSON.stringify({\n ...msg,\n id: fwdInfo.originalId\n })\n )\n }\n } catch {}\n return\n }\n\n const pending = this.pending.get(String(msg.id))\n if (!pending) return\n this.pending.delete(String(msg.id))\n clearTimeout(pending.timer)\n\n if (msg.error) {\n pending.reject(new Error(`[${msg.error.code}] ${msg.error.message}`))\n } else {\n pending.resolve(msg.result)\n }\n }\n\n /** 发送 JSON-RPC 2.0 请求,返回 result */\n async call(\n method: JsonRpcMethod,\n params: Record<string, unknown> = {},\n timeoutMs?: number,\n progressToken?: string | number,\n autoWaitMs: number = 0\n ): Promise<unknown> {\n if (autoWaitMs > 0 && !this.isConnected) {\n await this.waitForReady(autoWaitMs)\n }\n\n const targetSocket = this._getActiveSocket()\n\n if (!targetSocket) {\n throw new Error(\n '与 Chrome 扩展的连接尚未就绪,请确保:\\n' +\n ' 1. Chrome 浏览器已启动\\n' +\n ' 2. Tiny Robot 扩展已安装并开启\\n' +\n ' 3. 扩展侧边栏已打开'\n )\n }\n\n const effectiveTimeoutMs = timeoutMs ?? (method === 'sub_agent/run' ? 180_000 : REQUEST_TIMEOUT_MS)\n const id = String(++this.idCounter)\n const requestParams: Record<string, unknown> = { ...params }\n if (progressToken != null) {\n requestParams.progressToken = progressToken\n }\n const request: JsonRpcRequest = { jsonrpc: '2.0', id, method, params: requestParams }\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id)\n reject(new Error(`请求超时(${effectiveTimeoutMs / 1000}s):${method}`))\n }, effectiveTimeoutMs)\n\n this.pending.set(id, { resolve, reject, timer })\n try {\n targetSocket.send(JSON.stringify(request))\n } catch (err) {\n this.pending.delete(id)\n clearTimeout(timer)\n reject(err instanceof Error ? err : new Error(String(err)))\n }\n })\n }\n\n /** 销毁服务,断开所有连接 */\n destroy(): void {\n this.destroyed = true\n this._rejectAllPending('ExtensionBridgeClient 已销毁')\n this.forwardedRequests.clear()\n\n if (this.clientSocket) {\n try {\n this.clientSocket.close()\n } catch {\n // ignore\n }\n this.clientSocket = null\n }\n\n if (this.extensionSocket) {\n try {\n this.extensionSocket.close()\n } catch {\n // ignore\n }\n this.extensionSocket = null\n }\n\n if (this.wss) {\n try {\n this.wss.close()\n } catch {\n // ignore\n }\n this.wss = null\n }\n }\n\n private _rejectAllPending(reason: string): void {\n for (const [, pending] of this.pending) {\n clearTimeout(pending.timer)\n pending.reject(new Error(reason))\n }\n this.pending.clear()\n for (const [, fwdInfo] of this.forwardedRequests) {\n if (fwdInfo.timer) clearTimeout(fwdInfo.timer)\n }\n this.forwardedRequests.clear()\n }\n}\n","/**\n * WxtBrowserAdapter\n *\n * 基于 WebSocket + Chrome 扩展桥接实现的 BrowserAdapter,\n * 通过 ExtensionBridgeClient 与浏览器扩展通信,复用用户已有的 Chrome 数据与账号。\n */\n\nimport { ExtensionBridgeClient } from '../bridge/bridge-client.js'\nimport { BRIDGE_METHODS } from '../bridge/protocol.js'\nimport type { BrowserAdapter, BrowserStateResult, TabsOptions } from './interface.js'\n\nconst AUTO_WAIT_MS = 6000\n\nexport class WxtBrowserAdapter implements BrowserAdapter {\n private client: ExtensionBridgeClient\n\n constructor(token?: string, port?: number) {\n this.client = new ExtensionBridgeClient(port, token)\n // 防止未捕获的 error 事件导致进程崩溃\n this.client.on('error', () => {})\n }\n\n /** 确保 WS 桥接服务已启动并连接 */\n async ensureConnected(): Promise<void> {\n await this.client.startAuto()\n }\n\n async getState(tabId?: string | number): Promise<BrowserStateResult> {\n const numTabId = typeof tabId === 'string' ? parseInt(tabId, 10) || undefined : tabId\n const result = await this.client.call(\n BRIDGE_METHODS.BROWSER_STATE,\n { tabId: numTabId },\n undefined,\n undefined,\n AUTO_WAIT_MS\n ) as BrowserStateResult\n return result\n }\n\n async callTool(toolName: string, args: Record<string, unknown>, tabId?: string | number): Promise<unknown> {\n const numTabId = typeof tabId === 'string' ? parseInt(tabId, 10) || undefined : tabId\n return this.client.call(\n BRIDGE_METHODS.TOOL_CALL,\n { toolName, toolArgs: args, tabId: numTabId },\n undefined,\n undefined,\n AUTO_WAIT_MS\n )\n }\n\n async tabs(action: 'open' | 'close' | 'switch' | 'back' | 'forward', options: TabsOptions): Promise<unknown> {\n const numTabId = typeof options.tabId === 'string' ? parseInt(options.tabId, 10) || undefined : options.tabId\n return this.client.call(\n BRIDGE_METHODS.BROWSER_TABS,\n { tabAction: action, ...options, tabId: numTabId },\n undefined,\n undefined,\n AUTO_WAIT_MS\n )\n }\n\n /** 委托扩展内 Tiny Robot 子代理闭环执行高层任务 */\n async runSubAgent(\n instruction: string,\n options: { tabId?: number; maxSteps?: number; progressToken?: string | number } = {},\n timeoutMs?: number\n ): Promise<unknown> {\n const params = { instruction, tabId: options.tabId, maxSteps: options.maxSteps }\n return this.client.call(\n BRIDGE_METHODS.SUB_AGENT_RUN,\n params,\n timeoutMs,\n options.progressToken,\n AUTO_WAIT_MS\n )\n }\n\n /** 获取已注册的 Skills 列表(L1 索引) */\n async listSkills(): Promise<unknown> {\n return this.client.call(BRIDGE_METHODS.SKILLS_LIST, {}, undefined, undefined, AUTO_WAIT_MS)\n }\n\n /** 读取指定 Skill 的详细指令(L2 详情) */\n async getSkill(name: string): Promise<unknown> {\n return this.client.call(BRIDGE_METHODS.SKILLS_GET, { name }, undefined, undefined, AUTO_WAIT_MS)\n }\n\n /** 读取 Skill 关联资源(L3 资源) */\n async readSkillResource(name: string, resourcePath: string): Promise<unknown> {\n return this.client.call(\n BRIDGE_METHODS.SKILLS_READ_RESOURCE,\n { name, resourcePath },\n undefined,\n undefined,\n AUTO_WAIT_MS\n )\n }\n\n /** 获取底层 ExtensionBridgeClient(供 MCP Server 绑定事件) */\n get bridgeClient(): ExtensionBridgeClient {\n return this.client\n }\n\n async dispose(): Promise<void> {\n this.client.destroy()\n }\n}\n","import { spawn, exec } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { fileURLToPath } from 'node:url'\nimport { resolveOrCreateAuthToken, ExtensionBridgeClient, getKillPortHint } from './bridge-client.js'\n\nconst execAsync = promisify(exec)\n\nconst WS_PORT = 18999\nconst DAEMON_DIR = path.join(os.homedir(), '.robot-wxt')\n\n/** 获取指定端口对应的守护进程 PID 文件路径(默认 18999 对应 daemon.pid,自定义端口对应 daemon-{port}.pid) */\nexport function getDaemonPidFile(port: number = WS_PORT): string {\n if (port === WS_PORT) {\n return path.join(DAEMON_DIR, 'daemon.pid')\n }\n return path.join(DAEMON_DIR, `daemon-${port}.pid`)\n}\n\nexport const PID_FILE = getDaemonPidFile(WS_PORT)\n\n/** 检查指定 PID 的进程是否存活 */\nexport function isProcessAlive(pid: number): boolean {\n if (!pid || pid <= 0) return false\n try {\n process.kill(pid, 0)\n return true\n } catch {\n return false\n }\n}\n\n/** 跨平台根据端口探测占用该端口的 PID */\nexport async function findPidByPort(port: number, excludePid?: number): Promise<number | null> {\n if (process.platform === 'win32') {\n try {\n const { stdout } = await execAsync('netstat -ano -p tcp')\n const lines = stdout.split(/\\r?\\n/)\n for (const rawLine of lines) {\n const line = rawLine.trim()\n if (!line.toUpperCase().startsWith('TCP')) continue\n const parts = line.split(/\\s+/)\n if (parts.length < 5) continue\n const localAddr = parts[1]\n const state = parts[3]?.toUpperCase() || ''\n const pid = parseInt(parts[parts.length - 1], 10)\n\n if (!pid || isNaN(pid) || (excludePid && pid === excludePid)) continue\n\n if (localAddr.endsWith(`:${port}`)) {\n if (state.includes('LISTEN') || state.includes('侦听')) {\n return pid\n }\n }\n }\n return null\n } catch {\n return null\n }\n }\n\n try {\n const { stdout } = await execAsync(`lsof -nP -iTCP:${port} -sTCP:LISTEN -t`)\n const pids = stdout\n .trim()\n .split('\\n')\n .map((p) => parseInt(p.trim(), 10))\n .filter((p) => Boolean(p && !isNaN(p) && (!excludePid || p !== excludePid)))\n return pids[0] ?? null\n } catch {\n return null\n }\n}\n\n/** 跨平台终止指定 PID 及其子进程树 */\nexport async function killProcessTree(pid: number): Promise<boolean> {\n if (!pid || pid <= 0 || pid === process.pid) return false\n\n if (process.platform === 'win32') {\n try {\n await execAsync(`taskkill /pid ${pid} /T /F`)\n } catch {\n try {\n process.kill(pid, 'SIGKILL')\n } catch {\n // ignore\n }\n }\n for (let i = 0; i < 15; i++) {\n await new Promise((r) => setTimeout(r, 100))\n if (!isProcessAlive(pid)) return true\n }\n return !isProcessAlive(pid)\n }\n\n try {\n process.kill(pid, 'SIGTERM')\n } catch {\n // ignore\n }\n\n for (let i = 0; i < 10; i++) {\n await new Promise((r) => setTimeout(r, 100))\n if (!isProcessAlive(pid)) return true\n }\n\n try {\n process.kill(pid, 'SIGKILL')\n } catch {\n // ignore\n }\n\n for (let i = 0; i < 5; i++) {\n await new Promise((r) => setTimeout(r, 100))\n if (!isProcessAlive(pid)) return true\n }\n\n return !isProcessAlive(pid)\n}\n\n/** 强杀占用指定端口的进程以释放端口 */\nexport async function killProcessOnPort(port: number): Promise<boolean> {\n const pid = await findPidByPort(port, process.pid)\n if (pid) {\n await killProcessTree(pid)\n for (let i = 0; i < 20; i++) {\n await new Promise((r) => setTimeout(r, 100))\n const remainingPid = await findPidByPort(port, process.pid)\n if (!remainingPid) return true\n }\n }\n return false\n}\n\n/** 探测指定端口的 WS 桥接服务是否已就绪且鉴权通过 */\nexport async function probeServerReady(\n port: number = WS_PORT,\n token?: string,\n timeoutMs: number = 1000\n): Promise<{ running: boolean; authed: boolean; error?: string }> {\n return ExtensionBridgeClient.probe(port, token ?? resolveOrCreateAuthToken(), timeoutMs)\n}\n\n/** 检查受管的后台守护进程是否存活 */\nexport function isDaemonProcessAlive(port: number = WS_PORT): boolean {\n const pidFile = getDaemonPidFile(port)\n if (!fs.existsSync(pidFile)) return false\n try {\n const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim(), 10)\n return Boolean(pid && isProcessAlive(pid))\n } catch {\n return false\n }\n}\n\n/** 确保 18999 桥接后台服务在运行,若未运行则自动拉起常驻守护进程 */\nexport async function ensureBridgeDaemon(\n options: { port?: number; token?: string; timeoutMs?: number; silent?: boolean } = {}\n): Promise<{ newlyStarted: boolean }> {\n const port = options.port ?? WS_PORT\n const token = options.token ?? resolveOrCreateAuthToken()\n const timeoutMs = options.timeoutMs ?? 6000\n\n // 1. 先探测是否已有服务\n const probe = await probeServerReady(port, token, 800)\n if (probe.running && probe.authed) {\n // 已经有正常工作的服务,直接复用\n return { newlyStarted: false }\n }\n\n if (probe.running && !probe.authed) {\n if (!options.silent) {\n console.log(\n `\\x1b[33m[webmcp-cli]\\x1b[0m 🔄 检测到后台桥接服务 Token 不匹配,正在验证旧守护进程归属并尝试自动重启...`\n )\n }\n const stopped = await stopBridgeDaemon(port, { onlyVerified: true })\n if (!stopped) {\n const killTip = getKillPortHint(port)\n throw new Error(\n `本地 127.0.0.1:${port} 正在运行服务,但认证未通过(${probe.error || 'Token 不匹配'})。\\n` +\n `未能确认该进程归属于受管的桥接守护进程,为安全起见已阻止自动强杀。请检查端口 ${port} 是否被其他应用占用,或手动终止(可执行: ${killTip})。`\n )\n }\n await new Promise((r) => setTimeout(r, 400))\n }\n\n // 2. 启动后台常驻进程\n if (!options.silent) {\n console.log(`\\x1b[36m[webmcp-cli]\\x1b[0m 🚀 本地桥接服务未运行,正在自动拉起常驻服务 (127.0.0.1:${port})...`)\n }\n startDaemonProcessBackground(token, port)\n\n // 3. 轮询等待服务就绪\n const startTime = Date.now()\n while (Date.now() - startTime < timeoutMs) {\n await new Promise((r) => setTimeout(r, 200))\n const check = await probeServerReady(port, token, 400)\n if (check.running && check.authed) {\n if (!options.silent) {\n console.log(`\\x1b[32m[webmcp-cli]\\x1b[0m ✅ 桥接服务已启动,正在等待 Chrome 扩展连接...`)\n }\n return { newlyStarted: true }\n }\n }\n\n throw new Error(`启动后台 WebSocket 桥接服务超时(${timeoutMs}ms),请检查端口 ${port} 是否可用。`)\n}\n\nfunction resolveCliEntry(): string {\n const currentDir = path.dirname(fileURLToPath(import.meta.url))\n // webmcp-cli 产物入口为 bin.js\n const distCandidate = path.join(currentDir, 'bin.js')\n if (fs.existsSync(distCandidate)) return distCandidate\n\n const projectDistCandidate = path.resolve(currentDir, '../dist/bin.js')\n if (fs.existsSync(projectDistCandidate)) return projectDistCandidate\n\n return distCandidate\n}\n\n/** 在后台派生守护进程 */\nfunction startDaemonProcessBackground(token: string, port: number): void {\n const cliEntry = resolveCliEntry()\n if (!fs.existsSync(DAEMON_DIR)) {\n fs.mkdirSync(DAEMON_DIR, { mode: 0o700, recursive: true })\n }\n\n const child = spawn(process.execPath, [cliEntry, '--mode', 'wxt', 'daemon', '--port', String(port)], {\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n env: {\n ...process.env,\n ROBOT_WXT_BRIDGE_TOKEN: token\n }\n })\n\n child.unref()\n}\n\n/** 守护进程主循环(由 `webmcp-cli --mode wxt daemon` 调用) */\nexport async function runDaemonProcess(args: string[]): Promise<void> {\n let port = WS_PORT\n let token: string | undefined\n\n const portIdx = args.indexOf('--port')\n if (portIdx !== -1 && args[portIdx + 1]) {\n port = parseInt(args[portIdx + 1], 10)\n }\n const tokenIdx = args.indexOf('--token')\n if (tokenIdx !== -1 && args[tokenIdx + 1]) {\n token = args[tokenIdx + 1]\n } else if (process.env.ROBOT_WXT_BRIDGE_TOKEN) {\n token = process.env.ROBOT_WXT_BRIDGE_TOKEN\n }\n\n const client = new ExtensionBridgeClient(port, token)\n\n client.on('error', (err: any) => {\n if (err && (err.code === 'EADDRINUSE' || err.message?.includes('EADDRINUSE'))) {\n process.exit(1)\n }\n })\n\n const pidFile = getDaemonPidFile(port)\n\n // 成功开始监听端口后再写入 PID 文件,防止端口占用导致留下死 PID 文件\n client.on('listening', () => {\n try {\n if (!fs.existsSync(DAEMON_DIR)) {\n fs.mkdirSync(DAEMON_DIR, { mode: 0o700, recursive: true })\n }\n fs.writeFileSync(pidFile, String(process.pid), { mode: 0o600, encoding: 'utf8' })\n } catch {\n // ignore\n }\n })\n\n client.connect()\n\n const shutdown = () => {\n try {\n if (fs.existsSync(pidFile)) {\n const recordedPid = fs.readFileSync(pidFile, 'utf8').trim()\n if (recordedPid === String(process.pid)) {\n fs.unlinkSync(pidFile)\n }\n }\n } catch {\n // ignore\n }\n client.destroy()\n process.exit(0)\n }\n\n process.on('SIGINT', shutdown)\n process.on('SIGTERM', shutdown)\n process.on('exit', shutdown)\n\n // 保持进程常驻\n setInterval(() => {}, 60_000)\n}\n\n/** 校验指定 PID 是否为合法的 WebMCP 桥接守护进程 */\nexport async function isBridgeDaemonProcess(pid: number): Promise<boolean> {\n if (!pid || pid <= 0 || !isProcessAlive(pid)) return false\n try {\n let cmd = ''\n if (process.platform === 'win32') {\n const { stdout } = await execAsync(\n `powershell -NoProfile -Command \"(Get-CimInstance Win32_Process -Filter \\\\\"ProcessId = ${pid}\\\\\").CommandLine\"`\n )\n cmd = stdout.trim()\n } else {\n const { stdout } = await execAsync(`ps -p ${pid} -o command=`)\n cmd = stdout.trim()\n }\n if (!cmd) return false\n return (\n (cmd.includes('webmcp-cli') || cmd.includes('bin.js') || cmd.includes('daemon.js')) &&\n cmd.includes('daemon')\n )\n } catch {\n return false\n }\n}\n\n/** 停止后台运行的桥接服务 */\nexport async function stopBridgeDaemon(\n port: number = WS_PORT,\n options: { onlyVerified?: boolean } = {}\n): Promise<boolean> {\n const onlyVerified = options.onlyVerified ?? false\n let killedAny = false\n const pidFile = getDaemonPidFile(port)\n\n let daemonPid: number | null = null\n if (fs.existsSync(pidFile)) {\n try {\n const pidStr = fs.readFileSync(pidFile, 'utf8').trim()\n const p = parseInt(pidStr, 10)\n if (p && isProcessAlive(p)) {\n daemonPid = p\n }\n } catch {\n // ignore\n }\n }\n\n // 1. 若仅允许终止已验证的守护进程(如自动拉起守护进程时的清理):\n if (onlyVerified) {\n if (!daemonPid) {\n // 未记录 PID 或记录的进程已不存活,无法确认归属,禁止强杀\n return false\n }\n\n const isVerified = await isBridgeDaemonProcess(daemonPid)\n if (!isVerified) {\n // PID 进程未通过桥接守护进程身份校验,禁止强杀\n return false\n }\n\n const portPid = await findPidByPort(port, process.pid)\n if (portPid && portPid !== daemonPid) {\n // 端口上的进程与受管守护进程 PID 不一致,说明被外部进程占用,禁止强杀\n return false\n }\n\n const killed = await killProcessTree(daemonPid)\n if (killed) {\n killedAny = true\n try {\n if (fs.existsSync(pidFile)) fs.unlinkSync(pidFile)\n } catch {\n // ignore\n }\n }\n } else {\n // 普通停止模式(如用户显式执行 webmcp-cli stop):\n if (daemonPid) {\n try {\n const killed = await killProcessTree(daemonPid)\n if (killed) {\n killedAny = true\n try {\n if (fs.existsSync(pidFile)) fs.unlinkSync(pidFile)\n } catch {\n // ignore\n }\n }\n } catch {\n // ignore\n }\n }\n\n const portPid = await findPidByPort(port, process.pid)\n if (portPid) {\n const killedByPort = await killProcessOnPort(port)\n if (killedByPort) {\n killedAny = true\n }\n }\n }\n\n // 循环确认端口是否已被释放(最多等待 2 秒)\n let portReleased = false\n for (let i = 0; i < 10; i++) {\n const remainingPid = await findPidByPort(port, process.pid)\n if (!remainingPid) {\n portReleased = true\n break\n }\n await new Promise((r) => setTimeout(r, 200))\n }\n\n if (!portReleased) {\n return false\n }\n\n return killedAny\n}\n","/**\n * MCP Server 核心(双模式)\n *\n * 通过 @modelcontextprotocol/sdk 的 StdioServerTransport 以标准 MCP 协议对外暴露。\n * 支持两种底层连接模式:\n * - 'cdp'(默认):基于 Puppeteer + CDP 直连浏览器\n * - 'wxt':基于 WebSocket + Chrome 扩展桥接(可复用用户数据)\n *\n * 架构:\n * MCP Client(Claude Desktop / Cursor / …)\n * ──stdio──→ McpServer(本文件)\n * ├─ CDP 模式: Puppeteer ──CDP──→ 浏览器\n * └─ WXT 模式: ws://127.0.0.1:18999 ──→ Chrome 扩展 ──→ 页面\n */\n\nimport { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport type { CdpBrowserAdapter } from '../adapters/cdp-adapter.js'\nimport type { WxtBrowserAdapter } from '../adapters/wxt-adapter.js'\nimport packageJson from '../../package.json'\nimport {\n BrowserStateInput,\n BrowserToolCallInput,\n BrowserTabsOpenInput,\n BrowserTabsCloseInput,\n BrowserTabsSwitchInput,\n BrowserTabsNavInput,\n BrowserSubAgentRunInput,\n BrowserSkillsListInput,\n BrowserSkillsReadInput\n} from './tools.js'\n\nconst SERVER_NAME = 'webmcp-cli'\nconst SERVER_VERSION = packageJson.version || '0.0.9'\n\nexport type McpMode = 'cdp' | 'wxt'\nexport type McpAgentMode = 'tools' | 'agent'\n\nexport interface McpServerOptions {\n /** 底层连接模式,默认 cdp */\n mode?: McpMode\n /** 工具暴露模式:tools(全量原子工具)| agent(收敛为高层子代理,仅 wxt 模式有效) */\n agentMode?: McpAgentMode\n /** WXT 模式的认证 Token */\n token?: string\n /** WXT 模式的 WS 端口,默认 18999 */\n wsPort?: number\n}\n\nexport async function startMcpServer(options: McpServerOptions = {}): Promise<void> {\n const mode = options.mode ?? 'cdp'\n const agentMode = options.agentMode ?? 'tools'\n const isAgentMode = agentMode === 'agent'\n\n const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION })\n\n if (mode === 'cdp') {\n if (isAgentMode) {\n throw new Error('--agent 子代理委托模式仅在 WXT 模式可用,请使用: webmcp-cli --mode wxt mcp --agent')\n }\n await startCdpMcpServer(server, isAgentMode)\n } else {\n await startWxtMcpServer(server, isAgentMode, options)\n }\n\n const transport = new StdioServerTransport()\n await server.connect(transport)\n\n process.stderr.write(\n `[webmcp-cli] MCP Server 已启动(${SERVER_NAME} v${SERVER_VERSION},模式: ${mode}${isAgentMode ? '/agent' : '/tools'})\\n`\n )\n}\n\n// ─── CDP 模式 MCP Server ─────────────────────────────────────────────────────\n\nasync function startCdpMcpServer(server: McpServer, isAgentMode: boolean): Promise<void> {\n const { CdpBrowserAdapter } = await import('../adapters/cdp-adapter.js')\n const adapter = new CdpBrowserAdapter()\n\n registerCommonTools(server, adapter, isAgentMode)\n\n process.on('SIGINT', async () => { await adapter.dispose(); process.exit(0) })\n process.on('SIGTERM', async () => { await adapter.dispose(); process.exit(0) })\n}\n\n// ─── WXT 模式 MCP Server ─────────────────────────────────────────────────────\n\nasync function startWxtMcpServer(server: McpServer, isAgentMode: boolean, options: McpServerOptions): Promise<void> {\n const { WxtBrowserAdapter } = await import('../adapters/wxt-adapter.js')\n const { ensureBridgeDaemon } = await import('../bridge/daemon.js')\n\n // 确保后台 daemon 已在运行\n const daemonResult = await ensureBridgeDaemon({\n token: options.token,\n port: options.wsPort,\n silent: true\n })\n\n const adapter = new WxtBrowserAdapter(options.token, options.wsPort)\n await adapter.ensureConnected()\n\n if (daemonResult.newlyStarted) {\n process.stderr.write('[webmcp-cli] 🚀 本地桥接服务已启动,正在等待 Chrome 扩展连接...\\n')\n }\n\n const client = adapter.bridgeClient\n\n // 注册通用工具\n registerCommonTools(server, adapter, isAgentMode)\n\n // 注册 WXT 专属工具\n registerWxtTools(server, adapter, isAgentMode, server)\n\n // 注册 Skills Resource(L1/L2/L3)\n registerSkillsResources(server, adapter)\n\n client.on('connected', () => {\n process.stderr.write('[webmcp-cli] 已连接到 Chrome 扩展\\n')\n try {\n server.server.notification({ method: 'notifications/resources/list_changed' })\n } catch { /* ignore */ }\n })\n client.on('disconnected', () => {\n process.stderr.write('[webmcp-cli] 与 Chrome 扩展的连接已断开\\n')\n })\n\n process.on('SIGINT', async () => { await adapter.dispose(); process.exit(0) })\n process.on('SIGTERM', async () => { await adapter.dispose(); process.exit(0) })\n\n const tokenFingerprint = options.token ? `${options.token.slice(0, 6)}...` : '(auto)'\n process.stderr.write(`[webmcp-cli] 🔑 Token 指纹: ${tokenFingerprint} (完整凭据见 ~/.robot-wxt/bridge-token)\\n`)\n}\n\n// ─── 通用工具注册(CDP + WXT 均支持) ────────────────────────────────────────\n\ntype AnyAdapter = CdpBrowserAdapter | WxtBrowserAdapter\n\nfunction registerCommonTools(server: McpServer, adapter: AnyAdapter, isAgentMode: boolean): void {\n // browser_state\n server.registerTool(\n 'browser_state',\n {\n description:\n '获取当前浏览器状态,包括:当前 tab 的 URL / 标题、所有已打开的 tab 列表、当前页面注册的 WebMCP 工具列表。在执行操作前,建议先调用此工具了解当前浏览器上下文。',\n inputSchema: BrowserStateInput.shape\n },\n async (args) => {\n const result = await adapter.getState(args.tabId)\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }\n }\n )\n\n if (!isAgentMode) {\n // browser_tool_call\n server.registerTool(\n 'browser_tool_call',\n {\n description:\n '执行当前页面注册的 WebMCP 工具(如 click、input、scroll 等)。工具名称和参数 schema 通过 browser_state 返回的 webmcpTools 字段获取。',\n inputSchema: BrowserToolCallInput.shape\n },\n async (args) => {\n const result = await adapter.callTool(args.toolName, args.toolArgs ?? {}, args.tabId)\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }\n }\n )\n\n // browser_tabs_open\n server.registerTool(\n 'browser_tabs_open',\n { description: '在浏览器中打开一个新标签页并导航到指定 URL。', inputSchema: BrowserTabsOpenInput.shape },\n async (args) => {\n const result = await adapter.tabs('open', { url: args.url })\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }\n }\n )\n\n // browser_tabs_close\n server.registerTool(\n 'browser_tabs_close',\n { description: '关闭指定标签页(不指定 tabId 时关闭当前活跃标签页)。', inputSchema: BrowserTabsCloseInput.shape },\n async (args) => {\n const result = await adapter.tabs('close', { tabId: args.tabId })\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }\n }\n )\n\n // browser_tabs_switch\n server.registerTool(\n 'browser_tabs_switch',\n {\n description: '将焦点切换到指定标签页(tabId 通过 browser_state 返回的 tabs 列表获取)。',\n inputSchema: BrowserTabsSwitchInput.shape\n },\n async (args) => {\n const result = await adapter.tabs('switch', { tabId: args.tabId, activateVisible: args.activateVisible })\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }\n }\n )\n\n // browser_tabs_back\n server.registerTool(\n 'browser_tabs_back',\n { description: '在指定标签页(或当前活跃标签页)中执行浏览器后退操作。', inputSchema: BrowserTabsNavInput.shape },\n async (args) => {\n const result = await adapter.tabs('back', { tabId: args.tabId })\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }\n }\n )\n\n // browser_tabs_forward\n server.registerTool(\n 'browser_tabs_forward',\n { description: '在指定标签页(或当前活跃标签页)中执行浏览器前进操作。', inputSchema: BrowserTabsNavInput.shape },\n async (args) => {\n const result = await adapter.tabs('forward', { tabId: args.tabId })\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }\n }\n )\n }\n}\n\n// ─── WXT 专属工具注册 ─────────────────────────────────────────────────────────\n\nfunction registerWxtTools(\n server: McpServer,\n adapter: WxtBrowserAdapter,\n isAgentMode: boolean,\n mcpServer: McpServer\n): void {\n // browser_sub_agent_run\n server.registerTool(\n 'browser_sub_agent_run',\n {\n description: isAgentMode\n ? '《Tiny Robot 端侧自主子代理》将复杂或长流程的浏览器操作任务委托给扩展端侧的 Tiny Robot 子代理闭环执行。子代理将在端侧自主观察页面、规划步骤并执行原子操作,执行完毕后返回最终结果,极大地节省主 Agent 上下文 Token。'\n : '《高层任务委托》将复杂、长流程或需反复试错的浏览器操作任务委托给 Chrome 扩展内部的 Tiny Robot 子代理(Sub-Agent)自主闭环执行。子代理将在端侧自主进行页面探索、规划和原子操作,执行完毕后返回最终结果,极大地节省外部主 Agent 的上下文 Token。',\n inputSchema: BrowserSubAgentRunInput.shape\n },\n async (args, extra) => {\n const progressToken = extra?._meta?.progressToken as string | number | undefined\n const onProgress = progressToken != null\n ? (params: any) => {\n if (params?.progressToken && params.progressToken !== progressToken) return\n try {\n mcpServer.server.notification({\n method: 'notifications/progress',\n params: { progressToken, progress: params?.step ?? 0, total: params?.total ?? args.maxSteps ?? 8, message: params?.message ?? '' }\n })\n } catch { /* ignore */ }\n }\n : undefined\n\n if (onProgress) adapter.bridgeClient.on('progress', onProgress)\n try {\n const result = await adapter.runSubAgent(args.instruction, {\n tabId: args.tabId,\n maxSteps: args.maxSteps,\n progressToken\n })\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }\n } finally {\n if (onProgress) adapter.bridgeClient.off('progress', onProgress)\n }\n }\n )\n\n if (!isAgentMode) {\n // browser_skills_list\n server.registerTool(\n 'browser_skills_list',\n {\n description:\n '【技能渐进式披露 - L1 索引层】获取当前浏览器扩展中已维护的所有 Skills 技能简短清单(仅返回名称、简介,消耗极少 Token)。在自主执行复杂或垂直领域任务前,可先调用此工具匹配最适用的技能。',\n inputSchema: BrowserSkillsListInput.shape\n },\n async () => {\n const result = await adapter.listSkills()\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }\n }\n )\n\n // browser_skills_read\n server.registerTool(\n 'browser_skills_read',\n {\n description:\n '【技能渐进式披露 - L2 契约层】根据技能名称按需读取该技能的完整详细执行指令 (instructions)、工作流规范与输入输出契约。',\n inputSchema: BrowserSkillsReadInput.shape\n },\n async (args) => {\n const result = await adapter.getSkill(args.name)\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }\n }\n )\n }\n}\n\n// ─── Skills Resource 注册(L1/L2/L3) ────────────────────────────────────────\n\nfunction registerSkillsResources(server: McpServer, adapter: WxtBrowserAdapter): void {\n server.registerResource(\n 'skills_index',\n 'skills://index',\n { description: 'Skills L1:扩展已注册的所有技能列表(仅元数据,消耗极少 Token)', mimeType: 'application/json' },\n async () => {\n try {\n const skills = await adapter.listSkills()\n return { contents: [{ uri: 'skills://index', text: JSON.stringify(skills, null, 2), mimeType: 'application/json' }] }\n } catch (err) {\n return { contents: [{ uri: 'skills://index', text: JSON.stringify({ error: err instanceof Error ? err.message : String(err) }), mimeType: 'application/json' }] }\n }\n }\n )\n\n const skillDetailTemplate = new ResourceTemplate('skills://{skillName}/detail', { list: undefined })\n server.registerResource(\n 'skill_detail',\n skillDetailTemplate,\n { description: 'Skills L2:按技能名实时拉取完整 SOP 执行指令与输入输出契约', mimeType: 'application/json' },\n async (uri, params) => {\n const { skillName } = params as { skillName: string }\n try {\n const detail = await adapter.getSkill(skillName)\n return { contents: [{ uri: uri.href, text: JSON.stringify(detail, null, 2), mimeType: 'application/json' }] }\n } catch (err) {\n return { contents: [{ uri: uri.href, text: JSON.stringify({ error: err instanceof Error ? err.message : String(err) }), mimeType: 'application/json' }] }\n }\n }\n )\n\n const skillResourceTemplate = new ResourceTemplate('skills://{skillName}/{resourcePath}', { list: undefined })\n server.registerResource(\n 'skill_resource',\n skillResourceTemplate,\n { description: 'Skills L3:读取技能关联的深入参考资料或配置文件(按需加载)', mimeType: 'text/plain' },\n async (uri, params) => {\n const { skillName, resourcePath } = params as { skillName: string; resourcePath: string }\n try {\n const text = await adapter.readSkillResource(skillName, resourcePath)\n return { contents: [{ uri: uri.href, text: String(text), mimeType: 'text/plain' }] }\n } catch (err) {\n return { contents: [{ uri: uri.href, text: `读取资源失败: ${err instanceof Error ? err.message : String(err)}`, mimeType: 'text/plain' }] }\n }\n }\n )\n}\n","/**\n * agent 命令:委托 Chrome 扩展内 Tiny Robot 子代理自主执行高层任务\n *\n * 用法:\n * webmcp-cli --mode wxt agent run \"帮我把当前商品加入购物车\"\n * webmcp-cli --mode wxt agent run \"搜索并收藏前3篇文章\" --max-steps 10\n */\n\nimport type { WxtBrowserAdapter } from '../adapters/wxt-adapter.js'\n\nexport async function handleAgentCommand(adapter: WxtBrowserAdapter, args: string[]): Promise<void> {\n const subCommand = args[0]\n const restArgs = args.slice(1)\n\n if (!subCommand || subCommand === '--help' || subCommand === '-h') {\n printAgentHelp()\n return\n }\n\n if (subCommand === 'run') {\n await handleAgentRun(adapter, restArgs)\n return\n }\n\n console.error(`[错误] 未知子命令: agent ${subCommand}`)\n console.error('运行 webmcp-cli --mode wxt agent --help 查看支持的命令')\n process.exit(1)\n}\n\nasync function handleAgentRun(adapter: WxtBrowserAdapter, args: string[]): Promise<void> {\n // 提取选项\n let instruction = ''\n let maxSteps: number | undefined\n let tabId: number | undefined\n const isJson = args.includes('--json')\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]\n if (arg === '--max-steps' && args[i + 1]) {\n maxSteps = parseInt(args[++i], 10)\n } else if (arg === '--tab' && args[i + 1]) {\n tabId = parseInt(args[++i], 10)\n } else if (!arg.startsWith('-')) {\n instruction = arg\n }\n }\n\n if (!instruction) {\n console.error('[错误] 请提供任务指令。示例:webmcp-cli --mode wxt agent run \"帮我搜索最新新闻\"')\n process.exit(1)\n }\n\n if (!isJson) {\n console.log(`🤖 正在委托 Tiny Robot 子代理执行任务:「${instruction}」`)\n if (maxSteps) console.log(` 最大步数:${maxSteps}`)\n }\n\n try {\n const result = await adapter.runSubAgent(instruction, { tabId, maxSteps })\n if (isJson) {\n console.log(JSON.stringify(result, null, 2))\n } else {\n console.log('\\n✅ 子代理执行完成:')\n console.log(JSON.stringify(result, null, 2))\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (isJson) {\n console.log(JSON.stringify({ success: false, error: msg }))\n } else {\n console.error(`❌ 执行失败:${msg}`)\n }\n process.exit(1)\n }\n}\n\nfunction printAgentHelp(): void {\n console.log(`\nwebmcp-cli --mode wxt agent - 委托 Chrome 扩展内 Tiny Robot 子代理执行高层任务\n\n用法:\n webmcp-cli --mode wxt agent run \"<指令>\" 委托子代理自主执行自然语言任务\n\n选项:\n --max-steps <n> 最大执行步数(默认 8,最大 20)\n --tab <tabId> 指定目标标签页 ID\n --json 输出 JSON 格式结果\n\n示例:\n webmcp-cli --mode wxt agent run \"帮我把当前商品加入购物车\"\n webmcp-cli --mode wxt agent run \"搜索并收藏前3篇文章\" --max-steps 10\n`.trim())\n}\n","/**\n * skills 命令:查询与读取浏览器扩展中注册的 Skills 技能\n *\n * 用法:\n * webmcp-cli --mode wxt skills list\n * webmcp-cli --mode wxt skills get <skillName>\n */\n\nimport type { WxtBrowserAdapter } from '../adapters/wxt-adapter.js'\n\nexport async function handleSkillsCommand(adapter: WxtBrowserAdapter, args: string[]): Promise<void> {\n const subCommand = args[0]\n const restArgs = args.slice(1)\n const isJson = args.includes('--json')\n\n if (!subCommand || subCommand === '--help' || subCommand === '-h') {\n printSkillsHelp()\n return\n }\n\n if (subCommand === 'list') {\n await handleSkillsList(adapter, isJson)\n return\n }\n\n if (subCommand === 'get') {\n const skillName = restArgs.find((a) => !a.startsWith('-'))\n if (!skillName) {\n console.error('[错误] 请提供技能名称。示例:webmcp-cli --mode wxt skills get <skillName>')\n process.exit(1)\n }\n await handleSkillsGet(adapter, skillName, isJson)\n return\n }\n\n console.error(`[错误] 未知子命令: skills ${subCommand}`)\n printSkillsHelp()\n process.exit(1)\n}\n\nasync function handleSkillsList(adapter: WxtBrowserAdapter, isJson: boolean): Promise<void> {\n try {\n const result = await adapter.listSkills()\n if (isJson) {\n console.log(JSON.stringify(result, null, 2))\n } else {\n const skills = result as Array<{ name: string; description?: string; source?: string }>\n if (!skills || skills.length === 0) {\n console.log('(当前扩展未注册任何技能)')\n return\n }\n console.log(`\\n📚 已注册 Skills(共 ${skills.length} 个):\\n`)\n for (const skill of skills) {\n console.log(` • ${skill.name}`)\n if (skill.description) {\n console.log(` ${skill.description.slice(0, 100)}${skill.description.length > 100 ? '...' : ''}`)\n }\n }\n console.log(`\\n提示:使用 \"webmcp-cli --mode wxt skills get <name>\" 查看技能详情`)\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (isJson) {\n console.log(JSON.stringify({ error: msg }))\n } else {\n console.error(`❌ 获取技能列表失败:${msg}`)\n }\n process.exit(1)\n }\n}\n\nasync function handleSkillsGet(adapter: WxtBrowserAdapter, name: string, isJson: boolean): Promise<void> {\n try {\n const result = await adapter.getSkill(name)\n if (isJson) {\n console.log(JSON.stringify(result, null, 2))\n } else {\n const skill = result as { name: string; description?: string; instructions?: string }\n console.log(`\\n📖 技能:${skill.name}`)\n if (skill.description) console.log(`描述:${skill.description}`)\n if (skill.instructions) {\n console.log('\\n--- 指令 ---')\n console.log(skill.instructions)\n }\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (isJson) {\n console.log(JSON.stringify({ error: msg }))\n } else {\n console.error(`❌ 获取技能详情失败:${msg}`)\n }\n process.exit(1)\n }\n}\n\nfunction printSkillsHelp(): void {\n console.log(`\nwebmcp-cli --mode wxt skills - 查询与读取浏览器扩展中注册的 Skills 技能\n\n用法:\n webmcp-cli --mode wxt skills list 列出所有已注册的技能\n webmcp-cli --mode wxt skills get <name> 读取指定技能的详细执行指令\n\n选项:\n --json 输出 JSON 格式结果\n\n示例:\n webmcp-cli --mode wxt skills list\n webmcp-cli --mode wxt skills get order-management\n`.trim())\n}\n","#!/usr/bin/env node\nimport fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\nimport { readFileSync } from 'fs'\nimport { resolve } from 'path'\nimport { getFileBaseDir } from './expand-file-refs'\nimport { prepareRunArgsJson } from './parse-run-args'\nimport { stateCommand } from './commands/state'\nimport { runCommand } from './commands/run'\nimport { setClipboard } from './commands/clipboard'\nimport {\n tabsOpenCommand,\n tabsCloseCommand,\n tabsSwitchCommand,\n tabsBackCommand,\n tabsForwardCommand\n} from './commands/tabs'\nimport packageJson from '../package.json'\n\n// ─── WXT 模式预检:在 Commander 解析前提取 --mode 参数 ──────────────────────\n// 支持:--mode wxt / --mode cdp / WEBMCP_MODE=wxt 环境变量\nfunction extractMode(argv: string[]): { mode: 'cdp' | 'wxt'; filteredArgv: string[] } {\n let mode: 'cdp' | 'wxt' = (process.env.WEBMCP_MODE === 'wxt') ? 'wxt' : 'cdp'\n const filteredArgv: string[] = []\n for (let i = 0; i < argv.length; i++) {\n if (argv[i] === '--mode' && argv[i + 1]) {\n const val = argv[i + 1].toLowerCase()\n if (val === 'wxt' || val === 'cdp') mode = val\n i++ // 跳过值\n } else if (argv[i].startsWith('--mode=')) {\n const val = argv[i].split('=')[1]?.toLowerCase()\n if (val === 'wxt' || val === 'cdp') mode = val\n } else {\n filteredArgv.push(argv[i])\n }\n }\n return { mode, filteredArgv }\n}\n\nconst { mode: CLI_MODE, filteredArgv: FILTERED_ARGV } = extractMode(process.argv)\n\nconst program = new Command()\n\nfunction parseTabId(id?: string): string | undefined {\n if (!id) return undefined\n return id\n}\n\n/** 解析 browserState 返回文本:新格式为纯 JSON;兼容旧前缀 / 尾部告警 */\nfunction tryParseBrowserStateText(text: string): Record<string, unknown> & { content: string } | null {\n const tryParse = (jsonStr: string) => {\n try {\n const parsed = JSON.parse(jsonStr) as Record<string, unknown>\n if (parsed && typeof parsed.content === 'string') {\n return parsed as Record<string, unknown> & { content: string }\n }\n } catch {\n // ignore\n }\n return null\n }\n\n const direct = tryParse(text)\n if (direct) return direct\n\n if (text.startsWith('浏览器状态: ')) {\n let jsonStr = text.substring('浏览器状态: '.length)\n const firstNewline = jsonStr.indexOf('\\n')\n if (firstNewline !== -1) {\n const maybeJson = jsonStr.substring(0, firstNewline)\n if (tryParse(maybeJson)) jsonStr = maybeJson\n }\n return tryParse(jsonStr)\n }\n\n return null\n}\n\nfunction cleanOldLogs(baseDir: string, logDir: string) {\n try {\n // 1. 清理原本根目录下的旧版单文件和旧版日期文件\n const oldLogFile = path.join(baseDir, 'webmcp-cli.log')\n if (fs.existsSync(oldLogFile)) {\n try { fs.unlinkSync(oldLogFile) } catch {}\n }\n if (fs.existsSync(baseDir)) {\n const baseFiles = fs.readdirSync(baseDir)\n for (const file of baseFiles) {\n if (/^webmcp-cli-\\d{4}-\\d{2}-\\d{2}\\.log$/.test(file)) {\n try { fs.unlinkSync(path.join(baseDir, file)) } catch {}\n }\n }\n }\n\n // 2. 清理 logs 目录下超过 7 天的日志\n if (!fs.existsSync(logDir)) return\n const files = fs.readdirSync(logDir)\n const logFilePattern = /^webmcp-cli-(\\d{4}-\\d{2}-\\d{2})\\.log$/\n const now = Date.now()\n const maxAgeMs = 7 * 24 * 60 * 60 * 1000 // 7天\n\n for (const file of files) {\n const match = file.match(logFilePattern)\n if (match) {\n const fileDateStr = match[1]\n const fileDate = new Date(fileDateStr).getTime()\n if (isNaN(fileDate)) continue\n if (now - fileDate > maxAgeMs) {\n try {\n fs.unlinkSync(path.join(logDir, file))\n } catch {\n // 忽略单文件删除失败\n }\n }\n }\n }\n } catch (e) {\n // 忽略清理日志本身的错误\n }\n}\n\nfunction formatLogResult(result: any): string {\n if (result === undefined || result === null) {\n return 'null'\n }\n\n try {\n if (typeof result !== 'object') {\n return String(result)\n }\n\n // 深拷贝 result,防止意外修改原始数据导致控制台输出受影响\n const clone = JSON.parse(JSON.stringify(result))\n let a11yTreeStr = ''\n let searchResultStr = ''\n\n // 检测 page-agent-tool 的 browserState/操作 动作返回\n if (\n clone &&\n Array.isArray(clone.content) &&\n clone.content.length > 0 &&\n clone.content[0] &&\n typeof clone.content[0].text === 'string'\n ) {\n const text = clone.content[0].text\n const browserState = tryParseBrowserStateText(text)\n if (browserState) {\n a11yTreeStr = browserState.content\n // 替换 clone 中的 content 部分,避免在 JSON 序列化时产生超长难读的字符串\n browserState.content = '[Formatted A11y Tree - See details below]'\n clone.content[0].text = JSON.stringify(browserState, null, 2)\n } else if (\n text.includes('A11y Tree 搜索结果') ||\n text.includes('无障碍树搜索结果') ||\n text.includes('无障碍树搜索') ||\n text.includes('命中行') ||\n text.includes('context:')\n ) {\n // 如果是 searchTree 的返回,或者其他可能包含 A11y Tree 搜索结构的多行文本\n searchResultStr = text\n clone.content[0].text = '[Search A11y Tree Result - See details below]'\n }\n }\n\n let out = JSON.stringify(clone, null, 2)\n if (a11yTreeStr) {\n out += `\\n\\n[FORMATTED A11Y TREE]:\\n${a11yTreeStr}`\n }\n if (searchResultStr) {\n out += `\\n\\n[FORMATTED SEARCH RESULT]:\\n${searchResultStr}`\n }\n return out\n } catch (e) {\n // 降级使用标准 stringify\n try {\n return JSON.stringify(result, null, 2)\n } catch {\n return String(result)\n }\n }\n}\n\nfunction writeLog(commandName: string, args: any, result: any, error?: any) {\n try {\n const baseDir = process.env.WEBMCP_WORKSPACE || path.join(os.homedir(), '.webmcp_chrome_profile')\n const logDir = path.join(baseDir, 'logs')\n if (!fs.existsSync(logDir)) {\n fs.mkdirSync(logDir, { recursive: true })\n }\n const todayStr = new Date().toISOString().split('T')[0]\n const logFile = path.join(logDir, `webmcp-cli-${todayStr}.log`)\n\n const timestamp = new Date().toISOString()\n let logText = `========================================\\n`\n logText += `[${timestamp}] COMMAND: ${commandName}\\n`\n logText += `ARGS:\\n${JSON.stringify(args, null, 2)}\\n\\n`\n\n if (error) {\n logText += `ERROR:\\n${error instanceof Error ? error.stack : String(error)}\\n`\n } else if (result) {\n logText += `RESULT:\\n`\n const formattedResult = formatLogResult(result)\n logText += formattedResult.split('\\n').map(line => ` ${line}`).join('\\n') + '\\n'\n } else {\n logText += `RESULT: null\\n`\n }\n logText += `========================================\\n\\n`\n\n fs.appendFileSync(logFile, logText, 'utf-8')\n cleanOldLogs(baseDir, logDir)\n } catch (e) {\n // 忽略日志写入本身的错误,防止阻塞主流程\n }\n}\n\nfunction handleCommandError(error: unknown, commandName: string, args?: any): never {\n const msg = error instanceof Error ? error.message : String(error)\n writeLog(commandName, args, null, error)\n console.error(pc.red(`Error executing ${commandName} command: ${msg}`))\n process.exit(1)\n}\n\nprogram\n .name('webmcp-cli')\n .description(\n 'WebMCP CLI — 支持两种浏览器连接模式:\\n' +\n ' --mode cdp(默认): 基于 Puppeteer + CDP 直连浏览器(独立 profile)\\n' +\n ' --mode wxt : 基于 WebSocket + Chrome 扩展桥接(复用用户数据)'\n )\n .version(packageJson.version)\n .option('-w, --workspace <path>', '指定自定义的浏览器工作空间(用户配置目录)路径,仅 CDP 模式有效')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts()\n if (opts.workspace) {\n process.env.WEBMCP_WORKSPACE = opts.workspace\n }\n })\n\nprogram\n .command('state')\n .description('获取浏览器当前页签或指定页签的导航元数据(url、title、webmcpTools、所有页签列表)')\n .option('-t, --tabid <id>', '指定页签的 ID')\n .action(async (options) => {\n const args = { tabid: parseTabId(options.tabid) }\n try {\n const result = await stateCommand(args)\n writeLog('state', args, result)\n console.log(formatLogResult(result))\n } catch (error: unknown) {\n handleCommandError(error, 'state', args)\n }\n })\n\nprogram\n .command('run <toolName> [args...]')\n .description('向指定页签调用指定的 WebMCP 工具执行操作')\n .option('-t, --tabid <id>', '指定页签的 ID')\n .option(\n '-f, --file <path>',\n '从指定 .json 文件读取整个参数(文件内容即为参数 JSON)。\\n' +\n '如需在参数中内联引用文件,使用占位符语法:\\n' +\n ' @file:<path> 读取文件原始文本\\n' +\n ' @base64file:<path> 读取文件并 Base64 编码\\n' +\n '示例:webmcp-cli run mytool \\'{\"content\":\"@base64file:./doc.md\"}\\''\n )\n .action(async (toolName, args, options) => {\n let finalArgsJson = ''\n const rawArgs = { toolName, args, file: options.file, tabid: options.tabid }\n try {\n let fileContent: string | undefined\n let fileBaseDir = process.cwd()\n\n if (options.file) {\n const filePath = resolve(process.cwd(), options.file)\n fileBaseDir = getFileBaseDir(options.file)\n try {\n fileContent = readFileSync(filePath, 'utf-8')\n } catch (e: any) {\n throw new Error(`无法读取文件 \"${filePath}\": ${e.message}`)\n }\n }\n\n finalArgsJson = prepareRunArgsJson(args ?? [], fileContent, fileBaseDir)\n\n const result = await runCommand({\n toolName,\n argsJson: finalArgsJson,\n tabid: parseTabId(options.tabid)\n })\n writeLog('run', { ...rawArgs, finalArgsJson }, result)\n console.log(formatLogResult(result))\n } catch (error: unknown) {\n handleCommandError(error, 'run', { ...rawArgs, finalArgsJson })\n }\n })\n\n\nprogram\n .command('clipboard <content>')\n .description('将内容设置到系统剪贴板')\n .action(async (content) => {\n const args = { content }\n try {\n await setClipboard(content)\n const result = { success: true, message: '内容已设置到系统剪贴板' }\n writeLog('clipboard', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'clipboard', args)\n }\n })\n\nconst tabs = program.command('tabs').description('管理浏览器标签页')\n\ntabs\n .command('open <url>')\n .description('打开新网页')\n .action(async (url) => {\n const args = { url }\n try {\n const result = await tabsOpenCommand(url)\n writeLog('tabs open', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'tabs open', args)\n }\n })\n\ntabs\n .command('close <tabid>')\n .description('关闭指定 tabid 的标签页')\n .action(async (tabid) => {\n const args = { tabid }\n try {\n const result = await tabsCloseCommand(tabid)\n writeLog('tabs close', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'tabs close', args)\n }\n })\n\ntabs\n .command('switch <tabid>')\n .description('激活并切换到指定 tabid 的标签页')\n .action(async (tabid) => {\n const args = { tabid }\n try {\n const result = await tabsSwitchCommand(tabid)\n writeLog('tabs switch', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'tabs switch', args)\n }\n })\n\ntabs\n .command('back [tabid]')\n .description('将当前或指定标签页导航后退一步')\n .action(async (tabid) => {\n const args = { tabid: parseTabId(tabid) }\n try {\n const result = await tabsBackCommand(args.tabid)\n writeLog('tabs back', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'tabs back', args)\n }\n })\n\ntabs\n .command('forward [tabid]')\n .description('将当前或指定标签页导航前进一步')\n .action(async (tabid) => {\n const args = { tabid: parseTabId(tabid) }\n try {\n const result = await tabsForwardCommand(args.tabid)\n writeLog('tabs forward', args, result)\n console.log(JSON.stringify(result, null, 2))\n } catch (error: unknown) {\n handleCommandError(error, 'tabs forward', args)\n }\n })\n\n// CDP 模式:mcp 子命令(以 MCP Server 方式启动,CDP 底层)\nprogram\n .command('mcp')\n .description('以标准 MCP Server 模式启动(stdio 传输,CDP 底层)。\\n使用 --mode wxt mcp 切换到 WXT 桥接底层。')\n .option('--agent', '以子代理模式启动(收敛工具为高层委托接口)')\n .action(async (opts) => {\n try {\n const { startMcpServer } = await import('./mcp/server.js')\n await startMcpServer({ mode: 'cdp', agentMode: opts.agent ? 'agent' : 'tools' })\n } catch (error: unknown) {\n handleCommandError(error, 'mcp', {})\n }\n })\n\n// ─── 模式路由 ────────────────────────────────────────────────────────────────\nif (CLI_MODE === 'wxt') {\n // WXT 模式:路由到独立的 WXT 命令处理器\n void handleWxtMode(FILTERED_ARGV.slice(2)).catch((error: unknown) => {\n handleCommandError(error, `wxt:${FILTERED_ARGV[2] ?? 'help'}`, {})\n })\n} else {\n // CDP 模式(默认):走 Commander 原有逻辑,完全向后兼容\n program.parse(FILTERED_ARGV)\n}\n\nasync function handleWxtMode(args: string[]): Promise<void> {\n const command = args[0]\n\n // 生命周期命令(无需 adapter)\n if (command === 'daemon' || command === 'server') {\n const { runDaemonProcess } = await import('./bridge/daemon.js')\n await runDaemonProcess(args.slice(1))\n return\n }\n\n if (command === 'stop') {\n const { stopBridgeDaemon } = await import('./bridge/daemon.js')\n const stopped = await stopBridgeDaemon()\n console.log(stopped ? '✅ 已停止后台 WebSocket 桥接服务' : 'ℹ️ 当前没有运行中的后台桥接服务')\n return\n }\n\n if (command === 'token') {\n const subArgs = args.slice(1)\n let wsPort: number | undefined\n const cleanArgs: string[] = []\n for (let i = 0; i < subArgs.length; i++) {\n if ((subArgs[i] === '--ws-port' || subArgs[i] === '--port') && subArgs[i + 1]) {\n wsPort = parseInt(subArgs[++i], 10) || undefined\n } else {\n cleanArgs.push(subArgs[i])\n }\n }\n\n const action = cleanArgs[0]\n let tokenToSet: string | undefined\n if (action === 'set' && cleanArgs[1]) {\n tokenToSet = cleanArgs[1].trim()\n } else if (action && action !== 'get' && !action.startsWith('-')) {\n tokenToSet = action.trim()\n }\n\n const { resolveOrCreateAuthToken } = await import('./bridge/bridge-client.js')\n if (tokenToSet) {\n resolveOrCreateAuthToken(tokenToSet)\n console.log('✅ Token 已成功保存至 ~/.robot-wxt/bridge-token')\n const { stopBridgeDaemon, ensureBridgeDaemon } = await import('./bridge/daemon.js')\n await stopBridgeDaemon(wsPort)\n await ensureBridgeDaemon({ token: tokenToSet, port: wsPort })\n console.log('💡 后续所有 CLI 命令与 MCP 工具均将自动使用此凭据,无需重复输入。')\n return\n }\n\n console.log(resolveOrCreateAuthToken())\n return\n }\n\n if (command === 'mcp') {\n // MCP Server 模式(WXT 底层)\n const { startMcpServer } = await import('./mcp/server.js')\n const isAgent = args.includes('--agent') || args.includes('--mode=agent')\n const tokenIdx = args.indexOf('--token')\n const token = tokenIdx !== -1 ? args[tokenIdx + 1] : undefined\n const wsPortIdx = args.indexOf('--ws-port')\n const wsPort = wsPortIdx !== -1 ? parseInt(args[wsPortIdx + 1], 10) || undefined : undefined\n await startMcpServer({ mode: 'wxt', agentMode: isAgent ? 'agent' : 'tools', token, wsPort })\n return\n }\n\n if (!command || command === '--help' || command === '-h') {\n printWxtHelp()\n return\n }\n\n // 需要 adapter 的命令:提取 token、ws-port、tab 等公共选项\n let token: string | undefined\n let wsPort: number | undefined\n const commandArgs: string[] = []\n for (let i = 1; i < args.length; i++) {\n if (args[i] === '--token' && args[i + 1]) { token = args[++i] }\n else if (args[i] === '--ws-port' && args[i + 1]) { wsPort = parseInt(args[++i], 10) || undefined }\n else { commandArgs.push(args[i]) }\n }\n\n const { ensureBridgeDaemon } = await import('./bridge/daemon.js')\n const isJson = commandArgs.includes('--json')\n await ensureBridgeDaemon({ token, port: wsPort, silent: isJson })\n\n const { WxtBrowserAdapter } = await import('./adapters/wxt-adapter.js')\n const adapter = new WxtBrowserAdapter(token, wsPort)\n await adapter.ensureConnected()\n\n try {\n switch (command) {\n case 'state': {\n const tabIdx = commandArgs.indexOf('--tab')\n const tabId = tabIdx !== -1 ? commandArgs[tabIdx + 1] : undefined\n const result = await adapter.getState(tabId ? parseInt(tabId, 10) : undefined)\n console.log(JSON.stringify(result, null, 2))\n break\n }\n case 'run': {\n const toolName = commandArgs.find((a) => !a.startsWith('-'))\n const argsStr = commandArgs.slice(commandArgs.indexOf(toolName!) + 1).find((a) => !a.startsWith('-'))\n if (!toolName) { console.error('[错误] 请提供工具名称'); process.exit(1) }\n const toolArgs = argsStr ? JSON.parse(argsStr) : {}\n const result = await adapter.callTool(toolName, toolArgs)\n console.log(JSON.stringify(result, null, 2))\n break\n }\n case 'tabs': {\n const tabAction = commandArgs[0] as 'open' | 'close' | 'switch' | 'back' | 'forward'\n const tabArgs = commandArgs.slice(1)\n const url = tabArgs.find((a) => a.startsWith('http'))\n const tabIdVal = tabArgs.find((a) => !a.startsWith('-') && !a.startsWith('http'))\n const result = await adapter.tabs(tabAction, {\n url,\n tabId: tabIdVal ? parseInt(tabIdVal, 10) : undefined\n })\n console.log(JSON.stringify(result, null, 2))\n break\n }\n case 'agent': {\n const { handleAgentCommand } = await import('./commands/agent.js')\n await handleAgentCommand(adapter, commandArgs)\n break\n }\n case 'skills':\n case 'skill': {\n const { handleSkillsCommand } = await import('./commands/skills.js')\n await handleSkillsCommand(adapter, commandArgs)\n break\n }\n default:\n console.error(`[错误] WXT 模式下未知命令: ${command}`)\n printWxtHelp()\n process.exit(1)\n }\n } finally {\n await adapter.dispose()\n }\n}\n\nfunction printWxtHelp(): void {\n console.log(`\nwebmcp-cli --mode wxt — WXT 桥接模式(通过 Chrome 扩展连接,复用用户数据)\n\n命令:\n state 获取当前活跃 tab 信息与页面工具列表\n run <tool> [args] 调用页面 WebMCP 工具\n tabs <action> [...] 管理标签页(open/close/switch/back/forward)\n agent run \"<指令>\" 委托 Tiny Robot 子代理自主执行高层任务\n skills list 列出已注册的 Skills 技能\n skills get <name> 读取指定技能的详细指令\n token [get|set <t>] 查看或保存认证 Token\n stop 停止后台 WebSocket 桥接服务\n mcp 以 MCP Server 模式启动\n\n选项:\n --token <token> 认证 Token(优先于 ~/.robot-wxt/bridge-token)\n --ws-port <port> WS 桥接端口(默认 18999)\n --json 输出 JSON 格式\n\n示例:\n webmcp-cli --mode wxt state\n webmcp-cli --mode wxt agent run \"帮我把商品加入购物车\"\n webmcp-cli --mode wxt mcp --agent\n `.trim())\n}\n","import { readFileSync } from 'fs'\nimport { dirname, isAbsolute, normalize, resolve } from 'path'\nimport { fileURLToPath } from 'url'\n\n/** 匹配完整 JSON 字符串字面量 */\nconst JSON_STRING_LITERAL = /\"(?:[^\"\\\\]|\\\\.)*\"/g\n\n/** 匹配未加引号的 @file: / @base64file: 占位符(路径中可含反斜杠) */\nconst UNQUOTED_FILE_REF = /(?<![\\\\\"])@(base64)?file:([^\\s\"',}\\]]+)/g\n\nconst FILE_REF_PREFIX = /^@(base64)?file:(.+)$/s\n\nexport function resolveFilePath(filePath: string, baseDir: string = process.cwd()): string {\n let normalizedPath = filePath.trim()\n\n if (\n (normalizedPath.startsWith('\"') && normalizedPath.endsWith('\"')) ||\n (normalizedPath.startsWith(\"'\") && normalizedPath.endsWith(\"'\"))\n ) {\n normalizedPath = normalizedPath.slice(1, -1).trim()\n }\n\n if (normalizedPath.startsWith('file://')) {\n normalizedPath = fileURLToPath(normalizedPath)\n }\n\n if (isAbsolute(normalizedPath)) {\n return normalize(normalizedPath)\n }\n\n return resolve(baseDir, normalizedPath)\n}\n\n/**\n * 解码文件路径:仅折叠 JSON 中的 `\\\\`,不把 `\\t`、`\\U` 等当作转义。\n */\nexport function decodeFilePath(rawPath: string): string {\n return rawPath.replace(/\\\\\\\\/g, '\\\\')\n}\n\nfunction readFileRefContent(filePath: string, baseDir: string, base64: boolean): string {\n const absPath = resolveFilePath(filePath, baseDir)\n let content: string\n try {\n content = readFileSync(absPath, 'utf-8')\n } catch (e: any) {\n throw new Error(`无法读取文件引用 \"${filePath}\" (${absPath}): ${e.message}`)\n }\n\n return base64 ? Buffer.from(content, 'utf-8').toString('base64') : content\n}\n\nfunction expandFileRefValue(rawInner: string, baseDir: string): string | null {\n const match = rawInner.match(FILE_REF_PREFIX)\n if (!match) {\n return null\n }\n\n const [, base64Flag, rawPath] = match\n const filePath = decodeFilePath(rawPath)\n const value = readFileRefContent(filePath, baseDir, Boolean(base64Flag))\n return JSON.stringify(value)\n}\n\nfunction expandQuotedFileRefs(argsJson: string, baseDir: string): string {\n return argsJson.replace(JSON_STRING_LITERAL, (jsonStringLiteral) => {\n const rawInner = jsonStringLiteral.slice(1, -1)\n const replacement = expandFileRefValue(rawInner, baseDir)\n return replacement ?? jsonStringLiteral\n })\n}\n\nfunction expandUnquotedFileRefs(argsJson: string, baseDir: string): string {\n return argsJson.replace(UNQUOTED_FILE_REF, (match, base64Flag, filePath) => {\n const value = readFileRefContent(filePath, baseDir, Boolean(base64Flag))\n return JSON.stringify(value)\n })\n}\n\n/**\n * 展开 argsJson 中的文件引用占位符:\n * @file:<path> → 读取文件原始文本内容\n * @base64file:<path> → 读取文件内容并 Base64 编码\n */\nexport function expandFileRefs(argsJson: string, baseDir: string = process.cwd()): string {\n const withQuotedExpanded = expandQuotedFileRefs(argsJson, baseDir)\n return expandUnquotedFileRefs(withQuotedExpanded, baseDir)\n}\n\n/**\n * 确定 `@file` / `@base64file` 相对路径的解析基准目录。\n *\n * 未使用 `-f/--file` 时以 `process.cwd()` 为基准;\n * 使用参数文件时以该文件所在目录为基准,使 `args.json` 内 `./article.md` 等路径\n * 相对于参数文件而非 shell 当前工作目录解析。\n *\n * @example\n * // cwd 为 /home/user/project,执行 webmcp run tool -f test/fixtures/nested/args.json\n * getFileBaseDir('test/fixtures/nested/args.json')\n * // => '/home/user/project/test/fixtures/nested'\n */\nexport function getFileBaseDir(fileOption?: string): string {\n if (!fileOption) {\n return process.cwd()\n }\n return dirname(resolve(process.cwd(), fileOption))\n}\n","import JSON5 from 'json5'\nimport { expandFileRefs } from './expand-file-refs'\n\nexport function cleanJsonString(str: string): string {\n let cleaned = str.trim()\n if (cleaned.startsWith(\"'\") && cleaned.endsWith(\"'\")) {\n cleaned = cleaned.slice(1, -1).trim()\n }\n return cleaned\n}\n\nfunction looksLikeObjectBody(raw: string): boolean {\n return /^(\"?[\\w-]+\"?\\s*:)/.test(raw)\n}\n\n/**\n * 拼接 shell 拆散的参数。\n * 兼容 bash 花括号展开后丢失 `{}` 的情况:title:\"...\", \"content\":\"...\"\n */\nexport function joinShellArgs(args: string[]): string {\n const cleaned = args.map(cleanJsonString)\n const first = cleaned[0] ?? ''\n\n if (first.startsWith('{')) {\n return cleaned.join(' ')\n }\n\n if (looksLikeObjectBody(first)) {\n let joined = cleaned.join(' ')\n if (!joined.startsWith('{')) {\n joined = `{${joined}}`\n }\n if (!joined.endsWith('}')) {\n joined = `${joined}}`\n }\n return joined\n }\n\n return cleaned.join(' ')\n}\n\n/** 在相邻属性之间补逗号:title:\"a\" \"content\":\"b\" → title:\"a\",\"content\":\"b\" */\nexport function insertMissingCommas(raw: string): string {\n return raw.replace(/\"(\\s+)(\"?[\\w-]+\"?\\s*:)/g, '\",$2')\n}\n\n/**\n * 为未加引号的字符串值补引号。\n * 典型 shell 损坏:{title:TinyVue Icon,content:@base64file:./a.md}\n */\nexport function quoteUnquotedStringValues(raw: string): string {\n return raw.replace(\n /([{,]\\s*(?:\"([^\"]+)\"|([\\w-]+))\\s*:\\s*)(?!\"@(?:base64)?file:|\"|true|false|null|-?\\d|\\{|\\[)([^\",}\\]]+?)(?=\\s*[,}])/g,\n (_match, prefix, _quotedKey, _unquotedKey, value: string) => {\n const trimmed = value.trim()\n if (/^-?\\d+(\\.\\d+)?([eE][+-]?\\d+)?$/.test(trimmed)) {\n return prefix + trimmed\n }\n return prefix + JSON.stringify(trimmed)\n }\n )\n}\n\nexport function normalizeShellDamagedJson(raw: string): string {\n let normalized = raw.trim()\n normalized = insertMissingCommas(normalized)\n normalized = quoteUnquotedStringValues(normalized)\n return normalized\n}\n\nexport function buildArgsFromKeyValuePairs(args: string[]): string {\n const obj: Record<string, unknown> = {}\n for (const pair of args) {\n const index = pair.indexOf('=')\n if (index === -1) {\n throw new Error(`无效的参数格式 \"${pair}\"。请使用 key=value,或 JSON / -f 文件。`)\n }\n const key = pair.substring(0, index).trim()\n let val = cleanJsonString(pair.substring(index + 1).trim())\n\n try {\n obj[key] = JSON.parse(val)\n } catch {\n obj[key] = val\n }\n }\n return JSON.stringify(obj)\n}\n\n/**\n * 将用户输入的 JSON / JS 对象字面量解析并规范化为标准 JSON 字符串。\n *\n * 解析顺序:\n * 1. 去除首尾空白及 shell 单引号包裹\n * 2. 使用 JSON5 解析(支持尾随逗号、未加引号的 key 等)\n * 3. 若失败,尝试修复 shell 损坏(缺逗号、未加引号的字符串值)后重试\n *\n * @param raw - 原始参数字符串(可能已被 expandFileRefs 展开 @file 占位符)\n * @returns 规范化后的 JSON 字符串,可直接传给 MCP 工具\n *\n * @example\n * // 标准 JSON\n * parseArgsJson('{\"title\":\"标题\",\"content\":\"正文\"}')\n * // => '{\"title\":\"标题\",\"content\":\"正文\"}'\n *\n * @example\n * // shell 损坏:花括号展开后丢失逗号、值未加引号\n * parseArgsJson('{title:TinyVue Icon,content:\"hello\"}')\n * // => '{\"title\":\"TinyVue Icon\",\"content\":\"hello\"}'\n *\n * @example\n * // bash 单引号包裹(外层引号会被 cleanJsonString 剥除)\n * parseArgsJson('\\'{\"title\":\"标题\"}\\'')\n * // => '{\"title\":\"标题\"}'\n */\nexport function parseArgsJson(raw: string): string {\n const trimmed = cleanJsonString(raw)\n try {\n return JSON.stringify(JSON5.parse(trimmed))\n } catch (firstError) {\n const repaired = normalizeShellDamagedJson(trimmed)\n try {\n return JSON.stringify(JSON5.parse(repaired))\n } catch {\n const hint =\n '提示:bash 中 JSON 必须用单引号包裹,例如 \\'{\"title\":\"标题\",\"content\":\"@base64file:./article.md\"}\\';' +\n '或使用 key=value:title=标题 content=@base64file:./article.md;' +\n '或使用 -f args.json。'\n const message = firstError instanceof Error ? firstError.message : String(firstError)\n throw new Error(`参数不是有效的 JSON 或 JS 对象: ${message}\\n${hint}`)\n }\n }\n}\n\n/**\n * `webmcp run` 命令的入口:从 CLI 参数或文件内容组装最终 JSON 参数字符串,兼容三种情况。\n *\n * 参数来源优先级:`-f/--file` 文件内容 > 命令行 `args`。\n * 命令行支持三种格式(自动识别):\n * - JSON 对象:`{\"title\":\"标题\"}`\n * - shell 拆散的 JSON 片段:`title:\"标题\" \"content\":\"正文\"`(bash 花括号展开后)\n * - key=value:`title=标题 content=@base64file:./article.md`\n *\n * 组装后会调用 expandFileRefs 展开 `@file` / `@base64file` 占位符,再经 parseArgsJson 规范化。\n *\n * @param args - commander 解析后的剩余参数数组\n * @param fileContent - `-f` 指定文件的文本内容;未指定时为 undefined\n * @param baseDir - 解析 `@file` 相对路径的基准目录(`-f` 时为文件所在目录,否则为 cwd)\n * @returns 规范化后的 JSON 字符串\n *\n * @example\n * // CLI: webmcp run publish-article '{\"title\":\"标题\",\"content\":\"@base64file:./article.md\"}'\n * prepareRunArgsJson(['{\"title\":\"标题\",\"content\":\"@base64file:./article.md\"}'], undefined, process.cwd())\n *\n * @example\n * // CLI: webmcp run publish-article title=标题 content=@base64file:./article.md\n * prepareRunArgsJson(['title=标题', 'content=@base64file:./article.md'], undefined, process.cwd())\n *\n * @example\n * // CLI: webmcp run publish-article -f args.json\n * prepareRunArgsJson([], readFileSync('args.json', 'utf-8'), dirname('args.json'))\n */\nexport function prepareRunArgsJson(args: string[], fileContent: string | undefined, baseDir: string): string {\n if (fileContent !== undefined) {\n const trimmed = fileContent.trim()\n if (!trimmed) {\n throw new Error('通过 -f/--file 指定的参数文件内容不能为空')\n }\n const expanded = expandFileRefs(trimmed, baseDir)\n return parseArgsJson(expanded)\n }\n\n if (args.length === 0) {\n // 无参数工具(如 get_article_info)允许省略 args,默认空对象\n return '{}'\n }\n\n const joined = joinShellArgs(args)\n let raw = ''\n if (joined.startsWith('{') || looksLikeObjectBody(joined)) {\n raw = joined\n } else if (args.every((arg) => arg.includes('='))) {\n raw = buildArgsFromKeyValuePairs(args)\n } else {\n raw = joined\n }\n\n if (!raw.trim()) {\n throw new Error('未提供有效参数')\n }\n\n const expanded = expandFileRefs(raw, baseDir)\n return parseArgsJson(expanded)\n}\n","import { connectBrowser, getTargetPage, getPageTargetId, injectIntoPage } from '../browser'\n\nexport async function stateCommand({ tabid }: { tabid?: string }) {\n const browser = await connectBrowser()\n try {\n const page = await getTargetPage(browser, tabid)\n\n // 1. 尚未注入时注入一次,确保手动打开的页面也能使用工具\n await injectIntoPage(page)\n\n // 2. 在页面上下文中获取导航元数据和已注册的工具列表\n // 不获取 DOM content(由调用方按需通过 browserState 拉取)\n const state = await page.evaluate(async () => {\n const url = document.URL\n const title = document.title\n\n const mcp = (document as any).modelContext || (navigator as any).modelContext\n let webmcpTools: Array<{ name: string; description?: string }> = []\n\n // polyfill 暴露的是 getTools(不是 MCP SDK 的 listTools)\n // 只回传可结构化克隆的字段,避免工具对象上的函数导致 page.evaluate 序列化失败\n if (mcp && typeof mcp.getTools === 'function') {\n try {\n const toolsResult = await mcp.getTools()\n const list = (toolsResult?.tools || toolsResult || []) as Array<{ name?: string; description?: string }>\n webmcpTools = list\n .filter((t) => t && typeof t.name === 'string')\n .map((t) => ({\n name: t.name as string,\n description: typeof t.description === 'string' ? t.description.slice(0, 200) : undefined,\n }))\n } catch {\n webmcpTools = []\n }\n }\n\n return { url, title, webmcpTools }\n })\n\n const activeTabid = await getPageTargetId(page).catch(() => null)\n\n // 3. 获取所有标签页信息(排除 devtools:// 内部页面)\n const pages = await browser.pages()\n const tabs = await Promise.all(\n pages.map(async (p) => {\n const pUrl = p.url()\n if (pUrl.startsWith('devtools://')) return null\n\n const pTitle = await Promise.race([\n p.title().catch(() => 'Unknown'),\n new Promise<string>((resolve) => setTimeout(() => resolve('Unknown'), 500))\n ])\n\n return {\n // 使用真实的 Chrome target ID,而非数组下标\n tabid: await getPageTargetId(p).catch(() => pUrl),\n title: pTitle,\n url: pUrl\n }\n })\n )\n\n return {\n ...state,\n activeTabid,\n tabs: tabs.filter(Boolean)\n }\n } finally {\n await browser.disconnect()\n }\n}\n","import { connectBrowser, getTargetPage, injectIntoPage } from '../browser'\n\nexport async function runCommand({\n toolName,\n argsJson,\n tabid\n}: {\n toolName: string\n argsJson: string\n tabid?: string\n}) {\n const browser = await connectBrowser()\n try {\n const page = await getTargetPage(browser, tabid)\n const urlBefore = page.url()\n\n // 仅在尚未注入时注入一次,保留 page-agent-tool 的 refMap\n await injectIntoPage(page)\n\n // argsJson 已在 bin.ts 中完成 @base64file 展开与 JSON 校验\n const cleanedArgs = argsJson.trim()\n\n let result: any\n try {\n result = await page.evaluate(async (name, inputString) => {\n // @ts-expect-error WebMCP APIs are experimental and not yet in DOM types\n const mcp = document.modelContext || document.modelContext || document.modelContext\n\n if (!mcp || typeof mcp.executeTool !== 'function') {\n throw new Error('当前页面没有注入 WebMCP 环境 (document.modelContext 未找到)')\n }\n\n // executeTool 的第二个参数必须是 JSON 字符串\n const tools = await mcp.getTools();\n const toolObj = tools.find((t: any) => t.name === name);\n if (!toolObj) throw new Error(`Tool ${name} not found`);\n let res = await mcp.executeTool(toolObj, inputString)\n\n // executeTool 的返回值可能是普通对象,也可能是 JSON 字符串\n if (typeof res === 'string') {\n try {\n res = JSON.parse(res)\n } catch {\n // 保留原始字符串\n }\n }\n\n if (res === undefined || res === null) {\n throw new Error('工具 execute 未返回结果,请检查工具实现是否缺少 return')\n }\n\n if (typeof res === 'object' && (res as { success?: boolean }).success === false) {\n const failed = res as { error?: string; message?: string }\n throw new Error(failed.error || failed.message || '工具执行失败')\n }\n\n return res\n }, toolName, cleanedArgs)\n } catch (evalError: unknown) {\n const errMsg = evalError instanceof Error ? evalError.message : String(evalError)\n\n // 识别\"执行上下文已销毁\"错误:这通常是工具执行期间页面发生了正常导航(如发布后跳转)\n // 此时工具实际上已经成功执行,跳转本身就是成功的副作用,不应报错\n const isContextDestroyed =\n errMsg.includes('context was destroyed') ||\n errMsg.includes('Execution context was destroyed') ||\n errMsg.includes('Cannot read properties of null') && errMsg.includes('context')\n\n if (isContextDestroyed) {\n // 等待导航稳定,然后读取新页面 URL\n await new Promise(resolve => setTimeout(resolve, 800))\n let newUrl = ''\n try {\n // 重新读取页面(导航后 JS 上下文虽被销毁,但 page 实例本身的 url() 依然是最新的)\n newUrl = page.url()\n } catch { /* 忽略 */ }\n\n // 如果 URL 已经发生变化,认为是正常导航触发的上下文销毁(工具执行成功)\n if (newUrl && newUrl !== urlBefore) {\n return {\n success: true,\n message: `工具 ${toolName} 执行完成,页面已导航至 ${newUrl}`,\n navigatedTo: newUrl\n }\n }\n // URL 未变化,可能是真正的错误,重新抛出\n }\n\n throw evalError\n }\n\n return result\n } finally {\n await browser.disconnect()\n }\n}\n","import clipboard from 'clipboardy'\n\n/**\n * 将文本设置到系统剪贴板\n * 使用 clipboardy 包,跨平台统一接口,无需手动处理各系统命令\n */\nexport async function setClipboard(content: string): Promise<void> {\n try {\n await clipboard.write(content)\n } catch (error: any) {\n throw new Error(`设置剪贴板失败: ${error.message}`)\n }\n}\n","import {\n connectBrowser,\n getTargetPage,\n injectIntoPage,\n getPageTargetId,\n findPageTargetByTabId,\n activateTabById,\n setLastActiveTabId\n} from '../browser'\n\nfunction normalizeUrl(url: string): string {\n if (!url.startsWith('http://') && !url.startsWith('https://')) {\n return 'https://' + url\n }\n return url\n}\n\nexport async function tabsOpenCommand(url: string) {\n const browser = await connectBrowser()\n try {\n const page = await browser.newPage()\n url = normalizeUrl(url)\n\n await page.goto(url, { waitUntil: 'domcontentloaded' })\n await injectIntoPage(page)\n await new Promise((resolve) => setTimeout(resolve, 500))\n\n let tabid: string | undefined\n try {\n tabid = await getPageTargetId(page)\n await activateTabById(browser, tabid)\n setLastActiveTabId(tabid)\n } catch (e) {\n console.warn('Best-effort tab activation failed:', e)\n }\n\n return {\n success: true,\n tabid,\n url: page.url(),\n title: await page.title().catch(() => '')\n }\n } finally {\n await browser.disconnect()\n }\n}\n\nexport async function tabsCloseCommand(tabid: string) {\n const browser = await connectBrowser()\n try {\n const target = findPageTargetByTabId(browser, tabid)\n if (!target) {\n throw new Error(`Tab with targetId \"${tabid}\" not found.`)\n }\n\n const page = await target.page()\n if (!page) {\n throw new Error(`Tab with targetId \"${tabid}\" not found.`)\n }\n\n const closedTabid = await getPageTargetId(page).catch(() => tabid)\n await page.close()\n\n return {\n success: true,\n tabid: closedTabid\n }\n } finally {\n await browser.disconnect()\n }\n}\n\nexport async function tabsSwitchCommand(tabid: string) {\n const browser = await connectBrowser()\n try {\n await activateTabById(browser, tabid)\n const page = await getTargetPage(browser, tabid)\n\n const realTabid = await getPageTargetId(page)\n setLastActiveTabId(realTabid)\n\n return {\n success: true,\n tabid: realTabid,\n url: page.url(),\n title: await page.title()\n }\n } finally {\n await browser.disconnect()\n }\n}\n\nexport async function tabsBackCommand(tabid?: string) {\n const browser = await connectBrowser()\n try {\n const page = await getTargetPage(browser, tabid)\n const response = await page.goBack()\n\n if (!response) {\n return {\n success: false,\n error: '无法后退:已在历史记录起点',\n tabid: await getPageTargetId(page).catch(() => tabid),\n url: page.url(),\n title: await page.title()\n }\n }\n\n await injectIntoPage(page)\n\n return {\n success: true,\n tabid: await getPageTargetId(page),\n url: page.url(),\n title: await page.title()\n }\n } finally {\n await browser.disconnect()\n }\n}\n\nexport async function tabsForwardCommand(tabid?: string) {\n const browser = await connectBrowser()\n try {\n const page = await getTargetPage(browser, tabid)\n const response = await page.goForward()\n\n if (!response) {\n return {\n success: false,\n error: '无法前进:已在历史记录末尾',\n tabid: await getPageTargetId(page).catch(() => tabid),\n url: page.url(),\n title: await page.title()\n }\n }\n\n await injectIntoPage(page)\n\n return {\n success: true,\n tabid: await getPageTargetId(page),\n url: page.url(),\n title: await page.title()\n }\n } finally {\n await browser.disconnect()\n }\n}\n"],"mappings":"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","names":["path","os","fs","resolve","http","puppeteer","pc","import_fs","import_path","import_url","tabs","resolve","path","os","fs","path","fs","resolve","import_node_fs","import_node_path","resolve","import_node_child_process","fs","import_node_fs","import_node_path","import_node_os","path","os","resolve","WsClient","timer","killProcessTree","WS_PORT","path","fs","import_meta","import_node_child_process","import_node_fs","import_node_path","import_node_os","os","CdpBrowserAdapter","WxtBrowserAdapter","ensureBridgeDaemon","import_fs","import_path","import_os","import_picocolors","JSON5","expanded","tabs","resolve","resolve","clipboard","resolve","path","fs","os","pc","startMcpServer","runDaemonProcess","stopBridgeDaemon","wsPort","resolveOrCreateAuthToken","ensureBridgeDaemon","token","WxtBrowserAdapter","handleAgentCommand","handleSkillsCommand"]}