首页
/ Cline Debug Harness:以 HTTP API 驱动 VSCode 扩展调试与 UI 自动化的实战指南

Cline Debug Harness:以 HTTP API 驱动 VSCode 扩展调试与 UI 自动化的实战指南

2026-09-06 14:26:48作者:郜逊炳

本文基于 Cline 仓库中 VSCode 扩展的 Debug Harness(apps/vscode/src/dev/debug-harness/)展开。它是 Cline 团队为 VSCode 扩展自研的"HTTP 控制的调试服务器":通过一个常驻的 HTTP API,你可以用 curl 对扩展宿主进程(Node.js)打断点、对 Webview 打断点、用 Playwright 做 UI 自动化、拦截 openExternal() 实现的浏览器 URL 捕获,从而完成 Cline OAuth / MCP OAuth / Provider OAuth 等登录流程的端到端测试。读完后,你将掌握完整的启动方式、全部 API 方法、OAuth 测试的三条流程,以及断点 sourcemap 解析、数据隔离等底层实现原理。

一、Debug Harness 是什么

Debug Harness 是一个 HTTP 控制的调试服务器,专为 Cline VSCode 扩展设计,提供以下五类编程化能力:

  • 扩展宿主调试(Node.js):通过 CDP 对扩展宿主进程打断点、求值(evaluate)、单步、暂停/恢复;
  • Webview 调试(Chrome):通过 CDP 对 Webview 打断点、求值;
  • UI 自动化:基于 Playwright 的点击、输入、截图、打开侧边栏;
  • Sourcemap 解析:按"原始源码文件 + 行号"设置断点(自动反解到打包后的位置);
  • 数据隔离:被调试方(debugee)使用独立的 ~/.cline2 配置目录,避免干扰调试方;
  • OAuth 测试:浏览器 URL 捕获、token 检查、回调模拟。

它的核心设计意图是可以被 Agent 循环驱动——所有交互都是一条 curl 命令,天然适合脚本化与自动化测试。

整个实现集中在 server.ts(约 1600 行),配套的 MCP OAuth 测试服务器位于 mcp-oauth-test-server/server.ts

二、快速开始

2.1 最小启动方式

# 终端 1:启动 debug harness 服务器
# 注意:必须用 node 运行,不能用 bun ——
# Playwright 的 _electron.launch() 在 bun 下会超时
node src/dev/debug-harness/server.ts --auto-launch --skip-build

# 终端 2:用 curl 交互
curl localhost:19229/api -d '{"method":"status"}'
curl localhost:19229/api -d '{"method":"ui.open_sidebar"}'
curl localhost:19229/api -d '{"method":"ui.screenshot"}'

"必须用 node 而非 bun" 这条约束在 server.ts 的文件头注释中有明确解释:Electron 进程在 bun 下虽然能启动,但 _electron.launch() 永远无法附着成功而超时;同样的启动在 node 下正常。另外文件头注明 Node >= 22.6 可直接以 type stripping 方式运行该 .ts 文件。

2.2 服务器命令行参数

node src/dev/debug-harness/server.ts [options]

Options:
  --skip-build        跳过扩展/webview 构建(使用现有 dist/)
  --auto-launch       启动时自动拉起 VSCode
  --workspace PATH    要打开的工作区目录(默认 /tmp/cline-debug-workspace)
  --port PORT         服务器端口(默认 19229)
  --cline-dir PATH    覆盖被调试方的 CLINE_DIR(默认 ~/.cline2)

源码中实际还实现了文档未列出的两个选项,从 server.ts 的配置常量区可以确认:

  • --launch-timeout MS:Playwright _electron.launch 的超时时间,默认 120000ms。文件头注释解释:冷启动(首次 profile 初始化、慢速 CI/VM)可能超过旧的 60s 默认值,因此放宽并允许覆盖;
  • --no-browser-capture:让 openExternal() 打开真实浏览器窗口(用于交互式 OAuth 测试),默认是关闭捕获的。

