# MacroCLI Demo — gedit 完整测试方案 本文档记录 MacroCLI 在 **Linux 无头服务器 + Xvfb + noVNC** 环境下的完整测试过程, 包括虚拟桌面搭建、VNC 远程查看、宏执行和录制回放的全链路验证。 --- ## 环境架构 ``` 本地浏览器 │ SSH 隧道 (16080 → 16080) ▼ 远程 Linux 服务器 │ ├─ Xvfb :99 虚拟显示器 1920x1080 ├─ openbox 窗口管理器 ├─ x11vnc VNC 服务 (只监听 localhost:5900) ├─ websockify WebSocket → VNC 代理 (16080) └─ gedit 被操控的 GUI 应用 ``` --- ## 第一步:安装依赖 ```bash # 虚拟显示器和 VNC sudo apt install xvfb x11vnc openbox xdotool wmctrl # GUI 应用(demo 目标) sudo apt install gedit # noVNC(浏览器查看桌面) sudo apt install novnc websockify # AT-SPI 语义控制(可选,GTK 应用) sudo apt install python3-pyatspi # MacroCLI Python 依赖 conda activate macrocli # 或你的环境名 pip install -e "path/to/macrocli/agent-harness[visual]" # 等价于: pip install mss Pillow numpy pynput ``` --- ## 第二步:启动虚拟桌面 ```bash # 1. 启动 Xvfb 虚拟显示器(:99 号,1920x1080 24位色) Xvfb :99 -screen 0 1920x1080x24 -ac & # 2. 设置 DISPLAY(后续所有命令都需要) export DISPLAY=:99 # 3. 启动窗口管理器(让窗口能正常显示和拖动) openbox & # 4. 设置桌面背景色(避免纯黑) xsetroot -solid gray # 5. 启动 VNC 服务,只监听本地,允许多连接 x11vnc -display :99 -nopw -listen localhost -rfbport 5900 \ -forever -shared -bg -o /tmp/x11vnc.log # 6. 启动 noVNC websocket 代理 websockify --web /usr/share/novnc 16080 localhost:5900 & # 验证服务启动 ss -tlnp | grep -E "5900|16080" ``` 期望输出: ``` LISTEN 127.0.0.1:5900 ← x11vnc LISTEN 0.0.0.0:16080 ← websockify ``` --- ## 第三步:连接 VNC 查看桌面 在**本地机器**开 SSH 隧道: ```bash ssh -L 16080:localhost:16080 user@your-server -N ``` 然后浏览器访问: ``` http://localhost:16080/vnc.html ``` 点击 **Connect**,无需密码,即可看到虚拟桌面。 > **注意:** 如果 Connect 后显示"连接已中断",通常是 x11vnc 的客户端连接数超限。 > 重启 x11vnc 并加 `-shared` 参数即可: > ```bash > pkill x11vnc > x11vnc -display :99 -nopw -listen localhost -rfbport 5900 -forever -shared -bg > ``` --- ## 第四步:检查后端可用性 ```bash export DISPLAY=:99 conda activate macrocli cd path/to/macrocli/agent-harness cli-anything-macrocli --json backends ``` 期望输出(所有后端 available: true): ```json { "native_api": { "available": true, "priority": 100 }, "gui_macro": { "available": true, "priority": 80 }, "visual_anchor": { "available": true, "priority": 75 }, "file_transform":{ "available": true, "priority": 70 }, "semantic_ui": { "available": true, "priority": 50 }, "recovery": { "available": true, "priority": 10 } } ``` --- ## Demo A:手写宏执行 ### A1. 打开 gedit ```bash cli-anything-macrocli --json macro run gedit_new_window ``` VNC 里能看到 gedit 窗口弹出。 输出示例: ```json { "success": true, "telemetry": { "duration_ms": 39, "backends_used": ["native_api", "semantic_ui"] } } ``` > **实现细节:** `gedit_new_window` 用 `native_api` 的 `start_process` action 后台 > 启动 gedit(不等待进程退出),然后 `semantic_ui` 的 `wait_for_window` 等待窗口出现。 ### A2. 输入文字并保存 ```bash cli-anything-macrocli --json macro run gedit_type_and_save \ --param "text=Hello from MacroCLI!" ``` VNC 里能看到文字逐字输入到 gedit,然后触发 Ctrl+S。 输出示例: ```json { "success": true, "steps": [ { "backend_used": "semantic_ui", "output": {"focused": "gedit", "method": "wmctrl"} }, { "backend_used": "visual_anchor", "output": {"typed": 20} }, { "backend_used": "visual_anchor", "output": {"hotkey": "ctrl+s"} } ], "telemetry": { "duration_ms": 774 } } ``` > **实现细节:** 三个后端串联——`semantic_ui` 用 wmctrl 聚焦窗口,`visual_anchor` > 用 pynput 注入键盘事件,`visual_anchor` 发送 Ctrl+S 快捷键。 ### A3. 另存为指定路径 ```bash cli-anything-macrocli --json macro run gedit_save_as \ --param output_path=/tmp/macrocli_demo.txt ``` 执行过程(可在 VNC 观察): 1. Ctrl+Shift+S 弹出 Save As 对话框 2. Ctrl+L 打开路径输入框 3. Ctrl+A 清空已有内容 4. 输入 `/tmp/macrocli_demo.txt` 5. Enter 确认 ```bash # 验证文件已创建 cat /tmp/macrocli_demo.txt ``` --- ## Demo B:录制宏(核心功能) 录制功能把一次手工操作自动转成可重复调用的宏。 ### 录制原理 ``` 用户操作 GUI │ pynput 监听鼠标键盘事件 │ 每次点击: xdotool getwindowfocus → 获取焦点窗口名称和位置 计算点击在窗口内的百分比坐标 (x_pct, y_pct) → 生成 click_relative 步骤(窗口锚点,不依赖绝对坐标) │ 键盘输入: 累积字符(含空格)→ 生成 type_text 步骤 快捷键组合 → 生成 hotkey 步骤 │ Ctrl+Alt+S 停止录制 │ 自动写出 YAML 宏文件 ``` **为什么用窗口锚点而不是绝对坐标:** 点击空白文本区会截到全白图片,模板匹配无法识别。改用窗口相对坐标 (`click_relative`),回放时先找到窗口位置,再按百分比算出实际坐标, 窗口移动到任何地方都能正确点击。 ### 录制操作 ```bash # 开始录制,命名为 my_workflow cli-anything-macrocli macro record my_workflow \ --output-dir /tmp/my_recording \ --timeout 30 # 30秒后自动停止,或手动 Ctrl+Alt+S ``` 终端显示: ``` Recording 'my_workflow'. Press Ctrl+Alt+S to stop. [recorder] Recording 'my_workflow'. Press Ctrl+Alt+S to stop. ``` **现在操作 gedit(录制器会捕获这些动作):** 1. 在 VNC 里点击 gedit 文本区 2. 输入一段文字 3. 按 Ctrl+S 保存 按 Ctrl+Alt+S 停止(或等待超时),自动生成: ``` /tmp/my_recording/ ├── my_workflow.yaml ← 宏定义文件 └── my_workflow_templates/ ← 有特征区域的截图模板 └── step_001_click.png ← 若点击区域有特征才会保存 ``` 生成的 YAML 示例: ```yaml name: my_workflow steps: - id: step_001_click backend: visual_anchor action: click_relative # 窗口锚点,不是绝对坐标 params: window_title: gedit # 从 xdotool getwindowfocus 获取 x_pct: 0.35 # 点击位置在窗口宽度的 35% y_pct: 0.33 # 点击位置在窗口高度的 33% - id: step_002_type backend: visual_anchor action: type_text params: text: hello world # 空格正确合并(不再被切成 hotkey) - id: step_003_hotkey backend: visual_anchor action: hotkey params: keys: ctrl+s ``` ### 回放录制的宏 ```bash # 先清空 gedit 内容 # 然后回放 cli-anything-macrocli --json macro run my_workflow \ --macro-file /tmp/my_recording/my_workflow.yaml ``` 实际测试输出: ```json { "success": true, "telemetry": { "duration_ms": 486, "steps_run": 3, "backends_used": ["visual_anchor"] } } ``` VNC 截图验证(`hello world` 出现在 gedit): ``` gedit 窗口标题: macrocli_test_final.txt (/tmp) - gedit 内容: hello world 状态: 已保存(标题栏无 * 号) ``` --- ## Demo C:transform_json(file_transform 后端) > ⚠️ **未在本次测试中验证,仅供参考。** 不需要 GUI,直接操作 JSON 文件: ```bash # 创建测试文件 echo '{"app": "draw.io", "version": 1}' > /tmp/config.json # 用宏修改嵌套 key cli-anything-macrocli --json macro run transform_json \ --param file=/tmp/config.json \ --param key=settings.theme \ --param value=dark # 验证 cat /tmp/config.json # {"app": "draw.io", "version": 1, "settings": {"theme": "dark"}} ``` --- ## 常见问题 **Q: `macro run gedit_new_window` 超时 30 秒** 原因:`run_command` 会等待进程退出,GUI 应用永远不会退出。 解决:改用 `start_process` action(本项目已修复)。 **Q: `wait_for_window` 找不到窗口** 原因:`conda run` 会清除 `DISPLAY` 环境变量。 解决:激活 conda 环境后直接运行,不要用 `conda run`: ```bash conda activate macrocli export DISPLAY=:99 cli-anything-macrocli ... ``` **Q: VNC Connect 后显示"连接已中断"** 原因:x11vnc 默认不允许多个客户端同时连接。 解决:重启 x11vnc 并加 `-shared`: ```bash pkill x11vnc x11vnc -display :99 -nopw -listen localhost -rfbport 5900 -forever -shared -bg ``` **Q: 录制回放时点击位置不准** 原因:窗口大小与录制时不同,百分比坐标偏移。 解决:确保回放时窗口大小与录制时一致,或调整宏里的 `x_pct`/`y_pct`。 **Q: 模板图全白,click_image 永远超时** 原因:点击了空白区域(如文本编辑区),截图无特征。 解决:录制器已自动检测低方差图片,改用 `click_relative` 替代。 --- ## 验证结果汇总 | 宏 | 后端 | 结果 | 耗时 | |----|------|------|------| | `gedit_new_window` | native_api + semantic_ui | ✓ | ~40ms | | `gedit_type_and_save` | semantic_ui + visual_anchor | ✓ | ~774ms | | `gedit_save_as` | semantic_ui + visual_anchor | ✓ | ~1847ms | | `transform_json` | file_transform | ⚠️ 未验证 | — | | `macro record` + 回放 | visual_anchor | ✓ | ~486ms | --- ## 对接其他应用 同样的流程适用于任何 Linux GUI 应用: | 应用 | 推荐后端 | 说明 | |------|----------|------| | Inkscape | `native_api` (`--actions`) | 有完整命令行接口 | | GIMP | `native_api` (Script-Fu) | 脚本接口强大 | | LibreOffice | `native_api` (`--headless`) | UNO API | | draw.io | `file_transform` + `visual_anchor` | XML 格式可直接编辑 | | 任意 GUI 应用 | `macro record` + `visual_anchor` | 录制一次,窗口锚点回放 |