dsh-engram 0.8.7 → 0.8.8

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 CHANGED
@@ -264,7 +264,7 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
264
264
  <!-- dsh-market compatibility block — keep labels bilingual and in sync with
265
265
  docs/RELEASE-NOTES.TEMPLATE.md (market README convention) -->
266
266
 
267
- - **DSH 版本 / DSH versions**: `>=0.1.2-alpha.2 <0.3.0-0` (本版 `0.8.7`; 已发布的 `0.3.7`、`0.4.0` 仍声明旧的 `0.1.x` 范围 `>=0.1.2-alpha.2 <0.2.0-0` — 见下方矩阵)
267
+ - **DSH 版本 / DSH versions**: `>=0.1.2-alpha.2 <0.3.0-0` (本版 `0.8.8`; 已发布的 `0.3.7`、`0.4.0` 仍声明旧的 `0.1.x` 范围 `>=0.1.2-alpha.2 <0.2.0-0` — 见下方矩阵)
268
268
  - **最后验证日期 / Last verified**: 2026-10-27 — DSH `0.2.1-rc.2` (`dsh --version`), web profile live composition; npm test 483/483
269
269
  - **安装方式已验证 / Verified install**: `dsh plugin --profile web add dsh-engram`
270
270
 
@@ -294,7 +294,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
294
294
  | `0.8.3`–`0.8.4` | 本地 | 同 `0.5.0` — 审批门(v0.8-D)+ 其 GUI;G6 门槛改单边(Δ ≥ −2pp)+ 隐藏规格语料 | 同 `0.5.0` |
295
295
  | `0.8.5` | 本地 | 同 `0.5.0` — 记忆行文件信号(`⚠file-changed` / `⚠file-missing`),G6 第三/四轮(撤回 +30pp,Δ=+58.3pp) | 同 `0.5.0` |
296
296
  | `0.8.6` (npm) | published | 同 `0.5.0` — 修 issue #9:宿主没有 `sessionQuery`/`snapshotEvents` 时退回 `seq`+`eventAt` 逐条读,四项注入特性不再静默休眠;warn 报出宿主 surface;G6 第五轮 Δ=+90.0pp | 同 `0.5.0` |
297
- | `0.8.7` (本期 / this release) | 本地 | 同 `0.5.0` — 推送腿落盘(`$DSH_HOME/engram/push-legs.jsonl`)+ `status` 打印事件日志读法;`minimal` 预设不再承诺永远不会发生的自动接管 | 同 `0.5.0` |
297
+ | `0.8.7` (npm) | published | 同 `0.5.0` — 推送腿落盘(`$DSH_HOME/engram/push-legs.jsonl`)+ `status` 打印事件日志读法;`minimal` 预设不再承诺永远不会发生的自动接管 | 同 `0.5.0` |
298
+ | `0.8.8` (本期 / this release) | 本地 | 同 `0.5.0` — 修推送腿遥测写错目录(`engram/engram/`)导致状态显示「还没记录」;`pushLegsPath` 契约写死在一处 | 同 `0.5.0` |
298
299
 
299
300
  ### Where the API family broke — `0.1.2-alpha.2`
300
301
 
package/README.zh.md CHANGED
@@ -189,7 +189,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
189
189
  | `0.7.5`–`0.7.13` | 本地 | 同 `0.5.0` —— 账本按会话落行 + `gate-audit`;L1 从「自己剪」转成「记账 + 归因」;压缩入账读真实事件形状;会话计数重启不清零;CLI 尊重 `DSH_HOME` | 同 `0.5.0` |
190
190
  | `0.8.0`–`0.8.5` | 本地 | 同 `0.5.0` —— 证据化 procedure、导出 DSH Skill、subagent 交接胶囊、审批门 + GUI、记忆行文件信号(`⚠file-changed`/`⚠file-missing`)、G6 门改单边 + 隐藏规格语料(Δ=+58.3pp) | 同 `0.5.0` |
191
191
  | `0.8.6`(npm) | 已发布 | 同 `0.5.0` —— 修 issue #9:宿主不暴露 `sessionQuery`/`snapshotEvents` 时退回 `seq`+`eventAt` 逐条读,四项注入特性不再静默休眠;warn 报出宿主 surface;G6 第五轮 Δ=+90.0pp | 同 `0.5.0` |