另外环境变量 VSCODE_TEST_VERSION 可以指定被下载的 VSCode 版本,默认 1.103.0——源码注释指出捆绑的 Playwright 版本无法驱动最新 "stable" 的 Electron,因此默认钉住该版本,需要时可设为 "stable" 或具体版本号。

2.3 首次完整构建 + 启动

# 会构建 protos、扩展(不压缩 + sourcemap)、webview(不压缩 + sourcemap),
# 下载 VSCode、启动它,并通过 CDP 连上扩展宿主
node src/dev/debug-harness/server.ts --auto-launch

三、数据隔离:~/.cline2 的原理

被调试方默认以 CLINE_DIR=~/.cline2 运行,与你的真实 ~/.cline 完全分开。这防止了三类问题:

  • 被调试方登出时把调试方一起登出;
  • 任务历史、API key、设置在两个实例之间互相泄漏;
  • 共享 secrets.json 导致的状态损坏。

隔离目录会在 status()launch() 的响应中报告:

curl localhost:19229/api -d '{"method":"status"}'
# → { "clineDir": "/Users/you/.cline2", ... }

想换目录时用 --cline-dir /tmp/test-cline-dir

源码级原理

server 侧的隔离在 server.ts 中定义:DEFAULT_CLINE_DIR 硬编码为 ~/.cline2,并在 _electron.launch 时通过 CLINE_DIR 环境变量注入被调试方环境(CLINE_DIR_ARG 可覆盖)。

被调试方一侧的读取链路则在 storage-context.ts 中:resolveDataDirFromEnv()CLINE_DATA_DIR(去空白)> CLINE_DIR + "/data" > ~/.cline/data 的优先级解析数据目录;随后 createStorageContext() 基于该目录生成所有存储文件的绝对路径——globalState.jsonsecrets.json(文件权限 0o600,注释明确说明是为了保护 API key)、以及按工作区路径哈希隔离的 workspaces/<hash>/workspaceState.json。由于所有读写都收敛到这一个解析器,只要 harness 注入了 CLINE_DIR,被调试方的全部状态就落在独立目录中。

四、浏览器捕获与 OAuth 测试

4.1 URL 捕获机制

Debug Harness 启动 VSCode 时设置 CLINE_CAPTURE_BROWSER=1,这会拦截被调试方所有的 openExternal() 调用。URL 不再打开真实浏览器,而是被三重处理:

  1. 落盘:追加到 $CLINE_DIR/data/debug-captured-urls.jsonl
  2. 实时上报:POST 到 debug harness 服务器的 /captured-url 端点;
  3. 可查询:通过 oauth.captured_urls API 方法读取。

这段逻辑的实现就在 env.tsopenExternal() 中:当 CLINE_CAPTURE_BROWSER"1""true" 时走 captureBrowserUrl() 分支——先把 {timestamp, url} 以 JSONL 格式追加到 $CLINE_DIR/data/debug-captured-urls.jsonlCLINE_DIR 未设时回退到 ~/.cline),再若检测到 CLINE_DEBUG_HARNESS_PORT 环境变量,则以 fire-and-forget 方式 POST 到 127.0.0.1:<port>/captured-url。注意这里捕获是"只记不改":非捕获模式下 openExternal 走 host bridge RPC,失败时回退到 open npm 包(JetBrains 等宿主的路径)。

4.2 OAuth API 一览

方法 参数 说明
oauth.captured_urls {clear?} 获取被调试方试图打开的 URL(由浏览器拦截捕获)
oauth.read_stored_token 读取被调试方 secrets.json 中的 auth token 是否存在
oauth.simulate_callback {path, code?, state?, provider?, token?} 构造 vscode:// 回调 URI(用于 MCP/Provider OAuth)
oauth.read_captured_urls_file 读取磁盘上的捕获 URL JSONL 文件

4.3 测试 Cline OAuth(登录流程)

