memory-eternal 0.23.0 → 0.25.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
3
  "name": "memory-eternal",
4
- "version": "0.23.0",
4
+ "version": "0.25.0",
5
5
  "description": "记忆核心(Memory Eternal):对话结束后自动沉淀知识卡到本地记忆库(~/.dsh/memory-vault),支持检索 / 召回 / 审核中心。",
6
6
  "author": {
7
7
  "name": "EternalNight996",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "记忆核心(Memory Eternal):对话结束后自动沉淀知识卡到本地记忆库(~/.dsh/memory-vault),支持检索 / 召回 / 审核中心。",
5
5
  "author": {
6
6
  "name": "EternalNight996",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "记忆核心(Memory Eternal):对话结束后自动沉淀知识卡到本地记忆库(~/.dsh/memory-vault),支持检索 / 召回 / 审核中心。",
5
5
  "author": {
6
6
  "name": "EternalNight996",
package/README.md CHANGED
@@ -1,8 +1,14 @@
1
1
  # 🧠 memory-eternal — a second brain for your AI
2
2
 
3
+ <p align="center">
4
+ <img src="https://raw.githubusercontent.com/EternalNight996/memory-eternal/main/assets/screen/cover-zh.png" width="900" alt="记忆核心 memory-eternal:给 AI 一个不会忘、可审核、可量化的长期记忆" />
5
+ </p>
6
+
7
+ **记忆核心(memory-eternal)** —— 给 AI 一个不会忘、可审核、可量化的长期记忆。本地优先 · 审核闸门 · 记忆账本 · 一个库接入 DSH / Claude Code / Codex / Cursor 与任意 MCP 客户端。
8
+
3
9
  [![GitHub stars](https://img.shields.io/github/stars/EternalNight996/memory-eternal?style=flat)](https://github.com/EternalNight996/memory-eternal/stargazers)
4
10
  [![npm](https://img.shields.io/npm/v/memory-eternal)](https://www.npmjs.com/package/memory-eternal)
5
- [![release](https://img.shields.io/badge/release-v0.23.0-FF7A45)](https://github.com/EternalNight996/memory-eternal/releases)
11
+ [![release](https://img.shields.io/badge/release-v0.25.0-FF7A45)](https://github.com/EternalNight996/memory-eternal/releases)
6
12
  [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
7
13
 
8
14
  **English (default)** · [简体中文](README.zh-CN.md)
@@ -54,6 +60,75 @@ dsh-memory open # http://127.0.0.1:7999
54
60
  npx -y -p memory-eternal dsh-memory tui # live queue in the terminal
55
61
  ```
56
62
 
63
+ ## 🧬 How memory actually flows
64
+
65
+ One SQLite vault, one write gate, two read paths. Nothing enters recall without passing the gate.
66
+
67
+ ```mermaid
68
+ flowchart TD
69
+ subgraph S1["① Input"]
70
+ A1["Conversation + tool events<br/>captured when a turn ends"]
71
+ A2["Installed skills<br/>scanned from the host"]
72
+ A3["News follows<br/>RSS · GitHub · HN · arXiv · DSH plugins"]
73
+ A4["Manual cards / imports"]
74
+ end
75
+ subgraph S2["② Distill — the only LLM step"]
76
+ B1["LLM distills the session<br/>on failure: raw card, nothing lost"]
77
+ B2["Dedup: lexical Jaccard<br/>optional LLM merge decision"]
78
+ B3["Kind classification"]
79
+ end
80
+ subgraph S3["③ Review gate — human only"]
81
+ C1[("Quarantine<br/>pending / rejected")]
82
+ C2{"approve / reject"}
83
+ C3[("Main store<br/>approved only")]
84
+ end
85
+ subgraph S4["④ Storage"]
86
+ D1[("SQLite: cards + FTS5 index")]
87
+ D2["Markdown mirror<br/>git-able"]
88
+ D3["audit_log + token ledger"]
89
+ end
90
+ subgraph S5["⑤ Recall — every session"]
91
+ E1["Core memory → system prompt"]
92
+ E2["memory_recall → FTS5 + BM25"]
93
+ E3["memory_revise → pending revision"]
94
+ end
95
+ A1 --> B1 --> B2 --> B3 --> C1
96
+ A2 --> B2
97
+ A3 --> C1
98
+ A4 --> B2
99
+ C1 --> C2
100
+ C2 -->|approve| C3
101
+ C2 -->|reject| C1
102
+ C3 --> D1
103
+ D1 --> D2
104
+ C3 --> D3
105
+ C3 --> E1
106
+ C3 --> E2
107
+ E2 -->|hits + chars| D3
108
+ E3 --> C1
109
+ ```
110
+
111
+ The diagram is only true because three invariants are enforced in code, not by convention:
112
+
113
+ | Invariant | Enforced by |
114
+ |---|---|
115
+ | The main store **only** ever contains approved cards | Two physical tables; every read path queries the main one |
116
+ | An agent can never approve its own memory | Agent writes land in quarantine; approve/reject is a human action in the UI / TUI / CLI |
117
+ | Recall costs **zero model calls** | FTS5 + BM25; the LLM runs only while distilling |
118
+
119
+ ## 🔌 How agents talk to the memory
120
+
121
+ | Channel | Direction | When | Gate | Cost |
122
+ |---|---|---|---|---|
123
+ | `memory_recall` | agent → memory | on demand | approved only | **0 model calls** (p50 2.3 ms) |
124
+ | Core memory | memory → agent | every session, automatic | approved only | ~0.2k chars |
125
+ | Session capture / `memory_write` | conversation → memory | turn end | **queued for review** | 1 LLM call |
126
+ | `memory_revise` | agent → memory | on demand | **queued as a revision** | 0 |
127
+ | Review (Web UI · TUI · CLI) | human → memory | manual | — | 0 |
128
+ | Hooks (Claude Code / Codex / Cursor) | host → memory | session end | **queued** | 1 LLM call |
129
+ | MCP server | any MCP client | on demand | same gate | same |
130
+ | News follows | web → memory | interval / 24h | isolated from cards | network only |
131
+
57
132
  ## 🧾 Does it actually save tokens?
58
133
 
59
134
  Most memory products <em>say</em> they save tokens. We think you should check. The plugin ships a built-in **memory ledger** (Runtime status → Memory ledger) that records:
@@ -77,6 +152,42 @@ net benefit ≈ avoided context cost − (injected characters + distillation cal
77
152
 
78
153
  > Illustrative numbers, not a benchmark — measure your own with the ledger. If recall usefulness stays below ~60%, tune it down (fewer results, shorter summaries) or turn memory off.
79
154
 
155
+ ## 📊 How it compares — measured on a real vault
156
+
157
+ Snapshot **2026-11-07**. Our figures are measured on a real **2,321-card vault** on Windows (not a toy corpus); competitor figures come from their public README / npm / GitHub on the same date. `—` means *not advertised or not verifiable*, not "absent".
158
+
159
+ | Capability | **memory-eternal v0.24.0** | 灵枢 dsh-memory v0.9.23 | SAG-Wiki v0.2.7 | CLAUDE.md / AGENTS.md |
160
+ |---|---|---|---|---|
161
+ | Storage | SQLite + Markdown mirror | Markdown cognitive graph | SQLite FTS5 over your files | flat file(s) |
162
+ | Write gate | **human review queue** (3 stores) | deterministic rules | none — index is truth | none |
163
+ | Immutable audit log | ✅ enforced at the SQLite layer | ✅ claimed | — | — |
164
+ | Retrieval | FTS5 + **BM25/IDF**, column weights | rule-based graph walk | BM25 → JEV (LLM judge) | whole file injected |
165
+ | Recall latency | **p50 2.33 ms · p95 6.18 ms** | — | — | grows with file size |
166
+ | Recall model calls | **0** | 0 | 1–2 per query | 0 |
167
+ | Token ledger (measured usefulness) | ✅ | — | — | — |
168
+ | Multi-agent | DSH + MCP + hooks + TUI + browser | DSH + MCP | CLI + skill | per tool |
169
+ | npm downloads / month | 14,370 | **31,421** | 119 | n/a |
170
+ | GitHub stars | 147 | **612** | 124 | n/a |
171
+ | License | MIT | MIT | MIT | n/a |
172
+
173
+ **We are not the biggest here.** 灵枢 has more stars and downloads; SAG-Wiki retrieves over your own documents better than we do. What we do differently is the *write path*: a human gate, a three-store separation, and an audit trail you can point at — plus a token ledger so you can check whether recall is worth its cost.
174
+
175
+ Reproduce our numbers on your own vault:
176
+
177
+ ```bash
178
+ node scripts/bench-search.mjs --rebuild # rebuild time + p50/p95/max latency
179
+ dsh-memory ledger --days 30 --json # recall injection / capture / usefulness
180
+ ```
181
+
182
+ | Our measured baseline | Value |
183
+ |---|---|
184
+ | Cards indexed | 2,321 |
185
+ | Index rebuild (cold) | 869 ms |
186
+ | Recall p50 / p95 / max | 2.33 / 6.18 / 7.60 ms |
187
+ | Recall throughput | ~431 queries/s |
188
+ | Recall model calls | 0 |
189
+ | Injection per recall (60-day ledger) | ~1,394 chars |
190
+
80
191
  ## 🛡️ Review first, prove later
81
192
 
82
193
  A memory system that silently ingests everything will eventually recall a wrong fact as truth. memory-eternal defaults to **review-before-commit**:
package/README.zh-CN.md CHANGED
@@ -1,8 +1,14 @@
1
1
  # 🧠 memory-eternal —— 给 AI 装一个可信的第二大脑
2
2
 
3
+ <p align="center">
4
+ <img src="https://raw.githubusercontent.com/EternalNight996/memory-eternal/main/assets/screen/cover-zh.png" width="900" alt="记忆核心 memory-eternal:给 AI 一个不会忘、可审核、可量化的长期记忆" />
5
+ </p>
6
+
7
+ **记忆核心(memory-eternal)** —— 给 AI 一个不会忘、可审核、可量化的长期记忆。本地优先 · 审核闸门 · 记忆账本 · 一个库接入 DSH / Claude Code / Codex / Cursor 与任意 MCP 客户端。
8
+
3
9
  [![GitHub stars](https://img.shields.io/github/stars/EternalNight996/memory-eternal?style=flat)](https://github.com/EternalNight996/memory-eternal/stargazers)
4
10
  [![npm](https://img.shields.io/npm/v/memory-eternal)](https://www.npmjs.com/package/memory-eternal)
5
- [![release](https://img.shields.io/badge/release-v0.23.0-FF7A45)](https://github.com/EternalNight996/memory-eternal/releases)
11
+ [![release](https://img.shields.io/badge/release-v0.25.0-FF7A45)](https://github.com/EternalNight996/memory-eternal/releases)
6
12
  [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
7
13
 
8
14
  [English (default)](README.md) · **简体中文(镜像)**
@@ -54,6 +60,75 @@ dsh-memory open # http://127.0.0.1:7999
54
60
  npx -y -p memory-eternal dsh-memory tui # 终端里的实时待审队列
55
61
  ```
56
62
 
63
+ ## 🧬 底层记忆是怎么流动的
64
+
65
+ 一个 SQLite 库、一道写入闸门、两条读取路径。**没过闸门的东西,永远不会被召回。**
66
+
67
+ ```mermaid
68
+ flowchart TD
69
+ subgraph S1["① 输入"]
70
+ A1["对话 + 工具调用事件<br/>一轮结束后采集"]
71
+ A2["本机已装技能<br/>从宿主技能注册表扫描"]
72
+ A3["新闻关注<br/>RSS · GitHub · HN · arXiv · DSH 插件"]
73
+ A4["手动建卡 / 导入"]
74
+ end
75
+ subgraph S2["② 沉淀 —— 唯一消耗 LLM 的一步"]
76
+ B1["LLM 蒸馏成知识卡<br/>失败则降级原文卡,不丢内容"]
77
+ B2["去重:词法 Jaccard<br/>可选 LLM 判「新建 vs 追加」"]
78
+ B3["归类:knowledge / project / skill …"]
79
+ end
80
+ subgraph S3["③ 审核闸门 —— 只能由人操作"]
81
+ C1[("隔离区<br/>pending / rejected")]
82
+ C2{"批准 / 驳回"}
83
+ C3[("主库<br/>只存 approved")]
84
+ end
85
+ subgraph S4["④ 存储"]
86
+ D1[("SQLite:cards + FTS5 索引")]
87
+ D2["Markdown 镜像<br/>可 git 管理"]
88
+ D3["审计日志 + 记忆账本"]
89
+ end
90
+ subgraph S5["⑤ 召回 —— 每轮会话"]
91
+ E1["核心记忆 → systemPrompt"]
92
+ E2["memory_recall → FTS5 + BM25"]
93
+ E3["memory_revise → 待审修改副本"]
94
+ end
95
+ A1 --> B1 --> B2 --> B3 --> C1
96
+ A2 --> B2
97
+ A3 --> C1
98
+ A4 --> B2
99
+ C1 --> C2
100
+ C2 -->|批准| C3
101
+ C2 -->|驳回| C1
102
+ C3 --> D1
103
+ D1 --> D2
104
+ C3 --> D3
105
+ C3 --> E1
106
+ C3 --> E2
107
+ E2 -->|命中 + 注入字符| D3
108
+ E3 --> C1
109
+ ```
110
+
111
+ 这张图之所以成立,是因为三条不变量**写在代码里**,不是写在文档里:
112
+
113
+ | 不变量 | 由什么保证 |
114
+ |---|---|
115
+ | 主库**物理上只存 approved** | 两张物理表;所有读取路径只查主库 |
116
+ | Agent **永远不能批准自己的记忆** | Agent 只能写进隔离区;批准/驳回是 UI / TUI / CLI 里的人工动作 |
117
+ | 召回**零模型调用** | FTS5 + BM25;LLM 只在沉淀时运行 |
118
+
119
+ ## 🔌 Agent 与记忆的交互通道
120
+
121
+ | 通道 | 方向 | 何时 | 闸门 | 成本 |
122
+ |---|---|---|---|---|
123
+ | `memory_recall` | Agent → 记忆 | 按需 | 只读已批准 | **0 次模型调用**(p50 2.3ms) |
124
+ | 核心记忆 | 记忆 → Agent | 每轮会话自动 | 只读已批准 | 约 0.2k 字符 |
125
+ | 会话沉淀 / `memory_write` | 对话 → 记忆 | 一轮结束 | **进待审队列** | 1 次 LLM |
126
+ | `memory_revise` | Agent → 记忆 | 按需 | **进待审「修改副本」** | 0 |
127
+ | 审核(Web / TUI / CLI) | 人 → 记忆 | 手动 | — | 0 |
128
+ | Hook(Claude Code / Codex / Cursor) | 宿主 → 记忆 | 会话结束 | **进待审** | 1 次 LLM |
129
+ | MCP 服务 | 任意 MCP 客户端 | 按需 | 同上 | 同上 |
130
+ | 新闻关注 | 网络 → 记忆 | 按间隔 / 24h | 与知识卡隔离 | 仅网络 |
131
+
57
132
  ## 🧾 真的省 token 吗?
58
133
 
59
134
  大多数记忆产品都说自己省 token。我们认为你应该自己验证。插件内置**记忆账本**(运行状态 → 记忆账本),记录:
@@ -77,6 +152,42 @@ npx -y -p memory-eternal dsh-memory tui # 终端里的实时待审队列
77
152
 
78
153
  > 以上是示意数字,不是 benchmark —— 用账本测你自己的。如果召回有用率长期低于约 60%,就调小(更少条数、更短摘要)或直接关掉记忆。
79
154
 
155
+ ## 📊 与同类产品的实测对比
156
+
157
+ 数据快照:**2026-11-07**。我们的数字在**真实 2,321 张卡的库**上实测(不是玩具语料);竞品数据取自同一日期的公开 README / npm / GitHub。`—` 表示**未公开或无法核实**,不代表"没有"。
158
+
159
+ | 能力 | **memory-eternal v0.24.0** | 灵枢 dsh-memory v0.9.23 | SAG-Wiki v0.2.7 | CLAUDE.md / AGENTS.md |
160
+ |---|---|---|---|---|
161
+ | 存储 | SQLite + Markdown 镜像 | Markdown 认知图 | 对本地文件的 SQLite FTS5 索引 | 单个文件 |
162
+ | 写入闸门 | **人工审核队列**(三库分离) | 确定性规则裁决 | 无(索引即真相) | 无 |
163
+ | 不可变审计日志 | ✅ SQLite 层强制 | ✅ 官方声称 | — | — |
164
+ | 检索 | FTS5 + **BM25/IDF**,多列加权 | 规则化图谱遍历 | BM25 → JEV(LLM 判定) | 整文件注入 |
165
+ | 召回延迟 | **p50 2.33ms · p95 6.18ms** | — | — | 随文件体积增长 |
166
+ | 召回模型调用 | **0** | 0 | 每次查询 1–2 次 | 0 |
167
+ | 记忆账本(可量化有用率) | ✅ | — | — | — |
168
+ | 多 Agent | DSH + MCP + Hook + TUI + 浏览器 | DSH + MCP | CLI + Skill | 各工具各自为政 |
169
+ | npm 月下载 | 14,370 | **31,421** | 119 | 不适用 |
170
+ | GitHub Star | 147 | **612** | 124 | 不适用 |
171
+ | 许可证 | MIT | MIT | MIT | 不适用 |
172
+
173
+ **我们不是这里最大的。** 灵枢的 star 和下载都比我们多;SAG-Wiki 检索你自己文档的能力也比我们强。我们做的不一样的是**写入路径**:人审闸门、三库分离、可指认的审计链条,外加一本让你能自己核对"召回到底值不值"的记忆账本。
174
+
175
+ 在我们的库上自己复跑:
176
+
177
+ ```bash
178
+ node scripts/bench-search.mjs --rebuild # 重建耗时 + p50/p95/max 延迟
179
+ dsh-memory ledger --days 30 --json # 召回注入 / 沉淀调用 / 有用率
180
+ ```
181
+
182
+ | 我们实测的基线 | 数值 |
183
+ |---|---|
184
+ | 索引卡片数 | 2,321 |
185
+ | 冷启动全量重建 | 869 ms |
186
+ | 召回 p50 / p95 / max | 2.33 / 6.18 / 7.60 ms |
187
+ | 召回吞吐 | 约 431 次/秒 |
188
+ | 召回模型调用 | 0 |
189
+ | 每次召回注入(60 天账本) | 约 1,394 字符 |
190
+
80
191
  ## 🛡️ 先审核,再入库
81
192
 
82
193
  一个「什么都自动吞进去」的记忆系统,迟早会把错误事实当成真相召回。memory-eternal 默认**先审后入**:
@@ -2,7 +2,7 @@
2
2
  "name": "memory-eternal",
3
3
  "displayName": "Memory Atlas",
4
4
  "description": "Memory-eternal: open the local Memory Atlas library, review queue and knowledge graph in a Cursor/VS Code webview.",
5
- "version": "0.23.0",
5
+ "version": "0.25.0",
6
6
  "publisher": "EternalNight996",
7
7
  "license": "MIT",
8
8
  "repository": {
@@ -2,7 +2,7 @@
2
2
  "$schema": "urn:dsh-std:community-draft:dsh-plugin:0.15",
3
3
  "id": "memory-eternal-tui",
4
4
  "name": "memory-eternal-tui",
5
- "version": "0.23.0",
5
+ "version": "0.25.0",
6
6
  "manifestVersion": "0.15",
7
7
  "description": "Open Memory Atlas from dsh-TUI: native /audit scene plus browser launcher.",
8
8
  "facets": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal-tui",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "Memory Atlas for dsh-TUI: /audit scene with reason/severity, batch confirmation and reject reasons.",
5
5
  "type": "module",
6
6
  "main": "main.js",
package/lib/api.js CHANGED
@@ -24,6 +24,7 @@ import { FOLLOW_DOMAINS, parseFollowIntent, listFollows, saveFollow, removeFollo
24
24
  import { buildDigest, readDigest, digestPrompt } from './news-digest.js'
25
25
  import { getSetupStatus, runSetup, mcpAgentAction } from './setup.js'
26
26
  import { ledgerSummary } from './ledger.js'
27
+ import { starPromptStatus, markStarAction } from './star-prompt.js'
27
28
  import { backupDb, dbStatus, rebuildGuidance, withDbRetry } from './db.js'
28
29
  import { listNews, getNews, saveNews, deleteNews, setNewsRead } from './news.js'
29
30
  import { getNewsFeed, refreshNewsFeed } from './news-feed.js'
@@ -1306,6 +1307,24 @@ export function createApi(deps = {}) {
1306
1307
  } catch (e) { json(res, 200, { ok: false, error: String(e?.message || e) }) }
1307
1308
  return
1308
1309
  }
1310
+ case '/star/status': {
1311
+ // 价值触发的 star 提示:够不够格问、以及「讲证据」用的数字
1312
+ try {
1313
+ const env = typeof process !== 'undefined' ? process.env : {}
1314
+ json(res, 200, starPromptStatus({ root: vaultRoot, env }))
1315
+ } catch (e) { json(res, 200, { ok: false, error: String(e?.message || e) }) }
1316
+ return
1317
+ }
1318
+ case '/star/action': {
1319
+ const starChunks = []
1320
+ for await (const chunk of req) starChunks.push(chunk)
1321
+ let starBody
1322
+ try { starBody = JSON.parse(Buffer.concat(starChunks).toString('utf8') || '{}') } catch { return json(res, 400, { ok: false, error: 'JSON 解析失败' }) }
1323
+ const env = typeof process !== 'undefined' ? process.env : {}
1324
+ const action = String(starBody?.action || 'later')
1325
+ json(res, 200, { ok: markStarAction(env, action), action })
1326
+ return
1327
+ }
1309
1328
  case '/budget': {
1310
1329
  try {
1311
1330
  const cfg = getSettings() ?? {}