# @analy3939/dsh-heartbeat 中文文档

规范地址：https://npmcn.com/package/%40analy3939/dsh-heartbeat/

版本：0\.1\.10
npm 元数据更新时间：2026-10-11T16:25:53.926Z
中文译文更新时间：2026-11-07T00:05:12.844Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40analy3939/dsh-heartbeat
原文对照：https://npmcn.com/package/%40analy3939/dsh-heartbeat/?lang=original
项目主页：https://github.com/Matrix-P/dsh-heartbeat#readme
源码仓库：https://github.com/Matrix-P/dsh-heartbeat

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：452 kB，65 个文件
- 模块格式：ES Module
- TypeScript 类型：未声明
- Node.js 要求：\>=20
- 运行依赖：0 个
- peer 依赖：@deepseek-ai/cordis ^4\.0\.2，@deepseek-ai/dsh-llm ^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2，@deepseek-ai/dsh-agent ^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2，@deepseek-ai/dsh-session ^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2，@deepseek-ai/schemastery ^3\.18\.2，@deepseek-ai/dsh-settings ^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2，@deepseek-ai/dsh-home-paths ^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2，@deepseek-ai/dsh-host-webserver ^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2，@deepseek-ai/cordis-plugin-timer ^1\.1\.4，@deepseek-ai/dsh-api-session-controller ^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2
- 首次发布：2026-10-09T15:51:00.386Z
- 最新版本发布：2026-10-11T16:25:53.770Z
- 近 30 天下载量：2135（2026-10-06 至 2026-11-04，npm 官方下载统计）
- 已发布版本数：10（近 12 个月 10 个）

## 中文简介

DSH 心跳：按时间规则向指定会话的主 Agent 主动投递一条你自己写的提示；模型输出期间不计时

## 安装

```sh
npm install @analy3939/dsh-heartbeat
```

也可以使用：`pnpm add @analy3939/dsh-heartbeat`、`yarn add @analy3939/dsh-heartbeat`、`bun add @analy3939/dsh-heartbeat`

## README

# dsh-heartbeat · DSH 心跳

> 让 DeepSeek Harness 按你定的时间，**主动来跟你说话**。

`dsh-heartbeat` 是给 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的**定时任务组件**：按时间规则，向**你指定的那个会话**投递一条**你自己写的**提示。最终说什么，由那个会话的主 Agent 结合上下文和人设自己发挥。

```
你写：  早上好呀，看看 {weekday} 的日程，用你平时的语气跟我说句话
DSH 收到：「早上好呀，看看周一的日程，用你平时的语气跟我说句话」
目标会话的 Agent 结合上下文生成真正的回复 → 你收到一条消息
```

* * *

## 它和别的定时插件有什么不一样

|  |  |
| --- | --- |
| **模型说话期间不计时** | 下一次触发从「模型这次输出结束」那一刻重新起算。输出中不会被心跳打断，也不会因为回复耗时长而让计时漂移。 |
| **投给谁由你定** | 指定任意**根会话**（含 IM 渠道会话）。子 Agent 会话会被自动过滤掉 —— 心跳只找「主 Agent」。 |
| **文案权留给你和那个人设** | 插件只投递你写的提示，**不预设任何固定回复**。目标会话的 Agent 用自己的性格说话。 |
| **可视化设置界面** | 设置 → 心跳：任务列表、下次触发时间、已触发次数、无回应次数、立即触发一次、新建/编辑/删除。中英双语。 |
| **零运行时依赖** | 只依赖 DSH 官方包（`peerDependencies`）与 Node 内置模块。没有第三方运行时依赖。 |

* * *

## 安装

```sh
dsh plugin add @analy3939/dsh-heartbeat --profile web
```

因为包内声明了 `dsh.bundle`，`dsh` 会把它追加进 profile 的 `dsh.profile.bundles` 并自动应用配置层。**装完需要重启一次 DSH web**（新增插件行不会热加载）。

其他安装方式

```sh
# 从 GitHub 源码安装（需要额外给 pnpm 授权构建脚本）
dsh plugin add github:Matrix-P/dsh-heartbeat --profile web

# 从本地 tarball 安装（scoped 包的 tarball 名会把 scope 拼进来）
pnpm pack
dsh plugin add ./analy3939-dsh-heartbeat-0.1.2.tgz --profile web
```

> 这个包曾经以裸名 `dsh-heartbeat` 发布（0.1.0 / 0.1.1）。因为 GitHub 上已有同名插件 （`Kanadego/dsh-heartbeat`），为避免混淆改用了 npm scope 前缀 **`@analy3939/`**；旧名已 `deprecate`，内容等价。

要求：DSH **`0.1.5-rc.2` 或 `0.2.0-rc.2`**（两代都支持：配置通道在运行时探测 `settings.register` —— 有就走 0.1.x 的命名空间热更新，没有就用 0.2.x 的 Loader 行 Config）、Node ≥ 20、Web 系 profile（桌面端也是 Web 系）。