Cline OAuth 流程使用 SDK 的本地回调服务器。用户点击 "Login" 后,SDK 依次:

  1. 在随机端口启动本地 HTTP 服务器;
  2. 调用 openExternal(authorizationUrl)——被我们捕获;
  3. 用户在浏览器中认证——这一步需要我们来模拟;
  4. Provider 带着 ?code=... 重定向回本地回调服务器;
  5. SDK 捕获 code 并交换为 token。

完整测试步骤:

# 1. 在被调试方侧边栏点击 "Login"
curl localhost:19229/api -d '{"method":"ui.open_sidebar"}'
# 先关闭弹窗(见下文 "Dismissing Promotional Overlays")
curl localhost:19229/api -d '{"method":"ui.locator","params":{"text":"Login to Cline","frame":"sidebar","action":"click"}}'

# 2. 检查捕获的 URL,找到 authorization URL
curl localhost:19229/api -d '{"method":"oauth.captured_urls"}'
# → { "urls": [{ "url": "https://api.cline.bot/auth/authorize?callback_url=http://127.0.0.1:PORT/..." }] }

# 3. authorization URL 中的 callback_url 指向 SDK 本地服务器。
#    要完成流程,二选一:
#    a. 在真实浏览器中打开 authorization URL(会自动重定向回 SDK 本地回调服务器)
#    b. 提取 callback_url,带 code 参数直接 curl 模拟重定向:
curl "http://127.0.0.1:PORT/auth/callback?code=TEST_CODE" 2>/dev/null

# 4. 验证 token 已存储
curl localhost:19229/api -d '{"method":"oauth.read_stored_token"}'
# → { "found": true, "hasAccountId": true, "keys": ["cline:clineAccountId"] }

# 5. 截图验证 UI 显示已认证状态
curl localhost:19229/api -d '{"method":"ui.screenshot"}'

注意文档同时提醒:伪造 code 会导致 token 交换失败(provider 不认识该 code),你需要真实授权码(在浏览器完成流程获得)或者 mock 掉 token 交换端点。

4.4 测试 MCP OAuth

需要 OAuth 的 MCP server 走的是另一条流程:浏览器重定向到由扩展 URI handler 处理的 vscode:// URI。授权方(如 Linear)决定 code;端到端测试时搭配本地 MCP OAuth 测试服务器(bun run dev:mcp-oauth-test-server,详见 mcp-oauth-test-server/README.md)——它是一个零依赖(仅 Node http)服务器,同时扮演 OAuth 2.0 授权服务器(RFC 8414 / RFC 7591 DCR / RFC 7636 PKCE)和 MCP StreamableHTTP 资源服务器两个角色,能签发真实的 code/token,还支持 --slow-authorize--auto-deny 等选项用于复现 state 过期、拒绝授权等失败模式。

# 1. 触发 MCP OAuth(例如点击某个 server 的 "Authenticate" 按钮)
# 2. 在捕获的 URL 中找 authorization URL
curl localhost:19229/api -d '{"method":"oauth.captured_urls"}'
#    authorize URL 含 redirect_uri=vscode://saoudrizwan.claude-dev/mcp-auth/callback/HASH

# 3. 从授权服务器获取真实授权码:跟随捕获的 authorize URL
#    (测试服务器自动批准并 302 到 vscode:// 回调,带 ?code=...&state=...):
curl -s -D - -o /dev/null "<captured-authorize-url>" | grep -i '^location:'

# 4. 把 vscode:// 回调投递给扩展。VSCode 只会把真实 vscode:// URI
#    路由给已注册的 handler,而 harness 无法合成它——且扩展宿主是 ESM,
#    无法 require() handler 模块。因此调用 __clineHandleUri 钩子(见下):
curl localhost:19229/api -d '{
  "method": "ext.evaluate",
  "params": {
    "awaitPromise": true,
    "expression": "globalThis.__clineHandleUri(\"vscode://saoudrizwan.claude-dev/mcp-auth/callback/HASH?code=REAL_CODE&state=SAVED_STATE\")"
  }
}'

# 5. 验证 token 已存储
curl localhost:19229/api -d '{"method":"oauth.read_stored_token"}'

