dsh-engram 0.3.5 → 0.3.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 CHANGED
@@ -40,6 +40,17 @@ with one goal: **save tokens**.
40
40
  tokenization), recall runs a bounded substring scan over the newest session
41
41
  logs (zstd-decompressed, LRU-cached) and appends matched past sessions —
42
42
  deterministic `# past sessions` lines, capped files and bytes.
43
+ - **Session-start auto-recall (`autoRecallOnStart`, default on)** — the pull-only
44
+ design had a gap proven in real use: recall tools relied on model initiative,
45
+ and in practice the model almost never calls `engram_recall` on its own (19
46
+ real sessions, thousands of tool calls, ~5 recall calls total). So at the FIRST
47
+ assembly of a new session the host runs one deterministic BM25 recall keyed on
48
+ the session's first user message and injects the top ≤ `autoRecallLimit` hits
49
+ as a `[RECALL]` block (default 700-char budget, "few and precise" — agentmemory
50
+ candidate ①). Relevant memory is in context even without a single recall call.
51
+ Pure rule, zero LLM, pure read (never bumps `hits`); superseded stale truth does
52
+ not occupy an injection slot (still fetchable via `engram_detail`); frozen per
53
+ session together with `[ENGRAM]` for prefix stability.
43
54
  - **Memory-to-memory semantics** — `engram_store` accepts optional
44
55
  `supersedes` / `contradicts` memory ids (validated against the same
45
56
  workspace). A superseded ("stale truth") memory is demoted to the tail of
@@ -128,14 +139,175 @@ LLM-distillation and vector/graph niches are already crowded. dsh-engram fills t
128
139
  three gaps that matter for token discipline:
129
140
 
130
141
  1. **No model in the write path** — capture is deterministic pattern matching.
131
- 2. **No raw text in the prompt** — a bounded symbolic index is injected, retrieval
132
- stays on demand ("retrieved ≠ injected").
142
+ 2. **No raw text in the prompt** — a bounded symbolic index is injected, plus the
143
+ top ≤ N memories auto-recalled for the session's first message (within budget);
144
+ deeper retrieval stays on demand ("retrieved ≠ full-text injected").
133
145
  3. **Honest task closure** — STABLE cannot be declared without evidence.
134
146
 
135
147
  DSH already provides cross-session FTS (`ctx.sessionQuery`), storage
136
148
  (`ctx.storageDomain`), prompt-injection hooks and settings slots; dsh-engram is a
137
149
  thin composition layer over them, not a re-implementation.
138
150
 