> **0.2.x 上的两点差异**：0.2.0 移除了共享的 `plugin` 消息来源 kind，也移除了配置写前校验钩子。因此（1）心跳提示在 0.2.x 上按"未知来源"降级呈现；（2）配置问题通过 `/api/heartbeat/state` 的 `warnings` 暴露，而不是在保存时被直接拒绝。

* * *

## 快速开始

1.  打开 **设置 → 心跳**，勾选「启用组件」；
2.  点「新建任务」；
3.  填 **名称**、选 **目标会话**（下拉列出了你的所有根会话和它们的标题）、写 **提示文案**；
4.  选时间规则 → 保存。

任务立刻生效。列表里能看到状态、下次触发时间、已触发次数、连续无回应次数，也可以「立即触发」一次来验证链路。

* * *

## 时间规则

| 类型 | `type` | 说明 | 主要字段 |
| --- | --- | --- | --- |
| 一次性 | `once` | 某个日期时刻触发一次 | `at` |
| 每天 | `daily` | 每天固定时刻 | `at` |
| 每周 | `weekly` | 每周指定日 + 时刻 | `at`、`days` |
| 固定间隔 | `interval` | 每 N 分钟/小时触发 | `every`、`anchor` |
| 窗口内固定间隔 | `windowed-interval` | 只在每天的时间窗口内按间隔触发 | `every`、`window`、`align` |

-   **生效日**（`weekly`）：每天 / 工作日 / 周末 / 自定义。
-   **计时起点**（`interval`）：`enable-time` 从启用时刻起算，或 `interval-end` 每次触发后重新计时。
-   **窗口内对齐**（`windowed-interval`）：以窗口起点对齐，或从启用时刻对齐。
-   时长写法：`30s`、`15m`、`2h`、`1d`，也可以组合。

配置最终落在 `settings.yaml`：

```yaml
heartbeat:
  tasks:
    - id: task-1
      name: 早安
      session: <sessionId>
      schedule:
        type: interval
        every: 1m
        anchor: interval-end
      payload:
        kind: prompt
        text: 早上好呀，用你平时的语气跟我说句话
      noReply:
        max: 3
```

* * *

## 提示文案里的占位符

在文案里写 `{名字}` 即可，触发时求值。带参数的写 `{time:HH:mm}`，方括号可转义字面量（`[`、`]`）。

| 占位符 | 默认参数 | 含义 |
| --- | --- | --- |
| `{time}` | `HH:mm` | 当前时刻 |
| `{date}` | `YYYY-MM-DD` | 当前日期 |
| `{datetime}` | `YYYY-MM-DD HH:mm` | 当前日期与时间 |
| `{weekday}` | — | 星期几（周一…周日） |
| `{taskId}` | — | 任务 ID |
| `{taskName}` | — | 任务展示名 |
| `{fireCount}` | — | 含本次在内的累计触发次数 |
| `{noReplyStreak}` | — | 当前连续无回应次数 |
| `{lastFiredAt}` | `YYYY-MM-DD HH:mm` | 上次触发时间 |
| `{nextFireAt}` | `YYYY-MM-DD HH:mm` | 下次计划触发时间 |
| `{sinceLastUserMsg}` | — | 距用户上次发言的时长 |
| `{lastUserMsgAt}` | `YYYY-MM-DD HH:mm` | 用户上次发言时刻 |
| `{random}` | `1-100` | 随机整数（可指定范围，如 `{random:1-6}`） |

例：`{weekday} {time:HH:mm} 了，{sinceLastUserMsg} 没找我说话了，{random:1-3} 句话哄哄我`

* * *

## 投递策略

| 字段 | 取值 | 说明 |
| --- | --- | --- |
| `onBusy` | `queue`（默认）/ `skip` / `inject` | 目标会话正忙（模型在输出）时：排队等这轮结束 / 跳过本次 / 立刻插进去 |
| `missed` | `skip`（默认）/ `fire-once` | 进程重启或机器休眠期间错过的触发：跳过 / 补发一次 |
| `noReply.max` | 数字，`0` = 关闭 | 连续 N 次没有回应就暂停这个任务（静默），不再打扰你 |
| `noReply.window` | 时长，留空 = 到下次触发前 | 判定「有没有回应」的时间窗 |

被静默的任务会显示「暂停」状态，界面上可以直接重新启用。

* * *

## 状态与接口

组件把**运行期状态**（下次触发、触发次数、无回应次数、静默原因）通过只读 HTTP 暴露，**不写进 `settings.yaml`**，免得把配置文档弄脏：

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| `GET` | `/api/heartbeat/state` | 全部任务的运行期状态 |
| `GET` | `/api/heartbeat/sessions` | 可投递的会话候选（已过滤子会话） |
| `POST` | `/api/heartbeat/fire` | 立即触发一次（仅限本机请求），body `{"id":"<taskId>"}` |