globalThis.__clineHandleUri(url) — 仅限调试的 URI 投递钩子。 它在扩展激活期间注册于 extension.ts仅当 CLINE_CAPTURE_BROWSER 设置时才注册(harness 总会设置它),因此绝不会进入生产构建。它调用与 VSCode 真实 registerUriHandler 相同的 SharedUriHandler.handleUri(url),返回 Promise<boolean>(配合 awaitPromise: true 使用)。可用于任何 vscode:// 回调——MCP、OpenRouter、/auth 等。oauth.simulate_callback 只负责构造 URI,而该钩子负责真正投递它。

源码验证:extension.ts 中该钩子的注册条件正是 process.env.CLINE_CAPTURE_BROWSER === "1" || "true",且实现就是一行 SharedUriHandler.handleUri(url) 的委托——与真实 handler(同文件 L175 的 vscode.window.registerUriHandler)调用的是同一个方法。

4.5 测试 Provider OAuth(OpenRouter 等)

# 1. 触发 provider 登录(例如 "Get OpenRouter API Key" 按钮)
# 2. 检查捕获的 URL
curl localhost:19229/api -d '{"method":"oauth.captured_urls"}'
# 3. 模拟重定向回调
curl localhost:19229/api -d '{
  "method": "oauth.simulate_callback",
  "params": {"path": "/openrouter", "code": "TEST_CODE"}
}'

五、实战技巧

5.1 关闭促销弹窗

全新启动时可能出现一个或多个全屏促销弹窗(如 "Introducing Cline Kanban"),会挡住侧边栏的全部交互,让截图毫无用处。必须在打开侧边栏后立即、且在任何其他交互之前关闭它们:

# 先打开侧边栏
curl localhost:19229/api -d '{"method":"ui.open_sidebar"}'
# 关闭所有弹窗(多个弹窗可能需要执行两次)
curl localhost:19229/api -d '{"method":"web.evaluate","params":{"expression":"document.querySelectorAll(\".sr-only\").forEach(el => el.parentElement?.click())"}}'

这段表达式遍历所有 sr-only(屏幕阅读器专用、视觉隐藏)元素并点击其父级——即每个弹窗的关闭按钮所在容器。

5.2 用命令在视图间导航

与其在侧边栏头部找小图标点击,不如通过命令面板执行 VSCode 命令。这些命令注册在 registry.ts 中:

命令 打开的视图
cline.accountButtonClicked 账户 / 登录视图
cline.historyButtonClicked 任务历史视图
cline.settingsButtonClicked 设置视图
cline.mcpButtonClicked MCP 服务器视图
cline.plusButtonClicked 新任务(聊天视图)
cline.worktreesButtonClicked Worktrees 视图
curl localhost:19229/api -d '{"method":"ui.command_palette","params":{"command":"cline.accountButtonClicked"}}'
curl localhost:19229/api -d '{"method":"ui.command_palette","params":{"command":"cline.historyButtonClicked"}}'
curl localhost:19229/api -d '{"method":"ui.command_palette","params":{"command":"cline.settingsButtonClicked"}}'
curl localhost:19229/api -d '{"method":"ui.command_palette","params":{"command":"cline.mcpButtonClicked"}}'
curl localhost:19229/api -d '{"method":"ui.command_palette","params":{"command":"cline.plusButtonClicked"}}'

5.3 典型会话工作流

# 1. 启动(若没用 --auto-launch)
curl localhost:19229/api -d '{"method":"launch","params":{"skipBuild":true}}'

# 2. 打开侧边栏并关闭弹窗
curl localhost:19229/api -d '{"method":"ui.open_sidebar"}'
curl localhost:19229/api -d '{"method":"web.evaluate","params":{"expression":"document.querySelectorAll(\".sr-only\").forEach(el => el.parentElement?.click())"}}'

# 3. 检查状态(确认 CLINE_DIR、browser capture 等)
curl localhost:19229/api -d '{"method":"status"}'

# 4. 导航到目标视图
curl localhost:19229/api -d '{"method":"ui.command_palette","params":{"command":"cline.accountButtonClicked"}}'

