dsh-engram 0.8.6 → 0.8.7
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 +9 -2
- package/README.zh.md +2 -1
- package/docs/RELEASE-NOTES-v0.8.7.md +69 -0
- package/lib/index.js +14 -0
- package/lib/push-legs.js +121 -0
- package/package.json +1 -1
- package/scripts/dsh-engram.mjs +19 -2
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.
|
|
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` — 见下方矩阵)
|
|
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
|
|
|
@@ -293,7 +293,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
293
293
|
| `0.8.0`–`0.8.2` | 本地 | 同 `0.5.0` — 证据化 procedure(v0.8-A)、导出为 DSH Skill(v0.8-B)、subagent 交接胶囊(v0.8-C) | 同 `0.5.0` |
|
|
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
|
-
| `0.8.6` (
|
|
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
298
|
|
|
298
299
|
### Where the API family broke — `0.1.2-alpha.2`
|
|
299
300
|
|
|
@@ -1035,6 +1036,12 @@ and silence when there is nothing relevant to point at:
|
|
|
1035
1036
|
> session object does offer — that line is the thing to paste into a bug report.
|
|
1036
1037
|
> Known case: the **desktop runtime** (`@deepseek-ai/dsh-desktop-runtime`) on
|
|
1037
1038
|
> Windows, tracked as issue #9.
|
|
1039
|
+
>
|
|
1040
|
+
> `dsh-engram status` also prints a **push-legs** line — `推送腿:事件日志读法
|
|
1041
|
+
> sessionQuery · 最近 …` — the read path the live process actually took, written
|
|
1042
|
+
> to `$DSH_HOME/engram/push-legs.jsonl`. A dormant host shows
|
|
1043
|
+
> `事件日志不可读(none)… 休眠中` there, so the four features can be checked
|
|
1044
|
+
> without hunting a startup log.
|
|
1038
1045
|
|
|
1039
1046
|
### Entity pages + entity cards (v0.7-B)
|
|
1040
1047
|
|
package/README.zh.md
CHANGED
|
@@ -188,7 +188,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
188
188
|
| `0.7.3`–`0.7.4`(npm `latest`) | 已发布 | 同 `0.5.0` —— 设置卡迁到「Engram 记忆 → 设置」tab(DSH `0.2.1` 删了旧 section);修 DSH `0.2.x` 上「推送腿」整条静默失效(`[RECALL]` 启动召回、JIT 推送) | 同 `0.5.0` |
|
|
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
|
-
| `0.8.6
|
|
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
193
|
|
|
193
194
|
### API 族断裂点:`0.1.2-alpha.2`
|
|
194
195
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# dsh-engram v0.8.7
|
|
2
|
+
|
|
3
|
+
**「特性睡着了」这件事,现在有离线证据可查;顺手拆掉一句永远不会兑现的状态承诺。**
|
|
4
|
+
|
|
5
|
+
0.8.6 修了 issue #9 的**能力**问题(宿主不暴露批量读接口时退回 `seq`+`eventAt`)。
|
|
6
|
+
这一版补的是**可观测**问题:就算下一次再遇到同类宿主,也不该有人靠解 zstd 帧
|
|
7
|
+
才能证明「不是还没触发,是根本不会触发」。
|
|
8
|
+
|
|
9
|
+
## 新增:推送腿(push legs)有了落盘证据
|
|
10
|
+
|
|
11
|
+
`[RECALL]`、会话 episode、`[RESUME]` 简报、会话结束的 todo sink —— 这四件事共享
|
|
12
|
+
同一个前提:会话事件日志可读。它们一起醒,也一起睡。
|
|
13
|
+
|
|
14
|
+
以前这里只有一个 `warn`,打在一个没人留着的终端上。现在每个会话装配时,插件把
|
|
15
|
+
**实际走了哪条读法**追加进 `$DSH_HOME/engram/push-legs.jsonl`(有界:超 32 KB 只留尾 50 行):
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{"at":1793086321920,"pid":59392,"sessionId":"session-…","source":"sessionQuery"}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`source` 就是 `sessionEventsSource()` 的裁决:`legacy` / `sessionQuery` /
|
|
22
|
+
`snapshotEvents` / `eventAt` / `none`。
|
|
23
|
+
|
|
24
|
+
`dsh-engram status` 多一行:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
推送腿:事件日志读法 sessionQuery · 最近 2026/10/27 15:32:01 · sessionQuery×3 · eventAt×1
|
|
28
|
+
推送腿:⚠ 事件日志不可读(none)—— [RECALL]/episode/resume/todo-sink 休眠中 · 2026/10/27 15:32:01 · none×1
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
第二条就是 issue #9 那台机器的样子——不用开日志、不用解帧,一眼能看出是休眠还是没触发。
|
|
32
|
+
|
|
33
|
+
## 修复:`minimal` 预设的状态行在撒谎
|
|
34
|
+
|
|
35
|
+
`dsh-engram status` 对未接管的预设一直打印「出厂布局,重启 dsh web 后自动接管」。
|
|
36
|
+
但 DSH 0.2.1-rc.2 的 `minimal.patch.yml` 里 compaction 组**缺 `tool-result-pruner` 行**,
|
|
37
|
+
换行不变量(要标准形状)不成立,`swapCompactionRow` 返回 `null`,boot 时记的是
|
|
38
|
+
`skipped / layout-mismatch`——那句承诺永远不会兑现,重启多少次都是 `stock`。
|
|
39
|
+
|
|
40
|
+
现在对 `stock` 再做一次换行探测,换不动就直说:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
minimal: stock — 出厂布局但与标准形状不同(行不全),自动接管不会发生;要 Context GC 请手工接线或改用 standard
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 证据
|
|
47
|
+
|
|
48
|
+
- `npm test` **488/488**(+5:push-legs 落盘、最新裁决、休眠措辞、有界重写、坏文件不抛)
|
|
49
|
+
- `npm run typecheck` 通过;`prepublishOnly` 真实 tarball + peers 装上后 host/client 双入口导入通过
|
|
50
|
+
- 本机 0.8.6 实机取证:状态快照 `pid 59392`(15:31:47 写入)→ `recall-injections.json`
|
|
51
|
+
的 `lastInjection` 为 **15:32:01**,即重启后 14 秒推送腿真的动了
|
|
52
|
+
|
|
53
|
+
## 升级后请做的一件事(如果你在 issue #9 里报过障)
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
npx dsh-engram status
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
把「推送腿」那一行贴回 issue。如果它写 `none`,说明桌面运行时的 Session 连
|
|
60
|
+
`eventAt` 都不给,那才需要走「直接读 `session.v4.jsonl.zstd`」这条重路子
|
|
61
|
+
(Node 22 无内置 zstd,要引依赖);如果写 `eventAt` 或 `sessionQuery`,说明已经修好。
|
|
62
|
+
|
|
63
|
+
## DSH 版本支持(必填)
|
|
64
|
+
|
|
65
|
+
- **支持的 DSH 范围**:`>=0.1.2-alpha.2 <0.3.0-0`
|
|
66
|
+
- **验证版本**:`dsh 0.2.1-rc.2`(本机 CLI + web)
|
|
67
|
+
- **最后验证日期**:2026-10-27
|
|
68
|
+
- **安装方式已验证**:`prepublishOnly` 用真实 tarball 装 peers 后导入 host/client 双入口
|
|
69
|
+
- **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
|
@@ -33,6 +33,7 @@ import { buildEpisode } from "./episode.js";
|
|
|
33
33
|
import { collectStaleAnchors } from "./anchor.js";
|
|
34
34
|
import { renderIndex, renderStartRecall, renderResumeBrief, firstUserMessageText, renderEsr, esrMethodology, buildEsrSnapshot, buildFrozenEsrBlock } from "./index-block.js";
|
|
35
35
|
import { describeSessionSurface, sessionEventsSource, sessionSeq } from "./session-events.js";
|
|
36
|
+
import { noteSessionEventsSource } from "./push-legs.js";
|
|
36
37
|
import { makeTriggerRecorder } from "./trigger.js";
|
|
37
38
|
import { pendingTodosFromSession, sinkPendingTodos } from "./todo-sink.js";
|
|
38
39
|
import { installEngramSettings, makeEngineConfigSchema, SETTINGS_KEYS } from "./settings.js";
|
|
@@ -543,6 +544,8 @@ export function apply(ctx, config) {
|
|
|
543
544
|
const sessionCache = new WeakMap();
|
|
544
545
|
/** One-time-per-process notice: the host's session log is unreadable. */
|
|
545
546
|
let warnedUnreadableLog = false;
|
|
547
|
+
/** Sessions whose event-log read path was already recorded (push-legs.jsonl). */
|
|
548
|
+
const notedSessionEvents = new WeakSet();
|
|
546
549
|
const blockFor = (agent) => {
|
|
547
550
|
if (agent === void 0) return "";
|
|
548
551
|
const session = agent.session;
|
|
@@ -581,6 +584,17 @@ export function apply(ctx, config) {
|
|
|
581
584
|
// next assembly retry, so a new conversation never permanently misses its
|
|
582
585
|
// recalled memory.
|
|
583
586
|
if (resolved.autoRecallOnStart !== false) {
|
|
587
|
+
// Push-legs telemetry (issue #9): record which read path this session
|
|
588
|
+
// took, once per session object, so `dsh-engram status` can answer
|
|
589
|
+
// "were [RECALL]/episode/resume/todo-sink awake?" without a log capture.
|
|
590
|
+
if (!notedSessionEvents.has(session)) {
|
|
591
|
+
notedSessionEvents.add(session);
|
|
592
|
+
noteSessionEventsSource({
|
|
593
|
+
home: engramHome(),
|
|
594
|
+
source: sessionEventsSource(session, sessionQuery),
|
|
595
|
+
sessionId: session.header?.id ?? session.id,
|
|
596
|
+
});
|
|
597
|
+
}
|
|
584
598
|
const query = firstUserMessageText(session, sessionQuery);
|
|
585
599
|
if (query.length === 0) {
|
|
586
600
|
// Retry on the next assembly ONLY when the log is readable and the
|
package/lib/push-legs.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observability for the four features that read the session event log.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS (2026-10-27, issue #9): `[RECALL]`, the session episode, the
|
|
5
|
+
* resume brief and the session-end todo sink all depend on ONE host capability
|
|
6
|
+
* — a readable session event log. When a host stops exposing every read path,
|
|
7
|
+
* the four of them sleep together and the only trace is a single `warn` line on
|
|
8
|
+
* a terminal nobody kept. The reporter in issue #9 had to decompress
|
|
9
|
+
* `session.v4.jsonl.zstd` frames by hand to prove the features were not merely
|
|
10
|
+
* "not triggered yet".
|
|
11
|
+
*
|
|
12
|
+
* A warning is not an artifact. This module records which read path the live
|
|
13
|
+
* process actually took, once per session, into
|
|
14
|
+
* `$DSH_HOME/engram/push-legs.jsonl` so `dsh-engram status` can answer
|
|
15
|
+
* "were the push legs awake?" without a session, a log capture, or a report.
|
|
16
|
+
*
|
|
17
|
+
* The record is append-only and bounded (tail kept, like the other telemetry
|
|
18
|
+
* files): diagnostics must never grow without limit or throw into the
|
|
19
|
+
* assembly path.
|
|
20
|
+
* @module dsh-engram/push-legs
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { appendFileSync, existsSync, readFileSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
24
|
+
import { mkdirSync } from "node:fs";
|
|
25
|
+
import { dirname, join } from "node:path";
|
|
26
|
+
|
|
27
|
+
/** Rows kept before the file is rewritten (tail-first). */
|
|
28
|
+
export const PUSH_LEGS_KEEP = 50;
|
|
29
|
+
/** Size at which the file is rewritten to the kept tail. */
|
|
30
|
+
const PUSH_LEGS_MAX_BYTES = 32 * 1024;
|
|
31
|
+
|
|
32
|
+
/** `<home>/engram/push-legs.jsonl` */
|
|
33
|
+
export function pushLegsPath(home) {
|
|
34
|
+
return join(home, "engram", "push-legs.jsonl");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Record the read path taken for one session. Best effort: never throws.
|
|
39
|
+
*
|
|
40
|
+
* @param {object} options
|
|
41
|
+
* @param {string} options.home DSH home
|
|
42
|
+
* @param {string} options.source `sessionEventsSource()` verdict
|
|
43
|
+
* @param {string} [options.sessionId]
|
|
44
|
+
* @param {number} [options.pid]
|
|
45
|
+
* @param {number} [options.now]
|
|
46
|
+
* @returns {boolean} whether the row was written
|
|
47
|
+
*/
|
|
48
|
+
export function noteSessionEventsSource({ home, source, sessionId, pid = process.pid, now = Date.now() } = {}) {
|
|
49
|
+
if (typeof home !== "string" || home.length === 0) return false;
|
|
50
|
+
if (typeof source !== "string" || source.length === 0) return false;
|
|
51
|
+
const path = pushLegsPath(home);
|
|
52
|
+
const row = `${JSON.stringify({ at: now, pid, sessionId: sessionId ?? null, source })}\n`;
|
|
53
|
+
try {
|
|
54
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
55
|
+
if (existsSync(path) && statSync(path).size > PUSH_LEGS_MAX_BYTES) {
|
|
56
|
+
const kept = readFileSync(path, "utf8").split("\n").filter((line) => line.length > 0).slice(-PUSH_LEGS_KEEP);
|
|
57
|
+
writeFileSync(`${path}.tmp`, `${kept.join("\n")}\n`, "utf8");
|
|
58
|
+
renameSync(`${path}.tmp`, path);
|
|
59
|
+
}
|
|
60
|
+
appendFileSync(path, row, "utf8");
|
|
61
|
+
return true;
|
|
62
|
+
} catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Newest recorded read path (and how many rows mention each verdict).
|
|
69
|
+
* Never throws; returns `undefined` when nothing was ever recorded.
|
|
70
|
+
*
|
|
71
|
+
* @param {string} home DSH home
|
|
72
|
+
* @returns {{at: number, source: string, sessionId: string|null, pid: number, counts: Record<string, number>} | undefined}
|
|
73
|
+
*/
|
|
74
|
+
export function readPushLegsHealth(home) {
|
|
75
|
+
if (typeof home !== "string" || home.length === 0) return undefined;
|
|
76
|
+
let raw;
|
|
77
|
+
try {
|
|
78
|
+
raw = readFileSync(pushLegsPath(home), "utf8");
|
|
79
|
+
} catch {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
const counts = {};
|
|
83
|
+
let newest;
|
|
84
|
+
for (const line of raw.split("\n")) {
|
|
85
|
+
if (line.length === 0) continue;
|
|
86
|
+
let row;
|
|
87
|
+
try {
|
|
88
|
+
row = JSON.parse(line);
|
|
89
|
+
} catch {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (typeof row?.source !== "string") continue;
|
|
93
|
+
counts[row.source] = (counts[row.source] ?? 0) + 1;
|
|
94
|
+
if (newest === undefined || (typeof row.at === "number" && row.at >= (newest.at ?? 0))) newest = row;
|
|
95
|
+
}
|
|
96
|
+
if (newest === undefined) return undefined;
|
|
97
|
+
return {
|
|
98
|
+
at: typeof newest.at === "number" ? newest.at : 0,
|
|
99
|
+
source: newest.source,
|
|
100
|
+
sessionId: typeof newest.sessionId === "string" ? newest.sessionId : null,
|
|
101
|
+
pid: typeof newest.pid === "number" ? newest.pid : 0,
|
|
102
|
+
counts,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* One-line human summary for `dsh-engram status`.
|
|
108
|
+
* @param {ReturnType<typeof readPushLegsHealth>} health
|
|
109
|
+
* @returns {string}
|
|
110
|
+
*/
|
|
111
|
+
export function describePushLegs(health) {
|
|
112
|
+
if (health === undefined) return "推送腿:还没记录(本机还没有会话装配过)";
|
|
113
|
+
const when = new Date(health.at).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
|
|
114
|
+
const tally = Object.entries(health.counts)
|
|
115
|
+
.map(([source, count]) => `${source}×${count}`)
|
|
116
|
+
.join(" · ");
|
|
117
|
+
if (health.source === "none") {
|
|
118
|
+
return `推送腿:⚠ 事件日志不可读(none)—— [RECALL]/episode/resume/todo-sink 休眠中 · ${when} · ${tally}`;
|
|
119
|
+
}
|
|
120
|
+
return `推送腿:事件日志读法 ${health.source} · 最近 ${when} · ${tally}`;
|
|
121
|
+
}
|
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.
|
|
4
|
+
"version": "0.8.7",
|
|
5
5
|
"packageManager": "pnpm@11.22.0",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
package/scripts/dsh-engram.mjs
CHANGED
|
@@ -25,6 +25,7 @@ import { execFileSync } from "node:child_process";
|
|
|
25
25
|
import { dirname, basename, resolve, join } from "node:path";
|
|
26
26
|
import { homedir } from "node:os";
|
|
27
27
|
import { fileURLToPath } from "node:url";
|
|
28
|
+
import { describePushLegs, readPushLegsHealth } from "../lib/push-legs.js";
|
|
28
29
|
import {
|
|
29
30
|
compactionWireStatus,
|
|
30
31
|
discoverPresetsDir,
|
|
@@ -37,7 +38,7 @@ import { defaultSkillDir, exportSkills, skillDescription, skillName, planSkillEx
|
|
|
37
38
|
import { approvedIds, isApproved, loadApprovals, recordApproval, revokeApproval } from "../lib/approvals.js";
|
|
38
39
|
import { isProvenProcedure, invalidatedProcedure } from "../lib/status-insights.js";
|
|
39
40
|
import { workspaceKey } from "../lib/util.js";
|
|
40
|
-
import { ENGRAM_PRUNE_ROW_NAME } from "../lib/web-provision.js";
|
|
41
|
+
import { ENGRAM_PRUNE_ROW_NAME, swapCompactionRow } from "../lib/web-provision.js";
|
|
41
42
|
|
|
42
43
|
const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
43
44
|
|
|
@@ -236,6 +237,15 @@ async function printStatus(presetsDirFlag) {
|
|
|
236
237
|
}
|
|
237
238
|
} catch {}
|
|
238
239
|
|
|
240
|
+
// Push legs (issue #9): which session-event read path the live process took.
|
|
241
|
+
// Printed from data, not from startup logs — a dormant leg must be visible
|
|
242
|
+
// without the terminal that printed the warning.
|
|
243
|
+
try {
|
|
244
|
+
const home = process.env.DSH_HOME ?? join(homedir(), ".dsh");
|
|
245
|
+
log(` ${describePushLegs(readPushLegsHealth(home))}`);
|
|
246
|
+
log("");
|
|
247
|
+
} catch {}
|
|
248
|
+
|
|
239
249
|
if (status === undefined) {
|
|
240
250
|
log(" 尚无状态文件(插件还没写过,或本机没跑过 dsh web)。");
|
|
241
251
|
} else {
|
|
@@ -299,7 +309,14 @@ async function printStatus(presetsDirFlag) {
|
|
|
299
309
|
const note = cs === "wired"
|
|
300
310
|
? `已接管(dsh-engram/compaction 行${hasPrune ? " + dsh-engram/prune 行" : " · 缺 prune 行:L1 在这个预设里看不见边界,重跑 enable 补齐"})`
|
|
301
311
|
: cs === "stock"
|
|
302
|
-
?
|
|
312
|
+
? swapCompactionRow(text) === null
|
|
313
|
+
// "stock" only says the stock row is present; it does not promise
|
|
314
|
+
// the swap will take. `minimal` ships a compaction group without
|
|
315
|
+
// the result pruner, so the swap refuses to guess and the preset
|
|
316
|
+
// stays stock forever — saying "重启后自动接管" there would be a
|
|
317
|
+
// status line that lies.
|
|
318
|
+
? "出厂布局但与标准形状不同(行不全),自动接管不会发生;要 Context GC 请手工接线或改用 standard"
|
|
319
|
+
: "出厂布局,重启 dsh web 后自动接管"
|
|
303
320
|
: "自定义/无 compaction,插件不碰";
|
|
304
321
|
log(` ${preset.id}: ${cs} — ${note}`);
|
|
305
322
|
}
|