151
+ ## Security model
152
+
153
+ The DSH plugin ecosystem is young and unvetted — there is no official directory,
154
+ no signature check, and the harness's read/write permission tiers do **not**
155
+ constrain what a plugin's own code can do. So the trust bar for a memory plugin
156
+ is higher than for a tool: a memory plugin sits on your prompt prefix and writes
157
+ to disk on your behalf. dsh-engram's model, stated plainly:
158
+
159
+ - **No network, ever.** The plugin has no outbound socket, no telemetry, no
160
+ update pinger. Nothing here can leak your sessions off the machine.
161
+ - **No shell, no filesystem access beyond one storage file.** It never executes
162
+ commands and never touches arbitrary paths. All data lives in the single
163
+ storage-domain unit `~/.dsh/storages/dsh_engram.json` (plus the session-log
164
+ reads it makes through DSH's own `ctx.sessionQuery`).
165
+ - **Secrets are redacted before they can land on disk.** Every write path —
166
+ `engram_store`, auto-capture, and the import/restore route — runs text through
167
+ the deterministic `redactText` rule engine (API keys, JWTs, `Bearer` tokens,
168
+ private keys, `key=value` secret shapes) *before* the dedup hash, the char
169
+ cap, and storage. Nothing sensitive is ever persisted, so nothing sensitive
170
+ can be recalled later.
171
+ - **Doing harm requires your harness's own permissions.** The plugin only *asks*
172
+ the host to do things via the same seams the tools you already trust use. It
173
+ does not widen sandbox policy or escalate to `danger-full-access` — if you
174
+ keep your profile's defaults, engram inherits exactly those bounds.
175
+ - **Read-mostly web API, loopback-fenced.** The GUI routes under
176
+ `/api/dsh-engram` reject any non-loopback caller unless you explicitly
177
+ whitelist a hostname via `trustedHosts`; even then the same-origin fence holds.
178
+ - **Verifiable.** `npm run dsh-engram -- doctor` (`/scripts/dsh-engram.mjs
179
+ doctor`) reports what the plugin is configured to touch; the whole store is
180
+ inspectable, nothing is opaque. If you ever doubt a claim in this section, the
181
+ code to check is `lib/redact.js`, `lib/store.js` and this plugin's
182
+ `cordis.patch.yml`.
183
+
184
+ What this deliberately does **not** claim: it is not an air-gap. If your profile
185
+ grants the agent `danger-full-access` or a shell, the agent can use those —
186
+ engram is a memory layer, not a sandbox. The point above is that *dsh-engram
187
+ itself* adds no surface of its own.
188
+
189
+ ## Data contract: export / import
190
+
191
+ Memory should not be a hostage. The four tables (memories / tasks / links /
192
+ entities) can be dumped and restored through a stable, versioned, machine-readable
193
+ shape — so the corpus survives a reinstall, a machine move, or (when a thin
194
+ adapter is written) a move to another harness, MCP end-point or Claude Code
195
+ skill. The contract is plain JSON with a self-describing header:
196
+
197
+ ```http
198
+ GET /api/dsh-engram/export?workspace=/path/to/project # one workspace
199
+ GET /api/dsh-engram/export # every workspace
200
+ ```
201
+
202
+ ```jsonc
203
+ {
204
+ "meta": { "format": "dsh-engram/export", "version": 1, "exportedAt": 1724…, "workspace": "/path/to/project" },
205
+ "memories": [ /* all rows, archived included — a backup never loses provenance */ ],
206
+ "tasks": [ /* draft/active/stable + archived */ ],
207
+ "links": [ /* typed edges */ ],
208
+ "entities": [ /* graph nodes */ ]
209
+ }
210
+ ```
211
+
212
+ Restore is idempotent by default and gated when destructive:
213
+
214
+ ```http
215
+ POST /api/dsh-engram/import # body: { payload, mode, dryRun?, workspace?, confirm? }
216
+ ```
217
+
218
+ - **`mode: "merge"`** (default) — writes only rows whose `id` is absent, so a
219
+ backup can be re-applied any number of times without duplicating anything. Each
220
+ row keeps its own `workspace`.
221
+ - **`mode: "replace"`** — wipes the target `workspace` from all four tables, then
222
+ restores only its rows. Destructive, so it additionally requires
223
+ `confirm: "restore"` in the body.
224
+ - **`dryRun: true`** — computes the identical plan (what would be written /
225
+ skipped) without writing a single row.
226
+ - **Import honors the same invariants as `storeMemory`**: memory text passes the
227
+ secret redactor before touching disk, and rows that would break the contract
228
+ (missing id/workspace, empty text, over `maxMemoryChars`, id already present
229
+ in merge, over the workspace memory cap) are skipped and listed in the
230
+ response report instead of aborting the batch.
231
+
232
+ A restore round-trip for one workspace is then:
233
+
234
+ ```sh
235
+ curl -s "http://127.0.0.1:3080/api/dsh-engram/export?workspace=$PWD" -o engram-backup.json
236
+ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
237
+ -H "content-type: application/json" \
238
+ -d "{\"payload\": $(cat engram-backup.json), \"mode\": \"merge\"}"
239
+ ```
240
+
241
+ ## DSH compatibility
242
+
243
+ > **Short version.** Every **published** release (`0.2.0` … `0.3.6`) supports
244
+ > the **old** DSH API graph (`0.1.0-rc.7` / `0.1.1`, peers `^0.1.0-rc.7`)
245
+ > **only**. DSH `0.1.2-alpha.2` and newer are **not** compatible with those
246
+ > releases — the settings/client API family broke there. New-DSH support
247
+ > **starts with `0.3.7`**, the first release of the new API generation
248
+ > (described below).
249
+
250
+ | dsh-engram release | Status | DSH support | Declared via |
251
+ | --- | --- | --- | --- |
252
+ | `0.2.0` … `0.3.6` (npm, GitHub v0.3.3–v0.3.6) | published | **old DSH only** — `0.1.0-rc.7` / `0.1.0-rc.8` / `0.1.1-rc.1` / `0.1.1-rc.2` | peers `@deepseek-ai/dsh-*@^0.1.0-rc.7` |
253
+ | `0.3.7` (npm, GitHub v0.3.7) | published | **new DSH only** — `>=0.1.2-alpha.2 <0.2.0-0` | `engines.dsh` + peers `>=0.1.2-alpha.2 <0.2.0-0` |
254
+
255
+ ### Where the API family broke — `0.1.2-alpha.2`
256
+
257
+ `0.1.2-alpha.2` is the first version of the new API family and the first that
258
+ **breaks** the released plugin versions:
259
+
260
+ - `@deepseek-ai/dsh-settings` **removed** `settingsNamespace()` and
261
+ `installSettingsSection()` — the exact imports every release ≤ `0.3.6` uses —
262
+ and replaced them with `settings.installSection`. The old host half fails to
263
+ load on `0.1.2-alpha.2+`.
264
+ - The web client half swapped its inject set: `@deepseek-ai/dsh-client-runtime`
265
+ no longer exists in the new family (replaced by `dsh-api-remotes` plus
266
+ `dsh-client-locale` / `-conversation` / `-renderer` / `-ui-settings-plugins`),
267
+ and the settings card used to talk through `ctx.remote.settings`.
268
+ - Supporting bumps at the same boundary: `@deepseek-ai/cordis` `^4.0.1 → ^4.0.2`,
269
+ `@deepseek-ai/schemastery` `^3.18.1 → ^3.18.2`, and `@deepseek-ai/dsh` stopped
270
+ shipping `config/agent-presets` in the package (moved to `dsh.configTrees`).
271
+
272
+ The web config card no longer depends on any of this: since `0.3.7` it reads
273
+ and writes the `dsh-engram` settings namespace through the plugin's **own**
274
+ HTTP route (`/api/dsh-engram/settings`, same-origin fetch like the memory
275
+ viewer), so the card is generation-agnostic on both sides of the
276
+ `0.1.2-alpha.2` boundary.
277
+
278
+ So: keep DSH on `0.1.1-rc.2` or older while running a release ≤ `0.3.6`, and
279
+ upgrade the plugin to `>=0.3.7` before moving DSH to `0.1.2-alpha.2`.
280
+
281
+ ### Current release — `0.3.7`
282
+
283
+ This release declares support for DSH `>=0.1.2-alpha.2 <0.2.0-0` and was fully
284
+ validated against the `dsh-v0.1.5-alpha.1` source and web runtime from the local
285
+ `deepseek-harness` checkout.
286
+
287
+ | Component | Supported range |
288
+ | --- | --- |
289
+ | DSH runtime / host / client package family | `>=0.1.2-alpha.2 <0.2.0-0` |
290
+ | `@deepseek-ai/cordis` | `^4.0.2` |
291
+ | `@deepseek-ai/schemastery` | `^3.18.2` |
292
+ | Node.js | `>=22.19.0` |
293
+
294
+ `0.1.2-alpha.2` is the minimum version for this API family: host settings use
295
+ `settings.installSection`, and the browser settings card reads and writes
296
+ through the plugin's own HTTP route (`/api/dsh-engram/settings`, see Route B
297
+ above). Host import and settings-registration smoke checks pass on
298
+ `0.1.2-alpha.2` and `0.1.3-alpha.2`; the full regression suite is validated
299
+ on `0.1.5-alpha.1` (real-machine GET/PUT/conflict/reset/persist-across-restart
300
+ all verified on `dsh 0.1.5-rc.1` with an isolated profile). The older
301
+ `0.1.0-rc.7` and `0.1.1` API graphs are outside this release's compatibility
302
+ range.
303
+
304
+ To install the DSH version used for validation:
305
+
306
+ ```sh
307
+ npm install --global @deepseek-ai/dsh@0.1.5-alpha.1
308
+ dsh --version
309
+ ```
310
+
139
311
  ## Install