# 5. 交互并验证
curl localhost:19229/api -d '{"method":"ui.screenshot"}'

# 6. OAuth 流程时检查捕获的 URL
curl localhost:19229/api -d '{"method":"oauth.captured_urls"}'

# 7. 结束后关闭
curl localhost:19229/api -d '{"method":"shutdown"}'

六、完整 API 参考

所有命令均为 POST /api,JSON body 为 {"method": "...", "params": {...}}。响应格式:成功时 {"result": {...}},失败时 {"error": "..."}

便捷端点:

  • GET /health — 返回 {"status": "ok"}
  • GET /status — 完整 harness 状态
  • POST /captured-url — 内部端点:接收被调试方上报的捕获 URL(对应 env.ts 中的 fire-and-forget POST)

6.1 生命周期

方法 参数 说明
launch {workspace?, skipBuild?} 构建 + 启动 VSCode
shutdown 关闭 VSCode 及 CDP 连接
status 所有组件的当前状态
connect_webview 连接 Webview 的 CDP(侧边栏打开后调用)

6.2 扩展宿主调试(Node.js)

方法 参数 说明
ext.set_breakpoint {file, line, column?, condition?} 按源码文件设置断点(经 sourcemap 解析)
ext.set_breakpoint_raw {url?, urlRegex?, scriptId?, lineNumber, columnNumber?, condition?} 用原始 CDP 参数设置断点
ext.remove_breakpoint {breakpointId} 移除断点
ext.evaluate {expression, callFrameId?} 求值表达式(在断点处或全局)
ext.pause 暂停执行
ext.resume 恢复执行
ext.step_over 单步跳过
ext.step_into 单步进入
ext.step_out 单步跳出
ext.call_stack 获取调用栈(暂停时)
ext.scripts {filter?} 列出已加载脚本
ext.source_files 从 sourcemap 列出源码文件
ext.get_properties {objectId} 获取对象属性
ext.get_script_source {scriptId} 获取脚本源码文本

6.3 Webview 调试(Chrome)

侧边栏打开后需先调用 connect_webview(仅断点/单步需要)。

方法 参数 说明
web.set_breakpoint {url, line, column?, condition?} 按 URL 模式设置断点
web.remove_breakpoint {breakpointId} 移除断点
web.evaluate {expression, callFrameId?} 在侧边栏(Playwright)或断点处(CDP)求值
web.post_message {message} 通过暴露的 vsCodeApi 向扩展宿主发 postMessage
web.pause 暂停
web.resume 恢复
web.step_over/into/out 单步

6.4 UI 自动化(Playwright)

方法 参数 说明
ui.screenshot {fullPage?} 截图 → 返回 {path}(用 read_file 读该路径,不要 open 文件)
ui.sidebar_screenshot 聚焦侧边栏的截图 → 返回 {path}
ui.click {selector, frame?, delay?} 点击元素(Webview 用 frame: "sidebar"
ui.fill {selector, text, frame?} 填充输入框
ui.press {key} 按键(如 "Enter"、"Meta+Shift+p")
ui.type {text, delay?} 输入文本
ui.open_sidebar 打开 Cline 侧边栏
ui.frames 列出所有 frame
ui.wait_for_selector {selector, frame?, timeout?} 等待元素
ui.command_palette {command} 打开命令面板并执行命令
ui.get_text {selector, frame?} 获取元素文本
ui.locator {role?, name?, testId?, text?, frame?, action?, value?} 富 Playwright 定位器(侧边栏自动带 frame 刷新重试)
ui.react_input {text, selector?, clear?, submit?} 通过 execCommand('insertText') 设置 React 受控 textarea 的值
ui.send_message {text, images?, files?, responseType?} 绕过 textarea 直接发送聊天消息(走 gRPC postMessage)

6.5 OAuth 与浏览器捕获

方法 参数 说明
oauth.captured_urls {clear?} 获取被调试方试图在浏览器打开的 URL
oauth.read_stored_token 检查被调试方 secrets.json 中的 token
oauth.simulate_callback {path, code?, state?, provider?, token?} 构造 MCP/Provider OAuth 的 vscode:// 回调 URI(不投递)
oauth.read_captured_urls_file 读取磁盘上的捕获 URL JSONL 日志

要真正投递 vscode:// 回调,需通过 ext.evaluate(带 awaitPromise: true)调用调试钩子:globalThis.__clineHandleUri("vscode://saoudrizwan.claude-dev/...?code=...&state=...")。它调用与 VSCode 真实 URI handler 相同的 SharedUriHandler.handleUri,且仅在设置 CLINE_CAPTURE_BROWSER 时注册(生产环境永不注册)。

6.6 组合方法

方法 参数 说明
wait_for_pause {timeout?} 阻塞直到任一被调试方命中断点

七、示例工作流

7.1 设置断点并观察执行

curl localhost:19229/api -d '{
  "method": "ext.set_breakpoint",
  "params": {"file": "src/extension.ts", "line": 25}
}'
curl localhost:19229/api -d '{"method":"ui.open_sidebar"}'
curl localhost:19229/api -d '{"method":"wait_for_pause","params":{"timeout":10000}}'
curl localhost:19229/api -d '{"method":"ext.call_stack"}'
curl localhost:19229/api -d '{"method":"ext.resume"}'

