leinaldo/dsh-routines:给 DSH 补一套 Claude 风格的定时任务

前言

DSH 自带 @deepseek-ai/dsh-schedule 这套「自动化任务」,但它是排期提醒:到点把一条消息投回任务绑定的会话,用那个会话的历史继续干活。回执只表示「消息进了收件箱」,不表示模型执行完成,也没有暂停和手动运行。

下面介绍的 dsh-routines(维护者 leinaldo,分类「工作流」)把语义换成任务运行器:到点新开一个对话跑一轮,跑完有状态、耗时、步数和 token 回执,可以回看那轮会话。目标是照 Claude 桌面 App 本地定时任务(Routines / CCD scheduled tasks)的行为,给 DSH 补一套定时任务。

这是什么

一句话定位:一个 DSH 插件,用一份 JSON 索引管理定时任务,每次触发都新建会话、独立上下文跑一轮。

解决的实际问题是——内置提醒到点只投递消息,你不知道模型到底跑没跑完、跑得怎么样;而 dsh-routines 把这一轮当成一次真正的运行来记账,失败、超时都能查到。

与内置自动化任务的区别

维度 @deepseek-ai/dsh-schedule(内置) dsh-routines(本插件)
运行位置 投回绑定会话,复用其历史 新建会话,每轮独立上下文
执行回执 只表示消息进入收件箱 turn/end 后记录状态/耗时/步数/token
手动运行 无 「立即运行」,不改排期
停用/启用 无 支持
一次性任务 无 支持,跑完自动停用

因为每轮不共享上下文,任务里那条指令(prompt)必须自包含——写清楚要做什么,不要指望它会读到上一次的对话。

调度与运行语义

调度能力:

  • cron:五字段,本地时区;支持 *、a、a-b、a-b/n、列表、月份和星期英文缩写。
  • 一次性:ISO 时间点,只允许未来时间;跑完自动停用;超过 7 天未跑的到点任务直接停用。
  • 仅手动:cron 与一次性都不填,只保留在列表里,点「立即运行」。
  • 心跳:启动立即扫一次,之后每 60 秒扫一次。
  • 补跑:错过时在 max(创建时间, 7 天前, 启用时刻) 之后找最近一个槽补跑一次;迟到超过 2 分钟标记为 missed。
  • 抖动:cron 任务派发延迟 = sha256(taskId) % (min(10, 相邻间隔-1) * 60) 秒,同一任务恒定,避免整点同时触发。
  • 重试:建会话或投递失败按 5/15/30 分钟重试,最多三次;模型回合失败不重试。
  • 并发:同一任务同时只跑一次。

运行一轮的过程:

  1. ctx.sessionController.create({ cwd }) 新建会话,工作目录取任务配置的,否则取最近会话的。
  2. resolveAgent 后把标题改成「任务名 · 月-日 时:分」;会话 id 记进隐藏名单,从左侧列表过滤掉。
  3. 订阅 session/event,投递指令,等 turn/end:reason.kind === "completed" 记成功,其余(error、blocked、aborted、timeout 等)记失败并保留原因;45 分钟没结束按超时失败处理。
  4. 运行记录写进索引,每个任务保留最近 50 条。
  5. 任务由对话里的工具创建且开着通知时,跑完向创建它的那个会话发一条完成/失败消息;面板建的任务没有创建会话,不发。

状态只存在一个文件里:

~/.dsh/routines/
  scheduled-tasks.json          # 任务索引:名称、描述、指令、调度、运行记录

旧版本写在 <taskId>/SKILL.md 正文的任务,读取索引时会自动搬进 prompt 并删掉目录。

安装与启用

从插件市场安装,索引源是作者自己用 GitHub Pages 提供的:

https://leinaldo.github.io/dsh-routines/market/index.json
  1. 打开 插件 → 发现 → 添加索引源,填上面的 URL。
  2. 在列表里找到 定时任务,点 安装。
  3. 重启 DSH,左侧栏出现「定时任务」。

本地开发方式:

~/.dsh/plugins/dsh-routines
  1. 把仓库目录放到 ~/.dsh/plugins/dsh-routines。
  2. 在 ~/.dsh/profiles/desktop/package.json 的 dependencies 加 "dsh-routines": "file:/Users/leinaldo/.dsh/plugins/dsh-routines"(路径按本机调整)。
  3. 在同一个文件的 dsh.profile.bundles 末尾加 "dsh-routines"。
  4. 在 profile 目录执行 pnpm install,然后重启 DSH。

宿主代码在启动时加载,改完必须重启才生效;客户端面板随页面刷新重载。

典型用法

在侧边栏面板里操作:「新建」填名称、描述、指令、调度方式、工作目录;卡片上「立即运行」不改排期,只推 lastRunAt;「停用」只停自动派发,停用后手动运行也会被拒绝。「运行记录」展开后每条都有状态、时间、耗时、token、摘要与「查看会话」,点进去就是那次运行的会话——运行会话不出现在左侧列表,只从这里进入。

让模型直接建任务,不必先开面板:

工具 作用
routine_create 建任务:name、prompt 必填,cron_expression / fire_at / cwd / notify_on_completion 可选
routine_list 列出所有任务、下次运行时间与指令
routine_update 只改传入的字段;enabled:false 停用
routine_delete 删任务连同运行记录
routine_run 立即跑一次,不改排期

在对话里说「每天 12 点帮我总结 AI 资讯」时,模型会按工具描述在内置 schedule_* 与本插件之间选。想稳定走本插件,点名「用定时任务建」,或直接说「每次新开对话跑」。

HTTP 接口(面板底层就是这些):

方法 路径 说明
GET /dsh-routines/tasks 任务列表视图(含下次运行、最近一次状态、运行中标记)
GET /dsh-routines/task?id= 单个任务(含 prompt)与全部运行记录
GET /dsh-routines/defaults 默认工作目录
POST /dsh-routines/tasks/create {name, description?, prompt, cronExpression?\|fireAt?, cwd?, notifyOnCompletion?}
POST /dsh-routines/tasks/update 同上字段 + id,另支持 enabled、disableJitter
POST /dsh-routines/tasks/delete {id},任务文件与运行记录一起删
POST /dsh-routines/tasks/run {id},立即运行(不改排期)

适用场景与注意

适合这些情况:已经有一个想在固定时间跑的独立任务,希望每轮都是干净上下文、跑完能查回执;或者想用一次性任务做「跑到点就不动」的提醒。

几个需要留意的点:

  • 插件以当前 dsh 进程权限运行,装之前应先读一遍源码和许可证(MIT,见仓库 LICENSE)。
  • 需要审批的任务会停在审批卡上,直到超时记失败——没有无人值守审批策略。
  • 没有系统通知,只有发给创建会话的完成消息和面板状态;也没有费用字段,DSH 宿主只暴露 token,不暴露价格。
  • 运行会话的隐藏只做在网页端,代价是名单更新依赖这套客户端代码,宿主改列表实现时要跟着改。
  • 存储根目录只取 DSH_HOME 或 ~/.dsh,不读 ctx.baseDir——GUI 启动时后者常是 /,会导致面板永远读到空索引。

小结

dsh-routines 把 DSH 的定时动作从「提醒投递」升级为「运行记账」,调度语义、补跑和抖动都按 Claude Routines 对齐,代价是指令必须自包含、每轮新开会话。

  • 目录页:https://www.skillhub.cn/plugins/leinaldo/dsh-routines
  • GitHub:https://github.com/leinaldo/dsh-routines
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