@morningljn/mnemo 0.1.3 → 0.2.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.
Files changed (71) hide show
  1. package/README.md +43 -14
  2. package/dist/init.js +16 -8
  3. package/dist/init.js.map +1 -1
  4. package/dist/refine.d.ts +14 -0
  5. package/dist/refine.js +115 -0
  6. package/dist/refine.js.map +1 -0
  7. package/dist/resources.d.ts +27 -0
  8. package/dist/resources.js +56 -0
  9. package/dist/resources.js.map +1 -0
  10. package/dist/retriever.d.ts +3 -1
  11. package/dist/retriever.js +42 -42
  12. package/dist/retriever.js.map +1 -1
  13. package/dist/schema.d.ts +1 -1
  14. package/dist/schema.js +21 -10
  15. package/dist/schema.js.map +1 -1
  16. package/dist/server.js +41 -1
  17. package/dist/server.js.map +1 -1
  18. package/dist/store.d.ts +37 -0
  19. package/dist/store.js +166 -9
  20. package/dist/store.js.map +1 -1
  21. package/dist/types.d.ts +4 -1
  22. package/docs/superpowers/plans/2026-05-15-mnemo-mcp.md +1154 -0
  23. package/docs/superpowers/plans/2026-05-16-memory-self-learning.md +932 -0
  24. package/docs/superpowers/plans/2026-05-16-mnemo-query-cache.md +613 -0
  25. package/docs/superpowers/plans/2026-05-16-retrieval-and-injection-optimization.md +770 -0
  26. package/openspec/changes/archive/2026-05-15-mnemo-mcp/.openspec.yaml +2 -0
  27. package/openspec/changes/archive/2026-05-15-mnemo-mcp/design.md +83 -0
  28. package/openspec/changes/archive/2026-05-15-mnemo-mcp/proposal.md +32 -0
  29. package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/fact-retrieval/spec.md +75 -0
  30. package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/fact-store/spec.md +83 -0
  31. package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/mcp-server/spec.md +34 -0
  32. package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/security/spec.md +37 -0
  33. package/openspec/changes/archive/2026-05-15-mnemo-mcp/tasks.md +44 -0
  34. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/.openspec.yaml +2 -0
  35. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/design.md +96 -0
  36. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/proposal.md +29 -0
  37. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/specs/batch-operations/spec.md +42 -0
  38. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/specs/perf-metrics/spec.md +55 -0
  39. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/specs/query-cache/spec.md +65 -0
  40. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/tasks.md +45 -0
  41. package/openspec/changes/memory-self-learning/.openspec.yaml +2 -0
  42. package/openspec/changes/memory-self-learning/design.md +174 -0
  43. package/openspec/changes/memory-self-learning/proposal.md +35 -0
  44. package/openspec/changes/memory-self-learning/specs/fact-retrieval/spec.md +35 -0
  45. package/openspec/changes/memory-self-learning/specs/fact-summary/spec.md +45 -0
  46. package/openspec/changes/memory-self-learning/specs/length-penalty/spec.md +27 -0
  47. package/openspec/changes/memory-self-learning/specs/retrieval-log/spec.md +41 -0
  48. package/openspec/changes/memory-self-learning/specs/self-learning/spec.md +68 -0
  49. package/openspec/changes/memory-self-learning/tasks.md +56 -0
  50. package/openspec/changes/retrieval-and-injection-optimization/.openspec.yaml +2 -0
  51. package/openspec/changes/retrieval-and-injection-optimization/design.md +117 -0
  52. package/openspec/changes/retrieval-and-injection-optimization/proposal.md +30 -0
  53. package/openspec/changes/retrieval-and-injection-optimization/specs/adaptive-scoring/spec.md +43 -0
  54. package/openspec/changes/retrieval-and-injection-optimization/specs/injection-protocol/spec.md +48 -0
  55. package/openspec/changes/retrieval-and-injection-optimization/specs/mcp-resources/spec.md +39 -0
  56. package/openspec/changes/retrieval-and-injection-optimization/specs/query-refinement/spec.md +39 -0
  57. package/openspec/changes/retrieval-and-injection-optimization/tasks.md +33 -0
  58. package/openspec/config.yaml +20 -0
  59. package/package.json +1 -1
  60. package/src/init.ts +17 -9
  61. package/src/refine.ts +127 -0
  62. package/src/resources.ts +78 -0
  63. package/src/retriever.ts +46 -44
  64. package/src/schema.ts +21 -10
  65. package/src/server.ts +44 -1
  66. package/src/store.ts +215 -9
  67. package/src/types.ts +4 -1
  68. package/tests/refine.test.ts +52 -0
  69. package/tests/resource.test.ts +62 -0
  70. package/tests/retriever.test.ts +53 -0
  71. package/tests/store.test.ts +112 -0