140
312
 
141
313
  ```sh
@@ -317,8 +489,8 @@ npm run build:client
317
489
 
318
490
  | Tool | Purpose | Kind |
319
491
  |---|---|---|
320
- | `engram_store` | Explicitly store one memory (kind, tags, optional entity anchor, optional supersedes/contradicts memory ids) | write |
321
- | `engram_recall` | Deterministic keyword recall over workspace memories; optional `search_sessions` FTS over past sessions | read |
492
+ | `engram_store` | Explicitly store one memory (kind, tags, optional entity anchor, optional supersedes/contradicts ids, optional `source`/`conditions`) | write |
493
+ | `engram_recall` | Deterministic keyword recall over workspace memories; optional `search_sessions` FTS over past sessions; opt-in `scope=global`/`recallScope` cross-workspace recall with `[W:<ws>]` origin markers | read |
322
494
  | `engram_detail` | Full record of one memory id (provenance, tags, hits) | read |
323
495
  | `esr_task` | Create a task entity (draft → active) | write |
324
496
  | `esr_close` | Close a task via the evidence protocol (artifact + evaluation + memory_ref) | write |
@@ -542,7 +714,11 @@ ESR operating protocol (static, byte-identical every turn)
542
714
  [ENGRAM] workspace: symbolic-index · 2 memories · 1 task(s) active · 0 links
543
715
  [D] 06-18 Decided: use sqlite-vec for retrieval #a2331d87
544
716
  [T] 06-18 Retrieval upgrade — ACTIVE · gap: artifact, evaluation, memory_ref #tsk_8b26
545
- drill: engram_store (user asks to remember) | engram_recall <query> | engram_detail <id> | esr_task / esr_close / esr_link
717
+ drill: use [RECALL] below · engram_detail <id> (full record) · engram_recall <query> (more) · esr_task/esr_node/esr_link (work)
718
+
719
+ [RECALL] recall · 1 hit(s) · first msg: retrieval
720
+ - [D] 06-18 Decided: use sqlite-vec for retrieval upgrade #a2331d87 ×2
721
+ context: use above · engram_detail <id> · engram_recall <query>
546
722
 
547
723
  [ESR] tasks: 1 active / 1 stable
548
724
  - tsk_0d: Retrieval upgrade — ACTIVE · gap: artifact, evaluation, memory_ref
@@ -564,6 +740,14 @@ records via `engram_detail`. When a workspace has no tasks, `[ESR]` still render
564
740
  one line naming `esr_task`/`esr_close` so the mechanism stays visible to the
565
741
  model instead of vanishing.
566
742
 
743
+ `[RECALL]` (session-start auto recall, `autoRecallOnStart`) runs one deterministic
744
+ BM25 pass over the workspace keyed on the session's first user message and injects
745
+ the top `autoRecallLimit` hits, bounded by the `autoRecallMaxChars` character
746
+ budget; nothing renders on zero hits or an empty workspace. It is a *pointer* — the
747
+ model should treat it as "this is relevant; `engram_detail` for the full record" —
748
+ rather than full-text dumping. It is a pure read (never bumps `hits`), superseded
749
+ stale truth never occupies a slot, and it freezes per session with `[ENGRAM]`.
750
+
567
751
  ## Config
568
752
 
569
753
  Defaults are token-conscious; override any key via the profile patch
@@ -574,6 +758,10 @@ Defaults are token-conscious; override any key via the profile patch
574
758
  config:
575
759
  autoCapture: true # zero-LLM tool-result capture
576
760
  sessionSearch: true # engram_recall may also FTS past sessions
761
+ recallScope: workspace # recall scope: "workspace" (strict isolation, default) | "global" (opt-in cross-workspace recall with [W:<ws>] origin markers)
762
+ autoRecallOnStart: true # session-start auto recall (false = back to pure pull)
763
+ autoRecallLimit: 3 # [RECALL] max injected hits (few and precise)
764
+ autoRecallMaxChars: 700 # [RECALL] char budget
577
765
  autoCapturePerSession: 40
578
766
  indexMaxLines: 12 # [ENGRAM] line cap
579
767
  indexMaxChars: 700 # [ENGRAM] char cap (token budget)
@@ -616,7 +804,11 @@ dedup 1.0.
616
804
  **/api/dsh-engram/stats + the observability panel** is the real-session layer —
617
805
  it answers how the model actually uses the memory in production (ESR
618
806
  proactivity ratio, recall hit rate, detail conversion), while the eval
619
- answers how good the retrieval layer itself is.
807
+ answers how good the retrieval layer itself is. The stats read the
808
+ concatenated multi-frame `session.jsonl.zstd` logs with Node's built-in
809
+ `node:zlib` (frame scan + one reused decoder handle) — **no system `zstd` CLI
810
+ is required**, so the telemetry works out-of-the-box on Windows and other
811
+ hosts without an external codec.
620
812
 
621
813
  Repo layout: `lib/` (host half: store / capture / index-block / tools / api /
622
814
  settings), `client/` (browser half, TSX + `build.mjs`), `test/` (node:test).
package/README.zh.md CHANGED
@@ -28,6 +28,13 @@
28
28
  且查询含 **CJK 中文**(FTS5 中文分词整段只算一个 token)时,召回会对最近若干会话日志做
29
29
  有界的**子串扫描**(zstd 解压 + LRU 缓存,限文件数与字节),追加命中会话的确定性
30
30
  `# past sessions` 行。
