@goodandready/dsh-cron 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -15
- package/docs/README.ru.md +69 -14
- package/docs/README.zh.md +74 -14
- package/docs/design/DESIGN.md +18 -8
- package/docs/plans/0.2.5-ui-block.md +50 -0
- package/lib/channels.js +412 -0
- package/lib/client.js +1134 -30
- package/lib/index.js +311 -38
- package/lib/integrations.js +3 -1
- package/lib/runner.js +185 -28
- package/lib/runtimes.js +174 -0
- package/lib/scheduler.js +66 -60
- package/lib/secrets.js +123 -0
- package/lib/store.js +91 -21
- package/lib/task-transfer.js +226 -0
- package/lib/telegram.js +20 -4
- package/lib/templates.js +88 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,10 +31,12 @@ Autonomous AI agents often need to perform recurring duties: generating daily mo
|
|
|
31
31
|
|
|
32
32
|
**`@goodandready/dsh-cron`** is a native full-stack scheduling and background automation plugin for DeepSeek Harness. It bridges standard cron expressions and natural interval syntax with autonomous agent execution, providing:
|
|
33
33
|
|
|
34
|
-
1. **Rich Visual Task Manager** — a sidebar button and a full
|
|
34
|
+
1. **Rich Visual Task Manager** — a sidebar button with a collapsible list of active jobs (next run or live state, capped and persisted), plus a full panel to inspect, filter by type/model/channel, pause, trigger, duplicate, export/import and create tasks.
|
|
35
35
|
2. **Interactive "Create with DSH" Workflow** — chat with your agent to translate high-level requirements into a well-formed scheduled task.
|
|
36
36
|
3. **Autonomous AI Tool Calling** — native `cron_*` tools let agents schedule their own follow-up executions during conversations.
|
|
37
37
|
4. **Robust Scheduler & Atomic Storage** — built on `croner` with interval aliases, one-shot delays, atomic file persistence, run histories, and cost tracking.
|
|
38
|
+
5. **Six Execution Runtimes** — shell, Node.js, Python, HTTP/webhook, remote SSH and Docker, plus per-task environment variables, workspace binding and isolated git worktrees for code-modifying agent tasks.
|
|
39
|
+
6. **Multi-Channel Delivery With Templates** — one run fans out to Telegram, dsh-kanban, Discord, Slack, ntfy, Bark, PushPlus, voice (`dsh-tts`) and Gitea, with `{variable}` message templates and secrets referenced by DSH credential name.
|
|
38
40
|
|
|
39
41
|
---
|
|
40
42
|
|
|
@@ -47,7 +49,7 @@ graph TD
|
|
|
47
49
|
Overlay["Visual Task Manager Panel<br/>(Tabs: All, Active, Paused, Completed)"]
|
|
48
50
|
CreateWithDSH["'Create with DSH' Dialog<br/>(natural language task)"]
|
|
49
51
|
ManualForm["Manual Task Form<br/>(Cron Expression, Timeout, Overlap, Model)"]
|
|
50
|
-
SettingsCard["Settings Card<br/>(
|
|
52
|
+
SettingsCard["Settings Card<br/>(Channels, Templates, Credentials)"]
|
|
51
53
|
end
|
|
52
54
|
|
|
53
55
|
subgraph Server ["Server Runtime (Cordis & DSH Services)"]
|
|
@@ -56,7 +58,9 @@ graph TD
|
|
|
56
58
|
Scheduler["TaskScheduler Engine<br/>(Croner instances + one-shot timers)"]
|
|
57
59
|
Store["Atomic TaskStore<br/>(tasks.json with atomic write)"]
|
|
58
60
|
AgentRunner["Agent Session Dispatcher<br/>(Executes prompt with chosen model)"]
|
|
59
|
-
|
|
61
|
+
Runtimes["Execution Runtimes<br/>(shell, node, python, http, ssh, docker)"]
|
|
62
|
+
Notify["Delivery Router<br/>(templates + 9 channels)"]
|
|
63
|
+
Secrets["Credential References<br/>(DSH credentials / ENV)"]
|
|
60
64
|
end
|
|
61
65
|
|
|
62
66
|
SidebarBtn --> Overlay
|
|
@@ -95,7 +99,7 @@ Autonomous agents can manage schedules directly:
|
|
|
95
99
|
|
|
96
100
|
| Tool | Description |
|
|
97
101
|
|:---|:---|
|
|
98
|
-
| `cron_create_task` | Creates a scheduled task: `title`, `schedule`, `prompt`, optional `type` (`llm`/`script`), `delivery`, `provider`, `model`, `notifyTelegram`, `onlyOnFailure`, `timeoutSeconds`, `overlapPolicy`, `kanbanMode` |
|
|
102
|
+
| `cron_create_task` | Creates a scheduled task: `title`, `schedule`, `prompt`, optional `type` (`llm`/`script`/`node`/`python`/`http`/`ssh`/`docker`/`skill`/`workflow`), `delivery`, `provider`, `model`, `channels`, `template`, `notifyTelegram`, `onlyOnFailure`, `timeoutSeconds`, `overlapPolicy`, `kanbanMode` |
|
|
99
103
|
| `cron_schedule_task` | Alias of `cron_create_task` kept for compatibility with existing agent prompts |
|
|
100
104
|
| `cron_list_tasks` | Lists tasks with statuses, next run timestamps, token totals, and cost estimates |
|
|
101
105
|
| `cron_pause_task` | Pauses a schedule without deleting its configuration |
|
|
@@ -132,24 +136,43 @@ Powered by `croner`, supporting standard 5-field cron expressions plus user-frie
|
|
|
132
136
|
* **Concurrency limit** — `maxConcurrent` (plugin setting) caps parallel runs; extra runs are recorded as `skipped` with a reason.
|
|
133
137
|
* **Live execution indicator** — the task list shows a pulsing status icon and a running timer for the task in flight.
|
|
134
138
|
|
|
135
|
-
### 6.
|
|
139
|
+
### 6. Execution Runtimes
|
|
140
|
+
Every task picks its own runtime; non-LLM runtimes need no model and consume no tokens:
|
|
141
|
+
|
|
142
|
+
* **Shell** (`script`) — command or script through the harness shell, with `env` and `cwd`.
|
|
143
|
+
* **Node.js** (`node`) and **Python** (`python`) — run a snippet with an explicit interpreter path (`nodePath`, `pythonPath`); Python detects a project virtualenv.
|
|
144
|
+
* **HTTP** (`http`) — GET/POST/… to a URL with custom headers and body, and the response status/output recorded in the run history.
|
|
145
|
+
* **SSH** (`ssh`) — execute a command on a remote host through a `dsh-remote-workspace` profile (`sshProfileId`) or standalone host/key fields.
|
|
146
|
+
* **Docker** (`docker`) — run the command in a container image (`dockerImage`).
|
|
147
|
+
* **Environment variables** — a per-task `env` map (KEY VALUE per line in the UI) applied to external runtimes; secrets do not belong here.
|
|
148
|
+
* **Workspaces and worktrees** — bind a task to a harness workspace (`workspaceId`) and, for code-modifying agent tasks, run it in an isolated git worktree (`worktree`, `keepWorktree`).
|
|
149
|
+
|
|
150
|
+
### 7. Session Integration & Permissions
|
|
136
151
|
* **Per-task permission presets** — `default`, `read-only`, `workspace-write`, or `full` are applied to the task's agent session before the prompt runs.
|
|
137
152
|
* **Session auto-archive** — isolated cron sessions are archived after each run (best-effort) so they do not clutter the chat list.
|
|
138
153
|
* **History → session navigation** — every LLM run records its session; open it straight from the run history entry.
|
|
139
154
|
|
|
140
|
-
###
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
* **
|
|
144
|
-
* **
|
|
145
|
-
* **
|
|
155
|
+
### 8. Notification Channels & Message Templates
|
|
156
|
+
A finished run is delivered to every channel configured for the task — Telegram, dsh-kanban, Discord, Slack, ntfy, Bark, PushPlus, voice via `dsh-tts`, and Gitea issues:
|
|
157
|
+
|
|
158
|
+
* **Per-task channels** — tick the channels in the task form; an explicit selection overrides the legacy `notifyTelegram` / `kanbanMode` switches, and an empty selection falls back to them.
|
|
159
|
+
* **Failure isolation** — one unreachable channel is reported in the scheduler log with the other channels still delivered; a broken webhook never swallows the rest of the report.
|
|
160
|
+
* **Message templates** — a global template, per-channel overrides, or a per-task template rendered from `{title} {id} {status} {output} {error} {duration} {schedule} {time} {tokens} {cost}`. Unknown placeholders are left intact, failed runs default to a failure template.
|
|
161
|
+
* **`onlyOnFailure`** — globally or per task, clean runs stay silent and only `error`/`timeout` runs are dispatched.
|
|
162
|
+
* **Credentials by reference** — webhook tokens and the Telegram bot token are entered as the NAME of a DSH credential (`botTokenRef`, `ntfyTokenRef`, `pushplusTokenRef`, `giteaTokenRef`); the value is resolved at send time through the DSH credentials service with an environment-variable fallback, and never travels through plugin settings. Webhook URLs and the Bark device key do embed a secret, so they are stored in the plugin settings file but are always returned masked to the browser and a masked value echoed back by the UI never overwrites the stored one.
|
|
163
|
+
* **Delivery timeout** — every channel request is bounded (`deliveryTimeoutMs`, default 15000 ms, editable in the settings panel or `settings.yaml`) and channels are dispatched concurrently, so one unresponsive endpoint is recorded as a failure and cannot delay the other channels or the next scheduled tick. The bound is enforced around the whole channel handler, which also covers credential resolution, which does not support abort signals.
|
|
164
|
+
* **Telegram** — Markdown report with status badges (✅ / ❌), duration, schedule description and monospace output; dynamic values are escaped so odd titles cannot break the message. Credentials may be entered directly, or inherited from the `dsh-messenger-gateway` section of your DSH `settings.yaml` (best-effort fallback).
|
|
165
|
+
* **Discord / Slack** — webhook delivery; Discord carries an embed coloured by run status, Slack a plain text body.
|
|
166
|
+
* **ntfy / Bark / PushPlus** — mobile push with a topic/device key and an optional bearer token; the Bark title and text travel in the request path.
|
|
167
|
+
* **Voice** — `dsh-tts` speaks the report through its HTTP route (`ttsBaseUrl`, default `http://127.0.0.1:3080`).
|
|
168
|
+
* **Gitea** — opens an issue with the run report (`giteaBaseUrl`, `giteaRepo`, token credential); failures are labelled `cron`, `bug`, `alert`.
|
|
146
169
|
* **Test dispatch button** — verify Telegram connectivity on the spot before scheduling critical jobs.
|
|
147
170
|
|
|
148
|
-
###
|
|
171
|
+
### 9. Kanban Integration & Cost Meter
|
|
149
172
|
* **Automatic Kanban cards** — with `kanbanMode` set to `on_failure` or `always`, the plugin creates cards in `dsh-kanban` (`on_failure` → *Backlog* on `error`/`timeout`; `always` → *Done*/*Backlog* on completion).
|
|
150
173
|
* **Token & execution cost meter** — token consumption (input, output, cache reads) is tracked per run and per task, with USD estimates from a built-in pricing table and an aggregated analytics bar.
|
|
151
174
|
|
|
152
|
-
###
|
|
175
|
+
### 10. Overlap Policies & Execution Timeout
|
|
153
176
|
Prevent rogue processes from stacking concurrent duplicate executions:
|
|
154
177
|
|
|
155
178
|
* **Execution timeout (`timeoutSeconds`)** — when the limit is reached, shell subprocesses are killed immediately via the abort signal and agent sessions are disposed so they stop consuming tokens. Default: `1800` (30 minutes).
|
|
@@ -160,7 +183,7 @@ Prevent rogue processes from stacking concurrent duplicate executions:
|
|
|
160
183
|
|
|
161
184
|
If the daemon was offline at a scheduled time, the run is recorded as `missed` on startup, so gaps in the history stay visible.
|
|
162
185
|
|
|
163
|
-
###
|
|
186
|
+
### 11. Heartbeat Monitoring (#16-style dead man's switch)
|
|
164
187
|
* Set `heartbeatUrl` and `heartbeatIntervalSec` in the plugin settings and the scheduler pings that URL on schedule — an external monitor alerts when the pings stop.
|
|
165
188
|
* A built-in `GET /dsh-cron/heartbeat` endpoint reports liveness, active task count and the last run time for your own watchdogs.
|
|
166
189
|
|
|
@@ -194,6 +217,24 @@ dsh-cron:
|
|
|
194
217
|
maxConcurrent: 0 # max parallel task runs (0 = unlimited)
|
|
195
218
|
heartbeatUrl: "" # dead man's snitch URL pinged on the heartbeat interval
|
|
196
219
|
heartbeatIntervalSec: 0 # heartbeat ping interval in seconds (0 = off)
|
|
220
|
+
# --- delivery channels ---
|
|
221
|
+
botTokenRef: "" # credential NAME for the Telegram bot token
|
|
222
|
+
template: "" # global message template, e.g. "⏰ {title} — {status}"
|
|
223
|
+
channelTemplates: {} # per-channel template overrides keyed by channel id
|
|
224
|
+
deliveryTimeoutMs: 15000 # per-channel delivery timeout; slow channel = failure, others unaffected
|
|
225
|
+
discordWebhookUrl: "" # Discord webhook
|
|
226
|
+
slackWebhookUrl: "" # Slack incoming webhook
|
|
227
|
+
ntfyUrl: "https://ntfy.sh" # ntfy server; ntfyTopic / ntfyTokenRef
|
|
228
|
+
ntfyTopic: ""
|
|
229
|
+
ntfyTokenRef: ""
|
|
230
|
+
barkServerUrl: "https://api.day.app" # Bark server; barkKey = device key
|
|
231
|
+
barkKey: ""
|
|
232
|
+
pushplusUrl: "https://www.pushplus.plus/send" # pushplusTokenRef
|
|
233
|
+
pushplusTokenRef: ""
|
|
234
|
+
ttsBaseUrl: "http://127.0.0.1:3080" # dsh-tts base URL
|
|
235
|
+
giteaBaseUrl: "" # giteaRepo = owner/repo, giteaTokenRef = credential NAME
|
|
236
|
+
giteaRepo: ""
|
|
237
|
+
giteaTokenRef: ""
|
|
197
238
|
```
|
|
198
239
|
|
|
199
240
|
### Configuration Parameters
|
|
@@ -209,6 +250,16 @@ dsh-cron:
|
|
|
209
250
|
| `maxConcurrent` | `number` | `0` | Cap on parallel task runs; extra runs are recorded as `skipped` (0 = unlimited) |
|
|
210
251
|
| `heartbeatUrl` | `string` | `""` | Dead man's snitch URL pinged every `heartbeatIntervalSec` while the scheduler is alive |
|
|
211
252
|
| `heartbeatIntervalSec` | `number` | `0` | Heartbeat ping interval in seconds (0 = disabled) |
|
|
253
|
+
| `botTokenRef` | `string` | `""` | Name of the DSH credential holding the Telegram bot token; resolved at send time (falls back to `botToken`, then the messenger-gateway settings, then the `CRON_TELEGRAM_BOT_TOKEN` environment variable) |
|
|
254
|
+
| `template` | `string` | `""` | Global message template with `{title}`/`{status}`/`{duration}`/… placeholders; empty = built-in text |
|
|
255
|
+
| `channelTemplates` | `object` | `{}` | Per-channel template overrides keyed by channel id (`telegram`, `discord`, …) |
|
|
256
|
+
| `deliveryTimeoutMs` | `number` | `15000` | Per-channel delivery timeout; a slower endpoint is recorded as a delivery failure and does not delay the other channels or the next tick |
|
|
257
|
+
| `discordWebhookUrl` / `slackWebhookUrl` | `string` | `""` | Webhook URLs for the Discord and Slack channels |
|
|
258
|
+
| `ntfyUrl` / `ntfyTopic` / `ntfyTokenRef` | `string` | `"https://ntfy.sh"` / `""` / `""` | ntfy server, topic and an optional token credential name (sent as `Authorization: Bearer …`) |
|
|
259
|
+
| `barkServerUrl` / `barkKey` | `string` | `"https://api.day.app"` / `""` | Bark server and device key (key, title and text travel in the request path) |
|
|
260
|
+
| `pushplusUrl` / `pushplusTokenRef` | `string` | `"https://www.pushplus.plus/send"` / `""` | PushPlus endpoint (override for a self-hosted proxy) and token credential name |
|
|
261
|
+
| `ttsBaseUrl` | `string` | `"http://127.0.0.1:3080"` | Base URL of the `dsh-tts` plugin used for voice announcements |
|
|
262
|
+
| `giteaBaseUrl` / `giteaRepo` / `giteaTokenRef` | `string` | `""` | Gitea channel: base URL, `owner/repo`, and the credential name of the API token |
|
|
212
263
|
|
|
213
264
|
Notes:
|
|
214
265
|
|
|
@@ -231,7 +282,10 @@ All endpoints are served by the DSH web server under `/dsh-cron/`. Read endpoint
|
|
|
231
282
|
| `POST` | `/dsh-cron/tasks/:id/pause` | Pause the schedule |
|
|
232
283
|
| `POST` | `/dsh-cron/tasks/:id/resume` | Resume the schedule |
|
|
233
284
|
| `POST` | `/dsh-cron/tasks/:id/toggle` | Toggle active/paused |
|
|
234
|
-
| `
|
|
285
|
+
| `POST` | `/dsh-cron/tasks/:id/duplicate` | Creates a paused copy of a task: configuration copied, run state (history, counters, last run) reset |
|
|
286
|
+
| `GET` | `/dsh-cron/tasks/export` | Versioned JSON document with task configuration only — no history or counters. Channels reference credentials by name, but a task-level `env` map or HTTP headers you typed in yourself are part of the configuration and therefore appear in the file |
|
|
287
|
+
| `POST` | `/dsh-cron/tasks/import` | Validates a document and applies it with `add`, `replace` or `skip`; supports a `dryRun` summary. Imported tasks always start **paused**, so a restore never fires until reviewed |
|
|
288
|
+
| `PATCH` | `/dsh-cron/tasks/:id` | Partial update (whitelisted fields only: `title`, `schedule`, `prompt`, `type`, `delivery`, `provider`, `model`, runtime settings, `channels`, `template`, notification/timeout/overlap/kanban settings, `status`, `oneShot`) |
|
|
235
289
|
| `DELETE` | `/dsh-cron/tasks/:id` | Delete the task |
|
|
236
290
|
| `GET` | `/dsh-cron/models` | List LLM providers; `?provider=<id>` lists models |
|
|
237
291
|
| `POST` | `/dsh-cron/chat/start` | Start a "Create with DSH" agent session with the task-setup instructions |
|
package/docs/README.ru.md
CHANGED
|
@@ -31,10 +31,12 @@
|
|
|
31
31
|
|
|
32
32
|
**`@goodandready/dsh-cron`** — нативный полноформатный плагин планирования и фоновой автоматизации для DeepSeek Harness. Он связывает стандартные cron-выражения и естественные интервалы с автономным исполнением агентами:
|
|
33
33
|
|
|
34
|
-
1. **Развитый визуальный менеджер задач** — кнопка в сайдбаре и полноценная панель:
|
|
34
|
+
1. **Развитый визуальный менеджер задач** — кнопка в сайдбаре со сворачиваемым списком активных задач (следующий запуск или живой статус, с ограничением и запоминанием состояния) и полноценная панель: фильтры по типу, модели и каналу, пауза, немедленный запуск, дублирование, экспорт/импорт и создание задач.
|
|
35
35
|
2. **Интерактивный сценарий «Создать с DSH»** — опишите задачу словами, агент уточнит детали и оформит расписание.
|
|
36
36
|
3. **Автономный tool calling** — нативные инструменты `cron_*` позволяют агентам планировать собственные последующие действия прямо в диалоге.
|
|
37
37
|
4. **Надёжный планировщик и атомарное хранилище** — на базе `croner`: интервалы, разовые задачи с задержкой, атомарная запись, история запусков, учёт стоимости.
|
|
38
|
+
5. **Шесть рантаймов исполнения** — shell, Node.js, Python, HTTP/webhook, удалённый SSH и Docker, плюс переменные окружения на задачу, привязка workspace и изолированные git worktree для изменяющих код агентских задач.
|
|
39
|
+
6. **Многоканальная доставка с шаблонами** — один запуск расходится в Telegram, dsh-kanban, Discord, Slack, ntfy, Bark, PushPlus, голос (`dsh-tts`) и Gitea, с шаблонами сообщений `{переменные}` и секретами по имени credential в DSH.
|
|
38
40
|
|
|
39
41
|
---
|
|
40
42
|
|
|
@@ -46,8 +48,8 @@ graph TD
|
|
|
46
48
|
SidebarBtn["Кнопка-часы в сайдбаре<br/>(слот DSH Client UI)"]
|
|
47
49
|
Overlay["Панель управления задачами<br/>(табы: Все, Активные, На паузе, Завершённые)"]
|
|
48
50
|
CreateWithDSH["Диалог «Создать с DSH»<br/>(задача на естественном языке)"]
|
|
49
|
-
ManualForm["Ручная форма задачи<br/>(cron, таймаут, overlap,
|
|
50
|
-
SettingsCard["Карточка настроек<br/>(
|
|
51
|
+
ManualForm["Ручная форма задачи<br/>(рантайм, cron, таймаут, overlap, каналы)"]
|
|
52
|
+
SettingsCard["Карточка настроек<br/>(каналы, шаблоны, credentials)"]
|
|
51
53
|
end
|
|
52
54
|
|
|
53
55
|
subgraph Server ["Серверная часть (Cordis и сервисы DSH)"]
|
|
@@ -56,7 +58,9 @@ graph TD
|
|
|
56
58
|
Scheduler["Движок TaskScheduler<br/>(экземпляры Croner + таймеры one-shot)"]
|
|
57
59
|
Store["Атомарный TaskStore<br/>(tasks.json, атомарная запись)"]
|
|
58
60
|
AgentRunner["Диспетчер агентских сессий<br/>(запуск промпта выбранной моделью)"]
|
|
59
|
-
|
|
61
|
+
Runtimes["Рантаймы исполнения<br/>(shell, node, python, http, ssh, docker)"]
|
|
62
|
+
Notify["Маршрутизатор доставки<br/>(шаблоны + 9 каналов)"]
|
|
63
|
+
Secrets["Credential-ссылки<br/>(DSH credentials / ENV)"]
|
|
60
64
|
end
|
|
61
65
|
|
|
62
66
|
SidebarBtn --> Overlay
|
|
@@ -94,7 +98,7 @@ graph TD
|
|
|
94
98
|
|
|
95
99
|
| Инструмент | Описание |
|
|
96
100
|
|:---|:---|
|
|
97
|
-
| `cron_create_task` | Создаёт задачу: `title`, `schedule`, `prompt`, опционально `type` (`llm`/`script`), `delivery`, `provider`, `model`, `notifyTelegram`, `onlyOnFailure`, `timeoutSeconds`, `overlapPolicy`, `kanbanMode` |
|
|
101
|
+
| `cron_create_task` | Создаёт задачу: `title`, `schedule`, `prompt`, опционально `type` (`llm`/`script`/`node`/`python`/`http`/`ssh`/`docker`/`skill`/`workflow`), `delivery`, `provider`, `model`, `channels`, `template`, `notifyTelegram`, `onlyOnFailure`, `timeoutSeconds`, `overlapPolicy`, `kanbanMode` |
|
|
98
102
|
| `cron_schedule_task` | Псевдоним `cron_create_task` для совместимости с существующими промптами |
|
|
99
103
|
| `cron_list_tasks` | Список задач со статусами, временем следующего запуска, токенами и стоимостью |
|
|
100
104
|
| `cron_pause_task` | Приостанавливает расписание без удаления конфигурации |
|
|
@@ -131,24 +135,44 @@ cron_create_task({
|
|
|
131
135
|
* **Лимит параллельности** — настройка `maxConcurrent` ограничивает число одновременных запусков; лишние помечаются `skipped` с причиной.
|
|
132
136
|
* **Живой индикатор** — в списке задач пульсирует статус и идёт таймер текущего запуска.
|
|
133
137
|
|
|
134
|
-
### 6.
|
|
138
|
+
### 6. Рантаймы исполнения
|
|
139
|
+
Каждая задача выбирает собственный рантайм; не-LLM рантаймы не используют модель и не тратят токены:
|
|
140
|
+
|
|
141
|
+
* **Shell** (`script`) — команда или скрипт через shell харнесса, с `env` и `cwd`.
|
|
142
|
+
* **Node.js** (`node`) и **Python** (`python`) — запуск сниппета с указанием интерпретатора (`nodePath`, `pythonPath`); для Python определяется виртуальное окружение проекта.
|
|
143
|
+
* **HTTP** (`http`) — GET/POST/… по URL с собственными заголовками и телом; статус и вывод ответа попадают в историю запуска.
|
|
144
|
+
* **SSH** (`ssh`) — выполнение команды на удалённом хосте через профиль `dsh-remote-workspace` (`sshProfileId`) или отдельные поля host/key.
|
|
145
|
+
* **Docker** (`docker`) — выполнение команды в контейнере образа (`dockerImage`).
|
|
146
|
+
* **Переменные окружения** — карта `env` на задачу (в UI — строки KEY VALUE) для внешних рантаймов; секретам здесь не место.
|
|
147
|
+
* **Workspace и worktree** — привязка задачи к workspace харнесса (`workspaceId`) и, для изменяющих код агентских задач, запуск в изолированном git worktree (`worktree`, `keepWorktree`).
|
|
148
|
+
|
|
149
|
+
### 7. Интеграция сессий и права
|
|
135
150
|
* **Permission-пресеты на задачу** — `default`, `read-only`, `workspace-write` или `full` применяются к сессии агента перед запуском промпта.
|
|
136
151
|
* **Автоархивация сессий** — изолированные cron-сессии архивируются после запуска (best-effort), не засоряя список чатов.
|
|
137
152
|
* **История → сессия** — каждый LLM-запуск хранит свою сессию; открыть диалог можно прямо из записи истории.
|
|
138
153
|
|
|
139
|
-
###
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
154
|
+
### 8. Каналы доставки и шаблоны сообщений
|
|
155
|
+
Отчёт о завершённом запуске уходит во все каналы, выбранные для задачи — Telegram, dsh-kanban, Discord, Slack, ntfy, Bark, PushPlus, голос через `dsh-tts` и issue в Gitea:
|
|
156
|
+
|
|
157
|
+
* **Перенос задач** — экспорт всей конфигурации в версионированный JSON и импорт с предварительной сводкой; импортированные задачи приходят на паузе.
|
|
158
|
+
* **Каналы на задачу** — отметьте каналы в форме задачи; явный выбор перекрывает legacy-переключатели `notifyTelegram`/`kanbanMode`, а пустой выбор возвращается к ним.
|
|
159
|
+
* **Изоляция сбоев** — недоступный канал фиксируется в логе планировщика, остальные каналы получают отчёт; сломанный webhook не поглощает доставку целиком.
|
|
160
|
+
* **Шаблоны сообщений** — глобальный шаблон, переопределения по каналам или шаблон на задачу с переменными `{title} {id} {status} {output} {error} {duration} {schedule} {time} {tokens} {cost}`. Неизвестные плейсхолдеры остаются как есть, для сбойных запусков по умолчанию используется шаблон ошибки.
|
|
161
|
+
* **`onlyOnFailure`** — глобально или на задачу: успешные запуски молчат, уходят только `error`/`timeout`.
|
|
162
|
+
* **Креденшелы по ссылке** — токены webhook'ов и токен Telegram вводятся как ИМЯ credential в DSH (`botTokenRef`, `ntfyTokenRef`, `pushplusTokenRef`, `giteaTokenRef`); значение резолвится в момент отправки через credentials-сервис DSH с фолбэком на переменную окружения и никогда не проходит через настройки плагина. Webhook-URL и ключ устройства Bark содержат секрет внутри, поэтому хранятся в настройках плагина, но всегда отдаются в браузер замаскированными, а замаскированное значение из UI никогда не перезаписывает сохранённое.
|
|
163
|
+
* **Таймаут доставки** — каждый запрос канала ограничен (`deliveryTimeoutMs`, по умолчанию 15000 мс, задаётся в панели настроек или `settings.yaml`), каналы отправляются параллельно: недоступный endpoint фиксируется как сбой и не задерживает остальные каналы и следующий тик расписания. Ограничение действует на весь обработчик канала, включая резолв credential'ов, который не поддерживает abort-сигнал.
|
|
164
|
+
* **Telegram** — Markdown-отчёт со статусными значками (✅ / ❌), длительностью, описанием расписания и monospace-блоком вывода; динамические значения экранируются. Креденшелы можно ввести напрямую или унаследовать из секции `dsh-messenger-gateway` вашего DSH `settings.yaml` (best-effort).
|
|
165
|
+
* **Discord / Slack** — доставка через webhook: Discord получает embed с цветом по статусу запуска, Slack — обычный текст.
|
|
166
|
+
* **ntfy / Bark / PushPlus** — мобильные пуши: тема/ключ устройства и опциональный bearer-токен; у Bark заголовок и текст идут в пути запроса, у PushPlus endpoint настраивается (self-hosted прокси).
|
|
167
|
+
* **Голос** — `dsh-tts` озвучивает отчёт через свой HTTP-маршрут (`ttsBaseUrl`, по умолчанию `http://127.0.0.1:3080`).
|
|
168
|
+
* **Gitea** — создаёт issue с отчётом (`giteaBaseUrl`, `giteaRepo`, credential токена); сбойные запуски помечаются метками `cron`, `bug`, `alert`.
|
|
145
169
|
* **Кнопка проверки** — проверьте доставку в Telegram до запуска критичных задач.
|
|
146
170
|
|
|
147
|
-
###
|
|
171
|
+
### 9. Интеграция с Kanban и учёт стоимости
|
|
148
172
|
* **Автоматические карточки Kanban** — при `kanbanMode` = `on_failure` или `always` плагин создаёт карточки в `dsh-kanban` (`on_failure` → *Backlog* при `error`/`timeout`; `always` → *Done*/*Backlog* по завершении).
|
|
149
173
|
* **Счётчик токенов и стоимости** — потребление токенов (ввод, вывод, чтения из кэша) учитывается по запускам и задачам с оценкой в USD по встроенной таблице цен и сводной панелью аналитики.
|
|
150
174
|
|
|
151
|
-
###
|
|
175
|
+
### 10. Политики наложения и таймаут выполнения
|
|
152
176
|
|
|
153
177
|
* **Таймаут (`timeoutSeconds`)** — по достижении лимита shell-процесс немедленно завершается через abort-сигнал, а агентская сессия закрывается, чтобы не расходовать токены. По умолчанию `1800` (30 минут).
|
|
154
178
|
* **Политика наложения (`overlapPolicy`)** — что делать, когда тик срабатывает при ещё активном предыдущем запуске:
|
|
@@ -186,6 +210,24 @@ dsh-cron:
|
|
|
186
210
|
maxConcurrent: 0 # максимум параллельных запусков (0 = без лимита)
|
|
187
211
|
heartbeatUrl: "" # URL dead man's snitch, пингуется по интервалу
|
|
188
212
|
heartbeatIntervalSec: 0 # интервал heartbeat-пинга в секундах (0 = выключено)
|
|
213
|
+
# --- каналы доставки ---
|
|
214
|
+
botTokenRef: "" # ИМЯ credential для токена Telegram-бота
|
|
215
|
+
template: "" # глобальный шаблон сообщения, напр. "⏰ {title} — {status}"
|
|
216
|
+
channelTemplates: {} # переопределения шаблонов по каналам
|
|
217
|
+
deliveryTimeoutMs: 15000 # таймаут доставки на канал; медленный канал = сбой, остальные не ждут
|
|
218
|
+
discordWebhookUrl: "" # webhook Discord
|
|
219
|
+
slackWebhookUrl: "" # incoming webhook Slack
|
|
220
|
+
ntfyUrl: "https://ntfy.sh" # сервер ntfy; ntfyTopic / ntfyTokenRef
|
|
221
|
+
ntfyTopic: ""
|
|
222
|
+
ntfyTokenRef: ""
|
|
223
|
+
barkServerUrl: "https://api.day.app" # сервер Bark; barkKey — ключ устройства
|
|
224
|
+
barkKey: ""
|
|
225
|
+
pushplusUrl: "https://www.pushplus.plus/send" # pushplusTokenRef
|
|
226
|
+
pushplusTokenRef: ""
|
|
227
|
+
ttsBaseUrl: "http://127.0.0.1:3080" # базовый URL dsh-tts
|
|
228
|
+
giteaBaseUrl: "" # giteaRepo = owner/repo, giteaTokenRef = ИМЯ credential
|
|
229
|
+
giteaRepo: ""
|
|
230
|
+
giteaTokenRef: ""
|
|
189
231
|
```
|
|
190
232
|
|
|
191
233
|
### Параметры
|
|
@@ -201,6 +243,16 @@ dsh-cron:
|
|
|
201
243
|
| `maxConcurrent` | `number` | `0` | Лимит параллельных запусков; лишние помечаются `skipped` (0 = без лимита) |
|
|
202
244
|
| `heartbeatUrl` | `string` | `""` | URL dead man's snitch, пингуемый каждый `heartbeatIntervalSec`, пока жив планировщик |
|
|
203
245
|
| `heartbeatIntervalSec` | `number` | `0` | Интервал heartbeat-пинга в секундах (0 = выключено) |
|
|
246
|
+
| `botTokenRef` | `string` | `""` | Имя credential DSH с токеном Telegram-бота; резолвится при отправке (фолбэк: `botToken` → настройки messenger-gateway → переменная окружения `CRON_TELEGRAM_BOT_TOKEN`) |
|
|
247
|
+
| `template` | `string` | `""` | Глобальный шаблон сообщения с плейсхолдерами `{title}`/`{status}`/`{duration}`/…; пусто = встроенный текст |
|
|
248
|
+
| `channelTemplates` | `object` | `{}` | Переопределения шаблонов по каналам (`telegram`, `discord`, …) |
|
|
249
|
+
| `deliveryTimeoutMs` | `number` | `15000` | Таймаут доставки на канал; более медленный endpoint фиксируется как сбой и не задерживает остальные каналы и следующий тик |
|
|
250
|
+
| `discordWebhookUrl` / `slackWebhookUrl` | `string` | `""` | Webhook-URL каналов Discord и Slack |
|
|
251
|
+
| `ntfyUrl` / `ntfyTopic` / `ntfyTokenRef` | `string` | `"https://ntfy.sh"` / `""` / `""` | Сервер ntfy, тема и опциональное имя credential токена (`Authorization: Bearer …`) |
|
|
252
|
+
| `barkServerUrl` / `barkKey` | `string` | `"https://api.day.app"` / `""` | Сервер Bark и ключ устройства (ключ, заголовок и текст идут в пути запроса) |
|
|
253
|
+
| `pushplusUrl` / `pushplusTokenRef` | `string` | `"https://www.pushplus.plus/send"` / `""` | Endpoint PushPlus (переопределяется для self-hosted прокси) и имя credential токена |
|
|
254
|
+
| `ttsBaseUrl` | `string` | `"http://127.0.0.1:3080"` | Базовый URL плагина `dsh-tts` для голосовых объявлений |
|
|
255
|
+
| `giteaBaseUrl` / `giteaRepo` / `giteaTokenRef` | `string` | `""` | Канал Gitea: базовый URL, `owner/repo` и имя credential API-токена |
|
|
204
256
|
|
|
205
257
|
Примечания:
|
|
206
258
|
|
|
@@ -223,6 +275,9 @@ dsh-cron:
|
|
|
223
275
|
| `POST` | `/dsh-cron/tasks/:id/pause` | Пауза расписания |
|
|
224
276
|
| `POST` | `/dsh-cron/tasks/:id/resume` | Возобновление расписания |
|
|
225
277
|
| `POST` | `/dsh-cron/tasks/:id/toggle` | Переключение активна/на паузе |
|
|
278
|
+
| `POST` | `/dsh-cron/tasks/:id/duplicate` | Копия задачи в статусе «на паузе»: настройки копируются, история и счётчики сбрасываются |
|
|
279
|
+
| `GET` | `/dsh-cron/tasks/export` | Версионированный JSON только с конфигурацией задач — без истории и счётчиков. Каналы ссылаются на credential по имени, но введённые вручную `env` и HTTP-заголовки задачи являются частью конфигурации и попадают в файл |
|
|
280
|
+
| `POST` | `/dsh-cron/tasks/import` | Проверяет документ и применяет его стратегией `add`, `replace` или `skip`; поддерживает `dryRun`. Импортированные задачи всегда приходят **на паузе** — восстановление не сработает само |
|
|
226
281
|
| `PATCH` | `/dsh-cron/tasks/:id` | Частичное обновление (только whitelisted-поля: `title`, `schedule`, `prompt`, `type`, `delivery`, `provider`, `model`, настройки уведомлений/таймаута/overlap/kanban, `status`, `oneShot`) |
|
|
227
282
|
| `DELETE` | `/dsh-cron/tasks/:id` | Удаление задачи |
|
|
228
283
|
| `GET` | `/dsh-cron/models` | Список LLM-провайдеров; `?provider=<id>` — модели |
|
package/docs/README.zh.md
CHANGED
|
@@ -31,10 +31,12 @@
|
|
|
31
31
|
|
|
32
32
|
**`@goodandready/dsh-cron`** 是 DeepSeek Harness 的原生全栈调度与后台自动化插件。它将标准 cron 表达式、自然语言间隔语法与自主智能体执行连接起来:
|
|
33
33
|
|
|
34
|
-
1. **完善的可视化任务管理器** ——
|
|
34
|
+
1. **完善的可视化任务管理器** —— 侧边栏按钮带可折叠的活跃任务列表(下次运行时间或实时状态,行数有上限且状态可记忆),以及功能齐全的面板:按类型、模型、渠道筛选,暂停、立即运行、复制、导出/导入与创建任务。
|
|
35
35
|
2. **交互式“由 DSH 创建”流程** —— 与智能体对话,把高层需求转化为规范的定时任务。
|
|
36
36
|
3. **自主工具调用** —— 原生 `cron_*` 工具让智能体在会话中自行安排后续执行。
|
|
37
37
|
4. **健壮的调度器与原子存储** —— 基于 `croner`:间隔别名、一次性延时任务、原子写入、运行历史与成本追踪。
|
|
38
|
+
5. **六种执行运行时** —— shell、Node.js、Python、HTTP/webhook、远程 SSH 与 Docker,并支持按任务的环境变量、工作区绑定以及面向代码修改任务的隔离 git worktree。
|
|
39
|
+
6. **多渠道路由与模板** —— 一次运行可投递到 Telegram、dsh-kanban、Discord、Slack、ntfy、Bark、PushPlus、语音(`dsh-tts`)与 Gitea,支持 `{变量}` 消息模板与按 DSH 凭据名称引用的密钥。
|
|
38
40
|
|
|
39
41
|
---
|
|
40
42
|
|
|
@@ -46,8 +48,8 @@ graph TD
|
|
|
46
48
|
SidebarBtn["侧边栏时钟按钮<br/>(DSH 客户端插槽)"]
|
|
47
49
|
Overlay["任务管理面板<br/>(标签: 全部 / 活跃 / 暂停 / 已完成)"]
|
|
48
50
|
CreateWithDSH["“由 DSH 创建”对话框<br/>(自然语言任务)"]
|
|
49
|
-
ManualForm["手动任务表单<br/>(cron
|
|
50
|
-
SettingsCard["设置卡片<br/>(
|
|
51
|
+
ManualForm["手动任务表单<br/>(运行时、cron、超时、重叠策略、渠道)"]
|
|
52
|
+
SettingsCard["设置卡片<br/>(渠道、模板、凭据)"]
|
|
51
53
|
end
|
|
52
54
|
|
|
53
55
|
subgraph Server ["服务端 (Cordis 与 DSH 服务)"]
|
|
@@ -56,7 +58,9 @@ graph TD
|
|
|
56
58
|
Scheduler["TaskScheduler 引擎<br/>(Croner 实例 + one-shot 定时器)"]
|
|
57
59
|
Store["原子 TaskStore<br/>(tasks.json 原子写入)"]
|
|
58
60
|
AgentRunner["智能体会话调度器<br/>(以指定模型执行提示词)"]
|
|
59
|
-
|
|
61
|
+
Runtimes["执行运行时<br/>(shell、node、python、http、ssh、docker)"]
|
|
62
|
+
Notify["投递路由<br/>(模板 + 9 个渠道)"]
|
|
63
|
+
Secrets["凭据引用<br/>(DSH credentials / ENV)"]
|
|
60
64
|
end
|
|
61
65
|
|
|
62
66
|
SidebarBtn --> Overlay
|
|
@@ -94,7 +98,7 @@ graph TD
|
|
|
94
98
|
|
|
95
99
|
| 工具 | 说明 |
|
|
96
100
|
|:---|:---|
|
|
97
|
-
| `cron_create_task` | 创建任务:`title`、`schedule`、`prompt`,可选 `type`(`llm`/`script`)、`delivery`、`provider`、`model`、`notifyTelegram`、`onlyOnFailure`、`timeoutSeconds`、`overlapPolicy`、`kanbanMode` |
|
|
101
|
+
| `cron_create_task` | 创建任务:`title`、`schedule`、`prompt`,可选 `type`(`llm`/`script`/`node`/`python`/`http`/`ssh`/`docker`/`skill`/`workflow`)、`delivery`、`provider`、`model`、`channels`、`template`、`notifyTelegram`、`onlyOnFailure`、`timeoutSeconds`、`overlapPolicy`、`kanbanMode` |
|
|
98
102
|
| `cron_schedule_task` | `cron_create_task` 的别名,保持与既有提示词兼容 |
|
|
99
103
|
| `cron_list_tasks` | 列出任务的状态、下次运行时间、token 总量与成本估算 |
|
|
100
104
|
| `cron_pause_task` | 暂停调度而不删除配置 |
|
|
@@ -131,19 +135,44 @@ cron_create_task({
|
|
|
131
135
|
* **并发上限** —— 插件设置 `maxConcurrent` 限制并行运行数;超出的运行记录为 `skipped` 并附原因。
|
|
132
136
|
* **实时执行指示** —— 任务列表中的脉冲状态图标与运行计时器。
|
|
133
137
|
|
|
134
|
-
###
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* **
|
|
138
|
+
### 6. 执行运行时
|
|
139
|
+
每个任务可选择自己的运行时;非 LLM 运行时不需要模型,也不消耗 token:
|
|
140
|
+
|
|
141
|
+
* **Shell**(`script`)—— 通过 Harness shell 执行命令或脚本,支持 `env` 与 `cwd`。
|
|
142
|
+
* **Node.js**(`node`)与 **Python**(`python`)—— 指定解释器(`nodePath`、`pythonPath`)运行片段;Python 会自动识别项目虚拟环境。
|
|
143
|
+
* **HTTP**(`http`)—— 以自定义请求头与请求体访问 URL,状态码与响应写入运行历史。
|
|
144
|
+
* **SSH**(`ssh`)—— 通过 `dsh-remote-workspace` 配置(`sshProfileId`)或独立 host/key 字段在远程主机执行命令。
|
|
145
|
+
* **Docker**(`docker`)—— 在镜像容器(`dockerImage`)中执行命令。
|
|
146
|
+
* **环境变量** —— 按任务的 `env` 映射(界面中每行 KEY VALUE)应用于外部运行时;请勿在此存放密钥。
|
|
147
|
+
* **工作区与 worktree** —— 将任务绑定到 Harness 工作区(`workspaceId`);对会修改代码的智能体任务,可在隔离的 git worktree 中运行(`worktree`、`keepWorktree`)。
|
|
148
|
+
|
|
149
|
+
### 7. 会话集成与权限
|
|
150
|
+
* **按任务的权限预设** —— `default`、`read-only`、`workspace-write` 或 `full` 在提示词执行前应用于任务会话。
|
|
151
|
+
* **会话自动归档** —— 隔离的 cron 会话在运行后自动归档(尽力而为),不干扰聊天列表。
|
|
152
|
+
* **历史 → 会话** —— 每次 LLM 运行都会记录会话,可直接从历史记录打开对话。
|
|
153
|
+
|
|
154
|
+
### 8. 通知渠道与消息模板
|
|
155
|
+
运行完成后,报告会发送到该任务配置的所有渠道 —— Telegram、dsh-kanban、Discord、Slack、ntfy、Bark、PushPlus、语音(`dsh-tts`)以及 Gitea issue:
|
|
156
|
+
|
|
157
|
+
* **任务迁移** —— 将全部配置导出为版本化 JSON,并在别处导入(含预览摘要);导入的任务处于暂停状态。
|
|
158
|
+
* **按任务选择渠道** —— 在任务表单中勾选渠道;显式选择会覆盖旧版 `notifyTelegram`/`kanbanMode` 开关,留空则回退到它们。
|
|
159
|
+
* **故障隔离** —— 某个渠道不可用会记录在调度器日志中,其余渠道仍会收到报告;失效的 webhook 不会吞掉整份报告。
|
|
160
|
+
* **消息模板** —— 支持全局模板、按渠道覆盖或按任务模板,变量为 `{title} {id} {status} {output} {error} {duration} {schedule} {time} {tokens} {cost}`。未知占位符保持原样,失败运行默认使用失败模板。
|
|
161
|
+
* **`onlyOnFailure`** —— 全局或按任务生效:成功运行静默,仅发送 `error`/`timeout`。
|
|
162
|
+
* **凭据按名称引用** —— webhook token 与 Telegram bot token 填写 DSH 凭据的名称(`botTokenRef`、`ntfyTokenRef`、`pushplusTokenRef`、`giteaTokenRef`),发送时通过 DSH credentials 服务解析,并可回退到环境变量,且绝不会经过插件设置。webhook URL 与 Bark 设备键本身内嵌密钥,因此保存在插件设置文件中,但返回浏览器时始终为掩码,界面回传的掩码值也不会覆盖已保存的值。
|
|
163
|
+
* **投递超时** —— 每个渠道请求都有上限(`deliveryTimeoutMs`,默认 15000 毫秒,可在设置面板或 `settings.yaml` 中调整),且各渠道并发发送:无响应的端点只记录为失败,不会拖慢其他渠道或下一次调度。限制作用于整个渠道处理过程,也覆盖凭据解析——它不支持 abort 信号。
|
|
164
|
+
* **Telegram** —— 带状态徽标(✅ / ❌)、耗时、调度描述与等宽输出块的 Markdown 报告;动态值会被转义。凭据可直接填写,或从 DSH `settings.yaml` 的 `dsh-messenger-gateway` 段继承(尽力而为)。
|
|
165
|
+
* **Discord / Slack** —— 通过 webhook 投递:Discord 使用按运行状态着色的 embed,Slack 使用纯文本正文。
|
|
166
|
+
* **ntfy / Bark / PushPlus** —— 移动推送,支持主题/设备键与可选 bearer token;Bark 的标题与正文放在请求路径中,PushPlus 端点可指向自建代理。
|
|
167
|
+
* **语音** —— `dsh-tts` 通过其 HTTP 路由朗读报告(`ttsBaseUrl`,默认 `http://127.0.0.1:3080`)。
|
|
168
|
+
* **Gitea** —— 创建包含运行报告的 issue(`giteaBaseUrl`、`giteaRepo`、token 凭据);失败运行标记为 `cron`、`bug`、`alert`。
|
|
140
169
|
* **测试发送按钮** —— 在安排关键任务前现场验证 Telegram 连通性。
|
|
141
170
|
|
|
142
|
-
###
|
|
171
|
+
### 9. Kanban 集成与成本统计
|
|
143
172
|
* **自动创建 Kanban 卡片** —— 当 `kanbanMode` 为 `on_failure` 或 `always` 时,插件在 `dsh-kanban` 中创建卡片(`on_failure` → `error`/`timeout` 时进入 *Backlog*;`always` → 完成后进入 *Done*/*Backlog*)。
|
|
144
173
|
* **Token 与执行成本计量** —— 按运行与任务统计 token 消耗(输入、输出、缓存读取),基于内置价格表估算美元成本,并提供汇总分析栏。
|
|
145
174
|
|
|
146
|
-
###
|
|
175
|
+
### 10. 重叠策略与执行超时
|
|
147
176
|
|
|
148
177
|
* **执行超时(`timeoutSeconds`)** —— 达到限制后,shell 子进程通过 abort 信号立即终止,智能体会话被释放以停止消耗 token。默认 `1800`(30 分钟)。
|
|
149
178
|
* **重叠策略(`overlapPolicy`)** —— 上一次运行尚未结束时再次触发调度时的行为:
|
|
@@ -153,7 +182,7 @@ cron_create_task({
|
|
|
153
182
|
|
|
154
183
|
如果守护进程在计划时刻处于离线状态,启动时该次运行会被记录为 `missed`,历史空档始终可见。
|
|
155
184
|
|
|
156
|
-
###
|
|
185
|
+
### 11. 心跳监控(Dead man's switch)
|
|
157
186
|
* 在插件设置中配置 `heartbeatUrl` 与 `heartbeatIntervalSec`,调度器会按间隔 GET 该地址 —— 外部监控可在心跳停止时告警。
|
|
158
187
|
* 内置 `GET /dsh-cron/heartbeat` 端点返回存活状态、活跃任务数与最近运行时间,便于自建看门狗。
|
|
159
188
|
|
|
@@ -185,6 +214,24 @@ dsh-cron:
|
|
|
185
214
|
maxConcurrent: 0 # 最大并行运行数(0 = 不限)
|
|
186
215
|
heartbeatUrl: "" # 心跳上报 URL(dead man's snitch)
|
|
187
216
|
heartbeatIntervalSec: 0 # 心跳间隔秒数(0 = 关闭)
|
|
217
|
+
# --- 投递渠道 ---
|
|
218
|
+
botTokenRef: "" # Telegram bot token 的凭据名称
|
|
219
|
+
template: "" # 全局消息模板,例如 "⏰ {title} — {status}"
|
|
220
|
+
channelTemplates: {} # 按渠道覆盖模板
|
|
221
|
+
deliveryTimeoutMs: 15000 # 每个渠道的投递超时;慢端点记为失败,不影响其他渠道
|
|
222
|
+
discordWebhookUrl: "" # Discord webhook
|
|
223
|
+
slackWebhookUrl: "" # Slack incoming webhook
|
|
224
|
+
ntfyUrl: "https://ntfy.sh" # ntfy 服务器;ntfyTopic / ntfyTokenRef
|
|
225
|
+
ntfyTopic: ""
|
|
226
|
+
ntfyTokenRef: ""
|
|
227
|
+
barkServerUrl: "https://api.day.app" # Bark 服务器;barkKey = 设备键
|
|
228
|
+
barkKey: ""
|
|
229
|
+
pushplusUrl: "https://www.pushplus.plus/send" # pushplusTokenRef
|
|
230
|
+
pushplusTokenRef: ""
|
|
231
|
+
ttsBaseUrl: "http://127.0.0.1:3080" # dsh-tts 基础地址
|
|
232
|
+
giteaBaseUrl: "" # giteaRepo = owner/repo,giteaTokenRef = 凭据名称
|
|
233
|
+
giteaRepo: ""
|
|
234
|
+
giteaTokenRef: ""
|
|
188
235
|
```
|
|
189
236
|
|
|
190
237
|
### 配置参数
|
|
@@ -200,6 +247,16 @@ dsh-cron:
|
|
|
200
247
|
| `maxConcurrent` | `number` | `0` | 并行运行上限;超出的运行记录为 `skipped`(0 = 不限) |
|
|
201
248
|
| `heartbeatUrl` | `string` | `""` | 心跳上报 URL,调度器存活期间按 `heartbeatIntervalSec` 间隔 GET |
|
|
202
249
|
| `heartbeatIntervalSec` | `number` | `0` | 心跳间隔秒数(0 = 关闭) |
|
|
250
|
+
| `botTokenRef` | `string` | `""` | 保存 Telegram bot token 的 DSH 凭据名称;发送时解析(回退顺序:`botToken` → messenger-gateway 设置 → 环境变量 `CRON_TELEGRAM_BOT_TOKEN`) |
|
|
251
|
+
| `template` | `string` | `""` | 带 `{title}`/`{status}`/`{duration}` 等占位符的全局消息模板;留空使用内置文本 |
|
|
252
|
+
| `channelTemplates` | `object` | `{}` | 按渠道 ID 覆盖模板(`telegram`、`discord` 等) |
|
|
253
|
+
| `deliveryTimeoutMs` | `number` | `15000` | 每个渠道的投递超时;超时的端点记为失败,不拖慢其他渠道或下一次调度 |
|
|
254
|
+
| `discordWebhookUrl` / `slackWebhookUrl` | `string` | `""` | Discord 与 Slack 渠道的 webhook 地址 |
|
|
255
|
+
| `ntfyUrl` / `ntfyTopic` / `ntfyTokenRef` | `string` | `"https://ntfy.sh"` / `""` / `""` | ntfy 服务器、主题与可选的 token 凭据名称(以 `Authorization: Bearer …` 发送) |
|
|
256
|
+
| `barkServerUrl` / `barkKey` | `string` | `"https://api.day.app"` / `""` | Bark 服务器与设备键(键、标题和正文位于请求路径中) |
|
|
257
|
+
| `pushplusUrl` / `pushplusTokenRef` | `string` | `"https://www.pushplus.plus/send"` / `""` | PushPlus 端点(可指向自建代理)与 token 凭据名称 |
|
|
258
|
+
| `ttsBaseUrl` | `string` | `"http://127.0.0.1:3080"` | 用于语音播报的 `dsh-tts` 基础地址 |
|
|
259
|
+
| `giteaBaseUrl` / `giteaRepo` / `giteaTokenRef` | `string` | `""` | Gitea 渠道:基础地址、`owner/repo` 与 API token 的凭据名称 |
|
|
203
260
|
|
|
204
261
|
说明:
|
|
205
262
|
|
|
@@ -222,6 +279,9 @@ dsh-cron:
|
|
|
222
279
|
| `POST` | `/dsh-cron/tasks/:id/pause` | 暂停调度 |
|
|
223
280
|
| `POST` | `/dsh-cron/tasks/:id/resume` | 恢复调度 |
|
|
224
281
|
| `POST` | `/dsh-cron/tasks/:id/toggle` | 切换活跃/暂停 |
|
|
282
|
+
| `POST` | `/dsh-cron/tasks/:id/duplicate` | 创建暂停状态的副本:复制配置,重置运行历史与计数 |
|
|
283
|
+
| `GET` | `/dsh-cron/tasks/export` | 仅含任务配置的版本化 JSON —— 不含历史与计数。渠道按名称引用凭据,但手动填写在任务中的 `env` 与 HTTP 请求头属于配置,会出现在文件里 |
|
|
284
|
+
| `POST` | `/dsh-cron/tasks/import` | 校验文档并以 `add`、`replace` 或 `skip` 策略导入;支持 `dryRun` 预览。导入的任务始终为**暂停**状态,恢复不会自动触发 |
|
|
225
285
|
| `PATCH` | `/dsh-cron/tasks/:id` | 部分更新(仅白名单字段:`title`、`schedule`、`prompt`、`type`、`delivery`、`provider`、`model`、通知/超时/重叠/Kanban 设置、`status`、`oneShot`) |
|
|
226
286
|
| `DELETE` | `/dsh-cron/tasks/:id` | 删除任务 |
|
|
227
287
|
| `GET` | `/dsh-cron/models` | 列出 LLM 提供方;`?provider=<id>` 列出模型 |
|
package/docs/design/DESIGN.md
CHANGED
|
@@ -3,22 +3,24 @@
|
|
|
3
3
|
## Product / Purpose
|
|
4
4
|
- Назначение: Интегрированный планировщик cron-задач и фоновой автоматизации для DeepSeek Harness. Позволяет запускать агентские сессии по расписанию, выполнять автоматические проверки и предоставлять визуальный интерфейс управления задачами.
|
|
5
5
|
- Аудитория: Пользователи и операторы DeepSeek Harness, автоматизирующие периодические процессы (утренние сводки, проверка тикетов, мониторинг серверов).
|
|
6
|
-
- Статус: Active, публичный npm-пакет @goodandready/dsh-cron (
|
|
6
|
+
- Статус: Active, публичный npm-пакет @goodandready/dsh-cron (линия 0.2.x).
|
|
7
7
|
|
|
8
8
|
## User Surfaces
|
|
9
9
|
- Web/UI:
|
|
10
10
|
- Экран «Запланированные задачи» (полноэкранный оверлей в центральной колонке интерфейса DSH, аналогично dsh-kanban).
|
|
11
|
+
- Раздел «Активные задачи» в сайдбаре под кнопкой плагина: сворачиваемый (свёрнут по умолчанию, состояние запоминается), до пяти строк с названием и временем следующего запуска или живым статусом, строка «и ещё N»; клик открывает панель и подсвечивает задачу (#34).
|
|
12
|
+
- Панель фильтров в списке задач: тип, модель, канал; фильтрация мгновенная на клиенте, есть сброс, счётчик «показано N из M» и понятное пустое состояние (#40).
|
|
11
13
|
- Кнопка вызова в боковой панели (sidebar-entry) рядом с новой сессией + иконка в шапке сессии (utilities slot).
|
|
12
14
|
- Кнопка «Создать ⌄» с дропдауном:
|
|
13
15
|
- 💬 «Создать с DSH» (запуск интерактивного диалога постановки задачи агенту).
|
|
14
|
-
- ✏️ «Настроить вручную» (модальная форма:
|
|
16
|
+
- ✏️ «Настроить вручную» (модальная форма: тип и параметры рантайма, расписание, таймаут, overlap, промпт, модель, каналы доставки, шаблон сообщения).
|
|
15
17
|
- Табы фильтрации: «Все», «Активные», «На паузе», «Завершённые».
|
|
16
18
|
- Поисковая строка; сводная статистика (активные задачи, запуски, токены, стоимость).
|
|
17
19
|
- Карточки задач: статус-переключатель, название, расписание (человекочитаемое + raw cron), действия (запуск, редактирование, удаление).
|
|
18
20
|
- Блок «Рекомендуемые задачи»: готовые шаблоны (Daily digest, Weekly review, Follow-up monitor) в один клик.
|
|
19
21
|
- Карточка настроек в слоте settings.plugin.item, key = namespace `dsh-cron`; отдельный раздел настроек не используется (#102).
|
|
20
|
-
- LLM Tools: cron_create_task (+ alias cron_schedule_task), cron_list_tasks, cron_pause_task, cron_resume_task, cron_delete_task, cron_run_task.
|
|
21
|
-
- API: HTTP эндпоинты /dsh-cron/* (tasks, models, chat/start, settings, telegram/test, kanban/test, tasks/:id/actions, legacy action/:id/:action). Мутирующие эндпоинты отклоняют cross-origin запросы; script-задачи по HTTP требуют заголовок x-dsh-cron-confirm.
|
|
22
|
+
- LLM Tools: cron_create_task (+ alias cron_schedule_task), cron_list_tasks, cron_pause_task, cron_resume_task, cron_delete_task, cron_run_task. Параметры задачи включают рантайм (`type`), `channels` (список каналов доставки) и `template` (шаблон сообщения).
|
|
23
|
+
- API: HTTP эндпоинты /dsh-cron/* (tasks, models, chat/start, settings, telegram/test, kanban/test, tasks/:id/actions, legacy action/:id/:action). Мутирующие эндпоинты отклоняют cross-origin запросы; script-задачи по HTTP требуют заголовок x-dsh-cron-confirm. Настройки доставки принимаются как плоские ключи (webhook URL, топики, base URL) и `channelTemplates` — карта шаблонов по каналам.
|
|
22
24
|
- Chat / Slash Commands: отсутствуют (ранее заявленные /cron-команды не были реализованы и удалены из документации; решение 2026-09-09).
|
|
23
25
|
|
|
24
26
|
## Visual Direction
|
|
@@ -42,9 +44,11 @@
|
|
|
42
44
|
- CronSidebarButton: кнопка в левом сайдбаре DSH.
|
|
43
45
|
- CronScreen: основной оверлей со списком, табами, статистикой и рекомендациями.
|
|
44
46
|
- CreateDropdown: всплывающее меню выбора способа создания.
|
|
45
|
-
- ManualTaskModal: модальная форма создания/редактирования (вкладки «Параметры» / «История запусков»)
|
|
46
|
-
- SettingsModal: настройки
|
|
47
|
-
-
|
|
47
|
+
- ManualTaskModal: модальная форма создания/редактирования (вкладки «Параметры» / «История запусков»); блок каналов доставки — сетка чекбоксов (Telegram, dsh-kanban, Discord, Slack, ntfy, Bark, PushPlus, Voice, Gitea) и поле шаблона сообщения с подсказкой по переменным.
|
|
48
|
+
- SettingsModal: настройки доставки с тестами; три сворачиваемые секции — «Credentials (references)», «Delivery channels», «Message templates» (шапка-кнопка, aria-expanded, шеврон).
|
|
49
|
+
- DeliverySettingsForm: общая форма настроек доставки, одна реализация для SettingsModal и CronSettingsCard; секреты вводятся только по имени credential-ссылки.
|
|
50
|
+
- TaskItem: строка задачи с переключателем состояния и действиями (запуск, редактирование, дублирование, удаление); адресуется атрибутом data-task-id для подсветки из сайдбара.
|
|
51
|
+
- ImportModal: сводка по файлу (сколько добавится, заменится, пропустится) и выбор стратегии add/replace/skip до применения (#42).
|
|
48
52
|
- RecommendationCard: плашка с готовым шаблоном.
|
|
49
53
|
- CronSettingsCard: карточка параметров плагина в настройках; свёрнута по умолчанию, шапка-кнопка с шевроном разворачивает тело (aria-expanded), кнопка «Открыть панель задач» — внутри раскрытого тела (решение 2026-09-10, #100).
|
|
50
54
|
- States:
|
|
@@ -57,10 +61,16 @@
|
|
|
57
61
|
## User Flows
|
|
58
62
|
1. Создание через DSH-чат: «напоминай каждый день в 9 утра...» → «Создать с DSH» → агент уточняет тип (LLM/NO-LLM), расписание, модель, Silent Rule → после подтверждения вызывает cron_create_task → задача появляется на экране.
|
|
59
63
|
2. Создание вручную: кнопка сайдбара → «Создать ⌄» → «Настроить вручную» → форма → сохранение.
|
|
60
|
-
3. Выполнение по расписанию: croner/таймер one-shot → запуск shell
|
|
64
|
+
3. Выполнение по расписанию: croner/таймер one-shot → запуск по выбранному рантайму (агентская сессия, shell, node, python, http, ssh, docker) → запись в историю → доставка отчёта в выбранные каналы (Telegram, Kanban, Discord, Slack, ntfy, Bark, PushPlus, Voice, Gitea) с учётом `onlyOnFailure`.
|
|
61
65
|
4. Разбор инцидента: история запусков в карточке задачи → статус, длительность, вывод/ошибка.
|
|
62
66
|
|
|
63
67
|
## Locked Design Decisions
|
|
68
|
+
- 2026-09-11 — Доставка вынесена в отдельный слой: сообщение рендерится шаблоном `{var}` (#25), транспорт — адаптеры каналов с чистым builder'ом payload и инжектируемым fetch, маршрутизатор собирает ошибки каналов и не роняет запуск (#26, #20–#23, #28, #47). Явно выбранные каналы задачи перекрывают legacy-флаги `notifyTelegram`/`kanbanMode`.
|
|
69
|
+
- 2026-09-11 — Доставка не может заблокировать планировщик: каждый канал ограничен таймаутом (`deliveryTimeoutMs`, по умолчанию 15 с), каналы отправляются параллельно, а ошибки (включая таймаут) собираются в `failures`. Причина: `protect: true` в croner пропускал бы следующие тики, пока висит незавершённая доставка (находка независимого review PR #114).
|
|
70
|
+
- 2026-09-11 — Блок A (0.2.5): список активных задач в сайдбаре (#34), фильтры по типу/модели/каналу (#40), адаптив до 375 px без скрытия информации (#39), дублирование задачи серверным маршрутом с принудительной паузой и сбросом состояния (#41), экспорт/импорт конфигурации задач в JSON со стратегиями и dry-run (#42), нормализация и нижняя граница таймаута доставки (#115). Экспорт — только JSON: YAML-парсера в проекте нет, а зависимость ради формата не добавляется.
|
|
71
|
+
- 2026-09-11 — Значения с секретом внутри (webhook-URL Discord/Slack, ключ Bark) маскируются при отдаче в браузер, а замаскированное значение, вернувшееся от UI, не перезаписывает сохранённое; сырые credential-ключи отклоняются и в store, и на входе `/dsh-cron/settings`.
|
|
72
|
+
- 2026-09-11 — Секреты доставки хранятся только как credential-ссылки (#51): настройки содержат имя credential, значение резолвится в момент отправки через DSH credentials-сервис с фолбэком на ENV; store отказывается сохранять сырые secret-ключи.
|
|
73
|
+
- 2026-09-11 — Каталог данных плагина: `DSH_DATA_DIR` → `DSH_HOME/data` → `~/.dsh/data`. Причина: изолированный профиль не должен писать в чужой домашний каталог (issue #112, найдено на приёмке в тест-контуре).
|
|
64
74
|
- 2026-09-09 — Пакет надёжности ядра (v0.1.24): буфер shell-задач 10МБ, атомарное сохранение с PID, аудит пропущенных запусков при рестарте (missed), фоновый поллинг UI (8с).
|
|
65
75
|
- 2026-09-03 — Публичный скоуп @goodandready/dsh-cron; оверлей через mountSidebarEntry/mountScreen аналогично dsh-kanban; двойная кнопка «Создать ⌄».
|
|
66
76
|
- 2026-09-09 — Слот карточки настроек: settings.plugin.item с key/namespace `dsh-cron` (совпадение с серверной регистрацией). Причина: контракт слота настроек (#85). Changed 2026-09-10 (#102): settings.section fallback удалён — карточка только во вкладке плагинов.
|