dsh-wechat
perrylink/dsh-wechat
Bridges WeChat private messages to DSH with two-way text, image, file, and media transfer, aiming to restore the native DSH experience in WeChat.
インストール
dsh plugin --profile web add github:perrylink/dsh-wechatREADME
dsh-wechat
本仓不发布 npm 包。 npm 上的裸名
dsh-wechat属于上游pan17/dsh-wechat,不是本仓代码; 安装只走 GitHub / Gitee 源码通道(见安装)。
让微信成为 DeepSeek Harness (DSH) 的第二客户端:通过腾讯 iLink bot 协议把
微信私聊桥接到 DSH agent——文本/图片/文件/语音消息双向收发、微信内 slash
命令管理会话/工作区/Preset/模型/权限、DSH 设置页内扫码登录与连接配置。以
静态 Cordis 插件交付,零运行时 @deepseek-ai 依赖,直接调用 DSH 进程内服务。
审批/提问卡经原生 approval/request / user-questions/request waterfall
桥接,微信与 GUI 双端同卡、谁先回答谁生效(0.8.0 起恢复;见兼容性
的已知代价说明)。

兼容性
在 DSH 主版本 dsh-v0.1.5-alpha.1(GitHub tag;宿主 checkout 19d2e38480)上
通过 2026-09-09 本仓门禁链核验:typecheck + test(32 文件 / 370 用例)+
build + npm pack。profile 安装冒烟(L4)未执行。本插件零 @deepseek-ai
运行时依赖,不声明 peer 依赖,通过 ctx.get(...) 读取进程内服务。
- 会话日志世代化文件名:宿主按会话格式版本命名落盘文件
(
sessionFormatLogFilename)——session.v3.jsonl.zstd(0.1.5)→session.v2.jsonl.zstd(0.1.3)→session.v1.jsonl.zstd→session.jsonl.zstd(未版本化的 v0),压缩关闭时为同名.jsonl。本插件 按此顺序从新到旧枚举、只读不写,因此不需要迁移;但 0.1.5 明确「不读旧、 也不被旧读」,用旧 DSH 打开 0.1.5 写出的 profile 仍会失败。 ctx.agent已移除:0.1.5 起 agent 通过setup(agentCtx, agent)的 第 2 参传入(AgentSetup,ebce3a5f04起);本插件同时保留 ≤0.1.4 的ctx.agent回退,两代宿主都能挂载 preset 与模型路由。- 审批/提问卡走 answerer waterfall(0.8.0):0.1.2-rc.1 起
apiProxy包 与其 mux 帧流被移除(4f00a8b82a),旧接线空转;现在本插件在根 context 以{ prepend: true }注册approval/request与user-questions/request回答者,随后立即next()放行下游(GUI/ACP 卡片照常弹出),把「下游 结果」与「微信回复」竞速——谁先给出有效结果谁生效。prepend是硬约束: cordis 按注册顺序执行 waterfall,api-remotes 在自己的 apply 里注册 GUI 转发 且第三方插件行排在其后,不抢链首则回答者永不被调用。 已知代价:微信先答只结算宿主 waterfall,不结算网关 pending——浏览器里 那张卡不会自动消失,会挂到请求signalabort 为止(GUI 先答则微信卡立即 撤除)。零回答者时提问回退NO_PROVIDER、审批回退'unavailable'; 策略never在分发前即返回'rejected',回答者根本不会被调用。 /history读面(0.8.0):内存路径改用Session.snapshotEvents()(回退ownEvents()),持久回退改用sessionQuery.readSurface()(回退readSession());listEvents()返回的SessionEventRecord不带data,永远无法还原文本,已不再用于历史。合成注入(runtime context、 skill 正文、goal 续跑等source.kind === "plugin"的 user 事件)按 GUI 侧栏同款规则过滤,不计入用户轮次。/status权限行(0.8.0):permissionPresets.current()现在传会话对象 (宿主签名current(session: Session),读会话的permissions投影), 0.1.2-alpha.2 起即如此;旧实现传事件数组会抛错并被吞成「不显示该行」。- npm 通道不适用:本仓不发布 npm 包。npm 裸名
dsh-wechat属上游pan17/dsh-wechat(latest0.9.2),dsh plugin add dsh-wechat装到的是 上游包,不是本仓代码——安装请走下面的源码通道。
功能
- 发送 — 微信文本/图片/文件/语音消息 → DSH agent(媒体自动下载解密到
~/.dsh-wechat/tempfile/,本地路径作为附件注入) - 接收 — agent 回复文本回微信;
send_wechat工具可主动推送文本/文件到微信 - 微信 slash 命令 —
/workspace、/session、/preset、/model、/perm、/silent、/notify、/next、/status、/stop、/rp、/rq等 由 bridge 直接处理(见下方命令表) - 审批/提问卡(双端同卡) — 微信与 GUI 弹一致的原生审批/提问卡,
谁先回复谁生效(0.8.0 起经原生
approval/request/user-questions/requestanswerer 桥接;微信先答时浏览器侧卡片不会自动 消失,见兼容性)。 - 微信渠道提示词(动态注入) — 微信消息注入「通过微信」提示;GUI 消息时自动消失
- 静默模式 —
/silent on后每轮只发送最终回复,设置页可切换 - 繁忙时投递(与 DSH 同源) — 按
busyEnter排队/插话;微信/enter同步 - 跨会话通知 — 后台会话的已完成/报错/卡片通过微信提醒,
/notify on|off|status切换,默认关闭(单用户单闸) - 二维码登录 —
http://127.0.0.1:3080/wechat/qr扫码登录,设置页内嵌 - 设置页 UI — DSH 设置 → WeChat:单卡展示状态、扫码、退出登录、连接配置与通知/静默开关(保存即生效,存储于
~/.dsh-wechat/config.json与state.json) - 断点续传 —
sync-buf与微信会话映射持久化,重启 DSH 后自动恢复会话 - 单用户 — 只服务第一个微信用户;bot token 缺失/失效时不向微信推送,日志会写明原因(需重新扫码或等会话恢复)
安装(部署到 DSH profile)
⚠️ 本仓不发布 npm 包,
dsh plugin add dsh-wechat装的是别人的包。 npm 上的裸名dsh-wechat属于上游pan17/dsh-wechat(latest0.9.2); 本仓是PerryLink/dsh-wechat(GitHub)/gitee.com/perrylink/dsh-wechat(Gitee 镜像),只通过源码通道分发。
DSH 自带插件管理命令 dsh plugin(在 profile 目录转发 pnpm,并自动把
声明了 dsh.bundle 的依赖加入 bundle 层)。插件入口是 dist/index.js,
而 dist/ 不入库,所以先克隆并构建:
# 1) 克隆 + 构建(GitHub 或 Gitee 任选其一)
git clone https://github.com/PerryLink/dsh-wechat.git # 或 gitee.com/perrylink/dsh-wechat
cd dsh-wechat
npm ci && npm run build # tsc → dist/(含 dist/client.js、dist/dsh/session-log.cjs)
# 2) 以本地路径安装(自动添加依赖 + 注册 bundle 层)
npx @deepseek-ai/dsh plugin --profile <profile> add file:D:/path/to/dsh-wechat
# 3) 验证组合配置
npx @deepseek-ai/dsh --profile <profile> --dump-config # 应看到 "- id: dsh-wechat" 行
# 4) 重启 DSH(必须),然后:
# - 浏览器打开 设置 → WeChat:扫码登录、查看状态、改配置
# - 或直接打开 http://127.0.0.1:3080/wechat/qr 扫码
⚠️ 别用
npx dsh plugin——npm 上dsh这个名字早在 2016 年就被一个不相关的 JS shell 包占了(dsh@1.0.1,作者infusion),它没暴露 CLI bin,会报could not determine executable to run。DSH 的 CLI 在 scoped 包@deepseek-ai/dsh下,必须用完整名。
更新与卸载:
# 更新:拉取 + 重新构建后重启 DSH(file: 依赖指向该工作副本,无需重新 add)
git pull && npm ci && npm run build
# 卸载(从 bundles 移除)
npx @deepseek-ai/dsh plugin --profile <profile> remove dsh-wechat
dsh plugin add github:PerryLink/dsh-wechat目前不可用:pnpm 安装 git 依赖时只运行prepare脚本,本仓未声明该脚本,装出来会缺dist/。请用上面 的本地构建 +file:路径。修改代码后需重启 DSH 才能让改动生效。
微信命令
与 DSH 原生命令同步
点击展开:bridge 如何接入 DSH 的 ctx.commands 注册中心(计划模式 / 目标 / 压缩 等原生 slash 命令走的就是这条路)
微信消息进入后,bridge 先向 DSH 的 ctx.commands 注册中心查询当前会话
已注册的命令(这是 DSH 内置的人类 slash 命令注册服务,由 @deepseek-ai/dsh-commands
提供;name /plan、name /goal、name /compact 等命令都由各自的 bundle 在那里
注册)。命中即直接交给原生 handler 执行,并把结果回执渲染到微信——和 GUI 走同
一条命令管线。
未注册的命令回落到本仓库硬写的本地命令表(/silent、/next、/rp、/rq、
/workspace、/session 等),命中失败时按 "未知命令" 提示并作为文本转发给 agent。
DSH 的 ctx.commands 服务在某些极简装配下可能不挂载(缺失时会打一次 warn),
这种情形行为完全等同之前的版本。
所以:DSH 加任何新的 /xxx 命令 bundle,微信端无需改动即可识别——只要它是
按 DSH 命令注册契约挂上去的。例如装有 dsh-plan-mode 时微信发 /plan off 收
到原生回执 "Plan mode off.";装有 dsh-command-goal 时 /goal <目标> 收到原生
"Goal created ...";装有 dsh-command-compact 时 /compact 收到 "Compacted N
history items (~M tokens)."——与 GUI 同款回执,由原生 handler 自己算、自己发。
/help 在末尾加一段 ── DSH 原生命令(当前 profile 已注册)──,列出当前
profile 实际注册的所有原生命令;本地命令表里已有的名字自动去重,不会重复
出现。
本地命令表
| 命令 | 说明 |
|---|---|
/help(/h、/?) | 帮助 |
/status | 当前状态:工作区、会话、Agent、待处理提问/权限卡、当前会话 Preset、模型、上下文、权限、默认 Preset、静默、繁忙投递、跨会话通知;末尾追加 DSH 通过 ctx.sessionProjections 注册的所有会话级状态,分四段显示——[模式](plan / goal / subagent / todos)、[用量与统计](tokenUsage / contextPressure / contextBreakdown / sessionStats / subagentTiming)、[会话](title / sessionListMetadata / permissions / imageLimits)、[其它](未识别 key 自动归类);DSH 加新 plugin 自动出现 |
/workspace (ws) — list | status | switch <编号|路径> | add <路径> | 工作区管理(list 显示各工作区会话数,不含已归档;switch/add 回复会写明恢复的会话名字和完整 id,跳过已归档;该目录无可见会话时提示发送消息将创建) |
/session (s) — list [current] | switch <编号> | new | status | 会话管理(list 最近 20 个,标记当前,不显示 GUI 已归档会话;current 只看当前工作目录;switch 回复同时带会话名字和完整 id;new 复用当前工作区空白会话,与 GUI「新建会话」同款,无空白才新建) |
/preset (p) — list | switch <名称|编号> | status | 默认 Preset(写入 DSH 设置,与 GUI 同步;status 看全局默认,不是当前会话;当前会话无内容时 switch 立即应用) |
/model — list [提供商] | switch <提供商/模型> | status | 模型管理(切换立即作用于当前会话 + 设为默认;当前推理等级若新模型支持则一并保留,否则清空) |
/perm — status | list | switch <名称|编号> | default [名称|编号] | 权限管理(switch 实时切当前会话;default 写 DSH 设置,新会话生效) |
/reasoning — [list | default | switch <等级>] | 推理等级:查看当前/默认与模型支持的等级;switch <等级> 切换(实时 + 写默认);default 恢复模型默认 |
/enter queue|steer|status(/busy) | 繁忙时投递:agent 运行中收到微信消息时排队(queue)还是插话进当前轮次(steer);读写 DSH 设置 ui-conversation.busyEnter,与 GUI「繁忙时 Enter 键行为」同源同步;空闲会话始终新开一轮 |
/silent on|off(/sl) | 静默模式:开启后 agent 每轮的中间过程输出(工具调用、思考等)不再逐条推送,只在轮次结束时发送最终回复,避免刷屏;跨重启持久化,设置页可切换 |
/notify on|off|status(/watch) | 跨会话通知:后台会话的已完成/报错/卡片提醒,默认关闭(单用户单闸,设置页可切换) |
/history [数量] | 查看最近历史消息(默认 5 条,最多 20 条);当前会话有未回答的提问/权限卡时会完整重发,可直接回复 |
/stop | 中断当前任务 |
/next | 继续发送因微信限制被缓存的消息 |
/rp / /rq | 拒绝所有待处理权限卡 / 提问卡(微信端) |
其他 /xxx 命令作为文本转发给 agent;审批/提问卡双端同弹,已在其他端
处理的卡会提示(微信先答时浏览器侧卡片需等请求 abort 才消失,见
兼容性)。
所有命令均直接映射 DSH 原生服务(workspaceRegistry / sessionQuery /
agentPresets / agentDefaultModel / permissionPresets),默认值与 GUI
设置页同源同步。
架构
微信 (iLink) ── long-poll getupdates ──► dsh-wechat (Cordis host plugin)
▲ │
│ ◄── sendText/sendMedia ──────────────┤
│ ▼
│ DSH 进程内服务(零 @deepseek-ai 运行时依赖)
│ agents.create/resume ── agent.followup(消息入)
│ session/event ── assistant/message、turn/end(消息出)
│ approval/request、user-questions/request(waterfall,{ prepend: true })
│ ── 回答者持有 promise,立即 next() 放行 GUI/ACP,双端竞速
│ Session.snapshotEvents / sessionQuery.readSurface ── /history
│ permissionPresets.current(session) ── /status 权限行
│ tools.register ── send_wechat 工具
设计说明:微信端是 GUI 的第二客户端,功能不多也不少。
设置页(DSH 设置 → WeChat)
客户端半部通过 dsh.client + exports["./client"] 声明(与 dsh-mcp-manager
同款交付),挂载到 settings.section slot(nav 顺序 40):
- 状态卡 — 登录阶段(未登录/等待扫码/已扫码,待确认/已登录/登录失败)、Bot ID、
监控运行状态、已绑定用户数,与
跨会话通知/静默开关同卡展示 - 扫码 — 未登录时页面内直接显示二维码,扫码确认后自动进入已登录
- 操作按钮 —
重新扫码(清除 token 重新登录)、退出登录,与保存配置同行 - 连接配置 — baseUrl / cdnBaseUrl / botType / cwd /
textChunkLimit / cardTimeoutMs / 跨会话通知(全局)/ 静默;保存即生效,
网关参数变更会自动重启长轮询;存储于
~/.dsh-wechat/config.json与state.json
与宿主通信走插件自己的 HTTP API(/wechat/api/status|config|relogin| logout),客户端零 @deepseek-ai 依赖。
配置
优先级:内置默认 ← 插件行 config: ← ~/.dsh-wechat/config.json
(设置页写入,覆盖前两者)。插件行可带 config::
# 例:追加到 profile 的 cordis.patch.yml
- id: dsh-wechat
config:
cwd: 'C:\projects\my-project'
| 键 | 默认值 | 说明 |
|---|---|---|
baseUrl | https://ilinkai.weixin.qq.com | iLink 网关 |
cdnBaseUrl | https://novac2c.cdn.weixin.qq.com/c2c | 媒体 CDN |
botType | "3" | iLink bot 类型 |
storageDir | ~/.dsh-wechat | token/sync-buf/会话映射/临时文件 |
cwd | process.cwd() | 新会话工作目录 |
textChunkLimit | 4000 | 微信单条消息长度上限 |
cardTimeoutMs | 1800000 | 提问/权限卡软超时(30 分钟) |
crossSessionNotify | false | 跨会话通知总闸(已完成/报错/卡片,单用户) |
开发
npm install
npm run typecheck # tsc --noEmit
npm run build # tsc → dist/(+ scripts/copy-client.mjs 复制 client 与 session-log.cjs)
npm test # vitest(32 个测试文件 / 370 个用例)
已知边界
0.8.0 修复的存量死缝(此前三项均静默空转)
以下三项都不是 0.1.5 回归,而是本插件早于 0.1.2 的旧接线在当前宿主上已空转; 0.8.0 逐条修复:
- 审批/提问卡不出现 —— 旧实现用
ctx.inject(["apiProxy"], …)订阅events.mux帧流、并用apiProxy.respond()回注决策;apiProxy包已被移除 (4f00a8b82a,含于dsh-v0.1.2-rc.1),inject 永不回调。现在改为在根 context 以{ prepend: true }注册approval/request/user-questions/request回答者:立即next()让 GUI/ACP 卡片照常弹出, 再与微信回复竞速。/rp、/rq、卡片回复重新有效。 残留:微信先答时浏览器侧卡片不会自动撤除(网关 pending 只由浏览器回包 或signalabort 结算);子 agent 发起的提问受宿主DELEGATED_CALLER守卫,不会进入本回答者。 /history恒空 —— 内存路径依赖不存在的agent.session.events,持久回退sessionQuery.listEvents又不带data。现在改用Session.snapshotEvents()(回退ownEvents())与sessionQuery.readSurface()(回退readSession()),并过滤source.kind !== "user"的合成注入。/status权限行缺失 ——permissionPresets.current(events)形状过时; 宿主签名是current(session)(读permissions投影),0.1.2-alpha.2 起即 如此。现在直接传会话对象;服务缺失或抛错时该行仍按原样省略。/preset switch的「空白会话」判定同源修正:改用Session.seq === 0(旧的session.events?.length === 0恒为 false,导致 preset 从不应用到 空白会话)。
其他边界
send_wechat工具对所有 agent 可见;任何会话的 agent 都能调用——绑定会话发送到绑定用户,未绑定会话回退到首个已知微信用户(单用户部署默认行为)。 单用户模式下,工具推送与 assistant 回复共享唯一一份微信 10 条/窗口限流预算:超限或发送失败自动进入/nextFIFO 缓存队列。计数和队列持久化到state.json,普通 DSH 更新或重启后继续沿用;下一条微信入站会重置窗口并自动补发。微信真实限流响应(HTTP 200 +ret: -2/prepare failed)也会被识别并缓存,不再误判成功。/preset switch遵循 DSH 约束:只有未产生任何内容的会话才能当场recompose;已有内容的会话会提示 Preset 应用于下一个新会话。默认 Preset 本身写入 DSH 设置文档(agent-presetsnamespace),GUI 设置 页与微信双端读写同一事实源。- iLink 通道是腾讯官方 bot 协议,接口可能随官方调整;跟随 wechat-opencode
上游的
src/weixin/修复即可。
许可
MIT。src/weixin/、src/adapter/ 移植自
wechat-opencode(MIT,
原始来源 @tencent-weixin/openclaw-weixin),文件头保留出处注释。
PerryLink DSH Plugin Family
这是 PerryLink 维护的 37 个 DeepSeek Harness 插件 之一。如果它能帮到你,其他的也会:
| Plugin | One-liner |
|---|---|
| dsh-auto-review | 审批链上的第二模型自动审查,默认失败关闭 |
| dsh-background-agents | 带 Web UI 侧栏、消息与中断的持久后台子代理 |
| dsh-budget | DeepSeek Harness 的成本治理:预算、碳排与延迟一屏呈现。 |
| dsh-checkpoint-rewind | Claude Code /rewind 等价:快照、会话 fork、一次性恢复 |
| dsh-claude-move | 把 Claude Code 会话、记忆、技能与 CLAUDE.md 迁入 DSH |
| dsh-click | 跨平台原生桌面控制(DeepSeek Harness),Windows 优先。 |
| dsh-composer-history | Web 输入框的终端式历史:方向键、Ctrl+R 搜索 |
| dsh-data-quality | 数据集质量检查与引文核查(本插件可选消费的数字核查桥) |
| dsh-defend | DeepSeek Harness 的提示注入、越狱与密钥泄露防护。 |
| dsh-doublecheck | 工程纪律守卫:需求质询、测试门禁、对手评审 |
| dsh-draw | DeepSeek Harness 的统一静态图像生成路由。 |
| dsh-fast | DeepSeek Harness 只读性能诊断。 |
| dsh-fund-research | 面向中国公募基金的确定性研究报告 |
| dsh-github | 面向 DSH 的 GitHub PR/issues 集成,每次写入经审批门控 |
| dsh-industry-research | 行业研究编排,经本插件的 ctx.researchReport.assemble 封存交付物 |
| dsh-library | DeepSeek Harness 的本地文档知识库。 |
| dsh-local-ai | DeepSeek Harness 的本地模型(Ollama)接入。 |
| dsh-lsp-actions | 通过语言服务器的 LSP 诊断、格式化、补全、代码操作与重命名 |
| dsh-mask | PII 脱敏中间件:模型边界匿名化、展示层还原 |
| dsh-mcp-panel | 只读 MCP 运行时面板:/mcp 命令 + 带状态、工具与错误的 Settings 标签页 |
| dsh-memento | 审批门控的跨会话记忆:ctx.memory 接缝 + SQLite + 记忆工具 |
| dsh-observe | DeepSeek Harness 的 OpenTelemetry 与 Langfuse 可观测导出器。 |
| dsh-output-styles | Claude Code outputStyles 等价的运行时风格切换 |
| dsh-permission-rules | Claude Code 风格声明式 allow/deny/ask 权限规则,带审计 |
| dsh-personal-directive | 个人指令注入器:顶栏开关(框架版) |
| dsh-plugin-guide | 作为按需代理技能的插件开发知识库 |
| dsh-reach | 多渠道审批/提问桥接:微信/Telegram/飞书,会话控制台 |
| dsh-research-report | 可验证研究报告引擎:内容寻址证据账本与封存版本 |
| dsh-score | DeepSeek Harness 插件的多维质量评分。 |
| dsh-session-pin | 在 Web 侧栏置顶会话,带持久排序 |
| dsh-session-sync | DeepSeek Harness 的跨设备会话同步——会话存储的专用 git 镜像。 |
| dsh-skill-pack-security | 安全审计技能包:密钥扫描、依赖与供应链审查 |
| dsh-talk | DeepSeek Harness 的语音优先会话闭环:对它说,听它答。 |
| dsh-test-drive | DeepSeek Harness 插件的隔离试装冒烟。 |
| dsh-translate | DeepSeek Harness 的厂商参数翻译与确定性 JSON 修复。 |
| dsh-ticktick | TickTick/滴答清单任务桥接:会话头面板 + 11 个工具 |
免责声明
本项目与 DeepSeek Harness、腾讯微信官方互不隶属,非官方项目, 纯属个人学习用途。使用本项目即表示你自行承担由此产生的一切后果。