dsh-cherry-bridge
Manifest validDeepSeek Harness plugin bridging to Cherry Studio desktop instances over remote transport
English | 简体中文
dsh-cherry-bridge
把 DeepSeek Harness 桥接到 Cherry Studio 桌面端 — DSH 插件
在 DSH 会话里直接驱动局域网内 Cherry Studio 的 agent:配对、列设备/会话、读历史、 发消息并等待终态、应答审批与提问卡、取消执行;附一个同源设置页管理设备与工具启用范围。
flowchart TB
T["DSH 会话<br/>14 个 cherry_* 工具"] --> P
W["设置页<br/>设备 · 配对 · 启用范围"] --> P
P["dsh-cherry-bridge<br/>连接池 · 订阅缓存 · 作用域"]
P <-->|"ws:// · Noise XX"| C["Cherry Studio 桌面端<br/>二维码配对 · 审批"]
- 包名:
dsh-cherry-bridge - 插件 id:
cherry-remote(呼应协议发现类型remoteDiscoveryType的 mDNS 服务标识) - 传输:
ws://+ Noise XX(加密由 Noise 记录层提供,不依赖 TLS 终止) - 工具面:14 个
cherry_*工具 - 启用范围:这 14 个工具按工作区启用,默认谁都没有(见下文「启用范围」)
- HTTP 面:宿主 Web 服务器上的同源前缀
/cherry-remote/api
安装
DSH 版本需求:
>=0.2.0-rc.2 <0.3.0-0(由package.json的engines.dsh声明,DSH 的插件兼容门会据此检查;不满足时安装/启用会被拒绝——bundle 被跳过、行被禁用;确需在区间外使用可用dsh plugin allow-version精确豁免。0.3.0 需重新评估兼容性后再放开)。
# 从 GitHub 安装(推荐)
npx @deepseek-ai/dsh plugin --profile web add github:SAXEM1997/dsh-cherry-bridge
# 钉住版本标签(生产推荐)
npx @deepseek-ai/dsh plugin --profile web add github:SAXEM1997/dsh-cherry-bridge#v0.1.3
# 或从 npm registry 安装
dsh plugin --profile <name> add dsh-cherry-bridge
或以 bundle patch 方式合入 profile —— 本包自带 cordis.patch.yml,其中已声明插入行
cherry-remote 与默认配置(见下文「配置」)。package.json 的
dsh.bundle.patch 指向该文件,dsh-plugin-manager 据此自动插入插件行。
profile 手工加行等价于:
- id: cherry-remote
name: 'dsh-cherry-bridge'
config:
perSessionCacheBytes: 2097152
rateBudgetPerSecond: 32
首次配对
- 在 Cherry Studio 桌面端打开 remote access → 添加设备:该界面显示的是二维码, 配对信息(地址、端口与一次性邀请)要点开扫码后的页面才看得到。
- 扫这个二维码(微信、浏览器等均可),把扫码后页面上显示的配对信息复制下来。
- 在 DSH 里调用
cherry_pair(设置页向导亦可),粘贴这段配对信息。 - 双向核对 6 位验证码:
cherry_pair结果与设置页都会醒目展示该代码,请与桌面端 显示的数字人工比对一致后再在桌面端批准。 - 批准后设备档案写入插件数据目录(
devices.json,权限0600),其desktopIdentity被 pin 住;此后每次连接都校验 Noise 对端静态公钥与 pin 一致, 防止二维码被劫持后的中间人替换。
配置
| 键 | 类型 | 默认 | 说明 |
|---|---|---|---|
dataDir | string | $DSH_HOME/cherry-remote(回退 ~/.dsh/cherry-remote) | 插件数据目录,存放 identity.key 与 devices.json(均 0600)。 |
perSessionCacheBytes | number | 2097152(2 MiB) | 每个会话的本地订阅事件缓存字节上限。超出时按 LRU 丢弃最旧事件并 warn 记录。 |
rateBudgetPerSecond | number | 32 | 每设备二级平滑请求预算(请求/秒)。桌面端实现的硬上限是 64 req/s 且无协商通道(2.1.5 起 agent.content.read 另有 512 req/s 的独立窗口),超限会以 close 1011 终止整条会话;这里取保守值。 |
⚠️
cordis.patch.yml的config是整体替换,不与 bundle 默认值合并。装配层 (resolveBridgeConfig)对缺键回落上述默认值——因此删掉一个键得到的是插件默认 值,不是 profile 里别处的值。缺键与非法值是两回事:键存在但不可用(0、负数、 字符串)会按名warn后回落。
工具
| 工具 | 作用 |
|---|---|
cherry_devices | 列出所有已配对设备及其连接状态(connected/connecting/offline/disabled/identity-mismatch)。 |
cherry_agents | 列出某设备上可用的 agent(分页)。 |
cherry_workspaces | 列出某 agent 的已注册工作区,以及是否存在系统工作区。 |
cherry_sessions | 列出某 agent 的会话,可按工作区过滤。 |
cherry_read | 读取会话的消息历史快照(两级基线:agent.sessions.get + agent.messages.list/agent.parts.list;parts 按每条消息自身的 revision 读取)。附件部件只回 name/mediaType/byteLength 与空 content——字节不取。消息从新到旧排列(messages[0] 是最新的一条),因此 limit 丢掉的是最旧的消息;被截断的走查一定会说明(truncated 为 true,并带 truncationReason),messagesResumeCursor 用于续读更旧的消息;消息走查的截断只丢更旧的消息,绝不切开已返回消息内部的 parts(parts 走查熔断是另一层:partsTruncated 丢的是该消息较后的 parts)。某条消息自身的 parts 没能读全(有 part 带 unavailable,或 parts 走查熔断而带 partsTruncated)时,该消息带 incomplete: true,若有不可读的 part 还带 unavailableParts 计数——这是消息的内容判定,与走查是否截断无关。 |
cherry_events | 读取该会话缓冲区内比 cursor 更新的事件,并在投递后 ack。 |
cherry_create | 在 agent 工作区创建会话(工作区选择必填;创建后经 agent.sessions.get 回读身份)。 |
cherry_send | 向会话发消息,默认等待运行到终态并返回助手文本;wait: false 立即返回命令回执。内容被截断时 messagesTruncated/messagesTruncationReason 说的是消息被截断(丢更旧的消息),返回的消息内部不会被切开;返回的消息自身 parts 没读全则带 incomplete。 |
cherry_wait | 只等待该会话在途执行收敛(不发送新消息)。 |
cherry_interactions | 列出该会话待答的交互卡(提问 / 审批)。 |
cherry_respond | 应答交互卡:提问必须全量作答,审批走 decision。 |
cherry_cancel | 取消会话在途执行(expectedExecutionId 必填)。 |
cherry_pair | 用「扫码后页面显示的配对信息」建立与桌面端的配对。 |
cherry_unpair | 解除配对:断开连接并从设备档案删除。 |
设备选择器(device 参数)接受精确 deviceId,或 deviceId 前缀 / 显示名前缀
(两者合并匹配、按 deviceId 去重);前缀命中多项时返回结构化歧义错误(ambiguous-device
candidates),不会任选一个;一个都没命中时返回not-found+known(已配对设备的deviceId列表),而不是候选为空的歧义。cherry_devices以结构化结果原样返回这两种判定; 其余工具检索不到设备时 抛错而非返回判定对象。档案被隔离(archive-quarantined)优先于 上述一切。
cherry_send(wait: true) / cherry_wait 返回的 status 有 8 个取值:四个协议终态
(completed/failed/cancelled/interrupted)之外,还有四个 waiter 自己的判定——
awaiting-interaction(软终态:出现待答交互卡,运行仍活着)、timeout(窗口用尽,
不是失败,返回已到达的部分内容与续读游标)、idle(cherry_wait 遇到没有在途执行
的会话,立即返回当前快照)、subscription-lost(等待途中事件订阅丢失且重建失败,运行
结局从此处不可知:与 timeout 不同,随附修复订阅/按 id 回读运行的指引)。
错误与恢复语义
- 传输丢失分读写两面。 读方法在重连后单次配速重放(新的一次到达、重新过一遍
配速);二次丢失或连接生命周期结束(teardown)则返回结构化的 lost 错误,不会无限重试。
命令永不重放:
cherry_send/cherry_create/cherry_respond/cherry_cancel这类 写操作丢失应答时,调用方携原commandId重试即可——桌面端的命令账本会回放原回执, 同一 id 配不同正文才报幂等冲突。 - 单 ref 外置内容上限 32 MiB。 超过上限的 part 直接标
unavailable,该消息带incomplete: true,并在有不可读 part 时带unavailableParts计数;不返回无法校验的 部分内容。 - list 走查容忍「游标前进的连续空过渡页」至多 2 页,第 3 页即拒绝(桌面端分区切换 时的正常过渡,任何非空页都会重置计数);游标不前进或循环回已出现过的游标则直接拒绝, 不空转。
- 发布门分工:
prepublishOnly跑整条链(typecheck + 全量测试 + 两侧构建);tests/unit/artifactFreshness.test.ts另做逐字节比对——从当前源码重建到临时目录,与 已提交的dist/index.mjs/dist/index.d.mts/lib/client.js完全相同才通过。
设置页(web client)
插件同时是一个 web client bundle(package.json 的 dsh.client 声明
platform: web,导出 ./client)。它通过宿主设置页的 settings.section 槽位注册
一个 cherry-remote 命名空间页面,提供:
- 设备卡片列表:显示名、地址、连接状态灯、启用/停用、删除;
- 配对向导:粘贴扫码页显示的配对信息 → 展示 6 位验证码 → 展示终态;
- 启用范围面板:
全局/仅选定工作区二选一 + 工作区多选(标题 + 路径),见下文「启用范围」; - 实时状态:设备状态与配对进度经同源 SSE 流(
/cherry-remote/api/events)推送。
开发时可单独跑 npm run dev:ui(ui/ 下的 Vite 入口)。前提是同一个 DSH 宿主已在
http://127.0.0.1:23023 运行:该 dev server 只服务页面本身,页面调用的
/cherry-remote/api 由 ui/vite.config.ts 里的 dev-only 代理转发到宿主(SSE 也走
同一条代理,不被缓冲)。没有宿主时页面能渲染,但设备列表与事件流会报错。宿主在别的
端口时用 CHERRY_DEV_HOST=http://127.0.0.1:<port> npm run dev:ui 覆盖,不必改代码。
启用范围
14 个 cherry_* 工具按工作区决定是否出现,而不是在每个会话里都注册一遍。设置页的
「启用范围」面板(命名空间 cherry-remote,导航标签「Cherry Studio 互联」)负责编辑它。
机制是隐藏而非拒绝:不在范围的会话里,这些工具不进工具表(省上下文),而不是「看得见、
调用才报错」。
- 默认谁都没有:作用域文档不存在时按
selected+ 空列表处理——没有任何工作区拿到 这些工具。这是 fail-closed 的一侧:文档损坏 / 字段非法 / 读不出来同样落到更严的一侧, 不存在「读不出来就当全局」的退路。 仅选定工作区(selected):只有勾选的工作区里的会话才可能出现这些工具;没有工作区 的会话(cwd不属于任何已注册工作区)则始终没有(fail-closed)。全局(global):所有工作区都可见;此时面板上的勾选不参与判定(切回selected后才生效)。- 保存即时生效,含进行中的会话:保存成功后对所有 live agent 重装 / 释放限制层, 下一轮即生效——不需要重启 DSH,也不需要新建会话;取消勾选同样在下一轮消失。
- 范围只管工具:设置页与
/cherry-remote/api不受范围影响——被排除的工作区也必须能自救 (配对、改范围)。 - 能力不足时不假装:
host.state为pending(注入回调尚未到达)时面板只给中性等待提示, 不禁用保存;为unsupported(tools.register/tools.restrict/tools.schemas任一 静态能力缺失)时给只读告警、按真实缺因说明并禁用保存。两种状态下这些工具都不注册 (fail-closed),绝不退回「全局可见」。
文案边界:面板只声称「本插件未遮蔽这些工具」。上游
allow型过滤(例如子代理的toolFilter)仍可能让某个会话看不到它们——那是接受的行为,本插件不对上层过滤的结果作保证。
作用域文档与端点
作用域文档落在插件数据目录:<dataDir>/scope.json(默认 $DSH_HOME/cherry-remote/scope.json),
权限 0600、原子写入、revision 单调递增——唯一的例外是文档解析失败或字段非法:此时按更严的
一侧(selected + 空列表)重建并把 revision 归 0,文档仍可被正常写入覆盖;它不进
profile YAML(避免双真相源)。
GET /cherry-remote/api/scope 一次返回整份状态:
{
"scope": { "mode": "selected", "workspaceIds": [], "revision": 0 },
"workspaces": [{ "id": "…", "title": "…", "path": "…" }],
"staleWorkspaceIds": [],
"pathUnmatched": [{ "agentId": "…", "cwd": "…" }],
"host": { "state": "ready", "capable": true, "reason": "…", "degraded": [] }
}
scope—— 文档的三个可写字段(mode/workspaceIds/revision)。workspaces—— 注册表里的工作区(只投影id/title/path;浏览器够不到注册表本身)。staleWorkspaceIds—— 文档里勾选、但注册表已不存在的 id:由PUT修剪是清除它们的唯一 路径,界面据pruned回显清除结果,而不是报「校验失败」。pathUnmatched—— cwd 与当前一代的规范路径表不匹配的会话(agentId+cwd)。两类都记在 这里:解析成功、但规范化(realpath)后不属于任何已注册工作区的 cwd(拼写不同 / 符号链接 / 该 目录确实未注册,三者在此不可区分);以及宿主没有resolveByPath(见下面path-normalization一条)时,只按大小写敏感字符串等价比对而没命中的 cwd。 它们按「无工作区」处理:selected模式下这些会话看不到这 14 个工具;global模式下一切照常 可见(不看工作区登记),所以这条只在selected下解释「勾了却无工具」的原因;它不是降级, 也不改动勾选或mode、不触发写入。host—— 能力三态(pending/unsupported/ready,capable === (state === 'ready')) 与degraded数组({source, reason};同一来源只留最新一条,不同来源并存)。五个来源各自是:install—— 隐藏层的应用失败过;reason说明是四处里的哪一处:无参schemas()读不到 (本轮既不装也不释放任何层)、某层的释放抛错(旧层可能仍在生效)、agent 缺agent.ctx.tools.restrict、宿主拒绝了restrict()。它只累积、不被任何成功路径清除 (同来源被后一条覆盖),所以恢复之后它仍然只表示「本次会话中曾失败过一次」。workspace-list—— 工作区注册表读不到(读取失败或返回空表):判定 fail-closed、写侧拒绝; 这是五个来源里唯一会在下一次成功读取时被清掉的一个。visibility-only—— 宿主没有tools.guard,或安装它时被拒:restrict仍在装配层移除这 14 个 工具(不是渲染层假过滤),但执行侧兜底没了——没有任何一层会拒绝这些工具的调用,只算 可见性降级、不是执行边界。若某个 agent 连restrict也装不上(同一条install来源的 另一处),那个 agent 的目标工具保持可见、guard 也放行:插件隐藏不了它,只能把这件事记在degraded里。scope-version—— 文档的version与本插件支持的不一致(高于或低于皆同一条守卫):只读降级 并锁死写入(避免覆写不同格式的文档)。path-normalization—— 宿主没有resolveByPath:cwd 比对退化为大小写敏感字符串等价(不做 realpath),符号链接或拼写差异下规则二可能不命中。
PUT /cherry-remote/api/scope 是读-改-写:body 为 {mode, workspaceIds, expectedRevision},
expectedRevision 必填,就是上一次读到的 revision。成功返回 200 {scope, pruned}:
scope 是写入后的规范文档(被修剪的 id 已不在其中),pruned 是这次被修剪掉的已失效 id,返回的
新 revision 就是下一次写入的基准。失败返回 {error, message?},error 是稳定码:
| HTTP | error | 含义 |
|---|---|---|
| 400 | invalid-scope | 字段非法:mode 不是 global/selected,或 workspaceIds 不是字符串数组。 |
| 400 | missing-expected-revision | 请求没带基准 expectedRevision,或它不是有限数字(类型/取值都由同一条守卫判定)。 |
| 409 | scope-revision-conflict | 基准 revision 已过期(配置被他处改过);message 内含当前 revision。 |
| 503 | workspace-list-unavailable | 工作区注册表读不到:拒绝写入,已存勾选与 mode 一位不动(也不修剪)。 |
| 503 | scope-version-unsupported | 作用域文档的 version 与本插件支持的不一致(高于或低于都会命中同一条守卫):只读降级;重读仍是同一份文档。 |
请求体整个读不出来(非法 JSON)时仍走本模块既有的
400 invalid-request——那不是作用域 字段的裁决,故不在上表内。
HTTP 面(同源)
挂载在宿主 Web 服务器的 /cherry-remote/api 前缀下,不新增独立监听、不暴露局域网、
不设独立凭据:
| 方法与路径 | 作用 |
|---|---|
GET /cherry-remote/api/devices | 设备列表。 |
PATCH /cherry-remote/api/devices/:id | 改显示名/启用状态/地址/端口(hosts 为整体替换)。 |
DELETE /cherry-remote/api/devices/:id | 移除设备并断开其连接。 |
GET /cherry-remote/api/scope | 启用范围:作用域文档 + 注册表工作区列表 + host 诊断(见「启用范围」)。 |
PUT /cherry-remote/api/scope | 保存启用范围(读-改-写,expectedRevision 必填)。 |
POST /cherry-remote/api/pair | 启动一次配对,立即返回 202 {claimId},进度走 SSE。 |
GET /cherry-remote/api/events | SSE:device-state / pairing-progress(pairing-progress 每帧带产生它的 claimId;心跳为无载荷注释行)。 |
GET /cherry-remote/api/diagnostics | 运维诊断报告(见下)。 |
pairing-progress帧的最小形状是{stage, detail?};本插件在其上额外附带可选的claimId(跨 run 隔离用的裁定扩展,非计划内最小字段),消费方须容忍该字段缺失。
信任 fence:每个路由在动手前都自行过一遍同源判定,四分支按序为
(1) 非回环且未声明的 Host → 拒绝;(2) sec-fetch-site: cross-site → 拒绝;
(3) 附带 Origin 与 Host 非同源 → 拒绝;(4) Origin 缺失 → 放行(那是
curl 之类的非浏览器客户端,不是跨站页面)。
GET /diagnostics
汇总设备状态 / 连接统计 / 最近错误摘要,并按 §5 脱敏规则处理:
- 可出:
deviceId、显示名、状态、地址、端口、desktopIdentity的 12 位摘要、 hello 协商后的有效 limits(heartbeatMs/subscriptions/pageItems/inFlightRequests;只有存在活连接时才报——本端点从不拨号,无连接的设备既不报 limits、也不会被顺手唤醒,而不是拿客户端回退值冒充)、sessionId与会话游标(游标取自订阅层当前状态,未订阅的会话没有该字段)、stats计数器(connections/sockets/connectionsBuilt/subscriptions)、 装配层解析出的两个config键 (rateBudgetPerSecond/perSessionCacheBytes,与日志里报的是同一组数字)、 错误的 reason/message(message 在端点边界被截断到 200 字符, 见ERROR_MESSAGE_MAX); - 绝不出:
accessToken、tokenExpiresAt、invitationSecret、原始desktopIdentity、消息文本与 part 文本。
stats.connectionsBuilt是连接池自上次apply以来构建过的连接数, 不是 RPC 请求量——请求计数归传输层所有,本端点不发布同名指标以免误读。 计数器与错误环都在每次apply时清零:统计只描述当前这次装配。
脱敏是白名单投影而非黑名单过滤:报告是逐字段新建的对象,因此日后往设备档案里 新增的凭据字段会按构造被排除,而不依赖有人记得去更新一份拒绝清单。
日志
分级约定(spec §5):
- error —— 连接失败 / 认证失败 / 协议错误;
- warn —— 重连退避 / 缓存淘汰 / 订阅 LRU 驱逐;
- info —— 配对进度 / 订阅建立与恢复 / 设备状态迁移。
info 级只记阶段名与标识符(deviceId/sessionId/配对阶段),不记任何载荷。
敏感字段(token、invitationSecret、accessToken、消息内容与 part 文本)一律不入
日志;deviceId、desktopIdentity 摘要与 sessionId 可记。契约套件对一条完整的
配对→连接→发送→交互流程做了日志脱敏断言(tests/contract/contract.test.ts)。
开发
npm test # vitest 全量(含 tests/contract/)
npm run typecheck # 服务端 + UI 两侧
npm run build # tsdown → dist/index.mjs + dist/index.d.mts
npm run build:client # vite → lib/client.js
npm run dev:ui # 设置页 dev server(需宿主在 127.0.0.1:23023 运行,见上)
npm run prepublishOnly # 发布前闸门:typecheck + test + build + build:client
dist/与lib/是随仓库提交的构建产物,不是 gitignore 的输出。 改完src/或ui/后必须重跑npm run build && npm run build:client再提交,否则提交里的产物 就是旧的。这里没有prepare钩子:prepare在npm install时也会跑,而npm install --omit=dev会先剪掉 devDependencies,钩子随即因找不到tsdown/vite而失败(127)——整个安装被拖挂。产物入库后 git 安装、--omit=dev、以及对克隆目录 直接打包都无需任何构建步骤即可工作。tests/contract/contract.test.ts里的 「clean clone → pack」用例是这条的闸门:它克隆本仓库(不带node_modules),断言 克隆中已经含dist/index.mjs、dist/index.d.mts、lib/client.js,且npm pack --ignore-scripts的 tarball 里也含这三个文件。防止产物悄悄腐坏的是prepublishOnly:发布路径上它先跑 typecheck 与全量测试、再重建两侧产物。
依赖 @cherrystudio/remote-protocol@0.5.0 与 @cherrystudio/remote-transport@0.2.1
以精确版本固定(无 ^),并有测试断言锁死——升级时必须重跑
tests/contract/contract.test.ts 以防 schema drift。契约套件同时逐条建模了「本仓库
自环假对端」与「真实 Cherry Studio」的六项行为差异,并逐条对应
docs/e2e-checklist.md 中的人工核验步骤。
与 Cherry Studio 版本的对应关系
已验证的桌面端范围是 2.1.4 → 2.1.6(含 main 上 2.1.6 之后的提交),依据是逐面比对
上游 src/main/services/remoteAccess/ 与 packages/remote-{protocol,transport} 的差异:
| 上游变化 | 影响 |
|---|---|
2.1.5 起 connection.hello 增加 agentUploadsVersion/agentUploadChecksum/agentAttachmentSelections 与 5 个 agentUpload* limits | 加法,无影响:hello 无严格校验,限额按名读取(回归测试:tests/integration/connection.test.ts ①c) |
2.1.5 起记录分帧引入二进制 marker(首字节 1)承载上传块 | 加法:JSON 记录双向编码未变,本插件既不发也不收二进制 |
2.1.5 起附件按 {kind:'file', name, ref}(顶层 ref)投影,字节可经 agent.content.read 取 | 只取元数据(name/mediaType/byteLength),绝不取字节:读路径是文本通道(tests/integration/toolsRead.test.ts ④k/④l) |
2.1.5 起 agent.messages.send 要求 text trim 后非空 | cherry_send 对空白正文本地给出 text-empty,不上线(tests/integration/toolsSendGuard.test.ts) |
agent.content.read 单独放宽到 512 req/s;其余业务方法仍是 64 req/s | 本插件的 32 req/s 预算不变,仍然安全 |
| 2.1.5 起 Linux 无钥匙串时以明文 0600 存设备身份;identity 永不重生成 | 升级不需要重新配对;无钥匙串的 Linux 桌面从「不可用」变为「可用」 |
配对 payload、mDNS 广告、协议版本([1])与 Noise profile 在上游本轮更新中零改动。
上游另有 5db8ab7(agent runtime 由 DSH 换成 Pi,删除其自带的 packages/dsh-bridge)——
那是反方向的桥(Cherry 驱动 DSH),与本插件依赖的 remote-access 面无关。
zod是运行时依赖,不是可删的死依赖:本包的dist把@cherrystudio/remote-protocol作为 external,而该协议的运行时产物处处import zod(peer^4.3.4,协议包自身的 dev pin 已升到 4.4.3,不影响这个区间下界)。把它降级为 devDependency 或移除, 都会让协议包在运行时加载 schema 失败。这里精确钉在4.3.4——即 peer 区间下界, 也是协议包的测试基线。
TypeScript 钉在
~7.0.2(只放行补丁位)。已接受的风险:tsdown生成dist/index.d.mts走的是 TS 7 的实验性 dts API,该面在 minor 版本间可能变动; 限定为 patch-only 区间意味着 minor 不会在区间内静默改变这个面,升级必须显式改package.json并重跑npm run build+ 全量测试。类型面的产物随仓库提交,所以一次 坏升级会立刻在逐字节的产物闸门里现形,而不是等下游消费方撞上:tests/unit/artifactFreshness.test.ts按当前源码重建dist/index.mjs、dist/index.d.mts与lib/client.js,再与已提交的版本逐字节比对(契约套件的「clean clone → pack」用例只 断言这三个文件存在,看不到字节级的腐坏)。
说明:本仓库的
tests/loopback/fakeCherry.ts是测试内的自环假对端,不是发布物; 文档与代码注释中出现的Task N、spec §x、controller ruling、UltraReview等编号, 指向本项目内部的 SDD 过程文档(设计/任务/审查记录),不随包发布——它们只是把 「这条规则为什么长这样」的出处留在原处。发布物里docs/只含docs/e2e-checklist.md(files逐项列出,未列docs目录 本身),而docs/superpowers/**的内部过程文档被有意排除在 tarball 之外。
files里的src与ui是有意发布的:宿主侧排查(对照dist/lib的产物行为 读原始实现)与二次开发需要它们;运行时实际解析的是exports指向的dist/*与lib/client.js,src不参与加载。
发布前请走完 docs/e2e-checklist.md:Electron 端的人工批准无法 CI 化,真机流程
(配对 / 发送 / 交互应答 / 断连恢复 / 多设备并存)必须人工过一遍。
已知限制
cherry_respond允许 DSH agent 代替用户批准 Cherry 端的审批卡,存在滥用面。MVP 不再加拦截层,信任 DSH 自身的工具调用审批体系约束 agent 行为;二期可加「审批类应答 需经 DSH 侧ask_user_question确认」的 gate。- 每设备仅申请
agentcapability,不申请configuration。 - MVP 仅使用
ws://传输(加密由 Noise 记录层提供),不做 TLS 直连。
License
MIT
Comments
Loading…
From the same category
by ccch1mneyyy
DSH 官方公众号收录的 TUI 补位插件:Claude Code 风,鲸鱼顶栏/实时状态/流式思考/双击 Esc 回滚/上下文进度+TPS。npm 一键装。 DSH official WeChat featured TUI plugin — Claude Code style: whale bar, live status, streaming thoughts, double-Esc rol
★ 4.8k
↓ 11.9k/wk
MIT
TypeScript
Oct 18, 2026
dsh plugin --profile terminal add @deepseek-harness-tui/dsh-tuiby strukto-ai
The World's First Virtual Terminal for AI Agents
★ 3.7k
↓ 374/wk
Apache-2.0
TypeScript
Oct 18, 2026
dsh plugin --profile agent add @struktoai/mirage-dshby bowenliang123
The best DeepSeek Harness plugin for context insight and management, with context dashboard / browser / sidebar and context command, for context statistics, composition, breakdown, evolution details,
★ 2.3k
↓ 52.1k/wk
Apache-2.0
TypeScript
Oct 18, 2026
dsh plugin --profile web add dsh-contextby huiliyi37
官方 DeepSeek Harness 的交互式终端 UI 插件:自研 ANSI 极简交互渲染、流式 Markdown/工具卡、16+ 主题、slash 命令与选择器、输入历史与本地偏好持久化、LSP 诊断、memory记忆,很丝滑的开发体验。
★ 287
↓ 493/wk
Apache-2.0
TypeScript
Sep 30, 2026
dsh plugin --profile terminal add @huiliyi37/dsh-tianshu-tuiby Hilbert-beinghappy
面向 DeepSeek Harness 的 Claude Code 风格终端界面,支持 Windows、macOS 与 Linux,兼容透明终端、VS Code 主题和自定义配色。
★ 196
↓ 108/wk
MIT
TypeScript
Oct 13, 2026
dsh plugin --profile web add seekttyby c3cvld7aag
富江DSH完美破甲|富江破甲 DSH 本地插件,内置提示词规则,支持 Windows 一键安装、环境自动准备与一键卸载,全中文使用说明。
★ 121
JavaScript
Oct 3, 2026
dsh plugin --profile web add fujiang-armor