192
- | `0.8.7`(本期 / this release) | 本地 | 同 `0.5.0` —— 推送腿落盘(`$DSH_HOME/engram/push-legs.jsonl`)+ `status` 打印事件日志读法;`minimal` 预设不再承诺永远不会发生的自动接管 | 同 `0.5.0` |
192
+ | `0.8.7`(npm) | 已发布 | 同 `0.5.0` —— 推送腿落盘(`$DSH_HOME/engram/push-legs.jsonl`)+ `status` 打印事件日志读法;`minimal` 预设不再承诺永远不会发生的自动接管 | 同 `0.5.0` |
193
+ | `0.8.8`(本期 / this release) | 本地 | 同 `0.5.0` —— 修推送腿遥测写错目录(`engram/engram/`)导致状态显示「还没记录」;`pushLegsPath` 契约写死在一处 | 同 `0.5.0` |
193
194
 
194
195
  ### API 族断裂点:`0.1.2-alpha.2`
195
196
 
@@ -0,0 +1,44 @@
1
+ # dsh-engram v0.8.8
2
+
3
+ **0.8.7 的推送腿遥测写错了一层目录——装上真机、重启、看一眼状态,5 分钟内就露馅了。**
4
+
5
+ ## 修复:`push-legs.jsonl` 写到了 `engram/engram/`
6
+
7
+ 0.8.7 引入的推送腿遥测,`engramHome()` 已经以 `engram/` 结尾,写入端又拼了一次
8
+ `engram`,于是文件落在 `~/.dsh/engram/engram/push-legs.jsonl`;而 `dsh-engram status`
9
+ 读的是 `~/.dsh/engram/push-legs.jsonl`。
10
+
11
+ 结果是**一个工作正常的遥测,在状态里显示成「还没记录」**——正好是这一版想消灭的那种
12
+ 「看起来像没发生」。单测没抓到,因为测试自己造目录、两边用的是同一个临时路径。
13
+
14
+ 现在把契约写死在一处:`pushLegsPath(engramDir)` 的参数就是 engram 目录本身,
15
+ 写入端传 `engramHome()`、读取端传 `<dsh home>/engram`,注释里写明为什么不能拼第二次。
16
+ 新增一条回归测试直接断言 `pushLegsPath(dir) === join(dir, "push-legs.jsonl")`。
17
+
18
+ ## 顺带得到的一个真数据点
19
+
20
+ 修好路径、把线上那条记录归位之后,本机(`dsh 0.2.1-rc.2` CLI + web)的答案是:
21
+
22
+ ```
23
+ 推送腿:事件日志读法 snapshotEvents · 最近 2026/10/27 15:44:35 · snapshotEvents×1
24
+ ```
25
+
26
+ 也就是说**我们自己的宿主走的是 `snapshotEvents`**——`ctx.sessionQuery` 在这套组合里
27
+ 没挂上(宿主已把它标为 deprecated,但仍在)。这解释了为什么 0.8.6 补的
28
+ `seq`+`eventAt` 第四手值得留着:桌面运行时那类宿主一旦连 `snapshotEvents` 也去掉,
29
+ `eventAt` 就是最后的退路。
30
+
31
+ ## 证据
32
+
33
+ - `npm test` **489/489**(+1 路径契约回归)
34
+ - `npm run typecheck` 通过;`prepublishOnly` 真实 tarball + peers 后 host/client 双入口导入通过
35
+ - 真机验证:`dsh-engram status` 打印出上面那行读法;`~/.dsh/engram/engram/` 这个错误
36
+ 目录已清理,记录已归位到 `~/.dsh/engram/push-legs.jsonl`
37
+
38
+ ## DSH 版本支持(必填)
39
+
40
+ - **支持的 DSH 范围**:`>=0.1.2-alpha.2 <0.3.0-0`
41
+ - **验证版本**:`dsh 0.2.1-rc.2`(本机 CLI + web)
42
+ - **最后验证日期**:2026-10-27
43
+ - **安装方式已验证**:`prepublishOnly` 用真实 tarball 装 peers 后导入 host/client 双入口
44
+ - **peer 声明**:`@deepseek-ai/dsh-{settings,storage-domain,compaction,compaction-basic,llm}@>=0.1.2-alpha.2 <0.3.0-0`、`@deepseek-ai/cordis@^4.0.2`、`@deepseek-ai/schemastery@^3.18.2`
package/lib/index.js CHANGED
@@ -590,7 +590,7 @@ export function apply(ctx, config) {
590
590
  if (!notedSessionEvents.has(session)) {
591
591
  notedSessionEvents.add(session);
592
592
  noteSessionEventsSource({
593
- home: engramHome(),
593
+ engramDir: engramHome(),
594
594
  source: sessionEventsSource(session, sessionQuery),
595
595
  sessionId: session.header?.id ?? session.id,
596
596
  });
package/lib/push-legs.js CHANGED
@@ -29,26 +29,34 @@ export const PUSH_LEGS_KEEP = 50;
29
29
  /** Size at which the file is rewritten to the kept tail. */
30
30
  const PUSH_LEGS_MAX_BYTES = 32 * 1024;
31
31
 
32
- /** `<home>/engram/push-legs.jsonl` */
33
- export function pushLegsPath(home) {
34
- return join(home, "engram", "push-legs.jsonl");
32
+ /**
33
+ * `<engramDir>/push-legs.jsonl`.
34
+ *
35
+ * The argument is the ENGRAM directory (`~/.dsh/engram`), not the DSH home:
36
+ * `engramHome()` already ends in `engram/`, and appending it a second time is
37
+ * how 0.8.7 shipped a telemetry file at `~/.dsh/engram/engram/push-legs.jsonl`
38
+ * that `dsh-engram status` then reported as never written. Kept explicit so the
39
+ * two call sites cannot disagree again.
40
+ */
41
+ export function pushLegsPath(engramDir) {
42
+ return join(engramDir, "push-legs.jsonl");
35
43
  }
36
44
 
37
45
  /**
38
46
  * Record the read path taken for one session. Best effort: never throws.
39
47
  *
40
48
  * @param {object} options
41
- * @param {string} options.home DSH home
49
+ * @param {string} options.engramDir engram directory (`~/.dsh/engram`)
42
50
  * @param {string} options.source `sessionEventsSource()` verdict
43
51
  * @param {string} [options.sessionId]
44
52
  * @param {number} [options.pid]
45
53
  * @param {number} [options.now]
46
54
  * @returns {boolean} whether the row was written
47
55
  */
48
- export function noteSessionEventsSource({ home, source, sessionId, pid = process.pid, now = Date.now() } = {}) {
49
- if (typeof home !== "string" || home.length === 0) return false;
56
+ export function noteSessionEventsSource({ engramDir, source, sessionId, pid = process.pid, now = Date.now() } = {}) {
57
+ if (typeof engramDir !== "string" || engramDir.length === 0) return false;
50
58
  if (typeof source !== "string" || source.length === 0) return false;
51
- const path = pushLegsPath(home);
59
+ const path = pushLegsPath(engramDir);
52
60
  const row = `${JSON.stringify({ at: now, pid, sessionId: sessionId ?? null, source })}\n`;
53
61
  try {
54
62
  mkdirSync(dirname(path), { recursive: true });
@@ -68,14 +76,14 @@ export function noteSessionEventsSource({ home, source, sessionId, pid = process
68
76
  * Newest recorded read path (and how many rows mention each verdict).
69
77
  * Never throws; returns `undefined` when nothing was ever recorded.
70
78
  *
71
- * @param {string} home DSH home
79
+ * @param {string} engramDir engram directory (`~/.dsh/engram`)
72
80
  * @returns {{at: number, source: string, sessionId: string|null, pid: number, counts: Record<string, number>} | undefined}
73
81
  */
74
- export function readPushLegsHealth(home) {
75
- if (typeof home !== "string" || home.length === 0) return undefined;
82
+ export function readPushLegsHealth(engramDir) {
83
+ if (typeof engramDir !== "string" || engramDir.length === 0) return undefined;
76
84
  let raw;
77
85
  try {
78
- raw = readFileSync(pushLegsPath(home), "utf8");
86
+ raw = readFileSync(pushLegsPath(engramDir), "utf8");
79
87
  } catch {
80
88
  return undefined;
81
89
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-engram",
3
3
  "description": "Minimalist long-term memory for DeepSeek Harness, distilling symbolic-index + pi-esr ideas: zero-LLM auto-capture, a symbolic [ENGRAM] index with progressive disclosure, and an ESR-lite evidence-closure protocol (esr_task / esr_node / esr_close / esr_link). Real agent-behaviour telemetry (usage rollup + /stats) and a deterministic offline recall benchmark (npm run eval). Hot path is model-free; storage on ctx.storageDomain; web memory viewer, observability panel and config card through DSH's native settings slots.",
4
- "version": "0.8.7",
4
+ "version": "0.8.8",
5
5
  "packageManager": "pnpm@11.22.0",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -241,8 +241,9 @@ async function printStatus(presetsDirFlag) {
241
241
  // Printed from data, not from startup logs — a dormant leg must be visible
242
242
  // without the terminal that printed the warning.
243
243
  try {
244
- const home = process.env.DSH_HOME ?? join(homedir(), ".dsh");
245
- log(` ${describePushLegs(readPushLegsHealth(home))}`);
244
+ // `readLedger` above already resolves the same way: `<dsh home>/engram`.
245
+ const engramDir = join(process.env.DSH_HOME ?? join(homedir(), ".dsh"), "engram");
246
+ log(` ${describePushLegs(readPushLegsHealth(engramDir))}`);
246
247
  log("");
247
248
  } catch {}
248
249