DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Vision — DSH Plugin for DeepSeek Harness
← Plugins
V

vision

Vision

Vision DSH bundle: give the agent screen/window vision — see tool captures via the bundled Python cvision and returns the image natively

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:cczzyy-cn/c-vision#c8a002f518cdaed88c76ab3b714785d4d471ae08
READMECompatibilityVersions

Compatibility and provenance

Vision is published as vision and currently resolves to version 0.2.23. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
9/17/2026

Versions

0.2.23stable
9/17/2026
0.2.19stable
9/13/2026
0.2.18stable
9/10/2026
Show 8 more versionsCollapse versions
0.2.16stable
9/10/2026
0.2.13stable
9/10/2026
0.2.2stable
9/4/2026
0.2.1stable
9/4/2026
0.1.9stable
8/28/2026
0.1.8stable
8/23/2026
0.1.7stable
8/23/2026
0.1.2stable
8/23/2026

Related plugins

Loading related plugins…

Latest
0.2.23
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
BSD-3-Clause
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
9/17/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in

README

Vision · DeepSeek Harness (DSH) 视觉插件

给 DSH 的 agent 提供视觉(看)与用户级操作(操作):模型用 see/ocr/list_windows 看清屏幕与 窗口,再用 click/type_text/press_key/scroll/focus_window 像人一样操作,形成 看 → 操作 → 看 的 computer-use 闭环。

本包是一个 DSH 组合包(bundle),通过 dsh plugin add 安装。插件注册工具 → 跨语言调用包内捆绑的 Python 版 cvision 截屏/OCR/输入 → 写入 Harness 附件服务(ctx.attachments.saveImage)或返回文本 → 以 image ContentBlock / text 交给模型。

同一个包还带一个浏览器半边:输入框工具栏的「截图」按钮(人工一键抓屏,或把剪贴板里的图片作为附件)。

版本:0.2.23 · 平台:Windows(完整,实测)/ macOS(Phase 1,未真机验证)/ Linux(Phase 2 占位)· 许可:BSD-3-Clause · 变更历史见 CHANGELOG.md

目录

  • 快速开始
  • 特性
  • 工具一览
  • 输入框截图按钮(浏览器半边)
  • 给 AI 智能体的使用提示
  • computer-use 推荐流程
  • 多平台支持
  • 升级后必须做什么
  • 配置
  • 构建与测试
  • CI / 发布
  • 内部 CLI 契约(维护者)
  • 目录结构
  • 故障排查
  • 说明与限制
  • DSH STORE 上架契约

快速开始

# 1) 装插件(公开仓库免认证;--profile web = 浏览器面板/3080,桌面 App 用 --profile desktop)
npx -y @deepseek-ai/dsh plugin --profile web add github:cczzyy-cn/C-Vision

# 2) 装 Python 依赖(依赖清单随包分发;CVISION_DIR 默认指向包内,无需额外配置)
python -m pip install -r <插件安装目录>\requirements.txt
  1. 重启 DSH(宿主半边生效)→ 4) 硬刷新页面 Ctrl+Shift+R(浏览器半边生效,仅升级时需要)。

验证:让模型调用 cvision_status() 看运行环境探针;或直接说「用 see 看一下屏幕」。

依赖只在「装」和「升级」时需要管一次:pip install 是幂等的,依赖装在你的 Python 里而不是 插件目录里,所以升级插件一般不用重跑(除非换了机器/解释器,或 requirements.txt 加了新依赖)。 漏装也别慌:本会话第一次调用 see/ocr 等工具时,插件会先探一次环境,直接把「缺什么 + 带绝对 路径的 pip 命令」告诉你,而不是抛一句裸的 Python 报错(v0.2.18 起)。

dsh 通常不在系统 PATH(在 npx 缓存里),用 npx -y @deepseek-ai/dsh …;dsh plugin 是 pnpm 前向器, 需本机有 pnpm。装完 npx -y @deepseek-ai/dsh --dump-config 能看到多出 # == Vision 配置层。

特性

  • 原生看图:see 抓真实截图(WGC 抓窗口合成内容,GPU/被遮挡窗口也稳),模型直接看到。
  • 快速读字:ocr 直接返回文本 + 词级边界框;see/ocr 支持 region="x,y,w,h" 只取一块,省 token。
  • 用户级操作:鼠标点击/移动/滚动、键盘输入/快捷键、窗口聚焦(模拟人操作,只置前不改窗口状态)。
  • 输入框截图按钮(浏览器半边):
    • 短按 → 系统级框选截图(Windows Win+Shift+S / macOS screencapture -i,可框选可标注), 抓到的图直接进附件栏;宿主这条通道不可用时自动回退浏览器抓屏;
    • 剪贴板监视:别的软件(微信/QQ/Win+Shift+S)截图进剪贴板 → 按钮变色 + 圆点 + 提示; 长按 ≥0.9s → 把剪贴板图片作为附件插入(按住期间有进度条反馈);
    • 显示与否由宿主真实 inputModalities 决定(不靠模型名字猜)。
  • 跨平台:Windows 完整实测;macOS Phase 1(代码已写,未真机验证);Linux Phase 2 占位。
  • 开箱即用:包内自带 Python cvision 与依赖清单,CVISION_DIR 默认指向包内。

工具一览

看(观察)

