Repository navigation
Releases: wangx-wx/dsh-channel-wechat
Release list
v0.2.7 — 只有扫码登录的那个人能用
变更
- 只有扫码登录的那个微信号能驱动这个机器人。其他人发来的消息不建会话、不执行命令、也不回复,只在插件日志里留一行带对方 id 的记录。默认零配置即可用;要授权别人,在插件页「允许使用的人」里一行填一个 id。
- 填入名单后以名单为准,登录者不再自动包含——页面上写的名单就是实际放行的人。
- 桌面端 Web app 已打开的会话,通道现在会接管它继续用,而不是在写租约冲突时把每条入站消息都丢掉(表现为「发了没反应」)。
- 「允许使用的人」支持一行一个 id 粘贴,不再被单行输入框合并。
兼容性
- DeepSeek Harness:
>=0.2.0-rc.1 - Node.js:
^22.19.0或>=24.0.0
升级提示:默认行为是只放行登录账号。若你有第二个微信号一直在用这个机器人,升级到本版本后需要把它的 id 填进 allow,否则它发来的消息会被静默拒绝。
验证
npm publish --dry-run:tarball 含lib/index.js、lib/index.d.ts、lib/client.js、两个 README、LICENSE、第三方声明与 bundle 配置。npm view dsh-channel-wechat dist-tags:latest已指向0.2.7。- 本次按用户要求跳过了
pnpm build/pnpm typecheck/pnpm test:all的全量重跑;合并前在main上跑过一次全量(61 files / 851 tests 全过)。
安装
dsh plugin --profile <profile> add dsh-channel-wechat@0.2.7完整安装、配置和已知问题见 README。
v0.2.6 — 微信里切换目录、调用技能,回复不再丢失
变更
- 新增
/cwd <绝对路径>:在微信里切换工作目录。会话的cwd写入后不可修改,所以这是「结束当前会话、在新目录开始新对话」,历史不会跟过来;切换结果跨重启保留。 - 新增
/skills:列出可调用的技能名称(只列用户可调用的)。技能现在可以直接当命令发,例如/release-workflow,这一行会作为普通消息交给模型,而不是被当作未知命令拒掉。 - 新增
/h作为/help的别名。 - 修复:回复不再只发「一句话 + 冒号」。此前每条
assistant/message里的旁白都当成回答发出去,真实会话里 46 条此类消息有 40 条以冒号结尾,而正文是永远不会发送的工具参数。现在只有一轮结束时的纯文本回答会发出。 - 修复:长回答不再整条丢失。此前超过服务端接受长度的正文会被直接拒绝(微信没有重放),现在按段落/行/句子切成多段发送,并正确闭合跨段的代码围栏。
- 修复:
ret: -2限流不再三次 1 秒重试后静默丢弃,改为识别限流后按 2s→4s→8s→16s 退避,并主动把同一 peer 的发送间隔控制在 2 秒以上。 - 修复:宿主未提供
listRecords时通道不再反复崩溃,改为报告「无法发现已存登录」并继续可用。 - 修复:关闭顺序改为先等轮次结算再 drain 回复队列,正在结算的那条回复不会再被吞掉;等待有 10 秒上限,卡死的轮次不会拖住宿主退出。
- 修复:微信里
/stop中断的轮次不再回一条空消息。
兼容性
- DeepSeek Harness:
>=0.2.0-rc.1 - Node.js:
^22.19.0 || >=24.0.0
目录切换后沙箱写入边界仍按会话创建时的 cwd 判定,这是 Harness 侧行为,已在 commands 文档 记录。
验证
pnpm test:all:60 个文件 / 828 项通过(含真实 launcher 的集成测试)pnpm typecheck:通过pnpm build:通过
安装
dsh plugin --profile <profile> add dsh-channel-wechat@0.2.6完整安装、配置和已知问题见 README。
v0.2.5 — 通道长期运行、卡片提权与输入状态
变更
- 修复:通道不再在启动满 24 小时后静默停止轮询。此前运行上限是代码里的默认值,生产路径从未覆盖,到期后循环正常退出、没有任何报错。
- 新增:审批卡增加第 3 个选项「本会话全部权限」,可直接把当前会话切到
danger-full-access,等同于发送/permission danger-full-access。该预设捆绑approval: never,因此本会话之后不再弹审批卡;/new会按配置的权限重新创建会话。 - 新增:生成回复期间在微信显示「对方正在输入」,每 5 秒续期一次。票据获取失败或状态上报被拒时静默跳过,不影响回复。
兼容性
- DeepSeek Harness:
>=0.2.0-rc.1 - Node.js:
^22.19.0 || >=24.0.0
验证
pnpm test:all:58 个文件 / 732 项通过(含依赖已构建 DeepSeek Harness checkout 的集成测试)pnpm typecheck:通过pnpm build:通过
安装
dsh plugin --profile <profile> add dsh-channel-wechat@0.2.5完整安装、配置和已知问题见 README。
v0.2.4 — 微信里查看与切换模型
变更
- 新增
/models:按供应商列出当前部署真实的可用模型,并标出插件当前配置的那一项。 - 新增
/model <provider/model>:在微信里切换本插件使用的模型,下一条消息即生效,不需要/new。 - 修复
/help在微信里挤成一行:现在每条之间空一行,并带上各命令自己的说明。 - 升级文档新增「先 remove 再装、必须带版本号」一节,并补上微信内命令参考。
兼容性
- DeepSeek Harness:
>=0.2.0-rc.1 - Node.js:
^22.19.0 || >=24.0.0
/model 只写本插件自己的 provider/model 两个字段,不会改动 GUI 的默认模型,
也不影响 GUI 里已打开的会话。
验证
pnpm test:all:677 项通过(unit 563、integration 114),0 失败 0 跳过pnpm typecheck:0 错误- 集成测试运行在打包版 DSH
0.2.1-rc.2上 npm publish --dry-run:12 个文件,含lib/index.js、lib/index.d.ts、lib/client.js
安装
dsh plugin --profile <profile> add dsh-channel-wechat@0.2.4已安装旧版本的 profile 需要先 remove 再装(只写包名会被现有版本范围满足,pnpm 不会升级)。
装完完全重启 DSH。详见 安装说明。
v0.2.3 — 修好 0.2.2 里没生效的退出修复
这个版本修的是 0.2.2 里没生效的修复。
0.2.2 这个 tag 含有「把 abort 信号传进长轮询」的改动,却不含「Channel 真正读取该信号」的那一半——于是关桌面端/升级时仍会撞上:
Host did not complete graceful task teardown
(exit null, signal SIGTERM, shutdown acknowledged true, graceful deadline exceeded true)
已发布版本不能重发,只能由新版本覆盖。实测:SIGTERM → 74ms 退出。
安装 / 升级
# 必须先完全退出桌面端(profile 被 Electron 独占)
dsh plugin --profile <你的 profile> remove dsh-channel-wechat
dsh plugin --profile <你的 profile> add dsh-channel-wechat@0.2.3必须写 @0.2.3。 只写包名会被现有版本范围满足,pnpm 判定「无需变更」→ 原样重装旧版,并报成功。
变更
| 类型 | 内容 |
|---|---|
| fix | Channel 读取宿主传入的 signal;SingleRun.stop() 等待收尾而不是只 abort |
| fix | 空闲 sleep 与回复重试 timer 加 unref():重试拖尾 2002ms → 1ms |
| feat | 「检查更新」改为按钮触发,宿主侧不缓存;点一次就是真查一次 |
| feat | 插件发现元数据:dsh-plugin 关键词、icon、locale/*.json、市场索引 |
插件市场
https://wangx-wx.github.io/dsh-channel-wechat/market/index.json
路径:插件 → 实验性插件 → 更多 → 自定义插件市场 → 发现 → 添加索引源。
兼容性
engines.dsh 下界 >=0.2.0-rc.1,刻意不设上界。已验证运行时:
| DSH 版本 | 集成测试 |
|---|---|
0.2.1-rc.2(当前打包桌面端) |
111 项全通过,跳过 0 |
0.2.1-rc.1 |
全通过 |
0.2.0-rc.2 |
全通过 |
数据落在哪里
| 内容 | 路径 |
|---|---|
| 聊天记录 | ~/.dsh/sessions/(永不删除;/new 只是换会话目录) |
| 插件状态 | ~/.dsh/channel-wechat/ |
| 诊断日志 | ~/.dsh/channel-wechat/log/(保留 7 天) |
| 凭证 | DSH 凭据服务 |
已知问题
- 出站文件的
svr_id引用与message_id精度仍在观察(见 plan-v1 §Q45) - 更新必须由你手动执行命令:宿主进程内的插件管理器这条路会以
already-installed拒绝,实测走不通
许可
MIT。微信协议层移植自腾讯 @tencent-weixin/openclaw-weixin(MIT),署名见 THIRD_PARTY_NOTICES.md。
v0.2.2 — 检查更新、Windows 路径修复
新增
- 插件页的「版本与更新」卡片:检查 npm 上的新版本,发现后给出可直接复制的更新命令。
命令用当前进程的绝对路径拼成(不依赖PATH),并带上--config.minimumReleaseAge=0——
不带它,pnpm 会拒绝安装刚发布的版本,而「新版本」恰恰就是刚发布的。 - 桌面版给出 App 自带的
dsh:终端dsh管理desktopprofile 会被启动器直接拒绝。
修复
- Windows 上填不进工作目录:
D:\workspace\coding\dsh-ws被判为「必须是绝对路径」,
保存按钮禁用。判定现在按 DSH 自己的规则,接受 POSIX 绝对、盘符限定、完整 UNC 三种写法;
D:foo(盘符相对)与\foo仍拒绝——会话cwd记录后不可改,不能存依赖进程状态的路径。 - 出站文件名拼接(同一假设的第二处):绝对 Windows 路径曾被拼成
D:\ws\D:\ws\out.xlsx,
不报错,文件就是不发送。现在也按平台分隔符拼接。
为什么更新要手动执行命令
实测过三条路,只有一条是安全的:
| 路径 | 结果 |
|---|---|
进程内 pluginManager.installBundle |
拒绝:already-installed |
先 removeBundle 再装(官方页面做法) |
报 failed,但包还在 dependencies,已从 bundles 摘除 |
CLI dsh plugin add <包>@latest |
✅ 直接替换,bundle 保持选中 |
第二行最糟:插件从 GUI 消失,而没有任何提示指向这件事。官方已有同一缺陷的报告
(#9936),当前最新版仍未修。
所以卡片给的是那条不会弄坏 profile 的命令。
执行前请完全退出 DSH,装完再重开。
验证
- 单元 532 项、集成 104 项、
tsc干净 - 5 次变异验证全部被捕获
- 在真实 web profile + 独立
DSH_HOME上安装0.2.2并启动:两条新路由均正确应答,
current是从安装的 manifest 读出的运行时值
完整安装:dsh plugin --profile <你的 profile> add dsh-channel-wechat@0.2.2
v0.2.1 — 版本号跟随 DSH,修长轮询 teardown
安装
dsh plugin --profile <你的 profile> add dsh-channel-wechat@0.2.1装完完全退出并重启 DSH(见下方「已知问题」)。
刚发布的版本可能被 pnpm 的观察期策略跳过,装到上一个版本。
@latest不管用,
真正的开关是--config.minimumReleaseAge=0:dsh plugin --profile <你的 profile> add dsh-channel-wechat@0.2.1 --config.minimumReleaseAge=0
这个版本改了什么
版本号改为跟随 DSH
从本版起,版本号是 <DSH 主>.<DSH 次>.<我们自己的补丁号>:0.2.x 配 DSH 0.2 那一代。
补丁号完全归我们——DSH 发 0.2.2 我们不改号,只有本插件自己有改动才 +1。
兼容下界由 engines.dsh 声明
"engines": { "dsh": ">=0.2.0-rc.1" },刻意不设上界。
DSH 一旦看到 engines.dsh 就只用它判定兼容性,@deepseek-ai/dsh-* 的 peer 范围不再参与。
不设上界是因为:加了天花板,DSH 每发一个新版本、本插件未重发之前用户就装不上——
对通道插件来说,「立刻不能用」比「在未实测版本上运行」更糟。
| DSH 版本 | 能否安装 | 是否已验证 |
|---|---|---|
0.2.0-rc.2(打包桌面端) |
✅ | ✅ 99 项全通过 |
0.2.1-rc.1 |
✅ | ✅ 99 项全通过 |
0.2.x 其余 / 0.3.x / 1.x |
✅ | |
0.2.0-rc.1 以前 |
⛔ 安装时被拒绝并说明原因 | — |
修了一个真缺陷:长轮询没被中止
桌面端更新时报 Host did not complete graceful task teardown。
根因是在飞的 fetch 没被 abort,配合一个 ref'd 的 setTimeout,事件循环不退出。
原实现只「race 一个超时」——那只释放等待它的循环,没中止请求本身。
实测:改前约 114ms 结束循环、然后进程存活 10 秒以上;改后 119ms 干净退出。
升级注意
0.1.x → 0.2.x 属跨次版本,按 npm 语义是 breaking。 另外旧版不带
engines.dsh、新版带,兼容性判定口径会变。所以:
# 先完全退出桌面端(profile 被 Electron 独占)
dsh plugin --profile desktop remove dsh-channel-wechat
dsh plugin --profile desktop add dsh-channel-wechat@0.2.1必须写 @<版本>:只写包名的话,新版本本就满足现有的 ^0.1.x 范围,
pnpm 会判定「无需变更」→ 原样重装旧版并报成功。
已知问题
装完必须完全退出并重启。 Host 启动时若插件包不在 node_modules,它不会进入
boot graph,插件页的配置区会完全不出现,且不显示任何错误(客户端负缓存是永久的)。
重启自愈。这与装的是哪个版本无关。
从插件页安装后也可能看到同样的现象——这是常态,因为 Host 早就在跑,pnpm 之后才把包装上。
数据落在哪里
| 用途 | 路径 |
|---|---|
| 微信会话 | <DSH_HOME>/sessions/(永不删除;/new 只是换一个会话目录) |
| 插件状态 | <DSH_HOME>/plugins/channel-wechat/ |
| 诊断日志 | 同上,保留 7 天 |
| 微信登录凭证 | DSH 的 ctx.credentials 存储 |
做与不做
做:文本/图片/文件消息的双向收发、斜杠命令、交互卡片、出站文件(只发
deliverables/presented 声明的,绝不扫描目录)、按 peer 持久化会话、/new 换届。
不做:群聊、/cwd、/reconnect(已注册但会明确回复未实现)。
许可
移植自腾讯 @tencent-weixin/openclaw-weixin(MIT),内联 qrcode-generator(MIT)。
完整署名见 THIRD_PARTY_NOTICES.md。
v0.1.3 — 插件页内配置默认模型与会话权限
安装
dsh plugin --profile <你的 profile> add dsh-channel-wechat@0.1.3装完重启 DSH。从旧版本升级请先 remove 再 add(见 docs/release.md §四之二)。
本版新增:插件页内配置模型与权限
插件详情页的「设置」里新增两个字段,都只作用于微信会话,不影响 GUI:
- 默认模型 —— 从当前环境实际可用的模型列表里选(实时读取,不硬编码)。
留空表示跟随配置文件的默认模型。修改只影响之后新建的会话:会话一旦建立,
它记录的模型不可改写,这与cwd的语义一致。 - 微信会话权限 —— 三档:仅查看 / 工作区内修改 / 完全权限。
⚠️ 「完全权限」会关闭微信的审批卡。 该档位在 DSH 里的定义是
sandbox: danger-full-access+approval: never,而never会在本插件的审批卡之前就判定,
所以卡片不再出现。因此选择它时必须先在弹窗里勾选确认。日常建议用「工作区内修改」。
权限改动同样只作用于之后新建的会话,尊重你在会话中用/permission做的临时调整。
一直在做的事
- 微信 ↔ DSH 文本、命令、
/stop:/goal、/compact等原生命令直接在微信里用 - 媒体双向:收图、引用、出站文件(真机验证)
- 审批卡 / 提问卡:微信里批准或回答;
cards: wechat时 GUI 不重复弹卡 - 插件页内扫码登录 / 退出,无需翻日志找链接
数据落在哪里
| 内容 | 位置 |
|---|---|
| 聊天记录 | ~/.dsh/sessions/<cwd 转义>/channel-wechat-<peerId>[~g<N>]/ |
| 插件状态 | ~/.dsh/channel-wechat/(游标 + 会话代次) |
| 诊断日志 | ~/.dsh/channel-wechat/log/channel-wechat-YYYY-MM-DD.log(留 7 天) |
| 登录凭证 | ~/.dsh/.credentials.yaml |
日志留 7 天,但聊天记录永不删除 —— /new 只是换一个会话目录。
已知边界
- 微信端可用
/permission danger-full-access自己放宽权限(该命令是 DSH 原生的,本插件转发所有非本地命令)。它写的是会话持久事件,重启仍在,但/new后重置。本通道按设计是单方的,操作者即用户,故保留此行为。 - 引用自己的消息时只拿到
svr_id,显示为「引用的消息内容未能读取」;引用 Agent 的消息正常。 message_id服务端是 uint64,本插件声明为number,仅影响一条错误日志里的数字。
不做的事
群聊(协议无依据)、多账号运行期、消息去重/节流、主动推送、自建权限体系。
许可与致谢
协议规范与部分实现来自腾讯 openclaw-weixin(MIT);
工程实践参考 wechat-claude-code(MIT)。见 THIRD_PARTY_NOTICES.md。
v0.1.2 — GUI 内登录与配置,插件只占一行
安装 / Install
dsh plugin --profile <你的 profile> add dsh-channel-wechat@0.1.2
⚠️ 升级必须带@0.1.2,并且先remove再add。
只写包名的话^0.1.1已满足新版本,pnpm 会判定「无需变更」→ 原样重装旧版并报成功。
详见 docs/release.md §四之二。
本版新增
1. 登录搬进 GUI
不用再去日志里翻登录地址。侧边栏 Plugins → dsh-channel-wechat 的插件页里直接有:
- 当前连接状态(显示已连接的账号)
- 登录微信 → 页内显示二维码 → 手机扫码 → 需要验证码时页内输入 → 已连接
- 退出登录(先停轮询再删除凭证)
2. 配置可在 GUI 里改
同一个页面下方是 cwd 与 cards 的表单,保存写回 profile 的 cordis.patch.yml,不必手改 YAML。
cwd 的不可变性在页面文案里写明:修改只影响之后新建的会话。
3. 插件在 profile 里只占一行
之前是两行(dsh-channel-wechat/startup + 通道本身),GUI 上因此显示两张卡片。
现在合并成一行;没有 GUI 的 profile(如 headless)上 dsh <profile> login/logout/status 照旧可用。
修复的真实缺陷
logout 从来没有真正删除凭证。 旧实现调 modifyRecord(key, async () => undefined),
而 DSH 的 credentials 契约里 mutator 返回 undefined 的含义是「保持记录不变」,不是删除。
于是「登出」一路报成功,token 却还在 store 里——下次普通启动会继续以用户刚登出的账号轮询。
现在用 deleteRecord,并补了回归测试。
数据落在哪里
| 内容 | 位置 |
|---|---|
| 聊天记录 | ~/.dsh/sessions/<cwd 转义>/channel-wechat-<peerId>[~g<N>]/session.v4.jsonl.zstd |
| 插件状态 | ~/.dsh/channel-wechat/(游标 + 会话代次) |
| 诊断日志 | ~/.dsh/channel-wechat/log/channel-wechat-YYYY-MM-DD.log(留 7 天) |
| 登录凭证 | ~/.dsh/.credentials.yaml(DSH 凭证体系,非本插件私有) |
聊天记录永不自动删除——/new 只是换一个会话目录。
已知问题
- 引用自己的消息时微信客户端只发
svr_id,显示为「(引用的消息内容未能读取)」;引用 Agent 的消息正常 message_id在协议里声明为number而服务端是 uint64(仅影响超过 2^53 时的引用还原)cards: both且微信先答时,GUI 那张卡会滞留到该轮结束/cwd、/reconnect已注册但未实现,会明确回复
不做的事
群聊(协议无依据)、多账号运行期、主动推送、独立 HTTP 面板、自建权限体系。
致谢与许可
MIT。协议层移植腾讯官方 @tencent-weixin/openclaw-weixin(MIT, Copyright (C) 2026 Tencent);
内联的 qrcode-generator 2.0.4(MIT, Kazuhiko Arase)。详见 THIRD_PARTY_NOTICES.md。
v0.1.1
修掉两个会让每条微信消息都失败的缺陷。0.1.0 在真实环境里装得上、能加载、路由能响应 —— 但收不到任何回复。
修复
1. 插件把 DSH 核心包装进了 profile(严重)
@deepseek-ai/schemastery 之前声明为 dependencies,于是 pnpm 在 profile 里装了一份实体副本,
与安装自带的同名同版本副本并存:
3.18.4 inode 12121912 profiles/<name>/node_modules/@deepseek-ai/schemastery
3.18.4 inode 12148791 profiles/node_modules/@deepseek-ai/schemastery
同版本、不同 inode = 两份物理模块图。 cosmokit 里的
Symbol.for("cosmokit.volatile.write") 是 cordis 响应式系统的底座,
于是插件注册的 effect 落在 Host 的 agent-loop 永远看不到的实例上:
inbound message failed: no agent factory registered (load an agent-loop plugin)
inbound message failed: cannot create effect on inactive context
版本号完全一致,所以任何版本检查都发现不了。 已改为 peerDependencies
(由 Host 闭包提供)。修复后 profile 的 node_modules/@deepseek-ai/ 为空。
2. 登录地址是唯一不落盘的诊断
登录地址原先走 console.log —— 桌面端 host 的 stdout 交给 Electron 主进程,
没有终端也不写日志。而日志文件只在「有账号可轮询」时才创建,所以首次使用时
既看不到地址、也没有日志目录。现已改走 reporter,终端与日志文件双写。
升级
add 不会升级已满足版本范围的依赖,必须带版本号:
# 先完全退出桌面端
dsh plugin --profile <name> remove dsh-channel-wechat
dsh plugin --profile <name> add dsh-channel-wechat@0.1.1装完自查(第二项非空即说明缺陷仍在):
grep '"version"' <profile>/node_modules/dsh-channel-wechat/package.json
ls <profile>/node_modules/@deepseek-ai/数据位置
| 内容 | 路径 |
|---|---|
| 会话记录 | ~/.dsh/sessions/<cwd>/channel-wechat-<peerId>/session.v4.jsonl.zstd |
| 插件状态 | ~/.dsh/channel-wechat/ |
| 诊断日志 | ~/.dsh/channel-wechat/log/(每日一个文件,保留 7 天) |
已知问题(记录,未修)
- 引用自己的消息时客户端只给
svr_id,显示占位文字;引用 Agent 消息正常 message_id声明为number(服务端为 uint64),当前仅影响一条错误日志- 默认模型不可用时插件不会在启动时报错,直到第一条消息才 400
- DSH loader 的诊断(如
name mismatch)只写 stderr,桌面端不可见
取舍与实测数据见 docs/plan-v1.md §Q45/Q50/Q51/Q52。
致谢与许可
MIT。协议层移植自腾讯 openclaw-weixin(MIT),
详见 THIRD_PARTY_NOTICES.md。