dsh-auto-memory 0.1.0 → 0.3.0

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
@@ -1,130 +1,196 @@
1
1
  # dsh-auto-memory
2
2
 
3
+ [![CI](https://github.com/AskTheWay/dsh-auto-memory/actions/workflows/ci.yml/badge.svg)](https://github.com/AskTheWay/dsh-auto-memory/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/dsh-auto-memory)](https://www.npmjs.com/package/dsh-auto-memory)
5
+ [![npm downloads](https://img.shields.io/npm/dm/dsh-auto-memory)](https://www.npmjs.com/package/dsh-auto-memory)
6
+ [![License: MIT](https://img.shields.io/npm/l/dsh-auto-memory)](LICENSE)
7
+ [![Node](https://img.shields.io/node/v/dsh-auto-memory)](package.json)
8
+
3
9
  [English](README.md) | [中文](README.zh.md)
4
10
 
5
- **Claude Code-style auto-memory, as a native [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin.**
11
+ > ### Your dsh agent forgets everything you tell it. Every. Single. Session.
12
+ > **Fix it with one command.** Claude Code-style persistent memory for
13
+ > [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) — native,
14
+ > zero servers, zero embeddings, zero setup.
6
15
 
7
- A typed persistent-memory layer for dsh agents: memory files with frontmatter,
8
- a `MEMORY.md` index auto-injected into the system prompt, and four model-facing
9
- tools — lightweight, file-only, zero external services, no embeddings required.
16
+ ```sh
17
+ dsh plugin --profile demo add dsh-auto-memory
18
+ ```
10
19
 
11
- ## Why
20
+ Say *"Remember: I'm a Python backend engineer preparing for interviews"* today —
21
+ open a brand-new session tomorrow, ask *"what do you know about me?"*, and it
22
+ **remembers**.
12
23
 
13
- dsh itself has **no memory subsystem**. The official answer to memory is three
14
- *default-off* MCP bridge configs to third-party servers (Memorix, MCP Reference
15
- Memory, Engram) — which the official docs themselves qualify: not auto-injected
16
- (the model must choose to call a tool), no summarization, no conflict
17
- resolution, no forgetting.
24
+ ---
25
+
26
+ ## What's new in 0.3.0 (P2)
27
+
28
+ - **Pinned memories** (`pinned: true` on memory_write): pinned entries lead
29
+ the index, survive budget truncation, and are exempt from staleness
30
+ eviction — a trust anchor the user controls.
31
+ - **Eval-driven fix**: the injection budget now covers the *whole* section
32
+ (index + guidance); it used to overshoot by ~800 bytes. Caught by the new
33
+ deterministic evaluation layer on its first run.
34
+ - **Deterministic eval layer** ([evals/](evals/README.md)) in CI: injection
35
+ budget curves, eviction zero-misfire, link-expansion bounds, and a
36
+ signal-to-noise characterization — which pinned-priority truncation then
37
+ improved from **38% → ≥80% probe retention** under half-budget pressure.
38
+ Same budget, better memories.
39
+
40
+ ## What's new in 0.2.0 (P1)
41
+
42
+ - **Auto-consolidation** (`autoSummarize: true`): when a root session ends, a
43
+ background LLM pass extracts durable new facts from the session and files
44
+ them as memories — deduplicated, capped, fully silent on failure. Claude
45
+ Code doesn't do this automatically.
46
+ - **Forgetting & eviction**: every memory carries lifecycle metadata
47
+ (created/updated/reads); `memory_read` counts references; `staleAfterDays`
48
+ soft-hides zero-reference stale memories from the injected index (files
49
+ kept); `memory_prune` lists (dry-run) or deletes aged memories.
50
+ - **Recall expansion**: `memory_read` resolves `[[name]]` cross-links one
51
+ level and attaches linked summaries.
52
+ - `memory_delete_all` — guarded by `tools/pre-execute` **human approval**:
53
+ the model cannot self-confirm irreversible bulk deletes.
54
+ - Hardened by a second adversarial review (11 agents): single-lock `clear`
55
+ (no concurrent-write escape), conditional index rebuild on `touch`
56
+ (no O(N) amplification), session-start stale refresh, subagent capture
57
+ cleanup, abortable consolidation.
58
+
59
+ Tools: `memory_write` / `memory_read` / `memory_list` / `memory_delete` /
60
+ `memory_prune` / `memory_delete_all`.
61
+
62
+ ## Claude Code has this. dsh didn't. Now it does.
63
+
64
+ DeepSeek Harness is the hottest open agent harness on GitHub right now —
65
+ models, tools, sandboxes, everything is a plugin. But it ships with **no memory
66
+ subsystem at all**. The official answer is three *default-off* MCP configs to
67
+ third-party servers, which the official docs themselves qualify: not
68
+ auto-injected, no forgetting policy, substring-only search. Your agent has
69
+ amnesia by design.
18
70
 
19
71
  `dsh-auto-memory` closes that gap natively:
20
72
 
21
- | Capability | MCP bridge approach | dsh-auto-memory |
73
+ | | MCP bridge approach | **dsh-auto-memory** |
22
74
  |---|---|---|
23
- | Index auto-injected into every system prompt | ✗ | ✓ (zero footprint when empty) |
24
- | Typed memories (user / feedback / project / reference) | ✗ | ✓ |
25
- | Workspace-scoped + user-scoped layers, no cross-project leakage | ✗ | ✓ (scope flag enforced on every tool path) |
26
- | Crash/concurrency safety (cross-process file locks + orphan-lock recovery) | — | ✓ |
27
- | Forgetting / eviction policy (P1) | ✗ | planned |
28
- | Auto-consolidation on session end (P1) | ✗ | planned |
75
+ | Memories injected into **every** system prompt, automatically | ✗ | ✓ (zero tokens when empty) |
76
+ | Typed memories: user / feedback / project / reference | ✗ | ✓ |
77
+ | Workspace + user scope layers — no cross-project leakage | ✗ | ✓ |
78
+ | Crash & concurrency safety (cross-process locks, orphan recovery) | — | ✓ |
79
+ | External services / databases / embeddings required | ✓✓✓ | **none — just plain Markdown files** |
29
80
 
30
- ## Install
81
+ Memories are ordinary files under `$DSH_HOME/memory/` — hand-editable,
82
+ grep-able, git-friendly, yours.
31
83
 
32
- From a checkout (until the package is published to npm):
84
+ ## One minute to feel it
33
85
 
34
86
  ```sh
35
- npm install && npm run build
36
- dsh plugin --profile demo add /absolute/path/to/dsh-auto-memory
37
- dsh --profile demo # restart the profile to activate
87
+ node scripts/demo.mjs # no API key, no browser: watch write → index → inject → recall → forget
38
88
  ```
39
89
 
40
- Once published: `dsh plugin --profile demo add dsh-auto-memory`.
90
+ Or for real, in a chat: tell your agent things worth remembering. The model
91
+ calls `memory_write` / `memory_read` / `memory_list` / `memory_delete`,
92
+ following Claude Code's write discipline: **dedupe-and-update over piling up**,
93
+ absolute dates only, `[[name]]` cross-links, `feedback` memories carry
94
+ **Why:** / **How to apply:** lines.
41
95
 
42
- Requires `@deepseek-ai/dsh >= 0.1.5-rc.2` (Node `^22.19 || >=24`).
96
+ ## What the model actually sees
43
97
 
44
- ## Usage
98
+ Every request, one system-prompt section (order 4000) carries the index —
99
+ re-evaluated per step, byte-budgeted, and **gone entirely when the store is
100
+ empty**:
45
101
 
46
- Just tell the agent things worth remembering:
102
+ ```
103
+ # Persistent memory index
104
+ ## Project memories
105
+ - [压测过 PostgreSQL](id-generator-benchmark.md) — psycopg2 连接池有踩坑经验 (2026-09)
106
+ - [用户是 Python 后端工程师](user-prefers-python.md) — 正在准备面试; 偏好中文交流
107
+ ```
47
108
 
48
- > "Remember: I'm a Python backend engineer, preparing for interviews, prefer Chinese."
109
+ Chinese titles, YAML frontmatter, one file per memory — exactly the Claude
110
+ Code `MEMORY.md` model, rebuilt natively on dsh's prompt-assembly pipeline.
49
111
 
50
- The model calls `memory_write`. Next session, same workspace, the injected
51
- index is already there — ask *"what do you know about me?"* and it recalls.
112
+ ## Hardened before first release
52
113
 
53
- Tools: `memory_write` / `memory_read` / `memory_list` / `memory_delete`.
54
- Write rules follow Claude Code: dedupe-and-update over piling up, never store
55
- what the codebase or AGENTS.md already records, `feedback` memories carry
56
- **Why:** / **How to apply:** lines, relative dates become absolute, bodies
57
- cross-link with `[[name]]`.
114
+ This plugin survived a **12-agent adversarial code review** (680k tokens of
115
+ source-level scrutiny) before v0.1.0. Five production-grade traps were caught
116
+ and fixed — with regression tests — including two that would have been
117
+ field incidents:
58
118
 
59
- ## Where memories live
119
+ - **The NTFS silent destroyer**: a memory named `memory` collides with
120
+ `MEMORY.md` on case-insensitive filesystems — the write *succeeds* while
121
+ destroying the record. Blocked by a reserved-name guard.
122
+ - **The poisoned-prompt bomb**: three literal `{{{ }}}` braces in any memory
123
+ could crash *every* model request in the workspace — with no way for the
124
+ model to self-recover. Neutralized by a converging sanitizer.
60
125
 
61
- ```
62
- $DSH_HOME/memory/ # defaults to ~/.dsh/memory
63
- ├── --<workspace-slug>--/ # project layer (slug derived from session cwd)
64
- │ ├── MEMORY.md # the index (the only part injected)
65
- │ └── one-file-per-memory.md # frontmatter + body
66
- └── _user/ # user layer (shared across all workspaces)
67
- ```
126
+ Plus: orphaned-lock self-healing (Ctrl+C can't brick your memory store),
127
+ symlink-read protection, malformed-file tolerance, stable index ordering to
128
+ protect KV-prefix caches, and a strict no-custom-session-events policy (they
129
+ make dsh sessions refuse to resume).
68
130
 
69
- Each memory is plain Markdown — hand-editable, grep-able, git-friendly:
131
+ ## Measured, not just claimed
70
132
 
71
- ```markdown
72
- ---
73
- name: user-prefers-python
74
- title: Backend engineer, prefers Python
75
- description: Preparing for interviews; prefers Chinese
76
- type: user
77
- ---
133
+ A deterministic evaluation layer ([evals/](evals/README.md)) runs in CI —
134
+ no LLM, fully reproducible:
78
135
 
79
- Facts… cross-link with [[other-memory]].
80
- ```
136
+ - **Injection budget holds at any scale**: 20/50/100/200 memories → the
137
+ injected section stays ≤ 4 KB (4065/4048/4018/3940 bytes measured), with
138
+ truncation markers; empty store injects **0 bytes**.
139
+ - **Eviction never misfires**: four-class mixed scenario — only
140
+ stale-zero-read memories get hidden; zero files lost; one read revives.
141
+ - **Known limitation, pinned as baseline**: budget truncation is currently
142
+ positional (index order), not relevance-ranked — probe retention under
143
+ half-budget pressure drops to ~38%→10% as N grows. **Pinning fixes it for
144
+ what matters**: pinned probes retain **≥80%** at the same budget (0.3.0);
145
+ full relevance ranking remains on the roadmap.
146
+
147
+ This evaluation layer already caught a real bug: the byte budget used to
148
+ exclude the policy text, overshooting by ~800 bytes (fixed, regression-tested).
81
149
 
82
- ## How it works
150
+ **78 tests (incl. a deterministic eval layer). 0 runtime deps beyond `yaml`. 15 kB installed.**
83
151
 
84
- - **Write path**: tool `execute` → name normalized to `[a-z0-9-]` (reserved
85
- names rejected) → cross-process file lock (official `dsh-atomic-write`) →
86
- atomic file write → full index rebuild. Orphaned locks from crashes are
87
- self-healed (stale-pid detection).
88
- - **Inject path**: one dynamic system-prompt section (order 4000) re-evaluated
89
- on every step assembly; reads the index synchronously, enforces a byte
90
- budget, neutralizes literal `{{` (0.1.5 has no `interpolate` switch). Empty
91
- store → empty section → zero tokens.
92
- - **Audit**: no custom session events (third-party event types make dsh
93
- sessions fail to resume); everything flows through standard `tool/call` /
94
- `tool/result`.
152
+ ## Install
153
+
154
+ ```sh
155
+ dsh plugin --profile demo add dsh-auto-memory # from npm (prebuilt)
156
+ dsh --profile demo # restart the profile
157
+ ```
158
+
159
+ From source: `npm install && npm run build && dsh plugin --profile demo add /abs/path`.
160
+ Requires `@deepseek-ai/dsh >= 0.1.5-rc.2` (Node `^22.19 || >=24`).
95
161
 
96
162
  ## Configuration
97
163
 
98
- Override via your profile's `cordis.patch.yml` (config replaces wholesale —
99
- restate every key):
164
+ Override in your profile's `cordis.patch.yml` (config replaces wholesale):
100
165
 
101
166
  ```yaml
102
167
  - id: auto-memory
103
168
  config:
104
- maxBytes: 4096 # injection budget (index + policy text)
169
+ maxBytes: 4096 # injection budget
105
170
  memoryDir: D:/memories # default: $DSH_HOME/memory
106
171
  enableUserScope: true # false: user layer off on every path
107
- autoSummarize: false # P1 placeholder
108
172
  ```
109
173
 
110
- ## Design & research
111
-
112
- - [docs/design.md](docs/design.md) — design decisions and trade-offs
113
- - [docs/api-reports.md](docs/api-reports.md) — dsh source-level API research
114
- backing every implementation choice (including the traps this plugin avoids)
174
+ ## How it works (60 seconds)
115
175
 
116
- ## Roadmap
176
+ - **Write**: tool `execute` → name normalized to `[a-z0-9-]` (reserved names
177
+ rejected) → cross-process file lock (official `dsh-atomic-write`) → atomic
178
+ write → full index rebuild inside the lock.
179
+ - **Inject**: one dynamic section re-evaluated on every step assembly; reads
180
+ the index synchronously, enforces the byte budget, neutralizes `{{`.
181
+ Tool writes take effect on the **very next request** — no restart, ever.
182
+ - **Audit**: no custom session events (third-party types make dsh refuse to
183
+ resume); everything flows through standard `tool/call` / `tool/result`.
117
184
 
118
- - [x] P0: typed store + four tools + index injection + scoped layers + crash safety
119
- - [ ] P1: auto-consolidation on session end, forgetting/eviction, recall expansion
120
- - [ ] P2: Web UI memory cards, token-cost / recall-quality benchmarks
185
+ Deep dives: [design decisions](docs/design.md) ·
186
+ [dsh source-level research](docs/api-reports.md) ·
187
+ [postmortem: shipping a PR to awesome-dsh-plugin](docs/postmortem-pr-5696.md)
121
188
 
122
- ## Verification
189
+ ## Roadmap
123
190
 
124
- ```sh
125
- npx vitest run # 40 tests: store logic, braces regression, real Cordis stack
126
- node scripts/demo.mjs # key-less demo: write → index → injection → dedupe → empty
127
- ```
191
+ - [x] P0 — typed store, four tools, prompt injection, scoped layers, crash safety
192
+ - [x] P1 — auto-consolidation on session end, forgetting & eviction, recall expansion, human-gated bulk delete
193
+ - [ ] P2 — Web UI memory cards, token-cost / recall-quality benchmarks
128
194
 
129
195
  ## License
130
196
 
package/README.zh.md CHANGED
@@ -1,121 +1,170 @@
1
1
  # dsh-auto-memory
2
2
 
3
+ [![CI](https://github.com/AskTheWay/dsh-auto-memory/actions/workflows/ci.yml/badge.svg)](https://github.com/AskTheWay/dsh-auto-memory/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/dsh-auto-memory)](https://www.npmjs.com/package/dsh-auto-memory)
5
+ [![npm downloads](https://img.shields.io/npm/dm/dsh-auto-memory)](https://www.npmjs.com/package/dsh-auto-memory)
6
+ [![License: MIT](https://img.shields.io/npm/l/dsh-auto-memory)](LICENSE)
7
+ [![Node](https://img.shields.io/node/v/dsh-auto-memory)](package.json)
8
+
3
9
  [English](README.md) | [中文](README.zh.md)
4
10
 
5
- **把 Claude Code 的 auto-memory 机制移植为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的原生插件。**
11
+ > ### 你的 dsh 智能体把你说过的每件事都忘掉。每一次。每一个会话。
12
+ > **一条命令修复。** 把 Claude Code 式持久记忆带给
13
+ > [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)——原生实现,
14
+ > 零服务器、零 embedding、零配置。
15
+
16
+ ```sh
17
+ dsh plugin --profile demo add dsh-auto-memory
18
+ ```
19
+
20
+ 今天对它说 *"记住:我是准备面试的 Python 后端工程师"*——
21
+ 明天开一个全新会话,问 *"你对我有什么了解?"*,它**记得**。
22
+
23
+ ---
24
+
25
+ ## 0.3.0 新增(P2)
26
+
27
+ - **置顶记忆**(memory_write 传 `pinned: true`):置顶条目排在索引最前、
28
+ 在预算截断中优先保留、豁免软淘汰——用户可控的信任锚点。
29
+ - **评测驱动修复**:注入预算语义改为覆盖整段(索引+指导文本);旧实现会
30
+ 超支 ~800 字节——由新评测层首跑即抓出。
31
+ - **确定性评测层**([evals/](evals/README.md))进 CI:注入预算曲线、淘汰
32
+ 零误杀、链接展开边界、信噪比 characterization——pinned 优先截断把
33
+ 半量预算下的探针保留率从 **38% 提升到 ≥80%**。同样的预算,更对的记忆。
6
34
 
7
- 为 dsh 智能体提供类型化持久记忆层:带 frontmatter 的记忆文件、自动注入系统提示词的
8
- `MEMORY.md` 索引、四个模型工具——轻量、纯文件、无外部服务、无 embedding 依赖。
35
+ ## 0.2.0 新增(P1)
9
36
 
10
- ## 为什么
37
+ - **自动固化**(`autoSummarize: true`):根会话结束时,后台 LLM 从会话中提取
38
+ 值得长期保留的新事实并写入记忆——查重、限量、失败静默。Claude Code 没有全自动。
39
+ - **遗忘与淘汰**:每条记忆携带生命周期元数据(created/updated/reads);
40
+ `memory_read` 累计引用;`staleAfterDays` 把零引用超龄记忆从注入索引软隐藏
41
+ (文件保留);`memory_prune` 列出(dry-run)或删除高龄记忆。
42
+ - **召回展开**:`memory_read` 解析一层 `[[name]]` 交叉链接并附摘要。
43
+ - `memory_delete_all`——由 `tools/pre-execute` **人工审批**把关:
44
+ 模型无法自证通过不可逆批量删除。
45
+ - 经第二轮对抗审查(11 个智能体)加固:clear 单锁窗口(并发写不逃逸)、
46
+ touch 条件重建(消除 O(N) 放大)、会话启动刷新软淘汰、子代理缓冲清理、
47
+ 固化可中止。
11
48
 
12
- dsh 本体**没有记忆子系统**。官方对记忆的全部支持是三份*默认关闭*的 MCP 外挂配置
13
- (Memorix、MCP Reference Memory、Engram),官方文档自己承认其局限:不自动注入
14
- (模型必须主动调工具)、无自动摘要、无冲突消解、无遗忘策略。
49
+ 工具:`memory_write` / `memory_read` / `memory_list` / `memory_delete` /
50
+ `memory_prune` / `memory_delete_all`。
15
51
 
16
- `dsh-auto-memory` 用原生实现补上这一层:
52
+ ## Claude Code 有的东西,dsh 一直没有。现在有了。
17
53
 
18
- | 能力 | MCP 外挂方案 | dsh-auto-memory |
54
+ DeepSeek Harness 是当下 GitHub 最火的开源智能体框架——模型、工具、沙箱,万物皆插件。
55
+ 但它**根本没有记忆子系统**。官方的答案是三份*默认关闭*的 MCP 外挂配置,而且官方文档
56
+ 自己承认局限:不自动注入、无遗忘策略、只做子串搜索。你的智能体是**设计层面的失忆症**。
57
+
58
+ `dsh-auto-memory` 用原生实现补上这个缺口:
59
+
60
+ | | MCP 外挂方案 | **dsh-auto-memory** |
19
61
  |---|---|---|
20
- | 索引自动注入每次系统提示词 | ✗ | ✓(无记忆时零占用) |
21
- | 类型化记忆(user / feedback / project / reference) | ✗ | ✓ |
22
- | 项目级 + 用户级分层,跨项目不串扰 | ✗ | ✓(作用域开关贯通全部工具路径) |
23
- | 崩溃/并发安全(跨进程文件锁 + 孤儿锁自愈) | — | ✓ |
24
- | 遗忘/淘汰策略(P1) | ✗ | 计划中 |
25
- | 会话结束自动固化(P1) | ✗ | 计划中 |
62
+ | 记忆自动注入**每一次**系统提示词 | ✗ | ✓(无记忆时零 token 占用) |
63
+ | 类型化记忆:user / feedback / project / reference | ✗ | ✓ |
64
+ | 工作区 + 用户双层作用域——跨项目不串扰 | ✗ | ✓ |
65
+ | 崩溃与并发安全(跨进程锁、孤儿锁自愈) | — | ✓ |
66
+ | 需要外部服务 / 数据库 / embedding | ✓✓✓ | **全都不用——纯 Markdown 文件** |
26
67
 
27
- ## 安装
68
+ 记忆是 `$DSH_HOME/memory/` 下的普通文件——可手改、可 grep、对 git 友好,完全属于你。
28
69
 
29
- 本地检出安装(npm 发布前):
70
+ ## 一分钟感受它
30
71
 
31
72
  ```sh
32
- npm install && npm run build
33
- dsh plugin --profile demo add /绝对路径/dsh-auto-memory
34
- dsh --profile demo # 重启 profile 生效
73
+ node scripts/demo.mjs # 不要 API key、不开浏览器:看 写入 → 索引 → 注入 → 召回 → 遗忘
35
74
  ```
36
75
 
37
- 发布后:`dsh plugin --profile demo add dsh-auto-memory`。
76
+ 或者在真实对话里:告诉智能体值得记住的事。模型调用
77
+ `memory_write` / `memory_read` / `memory_list` / `memory_delete`,
78
+ 遵循 Claude Code 的写入纪律:**查重更新而非堆积**、只用绝对日期、
79
+ `[[name]]` 交叉链接、`feedback` 记忆附 **Why:** / **How to apply:** 行。
38
80
 
39
- 要求 `@deepseek-ai/dsh >= 0.1.5-rc.2`(Node `^22.19 || >=24`)。
81
+ ## 模型实际看到什么
40
82
 
41
- ## 使用
83
+ 每个请求,一个系统提示词段(order 4000)携带索引——每步重新求值、字节预算控制、
84
+ 存储为空时**整段消失**:
42
85
 
43
- 直接告诉智能体值得记住的事:
86
+ ```
87
+ # Persistent memory index
88
+ ## Project memories
89
+ - [压测过 PostgreSQL](id-generator-benchmark.md) — psycopg2 连接池有踩坑经验 (2026-09)
90
+ - [用户是 Python 后端工程师](user-prefers-python.md) — 正在准备面试; 偏好中文交流
91
+ ```
44
92
 
45
- > "记住:我是 Python 后端工程师,正在准备面试,偏好中文交流。"
93
+ 中文标题、YAML frontmatter、一条记忆一个文件——完整的 Claude Code `MEMORY.md`
94
+ 模型,在 dsh 的提示词组装管线上原生重建。
46
95
 
47
- 模型会调 `memory_write`。同一工作区的下一次会话,注入的索引已经在场——
48
- 问 *"你对我有什么了解?"* 它就能召回。
96
+ ## 首发之前就被锤炼过
49
97
 
50
- 工具:`memory_write` / `memory_read` / `memory_list` / `memory_delete`。
51
- 写入规则对齐 Claude Code:查重更新而非堆积、不存代码库/AGENTS.md 已记录的内容、
52
- `feedback` 类型带 **Why:** / **How to apply:** 行、相对日期转绝对、正文 `[[name]]` 交叉链接。
98
+ 这个插件在 v0.1.0 发布前经受了一次 **12 个智能体的对抗性代码审查**
99
+ (68 万 token 的源码级拷问)。五个生产级陷阱被抓出并修复——全部带回归测试——
100
+ 其中两个若上线就是事故:
53
101
 
54
- ## 记忆保存在哪
102
+ - **NTFS 静默毁数据**:名为 `memory` 的记忆会在大小写不敏感文件系统上撞上
103
+ `MEMORY.md`——写入*报告成功*,实际销毁记录。保留字守卫拦截。
104
+ - **毒提示炸弹**:任何记忆里三个字面 `{{{ }}}` 花括号,就能炸掉工作区的
105
+ *每一个*模型请求——且模型无法自救。收敛式消毒器中和。
55
106
 
56
- ```
57
- $DSH_HOME/memory/ # 默认 ~/.dsh/memory
58
- ├── --<工作区slug>--/ # 项目层(slug 由会话 cwd 派生)
59
- │ ├── MEMORY.md # 索引(唯一被注入的部分)
60
- │ └── 每条记忆一个.md # frontmatter + 正文
61
- └── _user/ # 用户层(所有工作区共享)
62
- ```
107
+ 还有:孤儿锁自愈(Ctrl+C 砸不坏你的记忆库)、symlink 读取防护、坏文件容错、
108
+ 稳定的索引排序(保住 KV 前缀缓存)、严格不写自定义会话事件(那会让 dsh 会话
109
+ 拒绝 resume)。
63
110
 
64
- 每条记忆都是纯 Markdown——可手改、可 grep、对 git 友好:
111
+ ## 用数字说话,不止口头宣称
65
112
 
66
- ```markdown
67
- ---
68
- name: user-prefers-python
69
- title: 后端工程师,偏好 Python
70
- description: 正在准备面试;偏好中文交流
71
- type: user
72
- ---
113
+ 确定性评测层([evals/](evals/README.md))随 CI 运行——无 LLM、结果完全可复现:
73
114
 
74
- 事实正文……用 [[其他记忆名]] 交叉链接。
75
- ```
115
+ - **注入预算任意规模下成立**:20/50/100/200 条记忆,注入段恒 ≤ 4 KB
116
+ (实测 4065/4048/4018/3940 字节)且带截断标记;空库注入 **0 字节**。
117
+ - **淘汰零误杀**:四类混合场景——只有"超龄零引用"被隐藏,文件零丢失,
118
+ 读一次即复活。
119
+ - **已知局限(有意钉板)**:预算截断目前按索引行序(位置式)而非相关性排序——
120
+ 半量预算压力下探针保留率随规模降至 ~38%→10%。**置顶可解关键项**:同预算下
121
+ pinned 探针保留 **≥80%**(0.3.0);完整相关性排序仍在路线图。
76
122
 
77
- ## 工作原理
123
+ 评测层已抓到过真实 bug:字节预算曾遗漏指导文本、整段超支 ~800 字节
124
+ (已修复并带回归)。
78
125
 
79
- - **写入路径**:工具 `execute` → name 归一化为 `[a-z0-9-]`(保留字拒绝)→
80
- 跨进程文件锁(官方 `dsh-atomic-write`)→ 原子写文件 → 全量重建索引。
81
- 崩溃留下的孤儿锁自动自愈(死 pid 检测)。
82
- - **注入路径**:单个动态系统提示词段(order 4000),每个 step 组装时重新求值;
83
- 同步读索引、字节预算截断、中和字面 `{{`(0.1.5 无 `interpolate` 开关)。
84
- 无记忆 → 空段 → 零 token。
85
- - **审计**:不写自定义会话事件(第三方事件类型会导致 dsh 会话 resume 拒读);
86
- 一切走标准 `tool/call` / `tool/result`。
126
+ **78 项测试(含确定性评测层)。运行时依赖仅 `yaml`。安装体积 15 kB。**
127
+
128
+ ## 安装
129
+
130
+ ```sh
131
+ dsh plugin --profile demo add dsh-auto-memory # npm 直装(预构建)
132
+ dsh --profile demo # 重启 profile 生效
133
+ ```
134
+
135
+ 源码安装:`npm install && npm run build && dsh plugin --profile demo add /绝对路径`。
136
+ 要求 `@deepseek-ai/dsh >= 0.1.5-rc.2`(Node `^22.19 || >=24`)。
87
137
 
88
138
  ## 配置
89
139
 
90
- 在 profile 的 `cordis.patch.yml` 覆盖(config 整表替换——须重述全部键):
140
+ 在 profile 的 `cordis.patch.yml` 覆盖(config 整表替换):
91
141
 
92
142
  ```yaml
93
143
  - id: auto-memory
94
144
  config:
95
- maxBytes: 4096 # 注入预算(索引 + 指导文本)
145
+ maxBytes: 4096 # 注入预算
96
146
  memoryDir: D:/memories # 默认: $DSH_HOME/memory
97
147
  enableUserScope: true # false: 用户层在所有路径禁用
98
- autoSummarize: false # P1 占位
99
148
  ```
100
149
 
101
- ## 设计与调研
150
+ ## 工作原理(60 秒)
102
151
 
103
- - [docs/design.md](docs/design.md) — 设计决策与取舍
104
- - [docs/api-reports.md](docs/api-reports.md) — 支撑每个实现选择的 dsh 源码级调研
105
- (含本插件规避的陷阱清单)
106
-
107
- ## 路线图
152
+ - **写入**:工具 `execute` → name 归一化为 `[a-z0-9-]`(保留字拒绝)→
153
+ 跨进程文件锁(官方 `dsh-atomic-write`)→ 原子写 → 锁内全量重建索引。
154
+ - **注入**:单个动态段,每步组装重新求值;同步读索引、执行字节预算、中和 `{{`。
155
+ 工具写入在**下一个请求**即生效——永远不需要重启。
156
+ - **审计**:不写自定义会话事件(第三方事件类型会让 dsh 拒绝 resume);
157
+ 一切走标准 `tool/call` / `tool/result`。
108
158
 
109
- - [x] P0:类型化存储 + 四工具 + 索引注入 + 分层作用域 + 崩溃安全
110
- - [ ] P1:会话结束自动固化、遗忘/淘汰、召回展开
111
- - [ ] P2:Web UI 记忆卡片、token 成本/召回质量评测
159
+ 深度内容:[设计决策](docs/design.md) ·
160
+ [dsh 源码级调研](docs/api-reports.md) ·
161
+ [复盘:向 awesome-dsh-plugin 提 PR](docs/postmortem-pr-5696.md)
112
162
 
113
- ## 验证
163
+ ## 路线图
114
164
 
115
- ```sh
116
- npx vitest run # 40 项测试:存储逻辑、花括号回归、真实 Cordis 栈
117
- node scripts/demo.mjs # 无 key 演示:写入 → 索引 → 注入 → 查重 → 删空
118
- ```
165
+ - [x] P0——类型化存储、四工具、提示词注入、分层作用域、崩溃安全
166
+ - [x] P1——会话结束自动固化、遗忘与淘汰、召回展开、人工审批的批量删除
167
+ - [ ] P2——Web UI 记忆卡片、token 成本/召回质量评测
119
168
 
120
169
  ## 许可
121
170
 
package/lib/index.d.ts CHANGED
@@ -11,8 +11,14 @@ interface Config {
11
11
  memoryDir?: string;
12
12
  /** 是否启用用户级作用域(_user 目录注入所有会话)。 */
13
13
  enableUserScope: boolean;
14
- /** P1 预留:会话结束自动总结固化。当前仅占位,不影响行为。 */
14
+ /** P1:会话结束自动总结固化(需要可用模型路由;失败静默不影响会话)。 */
15
15
  autoSummarize: boolean;
16
+ /** 单次固化最多写入的新记忆数。 */
17
+ autoSummarizeMaxMemories: number;
18
+ /** 固化模型调用的输出 token 上限。 */
19
+ autoSummarizeMaxTokens: number;
20
+ /** P1:软淘汰阈值(天)——超过且从未被读取的记忆在索引重建时从注入索引隐藏(文件保留)。0 禁用。 */
21
+ staleAfterDays: number;
16
22
  }
17
23
  declare const Config: z<Config>;
18
24
  declare function apply(ctx: Context, config: Config): void;