7.2 OAuth 登录流程测试

# 关闭弹窗后点击 Login
curl localhost:19229/api -d '{"method":"ui.open_sidebar"}'
curl localhost:19229/api -d '{"method":"web.evaluate","params":{"expression":"document.querySelectorAll(\".sr-only\").forEach(el => el.parentElement?.click())"}}'
curl localhost:19229/api -d '{"method":"ui.locator","params":{"text":"Login to Cline","frame":"sidebar","action":"click"}}'

# 查看捕获了什么 URL
curl localhost:19229/api -d '{"method":"oauth.captured_urls"}'

# URL 中含 callback_url=http://127.0.0.1:PORT/...
# 在真实浏览器中打开它完成认证,或模拟:
# (先从捕获的 URL 中提取端口)
curl "http://127.0.0.1:PORT/callback?code=real_or_test_code"

# 验证 token 已存储
curl localhost:19229/api -d '{"method":"oauth.read_stored_token"}'

7.3 导航到 Account 视图并检查认证状态

curl localhost:19229/api -d '{"method":"ui.command_palette","params":{"command":"cline.accountButtonClicked"}}'
curl localhost:19229/api -d '{"method":"ui.screenshot"}'

八、底层实现原理(How It Works)

harness 的完整数据流可拆为八步,均能在 server.ts 中找到对应实现:

  1. 构建:esbuild 打包 src/extension.tsdist/extension.js(不压缩、带 sourcemap);Vite 构建 webview-ui/webview-ui/build/(不压缩、内联 sourcemap)。不压缩 + sourcemap 是断点可用性的前提。

  2. 启动:用 @vscode/test-electron 下载 VSCode,再用 Playwright 的 _electron.launch()--inspect-extensions=9230(Node.js inspector 端口,源码中常量 EXT_INSPECT_PORT = 9230)和 --extensionDevelopmentPath(加载我们自己的扩展)启动。

  3. 数据隔离:在 debugee 环境注入 CLINE_DIR=~/.cline2。被调试方侧由 storage-context.tscreateStorageContext() 读取该变量,决定 globalState.jsonsecrets.json、任务历史、workspace 状态的存储位置。

  4. 浏览器捕获:在 debugee 环境注入 CLINE_CAPTURE_BROWSER=1CLINE_DEBUG_HARNESS_PORT=19229。当 env.tsopenExternal() 被调用时,检测到捕获模式就记录 URL 到 JSONL 文件并 POST 到 harness 服务器,而不打开真实浏览器——这是无头测试 OAuth 流程的关键。

  5. 扩展 CDP:通过 9230 端口的 WebSocket 连接扩展宿主的 V8 inspector,启用 DebuggerRuntime 域,跟踪 scriptParsed 事件与 paused/resumed 状态。

  6. Sourcemap 解析:按源码文件设置断点时,读取 dist/extension.js.map,用 VLQ 解码的 sourcemap 映射把"原始文件 + 行号"反解为"打包文件 + 行号"。server.ts 内置了一个自研的 VLQ 解码器(标准 64 字符 base64 变体 + 5 位 continuation 位解析),resolveSourceMapPosition() 先精确匹配 source 路径、再做后缀匹配。

  7. Webview CDP:侧边栏加载后为 Webview frame 创建 Playwright CDP 会话,启用调试命令;失败时回退到 frame.evaluate() 做表达式求值——所以即使 CDP 连不上,web.evaluate 依然可用。

  8. UI 自动化:Playwright 的 Page/Frame API 提供点击、填充、输入、截图、定位器查询等;侧边栏 Webview 作为 VSCode 窗口内的一个 Frame 访问。

