@kanadego/dsh-heartbeat 1.9.1 → 1.9.2
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 +27 -5
- package/cordis.patch.yml +18 -39
- package/dist/{chunk-BQCXYE7N.js → chunk-3MDBU6WY.js} +2 -2
- package/dist/{chunk-HT57FOEF.js → chunk-AJ5HLAL7.js} +34 -11
- package/dist/chunk-AJ5HLAL7.js.map +1 -0
- package/dist/{chunk-OYVNWB5G.js → chunk-CUOSICYJ.js} +2 -2
- package/dist/{chunk-WRJCINZ7.js → chunk-IG6YMUHW.js} +4 -4
- package/dist/{chunk-KOOQOMQY.js → chunk-JDH2LDFS.js} +2 -2
- package/dist/chunk-K5Y6JP2B.js +399 -0
- package/dist/chunk-K5Y6JP2B.js.map +1 -0
- package/dist/{chunk-QOQ7EPZZ.js → chunk-KB5SMG3F.js} +3 -3
- package/dist/{chunk-2NB4QILF.js → chunk-XFNCTOW7.js} +2 -2
- package/dist/cli/index.js +9 -9
- package/dist/{inbox-JLT5G7TL.js → inbox-P26DDMWC.js} +3 -3
- package/dist/index.d.ts +33 -0
- package/dist/index.js +104 -20
- package/dist/index.js.map +1 -1
- package/dist/{migrate-WDVFHUP7.js → migrate-D4VKAKYT.js} +3 -3
- package/dist/{orchestrator-2ZLU7RGE.js → orchestrator-EUTZ3KG6.js} +10 -8
- package/dist/{pool-B34NTH6D.js → pool-UTXQJJ5C.js} +3 -3
- package/dist/{snapshot-JQDJ346Z.js → snapshot-K5VHETTK.js} +4 -4
- package/package.json +83 -83
- package/dist/chunk-7TW6DD6Q.js +0 -208
- package/dist/chunk-7TW6DD6Q.js.map +0 -1
- package/dist/chunk-HT57FOEF.js.map +0 -1
- /package/dist/{chunk-BQCXYE7N.js.map → chunk-3MDBU6WY.js.map} +0 -0
- /package/dist/{chunk-OYVNWB5G.js.map → chunk-CUOSICYJ.js.map} +0 -0
- /package/dist/{chunk-WRJCINZ7.js.map → chunk-IG6YMUHW.js.map} +0 -0
- /package/dist/{chunk-KOOQOMQY.js.map → chunk-JDH2LDFS.js.map} +0 -0
- /package/dist/{chunk-QOQ7EPZZ.js.map → chunk-KB5SMG3F.js.map} +0 -0
- /package/dist/{chunk-2NB4QILF.js.map → chunk-XFNCTOW7.js.map} +0 -0
- /package/dist/{inbox-JLT5G7TL.js.map → inbox-P26DDMWC.js.map} +0 -0
- /package/dist/{migrate-WDVFHUP7.js.map → migrate-D4VKAKYT.js.map} +0 -0
- /package/dist/{orchestrator-2ZLU7RGE.js.map → orchestrator-EUTZ3KG6.js.map} +0 -0
- /package/dist/{pool-B34NTH6D.js.map → pool-UTXQJJ5C.js.map} +0 -0
- /package/dist/{snapshot-JQDJ346Z.js.map → snapshot-K5VHETTK.js.map} +0 -0
package/README.md
CHANGED
|
@@ -97,7 +97,9 @@ dsh plugin --profile web add file:D:/path/to/dsh-heartbeat
|
|
|
97
97
|
|
|
98
98
|
重启 DSH 即生效——插件自动创建专用心跳会话并按节律运行,之后日常无需任何操作。
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
**心跳预设是自动装的**:插件加载时直接向宿主注册(`agentPresets.register()`,v1.9.2 起),不需要任何手动操作,**安装清单里也不再声明宿主包**。早先那种"声明式"写法要求 profile 自己能解析 `@deepseek-ai/dsh-agent-preset`:解析不到,整个插件树加载失败(0.1.5 宿主);手工把它的 peer 闭包补进 profile,又会把 cordis 的装载机制装成两份,之后**任何会话都无法恢复**(`prompt section "deployment:persona-prefix" is already registered`,0.2.0-rc.2)——两种都踩过,见 issue #2。`0.1.7` 之前的宿主仍走目录安装路径:启动时检查 `<DSH_HOME>/.agent-presets/heartbeat/`,缺失就按包内模板建好,**已有文件永不覆写**(你手改过的预设原样保留)。无论走哪条路径,没有这个预设心跳 agent 就是个"裸 agent",连 `web_search` 都看不见——想手动检查/修复用 `preset status` / `preset install`(见下节);把插件 config 的 `installPreset` 设为 `false` 可同时关掉运行时注册与目录自装,预设完全由你管。
|
|
101
|
+
|
|
102
|
+
**数据默认放在包外**:`<DSH_HOME>/heartbeat-data`(没有 `DSH_HOME` 就是 `~/.dsh/heartbeat-data`),重装与升级都不会碰它。老版本装在包目录里的 `data/` 会在首次启动时自动搬过去(搬迁前先备份、逐文件校验通过才删原件,见下节「卸载」)。要换位置就用插件 config 的 `dataDir`,或环境变量 `HEARTBEAT_DATA_DIR`。
|
|
101
103
|
|
|
102
104
|
## CLI 命令
|
|
103
105
|
|
|
@@ -192,15 +194,28 @@ node <插件目录>/dist/cli/index.js <命令>
|
|
|
192
194
|
dsh plugin --profile web remove @kanadego/dsh-heartbeat
|
|
193
195
|
```
|
|
194
196
|
|
|
195
|
-
|
|
197
|
+
卸载只拆插件本体(包、挂载行、注册项,无残留引用),**不动用户数据**——v1.9.2 起数据默认住在包外的 `<DSH_HOME>/heartbeat-data`(`~/.dsh/heartbeat-data`),重装、升级、卸载都不会碰它。想连数据一起删,先 `burn --all` 焚毁敏感内容再删目录。
|
|
198
|
+
|
|
199
|
+
老版本(≤ v1.9.1)装在包目录里的 `data/` 会被自动搬出去:启动时若发现包内有数据、包外还没有,就递归复制过去——**先备份一份、再逐文件校验**(文件清单、大小、sha256 全部一致),全部通过才删原目录与备份;任何一步失败都原地不动,继续用包内那份,并留痕 `data_dir_relocate_failed`。搬完之后老位置不会再被读取,也不会再创建。
|
|
200
|
+
|
|
201
|
+
如果想自己指定位置(比如放到别的盘),在 profile 的 `cordis.patch.yml` 里给 `heartbeat` 覆盖:
|
|
202
|
+
|
|
203
|
+
```yaml
|
|
204
|
+
- id: heartbeat
|
|
205
|
+
config:
|
|
206
|
+
dataDir: D:/your/workspace/heartbeat-data
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
显式指定时**不会**触发自动搬迁,也不会被上面的默认值覆盖——从包内搬出去这件事需要你手动做(照第 1 条的路径拷过去即可)。
|
|
196
210
|
|
|
197
211
|
## 版本兼容
|
|
198
212
|
|
|
199
213
|
| 插件版本 | 适配的 DSH |
|
|
200
214
|
|---|---|
|
|
201
|
-
| **v1.
|
|
202
|
-
| v1.7.
|
|
203
|
-
| v1.7.
|
|
215
|
+
| **v1.9.2**(当前) | `0.2.0-rc.1` – `0.2.0-rc.2` |
|
|
216
|
+
| v1.7.4 – v1.9.1 | `0.2.0-rc.1` – `0.2.0-rc.2` |
|
|
217
|
+
| v1.7.2 – v1.7.3 | `0.1.7-rc.1` – `0.2.0-rc.1` |
|
|
218
|
+
| v1.7.0 – v1.7.1 | `0.1.5-rc.2` – `0.1.7-rc.2` |
|
|
204
219
|
| v1.2.x – v1.6.4 | `0.1.2-rc.1` – `0.1.5-rc.2` |
|
|
205
220
|
| v1.1 | `0.1.2-rc.1` |
|
|
206
221
|
| v1.0 | ≤ `0.1.1-rc.2` |
|
|
@@ -214,6 +229,13 @@ dsh plugin --profile web remove @kanadego/dsh-heartbeat
|
|
|
214
229
|
<details open>
|
|
215
230
|
<summary><b>v1.9.x</b></summary>
|
|
216
231
|
|
|
232
|
+
### v1.9.2 · 2026-10-10(修复:预设改为运行时注册 + 数据目录移出包外)
|
|
233
|
+
|
|
234
|
+
- **预设不再写进安装清单**:修复了心跳模式预设在 profile 解析不到宿主包时,导致整个插件树加载失败、DSH 启动不起来的问题。现已改为插件在加载时自己向宿主注册,超时或失败会自动回退并留痕。
|
|
235
|
+
- **补依赖不再把宿主装成两份**:修复了为解析预设包手工补齐依赖后,宿主装载机制出现两份实例、所有会话都无法恢复的问题。现在清单里不再出现任何宿主包,那条补法也用不上了。
|
|
236
|
+
- **会话恢复失败不再无限重试**:修复了旧格式会话迁移被拒时,引擎室被反复重试拖住、永远空转的问题。现已把这类永久性失败单独识别,当场重建会话并把正身指过去;真正暂时性的错误仍照旧退避重试。
|
|
237
|
+
- **数据目录默认移出包外**:修复了数据默认住在包目录里、`dsh plugin add` 与每次升级替换包目录时连带删掉画像、素材池与正身记录的问题(原本只有显式 `burn` 才会销毁)。默认位置现为 `<DSH_HOME>/heartbeat-data`;老版本装在包内的 `data/` 首次启动自动搬迁——先备份、再逐文件校验(清单、大小、sha256 全部一致),全部通过才删原件与备份,任何一步失败都原地不动。
|
|
238
|
+
|
|
217
239
|
### v1.9.1 · 2026-10-07(代码审查:86 项修复)
|
|
218
240
|
|
|
219
241
|
进行了一次全量代码审查,共 86 项。没有功能上的加减,优化了代码结构,清理并修复了一批 bug 与潜在问题:
|
package/cordis.patch.yml
CHANGED
|
@@ -8,46 +8,25 @@
|
|
|
8
8
|
# - id: heartbeat
|
|
9
9
|
# config:
|
|
10
10
|
# dataDir: D:/your/workspace/data
|
|
11
|
-
# Default: <
|
|
11
|
+
# Default: <DSH_HOME>/heartbeat-data (i.e. ~/.dsh/heartbeat-data), outside the
|
|
12
|
+
# package. Data written by v1.9.1 and earlier sits at <packageRoot>/data and is
|
|
13
|
+
# migrated out automatically on first start (backup, verify, then delete).
|
|
12
14
|
- insert:
|
|
13
15
|
- id: heartbeat
|
|
14
16
|
name: '@kanadego/dsh-heartbeat'
|
|
15
17
|
|
|
16
|
-
# ── Agent preset heartbeat
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# "
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
plugins:
|
|
32
|
-
- id: compaction
|
|
33
|
-
name: cordis:group
|
|
34
|
-
group: true
|
|
35
|
-
isolate:
|
|
36
|
-
compaction: true
|
|
37
|
-
toolResultPruner: true
|
|
38
|
-
config:
|
|
39
|
-
- id: compaction-basic
|
|
40
|
-
name: '@deepseek-ai/dsh-compaction-basic'
|
|
41
|
-
- id: command-compact
|
|
42
|
-
name: '@deepseek-ai/dsh-command-compact'
|
|
43
|
-
- id: tool-result-pruner
|
|
44
|
-
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
|
45
|
-
config:
|
|
46
|
-
thresholdChars: 8192
|
|
47
|
-
headChars: 4096
|
|
48
|
-
tailChars: 1024
|
|
49
|
-
- id: tool-web
|
|
50
|
-
name: '@deepseek-ai/dsh-tool-web'
|
|
51
|
-
config:
|
|
52
|
-
fetch: false
|
|
53
|
-
searchTimeoutMs: 60000
|
|
18
|
+
# ── Agent preset heartbeat(改为插件运行时注册,v1.9.2 / issue #2)────────
|
|
19
|
+
# 这里**故意不再**声明 `@deepseek-ai/dsh-agent-preset` 行。那行会让 profile
|
|
20
|
+
# 必须自己能解析该包,而它的 peer 闭包里含着 cordis 自己的装载机制
|
|
21
|
+
# (cordis-plugin-loader / -include / -group):
|
|
22
|
+
# · profile 解析不到 → 整个插件树加载失败(0.1.5-rc.2 实测);
|
|
23
|
+
# · 手工补进 peer 闭包 → 装载机制双实例,之后**任何会话 resume 全部失败**
|
|
24
|
+
# (`prompt section "deployment:persona-prefix" is already registered`,
|
|
25
|
+
# 0.2.0-rc.2 实测)。
|
|
26
|
+
# 两种都在 2026-10-10 被复现(见 issue #2)。现在预设定义活在插件里
|
|
27
|
+
# (src/core/preset-definition.ts),加载时经 `agentPresets.register()` 运行时
|
|
28
|
+
# 注册——declaring plugin 自己提供 definition 正是该 API 的用途;宿主没有这个
|
|
29
|
+
# API 时只记一条审计,绝不让宿主挂掉。老宿主(仍扫名册文件系统用户根)继续由
|
|
30
|
+
# preset-install 自装维持。内容与 assets/presets/heartbeat/agent.cordis.yml 一致:
|
|
31
|
+
# compaction 组 + 唯一模型工具 tool-web(fetch:false);刻意没有 persona 行——
|
|
32
|
+
# 部署人格(soul card)+ 心跳提示词已够,绝不能让 "You are a coding agent" 盖掉人格。
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
loadEncryptedText,
|
|
6
6
|
saveEncryptedText
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-K5Y6JP2B.js";
|
|
8
8
|
|
|
9
9
|
// src/profile/inbox.ts
|
|
10
10
|
import fs from "fs";
|
|
@@ -110,4 +110,4 @@ export {
|
|
|
110
110
|
inboxHealthCheck,
|
|
111
111
|
inboxFileExists
|
|
112
112
|
};
|
|
113
|
-
//# sourceMappingURL=chunk-
|
|
113
|
+
//# sourceMappingURL=chunk-3MDBU6WY.js.map
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
sendNewMessageHint,
|
|
21
21
|
sendWeeklyReadyHint,
|
|
22
22
|
weeklyDue
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-IG6YMUHW.js";
|
|
24
24
|
import {
|
|
25
25
|
getRuntime
|
|
26
26
|
} from "./chunk-3QJJRXIR.js";
|
|
@@ -31,17 +31,17 @@ import {
|
|
|
31
31
|
loadPool,
|
|
32
32
|
seedsFilePath,
|
|
33
33
|
surfaceSeed
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-JDH2LDFS.js";
|
|
35
35
|
import {
|
|
36
36
|
dedupeItems,
|
|
37
37
|
inboxClear,
|
|
38
38
|
inboxCount,
|
|
39
39
|
inboxDrain,
|
|
40
40
|
inboxFilePath
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-3MDBU6WY.js";
|
|
42
42
|
import {
|
|
43
43
|
snapshotIfDue
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-KB5SMG3F.js";
|
|
45
45
|
import {
|
|
46
46
|
appendAuditLine,
|
|
47
47
|
applyOpsToDoc,
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
readAuditLines,
|
|
54
54
|
readJournalTexts,
|
|
55
55
|
runDeterministicAging
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-CUOSICYJ.js";
|
|
57
57
|
import {
|
|
58
58
|
decryptFile,
|
|
59
59
|
encryptFile,
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
saveEncryptedText,
|
|
64
64
|
saveJson,
|
|
65
65
|
writeText
|
|
66
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-K5Y6JP2B.js";
|
|
67
67
|
import {
|
|
68
68
|
atomicWriteJsonSync,
|
|
69
69
|
burnFileSync
|
|
@@ -990,7 +990,7 @@ async function runConsolidation(guard, paths, policy, llm, now = Date.now()) {
|
|
|
990
990
|
const report = applyOpsToDoc(guard, paths.dataDir, doc, profileOpsCast, schema, policy, now);
|
|
991
991
|
const aged = runDeterministicAging(doc, policy, now);
|
|
992
992
|
persistWithJournal(guard, paths.dataDir, doc, { runId, applied: report.applied, rejected: report.rejected });
|
|
993
|
-
const { addSeed: addSeed2, seedsFilePath: seedsFilePath2 } = await import("./pool-
|
|
993
|
+
const { addSeed: addSeed2, seedsFilePath: seedsFilePath2 } = await import("./pool-UTXQJJ5C.js");
|
|
994
994
|
const seedAudit = (entry) => {
|
|
995
995
|
try {
|
|
996
996
|
appendAuditLine(paths.dataDir + "/logs/heartbeat.jsonl", entry);
|
|
@@ -1277,6 +1277,13 @@ function applyHeartbeatInterval(deps, intervalMin) {
|
|
|
1277
1277
|
reschedule?.(v);
|
|
1278
1278
|
appendAuditLine(deps.paths.logsDir + "/heartbeat.jsonl", { event: "interval_changed", intervalMin: v });
|
|
1279
1279
|
}
|
|
1280
|
+
function looksPermanentResumeFailure(error) {
|
|
1281
|
+
return [
|
|
1282
|
+
/SessionFormatUnsupportedError/i,
|
|
1283
|
+
/refuses the transformed artifact/i,
|
|
1284
|
+
/session migration[^]*refus/i
|
|
1285
|
+
].some((re) => re.test(error));
|
|
1286
|
+
}
|
|
1280
1287
|
function sessionEvents(session, fromSeq) {
|
|
1281
1288
|
if (!session) return [];
|
|
1282
1289
|
if (typeof session.snapshotEvents === "function") {
|
|
@@ -1398,6 +1405,11 @@ function makeHomeSetup(deps) {
|
|
|
1398
1405
|
return async (agentCtx) => {
|
|
1399
1406
|
const notes = [];
|
|
1400
1407
|
const presetId = deps.agentPreset ?? "heartbeat";
|
|
1408
|
+
try {
|
|
1409
|
+
await withTimeout(deps.presetRegistration?.() ?? Promise.resolve(), 3e4, "preset registration timeout (30s)");
|
|
1410
|
+
} catch (e) {
|
|
1411
|
+
notes.push(`preset-register=threw(${String(e).slice(0, 120)})`);
|
|
1412
|
+
}
|
|
1401
1413
|
try {
|
|
1402
1414
|
const presets = agentCtx.get("agentPresets");
|
|
1403
1415
|
if (typeof presets?.mount !== "function") {
|
|
@@ -1539,12 +1551,15 @@ async function ensureAgent(deps) {
|
|
|
1539
1551
|
agent = unwrap(handle);
|
|
1540
1552
|
appendAuditLine(paths.logsDir + "/heartbeat.jsonl", { event: "agent_resume_ok", sessionId: savedId, model: agent.options?.model ?? "(none)" });
|
|
1541
1553
|
} catch (resumeErr) {
|
|
1554
|
+
const resumeMessage = String(resumeErr);
|
|
1542
1555
|
appendAuditLine(paths.logsDir + "/heartbeat.jsonl", {
|
|
1543
1556
|
event: "agent_resume_failed",
|
|
1544
1557
|
sessionId: savedId,
|
|
1545
|
-
error:
|
|
1558
|
+
error: resumeMessage.slice(0, 160)
|
|
1546
1559
|
});
|
|
1547
|
-
|
|
1560
|
+
const gone = /not found/i.test(resumeMessage);
|
|
1561
|
+
const permanent = !gone && looksPermanentResumeFailure(resumeMessage);
|
|
1562
|
+
if (!gone && !permanent) {
|
|
1548
1563
|
appendAuditLine(paths.logsDir + "/heartbeat.jsonl", {
|
|
1549
1564
|
event: "agent_deferred",
|
|
1550
1565
|
sessionId: savedId,
|
|
@@ -1553,6 +1568,13 @@ async function ensureAgent(deps) {
|
|
|
1553
1568
|
agentPromise = null;
|
|
1554
1569
|
return null;
|
|
1555
1570
|
}
|
|
1571
|
+
if (permanent) {
|
|
1572
|
+
appendAuditLine(paths.logsDir + "/heartbeat.jsonl", {
|
|
1573
|
+
event: "agent_resume_permanent",
|
|
1574
|
+
sessionId: savedId,
|
|
1575
|
+
error: resumeMessage.slice(0, 160)
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1556
1578
|
try {
|
|
1557
1579
|
const handle = await withTimeout(Promise.resolve(ctx.agents.create({ sessionId: savedId, meta: { cwd: paths.dataDir }, ...agentOptions ? { agentOptions } : {}, setup })), 3e4, "agents.create (self-heal) timeout");
|
|
1558
1580
|
agent = unwrap(handle);
|
|
@@ -1760,7 +1782,7 @@ async function observeBoundSessions(bc) {
|
|
|
1760
1782
|
const { deps, now } = bc;
|
|
1761
1783
|
const { guard, paths } = deps;
|
|
1762
1784
|
const { loadBindings, observeTargets } = await import("./bindings-225SI7KC.js");
|
|
1763
|
-
const { inboxAppend, inboxFilePath: inboxFilePath2 } = await import("./inbox-
|
|
1785
|
+
const { inboxAppend, inboxFilePath: inboxFilePath2 } = await import("./inbox-P26DDMWC.js");
|
|
1764
1786
|
const data = loadBindings(guard, paths.settingsDir);
|
|
1765
1787
|
const targets = observeTargets(data);
|
|
1766
1788
|
if (targets.length === 0) return;
|
|
@@ -2428,6 +2450,7 @@ export {
|
|
|
2428
2450
|
StatusReader,
|
|
2429
2451
|
buildDigest,
|
|
2430
2452
|
applyHeartbeatInterval,
|
|
2453
|
+
looksPermanentResumeFailure,
|
|
2431
2454
|
sessionEvents,
|
|
2432
2455
|
sessionEventCount,
|
|
2433
2456
|
HOME_ROTATE_EVENT_COUNT,
|
|
@@ -2451,4 +2474,4 @@ export {
|
|
|
2451
2474
|
beat,
|
|
2452
2475
|
startOrchestrator
|
|
2453
2476
|
};
|
|
2454
|
-
//# sourceMappingURL=chunk-
|
|
2477
|
+
//# sourceMappingURL=chunk-AJ5HLAL7.js.map
|