31
+ - **会话启动自动召回(`autoRecallOnStart`,默认开)** — 纯拉取式设计有个被实证戳穿的盲区:
32
+ 召回工具只交模型自觉,而真实会话里模型几乎从不主动调 `engram_recall`(实测 19 个会话数千次
33
+ 工具调用只出现 ~5 次召回)。因此宿主在新会话**首次组装**时,用会话**首条用户消息**对工作区做
34
+ 一次确定性 BM25 召回,把命中前 ≤3 条直接注入 `[RECALL]` 块(默认 700 字符预算,"少而准",
35
+ agentmemory 候选①)——相关记忆不依赖模型想起来就已在上下文里。纯规则、零 LLM、
36
+ 纯读不 bump 命中;superseded 过期真相不占注入槽(仍可 `engram_detail` 重取);
37
+ 与 `[ENGRAM]` 一起按会话冻结保持前缀稳定。
31
38
  - **记忆间语义(supersede/contradict)** — `engram_store` 可选收 `supersedes` / `contradicts`
32
39
  记忆 id(同工作区校验)。被 supersede 的「过期真相」在召回里**降级到尾部**、并从 `[ENGRAM]`
33
40
  块中**剔除**(新陈述占行);被 contradicts 的记忆保留排序但标注 `· contradicted by <id>`。
@@ -83,12 +90,125 @@ MIT · node >= 22.19 · host 半边 + 浏览器半边合在一包
83
90
  dsh-engram 补的是对 token 纪律真正重要的三个空白:
