驱动

通用 v0 驱动把平台操作翻译成内核能用的结构化动作;任务权限由内核或宿主管理。本页的 UiDriver 和通用 ValuePattern 示例描述旧入口。新 agent 的专用记事本驱动另有固定计划、文档身份、定向输入及持续守卫合同,不自动继承通用驱动的回退操作。

专用记事本驱动

11.2607.14.0 的固定文档计划已通过真实服务 IPC、应用宿主和原生驱动完整链,分别验证 UTF-8 无 BOM 的 CRLF/LF、中文路径与正文、空行、精确副本及源文保持。本地合成规划与真实 DeepSeek 加原生三轮、四类故障及默认生产服务均已通过,精确发行版配置已放行;选择器只接受放行后精确版本与 zh-CN,通用构造器无 profile 时仍禁用保存。

本机编辑区支持 TextPattern/ValuePattern 读取,但 ValuePattern.SetValue 未产生所需 dirty 状态,因此编辑和文件名输入使用经验证的定向控件操作;raw CR 按源文件约定映射为 LF/CRLF,最终完整字节独立核验。同 PID 多窗口按具体 HWND、活动标签和文档实例绑定。守卫检测人工输入变化后停止,不代表任意外部 UIA/SendMessage 隔离;生产宿主生命周期只执行一个文档任务。详细来源链、运行限制和证据见首个应用。

接口

interface UiDriver {
  windows(): Promise<WindowInfo[]>;
  tree(ref: WindowRef, depth?: number): Promise<UiNode>;
  invoke(ref: WindowRef, selector: UiSelector): Promise<void>;
  click(ref: WindowRef, selector: UiSelector): Promise<void>;
  type(ref: WindowRef, selector: UiSelector, text: string): Promise<void>;
  keys(ref: WindowRef, combo: string): Promise<void>;
  focus(ref: WindowRef): Promise<void>;
}

各平台状态

Windows(已验证)

macOS(已在真机验证)

四条实测踩出来的坑,写在这里省别人时间:

  1. 别用 AppleScript 枚举窗口:System Events 逐窗口取属性在真机上要 19–23 秒,用 CGWindowList + AXUIElement 的原生桥是 36 毫秒。
  2. 别用 keystroke 打英文:它会走当前输入法,中文输入法下 hello 会变成 和力量。桥里改用 CGEvent 直接投递 Unicode。
  3. 聚焦要按 pid:CGWindowList 的 owner 名是本地化的("终端"),System Events 的进程名是 "Terminal",按名字匹配会 -1719。
  4. 按钮常常没有标题:macOS 计算器的按钮 AXTitle 为空,只能靠 AXIdentifier(Seven / Multiply / Equals)定位;显示区文本还带 U+200E 方向标记,比对前要剥掉。

Linux — X11,窗口级(CI 实测)

`` click 需要控件级定位,X11 驱动暂不支持(没有可访问性树)。 ``

在一台新机器上验证驱动

node bin/deskshell.ts doctor           # 环境自检:Node / 平台 / 权限 / 清单 / 可写
node scripts/verify-driver.ts          # 只读检查:窗口枚举、控件树、聚焦
node scripts/verify-driver.ts --input  # 额外测试按键与输入(会向当前窗口发一次按键)

输出是一张能力表:

PASS windows()  24 个窗口,例如:...
PASS tree()     记事本 → 37 个节点
PASS focus()    已聚焦
SKIP click()    需指定窗口与控件,verifier 不自动点击

失败的项会打印原始错误(例如 macOS 的 -1719 就是没给辅助功能权限)。

内存驱动(MockDriver)

packages/drivers/mock/driver.ts 是一个纯内存驱动:不碰真实桌面,行为完全可预测。

它的用途不是替代真驱动,而是证明内核对平台无感:

node scripts/contract-test.ts

六项契约:

| 契约 | 验证什么 | | --- | --- | | driver.tree | 树结构与选择器匹配 | | ui.type+assert | 输入后 ui.value 断言通过 | | assert.blocks | 错误断言必须阻断执行 | | rollback.cross-domain | 文件写入 + UI 失败 → 文件被回滚 | | ui.invoke | invoke 真的调到驱动 | | policy.deny | 未声明 ui.input 时点击被拒绝 |

新平台驱动只要通过这六项,就说明它和内核的契约是对的——剩下的只是"它在这个系统上准不准"。

写一个新驱动

  1. 新建 packages/drivers/<platform>/driver.ts,实现 UiDriver;
  2. 在 scripts/verify-driver.ts 里加平台分支;
  3. 文档里写清楚:已验证什么、未验证什么、怎么验证——三者缺一不可,否则别人没法判断能不能用。