九、注意事项与故障排查

9.1 注意事项

  • 数据隔离:debugee 默认使用 ~/.cline2。若要带真实数据测试,先复制:cp -r ~/.cline ~/.cline2。注意这样做会共享 secrets(API key、auth token)。
  • "Introducing Cline Kanban" 弹窗:全新启动时侧边栏可能出现全屏促销弹窗,阻塞所有交互并让截图失效。打开侧边栏后、做任何事之前立即关闭(命令见 5.1 节)。
  • 截图ui.screenshotui.sidebar_screenshot 将 PNG 保存到 /tmp/cline-debug/(可用 SCREENSHOT_DIR 环境变量配置,源码中默认为 os.tmpdir()/cline-debug),响应返回 {path}不要 open 该文件——macOS 上会弹出 Preview.app 遮住 VSCode 窗口,应使用 read_file 读取。
  • 真实 Provider 的 OAuth:浏览器捕获只拦截 debugee 试图打开的 URL。Cline OAuth 中 SDK 的本地回调服务器仍在运行、能接收重定向;Provider OAuth(OpenRouter、MCP)则需要模拟 vscode:// 回调 URI(见第四章)。
  • 伪造 code 的 Cline OAuth:用假 code 模拟回调时,SDK 的 token 交换会失败(provider 不认识该 code)。需要真实授权码或 mock token 交换端点。

9.2 故障排查

症状 原因与处置
"Inspector not available on port 9230" 扩展宿主尚未启动。等待更久,或确认扩展构建正确
"Sidebar frame not found" Cline 侧边栏未打开,先执行 ui.open_sidebar
"Webview CDP not connected" 侧边栏打开后调用 connect_webview;失败时 Webview 断点不可用,但 web.evaluate 仍可通过 Playwright 工作
Sourcemap 解析失败 先用 ext.source_files 查看 sourcemap 包含的路径,再用 ext.set_breakpoint_raw 配合 urlRegex 模式
截图目录 保存到 /tmp/cline-debug/(可经 SCREENSHOT_DIR 配置)
debugee 仍在用 ~/.cline 检查 status() 响应中是否出现 CLINE_DIR;缺失可能是 debugee 在 harness 设置环境变量之前就被启动了。Shutdown 后重新启动

十、小结与适用前提

Debug Harness 把"启动一个带 inspector 的 VSCode → 附着 CDP → 驱动 Playwright → 拦截外部浏览器调用"这一整套 VSCode 扩展调试链路收敛成了一个 19229 端口的 HTTP 服务,使断点调试、UI 断言与 OAuth 端到端测试都可以用纯 curl 序列表达,这也是它"专为 Agent 循环设计"的落地方式。使用前提:Node >= 22.6、以 node(而非 bun)运行、被调试方版本受 VSCODE_TEST_VERSION(默认 1.103.0)约束。仓库中相关入口文件:debug-harness/README.mddebug-harness/server.tsmcp-oauth-test-server/README.mdenv.tsstorage-context.tsextension.tsregistry.ts

登录后查看全文
热门项目推荐
相关项目推荐