状态目录：`$DSH_HOME/storages/heartbeat/`（每个任务一个 JSON，原子写）。

* * *

## 试出来的坑（给插件开发者的三条经验）

这个组件在真实 DSH 里调试时踩到几个只在运行时才暴露的坑，挑三条最值钱的：

1.  **`link:` 安装会分裂模块身份** —— 插件里的 `@deepseek-ai/*` 会解析到源码目录自己的副本，于是 `inject` 的服务永远解析不到，fiber 静静停在 `PENDING`。用真实副本 / npm 安装。
2.  **直读一个没有 `inject` 的服务会抛异常**（不是返回 `undefined`）——`(ctx as {x?: T}).x` 这种"可选直读"会让 `apply` 直接抛，插件整个不加载。正确写法是 `ctx.get(name)` + `ctx.inject([name], cb)`。
3.  **`settings.section` 的 owner 只传 `close` 一个 prop** —— 分区组件的 `scope`/`t`/数据都要靠注册时闭包带进去，直接注册裸组件会拿到一堆 `undefined`。

另外：客户端插槽所在的 Loader 行，**行名必须与 `package.json` 的 `name` 完全一致**，否则客户端半边不会被扫描到（宿主正常、界面永远不出现）。

* * *

## 开发

```sh
pnpm install
pnpm test        # 24 个测试文件 / 521 个用例
pnpm typecheck
pnpm build       # ESM → lib/，客户端 bundle → lib/client.js
```

-   `src/schedule/` 时间规则（时长、时区、日历、下次触发推导）
-   `src/templating/` 占位符解析与求值
-   `src/runtime/` 状态机、时钟 seam、单 timer 调度器、编排器、持久化
-   `src/delivery/` 投递端口（**只给主 Agent** 这条约束在这里）
-   `src/host/` 唯一直接接触 `@deepseek-ai/*` 的胶水层
-   `src/client/` 设置界面（纯逻辑与 React 组件分离）

* * *

## English

`dsh-heartbeat` is a scheduling component for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness): on your schedule, it delivers **a prompt you wrote** to **a session you pick**, and that session's main agent answers in its own voice, with full context.

Highlights:

-   **Output-aware timing** — the next fire is counted from the moment the model _finishes_ its output, not from the trigger. Heartbeats never interrupt an in-flight reply, and long answers don't drift the schedule.
-   **You choose the target** — any root session, including IM channels. Subagent sessions are filtered out; heartbeats only talk to a main agent.
-   **The text is yours** — the plugin delivers your prompt (13 `{placeholders}` supported) and leaves the wording to the target agent's persona.
-   **Visual settings UI** — task list, next fire time, fire count, no-reply streak, fire-now button, create/edit/delete. Bilingual (中文 / English).
-   **Zero runtime dependencies** — DSH official packages as peer dependencies plus Node built-ins.

```sh
dsh plugin add @analy3939/dsh-heartbeat --profile web
```

Requires DSH `0.1.5-rc.2`+, Node ≥ 20, and a Web-family profile.

## License

MIT

## 常见问题

### @analy3939/dsh-heartbeat 是什么？

DSH 心跳：按时间规则向指定会话的主 Agent 主动投递一条你自己写的提示；模型输出期间不计时

### 如何安装 @analy3939/dsh-heartbeat？

在项目目录运行 npm install @analy3939/dsh-heartbeat，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：@deepseek-ai/cordis（^4\.0\.2）、@deepseek-ai/dsh-llm（^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2）、@deepseek-ai/dsh-agent（^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2）、@deepseek-ai/dsh-session（^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2）、@deepseek-ai/schemastery（^3\.18\.2）、@deepseek-ai/dsh-settings（^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2）、@deepseek-ai/dsh-home-paths（^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2）、@deepseek-ai/dsh-host-webserver（^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2）、@deepseek-ai/cordis-plugin-timer（^1\.1\.4）、@deepseek-ai/dsh-api-session-controller（^0\.1\.5-rc\.2 \|\| ^0\.2\.0-rc\.2）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @analy3939/dsh-heartbeat 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/analy3939\_\_dsh-heartbeat 是否存在。

### @analy3939/dsh-heartbeat 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @analy3939/dsh-heartbeat 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=20。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @analy3939/dsh-heartbeat 可以商用吗？

@analy3939/dsh-heartbeat 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @analy3939/dsh-heartbeat 的下载量有多少？

根据 npm 官方下载统计，@analy3939/dsh-heartbeat 在 2026/10/06 – 2026/11/04 这 30 天内被下载 2,135 次，日均约 71 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @analy3939/dsh-heartbeat 还在维护吗？

最新版本 0\.1\.10 发布于 2026/10/12（27 天前）；至今共发布 10 个版本，其中过去 12 个月发布了 10 个；首次发布于 2026/10/09。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