84
91
 
85
92
  1. **写入路径没有模型** — 捕获是确定性的模式匹配。
86
- 2. **提示词里不灌原文** — 只注入有界的符号索引,检索按需进行("检索到 ≠ 注入")。
93
+ 2. **提示词里不灌全文** — 只注入有界的符号索引 + 会话启动时自动召回的最相关 ≤3 条(预算内),
94
+ 更深的检索按需进行("检索到≠灌全文")。
87
95
  3. **诚实的任务闭环** — 没有证据就不能宣布 STABLE。
88
96
 
89
97
  DSH 已经提供跨会话 FTS(`ctx.sessionQuery`)、存储(`ctx.storageDomain`)、提示词注入钩子和设置槽位;
90
98
  dsh-engram 只是这些能力之上的一层薄组合层,而非重新实现。
91
99
 
100
+ ## 安全模型
101
+
102
+ DSH 插件生态还很年轻、缺乏背书:没有官方目录、没有签名校验,且 harness 的读写权限三档**约束不了插件自身代码**。因此记忆插件面对的信任何题比工具更高——它趴在你的提示词前缀上,还替你在磁盘上写东西。dsh-engram 的模型,直说如下:
103
+
104
+ - **永远不联网。** 本插件没有出口 socket、没有遥测、没有更新探针。任何东西都不可能把会话带出本机。
105
+ - **无 shell、除一个存储文件外不碰文件系统。** 不执行命令、不碰任意路径。全部数据只落在一个 storage-domain 单元 `~/.dsh/storages/dsh_engram.json`(外加经 DSH 自身 `ctx.sessionQuery` 做的会话日志读取)。
106
+ - **密钥在落盘之前就被脱敏。** 每条写入路径——`engram_store`、自动捕获,以及本节的**导入/恢复**——都先把文本过一遍确定性的 `redactText` 规则引擎(API Key、JWT、`Bearer` token、私钥、`key=value` 密钥形态),*之后*才做去重哈希、字符上限与落盘。敏感文本永不落盘,召回时自然也不会有。
107
+ - **要做什么坏事,必须借你 harness 自己的权限。** 插件只通过你已信任的工具同款的 seam 向宿主"请求"做事;不扩沙箱策略、不拉高到 `danger-full-access`——你保持 profile 默认,engram 就只继承那些边界。
108
+ - **Web API 只读为主、loopback 栅栏。** `/api/dsh-engram` 下的 GUI 路由拒绝任何非回环调用方,除非你用 `trustedHosts` 显式放行某个主机名;即便放行,同源栅栏依然生效。
109
+ - **可核验。** `npm run dsh-engram -- doctor`(`scripts/dsh-engram.mjs doctor`)报告插件被配置去碰什么;整个 store 可检视、不透明的东西为零。如果对这一段有怀疑,要查的代码就是 `lib/redact.js`、`lib/store.js` 和本插件的 `cordis.patch.yml`。
110
+
111
+ 这**不是**说它是个气闸:如果你的 profile 给了 agent `danger-full-access` 或 shell,agent 可以用——engram 是记忆层而不是沙箱。上面这句话的意思是:*dsh-engram 自己*不新增任何攻击面。
112
+
113
+ ## 数据契约:导出 / 导入
114
+
115
+ 记忆不该当人质。四张表(memories / tasks / links / entities)可以用一个稳定、带版本号的机器可读格式整体倒出再恢复——重装、换机,或者(写一层薄适配器之后)搬到别的 harness / MCP 端点 / Claude Code skill,语料都跟得走。契约是带自描述头的纯 JSON:
116
+
117
+ ```http
118
+ GET /api/dsh-engram/export?workspace=/path/to/project # 单个工作区
119
+ GET /api/dsh-engram/export # 全部工作区
120
+ ```
121
+
122
+ ```jsonc
123
+ {
124
+ "meta": { "format": "dsh-engram/export", "version": 1, "exportedAt": 1724…, "workspace": "/path/to/project" },
125
+ "memories": [ /* 全部行,含归档——备份不丢溯源 */ ],
126
+ "tasks": [ /* draft/active/stable + 归档 */ ],
127
+ "links": [ /* 类型化边 */ ],
128
+ "entities": [ /* 图节点 */ ]
129
+ }
130
+ ```
131
+
132
+ 恢复默认幂等、破坏性操作有门禁:
133
+
134
+ ```http
135
+ POST /api/dsh-engram/import # body: { payload, mode, dryRun?, workspace?, confirm? }
136
+ ```
137
+
138
+ - **`mode: "merge"`**(默认)— 只写 `id` 尚不存在的行,备份可以随便重复套用而不会重复;每行保留自己的 `workspace`。
139
+ - **`mode: "replace"`** — 先把目标 `workspace` 的四张表清空,再只恢复属于它的行。破坏性操作,因此 body 里还要求 `confirm: "restore"`。
140
+ - **`dryRun: true`** — 只算出完全相同的执行计划(会写什么 / 跳过什么),不写任何一行。
141
+ - **导入遵守与 `storeMemory` 相同的不可变约定**:记忆文本落盘前先过密钥脱敏;会破坏契约的行(缺 id/workspace、空文本、超 `maxMemoryChars`、merge 时 id 已存在、超工作区记忆上限)会被跳过并写进响应报告,而不是中止整批。
142
+
143
+ 单工作区的恢复往返:
144
+
145
+ ```sh
146
+ curl -s "http://127.0.0.1:3080/api/dsh-engram/export?workspace=$PWD" -o engram-backup.json
147
+ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
148
+ -H "content-type: application/json" \
149
+ -d "{\"payload\": $(cat engram-backup.json), \"mode\": \"merge\"}"
150
+ ```
151
+
152
+ ## 兼容性
153
+
154
+ > **一句话结论**:所有**已真正发布**的版本(`0.2.0` … `0.3.6`)**只支持旧版
155
+ > DSH**(`0.1.0-rc.7` / `0.1.1` API 图,peers `^0.1.0-rc.7`)。DSH
156
+ > `0.1.2-alpha.2` 及更新版本与它们**不兼容**——settings/client API 族在该版本
157
+ > 断裂。新版 DSH 支持**自 `0.3.7` 起**提供——它是新 API 代际的第一个发布(见下文)。
158
+
159
+ | dsh-engram 发布版本 | 状态 | 支持的 DSH | 声明方式 |
160
+ | --- | --- | --- | --- |
161
+ | `0.2.0` … `0.3.6`(npm 全量 + GitHub v0.3.3–v0.3.6) | 已发布 | **仅旧版** —— `0.1.0-rc.7` / `0.1.0-rc.8` / `0.1.1-rc.1` / `0.1.1-rc.2` | peers `@deepseek-ai/dsh-*@^0.1.0-rc.7` |
162
+ | `0.3.7`(npm + GitHub v0.3.7) | 已发布 | **仅新版** —— `>=0.1.2-alpha.2 <0.2.0-0` | `engines.dsh` + peers 同范围 |
163
+
164
+ ### API 族断裂点:`0.1.2-alpha.2`
165
+
166
+ `0.1.2-alpha.2` 是新 API 族的第一个版本,也是第一个**让已发布插件失效**的版本:
167
+
168
+ - `@deepseek-ai/dsh-settings` **移除了** `settingsNamespace()` 与
169
+ `installSettingsSection()`(≤ `0.3.6` 的每个发布都直接 import 这两个符号),
170
+ 改为 `settings.installSection`——旧宿主端在 `0.1.2-alpha.2+` 上直接加载失败。
171
+ - Web 客户端注入集整体更换:`@deepseek-ai/dsh-client-runtime` 在新代际**已不存在**
172
+ (被 `dsh-api-remotes` + `dsh-client-locale` / `-conversation` / `-renderer` /
173
+ `-ui-settings-plugins` 取代),设置卡此前改走 `ctx.remote.settings`。
174
+ - 同一边界的伴随升级:`@deepseek-ai/cordis` `^4.0.1 → ^4.0.2`、
175
+ `@deepseek-ai/schemastery` `^3.18.1 → ^3.18.2`、`@deepseek-ai/dsh` 不再随包
176
+ 发布 `config/agent-presets`(改为 `dsh.configTrees` 机制)。
177
+
178
+ **web 设置卡已不依赖上面任何一项**:自 `0.3.7` 起,配置卡通过插件**自有**
179
+ HTTP 路由(`/api/dsh-engram/settings`,与记忆 viewer 同样的同源 fetch)读写
180
+ `dsh-engram` settings namespace,因此在 `0.1.2-alpha.2` 分界线两侧都是代际无关的。
181
+
182
+ 所以:跑 ≤ `0.3.6` 的已发布版本时请把 DSH 保持在 `0.1.1-rc.2` 或更旧;升级
183
+ DSH 到 `0.1.2-alpha.2` 之前,先升级插件到 `>=0.3.7`。
184
+
185
+ ### 当前发布版本 —— `0.3.7`
186
+
187
+ 当前发布版本声明适配 DSH `>=0.1.2-alpha.2 <0.2.0-0`,并以本地
188
+ `deepseek-harness` 的 `dsh-v0.1.5-alpha.1` 代码和 Web 运行时完成完整验证。
189
+
190
+ | 组件 | 适配版本 |
191
+ | --- | --- |
192
+ | DSH runtime / host / client 包族 | `>=0.1.2-alpha.2 <0.2.0-0` |
193
+ | `@deepseek-ai/cordis` | `^4.0.2` |
194
+ | `@deepseek-ai/schemastery` | `^3.18.2` |
195
+ | Node.js | `>=22.19.0` |
196
+
197
+ `0.1.2-alpha.2` 是这组 API 的最低版本:宿主设置注册使用
198
+ `settings.installSection`,浏览器端设置卡通过插件自有 HTTP 路由
199
+ (`/api/dsh-engram/settings`,见上文 Route B)读写。
200
+ `0.1.2-alpha.2` 和 `0.1.3-alpha.2` 已完成宿主导入与设置注册 smoke 验证;
201
+ `0.1.5-alpha.1` 已完成完整回归(并在 `dsh 0.1.5-rc.1` 隔离 profile 上真机验证
202
+ 设置 GET/PUT/冲突/复位/跨重启持久化全通)。旧的 `0.1.0-rc.7` 与 `0.1.1` API 图不在
203
+ 本发布版本的兼容范围内。
204
+
205
+ 如需按验证版本安装 DSH:
206
+
207
+ ```sh
208
+ npm install --global @deepseek-ai/dsh@0.1.5-alpha.1
209
+ dsh --version
210
+ ```
211
+
92
212
  ## 安装
