nicecx/dsh-relay
DSH plugin: relay approval & question requests to any chat channel — iMessage, Email, WeChat built-in; Telegram/DingTalk/Feishu/Slack via a common adapter contract (src/channels/types.js)
项目介绍Project Overview
dsh-relay 是 DSH 宿主级插件,把审批、提问和会话结束通知按编号推送到 iMessage、Email、微信等通道,可在通道内批准、拒绝、回答或注入文本,并用消息开关控制启用范围。适合离开网页仍需远程授权 DSH 任务时使用。注意 iMessage 仅支持 macOS 且需完全磁盘访问权限,微信默认关闭,Email 需自备 IMAP/SMTP 凭据。
dsh-relay is a DSH host-level plugin that relays approval requests, questions, and session-end notices to channels such as iMessage, Email, and WeChat. You can approve, reject, answer, inject text, or toggle scope directly from messages. Use it when you need to authorize DSH tasks away from the web UI. Note: iMessage requires macOS and Full Disk Access; WeChat is disabled by default, and Email needs real IMAP/SMTP credentials.
请帮我了解并安装插件:【dsh-relay】【https://github.com/nicecx/dsh-relay】
把上面这条消息直接发给当前会话里的 DSH,让它帮你了解并安装。安装命令不一定准确,发给 DSH 更稳。Send this message to DSH in your current session. CLI install commands may not be accurate across systems — DSH will figure it out for you.
或使用命令行安装(适合开发者)Or use CLI install (for developers)
命令行安装CLI Install
dsh plugin --profile web add github:nicecx/dsh-relay
把 nicecx/dsh-relay 加入你的 DSH 配置(web profile)即可启用。
READMEREADME
dsh-relay
🚀 欢迎贡献! 本项目把"诉求中转"做成通用框架:iMessage / Email / 微信 三个通道已端到端验收,Telegram / 飞书 / 钉钉 等待你来实现——按
src/channels/types.js的通道契约接入即可,详见 CONTRIBUTING.md。所有贡献需通过测试套件(见 TESTING.md)。
DSH(DeepSeek Harness)宿主级插件:把需要你授权或提供开发建议的诉求,按编号推送到 iMessage / Email / 微信等可配置通道,在通道里直接批准、拒绝或回答;功能开关与启用范围也全部通过通道消息配置。 跨会话共享(装在 profile 层,所有对话通用)。
架构基于成熟的 dsh-im-bridge(MIT)扩展:通道层与桥接层分离、持久去重、长回复分段、../!! 合并窗口均沿用其实现;编号审批应答参考 dsh-chatnode-wechat。并修正了上游在 web profile 中的两个关键问题:
approval/request监听以{ prepend: true }注册,排在网页答案器(api-proxy)之前——上游缺 prepend,在有浏览器的 web profile 里实际上拿不到审批;- 提问(ask_user_question)走
tools/execute拦截而非替换userQuestionsprovider——与网页 UI 共存,超时/未启用时next()转回网页,两不冲突。
能力
| 方向 | 内容 |
|---|---|
| DSH → 通道 | ① 审批诉求(工具名 + 原因 + 会话)② 提问诉求(选项列表,可多选)③ 会话轮次结束(完成/出错/被阻塞 + 片段,自动脱敏) |
| 通道 → DSH | #N 批准 / #N 拒绝 应答审批;#N <选项序号或文本> 回答提问;回复 #N <文本> 注入诉求所属会话;裸文本注入绑定会话。支持自然语言(见下) |
| 开关(通道内) | 开启 / 关闭(总开关)、开启 邮件 / 关闭 微信(单通道)、全部开启 / 全部关闭(所有对话)、/enable <会话id> / /disable <会话id>(单会话)、/sessions 列出会话 |
| 编号 | 每个诉求分配全局递增编号 #N,每天零点自动重置;诉求并发不冲突,回复必须带编号(仅 1 条待审批时允许裸「批准」) |
| 罗列待办 | ① 通道内发「还有哪些没处理」② 网页输入 /relay ③ 命令行 node cli.js(见下) |
语义理解回复
除了严格语法,普通自然语言也能执行(确定性规则 + LLM 兜底双保险,拿不准的文本一律按普通消息注入,绝不误执行):
- 「把 3 号批了」「同意第三个」「第2条不同意」→ 批准/拒绝对应诉求
- 「全部批准」「都拒绝」→ 批量应答所有待审批
- 「3号选2」「第三个:是」→ 回答对应提问
- 「告诉 3 号 继续跑测试」→ 文本注入该诉求所属会话
- 「还有哪些没处理」→ 罗列待办;「全部关掉」→ 全部会话停用
- 中文数字(三/十二/二十三…)与「第N个/条/项」均识别
- 规则层解析不了的疑似指令(含数字或指代词「刚才那个」),会调用默认模型做一次结构化分类;LLM 不可用/超时自动回退为普通消息
命令行罗列未回复诉求
node ~/.dsh/plugins/dsh-relay/cli.js # 罗列待回复诉求
node ~/.dsh/plugins/dsh-relay/cli.js status # 状态总览
node ~/.dsh/plugins/dsh-relay/cli.js --json # JSON 输出(脚本友好)
数据来自 ~/.dsh/dsh-relay/pending.json(插件实时落盘),只读、不连接运行时。
网页内等价命令:/relay、/relay status、/relay sessions。
安装
方式 A:从 git 安装(推荐,可获取更新)
dsh plugin --profile web add https://github.com/<owner>/dsh-relay
# 或把 "dsh-relay": "github:<owner>/dsh-relay" 加入 profile package.json 的
# dependencies,并把 "dsh-relay" 加进 dsh.profile.bundles,然后 pnpm install
方式 B:本地目录链接(开发/试用)
dsh plugin --profile web add link:$HOME/.dsh/plugins/dsh-relay
# 或等价地:编辑 profile package.json 的 dependencies 加
# "dsh-relay": "link:/Users/<you>/.dsh/plugins/dsh-relay"
# 并把 "dsh-relay" 加进 dsh.profile.bundles,然后 pnpm install
重启 DSH 生效。运行测试:npm test(详见 TESTING.md)。
配置(个人信息只放机器本地,绝不进 git)
行 config 是整体替换语义:profile patch 里同 id 的
config会完全替换 插件自带占位配置(插件的cordis.patch.yml里 handle 等一律留空占位)。
把个人配置写进 profile 的本地补丁文件
~/.dsh/profiles/<name>/cordis.patch.yml(机器本地文件,不属于本插件仓库):
- id: dsh-relay
name: 'dsh-relay'
config:
enabled: true # 初始总开关(之后用通道命令切换,状态落盘)
approvalTimeoutSecs: 600 # 审批等待通道答复,超时转回网页 UI
questionTimeoutSecs: 1800
channels:
imessage:
enabled: true
handle: '<你的手机号或 Apple ID 邮箱>' # 仅该地址可驱动
extraHandles: [] # 其他可信回复地址(手机号+邮箱同时用)
email:
enabled: false
from: 'you@example.com'
to: 'you@example.com'
imap: { host: 'imap.gmail.com', port: 993, secure: true, user: 'you@example.com', passRef: 'DSH_RELAY_EMAIL_PASS' }
smtp: { host: 'smtp.gmail.com', port: 465, secure: true, user: 'you@example.com', passRef: 'DSH_RELAY_EMAIL_PASS' }
# passRef 指向 ~/.dsh/.credentials.yaml 中的键(或同名环境变量),不落明文;
# 也可不用 passRef,直接写 pass: '授权码'
wechat:
enabled: false # iLink 扫码登录;个人微信自动化有风控风险,默认关闭
改完重启 DSH 生效(profile patch 文件被 watch,config 修改会自动热更新, 但首次安装本插件必须先重启一次)。
隐私 / Git 安全
- 个人配置:只写 profile 本地
cordis.patch.yml(机器本地,见上); - 本仓库(插件目录)不含任何个人信息:
handle一律空占位、README 全部用示例值; - 运行状态
~/.dsh/dsh-relay/state.json、凭据~/.dsh/.credentials.yaml、 profile 补丁~/.dsh/profiles/都在仓库之外; - 上传 git 前检查:
grep -rn "<你的手机号>|<你的邮箱>" . --exclude-dir=node_modules应为空;.gitignore已排除node_modules/、*.log、.DS_Store。
iMessage 通道权限(macOS,一次授权)
- 自动化:首次发送时系统弹窗,允许宿主进程控制 Messages.app;
- 完全磁盘访问:macOS 26 已移除 Messages 的 message 类 AppleScript,收信走
~/Library/Messages/chat.db轮询(sqlite3 -readonly)。请在 系统设置 → 隐私与安全性 → 完全磁盘访问 中加入运行 DSH 的进程。 若 DSH 由 launchd 托管,加它的 node 可执行文件(日志会打印process.execPath的实际路径,例如/Users/<you>/.hermes/node/bin/node; 添加时用Cmd+Shift+G粘贴路径)。授权后无需重启,轮询会自动恢复。
若 chat.db 不可读,插件日志会提示;此时 iMessage 通道只能发不能收。
使用
先给 DSH 跑任务(本机可先不发消息;首次使用建议从手机给本机发一条 iMessage,便于自动定位会话)。
有诉求时手机会收到:
🔐 #3 需要批准 会话: 修复登录页(sess-abc123) 工具: bash 原因: 执行 rm -rf 需要你的确认 回复「#3 批准」或「#3 拒绝」 (10 分钟内未回复将转回网页)回复
#3 批准→ 本机放行;回复关闭→ 插件整体停用;全部关闭→ 不再推送任何会话。
安全
⚠️ 白名单配置安全原则(配置本插件前必读)
白名单是安全必选项,不是可选项——每个使用者在配置时必须显式、最小化地列出可信身份,绝不放"任意人"进来。
- iMessage:
handle+extraHandles必须列出具体身份(你的手机号/Apple ID 邮箱/可信回复地址);白名单之外的一切号码/设备/邮箱一律不参与(它们可能收到审批推送或冒充你应答,涉及审批/敏感信息,泄露风险高); - 白名单是最小化的:只列你确实可信的;多设备/多号码场景逐一确认,不批量放行;
- 代码已强制:白名单含
*/any/空串等通配形式会被拒绝启动(防止误配置全放行);handle未配置时通道不启动(configured()要求白名单非空); - Email:
from/to/allowedFrom同理,只列你的地址;微信:扫码绑定的白名单用户同理; - 配置示例见上方「安装」章节;个人真实身份只在机器本地 profile(
~/.dsh/profiles/<name>/cordis.patch.yml),随仓库发布的cordis.patch.yml一律用占位符。
防篡改 / 防内网信息外泄(纵深防御):
- 每个通道独立发送方白名单:iMessage 仅
handle/extraHandles,Email 仅from/to/allowedFrom,微信仅扫码白名单用户;非白名单消息一律忽略并告警; - Email 身份认证强制:解析
Authentication-Results(SPF/DKIM/DMARC),任一fail直接拒绝;email.strictAuth: true时连无认证头的邮件也拒绝(防伪造发件人); - 通道命令是固定白名单(批准/拒绝/回答/开关/罗列),没有任何"执行 shell / 读文件 / 改配置"类命令;
- 通道文本只能注入会话流(
source.kind = 'plugin'),且注入时附带安全护栏提示(不得外发密钥/令牌/凭据,不得改仓库配置,高危操作照常走审批)——模型的危险动作仍受 DSH 审批栈约束; - 审批应答必须对应真实 pending 编号,超时/撤销/重启后失效(stale 不可应答);
- 外发脱敏:推送的轮次片段自动抹除常见密钥/令牌/私钥/凭据赋值(
security.redactSecrets); - 一键收紧:
security.allowInjection: false时通道只能批准/拒绝/回答,完全禁止文本注入; - iMessage 收信强制
is_from_me = 0,不会把插件自己的推送当命令回灌。
会话列表的通道隔离
/sessions(及模糊说法)在通道内默认只回复数量与指引,不暴露会话 id/标题
(共享通道上其他机器人可见,属轻度信息泄露;sessionsInChannel 可配 full/silent)。
完整列表只在两处:
- 网页:输入框执行
/relay sessions(命令面板输出,不进通道); - 命令行:
node cli.js status/node cli.js list。
环境假设与已知限制
- iMessage 通道仅 macOS(依赖 Messages.app 与
~/Library/Messages/chat.db;macOS 26 需"完全磁盘访问"授权收信); - Email 通道需真实 IMAP/SMTP 凭据验收(代码完成,未在真实邮箱联调过);发件人认证强制 SPF/DKIM/DMARC;
- 同通道多机器人共存:本插件用
ignorePrefixes(默认【)排除其他机器人消息,换环境请按需配置; - 停机期间到达的消息会在重启后补收(水位=最后处理 rowid),首次安装跳过既有历史;
- 微信通道默认禁用(iLink 个人微信自动化有风控风险);Telegram/飞书为预留接口。
接入新通道
实现 src/channels/types.js 描述的契约(configured/start/stop/send/isTrusted/status),
在 src/index.js 的 channels 列表注册即可。优先移植成熟实现:
Telegram → LoserFox/telegram(Bot API 长轮询)、
飞书 → imetn/dsh-lark-bridge、
微信 → dsh-im-bridge 的 iLink 客户端(本项目已移植)。
通道成熟度与实现来源矩阵见 TESTING.md。
通道健康监控(推荐搭配)
dsh-relay 的通道轮询已委托给 dsh-task-watchdog(通用任务健康监控插件):
- 每个通道登记为
ctx.jobs任务并接入 watchdog,轮询循环上报心跳; - 心跳停滞/启动卡死 → watchdog 自动抓根因诊断快照(进程状态/心跳/最近日志)→ 自动重启通道;
- 区分主动停止(你通过命令关闭通道 → 不重启不告警)与意外停滞(崩溃 → 诊断+重启);
- 提供事件流(
watchdog.onEvent),可对接任意通讯方式查看/审计 watchdog 的处理过程。
推荐:任何 DSH 插件有长轮询/后台任务的,都建议接入 dsh-task-watchdog(
ctx.jobs.start建任务 →watchdog.monitor+ 循环里beat),获得同样的监控/诊断/自愈能力。dsh-relay 本身不再内置 watchdog 逻辑(单一职责)。
安装 watchdog:见 dsh-task-watchdog README。
测试与贡献
npm test # 统一运行器:69 单元 + 27 dry-run + 冒烟,全部通过 ✅ 才算过
测试用例全集、手动验收清单(M1–M16)、通道成熟度矩阵、贡献流程见 TESTING.md。
贡献者必读(提交代码前):
- 运行
npm test,输出必须以全部测试套件通过 ✅结尾; - 把完整测试输出贴进 PR 描述(这是通过评审的凭证,缺失会被打回);
- 若新增/改动通道,附上对应的手动验收记录(真实通道 E2E,见 TESTING.md 清单),或至少给出 dry-run 测试;
- 改动/新增通道必须附带通过输出,否则不予合并。
开发
cd ~/.dsh/plugins/dsh-relay
pnpm install
npm test
node cli.js list # 命令行罗列待回复诉求
致谢
- dsh-im-bridge(MIT):iLink 协议客户端、桥接循环、去重/分段/合并、状态存储
- dsh-chatnode-wechat:编号审批交互范式
- dsh-lark-bridge:凭据引用(credentials)用法参考
License
MIT
nexu-io/open-design
freestylefly/awesome-gpt-image-2
anywhere-labs/dsh-desktop
walkinglabs/learn-harness-engineering
awesome-dsh-plugin/awesome-dsh-plugin
MemTensor/MemOS