工具说明
see(handle?, window?, region?, delay?, maximize?, format?, ocr?, text?, max_elements?)截屏/窗口 → 图片返回(模型原生看)。handle(来自 list_windows)比 window 标题更精确、标题变化时更稳,二者二选一且优先 handle;region="x,y,w,h" 只取一块(省 token);delay=毫秒 等渲染;maximize 默认关;format 可选 PNG/JPEG/WEBP;ocr=true 同时返回 OCR 文本/词框;text=true 同时返回可点击元素(见下)
ocr(handle?, window?, region?, delay?)截屏后 OCR → 文本 + 词级边界框 words({text,x,y,w,h},供精确定位点击点);同样 handle 优先于 window
list_windows()列出可见窗口(标题 + 句柄 + 尺寸)
screen_info()列出显示器/DPI 布局(x/y/width/height/primary/scale),高 DPI 折算坐标用
cvision_status()运行环境健康探针(Python 版本、平台后端、OCR 引擎、依赖/后端是否可用、platform_support 三态、本平台能力清单)
wait_for_window(title?, timeout?)轮询等某个窗口出现(默认 500ms/次,10s 超时)
wait_until_changed(window?, handle?, region?, interval?, timeout?, threshold?, format?)轮询截图,直到画面真的变了才把那一帧返回(等进度条/等弹窗)。返回 changed/diff_ratio/diff_bbox;默认阈值 0.01

点击定位:see(text=true)

给模型可直接点击的坐标,不必自己从截图里估算像素:

see(text=true)  →  图片 + elements: [{ text, screen_center:{x,y}, screen_box, box, center, word_count }]
                                          ↑ 直接喂给 click(x, y)

为什么需要它:ocr 给的是词框且坐标相对那张图片,而 click 吃的是屏幕绝对坐标—— 两者之间差了三件事,模型很容易算错:裁剪偏移(region)、窗口/多屏偏移、DPI 缩放。 see(text=true) 把这三层换算固定成代码(cvision/coordinates.py),并顺手把同一行的相邻词 合并成一个控件(cvision/ui_elements.py)、四周外扩一点 padding,让中心点更稳地落在控件内部。

max_elements 默认 40(按从上到下、从左到右取前 N 个),防止一屏几百个元素刷爆上下文。

操作(模拟用户级输入)

工具说明
click(x, y, button?) / double_click(x, y)屏幕绝对坐标单击 / 双击(left/right/middle)
mouse_move(x, y)移动鼠标到屏幕坐标(不点击)
scroll(x, y, dy?, dx?)在 (x,y) 处滚动(dy>0 上滚;dx 水平滚动)
drag(x1, y1, x2, y2, button?)从 (x1,y1) 拖拽到 (x2,y2)(框选/拖文件)
type_text(text)像键盘一样输入文本到当前焦点
press_key(keys)发送快捷键,如 ctrl+l、enter、ctrl+shift+t、alt+tab
get_clipboard() / set_clipboard(text)读写剪贴板文本(Windows 原生;macOS/Linux 走 pyperclip)
focus_window(title?, handle?)把窗口置前(用户级激活);handle 优先;只改前后层级,不改窗口尺寸/最大化状态(仅最小化的窗口会被还原)

关键:默认不最大化、不切前台——WGC 抓的是窗口自身的合成内容,与前台/遮挡无关。

输入框截图按钮(浏览器半边)

本包是双面包:除宿主半边的工具外,还声明 dsh.client,由 DSH 客户端模块系统把 exports["./client"] (lib/client.js,经典脚本)送进浏览器,在 conversation.input.right 挂一个「截图」按钮。

短按 = 系统级框选截图(默认通道):

Windows  Win+Shift+S(`ms-screenclip:` 兜底)→ 系统覆盖层,框选后结果进剪贴板
macOS    screencapture -i -x <tmp.png>        → 交互框选直接写文件(Esc 不留文件)
Linux    Phase 2:返回 501 → 浏览器半边自动回退到浏览器抓屏

→ 宿主用 POST /cvision/snip 把用户刚框出来的那张图交回浏览器 → 包成 File → 作为草稿图进附件栏 → 跟随消息发给模型。

为什么默认走这条:框选与标注都是系统原生、天然跨显示器,抓屏授权由系统 UI 承载——宿主只读「用户刚 放进剪贴板/文件的那张新图」,因此不存在「页面里任何脚本都能静默截屏」的口子。代价是这一步会占用剪贴板 (Win+Shift+S 的固有行为)。

取消与归属:cli_snip 用截图覆盖层窗口判断用户是否取消(Windows 11 是 SnippingTool.exe 的 SnipOverlayRootWindow;类名与语言无关)。覆盖层消失且剪贴板始终没有新图 → 立即判定取消(宿主回 204, 客户端静默);覆盖层消失之后才出现的图一律不算本次截图(否则「取消后再用微信截图」会被误当成框选结果, v0.2.13 修的就是这个)。观测不到覆盖层时退回「只等剪贴板 + 超时」,不会误判成取消。

同时宿主会告诉页面哪些剪贴板图片是我们自己产出的(状态路由的 served 字段):单击系统截图后,系统把 刚截的图放进剪贴板,按钮不应该再亮「长按插入剪贴板图片」——那张图刚刚已经进过附件栏了。别家软件的 截图(token 变了、served=false)照常点亮。

长按 ≥0.9s = 插入剪贴板图片:

每秒        GET  /cvision/clipboard       宿主原生查:有没有图片 + token(不解码图片)
出现新图片  按钮变色 + 右上角圆点 + 提示「剪贴板有新图片:长按按钮插入」
长按 ≥0.9s POST /cvision/clipboard/image  图片进附件栏 → 配色恢复正常(按住期间有进度条反馈)
短按        系统框选截图(上面的默认通道)

两个约束都是为了守住「短按必须是截图」:只在按钮已点亮时(剪贴板里确有新图片)才启动长按计时;按住 期间给出进度反馈,慢点击会在进度条走完之前松手。

为什么轮询在宿主:浏览器不可能在后台读剪贴板——navigator.clipboard.read() 需要用户手势与授权,而且 没有剪贴板变更事件。页面只做同源 HTTP 轮询,真正读剪贴板的是宿主原生侧。页面隐藏时不轮询;宿主没有这 条路由(未升级/未重启)或连续失败 3 次即停止,且只告警一次。

⚠️ 已知取舍:取图路由让页面里的脚本(包括其它客户端插件)也能读到剪贴板里的图片——这是「让按钮 看见其它软件的截图」的固有代价,所以取了 同源 + 仅 POST + 只在长按时调用三个约束,并在 STORE 契约里写明。

回退通道:浏览器 getDisplayMedia。只有宿主那条路不可用(非桌面平台组合、Electron file:// 里没有 web 服务器、旧版宿主)或明确返回不支持时,才回退浏览器抓屏——功能在任何平台上都不会消失。点按钮后按钮进入 「等待框选」态(期间禁用,Esc 取消即静默恢复)。

可见性判定:DSH 给浏览器的模型目录(buildModelCatalog)只投影 id/name/description/reasoning, 刻意剥掉了 inputModalities,客户端无法自行判断当前模型收不收图。本包改为向自己宿主半边的只读路由 查询:

GET /cvision/model-capability?provider=<id>&model=<id>
→ { "source": "declared", "image": true|false, "modalities": ["text","image"] }   # 按真实适配器目录
→ { "source": "unknown",  "image": false }                                        # 该路由解析不出来

判定口径与 Session 的图片准入一致:只有显式声明了 inputModalities 且不含 image 才算不收图(未声明 时 DSH 仍会放行)。宿主答 declared 时以宿主为准;答 unknown、或路由根本不可达时才退回「id/name 含 vision|visual」的名字启发式。同一 provider/model 只查一次并缓存。

⚠️ 与原外部插件不能同时挂载,否则输入框会出现两个截图按钮。若曾装过 @deepseek-ai/dsh-client-ui-screenshot,请从 profile 的 cordis.patch.yml 删掉它的 insert 行,并(可选) npx -y @deepseek-ai/dsh plugin --profile web rm @deepseek-ai/dsh-client-ui-screenshot 清理依赖。

给 AI 智能体的使用提示(重要)

  • 默认不要传 maximize=true:WGC 抓的是窗口自身的合成内容,跟是否前台、是否被遮挡无关。
  • 不要为了截图去激活/切换前台窗口:WGC 路径不抢焦点、不切走你正在用的窗口。
  • ⚠️ 但「不抢前台」只对普通窗口成立。实测(Windows,非最小化):目标无论在前台还是背景, 抓取都不改几何、不抢前台;而目标处于最小化时,「先还原再抓」那条路径会把它置前、抢走前台 (抓完几何会还原回最小化,但前台已经变了)。所以不要假设抓完前台没变——尤其在用户正在别处打字时。 兜底路径(WGC 与 PrintWindow 都失败、改用读合成桌面区域)同样会置前。
  • 什么情况才用 maximize=true:仅当窗口已最小化、或太小、或被完全挡住且内容读不出来时。插件 抓完会自动还原窗口原状态(GetWindowPlacement / SetWindowPlacement 成对使用)。
  • focus_window 只置前:它不会改窗口尺寸/最大化状态(v0.2.7 起)。只有真的需要键盘焦点时才调用。
  • 推荐流程:先 list_windows() → 直接 see(handle=<句柄>)(标题会变时优先 handle);整屏用 see()。
  • 要点击就用 see(text=true):它返回的 screen_center 是屏幕绝对坐标,可直接喂给 click。 不要自己从截图估算像素——裁剪、窗口位置、多屏、DPI 四层差异都由插件换算好了。
  • ⚠️ 被遮挡的窗口点不到:screen_center 是按屏幕坐标算的,但点击会被前台窗口接住。若目标窗口 不是前台(或多窗口重叠),先 focus_window 把它置前再点,否则会点到压在上面的那个窗口上。

电脑使用(computer-use)推荐流程

把「看 → 操作 → 看」写成可复用的循环:

  1. 观察:list_windows() 找目标窗口;或 see(window="<标题>") / see(handle=<句柄>) 看清内容。
  2. 定位:用 see(text=true) 拿到可点击元素的 screen_center(屏幕绝对坐标),直接用于点击。

    两步旧做法(ocr 取词框 → 自己把图片坐标折算成屏幕坐标)已不推荐:那段换算正是最容易错的地方, 现已由插件承担。只有需要词级粒度(而非合并后的控件)时才用 ocr。

  3. 操作:focus_window(仅需要键盘焦点、或要点被遮挡窗口时)→ click(x,y) / double_click / type_text / press_key / scroll。
  4. 确认:再 see 看结果;不对就回到 2/3 重试,直到目标达成。
focus_window("Google Chrome") → press_key("ctrl+l") → type_text("https://…") → press_key("enter") → see()

⚠️ 操作会真实移动/点击/输入到你的鼠标键盘;务必先 see 确认坐标再操作,避免误触。 坐标是「抓取那一刻」的快照——拿到后请尽快点击,中间别插其它会改变画面的操作。

多平台支持

能力WindowsmacOSLinux
抓窗口 / 抓屏✅ 完整(WGC > PrintWindow > 桌面区域),实测⚠️ Phase 1 代码已写(Quartz 枚举 + screencapture -l),未真机验证,需「屏幕录制」授权❌ Phase 2 占位(capture/linux.py 三个入口 NotImplementedError)
screen_info(多屏/DPI)✅⚠️ 已写未测⚠️ 回退 PIL 单屏、scale=1
OCR✅ Windows.Media.Ocr(winsdk)⚠️ 回退 pytesseract(需另装 Tesseract)⚠️ 同上
鼠标/键盘(pyautogui)✅ 实测⚠️ 需辅助功能授权,未测⚠️ 需 X11/显示,未测
focus_window✅❌ 仅 Windows(其他平台明确抛错)❌ 同
文本剪贴板✅ 原生(pywin32)⚠️ pyperclip(已进 requirements)⚠️ 同
剪贴板图片(按钮变色/长按插入)✅ 实测⚠️ NSPasteboard/changeCount,未真机验证❌ Phase 2(如实返回不支持,按钮就不监视不提示)
系统级框选截图(短按)✅ 实测(含取消识别)⚠️ screencapture -i,未真机验证❌ 501 → 自动回退浏览器抓屏

⚠️ 只有 Windows 这条链路经过实测。在 macOS/Linux 上反馈问题时请附平台、Python 版本与完整报错。

这套「实测 / 未验证 / 未实现」的区分不只在文档里——cvision_status() 会把它作为机器可读字段给出, 模型据此判断该不该尝试 computer-use、以及出问题时该不该怀疑插件:

platform_support含义当前平台
supported代码完整且已实测Windows
unverified代码完整但未在真机验证,行为可能与文档有出入macOS
unsupported明确未实现,调用会得到清晰报错(不是静默失败)Linux

升级后必须做什么

本包是双面的,两半的生效方式不同——升级后没变化,先看这里:

改了什么生效方式
lib/client.js(浏览器半边:按钮、剪贴板监视、门控)硬刷新页面 Ctrl+Shift+R(普通刷新可能仍用缓存)
lib/index.js(宿主半边:工具、四条路由)重启 DSH(宿主进程加载时才注册路由)
cvision/*.py(Python 侧)每次调用是新子进程,一般即改即生效;但常驻 Python server 会继续用已加载的旧模块——重启宿主最稳

升级方式:dsh plugin --profile web add(重新装)/ rm 后再 add;或换成新的 Release tarball。

装/升级前需要先关掉 DSH 吗? v0.2.16 起不需要。若你遇到过这条错误:

[ERR_PNPM_EPERM] [importPackage …\node_modules\vision] EPERM: operation not permitted,
  rename '…\vision_tmp_23816_2' -> '…\vision'

根因是插件自己拉起的常驻 Python 子进程(python -m cvision.cli_server)以安装目录为工作目录, 而 Windows 下「进程的当前目录」就是该目录上的一个句柄 → pnpm 无法把临时目录替换成 node_modules/vision。 现在子进程的 cwd 改为系统临时目录、靠 PYTHONPATH 找到包内源码,任何子进程都不再持有安装目录, 于是可以边跑边升级。

⚠️ 但从 ≤0.2.15 升到 0.2.16 这一次仍然要先关 DSH(旧版本还在用旧行为)。

配置(可选)

默认即可用;如需覆盖:

  • CVISION_PYTHON:Python 可执行文件,默认 python。
  • CVISION_DIR:cvision 项目根(含 cvision/ 包)。默认 = 本插件安装目录(包内捆绑版);若不用包内 副本,可指向仓库根。

插件 spawn 的所有 Python 都强制 PYTHONUTF8=1 + PYTHONIOENCODING=utf-8(否则中文窗口标题在 Windows 下会乱码,v0.2.2 修)。

构建与测试

DSH 运行时只加载 JS,仓库已提交构建好的 lib/:

  • lib/index.js ← src/index.ts(tsc 编译,宿主半边:工具 + 四条路由);
  • lib/client.js ← src/client.js(逐字节拷贝)。它不能交给 tsc:本包 "type": "module" 会让 tsc 把它 当 ES 模块并在末尾追加 export {},而 DSH 以经典脚本加载该文件,export 会直接语法错误 (见 scripts/copy-client.mjs)。
npm ci
npm run build        # tsc -p tsconfig.json && node scripts/copy-client.mjs
npm run test:js      # node --test:客户端半边 + 宿主四条路由
npm run check:dsh    # DSH 组合包/客户端契约自检(30 项)
npm run check:docs   # 文档一致性自检(14 项)
npm run check:deps   # Python 依赖锁定自检(9 项)
python -m unittest discover -s tests -v   # Python 纯逻辑单测(仅需 Pillow)

当前规模:JS 68 条 + Python 188 条。

文档约定(自动校验)

文档漂移靠人记不住,所以 npm run check:docs 把下面这些变成断言(CI 每次都会跑):

断言防止的漂移
package.json 版本 == README 头部版本 == CHANGELOG 最新条目改了代码忘了升版/记条目
CHANGELOG 最新条目有实质内容、无 TODO/待填占位条目混进发布
README 里的长按阈值 == src/client.js 的 LONG_PRESS_MS(且不残留旧值)改了行为忘了改文档(真的发生过:550ms → 900ms)
cvision/、tests/、scripts/ 下每个文件都出现在 README 目录结构里新增文件忘了写文档(也真的发生过)
全部顶层文档都在 package.json 的 files 里新文档没随包发布
README 覆盖宿主注册的全部工具与全部路由加了工具/路由却没有文档
README 声称的测试条数 == 实际条数测试增减后数字过期
README 内部锚点都能落到标题目录断链
requirements.txt 每条依赖都有下界与上界(npm run check:deps)依赖被静默升级到破坏性版本(供应链面失控)

CI / 发布

.github/workflows/ci.yml 在每次 push / pull_request 时:

  • npm ci && npm run build,并校验 lib/ 与源码编译产物一致(改了 src 却忘编译会失败);
  • npm run check:dsh(30 项契约)+ npm run check:docs(14 项文档一致性)+ npm run check:deps(9 项依赖锁定);
  • npm run test:js(客户端半边 + 宿主路由);
  • Python 单测跑在 ubuntu + macOS 矩阵(仅装 Pillow,不需要桌面);
  • windows-latest 冒烟:按 requirements.txt 真装依赖,再断言 backend=windows、 platform_support=supported、ok=true。加它的原因:上面两个平台装不了 pywin32/winsdk,于是 Windows 后端的关键路径(WGC / PrintWindow / 窗口枚举)在 CI 上从不执行——这一条至少保证 「用户照 README 在 Windows 上装完不会立刻报缺依赖」。

Python 依赖的定期审查

requirements.txt 每条都是双向锁定(见 STORE 契约),上界取「下一个可能破坏兼容的 边界」。代价是上界不会自己变,所以约定:每季度审查一次——

npm run check:deps -- --list   # 打印当前每条依赖的锁定区间

审查点两条:上游是否已发新主版本(该不该跟进);上界是否过紧导致安全修复进不来。 pywin32 尤其注意:官方明确建议固定(任意一次 build 号增加都可能有接口破坏),所以它锁到下一个 build, 每次官方发版都得显式决定要不要跟。

⚠️ 预发布包的上界必须写「下一个预发布号」,不能写它的正式版本。 winsdk>=1.0.0b10,<1.0.0 看着合理, 实际装不上:PEP 440 下 <1.0.0 会排除预发布版,于是把唯一可用的 1.0.0b10 也排除了。这个坑 在 v0.2.17 真实踩过(Windows 上 pip install 直接失败,直到 v0.2.19 的 windows 冒烟 job 才发现)。 现在 check:deps 有一项断言专门盯它。

发布:推一个 v* tag → 构建+测试通过后自动 npm pack 出 vision-<version>.tgz 并创建 GitHub Release:

git tag v0.2.14
git push origin v0.2.14          # ⚠️ 一次只推一个 tag,见下

⚠️ 踩过的坑:一条 git push origin v0.2.6 v0.2.7 … v0.2.13 连推多个 tag 时,GitHub 没有为这些 tag 创建任何 workflow run(actions/runs?branch=<tag> 的 total_count=0),Release 自然也不会生成;逐个 推(或分批、间隔几秒)才可靠。判据:git ls-remote --tags origin 有 ref ≠ 有 run,要看 Actions 页面。

装 Release 产物:npx -y @deepseek-ai/dsh plugin --profile web add <下载目录>\vision-0.2.14.tgz。

内部 CLI 契约(维护者)

宿主半边用 child_process 调这些 python -m 入口,stdout 恒为一行 JSON(ensure_ascii=True), 契约比退出码更重要——非零退出时宿主仍会读 stdout(v0.2.6 的取消路径 bug 就出在这)。

入口参数结果
cvision.cli_capture--list / --screen-info / --status / --window / --handle / --region / --delay / --format / --text / --wait-changed截图时是裸 data URL 字符串(不是 JSON);--list/--screen-info/--status 是各自的 JSON;--text → {ok:true,kind:"capture_text",data_url,width,height,elements:[{text,box,center,screen_box,screen_center,word_count}]};--wait-changed → {ok:true,kind:"wait_changed",data_url,changed,samples,elapsed_ms,diff_ratio,mean_diff,diff_bbox}
cvision.cli_ocr--window / --handle / --region / --delay{ok:true,text,lines,words:[{text,x,y,w,h}]}
cvision.cli_input--click/--double/--move/--scroll/--scroll-h/--drag/--type/--keys/--focus/--focus-handle/--get-clipboard/--set-clipboard动作类 {ok:true};--get-clipboard → {text}
cvision.cli_snip--timeout 60 / --format{ok:true,data_url}(退出 0)/ {ok:false,reason:"cancelled"}(2)/ "unsupported"(3)/ "error"(1)
cvision.cli_clipboard--state / --image{ok:true,supported,image,token,reason} / {ok:true,data_url}、{ok:false,reason:"empty"|"unsupported"|"error"}

cli_capture 这一行以前写错过:它被写成返回 {ok:true,data_url,width,height},实际截图路径输出的是 裸 data URL(宿主 runCliCapture 就当整串是 data URL)。现在表格以代码实际行为为准,并由 test_cli_server.py / test_cli_ocr.py / test_cli_input.py 三份契约测试盯住——cli_server 的 JSON-line 协议此前一行测试都没有,而它是宿主唯一的常驻通道。

另有常驻进程 cvision.cli_server:stdin 逐行收 JSON 请求、stdout 逐行回响应,复用 WGC 的 D3D 设备与 编码器(避免每次工具调用冷启动解释器)。op:ping / capture(text:true 时返回可点击元素)/ wait_changed / ocr / list / screen_info / status / clipboard_state / quit。 宿主优先走它,失败自动回退到上面的 CLI。

⚠️ 宿主的请求超时是 45s(v0.2.19 从 30s 提高):wait_changed 会在 Python 侧阻塞到画面变化或 超时,这个上限必须大于它,否则常驻进程会被自己的超时回收,白等一场还回退到 CLI。

目录结构

vision/                      # 仓库根 = 插件本体
  src/index.ts           # 宿主半边源(工具 + 四条 /cvision/* 路由)
  src/client.js          # 客户端半边源(经典脚本:截图按钮 + 剪贴板监视 + 门控)
  lib/index.js           # tsc 编译产物(DSH 实际加载)
  lib/client.js          # 客户端产物(scripts/copy-client.mjs 逐字节拷贝,不能过 tsc)
  scripts/
    copy-client.mjs      #   把 src/client.js 拷到 lib/
    check-dsh-contract.mjs #  DSH 组合包/客户端契约自检(30 项,CI 跑)
    check-docs.mjs       #   文档一致性自检(14 项:版本号/阈值/目录/工具/路由/测试数/锚点,CI 跑)
    check-deps.mjs       #   Python 依赖锁定自检(9 项:上下界/具体版本/预发布上界/重复/marker,CI 跑)
  tsconfig.json          # TS 配置
  package.json           # 声明 dsh.bundle + dsh.client,files 含 lib/cvision/requirements.txt/CHANGELOG
  cordis.patch.yml       # bundle 的配置层,按包名引用
  requirements.txt       # Python 依赖(全部双向锁定 >=x,<y:Pillow/pyautogui/pyperclip;Windows 加 pywin32/winsdk;macOS 加 pyobjc;需 Python 3.10+)
  cvision/               # 捆绑的 Python 版 cvision(截屏/OCR/用户级输入/系统截图/剪贴板)
    __init__.py          #   包标记
    capturer.py          #   兼容层:转发到平台捕获后端
    capture/             #   平台捕获后端(门面,按 sys.platform 选)
      __init__.py        #     选后端并暴露 list_windows/capture_window/capture_screen
      base.py            #     平台无关 Window + CaptureBackend 协议
      windows.py         #     Windows 后端(WGC > PrintWindow > 读合成桌面区域)
      macos.py           #     macOS 后端(Quartz 枚举 + screencapture -l)
      linux.py           #     Linux 后端(Phase 2 占位)
    detect.py            #   纯逻辑判定(GPU 类/空白帧),不依赖 win32,可跨平台单测
    coordinates.py       #   图片像素 → 屏幕绝对坐标(裁剪/窗口/多屏/DPI 四层换算)
    ui_elements.py       #   词框合并成可点击元素(同行相邻词合并 + padding + 屏幕坐标)
    diff.py              #   帧间差异度量(灰度缩略图 + 变化占比 + 变化区域),供 wait_until_changed
    diagnose.py          #   窗口跟踪诊断(默认关闭、零开销):定位「抓图是否挪动了窗口」
    encoding.py          #   PIL -> data URL;crop_region;fit_for_attachment(附件缩图)
    screen.py            #   显示器/DPI 布局(Windows/macOS;Linux 回退 PIL 单屏)
    status.py            #   运行环境探针(平台后端/OCR/依赖/能力清单)
    ocr.py               #   OCR(Windows.Media.Ocr 优先 / pytesseract 回退)
    input.py             #   用户级输入(pyautogui)+ focus_window(仅 Windows;只置前不改尺寸)
    snip.py              #   系统级区域截图(人工通道):拉起系统截图 UI、识别取消、取回框选结果
    clipboard.py         #   剪贴板图片读取 + 「是否变了」判定(Windows/macOS;Linux Phase 2)
    cli_capture.py cli_ocr.py cli_input.py cli_snip.py cli_clipboard.py cli_server.py
  tests/
    test_detect.py test_encoding.py test_ocr_words.py test_pick_window.py test_screen.py test_status.py
    test_input.py         #   置前语义(假 win32:最大化绝不被降级)+ 能力清单按平台
    test_cli_ocr.py       #   cli_ocr stdout 契约(词框透传/字段形状/缺字段兜底/--region 转发)
    test_cli_server.py    #   **常驻 server 的 JSON-line 协议**(响应形状 + 真 spawn 进程往返)
    test_cli_input.py     #   cli_input 参数层(13 个子命令 → input 函数的逐条映射)
    test_coordinates.py   #   坐标换算(DPI/裁剪/窗口/多屏/负坐标)
    test_ui_elements.py   #   词框合并成可点击元素(同行相邻合并/间距切分/坐标换算)
    test_diff.py          #   帧间差异(相同/微变/实变/尺寸变化 + 阈值边界)
    test_clipboard_race.py #  剪贴板竞态回归(用户占用期间复制的内容绝不被覆盖)
    test_capture_foreground.py #  抓图前的窗口准备:普通窗口不碰前台/最小化窗口会被置前
    test_diagnose.py      #   窗口跟踪诊断(改动字段判定 / 开关 / 关闭时不写文件 / 写失败不抛)
    test_snip.py          #   系统截图 CLI 的 JSON 契约
    test_snip_windows.py  #   取消识别(假时钟/覆盖层/剪贴板:取消立即返回、晚到图片不算本次)
    test_clipboard.py     #   剪贴板模块与 CLI 契约(平台分支 / empty / unsupported / error)
    vision.client.test.mjs #  客户端半边单测(门控/截图与回退/剪贴板监视与长按/失败可见)
    vision.host.test.mjs   #  宿主四条路由单测(能力判定 + 系统截图 + 剪贴板状态/取图)
  README.md  CHANGELOG.md

注:MCP server 相关的 config.py/deepseek.py/server.py 已从捆绑包移除(插件截屏无需它们,也免去了 DEEPSEEK_API_KEY 依赖)。

故障排查

现象先看这里
截图按钮不显示当前模型是否收图(inputModalities 不含 image 时按设计隐藏);cvision_status();控制台 [vision] 日志;若出现两个按钮,是旧插件 @deepseek-ai/dsh-client-ui-screenshot 仍在挂载
点按钮没反应控制台 [vision] … 一定给了原因(插入链的失败在 v0.2.4 起不再静默);附件栏被拒时会自动重试 6 次
按钮变蓝、长按却没插入长按阈值 0.9s;按住时应看到底部进度条;按钮未点亮时按住不做任何事(按设计)
单击截图后按钮变蓝已由 served 归属解决(v0.2.10/0.2.11);若仍出现,见 README「取消与归属」的时序说明
取消了截图,之后别的截图却进了附件栏v0.2.13 起修复(覆盖层判据);若先前的旧版本仍在跑,重启宿主
工具报 python 找不到 / 依赖缺失装 Python 3.10+ 与 python -m pip install -r requirements.txt;v0.2.18 起首次调用会直接给出带绝对路径的安装命令;cvision_status() 会列出缺哪个模块
抓窗口是黑图/空白未装 winsdk 时 WGC 不可用,会回退 PrintWindow/桌面区域;装 winsdk 后最准(微信等 Qt 窗口属已知空白帧场景)
抓图后窗口位置/大小变了(如分屏被破坏)用内置窗口跟踪诊断取证,别猜:$env:CVISION_TRACE_WINDOWS='1'; $env:CVISION_TRACE_FILE='C:\Temp\cv-trace.jsonl' → 复现一次 → python -m cvision.diagnose。日志按阶段(prepare/wgc/printwindow/grab_region)记录 rect/showCmd/zoomed/iconic/foreground 的前后值,能区分「抓取过程中动的」与「抓取前后被别的因素动的」。默认关闭、零开销
中文窗口标题匹配不上v0.2.2 起所有 Python 子进程强制 UTF-8;若自行调用 Python,请一并设 PYTHONUTF8=1
升级后行为没变见升级后必须做什么:客户端半边要硬刷新,宿主半边要重启
plugin add 报 ERR_PNPM_EPERM … rename '…vision_tmp_…' -> '…vision'安装目录被占用(≤0.2.15 的插件 Python 子进程以它为 cwd)。先关 DSH 再装;0.2.16 起不会再有此问题(cwd 已改为系统临时目录)
macOS 上窗口标题为空需在「系统设置 → 隐私与安全 → 屏幕录制」授权

说明与限制

  • 跨语言:插件用 child_process 调包内 Python 做截屏/OCR/输入,需目标机器有桌面环境与 Python 3.10+。
  • 截图后端:capture_window 依次尝试 Windows Graphics Capture(真实合成内容,抓 GPU/Chromium/被遮挡 窗口最准,需 winsdk)→ PrintWindow → 读合成桌面区域(兜底,此时才可能置前,抓完立即还原)。
  • 附件限制:Harness attachment 单图源 ≤20MiB、单边 ≤8192px、每条消息 ≤20 张;输出前会自动缩放到限制内 (encoding.fit_for_attachment),超大屏也不会被拒。
  • 省 token:region="x,y,w,h" 只处理一块;ocr 直接返回文本;超大图自动降采样。
  • 无出站网络:所有捕获/OCR/输入都在本地完成。
  • 输入类工具(click/type_text 等)会真实操作你的鼠标键盘;调用前请先 see 确认坐标。
  • macOS/Linux 后端为编写实现,需在对应平台 + 权限下验证;未支持平台上的边界由各工具显式报错。

DSH STORE 上架契约

下面每一条都由 npm run check:dsh(scripts/check-dsh-contract.mjs)机械校验,CI 每次都会跑;对应 DSH 文档 docs/user/develop/basic/publish.zh.md(组合包 manifest)与 docs/subsystems/client-modules.zh.md(客户端半边)。

依赖

  • Node 运行时:无 npm 运行时依赖(dependencies 为空)。
  • 内置组件:包内捆绑 Python 版 cvision(cvision/**/*.py)+ 依赖清单 requirements.txt;运行时跨语言 调用该 Python 子进程做截屏/OCR/输入,CVISION_DIR 默认指向包内。这是本插件唯一的独立供应链面,由 DSH STORE 供应链复查把关。
  • Peer:@deepseek-ai/dsh-tools、@deepseek-ai/cordis——由宿主提供,且两者本来就是本仓库的 devDependency(因此 npm ci 不需要额外下载)。lib/index.js 运行时只 import 前者(cordis / dsh-attachment / node:http 都是 import type,编译后不残留);ctx.tools / ctx.attachments 由宿主注入。
  • 宿主入站路由:四条,都通过 ctx.inject(['webServer', ...]) 可选挂载,组合里没有 web 服务器时整段跳过。
    • GET /cvision/model-capability:只读、同源、无副作用、不回传任何凭据,供浏览器半边判断当前模型是否 收图。
    • POST /cvision/snip:仅 POST、仅同源(Origin host 必须等于 Host,否则 403),拉起系统截图 UI 并 把用户框选的那张图回传(200 图片字节 / 204 用户取消 / 501 平台不支持)。抓屏动作由用户在系统 UI 里完成, 本路由只读「调用之后新出现」的剪贴板图片,因此不构成静默抓屏能力;客户端断开(关页/取消)会中止等待中的 Python 子进程。
    • GET /cvision/clipboard:只读、廉价(只查剪贴板格式 + token,不解码图片),供页面每秒轮询「剪贴板里 有没有图片」,并附 served 标记(这张图是不是我们自己刚产出的)。不回传图片内容本身。
    • POST /cvision/clipboard/image:仅 POST、仅同源,返回剪贴板里的图片(200 图片字节 / 204 没有图片 / 501 平台不支持)。注意:它让页面里的脚本(含其它客户端插件)也能读到剪贴板图片——这是「按钮要看见 其它软件的截图」的固有代价,故限制为同源 + 仅 POST + 只在用户长按时调用。

