🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

审批中转通道 nicecx/dsh-relay

DeepSeek Harnessv0.2.1
nicecx56 天前有提交已提供中文文档扫描:含敏感能力

把授权与提问推送到微信邮件,回复编号即可处理

30.7/100
综合分
3
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/9/16 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查有告警:npm 同名包「dsh-relay」归属 sorsama/deepseek-harness-relay,装到的可能不是本插件。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add nicecx/dsh-relay
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · platform
装得上吗
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 56 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意

npm 同名包「dsh-relay」归属 sorsama/deepseek-harness-relay,装到的可能不是本插件

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-relay @ 0.2.1
✓Node 引擎要求 >=22.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/12 09:39:32

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件发起外部网络请求
查看扫描证据(共 41 处,展示前 39 条)
  • 写入本地文件
    src/index.js:96
    mkdirSync(stateDir, { recursive: true })
  • 写入本地文件
    src/index.js:98
    writeFileSync(tmp, JSON.stringify({ updatedAt: Date.now(), pending: snapshot }))
  • 写入本地文件
    src/index.js:99
    renameSync(tmp, pendingPath)
  • 读取本地文件
    src/index.js:106
    const raw = JSON.parse(readFileSync(pendingPath, 'utf8'))
  • 读取本地文件
    src/index.js:819
    files = readdirSync(inbox.inboxDir).filter(
  • 读取本地文件
    src/store.js:64
    const raw = JSON.parse(readFileSync(this.path, 'utf8'))
  • 写入本地文件
    src/store.js:309
    mkdirSync(dirname(this.path), { recursive: true })
  • 写入本地文件
    src/store.js:311
    writeFileSync(tmp, JSON.stringify(this.state))
  • 写入本地文件
    src/store.js:312
    renameSync(tmp, this.path)
  • 发起网络请求
    src/channels/email.js:178
    for await (const msg of client.fetch(`${from}:*`, { uid: true, source: true })) {
  • 发起网络请求
    src/channels/wechat.js:86
    const res = await fetch(`${this.baseUrl}${path}`, {
  • 发起网络请求
    src/channels/wechat.js:104
    const data = await this.request('/ilink/bot/get_bot_qrcode?bot_type=3', { timeoutMs })
  • 发起网络请求
    src/channels/wechat.js:112
    const data = await this.request(`/ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(qrcodeId)}`, {
  • 发起网络请求
    src/channels/wechat.js:129
    const data = await this.request('/ilink/bot/getupdates', {
  • 发起网络请求
    src/channels/wechat.js:148
    await this.request('/ilink/bot/sendmessage', {
  • 写入本地文件
    src/channels/wechat.js:189
    mkdirSync(dirname(deps.stateDir), { recursive: true })
  • 写入本地文件
    src/channels/wechat.js:190
    writeFileSync(join(deps.stateDir, 'wechat-login-url.txt'), `${qr.qrUrl}\n`)
  • 读取本地文件
    src/inbox.js:69
    cwdDirs = readdirSync(sessionsDir, { withFileTypes: true })
  • 读取本地文件
    src/inbox.js:77
    sidDirs = readdirSync(join(sessionsDir, cwdEnt.name), { withFileTypes: true })
  • 读取本地文件
    src/inbox.js:86
    if (existsSync(join(sessionsDir, cwdEnt.name, sidEnt.name, 'session.jsonl.zstd'))) {
  • 写入本地文件
    src/inbox.js:105
    try { mkdirSync(inboxDir, { recursive: true }) } catch (err) { warn('inbox: 目录创建失败:', err) }
  • 写入本地文件
    src/inbox.js:114
    appendFileSync(join(inboxDir, AUDIT_FILE), JSON.stringify({ ts: new Date().toISOString(), ...entry }) + '\n', 'utf8')
  • 读取本地文件
    src/inbox.js:120
    const w = JSON.parse(readFileSync(waterOf(sid), 'utf8'))
  • 写入本地文件
    src/inbox.js:135
    writeFileSync(tmp, JSON.stringify({
  • 写入本地文件
    src/inbox.js:140
    renameSync(tmp, waterOf(sid))
  • 写入本地文件
    src/inbox.js:172
    appendFileSync(fileOf(normTo), JSON.stringify(msg) + '\n', 'utf8')
  • 读取本地文件
    src/inbox.js:188
    try { size = statSync(fileOf(sid)).size } catch { return { msgs: [], offset: water.offset, size: 0, water } }
  • 读取本地文件
    src/inbox.js:231
    try { size = statSync(path).size } catch { return { ok: false, reason: 'missing' } }
  • 写入本地文件
    src/inbox.js:248
    renameSync(path, `${path}${ARCHIVE_SUFFIX}${ts}`)
  • 读取本地文件
    cli.js:22
    return JSON.parse(readFileSync(path, 'utf8'))
  • 删除本地文件递归
    src/apply.smoke.js:111
    rmSync(dir, { recursive: true, force: true })
  • 删除本地文件递归
    src/dryrun.test.js:335
    rmSync(tmp, { recursive: true, force: true })
  • 删除本地文件递归
    src/dryrun.test.js:452
    rmSync(tmp, { recursive: true, force: true })
  • 删除本地文件递归
    src/index.test.js:184
    rmSync(dir, { recursive: true, force: true })
  • 删除本地文件递归
    src/index.test.js:194
    rmSync(dir, { recursive: true, force: true })
  • 删除本地文件递归
    src/index.test.js:205
    rmSync(dir, { recursive: true, force: true })
  • 删除本地文件递归
    src/index.test.js:219
    rmSync(dir, { recursive: true, force: true })
  • 删除本地文件递归
    src/index.test.js:348
    rmSync(dir, { recursive: true, force: true })
  • 删除本地文件递归
    src/index.test.js:362
    rmSync(dir, { recursive: true, force: true })
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 转发审批与提问请求
  • 内置微信邮件渠道
  • 统一适配器接入

DSH 插件:把审批和提问请求转发到任意聊天渠道——内置 iMessage、Email、微信;Telegram/钉钉/飞书/Slack 走统一适配器契约(src/channels/types.js)

README

由 DeepSeek 最新模型翻译生成
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。
展开完整文档(README 剩余 1 节)
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 拦截而非替换 userQuestions provider——与网页 UI 共存,超时/未启用时 next() 转回网页,两不冲突。

能力

| 方向 | 内容 |
| DSH → 通道 | ① 审批诉求(工具名 + 原因 + 会话)② 提问诉求(选项列表,可多选)③ 会话轮次结束(完成/出错/被阻塞 + 片段,自动脱敏) |
| 通道 → DSH | #N 批准 / #N 拒绝 应答审批;#N 回答提问;回复 #N 注入诉求所属会话;裸文本注入绑定会话。支持自然语言(见下) |
| 开关(通道内) | 开启 / 关闭(总开关)、开启 邮件 / 关闭 微信(单通道)、全部开启 / 全部关闭(所有对话)、/enable / /disable (单会话)、/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//dsh-relay
或把 "dsh-relay": "github:/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//.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//cordis.patch.yml(机器本地文件,不属于本插件仓库):

- id: dsh-relay
name: 'dsh-relay'
config:
enabled: true # 初始总开关(之后用通道命令切换,状态落盘) approvalTimeoutSecs: 600 # 审批等待通道答复,超时转回网页 UI questionTimeoutSecs: 1800 channels: imessage: enabled: true handle: '' # 仅该地址可驱动
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,一次授权)

1. 自动化:首次发送时系统弹窗,允许宿主进程控制 Messages.app;
2. 完全磁盘访问:macOS 26 已移除 Messages 的 message 类 AppleScript,收信走 ~/Library/Messages/chat.db 轮询(sqlite3 -readonly)。请在系统设置 → 隐私与安全性 → 完全磁盘访问* 中加入运行 DSH 的进程。
若 DSH 由 launchd 托管,加它的 node 可执行文件(日志会打印 process.execPath 的实际路径,例如 /Users//.hermes/node/bin/node;添加时用 Cmd+Shift+G 粘贴路径)。授权后无需重启,轮询会自动恢复。

若 chat.db 不可读,插件日志会提示;此时 iMessage 通道只能发不能收。

使用

1. 先给 DSH 跑任务(本机可先不发消息;首次使用建议从手机给本机发一条 iMessage,便于自动定位会话)。
2. 有诉求时手机会收到:

🔐 #3 需要批准会话: 修复登录页(sess-abc123)工具: bash 原因: 执行 rm -rf 需要你的确认回复「#3 批准」或「#3 拒绝」(10 分钟内未回复将转回网页)

3. 回复 #3 批准 → 本机放行;回复 关闭 → 插件整体停用;全部关闭 → 不再推送任何会话。

安全

⚠️ 白名单配置安全原则(配置本插件前必读)

白名单是安全必选项,不是可选项——每个使用者在配置时必须显式、最小化地列出可信身份,绝不放"任意人"进来。

- iMessage:handle + extraHandles 必须列出具体身份(你的手机号/Apple ID 邮箱/可信回复地址);白名单之外的一切号码/设备/邮箱一律不参与(它们可能收到审批推送或冒充你应答,涉及审批/敏感信息,泄露风险高);
- 白名单是最小化的:只列你确实可信的;多设备/多号码场景逐一确认,不批量放行;
- 代码已强制:白名单含 */any/空串等通配形式会被拒绝启动(防止误配置全放行);handle 未配置时通道不启动(configured() 要求白名单非空);
- Email:from/to/allowedFrom 同理,只列你的地址;微信:扫码绑定的白名单用户同理;
- 配置示例见上方「安装」章节;个人真实身份只在机器本地 profile(~/.dsh/profiles//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。

测试与贡献 bash
npm test # 统一运行器:69 单元 + 27 dry-run + 冒烟,全部通过 ✅ 才算过

测试用例全集、手动验收清单(M1–M16)、通道成熟度矩阵、贡献流程见 TESTING.md。

贡献者必读(提交代码前):
1. 运行 npm test,输出必须以 全部测试套件通过 ✅ 结尾;
2. 把完整测试输出贴进 PR 描述(这是通过评审的凭证,缺失会被打回);
3. 若新增/改动通道,附上对应的手动验收记录(真实通道 E2E,见 TESTING.md 清单),或至少给出 dry-run 测试;
4. 改动/新增通道必须附带通过输出,否则不予合并。

开发 bash
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

测试与覆盖

- 测试:npm test(统一运行器 test/run-all.mjs:dry-run / env-check / 契约)
- 覆盖矩阵与质量检测基线:test/DRYRUN.md(正向推演:功能规格 → 测试设计技术 → 规模层 → 风险 → 断言 → 回归实证;含 c8 覆盖率快照与盲区标注)
- 覆盖率复测:npm run coverage(c8 text-summary;数字变化时请同步更新 DRYRUN.md)
预览分享卡片长什么样 ↓nicecx/dsh-relay
分享 · DeepSeek Harness Hub
nicecx/dsh-relay

把授权与提问推送到微信邮件,回复编号即可处理

回到顶部