@@ -0,0 +1,2 @@
1
+ schema: spec-driven
2
+ created: 2026-05-15
@@ -0,0 +1,83 @@
1
+ ## Context
2
+
3
+ Ocean CLI(ocean-cc-cli)内置了一套从 Hermes 项目移植的结构化事实记忆系统,核心代码在 `src/memory/` 目录下约 2000 行 TypeScript。该系统包含:
4
+
5
+ - **存储层**:MemoryStore(SQLite + FTS5,`bun:sqlite` 绑定)
6
+ - **检索层**:FactRetriever(5 级 fallback 混合检索管线)
7
+ - **编排层**:MemoryManager + MemoryProvider 抽象 + HolographicProvider 实现
8
+ - **辅助**:安全扫描(security.ts)、类型定义(types.ts)、DDL(schema.ts)、注入工具(injection.ts)
9
+
10
+ 系统被设计为"双层存储"(全局库 + 项目库)+ 多 provider 编排,与 Ocean CLI 的生命周期深度耦合。
11
+
12
+ 目标:将核心存储和检索逻辑提取为独立 MCP server,支持 Claude Code 和 Codex 等任意 MCP 客户端。
13
+
14
+ ## Goals / Non-Goals
15
+
16
+ **Goals:**
17
+ - 独立 npm 包 `mnemo-mcp`,一行配置即可在任何 MCP 客户端使用
18
+ - 忠实移植全部核心算法(检索管线、去重、信任、矛盾、关键词、双语)
19
+ - Node.js 兼容(使用 `better-sqlite3` 替代 `bun:sqlite`)
20
+ - 单库存储 `~/.mnemo/facts.db`,去掉项目库概念
21
+ - 零外部服务依赖,纯本地运行
22
+
23
+ **Non-Goals:**
24
+ - 不做多用户 / 中心化存储
25
+ - 不做 system prompt 注入逻辑(MCP 客户端自行决定如何消费数据)
26
+ - 不做项目库 / 双层架构
27
+ - 不做数据迁移工具(v1 用户可手动复制 SQLite 文件)
28
+ - 不做 Web UI / 管理界面
29
+ - 不修改 Ocean CLI 现有代码
30
+
31
+ ## Decisions
32
+
33
+ ### 1. SQLite 绑定:better-sqlite3
34
+
35
+ **选择**:better-sqlite3
36
+ **替代方案**:sql.js(纯 WASM)、drizzle-orm(抽象层)
37
+ **理由**:better-sqlite3 是 Node.js 生态最成熟的 SQLite 绑定,同步 API(和 bun:sqlite 一致),迁移成本最低。sql.js 性能差,drizzle 多一层抽象没必要。
38
+
39
+ ### 2. 传输协议:stdio
40
+
41
+ **选择**:MCP stdio transport
42
+ **替代方案**:SSE transport(HTTP 长连接)
43
+ **理由**:本地工具标准模式,所有 MCP 客户端都支持 stdio。SSE 适合远程/多用户场景,v1 不需要。
44
+
45
+ ### 3. 项目结构
46
+
47
+ ```
48
+ mnemo-mcp/
49
+ ├── src/
50
+ │ ├── server.ts # MCP 入口,注册 tools
51
+ │ ├── store.ts # MemoryStore 移植(better-sqlite3)
52
+ │ ├── retriever.ts # FactRetriever 移植
53
+ │ ├── schema.ts # DDL
54
+ │ ├── security.ts # 安全扫描
55
+ │ └── types.ts # 类型定义
56
+ ├── package.json
57
+ ├── tsconfig.json
58
+ └── README.md
59
+ ```
60
+
61
+ **理由**:扁平结构,6 个文件,无子目录嵌套。核心代码从 Ocean CLI 直接移植,只改 import 和 SQLite 绑定。
62
+
63
+ ### 4. category 保留 5 个固定分类
64
+
65
+ **选择**:identity / coding_style / tool_pref / workflow / general
66
+ **理由**:v1 不动分类,保持和 Ocean CLI 一致,降低移植风险。后续根据用户反馈迭代。
67
+
68
+ ### 5. 去掉编排层和抽象
69
+
70
+ **选择**:不移植 MemoryManager、MemoryProvider、HolographicProvider、instance.ts、injection.ts
71
+ **理由**:MCP server 只需要一个 store + 一个 retriever,不需要 provider 抽象和编排。HolographicProvider 中的工具处理逻辑(handleFactStore/handleFactFeedback)直接下沉到 server.ts。
72
+
73
+ ### 6. 安全扫描保留但降低为可选
74
+
75
+ **选择**:security.ts 移植但在 tool 响应中只做警告,不阻止操作
76
+ **理由**:MCP 客户端可能是 AI 自己调用,硬拦截可能导致功能异常。检测到风险时返回 warning 字段。
77
+
78
+ ## Risks / Trade-offs
79
+
80
+ - **[better-sqlite3 native 编译]** → 用户安装时需要 C++ 编译环境。缓解:提供 prebuilt binaries(better-sqlite3 官方已支持 prebuild)。
81
+ - **[存储路径冲突]** → 多个 AI 工具同时写入 `~/.mnemo/facts.db`。缓解:SQLite WAL 模式支持并发读写,短锁等待即可。
82
+ - **[算法移植遗漏]** → 直接移植代码,关键算法用 diff 对比确认无遗漏。
83
+ - **[MCP SDK 版本]** → @modelcontextprotocol/sdk 仍在快速迭代。缓解:锁定具体版本,定期更新。
@@ -0,0 +1,32 @@
1
+ ## Why
2
+
3
+ Ocean CLI 内置了一套结构化事实记忆系统(SQLite + FTS5),具备信任评分、实体图谱、矛盾检测、双语检索等能力。这套系统完全独立于 Ocean CLI 的业务逻辑,但被耦合在代码中,无法被其他 AI 编程工具(Codex、Cursor 等)复用。需要将其提取为独立的 MCP server,让团队成员在任意 AI 编程工具中使用同一套个人记忆。
4
+
5
+ ## What Changes
6
+
7
+ - 新建独立项目 `mnemo-mcp`,从 Ocean CLI 移植核心记忆逻辑
8
+ - 砍掉编排层(MemoryManager、MemoryProvider 抽象、instance 单例)
9
+ - 砍掉注入层(system prompt 拼接、围栏注入、prefetch 机制)
10
+ - 砍掉项目库双层存储,简化为单库 `~/.mnemo/facts.db`
11
+ - 将 `bun:sqlite` 替换为 `better-sqlite3`(Node.js 兼容)
12
+ - 新增 MCP server 入口,使用 `@modelcontextprotocol/sdk` 注册 tools
13
+ - 保留完整的核心算法:检索管线、去重、信任衰减、矛盾检测、关键词提取、双语扩展、安全扫描
14
+
15
+ ## Capabilities
16
+
17
+ ### New Capabilities
18
+ - `mcp-server`: MCP 协议适配层,注册 fact_store / fact_feedback 两个 tools,stdio transport
19
+ - `fact-store`: 结构化事实存储核心(SQLite + FTS5 + 实体图谱 + 信任评分 + 矛盾检测)
20
+ - `fact-retrieval`: 混合检索管线(FTS5 → LIKE → 字符交叉 → 分类推断 → trust fallback),含双语扩展和 category 信号
21
+ - `security`: 安全扫描(注入检测、PII 检测、不可见 Unicode)
22
+
23
+ ### Modified Capabilities
24
+
25
+ (无,全新项目)
26
+
27
+ ## Impact
28
+
29
+ - 新项目依赖:better-sqlite3、@modelcontextprotocol/sdk、TypeScript
30
+ - 存储位置:`~/.mnemo/facts.db`(独立于 `~/.claude/`)
31
+ - 配置方式:各 AI 工具的 MCP server 配置文件中添加 mnemo-mcp
32
+ - 用户数据:从 Ocean CLI 的 `~/.claude/memory/facts.db` 迁移脚本(可选)
@@ -0,0 +1,75 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: 多级 fallback 检索
4
+ 系统 SHALL 实现 5 级 fallback 检索管线:FTS5 → LIKE → 字符交叉 → 分类推断 → trust fallback。
5
+
6
+ #### Scenario: FTS5 命中
7
+ - **WHEN** 搜索 "用户偏好" 且 FTS5 索引返回匹配结果
8
+ - **THEN** 返回 FTS5 候选集,进入 Jaccard + 信任 + 时间衰减重排序
9
+
10
+ #### Scenario: FTS5 无结果 fallback 到 LIKE
11
+ - **WHEN** FTS5 无匹配
12
+ - **THEN** 使用 LIKE 模糊匹配(含中文 bigram/trigram 滑动窗口)
13
+
14
+ #### Scenario: LIKE 无结果 fallback 到字符交叉
15
+ - **WHEN** LIKE 也无匹配
16
+ - **THEN** 提取查询中文字符,与事实内容做单字交叉匹配(≥40% 命中率)
17
+
18
+ #### Scenario: 全部无结果 fallback 到 trust
19
+ - **WHEN** 所有检索级别都无匹配且查询为个人/身份相关
20
+ - **THEN** 按 trust_score 返回 top-N 事实
21
+
22
+ ### Requirement: 检索结果评分
23
+ 系统 SHALL 对检索结果计算综合评分:FTS 权重 × ftsScore + Jaccard 权重 × (0.20 × Jaccard + 0.45 × Containment + 0.35 × KeywordScore) × trustScore × 时间衰减。
24
+
25
+ #### Scenario: 评分排序
26
+ - **WHEN** 搜索返回多条结果
27
+ - **THEN** 按综合评分降序排列
28
+
29
+ #### Scenario: Category 信号强化
30
+ - **WHEN** 查询命中某个 category 的特有 tag
31
+ - **THEN** 该 category 的事实获得乘法强化(1 + 0.5 × 集中度 × 归一化信号)
32
+
33
+ ### Requirement: Category 多样性
34
+ 系统 SHALL 在返回结果中保证 category 多样性,避免同类事实垄断。
35
+
36
+ #### Scenario: 去重补位
37
+ - **WHEN** 返回结果中同一 category 事实过多
38
+ - **THEN** 每个 category 优先保留评分最高的,不足 limit 时从原列表补位
39
+
40
+ ### Requirement: 检索追踪
41
+ 系统 SHALL 追踪检索命中的事实,递增 retrieval_count,top 3 的 trust_score += 0.01 并重置 updated_at。
42
+
43
+ #### Scenario: 命中追踪
44
+ - **WHEN** search 返回结果
45
+ - **THEN** 所有返回事实的 retrieval_count += 1,top 3 获得信任微增和时间续命
46
+
47
+ ### Requirement: 高级检索操作
48
+ 系统 SHALL 支持 probe(实体探测)、related(实体关联)、reason(多实体推理)、contradict(矛盾检测)四种高级操作。
49
+
50
+ #### Scenario: 实体探测
51
+ - **WHEN** 调用 `fact_store(action="probe", entity="TypeScript")`
52
+ - **THEN** 返回所有关联 TypeScript 实体的事实
53
+
54
+ #### Scenario: 实体关联
55
+ - **WHEN** 调用 `fact_store(action="related", entity="TypeScript")`
56
+ - **THEN** 返回与 TypeScript 共享上下文的其他实体关联的事实(排除原始事实)
57
+
58
+ #### Scenario: 多实体推理
59
+ - **WHEN** 调用 `fact_store(action="reason", entities=["TypeScript", "测试"])`
60
+ - **THEN** 返回同时关联两个实体的事实
61
+
62
+ #### Scenario: 矛盾检测
63
+ - **WHEN** 调用 `fact_store(action="contradict")`
64
+ - **THEN** 返回高实体重叠 + 低内容相似度的矛盾事实对
65
+
66
+ ### Requirement: 双语查询扩展
67
+ 系统 SHALL 自动学习中英术语对照,搜索时将查询中的术语翻译为对端语言。
68
+
69
+ #### Scenario: 中文搜英文
70
+ - **WHEN** 搜索 "部署" 且已学习 "部署→deploy" 映射
71
+ - **THEN** 查询扩展为 "部署 deploy",同时命中中英文事实
72
+
73
+ #### Scenario: 英文搜中文
74
+ - **WHEN** 搜索 "cache" 且已学习 "缓存→cache" 映射
75
+ - **THEN** 查询扩展为 "cache 缓存"
@@ -0,0 +1,83 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: 事实 CRUD
4
+ 系统 SHALL 支持 add / update / remove / list 四种事实操作,事实以 (content, category, tags, trust_score) 结构存储。
5
+
6
+ #### Scenario: 添加新事实
7
+ - **WHEN** 调用 `fact_store(action="add", content="用户偏好深色主题", category="tool_pref", tags="theme,dark")`
8
+ - **THEN** 创建事实记录,返回 `{"fact_id": N, "status": "added", "category": "tool_pref"}`
9
+
10
+ #### Scenario: 添加重复事实
11
+ - **WHEN** 调用 add 时 content 与已有事实精确相同
12
+ - **THEN** 返回已有 fact_id,不创建重复记录
13
+
14
+ #### Scenario: 添加相似事实
15
+ - **WHEN** 调用 add 时 content 与已有事实通过三层去重检测(实体重叠+编辑距离 / Jaccard / Containment)判定为相似
16
+ - **THEN** 更新已有事实内容,返回 `{"fact_id": N, "status": "updated", "reason": "similar_fact_merged"}`
17
+
18
+ #### Scenario: 更新事实
19
+ - **WHEN** 调用 `fact_store(action="update", fact_id=1, content="新内容", trust_delta=0.1)`
20
+ - **THEN** 更新指定事实的字段,重新提取实体
21
+
22
+ #### Scenario: 删除事实
23
+ - **WHEN** 调用 `fact_store(action="remove", fact_id=1)`
24
+ - **THEN** 删除事实及其实体关联,清理孤立实体
25
+
26
+ #### Scenario: 浏览事实
27
+ - **WHEN** 调用 `fact_store(action="list", category="identity", min_trust=0.5, limit=10)`
28
+ - **THEN** 返回符合条件的事实列表,按 trust_score 降序
29
+
30
+ ### Requirement: 实体自动提取
31
+ 系统 SHALL 从事实内容中自动提取中英文实体并建立关联图谱。
32
+
33
+ #### Scenario: 英文实体提取
34
+ - **WHEN** 添加内容包含大写首字母词组(如 "Visual Studio Code")、引号包裹词(如 "TypeScript")
35
+ - **THEN** 提取为实体,创建 entity 记录,关联到事实
36
+
37
+ #### Scenario: 中文实体提取
38
+ - **WHEN** 添加内容包含书名号(如《设计模式》)、引号包裹(如「记忆系统」)、声明模式(如"我叫暖暖")
39
+ - **THEN** 提取为实体,创建 entity 记录
40
+
41
+ ### Requirement: 信任评分系统
42
+ 系统 SHALL 维护每个事实的 trust_score(0.0~1.0),支持反馈调整和时间衰减。
43
+
44
+ #### Scenario: 正向反馈
45
+ - **WHEN** 调用 `fact_feedback(action="helpful", fact_id=1)`
46
+ - **THEN** trust_score += 0.05(上限 1.0),helpful_count += 1
47
+
48
+ #### Scenario: 负向反馈
49
+ - **WHEN** 调用 `fact_feedback(action="unhelpful", fact_id=1)`
50
+ - **THEN** trust_score -= 0.10(下限 0.0)
51
+
52
+ #### Scenario: 时间衰减
53
+ - **WHEN** session 启动时执行信任衰减
54
+ - **THEN** 超过宽限期的事实按 category 配置的速率衰减,trust_score < 0.1 的自动删除
55
+
56
+ ### Requirement: 矛盾检测
57
+ 系统 SHALL 在写入新事实时检测同 category 中共享实体但内容冲突的旧事实,自动降权。
58
+
59
+ #### Scenario: 写入时矛盾降权
60
+ - **WHEN** 添加新事实后,同 category 中存在共享实体但编辑距离在 0.2~0.5 区间的旧事实
61
+ - **THEN** 旧事实 trust_score -= 0.10
62
+
63
+ #### Scenario: 启动时矛盾审计
64
+ - **WHEN** server 启动时
65
+ - **THEN** 扫描所有事实对(实体 JOIN + Jaccard 双层),降权较旧的矛盾事实
66
+
67
+ ### Requirement: 关键词提取
68
+ 系统 SHALL 从事实内容中自动提取主题关键词,用于检索增强。
69
+
70
+ #### Scenario: 关键词生成
71
+ - **WHEN** 添加或更新事实
72
+ - **THEN** 从 content + tags 中提取关键词(位置权重 × 频率 × 类别特异性 × tags 加权),存储为 JSON 数组
73
+
74
+ ### Requirement: 分类固定为 5 个
75
+ 系统 SHALL 支持固定的 5 个 category:identity / coding_style / tool_pref / workflow / general。
76
+
77
+ #### Scenario: 使用有效 category
78
+ - **WHEN** 调用 add 时 category 为 5 个之一
79
+ - **THEN** 正常存储
80
+
81
+ #### Scenario: 未指定 category
82
+ - **WHEN** 调用 add 时未提供 category
83
+ - **THEN** 默认为 "general"
@@ -0,0 +1,34 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: MCP server 启动与工具注册
4
+ 系统 SHALL 作为 MCP server 通过 stdio transport 运行,注册 `fact_store` 和 `fact_feedback` 两个 tools。
5
+
6
+ #### Scenario: 正常启动
7
+ - **WHEN** 运行 `npx mnemo-mcp` 或 `node dist/server.js`
8
+ - **THEN** server 通过 stdio 建立 MCP 连接,注册 fact_store(9 个 action)和 fact_feedback(2 个 action)两个 tools
9
+
10
+ #### Scenario: 客户端连接
11
+ - **WHEN** Claude Code 或 Codex 通过 MCP 配置启动 mnemo-mcp
12
+ - **THEN** server 响应 `tools/list` 请求返回两个 tool schema,响应 `tools/call` 请求执行对应操作
13
+
14
+ ### Requirement: 存储路径
15
+ 系统 SHALL 使用 `~/.mnemo/facts.db` 作为默认存储路径,目录不存在时自动创建。
16
+
17
+ #### Scenario: 首次运行
18
+ - **WHEN** `~/.mnemo/` 目录不存在
19
+ - **THEN** server 自动创建目录和数据库文件,执行 schema 初始化
20
+
21
+ #### Scenario: 数据库已存在
22
+ - **WHEN** `~/.mnemo/facts.db` 已存在
23
+ - **THEN** server 打开已有数据库,执行增量迁移(如添加新列),不破坏已有数据
24
+
25
+ ### Requirement: 错误处理
26
+ 系统 SHALL 在 tool 调用失败时返回包含 error 字段的 JSON,不抛出未捕获异常。
27
+
28
+ #### Scenario: 无效 action
29
+ - **WHEN** fact_store 被调用且 action 为未知值
30
+ - **THEN** 返回 `{"error": "Unknown action: xxx"}`
31
+
32
+ #### Scenario: 缺少必需参数
33
+ - **WHEN** add action 缺少 content 参数
34
+ - **THEN** 返回 `{"error": "Missing required argument: content"}`
@@ -0,0 +1,37 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: 提示注入检测
4
+ 系统 SHALL 检测记忆内容中的提示注入尝试(伪造围栏标签、system-reminder 伪装、注入指令模式)。
5
+
6
+ #### Scenario: 检测到注入
7
+ - **WHEN** 添加的内容包含 `<memory-context>` 标签或 "ignore previous instructions" 模式
8
+ - **THEN** 返回结果中包含 warnings 字段标记风险
9
+
10
+ #### Scenario: 安全内容
11
+ - **WHEN** 添加的内容无注入特征
12
+ - **THEN** 正常存储,不附加 warnings
13
+
14
+ ### Requirement: PII 检测
15
+ 系统 SHALL 检测记忆内容中的个人信息(邮箱、API 密钥模式)。
16
+
17
+ #### Scenario: 检测到邮箱
18
+ - **WHEN** 添加的内容包含邮箱地址
19
+ - **THEN** 返回 warnings 字段提示"包含邮箱地址",但不阻止存储
20
+
21
+ #### Scenario: 检测到 API 密钥
22
+ - **WHEN** 添加的内容匹配 API 密钥模式(sk-xxx、ghp_xxx 等)
23
+ - **THEN** 返回 warnings 字段提示"包含 API 密钥模式"
24
+
25
+ ### Requirement: 不可见 Unicode 检测
26
+ 系统 SHALL 检测记忆内容中的不可见 Unicode 字符(零宽字符、控制字符、BOM 等)。
27
+
28
+ #### Scenario: 零宽字符检测
29
+ - **WHEN** 添加的内容包含 U+200B~U+200F 范围的零宽字符
30
+ - **THEN** 返回 warnings 字段提示具体字符类型
31
+
32
+ ### Requirement: 安全警告不阻止操作
33
+ 系统 SHALL 将安全检测结果作为 warnings 返回,不阻止事实的存储或检索操作。
34
+
35
+ #### Scenario: 有警告但操作成功
36
+ - **WHEN** 添加的事实通过安全扫描发现 PII
37
+ - **THEN** 事实正常存储,响应中附加 `"warnings": ["包含邮箱地址"]` 字段
@@ -0,0 +1,44 @@
1
+ ## 1. 项目初始化
2
+
3
+ - [ ] 1.1 在 `~/Documents/demo/ocean/mnemo-mcp/` 创建项目目录,初始化 package.json(name: mnemo-mcp, bin 入口, dependencies: better-sqlite3, @modelcontextprotocol/sdk)
4
+ - [ ] 1.2 创建 tsconfig.json(target: ES2022, module: NodeNext, outDir: dist)
5
+ - [ ] 1.3 创建项目骨架文件:src/server.ts, src/store.ts, src/retriever.ts, src/schema.ts, src/security.ts, src/types.ts
6
+
7
+ ## 2. 类型与 Schema 移植
8
+
9
+ - [ ] 2.1 移植 types.ts:去掉 ProviderContext/ToolSchema 等 Ocean CLI 特有类型,保留 Fact/ScoredFact/Contradiction/SearchOptions/FactStoreArgs/FactFeedbackArgs/FactCategory 等核心类型
10
+ - [ ] 2.2 移植 schema.ts:去掉 doc_index 表和 category_token_stats 表(v1 简化),保留 facts + entities + fact_entities + FTS5 索引 + 触发器
11
+
12
+ ## 3. 存储层移植
13
+
14
+ - [ ] 3.1 移植 MemoryStore → store.ts:将 `bun:sqlite` 替换为 `better-sqlite3`,保留全部 public API(addFact/findSimilarFact/updateFact/removeFact/listFacts/recordFeedback/getFactsByEntity/getFactsByEntities/decayTrustScores/demoteContradictingFacts/auditContradictions)
15
+ - [ ] 3.2 移植实体提取逻辑(extractEntities/resolveEntity/classifyEntity/cleanOrphanEntities)
16
+ - [ ] 3.3 移植去重算法(三层递进:实体重叠+编辑距离 / Jaccard bigram / Containment)
17
+ - [ ] 3.4 移植信任衰减逻辑(decayTrustScores,按 category 宽限期 + 衰减率)
18
+ - [ ] 3.5 移植关键词提取逻辑(extractKeywords/tokenizeForKeywords/backfillKeywords + category_token_stats 表)
19
+
20
+ ## 4. 检索层移植
21
+
22
+ - [ ] 4.1 移植 FactRetriever → retriever.ts:5 级 fallback(ftsCandidates/likeFallback/charOverlapFallback/categoryInferFallback/trustFallback)
23
+ - [ ] 4.2 移植评分逻辑(Jaccard + Containment + KeywordScore + Category 信号乘法 + 时间衰减)
24
+ - [ ] 4.3 移植高级检索(probe/related/reason/contradict)
25
+ - [ ] 4.4 移植双语查询扩展(getCnEnPairs/expandQueryBilingually + 种子表)
26
+ - [ ] 4.5 移植检索追踪(trackRetrieval: retrieval_count + top3 信任刷新)
27
+
28
+ ## 5. 安全扫描移植
29
+
30
+ - [ ] 5.1 移植 security.ts:注入检测、PII 检测、不可见 Unicode 检测,保留全部函数签名
31
+
32
+ ## 6. MCP Server 入口
33
+
34
+ - [ ] 6.1 实现 server.ts:McpServer 创建,stdio transport,注册 fact_store 和 fact_feedback 两个 tools
35
+ - [ ] 6.2 实现 fact_store tool handler:9 个 action(add/search/probe/related/reason/contradict/update/remove/list),调用 store + retriever
36
+ - [ ] 6.3 实现 fact_feedback tool handler:helpful/unhelpful 两个 action
37
+ - [ ] 6.4 实现启动初始化:创建 ~/.mnemo/ 目录、打开/创建数据库、执行信任衰减和矛盾审计、关键词补算
38
+ - [ ] 6.5 安全扫描集成:add/update 时调用 fullSecurityScan,将 warnings 附加到响应中
39
+
40
+ ## 7. 构建与验证
41
+
42
+ - [ ] 7.1 配置构建脚本(tsc 编译),确认 `node dist/server.js` 可正常启动
43
+ - [ ] 7.2 用 MCP Inspector 或手动测试验证 tools/list 和 tools/call 响应格式正确
44
+ - [ ] 7.3 验证 add → search → feedback 完整流程可用
@@ -0,0 +1,2 @@
1
+ schema: spec-driven
2
+ created: 2026-05-16
@@ -0,0 +1,96 @@
1
+ ## Context
2
+
3
+ mnemo-mcp 作为独立 MCP server,每次 fact_store tool 调用都直接查询 SQLite(FTS5 + Jaccard + 多级 fallback)。相同 query 在短时间内重复检索浪费计算资源。同时缺少批量操作能力,一次只能 add 一条事实,MCP 往返次数多。
4
+
5
+ 当前查询链路:
6
+ ```
7
+ tool call → server.ts → retriever.search() → FTS5 → Jaccard → 评分 → 返回
8
+ ```
9
+
10
+ 优化目标:减少重复查询开销,支持批量操作,提升整体响应速度。
11
+
12
+ ## Goals / Non-Goals
13
+
14
+ **Goals:**
15
+ - 实现查询结果缓存层,相同 query + 参数在 TTL 内直接返回缓存
16
+ - 支持批量 add 操作,一次写入多条事实
17
+ - 增加性能监控(debug 模式),记录查询耗时和缓存命中率
18
+ - 启动时延迟加载非关键索引,减少首次响应时间
19
+
20
+ **Non-Goals:**
21
+ - 不修改检索算法(FTS5 + Jaccard 不动)
22
+ - 不修改存储 schema(facts/entities/fact_entities 表结构不变)
23
+ - 不做分布式缓存(单机 SQLite,本地内存缓存足够)
24
+ - 不做持久化缓存(进程级缓存,重启失效可接受)
25
+
26
+ ## Decisions
27
+
28
+ ### 1. 缓存实现方式
29
+
30
+ **选择**:进程内 Map 缓存,基于 query + category + limit + minTrust 做键
31
+
32
+ ```typescript
33
+ interface CacheEntry {
34
+ results: ScoredFact[]
35
+ timestamp: number
36
+ queryKey: string
37
+ }
38
+
39
+ const cache = new Map<string, CacheEntry>()
40
+ const CACHE_TTL_MS = 60_000
41
+ ```
42
+
43
+ **理由**:mnemo-mcp 是单进程 MCP server,没有多进程共享需求。Map 简单高效,不需要引入 Redis 等外部依赖。
44
+
45
+ ### 2. 缓存失效策略
46
+
47
+ **选择**:写操作(add/update/remove)时清空全部缓存
48
+
49
+ **理由**:事实写入会改变查询结果,但写入频率远低于查询频率。全量清空实现简单,不需要维护复杂的依赖图。
50
+
51
+ ### 3. 批量 add 接口
52
+
53
+ **选择**:扩展 fact_store 的 add action,支持 `content` 为数组
54
+
55
+ ```typescript
56
+ // 单条(兼容现有)
57
+ { action: 'add', content: '事实内容', category: 'general' }
58
+
59
+ // 批量(新增)
60
+ { action: 'add', content: ['事实1', '事实2'], category: 'general' }
61
+ ```
62
+
63
+ **理由**:保持接口向后兼容,现有单条调用不受影响。批量返回数组形式的 fact_id 和状态。
64
+
65
+ ### 4. 性能监控
66
+
67
+ **选择**:环境变量开关 `MNEMO_DEBUG=1`,开启时记录查询日志
68
+
69
+ **记录内容**:
70
+ - 查询耗时(ms)
71
+ - 是否命中缓存
72
+ - 检索路径(FTS5 / LIKE / charOverlap / categoryInfer / trustFallback)
73
+ - 返回结果数
74
+
75
+ **理由**:默认关闭避免性能开销,开发调试时开启。
76
+
77
+ ### 5. 延迟加载
78
+
79
+ **选择**:启动时不预加载 category_tag_map 和 cn_en_pairs,首次查询时惰性初始化
80
+
81
+ **理由**:这两个数据结构在 `FactRetriever` 中已经是惰性初始化的(`getCategoryTagMap()` 和 `getCnEnPairs()`),但启动时的 `auditContradictions` 和 `decayTrustScores` 会触发数据库全表扫描。改为启动时跳过这些操作,首次 tool 调用时再执行。
82
+
83
+ ## Risks / Trade-offs
84
+
85
+ - **[缓存雪崩]** → 大量并发请求同时命中失效缓存。缓解:缓存失效是同步的,SQLite 的 WAL 模式本身有锁保护。
86
+ - **[批量 add 部分失败]** → 数组中某条写入失败(如 UNIQUE 冲突)。缓解:逐条处理,返回每条独立的状态,部分成功部分失败。
87
+ - **[延迟加载导致首次查询慢]** → 启动时跳过的审计和衰减在首次查询时执行。缓解:这些操作通常很快(<100ms),且只在首次触发。
88
+
89
+ ## Migration Plan
90
+
91
+ 无需迁移。新增功能完全向后兼容,现有 tool 调用方式不变。
92
+
93
+ ## Open Questions
94
+
95
+ - 是否需要支持缓存预热(启动时预加载高频查询)?
96
+ - 批量 add 是否需要支持每条不同的 category 和 tags?
@@ -0,0 +1,29 @@
1
+ ## Why
2
+
3
+ mnemo-mcp 作为独立 MCP server,每次 tool 调用都直接查询 SQLite(FTS5 + Jaccard + 多级 fallback),相同 query 重复检索浪费计算资源。同时缺少批量操作能力,一次只能 add 一条事实,MCP 往返次数多。需要增加查询缓存和批量操作支持,提升响应速度和用户体验。
4
+
5
+ ## What Changes
6
+
7
+ - 增加查询结果缓存层:相同 query + 参数在 60s 内直接返回缓存结果
8
+ - 增加批量 add 操作:支持一次写入多条事实,减少 MCP 往返
9
+ - 增加启动性能优化:延迟加载非关键索引、异步初始化
10
+ - 增加查询性能监控:记录检索耗时、缓存命中率(debug 模式)
11
+
12
+ ## Capabilities
13
+
14
+ ### New Capabilities
15
+ - `query-cache`: 查询结果缓存层,基于 query + category + limit + minTrust 做缓存键,TTL 60s
16
+ - `batch-operations`: 批量事实操作,支持一次 add 多条、一次 remove 多条
17
+ - `perf-metrics`: 性能监控,记录查询耗时、缓存命中率、检索 fallback 路径
18
+
19
+ ### Modified Capabilities
20
+ - `fact-store`: 修改 fact_store tool 的 add action,支持传入数组批量写入
21
+
22
+ ## Impact
23
+
24
+ - 修改文件:`src/store.ts`(增加缓存层、批量操作接口)
25
+ - 修改文件:`src/retriever.ts`(增加缓存查询、性能埋点)
26
+ - 修改文件:`src/server.ts`(增加 batch_add handler、perf_metrics 开关)
27
+ - 修改文件:`src/types.ts`(增加批量操作类型定义)
28
+ - 无外部依赖变化
29
+ - 预估性能提升:重复查询减少 80% 计算开销,批量操作减少 N 次 MCP 往返
@@ -0,0 +1,42 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: Batch add supports multiple facts in one call
4
+ The system SHALL support adding multiple facts in a single fact_store tool call.
5
+
6
+ Batch add interface:
7
+ - The `content` field SHALL accept either a string (single fact) or an array of strings (multiple facts)
8
+ - All facts in a batch SHALL share the same category and tags
9
+ - The response SHALL contain an array of results, one per fact
10
+
11
+ Individual result format:
12
+ - `fact_id`: number (or -1 on error)
13
+ - `status`: "added" | "updated" | "error"
14
+ - `reason`: optional string explaining the result
15
+
16
+ #### Scenario: Batch add multiple facts
17
+ - **WHEN** fact_store is called with action="add", content=["事实1", "事实2"], category="general"
18
+ - **THEN** the system SHALL process each fact sequentially
19
+ - **AND** return an array of results with fact_id and status for each
20
+
21
+ #### Scenario: Batch add with partial failure
22
+ - **WHEN** a batch contains one valid fact and one empty string
23
+ - **THEN** the valid fact SHALL be added successfully
24
+ - **AND** the empty string SHALL return an error status
25
+ - **AND** the overall response SHALL include all individual results
26
+
27
+ #### Scenario: Single fact add remains compatible
28
+ - **WHEN** fact_store is called with action="add", content="单条事实" (string, not array)
29
+ - **THEN** the system SHALL process it as a single fact
30
+ - **AND** return a single result object (backward compatible)
31
+
32
+ ### Requirement: Batch remove supports multiple fact IDs
33
+ The system SHALL support removing multiple facts in a single fact_store tool call.
34
+
35
+ Batch remove interface:
36
+ - The `fact_id` field SHALL accept either a number (single) or an array of numbers (multiple)
37
+ - The response SHALL contain an array of results, one per fact_id
38
+
39
+ #### Scenario: Batch remove multiple facts
40
+ - **WHEN** fact_store is called with action="remove", fact_id=[1, 2, 3]
41
+ - **THEN** the system SHALL attempt to remove each fact
42
+ - **AND** return an array of {fact_id, removed: boolean} results
@@ -0,0 +1,55 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: Query execution time is recorded
4
+ The system SHALL record the execution time of every database query when debug mode is enabled.
5
+
6
+ Recorded metrics:
7
+ - Query type (search/probe/related/reason/contradict/list)
8
+ - Execution time in milliseconds
9
+ - Number of results returned
10
+ - Retrieval path (which fallback stages were used)
11
+
12
+ #### Scenario: Debug mode records search timing
13
+ - **WHEN** MNEMO_DEBUG=1 is set
14
+ - **AND** a search query is executed
15
+ - **THEN** the system SHALL log the query type, execution time, and result count
16
+
17
+ #### Scenario: Non-debug mode skips recording
18
+ - **WHEN** MNEMO_DEBUG is not set or is 0
19
+ - **AND** a query is executed
20
+ - **THEN** no performance metrics SHALL be recorded
21
+ - **AND** no debug logs SHALL be emitted
22
+
23
+ ### Requirement: Retrieval path is tracked
24
+ The system SHALL record which retrieval stages were executed for each search query.
25
+
26
+ Retrieval stages:
27
+ - FTS5 (ftsCandidates)
28
+ - LIKE fallback (likeFallback)
29
+ - Character overlap fallback (charOverlapFallback)
30
+ - Category inference fallback (categoryInferFallback)
31
+ - Trust fallback (trustFallback)
32
+
33
+ #### Scenario: Search hits FTS5 path
34
+ - **WHEN** a search query matches via FTS5
35
+ - **THEN** the logged retrieval path SHALL include "FTS5"
36
+ - **AND** SHALL NOT include subsequent fallback stages
37
+
38
+ #### Scenario: Search falls through to LIKE
39
+ - **WHEN** a search query finds no FTS5 results but matches via LIKE
40
+ - **THEN** the logged retrieval path SHALL include "FTS5,LIKE"
41
+
42
+ ### Requirement: Cache statistics are aggregated
43
+ The system SHALL maintain aggregate cache statistics over the process lifetime.
44
+
45
+ Aggregated metrics:
46
+ - totalQueries: total number of queries processed
47
+ - cacheHits: number of queries served from cache
48
+ - cacheMisses: number of queries executed against database
49
+ - avgQueryTime: average execution time for cache misses (ms)
50
+ - totalTimeSaved: estimated time saved by cache hits (sum of miss avg × hit count)
51
+
52
+ #### Scenario: Cache stats are queryable
53
+ - **WHEN** the system has processed multiple queries
54
+ - **AND** MNEMO_DEBUG=1 is set
55
+ - **THEN** a special internal call SHALL return the aggregated statistics