lynx-devtool

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`)时。

25Star
8Fork
更新于 2026/7/27
SKILL.md
readonly只读
name
lynx-devtool
description

当处理 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 通过包/应用标识符(AppProcessNamebundleIdbundleNameApp)从 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.getDocumentRuntime.evaluate)。
  • -c, --client <clientId>:(可选)客户端 ID。如果省略,则使用第一个可用客户端。
  • --client-name <name>:(可选)从 list-clients 解析的包/应用名称。
  • -s, --session <sessionId>:(可选)会话 ID。如果省略,则使用最新会话(具有最大会话 ID)。
  • --thread <thread>:(可选)目标 VM 线程,backgroundmain。默认为 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 线程:backgroundmain。如果省略,默认收集两个线程。
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 线程,backgroundmain。默认为 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>:(可选)startend 的客户端 ID。
  • -o, --output <path>:(可选)end 的输出文件或目录路径。默认为 ~/.lynx-devtool/files/lynxrecorder/recording-<clientId>-<timestamp>.json

工作流程:

  1. 运行 recorder start。如果它启用了 enable_debug_mode,请重启应用并再次运行 recorder start
  2. 用户打开并与 Lynx 页面交互。
  3. 运行 recorder end --output <file.json> 停止并保存。
  4. 将绝对文件路径报告给用户。

重要: 为了生成可回放的文件,请在 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.bodypreactDevtoolsCtx.Node 修复(针对 lynx-family/preact-devtools 的 PR #2 + PR #5)。没有这些修复,refresh 通道将返回零个 operation_v2 帧,CLI 将打印“过时的 preact-devtools”诊断信息。

当树返回为空时,CLI 以代码 1 退出,并在 stderr 上写入三个有针对性的诊断信息之一:

  • saw 0 framesPreactDevtools 通道上没有回复。应用很可能缺少 @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 调用的推荐方式。