
lynx-devtool
当处理 Lynx DevTool 或调试 Lynx 应用、页面或设备时使用,特别是当任务涉及客户端或会话、CDP 或 App 命令、DOM/CSS 检查、运行时或控制台日志、截图、堆快照、Page.reload 或 App.openPage、全局开关,或在 Android、iOS 或 Desktop 上检查 ReactLynx 组件树(`reactlynx tree`)、搜索组件(`reactlynx find`)、检查 props/state/hooks(`reactlynx component`)或修改 props/state/context(`reactlynx update-prop` / `update-state` / `update-context`)时。
当处理 Lynx DevTool 或调试 Lynx 应用、页面或设备时使用,特别是当任务涉及客户端或会话、CDP 或 App 命令、DOM/CSS 检查、运行时或控制台日志、截图、堆快照、Page.reload 或 App.openPage、全局开关,或在 Android、iOS 或 Desktop 上检查 ReactLynx 组件树(`reactlynx tree`)、搜索组件(`reactlynx find`)、检查 props/state/hooks(`reactlynx component`)或修改 props/state/context(`reactlynx update-prop` / `update-state` / `update-context`)时。
DevTool 技能
此技能允许您使用 Lynx DevTool CLI 与连接设备(Android、iOS、Desktop)上运行的 Lynx 应用进行交互。
使用方法
CLI 位于此技能目录下的 <path_to_the_skill>/scripts/index.mjs。您可以使用 node 运行它。
编程 API 位于 <path_to_the_skill>/scripts/connector.mjs。此入口重新导出 @lynx-js/devtool-connector、@lynx-js/devtool-connector/transport 和 @lynx-js/devtool-connector/streams 的所有内容,并提供与 CLI 默认值匹配的 createDefaultTransports() 和 createDefaultConnector() 辅助函数。
在技能目录中,使用:
node <path_to_the_skill>/scripts/index.mjs <command>
注意: 所有命令输出都是多行 JSON。您可以使用 jq 或 Node.js 处理数据。
作为库使用
如果您想直接从 JavaScript 驱动 Lynx DevTool 而不是通过 CLI 执行 shell 命令,请从 scripts/connector.mjs 导入。
import {
Connector,
createDefaultConnector,
} from "<path_to_the_skill>/scripts/connector.mjs";
const connector = createDefaultConnector();
const clients = await connector.listClients();
console.log(clients);
有关更完整的编程工作流,请参阅 库使用参考 和 编程调试示例。
如果您需要自定义传输,也可以手动构建连接器:
import {
AndroidTransport,
Connector,
DesktopTransport,
iOSTransport,
} from "<path_to_the_skill>/scripts/connector.mjs";
const connector = new Connector([
new AndroidTransport({ host: "127.0.0.1", port: 5037 }),
new DesktopTransport(),
new iOSTransport(),
]);
全局选项
-h, --help:显示命令帮助。
注意: 每个子命令都支持 --help 标志(例如 node <path_to_the_skill>/scripts/index.mjs cdp --help)。使用此标志查看所有可用参数及其描述。
客户端定位
接受 -c, --client <clientId> 的命令也接受 --client-name <name>。
使用 --client-name 通过包/应用标识符(AppProcessName、bundleId、bundleName 或 App)从 list-clients 中解析客户端,例如:
node <path_to_the_skill>/scripts/index.mjs cdp --client-name com.example.app -m DOM.getDocument
node <path_to_the_skill>/scripts/index.mjs list-sessions --client-name com.lynx.uiapp
如果多个客户端匹配该名称,请使用 list-clients 并通过 --client 传递确切的客户端 ID。
命令
1. 列出客户端
列出所有可用的 Lynx 客户端(启用了 DevTool 的应用)。
node <path_to_the_skill>/scripts/index.mjs list-clients
2. 列出会话
列出所有活动的调试会话。一个会话对应一个特定的 Lynx 视图或上下文。
node <path_to_the_skill>/scripts/index.mjs list-sessions
# 可选:按客户端 ID 过滤
node <path_to_the_skill>/scripts/index.mjs list-sessions --client <clientId>
3. 发送 CDP 命令
向特定会话发送 Chrome DevTools 协议(CDP)命令。
注意:Lynx 仅支持标准 CDP 命令的一部分。
LynxView 注意:当目标会话是 LynxView 时,您必须在发送 CDP 命令之前阅读 支持的 CDP 方法。
WebView 注意:当目标会话是 WebView(例如type: "web"或 HTTP/HTTPS URL)时,请使用标准 Chrome DevTools 协议文档了解 CDP 方法名称、参数和启用前提条件。本地的references/cdp页面侧重于 LynxView 支持和 Lynx 特定扩展,在 WebView 目标上可能返回method not found。
node <path_to_the_skill>/scripts/index.mjs cdp -m <method> [options] [params]
-m, --method <method>:CDP 方法名称(例如DOM.getDocument、Runtime.evaluate)。-c, --client <clientId>:(可选)客户端 ID。如果省略,则使用第一个可用客户端。--client-name <name>:(可选)从list-clients解析的包/应用名称。-s, --session <sessionId>:(可选)会话 ID。如果省略,则使用最新会话(具有最大会话 ID)。--thread <thread>:(可选)目标 VM 线程,background或main。默认为background。[params]:(可选)命令参数的 JSON 字符串。
当使用 --thread main 时,仅支持 Debugger.*、Runtime.*、HeapProfiler.* 和 Profiler.* 方法。
示例:
# 获取文档根节点
node <path_to_the_skill>/scripts/index.mjs cdp -m DOM.getDocument
# 评估 JavaScript
node <path_to_the_skill>/scripts/index.mjs cdp -m Runtime.evaluate '{"expression": "2 + 2"}'
# 在主线程 VM 上评估 JavaScript
node <path_to_the_skill>/scripts/index.mjs cdp --thread main -m Runtime.evaluate '{"expression": "2 + 2"}'
4. 发送 App 命令
发送应用级命令。
node <path_to_the_skill>/scripts/index.mjs app -m <method> [options] [params]
-m, --method <method>:App 方法名称(例如App.openPage)。-c, --client <clientId>:(可选)客户端 ID。--client-name <name>:(可选)从list-clients解析的包/应用名称。[params]:(可选)参数的 JSON 字符串。
您必须在发送 App 命令之前阅读 支持的 App 方法。
5. 打开 URL
在 Lynx 应用中打开特定 URL。
node <path_to_the_skill>/scripts/index.mjs open <url> [options]
<url>:要打开的 URL。-c, --client <clientId>:(可选)客户端 ID。
示例:
node <path_to_the_skill>/scripts/index.mjs open "lynx://example/page"
6. 检查
输出客户端/会话的检查器 URL。
node <path_to_the_skill>/scripts/index.mjs inspect [options]
-c, --client <clientId>:(可选)客户端 ID。-s, --session <sessionId>:(可选)会话 ID。--port <port>:(可选)守护进程端口。默认为21783。
7. 获取控制台
从设备捕获控制台日志。
node <path_to_the_skill>/scripts/index.mjs get-console [options]
-c, --client <clientId>:(可选)客户端 ID。-s, --session <sessionId>:(可选)会话 ID。--offset <number>:跳过 N 条消息。--limit <number>:限制消息数量。--include-stack-traces:包含非错误消息的堆栈跟踪。--level <levels>:过滤日志级别(例如error,warning)。--thread <thread...>:目标 VM 线程:background或main。如果省略,默认收集两个线程。
8. 获取源码
列出所有已解析的脚本。这对于查找脚本 ID 以用于其他命令(例如 Debugger.getScriptSource)非常有用。该命令自动获取所有当前加载的脚本。
node <path_to_the_skill>/scripts/index.mjs get-sources [options]
-c, --client <clientId>:(可选)客户端 ID。-s, --session <sessionId>:(可选)会话 ID。
9. 截图
截取当前页面的屏幕截图。
node <path_to_the_skill>/scripts/index.mjs take-screenshot [options]
-c, --client <clientId>:(可选)客户端 ID。-s, --session <sessionId>:(可选)会话 ID。--fullscreen:(可选)以fullscreen模式截图。如果未提供,默认为lynxview模式。-o, --output <path>:(可选)输出文件路径。
10. 获取堆快照
从当前 Lynx 会话捕获 QuickJS 堆快照并保存为 .heapsnapshot 文件。
node <path_to_the_skill>/scripts/index.mjs take-heap-snapshot [options]
-c, --client <clientId>:(可选)客户端 ID。-s, --session <sessionId>:(可选)会话 ID。--thread <thread>:(可选)目标 VM 线程,background或main。默认为background。-o, --output <path>:(可选)输出文件路径。默认为操作系统临时目录。
11. 全局开关
管理 DevTool 全局开关。
# 列出所有支持的键及其当前值
node <path_to_the_skill>/scripts/index.mjs global-switch list [options]
# 获取一个键
node <path_to_the_skill>/scripts/index.mjs global-switch get --key <globalKey> [options]
# 设置一个键
node <path_to_the_skill>/scripts/index.mjs global-switch set --key <globalKey> --status <on|off> [options]
-c, --client <clientId>:(可选)客户端 ID。
global-switch list 选项:
--fail-fast:在第一次键读取失败时中止。
global-switch get 选项:
--key <globalKey>:全局开关键。(必需)
global-switch set 选项:
--key <globalKey>:全局开关键。(必需)--status <on|off>:目标开关状态。(必需)
有关完整键列表和示例,请参阅 全局开关参考。
12. 查询全局内存使用情况
通过全局 Memory.* CDP 域查询 Lynx 全局内存使用情况。使用通用 cdp 命令,将会话 ID 设置为 -1 将请求发送到全局 DevTool 处理程序。
# 获取跨活动实例的全局 Lynx 内存使用情况
node <path_to_the_skill>/scripts/index.mjs cdp -s -1 -m Memory.getAllMemoryUsage
node <path_to_the_skill>/scripts/index.mjs cdp -s -1 -m Memory.getAllMemoryUsage '{"timeoutMs":50000}'
-c, --client <clientId>:(可选)客户端 ID。-s, --session <sessionId>:CDP 会话 ID。除非有特定平台原因需要覆盖,否则使用-1作为全局 DevTool 处理程序。params.timeoutMs(可选):非负超时时间(毫秒)。最大值为300000。
当 DevTool MCP 服务器可用时,优先使用 Memory_getAllMemoryUsage MCP 工具获取相同的原始负载,而不是通过 CLI 执行 shell 命令。
13. 录制
通过 TestBench(基于 CDP)录制 Lynx 页面交互。捕获所有操作(模板加载、触摸事件、JS 模块调用、数据更新)并生成 JSON 回放文件。
# 开始录制(在打开目标页面之前)
node <path_to_the_skill>/scripts/index.mjs recorder start [options]
# 停止录制并保存回放文件
node <path_to_the_skill>/scripts/index.mjs recorder end [options]
-c, --client <clientId>:(可选)start和end的客户端 ID。-o, --output <path>:(可选)end的输出文件或目录路径。默认为~/.lynx-devtool/files/lynxrecorder/recording-<clientId>-<timestamp>.json。
工作流程:
- 运行
recorder start。如果它启用了enable_debug_mode,请重启应用并再次运行recorder start。 - 用户打开并与 Lynx 页面交互。
- 运行
recorder end --output <file.json>停止并保存。 - 将绝对文件路径报告给用户。
重要: 为了生成可回放的文件,请在 recorder start 之后打开或重新加载目标页面,以便录制包含 loadTemplate。
有关更多详细信息,请参阅 录制参考。
14. ReactLynx 组件树
打印正在运行的 ReactLynx 页面的组件树,从 @lynx-js/preact-devtools 解码。CLI 打开一个 Lynx.onVMEvent 流,发送 Preact DevTools init+refresh 握手,并将生成的 operation_v2 负载渲染为 ASCII 树。
node <path_to_the_skill>/scripts/index.mjs reactlynx tree [options]
-c, --client <clientId>:(可选)客户端 ID。-s, --session <sessionId>:(可选)会话 ID。--depth <n>:(可选)要打印的最大树深度。默认:无限制。--show-shells:包含 ReactLynx 插入的合成Fragment/Root/Anonymous包装器。默认隐藏。--json:输出{ labels, roots, nodes }而不是 ASCII;当脚本将使用树时使用此选项。
输出使用 @cN [type] Name 引用(来自 agent-react-devtools 的约定)。标签是对可见根进行前序 DFS 的结果,并在每次调用时重置,因此在单个命令内是稳定的,但不跨运行:
@c1 [fn] App
├─ @c2 [fn] Header
│ └─ @c3 [fn] Logo
└─ @c4 [fn] Body
要求:
- 页面必须是运行
@lynx-js/preact-devtools的开发构建(生产包会剥离setupReactLynx())。成功初始化会在设备控制台记录[PREACT DEVTOOLS] Devtools initialized successfully。 @lynx-js/preact-devtools必须包含document.body和preactDevtoolsCtx.Node修复(针对lynx-family/preact-devtools的 PR #2 + PR #5)。没有这些修复,refresh通道将返回零个operation_v2帧,CLI 将打印“过时的 preact-devtools”诊断信息。
当树返回为空时,CLI 以代码 1 退出,并在 stderr 上写入三个有针对性的诊断信息之一:
saw 0 frames:PreactDevtools通道上没有回复。应用很可能缺少@lynx-js/preact-devtools,是生产构建,尚未完成setupReactLynx(),或者您选择了错误的--session。saw N frames but no operation_v2:钩子已加载但其refresh处理程序有 bug。将@lynx-js/preact-devtools升级到包含 PR #2 和 #5 的构建。tree is empty:每个节点在提交之间被卸载——很少见,使用DEBUG(见下文)重新运行以查看原始信封。
对于深度调试,设置 DEBUG=devtool-mcp-server:reactlynx 以在 stderr 上记录每个 PreactDevtools 帧(类型 + 负载大小),同时保持 stdout(树/JSON)干净:
DEBUG='devtool-mcp-server:reactlynx' node <path_to_the_skill>/scripts/index.mjs reactlynx tree
15. ReactLynx 组件检查
通过发送 Preact DevTools inspect 信封并读取 inspect-result 来检查单个 ReactLynx 组件(props / state / hooks / context / signals)。
node <path_to_the_skill>/scripts/index.mjs reactlynx component <ref> [options]
<ref>:可以是reactlynx tree/reactlynx find生成的标签@cN,也可以是数字 vnode id。- 使用
@cN时,CLI 首先执行额外的 init+refresh+tree 往返以解析标签。如果(且仅当)标签是在显示外壳的情况下生成的,请传递--show-shells。 - 使用数字 id(例如
3856353762)时,跳过快照——总共一次往返。
- 使用
-c, --client <clientId>,-s, --session <sessionId>:(可选)标准定位标志。--show-shells:在解析@cN时,以与reactlynx tree --show-shells相同的方式计数合成 Fragment / Root / Anonymous 包装器。--json:打印原始InspectData负载为 JSON。默认输出是紧凑的 ASCII 摘要。
示例输出:
@c5 (id=3856353783) [fn] TUXIntroViewListCell key=1. HMR
source: src/TUXIntroViewListCell.tsx:42:3
props:
{
"title": "1. HMR",
"icon": { "type": "vnode", "name": "TUXIcon" }
}
16. ReactLynx 组件查找
查找名称与子字符串或正则表达式匹配的每个组件。输出顺序与 reactlynx tree 相同(前序 DFS),因此 @cN 标签可以与其他子命令往返。
node <path_to_the_skill>/scripts/index.mjs reactlynx find <pattern> [options]
<pattern>:子字符串(默认,不区分大小写)或使用--regex的 JavaScript 正则表达式。-c, --client <clientId>,-s, --session <sessionId>:(可选)标准定位标志。--regex:将<pattern>视为 JavaScript 正则表达式(例如--regex '^Toast(List)?$')。--show-shells:包含合成 Fragment / Root / Anonymous 包装器。--limit <n>:要打印的最大匹配数。默认为50。--json:输出[{ label, id, name, type, key, ancestors: [{label, name}] }, ...]用于脚本化后处理。
示例输出:
@c8 [fn] TUXCenterToastActivator
in @c1 TUXApp > @c2 Provider > @c3 App
@c10 [fn] TUXTopToastActivator
in @c1 TUXApp > @c2 Provider > @c3 App
当树太大无法视觉扫描时,reactlynx find 是发现标签以进行后续 reactlynx component @cN 调用的推荐方式。