权限说明(真实高权限)

  • 通过跨语言 spawn 包内 Python cvision 子进程(child_process/进程管理)。
  • 用户级操作:屏幕截图、OCR、鼠标点击/移动/滚动、键盘输入/快捷键、窗口聚焦——属于设备级输入/捕获权限。
  • 剪贴板:读取剪贴板图片(仅在按钮长按时)与读写剪贴板文本。
  • 把截图写入 Harness 附件服务 ctx.attachments.saveImage(由宿主代为落盘),或返回文本。
  • 这些是插件正常工作所需的真实高权限,DSH STORE 会将其作为 user-reviewed/guarded 对待。

外部服务

  • 无出站网络:所有捕获/OCR/输入/剪贴板读取均在本地。

失败边界

  • 包内 Python cvision 缺失或 requirements.txt 依赖未安装 → see/ocr/click 等工具报错或禁用。
  • 系统级屏幕捕获/权限被拒、被遮挡窗口、无窗口 → 对应工具返回失败(不影响宿主主流程)。
  • 抓取最小化窗口会置前并抢走前台(几何抓完会还原回最小化,但前台已经被它拿走);兜底路径 (WGC 与 PrintWindow 都失败、改读合成桌面区域)同样会置前。普通窗口(前台或背景)则不改几何、 不抢前台。口径与实测值见给 AI 智能体的使用提示。
  • 被遮挡/重叠窗口的控件点不到:see(text=true) 给的 screen_center 坐标本身正确,但点击按屏幕 坐标下发、只会命中前台窗口。需先 focus_window 让目标在前。
  • 系统截图被用户取消 → 返回 204,客户端静默、不插入任何附件(v0.2.13 起不再把晚到的剪贴板图片当成本次结果)。
  • 剪贴板图片在未支持平台(Linux Phase 2)→ 返回 501,客户端按钮不监视也不提示(功能不报错)。
  • 跨平台支持不完整(macOS/Linux 为 Phase 1/2),在未支持平台上报错的边界由各工具显式给出。
  • 宿主能力/剪贴板路由不可达(Electron file:// 组合、webServer 未挂载、旧版宿主未重启)→ 浏览器半边退回 名字启发式或停止轮询(只告警一次);工具本身不受影响。

一次性 Profile 安装-启动-卸载证据

dsh plugin --profile tmp add github:cczzyy-cn/c-vision   # 作为 bundle 自动挂载
dsh profile start tmp &      # 加载 `vision` bundle,注册 see/ocr/click 等工具
dsh plugin --profile tmp rm vision
dsh profile stop tmp         # 干净退出,无残留

Related plugins

More verified plugins in vision-media.

Tool Describe Image@linxin666/dsh-tool-describe-imageModel-facing describe_image tool for the dsh web GUI: gives a text-only model image understanding by asking a vision-language model at an OpenAI-compatible endpoint to describe one image (local path, http(s) URL, or attachment reference). Hot-pluggable — Modlens@liustack/modlensPlug-in vision for text-only LLMs, powered by the free Antigravity CLIDeepseek Ivideodeepseek-ivideoiPolloWork HyperFrames Video Studio and 27 editable video templates as a native DeepSeek Harness conversation view.Codexdsh-codexChatGPT OAuth, Codex models, search, read_image URL support, and gpt-image-2 generation for DeepSeek Harness