dsh-mail-command
用邮件指挥 DeepSeek Harness:回复一封通知邮件,就能让正在跑的任务继续或停止,正文可以写具体要求。
它是 dsh-qq-mail-notify 的附属插件——那个负责发信,这个负责收信。两个独立安装、互不硬依赖:只装通知插件就是纯提醒;两个都装,邮件才变成双向通道。
前置要求
本插件必须搭配 dsh-qq-mail-notify 一起使用,单独装它没有任何效果。
原因很直接:它自己不发送任何邮件。一次性口令是随通知邮件一起发出去的,你回复的也是那封邮件。没有发信侧,你的收件箱里就不会出现带口令的邮件,也就没有东西可以回复,整个功能等于不存在。
正确用法是两个都装:
dsh plugin --profile desktop add github:yashua233/dsh-qq-mail-notify
dsh plugin --profile desktop add github:yashua233/dsh-mail-command
装好后在通知插件的设置里填好发件邮箱与 SMTP 授权码(本插件复用同一份凭据),发一封测试邮件确认能收到,再回复它试试。
它解决什么问题
任务跑到一半因为额度不足停住,你充完钱还得回到电脑前重新说一遍;或者一个任务明显跑偏了,你只能等它结束。装上这个插件之后:
- 通知邮件里带上一次性口令;
- 你直接在手机上回复那封邮件,写「继续」,任务接着跑;
- 写「停止」,当前这一轮立刻中断;
- 写「继续,但把测试也跑一遍」,这句话原样成为给 agent 的新输入。
安装
# 从 GitHub
dsh plugin --profile desktop add github:yashua233/dsh-mail-command
# 本地目录
dsh plugin --profile desktop add link:/path/to/dsh-mail-command
desktop 是桌面端默认的 profile 名,用你自己的那个(~/.dsh/profiles/ 下能看到的目录名)。装完重启一次生效。
建议与通知插件一起装:
dsh plugin --profile desktop add github:yashua233/dsh-qq-mail-notify
怎么用
装好并重启,确认
dsh-qq-mail-notify已经配好发件邮箱和 SMTP 授权码(同一套凭据本插件复用);之后每次通知邮件末尾都会附上:
可用指令(直接回复本邮件,保留主题里的 [CONT:AB12CD34]): · 继续 —— 正文写要继续做的事;只写「继续」就按原计划接着干 · 停止 —— 正文写「停止」或 stop,立刻中断当前这一轮回复那封邮件即可。主题里的口令要保留(邮件客户端默认会保留),正文写你要它做什么。
指令怎么判定
| 你回的正文 | 结果 |
|---|---|
| 空 | 按原计划继续 |
继续 |
继续 |
停止 / stop / 取消 |
停止当前轮 |
停止,剩下的别改了 |
停止(后半句记进日志) |
继续,但把测试也跑一遍 |
继续,要求 = 整句原文 |
把 README 补完再提交 |
继续,要求 = 这句 |
引用区(> 开头的行、-----原始邮件----- 之后的内容)会自动剥掉,不会被当成指令的一部分。
收件节奏(三段自适应)
刚发出通知时你最可能就在手机旁边,所以前 10 分钟查得勤;越往后越稀疏;超过 30 分钟基本不会回了,干脆停下,等下一封邮件发出时再被唤醒。
| 字段 | 默认 | 说明 |
|---|---|---|
fastWindowMs |
600000 |
快速窗口长度(10 分钟) |
fastIntervalMs |
5000 |
快速窗口内每隔多久查一次(5 秒) |
slowIntervalMs |
600000 |
超过快速窗口后每隔多久查一次(10 分钟) |
stopAfterMs |
1800000 |
超过这个时间就暂停检测(30 分钟),新邮件发出时自动唤醒 |
想更快可以调小 fastIntervalMs(比如 2000),但 QQ 邮箱有 IMAP 频率限制,设太小会被重连。mail_command action=status 会告诉你当前处于哪一档。
安全设计
为什么必须带口令:SMTP 的发件人地址是可以伪造的。如果只按 From 判断,任何知道你邮箱的人伪造一封「继续」就能让 agent 跑起来——而 agent 有完全的文件权限。所以:
- 口令随邮件主题发出,长度 8 位、一次性、命中即作废;
- 校验顺序是「发件人必须在允许列表内」且「口令必须存在且未用过」,两条同时成立才动作;
- 口令默认 7 天过期(
tokenTtlMs),不会长期挂着一条可用的后门; - 插件重启后所有旧口令失效,之前发出的邮件回复也不会再触发任何动作(这是刻意的)。
配置
复用发件插件的凭据,不需要重复填。自己的可选项写在 $DSH_HOME/mail-command.json:
| 字段 | 默认 | 说明 |
|---|---|---|
enabled |
true |
总开关;关掉后不再轮询收件 |
intervalMs |
60000 |
轮询间隔,最小 30 秒。别设太短,QQ 邮箱会限流 |
host / port |
imap.qq.com / 993 |
IMAP 服务器,端口即隐式 TLS |
tokenTtlMs |
604800000 |
口令有效期(7 天) |
user / authCode |
取自通知插件 | 想用另一个邮箱收信时才需要填 |
邮箱凭据默认从 $DSH_HOME/qq-mail-notify.json 读;单独配了 user / authCode 就以自己的为准。
它是怎么让任务继续的
DSH 的 agent 有一个待处理队列:next-turn 是「等下一轮处理」的输入,next-step 是「等下一个步骤」的输入。往 next-turn 追加一条消息再唤醒驱动,效果等同于用户在界面里发了这条消息。
停止走的是 agent.cancel():清空待处理队列 + 中止当前 turn 的 AbortController,和你在界面上点停止是同一条路径。
这两处用的是 DSH 内部结构(不是公开 API),所以我把它单独做成插件——将来宿主换了实现,只需要更新这一个插件,不影响通知那一半。
和通知插件的关系
dsh-qq-mail-notify ──发信──▶ 你的邮箱
│ │
│ issueToken(sessionId) │ 你回复
▼ ▼
dsh-mail-command ◀────── 收信、校验口令、注入指令
通知插件通过 cordis 服务 mailCommand 拿到口令;取不到服务时它照常发信,只是邮件里没有口令,回复也就不触发任何动作。两个插件谁都不 import 对方。
隐私
不联网(除了连你自己的 IMAP 服务器),不收集任何数据。邮件原文不会落盘,解析完即丢;只把口令与它对应的会话 id 记在内存里,插件重启即清空。
许可证
MIT,见 LICENSE。
No comments yet. Be the first to write one.