安装
在 DeepSeek Harness 里通过 dsh-market 安装
dsh plugin --profile web add dshmarket
或使用命令行
dsh plugin --profile web add @goodandready/dsh-cron
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络。请先审阅源码,并尽量锁定 commit(github:owner/repo#sha)。
README
⚡ 概述与问题
自主 AI 智能体经常需要执行周期性任务:生成每日晨报、整理缺陷跟踪、检查 API 健康状态、同步数据库或定期执行 Git 清理。如果 Harness 内没有专用调度器,用户只能依赖外部 crontab 封装、复杂的 webhook 方案或手动干预。
@goodandready/dsh-cron 是 DeepSeek Harness 的原生全栈调度与后台自动化插件。它将标准 cron 表达式、自然语言间隔语法与自主智能体执行连接起来:
- 完善的可视化任务管理器 —— 侧边栏按钮带可折叠的活跃任务列表(下次运行时间或实时状态,行数有上限且状态可记忆),以及功能齐全的面板:按类型、模型、渠道筛选,暂停、立即运行、复制、导出/导入与创建任务。
- 交互式“由 DSH 创建”流程 —— 与智能体对话,把高层需求转化为规范的定时任务。
- 自主工具调用 —— 原生
cron_*工具让智能体在会话中自行安排后续执行。 - 健壮的调度器与原子存储 —— 基于
croner:间隔别名、一次性延时任务、原子写入、运行历史与成本追踪。 - 六种执行运行时 —— shell、Node.js、Python、HTTP/webhook、远程 SSH 与 Docker,并支持按任务的环境变量、工作区绑定以及面向代码修改任务的隔离 git worktree。
- 多渠道路由与模板 —— 一次运行可投递到 Telegram、dsh-kanban、Discord、Slack、ntfy、Bark、PushPlus、语音(
dsh-tts)与 Gitea,支持{变量}消息模板与按 DSH 凭据名称引用的密钥。
🏗️ 架构
graph TD
subgraph Client ["Web 客户端 (DSH UI)"]
SidebarBtn["侧边栏时钟按钮<br/>(DSH 客户端插槽)"]
Overlay["任务管理面板<br/>(标签: 全部 / 活跃 / 暂停 / 已完成)"]
CreateWithDSH["“由 DSH 创建”对话框<br/>(自然语言任务)"]
ManualForm["手动任务表单<br/>(运行时、cron、超时、重叠策略、渠道)"]
SettingsCard["设置卡片<br/>(渠道、模板、凭据)"]
end
subgraph Server ["服务端 (Cordis 与 DSH 服务)"]
HttpRoutes["HTTP REST API<br/>(/dsh-cron/*)"]
AgentTools["工具调用网关<br/>(cron)"]
Scheduler["TaskScheduler 引擎<br/>(Croner 实例 + one-shot 定时器)"]
Store["原子 TaskStore<br/>(tasks.json 原子写入)"]
AgentRunner["智能体会话调度器<br/>(以指定模型执行提示词)"]
Runtimes["执行运行时<br/>(shell、node、python、http、ssh、docker)"]
Notify["投递路由<br/>(模板 + 9 个渠道)"]
Secrets["凭据引用<br/>(DSH credentials / ENV)"]
end
SidebarBtn --> Overlay
Overlay --> CreateWithDSH
Overlay --> ManualForm
SettingsCard --> HttpRoutes
CreateWithDSH -->|POST /chat/start| HttpRoutes
ManualForm -->|POST /tasks| HttpRoutes
HttpRoutes --> Scheduler
AgentTools --> Scheduler
Scheduler --> Store
Scheduler -->|按间隔/一次性触发| AgentRunner
Scheduler --> Notify
✨ 功能与能力
1. 可视化任务管理器
点击 DSH 侧边栏中的时钟图标(位于“新会话”按钮旁)打开管理面板:
- 状态过滤标签:全部、活跃、已暂停、已完成。
- 即时操作:立即运行(Run Now)、暂停/恢复调度、带确认的删除。
- 一键预设模板:每日摘要、每周回顾、待办监控。
- 运行历史:打开任务卡片查看历史运行 —— 时间、耗时、状态(成功 / 失败 / 超时 / 跳过 / 错过)、输出与错误。
- 快捷计划预设:在任务编辑弹窗中通过预设按钮一键填入常用频率(
15m、1h、Daily 09:00、Weekdays、Weekly Mon),并即时更新自然语言预览。 - 自动暂停与预算保护徽章:当任务因预算熔断机制(Burn Guard)自动暂停或手动暂停时,任务卡片上显著展示包含具体原因的状态徽章。
- 汇总统计栏:活跃任务数、总运行次数、总 token 消耗与估算美元成本。
2. “由 DSH 创建”对话框
无需猜测 cron 语法,用自然语言即可创建任务:
- 点击 Create ⌄ ➔ Create with DSH。
- 描述要自动化的内容(例如:“每个工作日早上 9 点检查未处理的 PR 并起草评论”)。
- 插件会创建一个注入了调度器指令的专属智能体会话。智能体会与你确认细节 —— LLM 还是 NO-LLM shell 任务、准确的 cron 表达式、在你的 DSH 安装中可用的经济型模型,以及是否启用“静默规则”(仅在新事件或故障时告警)—— 评估属于对话内定时提醒(
schedule_create)还是后台自动化(cron),并在获得您的确认后通过cron工具(action: 'create')注册任务。
2. DSH 核心内置 schedule 与 dsh-cron 对比
DeepSeek Harness 内置了轻量级扩展 @deepseek-ai/dsh-schedule,用于会话内的基础定时提醒。下表帮助您根据场景选择合适的工具:
| 功能维度 | DSH 核心 schedule (@deepseek-ai/dsh-schedule) |
@goodandready/dsh-cron |
|---|---|---|
| 主要定位 | 当前会话内的定时提醒与催办消息 | 无人值守的后台自动化执行器与任务编排引擎 |
| 执行上下文 | 当前活动会话内 | 独立的隔离智能体会话或外部后台进程 |
| 执行运行时 | 仅当前会话提示词(LLM) | 9 种运行时:llm、script (bash/sh)、node、python、http (REST/webhook)、ssh、docker、skill、workflow |
| 模型工具 | schedule_create、schedule_list、schedule_delete |
统一 cron 工具(action: create、list、get、update、pause、resume、run、delete) |
| 工具模式体积 | 约 1.5k 字符 | 约 1.5k 字符(由 9 个工具合并为 1 个,节省约 12k 字符上下文) |
| 推送渠道 | 仅限当前会话 | 多渠道:Telegram、Discord、Slack、Webhook、Kanban、ntfy、Bark、PushPlus、语音 (TTS)、Gitea |
| 代码修改隔离 | 无 | 临时或保留的 git worktree 隔离环境(worktree: true) |
| 成本与 Token 限制 | 无 | 成本熔断防护:costLimitUsd、dailyCostLimitUsd、tokenLimit 自动暂停 |
| 容错与健康检查 | 无 | 指数退避自动重试、失败自动诊断、心跳监测 (Dead Man's Snitch / Better Uptime) |
| 静默规则 (Silent Rule) | 无 | 无新事件或变更时完全静默(杜绝通道垃圾消息) |
| 任务管理 | 基础列表与删除 | 完整 UI 管理器、运行历史、日志查看器、指标统计、手动触发、导入导出、配置同步 |
3. 智能体工具 (cron)
自主智能体通过单个统一的 cron 工具直接管理定时任务,大幅降低模型模式开销:
| 动作 (action) | 说明 | 核心参数 |
|---|---|---|
create |
创建新的后台定时任务或自动化作业 | title、schedule、prompt、type、model、channels、delivery 等 |
list |
列出任务的状态、下次运行时间、token 总量与成本估算 | status ('all'、'active'、'paused'、'completed') |
get |
根据任务 ID 获取单项任务的完整配置 | id |
update |
就地修改现有任务(切换到代码执行运行时需 confirmCodeSwitch: true) |
id、修改字段 |
pause |
暂停调度而不删除配置 | id |
resume |
恢复已暂停的调度 | id |
run |
触发一次立即的带外运行 | id |
delete |
永久删除任务及其历史 | id |
[!NOTE] 上下文优化与平滑迁移:此前 9 个单独的工具模式在每次模型轮次中消耗约 13.6k 字符。整合为单一
cron工具后,模式开销减少约 88%(降至约 1.5k 字符)。旧工具名(cron_create_task、cron_schedule_task、cron_list_tasks等)被优雅拦截,并返回清晰迁移提示,引导模型使用带对应action的cron工具。对于简单的会话内提醒,模型将建议使用核心内置的schedule_create。
会话中模型可进行的调用示例:
cron({
"action": "create",
"title": "Morning digest",
"schedule": "0 8 * * 1-5",
"prompt": "Prepare a brief morning digest of active tasks and open tickets.",
"type": "llm",
"delivery": "isolated"
})
4. 调度表达式语法
基于 croner,支持标准 5 段 cron 表达式与友好的别名:
0 9 * * 1-5—— 工作日 09:00*/15 * * * *—— 每 15 分钟0 0 * * 0—— 每周日午夜every 10m/every 2h/every 30s—— 自然语言间隔daily/hourly/weekdays快捷方式,以及标准@hourly/@daily/@weekly/@monthly/@yearly与@every 30m- 任务级时区 —— 可为任务设置 IANA 时区(如
Europe/Berlin);未设置时按服务器本地时间调度 - 一次性任务:
at: 2026-09-05T15:00:00Z(精确 ISO 时间戳)或相对延时in 20m/in 2h(也接受через 15 минут之类的俄语输入)。一次性任务在单次运行后自动转为completed,显示在 已完成 标签下。
5. 执行可靠性
- 自动重试 —— 按任务设置
maxRetries与基础retryBackoffMs:失败(error/timeout)的运行按指数退避自动重试,成功后计数归零。 - Misfire 策略 —— 选择守护进程离线期间错过的运行如何处理:
skip(默认 —— 记录缺口)、runOnce(迟执行一次)或catchUpAll(迟执行并记录缺口)。skip下错过的一次性任务直接转为completed,不再过期触发。 - 并发上限 —— 插件设置
maxConcurrent限制并行运行数;超出的运行记录为skipped并附原因。 - 实时执行指示 —— 任务列表中的脉冲状态图标与运行计时器。
6. 执行运行时
每个任务可选择自己的运行时;非 LLM 运行时不需要模型,也不消耗 token:
- Shell(
script)—— 通过 Harness shell 执行命令或脚本,支持env与cwd。 - Node.js(
node)与 Python(python)—— 指定解释器(nodePath、pythonPath)运行片段;Python 会自动识别项目虚拟环境。 - HTTP(
http)—— 以自定义请求头与请求体访问 URL,状态码与响应写入运行历史。 - SSH(
ssh)—— 通过dsh-remote-workspace配置(sshProfileId)或独立 host/key 字段在远程主机执行命令。 - Docker(
docker)—— 在镜像容器(dockerImage)中执行命令。 - 环境变量 —— 按任务的
env映射(界面中每行 KEY VALUE)应用于外部运行时;请勿在此存放密钥。 - 工作区与 worktree —— 将任务绑定到 Harness 工作区(
workspaceId);对会修改代码的智能体任务,可在隔离的 git worktree 中运行(worktree、keepWorktree)。
7. 成本控制:回退模型与支出保护(Burn Guard)
- 回退模型 —— 任务可以默认使用便宜模型,失败时改用更强模型完成:设置
fallbackModel(可选fallbackProvider),失败(error或timeout)的运行会在该模型上重试一次,之后才进入常规重试退避。历史记录会标明最终产出结果的模型以及是否使用了回退,两次尝试的用量与成本都会累计,模板变量{model}渲染完成运行的模型。回退仅适用于智能体类型(llm、skill、workflow)。 - Token 与成本支出保护(Burn Guard) —— 为任务配置严格预算上限:
costLimitUsd(总支出美元上限)、dailyCostLimitUsd(24小时滚动支出上限)和tokenLimit(Token总数上限)。一旦达到任一阈值,任务将自动暂停并记录pausedReason(cost_limit_exceeded、daily_cost_limit_exceeded或token_limit_exceeded),同时向所有配置的通知渠道发送报警通知。
8. 会话集成与权限
- 按任务的权限预设 ——
default、read-only、workspace-write或full在提示词执行前应用于任务会话。 - 会话自动归档 —— 隔离的 cron 会话在运行后自动归档(尽力而为),不干扰聊天列表。
- 历史 → 会话 —— 每次 LLM 运行都会记录会话,可直接从历史记录打开对话。
9. 按规则保持安静
有输出的任务可以设置用自然语言描述的静默规则(例如“当没有分区使用率超过 80% 时保持安静”)。运行成功时,由便宜模型对照该规则判断输出,若结论为保持安静则跳过报告,并在运行历史中记录原因。遵循 fail-open:没有规则、没有模型、调用失败或答案无法解析时都会照常投递报告。插件设置 silentRuleModel 指定用于判断的模型。
10. 失败诊断
智能体任务可以请求诊断:设置 inspectOnFailure 后,失败(error 或 timeout)的运行会连同任务提示词与截断输出一起交给模型,运行历史中会保存简短诊断与具体的提示词修改建议。历史记录提供按钮把该建议载入编辑表单 —— 不会自动应用。模型由 inspectorModel 指定,消息模板中可使用 {diagnosis}。模型不可用或调用失败时,失败的运行保持原样。
11. 通知渠道与消息模板
运行完成后,报告会发送到该任务配置的所有渠道 —— Telegram、dsh-kanban、Discord、Slack、ntfy、Bark、PushPlus、语音(dsh-tts)以及 Gitea issue:
- 任务迁移 —— 将全部配置导出为版本化 JSON,并在别处导入(含预览摘要);导入的任务处于暂停状态。
- 按任务选择渠道 —— 在任务表单中勾选渠道;显式选择会覆盖旧版
notifyTelegram/kanbanMode开关,留空则回退到它们。 - 故障隔离 —— 某个渠道不可用会记录在调度器日志中,其余渠道仍会收到报告;失效的 webhook 不会吞掉整份报告。
- 消息模板 —— 支持全局模板、按渠道覆盖或按任务模板,变量为
{title} {id} {status} {output} {error} {duration} {schedule} {time} {tokens} {cost}。未知占位符保持原样,失败运行默认使用失败模板。 onlyOnFailure—— 全局或按任务生效:成功运行静默,仅发送error/timeout。- 凭据按名称引用 —— webhook token 与 Telegram bot token 填写 DSH 凭据的名称(
botTokenRef、ntfyTokenRef、pushplusTokenRef、giteaTokenRef),发送时通过 DSH credentials 服务解析,并可回退到环境变量,且绝不会经过插件设置。webhook URL 与 Bark 设备键本身内嵌密钥,因此保存在插件设置文件中,但返回浏览器时始终为掩码,界面回传的掩码值也不会覆盖已保存的值。 - 投递超时 —— 每个渠道请求都有上限(
deliveryTimeoutMs,默认 15000 毫秒,可在设置面板或settings.yaml中调整),且各渠道并发发送:无响应的端点只记录为失败,不会拖慢其他渠道或下一次调度。限制作用于整个渠道处理过程,也覆盖凭据解析——它不支持 abort 信号。 - Telegram —— 带状态徽标(✅ / ❌)、耗时、调度描述与等宽输出块的 Markdown 报告;动态值会被转义。凭据可直接填写,或从 DSH
settings.yaml的dsh-messenger-gateway段继承(尽力而为)。 - Discord / Slack —— 通过 webhook 投递:Discord 使用按运行状态着色的 embed,Slack 使用纯文本正文。
- ntfy / Bark / PushPlus —— 移动推送,支持主题/设备键与可选 bearer token;Bark 的标题与正文放在请求路径中,PushPlus 端点可指向自建代理。
- 语音 ——
dsh-tts通过其 HTTP 路由朗读报告(ttsBaseUrl,默认http://127.0.0.1:3080)。 - Gitea —— 创建包含运行报告的 issue(
giteaBaseUrl、giteaRepo、token 凭据);失败运行标记为cron、bug、alert。 - 测试发送按钮 —— 在安排关键任务前现场验证 Telegram 连通性。
12. Kanban 集成与成本统计
- 自动创建 Kanban 卡片 —— 当
kanbanMode为on_failure或always时,插件在dsh-kanban中创建卡片(on_failure→error/timeout时进入 Backlog;always→ 完成后进入 Done/Backlog)。 - Token 与执行成本计量 —— 按运行与任务统计 token 消耗(输入、输出、缓存读取),基于内置价格表估算美元成本,并提供汇总分析栏。
13. 重叠策略与执行超时
- 执行超时(
timeoutSeconds) —— 达到限制后,shell 子进程通过 abort 信号立即终止,智能体会话被释放以停止消耗 token。默认1800(30 分钟)。 - 重叠策略(
overlapPolicy) —— 上一次运行尚未结束时再次触发调度时的行为:skip(默认):丢弃重叠的运行,在历史中记录skipped;queue:将下一次运行排队,当前任务完成后自动开始;replace:通过AbortController中止当前运行并启动新的执行。
如果守护进程在计划时刻处于离线状态,启动时该次运行会被记录为 missed,历史空档始终可见。
14. 心跳监控(Dead man's switch)
- 在插件设置中配置
heartbeatUrl与heartbeatIntervalSec,调度器会按间隔 GET 该地址 —— 外部监控可在心跳停止时告警。 - 内置
GET /dsh-cron/heartbeat端点返回存活状态、活跃任务数与最近运行时间,便于自建看门狗。
15. 来自配置的声明式任务(#50)
长期运行的任务可以直接声明在配置文件里,而无需在界面中手工重建。配置文件拥有这些任务:每次插件启动时会创建或更新它们,从文件中消失的任务会被删除。
在配置文件(cordis.patch.yml)的插件段加入 jobs 列表:
dsh-cron:
jobs:
- id: nightly-backup
title: Nightly backup
schedule: "0 3 * * *"
type: script
prompt: "bash /path/to/backup.sh"
channels: ["telegram"]
timeoutSeconds: 3600
- id: morning-digest
title: Morning digest
schedule: "0 8 * * 1-5"
type: llm
prompt: "Prepare a brief morning digest of active tasks."
provider: my-provider
model: provider-id/model-id
- 每条必填:
id、title、schedule;以提示词承载有效载荷的类型(script、node、python、ssh、docker、llm、skill、workflow)还需非空prompt。http例外:目标由httpUrl(或prompt)给出。 - 其余任务字段按原样透传,校验与 API 一致:
channels、model、provider、fallbackModel、silentRule、inspectOnFailure、timezone、timeoutSeconds、template、env、cwd,以及运行时字段(nodePath、pythonPath、httpUrl、httpMethod、httpHeaders、httpBody、sshProfileId、sshTarget、dockerImage、workspaceId、worktree、keepWorktree、skillName、workflowName)。 - 声明式任务标记为由配置管理;面板中显示来源标签而不是编辑/删除按钮。
- 对配置任务的编辑、暂停、恢复、切换与删除在面板和 API 上返回
409,携带配置任务现有id的创建或更新请求POST /dsh-cron/tasks同样被拒绝 —— 配置文件的来源为唯一真值。立即运行仍然可用。 - 通过 UI、API 或智能体工具创建的、
id相同的任务绝不会被覆盖:该条目会被跳过,冲突写入日志。 - 会执行代码的类型照常激活,但启动时插件会向日志写警告,使通过配置引入的代码路径可见。
- 条目逐条校验并带下标(
config.jobs[i]: …);一条坏条目会被跳过,不会阻止其余任务或整个配置。
16. 外部 REST API(/dsh-cron/api/*,#54)
外部系统(CI、宿主机 cron、curl)无需打开面板即可驱动调度器。这是唯一由 bearer 令牌保护的接口;面板路由保持本地且防跨站。
令牌是插件设置 apiToken(与所有密钥一样掩码显示)。认证与错误:
- 未配置令牌 → 整个接口返回
503; - 缺少或错误的
Authorization: Bearer <token>→401,比较为常量时间。
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/dsh-cron/api/tasks |
任务列表(status / query 过滤,同面板) |
GET |
/dsh-cron/api/tasks/:id |
读取单个任务 |
POST |
/dsh-cron/api/tasks |
创建任务;带 id 时更新现有任务 |
DELETE |
/dsh-cron/api/tasks/:id |
删除任务 |
POST |
/dsh-cron/api/tasks/:id/run |
强制执行一次 |
这些操作复用面板处理器,因此对会执行代码类型的 x-dsh-cron-confirm: script 门禁以及对配置任务的 409 拒绝与 UI 完全一致。
BASE="http://127.0.0.1:3080"
TOKEN="<API_TOKEN>"
# 列表
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/dsh-cron/api/tasks"
# 创建;请求体带 id 时为更新
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"id":"cleanup","title":"Cleanup","schedule":"0 4 * * *","prompt":"Remove stale temporary files."}' \
"$BASE/dsh-cron/api/tasks"
# 强制执行
curl -s -X POST -H "Authorization: Bearer $TOKEN" "$BASE/dsh-cron/api/tasks/cleanup/run"
# 删除
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" "$BASE/dsh-cron/api/tasks/cleanup"
# 会执行代码的任务还需确认头
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "x-dsh-cron-confirm: script" \
-H "Content-Type: application/json" \
-d '{"title":"Disk check","schedule":"0 * * * *","type":"script","prompt":"df -h"}' \
"$BASE/dsh-cron/api/tasks"
17. Prometheus 指标(#53)
GET /dsh-cron/metrics 返回 Prometheus 文本格式,无需新增依赖即可被抓取:
dsh_cron_tasks_total{status}—— 按状态统计的任务数(gauge)。dsh_cron_task_last_duration_seconds{task}—— 任务最近一次完成运行的耗时(秒,gauge)。dsh_cron_runs_total{status}—— 自插件进程启动以来完成的运行数(counter);状态为success、error、timeout、skipped、missed。dsh_cron_run_records—— 当前保存在内存中的运行记录数(gauge)。
导出内容只有计数、状态和耗时;提示词、运行输出与任务配置不会出现在其中。
scrape_configs:
- job_name: dsh-cron
static_configs:
- targets: ["127.0.0.1:3080"]
metrics_path: /dsh-cron/metrics
18. 严格的渠道校验(#121)
创建或更新任务时若包含未知的投递渠道 id,现在会返回 400 并列出违规项:
{ "ok": false, "error": "Unknown channel ids: email_ping", "unknownChannels": ["email_ping"] }
Changed in v0.2.7:此前未知 id 会被静默丢弃,客户端即使有拼写错误也会得到 ok: true,最终得到一个不投递任何地方的任务。
导入有意保持宽容(文件可能来自旧版本):未知 id 会从导入的任务中丢弃,但会在响应(unknownChannels)中列出并写入调度器日志,而不是无声消失。
19. 安装后校验(#126)
deploy.sh 新增仅校验模式,用于检查已安装的配置而不安装任何东西:
bash deploy.sh verify [exact-version]
它确认配置报告了指定版本(默认取 package.json 的版本),登录 Web UI,然后下载客户端 bundle 并确认其中包含包名。
为什么需要它:Web 配置可能位于认证插件之后并对匿名请求返回 401,而插件客户端 bundle 只能通过认证后索引中打印的精确组合 ?? URL 获取 —— 裸的 /plugins/<name>/client.js 会返回 404。因此校验需要先建立已认证会话。
校验使用的环境变量:DSH_WEB_BASE(默认 http://127.0.0.1:3080)、DSH_WEB_TOKEN(令牌;未设置时脚本从单元日志读取最后一个)、DSH_WEB_UNIT(默认 dsh-web.service)。脚本中不含任何密钥。
20. 内部重构:调度解析与排程(#97)
面向开发者,行为不变。parseScheduleExpression 被拆分为保持相同分支顺序的小函数 —— parseAtExpression、parseRelativeOneShot、parseIntervalExpression、parseAliasExpression、parseCronExpression,scheduleTask 拆分为 clearScheduled、scheduleOneShot、scheduleCron。原有测试全部通过,并新增了针对分支优先级与错误的测试。
21. 性能与进程隔离增强包(v0.2.9,#134)
- 进程树终止隔离:Shell 和 Script 任务在独立进程组启动(POSIX 下
detached: true);中止或超时向整组发送-child.pid SIGTERM -> SIGKILL,杜绝孤儿进程与僵尸进程。 - 并发控制限流:默认安全阈值
maxConcurrent = 2,避免定时重叠引发 CPU 和内存峰值。 - 瞬态错误重试:针对网络抖动和模型速率限制(
429、502、503、504、ECONNRESET)提供指数退避重试(最多3次)。 - 网络与前端优化:
GET /dsh-cron/tasks支持ETag与304 Not Modified;前端页面根据visibilityState自适应轮询(前台 8s,后台 30s)。 - 历史记录轮换与归档:活动任务仅保留最新 100 次运行,超出部分自动归档至
tasks-history-archive.json。 - 自主 PR 审查配方 (#33):Template Hub 预置配方与
prReviewerEnabled设置项。
22. 自动化、任务链与可观测性包(v0.2.10,#137)
- Telegram 双向交互控制:任务通知附带内嵌操作按钮(
🚀 立即运行、⏸️ 暂停/恢复、📋 最新日志)。由POST /dsh-cron/telegram/webhook处理,严格鉴权 Chat ID 并调用answerCallbackQuery反馈。 - 任务链上下文与动态变量插值:配置
onSuccess与onFailure下游触发器。父任务的执行结果与元数据自动传递给子任务,在 Shell 任务中提供$DSH_PREV_OUTPUT、$DSH_PREV_TASK_ID、$DSH_PREV_STATUS环境变量,在 LLM Prompt 中支持{{prev.output}}(或{{prevOutput}})、{{prev.taskId}}、{{prev.status}}占位符插值。Prompt 额外支持动态运行时时间与元数据变量:{{date}}、{{time}}、{{datetime}}、{{timestamp}}、{{year}}、{{month}}、{{day}}、{{taskId}}、{{taskName}}、{{runCount}}。内置最大 5 级深度递归防护,杜绝死循环。 - 模型结构化动作指令:自主分析任务可输出 JSON 指令触发级联任务(
trigger_task)、定向告警(notify)或创建 Issue。受llmActionsEnabled: false严格保护。 - 历史归档与延迟洞察:REST 接口
GET /dsh-cron/tasks/:id/archive(支持分页)与GET /dsh-cron/tasks/:id/stats;UI 任务卡片展示耗时彩色徽章(<5s 绿,<30s 黄,≥30s 红)。 - Prometheus 监控增强:
/dsh-cron/metrics导出当前活动并发量dsh_cron_concurrent_running、各任务 Token 计数器及成本预估指标。
23. 高级可靠性、自愈、心跳与体验包(v0.2.11,#139)
- 心跳与寂静监控(Heartbeat / Dead Man's Snitch):针对外部备份与后台作业提供反向监控。外部脚本定期向
/dsh-cron/heartbeat/:id发送请求;超出heartbeatIntervalSeconds+ 宽限期未打卡时,任务标记为missed,即刻推送失联告警并触发onFailure应急流程。 - 执行前置检查(Pre-flight Gates):执行前先验证条件(HTTP 状态 2xx、命令退出码 0、最低可用磁盘 MB)。未通过直接置为
skipped,杜绝因外部环境异常产生无意义的模型 Token 消耗与错误干扰。 - 试运行与调度模拟器(Dry-Run & Simulator):接口
POST /dsh-cron/tasks/:id/dry-run与 UI🧪 试运行按钮支持无副作用执行(不入库历史、不发渠道通知);POST /dsh-cron/schedule/preview实时计算未来 5 次运行时间。 - 优先级队列与并发池(Priority Queues):并发满载时,等待队列严格依据任务
priority(1 最高,10 最低)调度。 - 自愈脚本与 AI 根因诊断(Self-Healing):任务失败后自动执行补偿指令
selfHealingCommand(例如重启服务或清理临时空间);autoDiagnose自动生成 AI 故障根因摘要。 - UI 交互式归档与管道全景:支持分页浏览任务历史运行全量输出,直观展示
➜ 成功触发与↳ 失败触发关联关系。
24. 自动挂载智能体预设与工具支持 (#141 / GH-1,v0.2.12 新增)
- 自动挂载智能体预设:计划执行的自主
llm任务和交互式启动现在会自动解析并挂载系统智能体预设(默认通过setup钩子中的presets.mount(agentCtx, preset.id)挂载用户的标准预设)。计划会话现已具备完整的工具调用能力(文件读写、工作区操作、Shell 终端等),彻底解决此前空会话无工具调用的问题。 - 单任务预设覆盖:可在 Web 管理界面、REST API 或配置文件中为具体任务配置独立的
agentPreset标识(例如coding、system、minimal)。未设置时自动继承系统默认预设。 - 优雅降级保障:当未安装
agentPresets服务或指定了未知的预设 ID 时,调度器仅记录友好的警告日志,并安全平稳地继续执行基础模型会话,避免定时任务中断。
25. 常驻持久会话与上下文延续 (targetSessionId,v0.2.13 新增,#143)
- 跨周期会话上下文延续:支持在任务中配置
targetSessionId。设置后,调度器将在每次定时触发时通过agents.resume()唤醒已有会话,而不再每次生成孤立的临时会话(cron-exec-${id}-${uuid})。智能体能够完整继承上一轮对话的历史记忆与分析结论。 - 上下文窗口保护与轮转机制 (
targetSessionReset):为防止高频执行导致模型上下文窗口超限与 Token 成本暴增,支持智能轮转策略:never:持续累积单一会话,不重置。daily:每日自动开启全新子会话(后缀<id>-YYYY-MM-DD)。weekly:每周自动开启全新子会话(后缀<id>-YYYY-Www)。- 日期变量插值:
targetSessionId中支持{{date}}占位符,自动注入当前日期YYYY-MM-DD。
- 主界面原生可见交互:持久会话不会被标记为
ephemeral/internal,且在执行后跳过自动归档(sessions.archive()),用户可在 DSH 聊天列表中直接查看并继续手动对话。 - 预设工具链无缝适配:恢复会话时同样完整挂载
agentPresets,保障文件读写、代码编辑与终端工具持续可用。 - 致谢:功能灵感源自社区开发者 @RaulLazaro。
26. 系统稳定性、硬化与自愈维护包 (v0.2.14, #145)
- 重试预算自动重置:彻底修复重试耗尽后的计数残留问题。当任务耗尽配置的重试次数(
maxRetries)后,attempts计数器自动清零,确保后续周期的定时调度享有完整的重试预算。常规计划执行或手动触发也均保证以干净的重试预算启动。 - 清除队列僵尸任务:通过界面/API 暂停或删除任务时,调度器会立即将其从并发等待队列(
this.queue)中剔除;并发槽位释放出队时,非激活或已删除的任务也会被自动安全跳过。 - 历史归档容量上限保护:针对长期运行和高频调度的生产环境,
tasks-history-archive.json针对每个任务安全限制保留最新的 1,000 条运行记录,消除无限制磁盘占用与同步 JSON 序列化卡顿。 - 灾难恢复与存储自动备份:
TaskStore在每次成功持久化时自动维护原子的tasks.json.bak备份副本。若发生进程异常导致数据损坏,存储引擎会自动保存现场切片tasks.json.corrupted.<timestamp>供故障分析,并无缝从备份中自愈恢复。 - 上下文超限自愈与平滑轮转:在常驻持久会话(
targetSessionId)中,若智能体因模型上下文窗口溢出(context_length_exceeded)失败,运行器将精准捕获超限错误,归档已满会话,自动轮转至全新子会话并平滑重试,避免任务中断。 - Windows 进程树彻底终止:在 Windows 系统上,外部进程任务被取消或超时终止时,改为执行
taskkill /pid <pid> /T /F,杜绝孤儿进程和后台残留外壳。
27. 弹窗视口高度自适应与包体积精简 (v0.2.15, #153, #148, #151, #152)
- 视口高度约束与粘性底部操作栏:所有弹窗(包括任务编辑、新建及推荐模板预设)现已严格受控于视口尺寸
max-height: min(90vh, calc(100vh - 36px)),并内置平滑纵向滚动条。弹窗操作栏(“取消”、“保存”、“创建”)采用position: sticky底部悬浮固定,确保无论表单项多长或屏幕分辨率高低,操作按钮始终清晰可见且可随时点击。 - 遮罩层滚动溢出保护:弹窗遮罩层增加了安全边距与
overflow-y: auto,防止小屏设备在 Flex 居中时发生头部或底部截断。 - npm 包体积深度精简:从 npm 分发清单中剔除了多余的重复文档副本,使 tarball 体积立减 32 kB 以上,解压后体积减少约 102 kB。
- Cordis 客户端注入依赖规范化:在
package.json的dsh.client.inject中完整声明了locale和slots服务依赖。
31. 质量加固与 CI 预检标准包 (v0.2.19, #149, #152, #155, #156, #162)
- 彻底消除空 catch 块 (#156):引入符合标准规范的
lib/best-effort.js模块,全面支持同步/异步安全调用、回退返回值和可选日志记录,清除了 runner、scheduler、store 及客户端中的所有 63 处空 catch 块。 - CI 工作流与本地预检门禁 (#162):新增自动化 CI 工作流(
.gitea/workflows/ci.yml与.github/workflows/ci.yml),集成本地预检门禁脚本scripts/ci-preflight.mjs,在出现语法错误、空 catch、颜色硬编码或信息泄露时自动阻断。 - 主题设计令牌现代化 (#149):将模态对话框与设置卡片中遗留的
rgba(...)全部重构为原生的color-mix(in srgb, var(--token) N%, transparent)。 - 插件清单注入声明规范化 (#152):在
package.json的dsh.client.inject中统一声明完整的 Cordis 包名(@deepseek-ai/dsh-client-locale、@deepseek-ai/dsh-client-ui-slots)。 - 生产管线导出连接 (#155):将此前仅在测试中调用的导出(
findDestructiveRecipe、shouldNotifyTask和TEMPLATE_VARIABLES)全面接入配方过滤、通知分发及模板生成核心逻辑。
30. 自更新模块英文与中文多语言支持 (v0.2.18, #160)
- 设置面板自更新多语言 (#160):在
lib/client-src/10-locales.js的英文 (en) 与中文 (zh) 字典中补全了全部 10 个自更新键值 (updater.title,updater.btnCheck,updater.checking,updater.btnUpdate,updater.updating,updater.desc,updater.current,updater.available,updater.upToDate,updater.success)。遵循 DSH 插件规范,插件核心内置英文与中文,俄语多语言由dsh-russian-lang统一扩展。
29. 客户端模块化解耦与原生主题标准化 (v0.2.17, #149, #150)
- 客户端模块化架构 (#150): 将庞大的单文件
lib/client.js(约 3950 行) 拆分为lib/client-src/下的 14 个高内聚模块文件 (各模块严格 <= 580 行)。集成零依赖构建脚本scripts/build-client.mjs并接入package.json(build:client,pretest),通过"files": ["lib/*.js", ...]避免开发源码冗余打包进 npm 发布包。 - DSH 语义化主题变量对齐 (#149): 将任务类型标签 (
onSuccess,onFailure,heartbeat,targetSession,preflight) 的内联样式全部替换为基于主题变量的.dsh-cron-tag-*类;模态框遮罩层接入自适应主题遮罩变量var(--dsw-alias-bg-mask, rgba(0, 0, 0, 0.75)),移除脉冲动画关键帧中的硬编码 RGBA。 - 标签治理与工单审计 (#95): 审计并确认全仓库 100% 统一规范使用仓库级标签集。
28. 应用内一键自更新与错误容错增强 (v0.2.16, #147, #155, #156)
- 插件自更新模块 (#147):新增应用内一键自更新机制 (
lib/updater.js)、/api/dsh-cron/update接口与设置面板专属卡片。自动轮询 npmjs 仓库最新版本,精准比对 Semver 版本号(含预发布版本),通过 DSH CLI 就地升级@goodandready/dsh-cron,无需 SSH 终端操作。POST 请求受跨域与来源保护 (rejectCrossOrigin)。 - 消除静默异常与错误追踪 (#156):全面消除空
catch异常压制:任务导入事务回滚失败记录warn级别日志、动态核心模块降级原因记录诊断日志、会话自动唤出失败向用户呈现友好提示。 - 死代码清理与模块导出精简 (#155):清理未引用的旧版实体 (
CHANNEL_LABELS,makeInspectAsk),收回 16 个内部工具函数的暴露权限,并将supportsSilentRule接入静默规则核心执行流水线。
📦 安装
dsh plugin --profile web add @goodandready/dsh-cron
重启 DeepSeek Harness 实例并刷新浏览器。
⚙️ 配置(settings.yaml)
可以在 settings.yaml 中配置,也可以通过 DSH 中的插件设置卡片交互式管理:
# settings.yaml
dsh-cron:
botToken: "" # Telegram Bot API 令牌(保密字段)
chatId: "" # 接收报告的 Telegram chat ID
notifyTelegram: false # 全局投递所有任务的报告
onlyOnFailure: false # 仅失败时投递报告
kanbanBaseUrl: "http://127.0.0.1:3000" # dsh-kanban HTTP API 基础地址
defaultTimezone: "" # 默认 IANA 时区(空 = 服务器本地)
maxConcurrent: 0 # 最大并行运行数(0 = 不限)
heartbeatUrl: "" # 心跳上报 URL(dead man's snitch)
heartbeatIntervalSec: 0 # 心跳间隔秒数(0 = 关闭)
# --- 投递渠道 ---
botTokenRef: "" # Telegram bot token 的凭据名称
template: "" # 全局消息模板,例如 "⏰ {title} — {status}"
channelTemplates: {} # 按渠道覆盖模板
deliveryTimeoutMs: 15000 # 每个渠道的投递超时;慢端点记为失败,不影响其他渠道
discordWebhookUrl: "" # Discord webhook
slackWebhookUrl: "" # Slack incoming webhook
ntfyUrl: "https://ntfy.sh" # ntfy 服务器;ntfyTopic / ntfyTokenRef
ntfyTopic: ""
ntfyTokenRef: ""
barkServerUrl: "https://api.day.app" # Bark 服务器;barkKey = 设备键
barkKey: ""
pushplusUrl: "https://www.pushplus.plus/send" # pushplusTokenRef
pushplusTokenRef: ""
ttsBaseUrl: "http://127.0.0.1:3080" # dsh-tts 基础地址
giteaBaseUrl: "" # giteaRepo = owner/repo,giteaTokenRef = 凭据名称
giteaRepo: ""
giteaTokenRef: ""
# --- 外部 REST API(#54)---
apiToken: "" # 外部 /dsh-cron/api/* 接口的 bearer 令牌(掩码;空 = 503)
配置参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
botToken |
string |
"" |
Telegram Bot API 令牌。留空时插件会尽力继承 DSH 设置中 dsh-messenger-gateway 配置的机器人。保密字段:界面只显示掩码值 |
chatId |
string |
"" |
接收报告的 Telegram chat ID。留空时回退到 dsh-messenger-gateway 的第一个允许会话 |
notifyTelegram |
boolean |
false |
全局开关:向 Telegram 投递运行报告 |
onlyOnFailure |
boolean |
false |
全局开关:仅对 error/timeout 运行投递报告 |
kanbanBaseUrl |
string |
"http://127.0.0.1:3000" |
用于自动卡片的 dsh-kanban HTTP API 基础地址 |
defaultTimezone |
string |
"" |
任务调度的默认 IANA 时区;空 = 服务器本地时间 |
maxConcurrent |
number |
0 |
并行运行上限;超出的运行记录为 skipped(0 = 不限) |
heartbeatUrl |
string |
"" |
心跳上报 URL,调度器存活期间按 heartbeatIntervalSec 间隔 GET |
heartbeatIntervalSec |
number |
0 |
心跳间隔秒数(0 = 关闭) |
botTokenRef |
string |
"" |
保存 Telegram bot token 的 DSH 凭据名称;发送时解析(回退顺序:botToken → messenger-gateway 设置 → 环境变量 CRON_TELEGRAM_BOT_TOKEN) |
template |
string |
"" |
带 {title}/{status}/{duration} 等占位符的全局消息模板;留空使用内置文本 |
channelTemplates |
object |
{} |
按渠道 ID 覆盖模板(telegram、discord 等) |
deliveryTimeoutMs |
number |
15000 |
每个渠道的投递超时;超时的端点记为失败,不拖慢其他渠道或下一次调度 |
discordWebhookUrl / slackWebhookUrl |
string |
"" |
Discord 与 Slack 渠道的 webhook 地址 |
ntfyUrl / ntfyTopic / ntfyTokenRef |
string |
"https://ntfy.sh" / "" / "" |
ntfy 服务器、主题与可选的 token 凭据名称(以 Authorization: Bearer … 发送) |
barkServerUrl / barkKey |
string |
"https://api.day.app" / "" |
Bark 服务器与设备键(键、标题和正文位于请求路径中) |
pushplusUrl / pushplusTokenRef |
string |
"https://www.pushplus.plus/send" / "" |
PushPlus 端点(可指向自建代理)与 token 凭据名称 |
ttsBaseUrl |
string |
"http://127.0.0.1:3080" |
用于语音播报的 dsh-tts 基础地址 |
giteaBaseUrl / giteaRepo / giteaTokenRef |
string |
"" |
Gitea 渠道:基础地址、owner/repo 与 API token 的凭据名称 |
telegramAllowedChatIds |
string |
"" |
允许执行交互式机器人命令的 Telegram Chat ID 或 User ID(英文逗号分隔) |
apiToken |
string |
"" |
外部 /dsh-cron/api/* 接口的 Bearer 令牌。保密字段,返回时掩码;为空时接口返回 503,错误值返回 401 |
说明:
- 运行历史上限为每任务 50 条(固定);每条记录最多保留 4000 字符输出。
- 任务在服务器本地时区执行;cron 表达式由
croner按主机时钟计算。 - 任务持久化在 DSH 数据目录(
cron/tasks.json),重启后保留;启动时会检测错过的一次性任务。
🔌 HTTP API 参考
所有端点由 DSH Web 服务器在 /dsh-cron/ 下提供。所有端点均受到强化的 HTTP 来源防护(isTrustedRequest):非回环远程客户端必须携带有效令牌(Authorization: Bearer <token> 或 x-dsh-cron-token),浏览器请求严格校验 Host 与 Origin 一致性并拒绝 Origin: null,同时限制 Sec-Fetch-Site 仅允许 same-origin 或 none。心跳 ping 端点严格要求 POST 方法。任务 GET 响应自动将敏感字段(env、httpHeaders、httpBody)掩码为 '[REDACTED]',并在更新操作提交 '[REDACTED]' 时安全保留已有原密钥。通过 HTTP 创建 script 类型任务还需要 x-dsh-cron-confirm: script 请求头。请求体大小上限为 1 MB。
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/dsh-cron/tasks |
任务列表;查询参数 status(all/active/paused/completed)、query(子串搜索)。返回任务、推荐模板与汇总统计 |
POST |
/dsh-cron/tasks |
创建或更新任务(携带 id 时为更新)。需要 title、schedule、prompt |
GET |
/dsh-cron/tasks/:id/history |
运行历史,?limit=20 |
POST |
/dsh-cron/tasks/:id/run |
立即手动运行 |
POST |
/dsh-cron/tasks/:id/pause |
暂停调度 |
POST |
/dsh-cron/tasks/:id/resume |
恢复调度 |
POST |
/dsh-cron/tasks/:id/toggle |
切换活跃/暂停 |
POST |
/dsh-cron/tasks/:id/duplicate |
创建暂停状态的副本:复制配置,重置运行历史与计数 |
GET |
/dsh-cron/recipes |
内置配方目录:按类别分组的现成监控预设,全部为只读操作 |
GET |
/dsh-cron/tasks/export |
仅含任务配置的版本化 JSON —— 不含历史与计数。渠道按名称引用凭据,但手动填写在任务中的 env 与 HTTP 请求头属于配置,会出现在文件里 |
POST |
/dsh-cron/tasks/import |
校验文档并以 add、replace 或 skip 策略导入;支持 dryRun 预览。导入的任务始终为暂停状态,恢复不会自动触发 |
PATCH |
/dsh-cron/tasks/:id |
部分更新(仅白名单字段:title、schedule、prompt、type、delivery、provider、model、通知/超时/重叠/Kanban 设置、status、oneShot) |
DELETE |
/dsh-cron/tasks/:id |
删除任务 |
GET |
/dsh-cron/models |
列出 LLM 提供方;?provider=<id> 列出模型 |
POST |
/dsh-cron/chat/start |
启动带任务配置指令的“由 DSH 创建”智能体会话 |
GET |
/dsh-cron/settings |
客户端安全设置(令牌掩码显示) |
POST |
/dsh-cron/settings |
更新集成设置(通过设置服务应用) |
GET |
/dsh-cron/heartbeat |
存活探针:活跃任务数与最近运行时间 |
POST |
/dsh-cron/telegram/test |
发送 Telegram 测试消息 |
POST |
/dsh-cron/kanban/test |
创建 Kanban 连通性测试卡片 |
* |
/dsh-cron/action/:id/:action |
任务操作路由的兼容别名(run、toggle、delete、history) |
GET |
/dsh-cron/metrics |
Prometheus 文本格式的任务与运行计数 —— 不含提示词与输出(#53) |
GET / POST |
/api/dsh-cron/update |
插件一键自更新:查询仓库最新版本并就地平滑升级 (#147) |
GET / POST |
/dsh-cron/api/tasks |
令牌保护的外部接口:列表 / 创建或更新(#54) |
GET / DELETE |
/dsh-cron/api/tasks/:id |
令牌保护的外部接口:读取 / 删除(#54) |
POST |
/dsh-cron/api/tasks/:id/run |
令牌保护的外部接口:强制执行(#54) |
🧪 测试与预检门禁 (Preflight)
运行全套自动化测试(调度表达式解析、调度器引擎、原子存储、HTTP 辅助函数、通知与工具契约):
npm test
本地执行质量预检门禁(语法检查、零空 catch 块、主题设计规范、npm 发布归档合规性及防泄漏检查):
node scripts/ci-preflight.mjs
📄 许可证
MIT © GooDAnDReaDY
评论
评论存放在 GitHub Discussions。用 GitHub 账号登录后可发表评论或点表情。