dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DeepSeek Harness 插件,把 agent 的每一轮回答和你的邮箱接起来,双向:
一个任务常常要连跑好几轮(turn/end 之后还会继续下一轮),所以标题分成两种: 中途那几轮是 DSH 任务进行中|…,整段任务真正跑完(agent 停稳)那一封是 DSH 任务完成|…, 收件箱里一眼看得出哪封才是结束了。父会话停下来不等于整段任务结束:名下还有子代理 (Agent Teams 成员等)在跑时,收尾那封不会报「任务完成」——中途通知开着就改发 DSH 任务进行中(N 个子代理仍在跑)|…,关着就等它们跑完再发。详见两种邮件。
DSH),插件会把邮件正文**作为一条用户消息追加到那封通知所属的会话里,接着原来的上下文继续干;或者新写一封邮件、标题正好是 创建对话 (默认也认 创建新对话、新建对话), 插件会新建一条会话,并把邮件正文原样作为这条对话的第一句话,工作区则由默认模型**看着邮件内容 从你已登记的项目里挑(挑不出来才沿用上一次的目录)。答案都按上面的规则回信给你 (见下文「收信触发」一节)。
ask_user_question 向你要答案时,这一轮会停在原地等你,所以插件不等轮次结束,提问一发生就发一封 DSH 等待你的回答|问题摘要,正文列出每个问题、 可选项和补充说明,提醒你回 DSH 界面回答(见提问时也会立刻发一封)。
dsh-schedule)那一轮整轮不发信,也不会把你正跑着的任务的收尾邮件降级成「进行中」;要跳别的自动化来源(目标续跑、webhook、邮件触发……)往 skipSources 里加 kind 即可。
smtp.mjs)、IMAP 客户端(imap.mjs)、邮件解析(mail.mjs)和邮件组装(mime.mjs)只用 Node 内置模块,不需要 pnpm add 任何东西。
.mjs,直接就是运行时代码。mail_notify 工具,可以直接让 Agent 帮你配好、试发、查为什么没触发。qq.com、163.com、gmail.com 都一样能收。插件注册了 mail_notify 工具,三个 action:
action · 作用 status · 报告当前到底会不会发信,以及收信触发的状态:SMTP 端点、发件账号、收件人、授权码从哪儿读、关键字、白名单、UID 水位 guide · 给出配置文件的确切路径,以及一段可直接粘贴的 YAML test · 立刻真发一封测试邮件(可用 to 临时指定别的收件人),验证网络/TLS/授权码/中文编码 reply_status · 只说收信触发:IMAP 端点、关键字规则、创建对话短语、工作目录策略、白名单、投递方式、已登记的通知与所属会话、UID 水位、最近一次轮询与投递(含逐封判定结果与原因——被跳过的邮件也列出来,所以「刚才那封为什么没触发」事后也查得到) reply_check · 立刻只读检查一次邮箱,逐封打印判定结果、原因,以及会落到哪条会话;不改状态、不投递。问「为什么我回复了却没反应」时用它
所以装好之后你只要说「帮我把邮件通知配好」,或者「为什么没收到邮件」,Agent 就能查到原因。 配置写错时这个工具照样注册——那时它正是把错因讲清楚的唯一入口。
五条硬保证,都有测试兜着(node --test,175 个用例):
enabled: false 且 reply.enabled: false(出厂默认)时,apply 在注册session/event 监听器和定时器之前就返回,不响应任何会话事件,也没有网络或文件动作。
to、地址非法、发件域名认不出、reply 字段类型错、config 整个是undefined,这些情况都只写 error 日志然后保持惰性。
enabled 只管发通知,reply.enabled 只管收信触发;可以只发、只收,或都开。
try 里——附加能力不能连累主功能。user/message.source.kind,辅以 turn/start那一刻收件箱里即将被领取的那批消息);读不到就照常发信,绝不因为猜错而漏发。
第一版把 .mjs 直接放在 profiles/desktop/plugins/ 下,再往 profile 的 cordis.patch.yml 里 insert 一行,结果运行中的 dsh 卡死,只能重启恢复。 profile 内的相对路径插件要靠 HMR 的运行时 reconcile 去 import 一个新模块; 而 bundle 方式是启动时解析的(dsh.profile.bundles),是 xl 插件已经验证过的路径。 所以现在代码放在 profile 目录之外,走 bundle。
在 %USERPROFILE%.dsh\profiles\desktop\package.json 的 dependencies 里加一行:
"dependencies": {
"dsh-mail-notify": "link:C:/Users/you/Documents/GitHub/dsh-mail-notify" // 换成你自己的绝对路径
}cd $env:USERPROFILE\.dsh\profiles\desktop
pnpm install这一步不要动 dsh.profile.bundles。没有任何 bundle 或 patch 引用这个包, 加载器就不会 import 它,启动树和现在完全一样。确认 dsh 照常启动,再进第 2 步。
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"xl",
"dsh-mail-notify" // 新增
]
}
}完全退出再启动 dsh(bundle 解析变更本来就要重启,这是 dsh 的设计)。 此时插件已挂载,但 cordis.patch.yml 里 enabled: false,所以仍然不发信。 可以先用 mail_notify 的 guide / test 把配置弄好再来这一步之后的启用。
本包的 cordis.patch.yml 里只有占位地址(you@example.com),真实邮箱写在 profile 自己的覆盖层 %USERPROFILE%.dsh\profiles\desktop\cordis.patch.yml 里, 这样公开仓库不会留下你的地址:
- id: mail-notify
name: 'dsh-mail-notify'
config:
enabled: true
smtp:
user: 你的账号@qq.com
from: 你的账号@qq.com
to:
- 收件人@qq.compatch 是整体替换 config,不是深合并,所以这段会覆盖本包的默认值——从 enabled 开始写全。 host / port / secure 会按发件域名自动推断,不必手写;其余字段都有代码默认值。
example.com故意不在内置端点表里:如果只把enabled改成true而不填真实地址,
会得到一条明确的配置错误日志,而不是静默失败。
把 dsh-mail-notify 从 dsh.profile.bundles 里删掉再重启,就回到装之前的状态。 或者只把 enabled 改回 false。
不写进任何配置文件。按 内联 → 环境变量 → 文件 的顺序找:
config.authCode(不推荐)config.authCodeEnv 指的环境变量,默认 QQ_SMTP_AUTH_CODEconfig.authCodeFile 指的文件,默认就是本目录下的 secret.txtsecret.txt 每次发信都重新读,所以补进去之后不用重启。它已在 .gitignore 里,不要提交。 QQ 邮箱要用「设置 → 账户 → POP3/IMAP/SMTP 服务」里生成的授权码,不是登录密码。
驱动循环是 while (await turn()):一个任务的很多轮之间不会回到 idle,只有整段跑完 agent.status 才变成 idle。所以判定链是这样的:
某一轮 turn/end → 先不发,等「安静窗口」(默认 5 秒)
├─ 期间收到下一轮 turn/start ⇒ 上一轮只是中途 → 发「DSH 任务进行中|摘要」
├─ 窗口到期、agent idle,但名下还有子代理在跑
│ ├─ 中途通知开着 ⇒ 发「DSH 任务进行中(N 个子代理仍在跑)|摘要」
│ └─ 中途通知关着 ⇒ 继续等,子代理收口后才发收尾那封
└─ 窗口到期、agent idle,且没有子代理在跑 ⇒ 整段任务结束 → 发「DSH 任务完成|摘要」父会话 idle 不等于整段任务结束:Agent Teams 成员、子代理都开自己的会话,父会话在等它们时 本来就是 idle;只看父会话就会把「还有成员在干活」报成「任务完成」。所以收尾那一封会再查一次 agents 实时注册表,只统计本会话的后代(沿会话血缘 parentSession 跨多层),有正在跑的 子代理就绝不出现「任务完成」:
情况 · 邮件 一轮就干完(最常见) · 只有一封:DSH 任务完成|…(正文带这一轮的回答) 连跑 3 轮 · 3 封:进行中、进行中、完成(都各自带那一轮的回答) 父会话停下时还有子代理在跑 · 中途通知开着:一封 进行中(N 个子代理仍在跑)|…,子代理收口后接一封 完成;notifyProgress: false 时只有子代理跑完那一封 完成 notifyProgress: false · 只有最后那封 完成,中途不打扰;正文只带最后一轮的回答
「完成」那一封正文开头会写清 本次任务已全部结束(N 轮),所以即使和「进行中」的邮件混在 一个会话里也能一眼确认收尾。两种邮件都带会话 token,回复任意一封都能接回同一条会话。
配置:
字段 · 默认 · 说明 subject · DSH 任务完成 · 全部结束那一封的前缀(非正常结束时自动补后缀) subjectProgress · DSH 任务进行中 · 中途每轮的前缀 notifyProgress · true · 中途那些轮是否各发一封;false = 一个任务只发一封 finalQuietSeconds · 5 · 安静多久算这一波结束;0 = 不等,立刻算结束(等于不管续跑)
安静窗口只影响「哪一封算完成」,不影响内容;把它调大一些可以更稳妥地吸收紧接着的续跑
(例如目标循环)。窗口内进程被关掉的话,这一封会丢——不放心就设 finalQuietSeconds: 0或直接关掉 notifyProgress 之外的顾虑。ask_user_question(以及任何走 DSH 问答服务的提问,比如计划审阅)和「一轮结束」不是一回事: 这一轮会停在原地等人回答,你不在界面(或界面根本关着)时它会一直等下去。所以这一封不等 turn/end,提问一发生就发:
智能体正在等你回答下面的问题:
1. 【确认】是否删除旧文件?
- 删除(推荐):永久删除,不能恢复
- 保留
请回到 DSH 界面里回答(这封邮件只是提醒,问题要在界面里答)。情况 · 邮件 一次提问(ask_user_question) · 一封 DSH 等待你的回答|第一条问题的摘要 答完、这一轮继续跑完 · 照常再收到「进行中 / 完成」那一封 notifyQuestions: false · 提问时不发,只保留轮次通知
要点:
user-questions/request 瀑布,并且注册在宿主转发器之前——正常答题(result)时宿主转发器直接返回、不再往下传,晚注册的监听器在真机上根本轮不到。
发信失败只记 error 日志,绝不让提问本身出错。
detail(标注「待审阅的计划」)、多选标记也会带上。正文超长按 maxBodyChars 截断,但「回界面回答」这句提醒不会被截掉。
它是「有人在等你」的行动提醒,不是任务结束的噪音。
答完才会被读到),问题本身还得在界面回答。所以正文里的 token 页脚也是专门的措辞,不是 轮次通知那句「回复可以继续对话」。
reply.token 未关 + 邮件真的发出」才会附[DSH-XXXXXX] 并登记;没有 agent 的编程式提问(没有会话)不带 token,正文也不会承诺回信能排队。
notifyQuestions: false;目前没有「N 秒没答才发」的延迟选项。