93
213
 
94
214
  ```sh
@@ -224,8 +344,8 @@ npm run eval # 离线召回 + 结构基准(确定性语料,跑真实 store/
224
344
 
225
345
  | 工具 | 用途 | 类型 |
226
346
  |---|---|---|
227
- | `engram_store` | 显式存入一条记忆(kind、tags、可选实体锚点、可选 supersedes/contradicts 记忆 id) | 写 |
228
- | `engram_recall` | 工作区记忆的确定性关键词召回;可选 `search_sessions` 跨会话 FTS | 读 |
347
+ | `engram_store` | 显式存入一条记忆(kind、tags、可选实体锚点、可选 supersedes/contradicts id,可选 `source`/`conditions`) | 写 |
348
+ | `engram_recall` | 工作区记忆的确定性关键词召回;可选 `search_sessions` 跨会话 FTS;可选 `scope=global`/`recallScope` 跨工作区召回(带 `[W:<ws>]` 来源标记) | 读 |
229
349
  | `engram_detail` | 一条记忆 id 的完整记录(来源、标签、命中数) | 读 |
230
350
  | `esr_task` | 创建任务实体(draft → active) | 写 |
231
351
  | `esr_close` | 按证据协议关闭任务(artifact + evaluation + memory_ref) | 写 |
@@ -402,7 +522,11 @@ ESR 操作协议(静态,每轮逐字节相同)
402
522
  [ENGRAM] workspace: symbolic-index · 2 memories · 1 task(s) active · 0 links
403
523
  [D] 06-18 Decided: use sqlite-vec for retrieval #a2331d87
404
524
  [T] 06-18 Retrieval upgrade — ACTIVE · gap: artifact, evaluation, memory_ref #tsk_8b26
405
- drill: engram_store (user asks to remember) | engram_recall <query> | engram_detail <id> | esr_task / esr_close / esr_link
525
+ drill: use [RECALL] below · engram_detail <id> (full record) · engram_recall <query> (more) · esr_task/esr_node/esr_link (work)
526
+
527
+ [RECALL] recall · 1 hit(s) · first msg: retrieval
528
+ - [D] 06-18 Decided: use sqlite-vec for retrieval upgrade #a2331d87 ×2
529
+ context: use above · engram_detail <id> · engram_recall <query>
406
530
 
407
531
  [ESR] tasks: 1 active / 1 stable
408
532
  - tsk_0d: Retrieval upgrade — ACTIVE · gap: artifact, evaluation, memory_ref
@@ -420,6 +544,11 @@ promote: 2 pending todo(s) vs 1 ESR task(s) — esr_task(name="…") #suggest-pr
420
544
  `#` id 通过 `engram_detail` 取完整记录。工作区没有任务时,`[ESR]` 仍会渲染一行点名 `esr_task`/`esr_close`,
