🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

桌面操控 baldovinmarques391-design/dsh-computer-control

DeepSeek Harness
baldovinmarques391-design31 天前有提交已提供中文文档扫描:含敏感能力

把 Windows 桌面操作拆成独立工具调用并回传画面

29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/4 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add baldovinmarques391-design/dsh-computer-control
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · desktop
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 31 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令发起外部网络请求
查看扫描证据(共 5 处,展示前 5 条)
  • 执行外部命令固定命令
    lib/desktop.mjs:79
    const killer = spawn('taskkill', ['/PID', String(pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true });
  • 执行外部命令来自配置/变量
    lib/desktop.mjs:123
    child = spawn(resolvePowerShell(), ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass',
  • 执行外部命令来自配置/变量
    lib/desktop.mjs:419
    const child = spawn(powerShell, ['-NoProfile', '-NonInteractive', '-Command',
  • 执行外部命令来自配置/变量
    lib/desktop.mjs:488
    const child = spawn(
  • 发起网络请求
    lib/relay.mjs:232
    const response = await fetch(`${this.#url}/relay`, {
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-llm@deepseek-ai/dsh-tools@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 拆分桌面操作为工具调用
  • 回传调用前后画面

DeepSeek Harness 套件:把 Windows 桌面操作拆成一个个工具调用,每次调用都返回调用前后抓取的画面。

README

由 DeepSeek 最新模型翻译生成
dsh-computer-control 一个 DeepSeek Harness 插件包,把 Windows 桌面操作拆成一个个独立的工具调用。每次调用只做一件事,返回从动作开始前到动作结束稳定期之后抓取的画面,模型不用再惦记着截图。 安装 dsh plugin 会把参数原样转发给配置档目录下的 pnpm,所以无论是本地检出、git 地址还是已发布的 tarball,安装方式都一样: dsh plugin --profile web add <path-to-this-checkout> 对等依赖(@deepseek-ai/dsh-tools、@deepseek-ai/dsh-llm、@deepseek-ai/schemastery)由 harness 提供,所以本包只声明它们,不依赖它们;本地检出通常没有自己的 node_modules。 DeepSeek Harness 不接受外部 pull request;社区插件被发现的官方途径是公开仓库并打上 dsh-plugin 这个 GitHub topic,package.json 的 keywords 里列它就是这个原因。
展开完整文档(README 剩余 1 节)
dsh-computer-control

一个 DeepSeek Harness 插件包,把 Windows 桌面操作拆成一个个独立的工具调用。每次调用只做一件事,返回从动作开始前到动作结束稳定期之后抓取的画面,模型不用再惦记着截图。

安装

dsh plugin 会把参数原样转发给配置档目录下的 pnpm,所以无论是本地检出、git 地址还是已发布的 tarball,安装方式都一样:

dsh plugin --profile web add <path-to-this-checkout>

对等依赖(@deepseek-ai/dsh-tools、@deepseek-ai/dsh-llm、@deepseek-ai/schemastery)由 harness 提供,所以本包只声明它们,不依赖它们;本地检出通常没有自己的 node_modules。

DeepSeek Harness 不接受外部 pull request;社区插件被发现的官方途径是公开仓库并打上 dsh-plugin 这个 GitHub topic,package.json 的 keywords 里列它就是这个原因。

test/ 下的测试套件按本检出和 harness 包解析导入,装好对等依赖后,在任何工作目录都能跑:

npm test # or: node test/run-all.mjs

你能得到什么

十一个工具,注册在宿主 tools 服务上:

| 工具 | 一次调用做什么 | 返回 |
| computer_probe | 什么都不做;报告屏幕尺寸、指针位置与形状、指针下的窗口 | 只有文本,没有图像 |
| computer_screenshot | 什么都不做;截取整屏,或按整数缩放截取一块矩形 | 一张图像 |
| computer_move | 移动指针 | 移动前后的画面 |
| computer_click | 按下并松开一次某个按键 | 点击前后的画面 |
| computer_drag | 按下、拖动、松开 | 整个手势过程的画面 |
| computer_scroll | 一次滚轮手势 | 手势前后的画面 |
| computer_type | 把字符串按 Unicode 按键逐个输入 | 文字落屏期间的画面 |
| computer_key | 按下并松开一个指定按键 | 按键前后的画面 |
| computer_chord | 按住修饰键,按一个键,再全部松开 | 组合键前后的画面 |
| computer_wait | 不注入任何操作,只观察 | 等待期间的画面 |
| computer_frames | 读取两个较早帧之间录下的画面 | 最多到工具自己的 maxFrames(默认 16);其中至多 maxAttachedImages 张以图像形式送达,其余打印为路径 |

computer_frames 是唯一不产生新截图的工具:它重新读取录制环中前一次调用返回的两帧之间的内容,所以两帧的返回就够重建它们之间的运动,不必每次调用都多付图像的开销。

在两帧之间读取

一次调用会抓十到三十帧,只返回其中两帧。computer_frames 会回到录制环里取出这段区间剩下的帧:

<computer-control action="frames">
result: ok
从:<调用打印出的较早帧> 到:<调用打印出的较晚帧> span:1995 ms 两者之间记录:21 帧;返回:4 实际速率:1.78 fps 已附加:4 个返回帧中的 2 个,这个上限让单次调用的开销可预测说明:以 2 fps 从 21 个记录帧中采样 4 个;fps 越高返回的帧越多;在 4 帧上限处停止;缩小 span 或降低 fps 可看到全部帧(偏移量相对于较早帧):
0. +0 ms | 1024x576 | 51399 bytes | image attached | <path>
1. +587 ms | 1024x576 | 51389 bytes | image attached | <path>
2. +1121 ms | 1024x576 | 51304 bytes | path only, read it with read_image | <path>
3. +1686 ms | 1024x576 | 51303 bytes | path only, read it with read_image | <path>
</computer-control>

这个信封里有两点是刻意设计的。recorded between them 报告环形缓冲区里存了什么,这样答案偏少时,你能分清是记录器没覆盖到这段 span,还是别的原因;attached 说明列出的帧里有多少以图像形式送达:上限是 maxAttachedImages,它的存在是为了让单次调用的开销可预测,所以超过上限的帧会保存下来、以路径形式打印,而不是附加。未附加的帧之后可以用 read_image 读取,不必重新请求,只要部署的截图目录还留着它:该目录保存最近的 SHOT_RETENTION 个文件,超过之后,最早保存的路径就不再能解析,之后再请求其中一个会明确告诉你,而不是报告文件不存在。

设计上就是离散的

没有 hold、repeat、macro、loop 或「run this until」参数,也无法让按钮或按键跨调用保持按下:

- computer_click 在一次注入批次里完成按下和释放。
- computer_key 和 computer_chord 在同一次调用内释放它们按下的每一个键。
- computer_drag 是一个原子手势;步数上限由 maxDragSteps 决定。
- 每个工具都注册为并发不安全,所以注册表会把桌面输入串行化。
- computer_scroll 拒绝零刻度手势,而不是把无操作报告成成功。

要点击两次,就调用 computer_click 两次。每次调用都会带回自己的帧。

配置

下面每个值都是 Config 字段;在你的配置档 cordis.patch.yml 里覆盖对应行,并重新写出你要保留的键,因为补丁会替换整行的 config。

| 键 | 默认值 | 含义 |
| capturesPerSecond | 10 | 记录器产生的帧率 |
| maxFrames | 2 | 单次调用返回的帧数(1 到 20):动作前的参考帧和稳定后的结束状态。computer_frames 的上限更低,为 16 |
| maxAttachedImages | 2 | 以图像形式附加的帧数(0 到 19);更多帧仍会保存到磁盘并打印其路径 |
| changeThreshold | 0.003 | 视为变化的签名位移 |
| settleMs | 700 | 动作完成后额外捕获的时间 |
| settleRunFrames | 2 | 连续多少对尾部帧保持不变,信封才认定窗口已稳定 |
| maxWindowMs | 15000 | 单个捕获窗口的上限(200 到 120000);同时决定工具超时 |
| maxWaitSeconds | 10 | 被动观察的最长时间 |
| maxTypeChars | 2000 | computer_type 接受的最长字符串(最多 20000) |
| maxScrollClicks | 10 | 最大滚轮手势,单位为格 |
| maxDragSteps | 120 | 最大拖拽步数 |
| maxZoom | 8 | 最大整数缩放倍数(1 到 16) |
| maxZoomedPixels | 16000000 | 单次缩放捕获的像素上限,在任何内存分配之前检查 |
| frameMaxEdge | 1024 | 捕获帧的最长边 |
| frameQuality | 75 | JPEG 质量,1 到 100,仅用于进程内回退捕获;录制帧由 ffmpeg 按 recorderQuality 编码 |
| ffmpegPath | ffmpeg | 录制屏幕的可执行文件 |
| tempRoot | | 存放暂存辅助程序、录制环形缓冲、截图和标记的目录;留空表示系统临时目录下的某个目录。插件激活时会拒绝盘符根目录和扩展长度路径,因为这两种情况下录制器都无法保留,每次调用都会回退到进程内捕获 |
| recorderQuality | 5 | 录制帧的 ffmpeg -q:v,1 到 31;数值越低质量越好、文件越大 |
| recorderBufferMs | 4000 | 一次调用能回溯多远,以取到自己的首帧 |
| recorderPrimeMs | 400 | 注入输入之前录制器的提前启动时间 |
| recorderIdleStopMs | 30000 | 空闲录制器停止前的宽限期 |
| imageMode | auto | auto 在路由接受图像且附件服务已挂载时附带帧;text 从不附带。路由自身的能力仍会被解析,因此信封可以说明 read_image 对已在磁盘上的帧是否可用 |
| captureTimeoutMs | 20000 | 捕获或探测调用的超时预算 |
| actionTimeoutSlackMs | 10000 | 加到 maxWindowMs 上,作为动作工具的超时 |
| compactionCleanupEnabled | false | 压缩摘要处理完本会话的图像后,将其删除。默认关闭:清理逻辑已实现并测试过,但八次对抗性审查每次都发现真实缺陷,所以它出厂时不启用。设为 false 时,压缩不删除任何东西,每张图像都留在磁盘上。启用它是一个决定,不是默认行为——见 DELIVERY.md |
| desktopTarget | local | 屏幕和输入操作发生在哪个桌面。agent 是中继实例的桌面——默认是智能体自己的,也就是副账号;user 是本进程自己的 Windows 会话——坐在键盘前的那个人;auto 优先选 agent,只有在中继完全无法连接时才回退到 user,绝不重试中继已经应答过的命令,因为已经连上的中继可能已经执行了操作,再在用户桌面上重复一次就成了没人要求的第二次操作(每次回退都会记日志)。local 和 relay 是按机制命名的写法,分别对应 user 和 agent。这是部署事实,不是偏好:ffmpeg 的 gdigrab 和 SendInput 只作用于调用进程自己的会话,所以实例若要驱动另一个账号的桌面,必须委托给运行在那个桌面上的实例 |
| relayUrl | "" | 中继实例的源地址,当 desktopTarget 为 agent、relay 或 auto 时使用,例如 http://127.0.0.1:3079。只接受回环地址 |
| relayToken | "" | 中继协议的 Bearer token。在某个实例上设置它,就会为该实例安装 /relay 路由;留空表示该路由根本不存在 |
| relayTimeoutMs | 60000 | 单条转发命令的上限,这样中继卡住时不会让工具调用无限期挂起 |
| agentAccount | "" | 本次部署用来运行自动化会话的 Windows 账号。它和 userAccount 一起启用账号段落;只要其中一个为空,该段落就不存在,这也是默认情况 |
| userAccount | "" | 坐在键盘前的人使用的 Windows 账号,在账号段落中写明 |
| userDesktop | "" | 那个人的桌面路径,在账号段落中写明。留空则不提及,当它就是配置档自己的 Desktop 文件夹时,这样处理正合适 |
| userDocuments | "" | 那个人的文档路径,在账号段落中写明。留空则不提及 |

实现

采集委托给 ffmpeg(-f gdigrab),它能在全屏尺寸下保持真实帧率:实测 1600x900 和 1024 宽下均为 9.9-10.7 fps,没有丢帧。ffmpeg 自己缩放到 frameMaxEdge,所以本包从不编码任何帧。进程内的 GDI+ 路径只作为回退存在,每帧要花 100-300 ms,因为耗时主要来自 PowerShell 的缩放加 JPEG 编码;这笔开销是缩放,不是采集。

lib/desktop-helper.ps1 是长期运行的 PowerShell 辅助进程,负责输入注入并监管录制器。它通过 stdin/stdout 传输换行分隔的 JSON,并以 BOM 编码的副本形式投递到每进程的临时目录下,因为 Windows PowerShell 5.1 会把没有 BOM 的脚本按 ANSI 读取。lib/desktop.mjs 监管该进程,lib/frames.mjs 挑选值得返回的帧,lib/tools.mjs 声明工具。

帧记录来自录制器写入的文件。它们的时刻就是文件的创建时间,而不是发现它们的轮询:NTFS 保留亚毫秒级创建时间,而轮询会把一次扫描中的每一帧都量化到同一瞬间。帧按名称序号顺序发出,因为那才是采集顺序,而创建时间戳可能相同,也可能倒退几毫秒。helper 还会运行一个裸的阻塞式 ReadLine,因为在这个 PowerShell 里 Console.In.Peek() 会在重定向管道上阻塞,围绕它的「空闲切片」循环会让 helper 挂起。

有两条生命周期规则比看上去更重要:

- 必须停止录制器,而不只是 helper。 ffmpeg 是 helper 的子进程,所以只杀掉 helper 会让录制器永远写帧;实测泄漏出 16 个孤儿录制器,达到 2.4 GB 的帧。看门狗覆盖宿主死亡的情况,sweepOrphanRecorders() 覆盖 helper 被杀的情况。
- 环形缓冲按帧数裁剪,绝不按时间裁剪。 调用方可能仍需要某个任何时间窗口都不会保留的帧,所以帧数是安全的界限,而且只在一次调用交出它的帧之后才应用。

返回的截图会降采样,所以结果会发布回真实屏幕像素的映射:信封里给出 screen 矩形,每一帧带一个 scale 因子。模型在返回的图像里测量某个特征后,乘以 scale 就得到它应该点击的坐标。

帧选择锚定在注入瞬间,而不是最大差异:它保留输入之前采集的最新帧、稳定后的结束帧,然后是离注入点最近的已变化帧。

模型体验

请求上下文与条件

模型看到什么

一个系统提示词段落,通过 ctx.systemPrompt.section() 注册到 harness 为 computer-use 插件保留的槽位(TOOL_COMPUTER_USE,顺序 3000),每次组装时由服务商解析;代码在 lib/prompt.mjs,注册在 index.js。它有三部分,其中只有第一部分是无条件的:

- 对工具以及一次调用返回什么的常驻描述。
- 账户段落,仅当本进程作为配对智能体账户运行时出现:会话是哪个 Windows 账户,键盘前的人以哪个账户工作,以及他们的文件可以自由读写。COMPUTER_CONTROL_ACCOUNTS=agent:user 覆盖配对。
- 桌面目标段落,仅当 desktopTarget 不是 local 或 user 时出现:命令作用于配对账户的桌面,而不是本会话的桌面,并且 shell 命令和 UAC 提示跟随执行它们的人。

对话中不会添加任何内容,所以这些指引既不与用户自己的消息竞争,也不会让历史增长。

常驻描述原文

计算机控制工具用来操作桌面:computer_probe 和 computer_screenshot 读取屏幕,computer_move、computer_click、computer_drag、computer_scroll、computer_type、computer_key、computer_chord 和 computer_wait 操作桌面。

一次调用默认返回两张图:注入输入之前或当时的最后一帧,以及输入之后稳定下来的那一帧。把第一张读作动作开始时的状态,第二张读作动作的结果;返回内容里会标明哪张是哪张。每一张捕获的帧也会写入磁盘,结果会为返回的每一帧打印绝对路径,这些路径在重启后依然有效。

两张帧不够看清它们之间发生了什么时,用打印出的这两个路径加上目标 fps 调用 computer_frames。每返回一帧都要消耗视觉 token,所以按问题的需要去要帧率,别一上来就要最高帧率。

一次调用只执行一个动作:要点击两次,就调用两次。一次调用绝不会让某个键或按钮保持按下状态。

Token 影响

有条件,且在每种条件下固定。常驻描述在每次请求中都是 1005 个字符。账户段落增加 1196 个字符,只出现在配对的智能体账户中。桌面目标段落增加 628 个字符,当 desktopTarget 为 auto 时是 690 个字符,因为该值还要说明回退行为,且只在目标不是 local 或 user 时出现。因此,以用户自己的账户运行、并使用默认目标的部署,只需承担常驻描述。

KV Cache 影响

前缀稳定。这一段属于系统提示词,其文本在同一部署的各次请求中完全一致,所以它延长的是可复用的前缀,而不是替换更早的 token。有三种由包自身引起的变更会让从该点起的复用失效:在 Windows 账户之间移动会话,会增删账户段落;把 desktopTarget 在 local 或 user 与其他值之间切换,会增删桌面目标段落;在 agent、relay 和 auto 之间切换,会改变该段落的长度。这三种都是部署变更,改动它们的配置档补丁编辑会由加载器实时应用,无需重启。

computer_ 的工具 schema

模型看到的内容

只要会话的配置档挂载了这个 bundle,每个请求里都会带上它;十一份工具定义和它们的参数说明每一轮都会发送,这里没有任何条件判断,也没有上限。请求的工具列表里每个工具占一项,按注册顺序排列:先是八个动作工具(computer_move、computer_click、computer_drag、computer_scroll、computer_type、computer_key、computer_chord、computer_wait),然后是 computer_screenshot、computer_probe 和 computer_frames。说明里写明每次调用只执行一个动作,参数说明则列出每一个边界(maxTypeChars、maxDragSteps、maxScrollClicks、maxZoom、maxWaitSeconds),这样参数被拒绝时是可预期的,而不是让人意外。

Token 影响

只要 bundle 还挂着,每个请求就有一笔固定开销,与这十一份 schema 成正比。参数映射刻意收得很窄:坐标是整数,type 字符串有长度上限,没有任何工具暴露自由格式的对象。

KV Cache 影响

只追加,且稳定。工具列表在会话的各轮之间逐字节一致,因此它构成可复用请求前缀的一部分,不会让它失效。

动作工具返回的帧与信封

模型看到什么

只有在模型确实调用了八个动作工具之一或截图工具的那一轮,并且只有调用路由接受图像时才会出现:imageMode: text 会完全抑制附件,不接受图像输入的路由只会收到信封文本,没有附件。最多 maxFrames 帧以图像形式返回,每帧都带有相对于输入注入时刻的毫秒偏移,另外还有一段文本信封,写明屏幕矩形、图像到屏幕的 scale、光标、指针下的窗口、捕获与返回的帧数,以及返回帧之间的间隔。其中一帧是刻意保留的动作前参照,信封会标注它,这样从它到其余帧的间隔就不会被误读成采样间隔。

逐字信封

<computer-control action="click">
result: ok
detail: {...}
captured: 12 frame(s), of which 2 were not returned
showing: 2 frame(s) over 874 ms, 84-383 ms apart (sampled, so gaps vary); recorded at 10 fps and returned as 2 image(s), not one image per recorded frame
first change: +81 ms after injection
last change: +180 ms after injection — the capture saw no movement after this settled: no — only 1 unchanged frame pair(s) end the window (2 required), so the last returned frame is a mid-transition state rather than a settled one; a follow-up computer_wait is the way to see the outcome screen: 1600x900 at 0,0; every returned image is a downscaled capture of it, so multiply a measured pixel by scale to get real screen pixels
frames (offset relative to the moment input was injected):
note: frame 0 is the pre-action reference (1 frame(s) at or before injection); the frames after it are the action and its result, spaced 84-383 ms
0. -32 ms | 1024x576 scale 1.5625 | cursor not recorded | pointer over not recorded | image attached, saved at <path> <- 操作前参考
1. +180 ms | 1024x576 scale 1.5625 | cursor not recorded | pointer over not recorded | image attached, saved at <path> <- 稳定后的结束状态
</computer-control>

Token 开销

这是本包的主要成本。图片按像素尺寸计费,所以 frameMaxEdge 和 maxAttachedImages 就是控制成本的两个旋钮:调低任意一个,都能直接减少每次调用的 token。1024x576 的一帧,比它来源的 1600x900 屏幕便宜得多,这也是截图要缩小的原因。

KV Cache 影响

它替换的是早先请求里的 token,而不是往稳定前缀后面追加,所以不会延长可复用的前缀。帧永远不会重发:它们属于某一轮的工具结果,后面某一轮不再显示这些帧时,请求就恢复成更短的样子。

已知限制与待办事项

- 空闲时录制器并不是真的零开销。 它由一串调用中的第一次调用启动,之后看门狗等到 recorderIdleStopMs 过去、仍无新调用时才停止它。在这段宽限窗口里,屏幕仍在被捕获;把 recorderIdleStopMs 设小可以缩短窗口,代价是要重新预热(每次冷启动到录制器出第一帧大约要 1.5-2 s)。
- 帧时间戳是文件写入的时刻,不是像素被读取的时刻。 gdigrab 捕获、JPEG 编码、DWM 合成,会在屏幕和代表它的那一帧之间造成大约一个帧间隔的延迟。所以一帧的偏移量精度约为一个间隔,并不精确。
- 活动指针会被合成进录制的帧里。 光标画出的位置,可能和这一帧其余部分被捕获的时刻对不上。
- 录制仅支持 Windows。 它依赖 gdigrab;macOS 和 Linux 没有对应的实现路径,本包也没有相关计划。
- 进程内回退要慢得多。 录制器启动不了时,helper 会回退到 GDI+ 捕获;在这台机器上,1024 px 宽时实测只有 2-3 fps,因为缩小和 JPEG 编码占了大头——比 ffmpeg 录制器稳定达到的 9.9-10.7 fps 低一个数量级。无论走哪条路,envelope 都会报告实测差距,所以回退调用是明显变慢,而不是悄悄出错。
- 路由能力决定 envelope 能给出什么建议。 调用方所在路由拒绝图片时,envelope 会说明这一点,帧则留在磁盘上;路由自身的能力仍会被解析,所以 envelope 能区分「这个部署关掉了图片」——此时 read_image 仍可显示已保存的帧——和「这条路由拒收图片」,后者在这条路由上什么都做不了。要取回证据,就得换一条接受图片的路由。
- 返回的帧是抽样后的子集。 一次调用捕获的帧远多于 maxFrames,而选择会保留两个锚点——注入时刻或之前的最后一帧,以及最终帧——然后用从注入点开始的一段连续帧填满剩余预算,最后才从动作前参考帧向前回溯。变化最大的帧会排在这段填充之前考虑,所以单帧闪烁也能在数量上限内保留下来;如果只按位置排序,预算就会全花在最先抖动的几帧上。信封会报告两个重复计数——按签名统计的 repeatedFrames 和按 JPEG 字节统计的 identicalFrames——因为这里的重复意味着采样器没有新内容可加,而不是屏幕被持续观看。只有字节计数能从调用方收到的图像复现,只要重新编码把像素变化压到签名阈值以下,两者就会差几帧。

- 录制帧的签名由辅助程序计算。 帧分诊需要每帧一个签名来按变化排序,没有别的东西能提供:录制器写的是 JPEG 文件,没有像素经过辅助程序,Node 侧也没有图像解码器。因此每个新帧都要在调用路径上付出一次 32x32 缩略图解码——几毫秒。网格是逐点采样的,不是取平均,因为取平均的单元格会把指针、复选框或高亮的菜单行藏进自己的均值里。

- 两条捕获路径通过不同的网格达到同一个阈值。 录制帧带的是逐点采样的 32x32 签名,所以一个单元格占整帧的 0.000977,默认 changeThreshold 允许三个;进程内回退路径计算的是 16x16 的平均*单元格,一个单元格占 0.0039,同样的阈值连一个都不到。因此回退路径上单个有噪声的平均单元格就可能被读成变化,而小到能装进一个录制单元格的特征在录制器路径上可能被漏掉。放大是看清这类特征的办法;它不会改变任何一种网格。

- 录制帧不带指针元数据。 cursor 和 under 来自 GDI+ 捕获路径,每次捕获时采样;ffmpeg 录制器只写像素,所以动作帧里没有这些成员,信封会打印 not recorded,而不是占位坐标。这些数据可以从 computer_probe 和 computer_screenshot 获取,detail 则带有辅助程序对本次调用的结果,其中包含任何辅助程序采样过的调用所对应的指针下窗口。

- 图像到屏幕的系数只有一个方向。 scale 始终表示「把返回图像中量得的像素乘以它,得到屏幕像素」,所以对缩小过的全屏帧它大于 1,对放大的区域它小于 1。两条捕获路径测量它的方向相反,因此它由帧自身的源矩形和返回宽度推导得出,而不是取自任何一条路径。
- wait 无法按自己的条件观察。 它不注入任何东西,所以它的帧就是屏幕自己在变化;真正静止的屏幕产生的帧,差别只在于合成后的指针。
- 帧是采样得到的,所以返回的集合通常是满的。 剩余预算会从注入点开始连续取一段,这意味着一次捕获超过 maxFrames 的调用通常正好返回 maxFrames 帧,屏幕安静时其中大部分与前一帧完全相同。信封里的重复计数会说明有多少帧重复。
- 仅限 Windows。 这个辅助程序通过 PowerShell 编译 user32.dll 互操作,在其他平台上拒绝加载。
- 只有一个桌面。 同一台机器上的所有会话共用一个指针和一个键盘。两次并发调用会被注册表串行化,但一个会话里的调用仍会移动用户正握着的指针。
- 键盘操作把输入送到获得焦点的窗口。 computer_type、computer_key 和 computer_chord 作用于当前持有焦点的窗口;只有指针类工具才以坐标为靶。目标窗口里的中文输入法可能截获注入的按键,把它们变成候选文本。
- 捕获按请求的帧率尽力而为。 在这个屏幕尺寸下,录制器大约能保持 10 fps;进程内回退路径捕获一帧全屏大约要 100-300 ms,所以走这条路时,一个短窗口只会得到两三帧,而不是严格的采样。
- 一帧是一个屏幕,不是一个窗口。 没有按窗口捕获,所以被遮住的窗口不把它调到前面就无法观察。
- 区域缩放会成倍放大像素。 maxZoomedPixels 限制了分配量,但高缩放下的大区域仍然是一次昂贵的捕获。
- 截图保存在部署的 scratch 根目录下的磁盘上,每个 scratch 根目录上限 200 个文件,插件卸载时不会删除。
- 在这个 Harness 版本里,engines.dsh 只是声明性的:没有任何代码读取它。插件管理器真正检查的字段是 peerDependencies。
- 用于自动化验证的 scratch 配置档不属于这个 bundle;这个包目前还没有自带测试套件。
预览分享卡片长什么样 ↓baldovinmarques391-design/dsh-computer-control
分享 · DeepSeek Harness Hub
baldovinmarques391-design/dsh-computer-control

把 Windows 桌面操作拆成独立工具调用并回传画面

这是你的仓库?认领条目

回到顶部