421
545
  让机制对模型保持可见,而不是整体消失。
422
546
 
547
+ `[RECALL]`(会话启动自动召回,`autoRecallOnStart`)按会话首条消息对工作区做确定性 BM25 召回,
548
+ 把命中前 `autoRecallLimit` 条注入,受 `autoRecallMaxChars` 字符预算约束;无命中或空工作区时不渲染。
549
+ 它是一条**提示**而不是全文灌入——模型该把它当成"这条相关,可能需要用 `engram_detail` 看细节"。
550
+ 纯读、不 bump 命中、superseded 过期真相不占槽位;随 `[ENGRAM]` 一起按会话冻结。
551
+
423
552
  ## 配置
424
553
 
425
554
  默认值以 token 为优先;可通过 profile 补丁(`~/.dsh/profiles/web/cordis.patch.yml`)或 Web 配置卡片覆盖任意键:
@@ -429,6 +558,10 @@ promote: 2 pending todo(s) vs 1 ESR task(s) — esr_task(name="…") #suggest-pr
429
558
  config:
430
559
  autoCapture: true # 零 LLM 工具结果捕获
431
560
  sessionSearch: true # engram_recall 也可对历史会话 FTS
561
+ recallScope: workspace # 召回范围:workspace(严格工作区隔离,默认)| global(可选跨工作区召回,带 [W:<ws>] 来源标记)
562
+ autoRecallOnStart: true # 会话启动自动召回:按首条消息注入 [RECALL] 块(false=回到纯拉取)
563
+ autoRecallLimit: 3 # [RECALL] 最多注入条数(少而准)
564
+ autoRecallMaxChars: 700 # [RECALL] 字符预算
432
565
  autoCapturePerSession: 40
433
566
  indexMaxLines: 12 # [ENGRAM] 行数上限
434
567
  indexMaxChars: 700 # [ENGRAM] 字符上限(token 预算)
@@ -0,0 +1,68 @@
1
+ # Release Notes 模板(每次发布必用)
2
+
3
+ 每个 GitHub Release 正文都应包含以下区块。**「DSH 版本支持」一节为必填**,
4
+ 其余按发布内容填写。版本支持信息从 `package.json` 读取,避免手写漂移:
5
+
6
+ ```sh
7
+ # 直接生成「DSH 版本支持」markdown 段(读 package.json 的 engines.dsh + peers)
8
+ npm run dsh-engram:release-notes
9
+ # 或
10
+ node scripts/gen-release-notes.mjs
11
+ ```
12
+
13
+ ---
14
+
15
+ ## 模板正文(复制后填空)
16
+
17
+ ```
18
+ ## dsh-engram v<版本号>
19
+
20
+ <一句话:自上一个版本以来的主题>
21
+
22
+ ### 功能
23
+ - ...
24
+
25
+ ### 修复
26
+ - ...
27
+
28
+ ### 其他
29
+ - ...
30
+
31
+ ## DSH 版本支持(必填)
32
+
33
+ - **支持的 DSH 范围**:`<复制自 package.json engines.dsh,如 >=0.1.2-alpha.2 <0.2.0-0>`
34
+ - **验证版本**:`<如 dsh-v0.1.5-alpha.1>`(本地 deepseek-harness checkout)
35
+ - **最后验证日期**:`<YYYY-MM-DD>`
36
+ - **安装方式已验证**:`<如 dsh plugin --profile web add dsh-engram>`
37
+ - **peer 声明**:`<复制自 package.json peerDependencies 中的 @deepseek-ai/dsh-* 范围>`
38
+
39
+ > ⚠️ 新旧分界:DSH `0.1.2-alpha.2` 起 settings/client API 族大改
40
+ > (`@deepseek-ai/dsh-settings` 移除 `settingsNamespace`/`installSettingsSection`,
41
+ > 改 `settings.installSection`;client 注入集从 `dsh-client-runtime` 换到
42
+ > `dsh-api-remotes` 等;cordis `^4.0.2`、schemastery `^3.18.2`)。
43
+ > 若本版本仍声明 peers `^0.1.0-rc.7`,说明它**只支持旧版 DSH**
44
+ > (≤ `0.1.1-rc.2`),正文必须写明「仅支持旧版 DSH」并用上面第一段替换当前示例。
45
+ ```
46
+
47
+ ---
48
+
49
+ ## 历史版本口径(补注用,legacy releases 说明)
50
+
51
+ 已发布版本 `0.2.0` … `0.3.6` 的 Release/README 如果缺失 DSH 兼容说明,统一补这
52
+ 一段:
53
+
54
+ ```
55
+ ## DSH 版本支持
56
+
57
+ - **支持的 DSH 范围**:仅旧版 —— `0.1.0-rc.7` / `0.1.0-rc.8` / `0.1.1-rc.1` / `0.1.1-rc.2`
58
+ - **peer 声明**:`@deepseek-ai/dsh-*@^0.1.0-rc.7`
59
+ - ⚠️ DSH `>=0.1.2-alpha.2` 与本版本**不兼容**(settings/client API 族在该版本断裂)。
60
+ 如需新版 DSH,请升级插件到 `master` 的下一个发布。
61
+ ```
62
+
63
+ ## dsh-market 兼容信息格式参考
64
+
65
+ - 包清单的版本兼容字段是 **semver 范围**:`package.json` / `dsh.plugin.json` 的
66
+ `engines.dsh`(如 `">=0.1.5-alpha.2"` 或 `"0.1.0-rc.6 || 0.1.2-rc.1"`)。
67
+ - 市场侧 README 公约(`## Compatibility` 段):
68
+ `DSH 版本` · `最后验证日期` · `安装方式已验证`。