@morningljn/mnemo 0.1.3 → 0.1.4

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 (49) 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 +38 -26
  12. package/dist/retriever.js.map +1 -1
  13. package/dist/server.js +7 -0
  14. package/dist/server.js.map +1 -1
  15. package/docs/superpowers/plans/2026-05-15-mnemo-mcp.md +1154 -0
  16. package/docs/superpowers/plans/2026-05-16-mnemo-query-cache.md +613 -0
  17. package/docs/superpowers/plans/2026-05-16-retrieval-and-injection-optimization.md +770 -0
  18. package/openspec/changes/archive/2026-05-15-mnemo-mcp/.openspec.yaml +2 -0
  19. package/openspec/changes/archive/2026-05-15-mnemo-mcp/design.md +83 -0
  20. package/openspec/changes/archive/2026-05-15-mnemo-mcp/proposal.md +32 -0
  21. package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/fact-retrieval/spec.md +75 -0
  22. package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/fact-store/spec.md +83 -0
  23. package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/mcp-server/spec.md +34 -0
  24. package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/security/spec.md +37 -0
  25. package/openspec/changes/archive/2026-05-15-mnemo-mcp/tasks.md +44 -0
  26. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/.openspec.yaml +2 -0
  27. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/design.md +96 -0
  28. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/proposal.md +29 -0
  29. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/specs/batch-operations/spec.md +42 -0
  30. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/specs/perf-metrics/spec.md +55 -0
  31. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/specs/query-cache/spec.md +65 -0
  32. package/openspec/changes/archive/2026-05-16-mnemo-query-cache/tasks.md +45 -0
  33. package/openspec/changes/retrieval-and-injection-optimization/.openspec.yaml +2 -0
  34. package/openspec/changes/retrieval-and-injection-optimization/design.md +117 -0
  35. package/openspec/changes/retrieval-and-injection-optimization/proposal.md +30 -0
  36. package/openspec/changes/retrieval-and-injection-optimization/specs/adaptive-scoring/spec.md +43 -0
  37. package/openspec/changes/retrieval-and-injection-optimization/specs/injection-protocol/spec.md +48 -0
  38. package/openspec/changes/retrieval-and-injection-optimization/specs/mcp-resources/spec.md +39 -0
  39. package/openspec/changes/retrieval-and-injection-optimization/specs/query-refinement/spec.md +39 -0
  40. package/openspec/changes/retrieval-and-injection-optimization/tasks.md +33 -0
  41. package/openspec/config.yaml +20 -0
  42. package/package.json +1 -1
  43. package/src/init.ts +17 -9
  44. package/src/refine.ts +127 -0
  45. package/src/resources.ts +78 -0
  46. package/src/retriever.ts +40 -26
  47. package/src/server.ts +8 -0
  48. package/tests/refine.test.ts +52 -0
  49. package/tests/resource.test.ts +62 -0
@@ -0,0 +1,65 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: Query results are cached with TTL
4
+ The system SHALL cache query results and return cached data for identical queries within the TTL period.
5
+
6
+ Cache key:
7
+ - SHALL be derived from query string, category, limit, and minTrust parameters
8
+ - SHALL NOT include trust_score or updated_at values (these change frequently)
9
+
10
+ Cache behavior:
11
+ - Cache TTL SHALL be 60 seconds by default
12
+ - Cache SHALL be stored in process memory (Map)
13
+ - Cache SHALL be cleared on any write operation (add/update/remove)
14
+
15
+ #### Scenario: Identical query returns cached result
16
+ - **WHEN** a search query with parameters {query: "用户偏好", category: "identity", limit: 10} is executed
17
+ - **AND** the same query is executed again within 60 seconds
18
+ - **THEN** the second call SHALL return the cached results
19
+ - **AND** no database query SHALL be executed
20
+
21
+ #### Scenario: Cache cleared on fact addition
22
+ - **WHEN** a new fact is added via fact_store
23
+ - **THEN** all cached query results SHALL be invalidated
24
+ - **AND** the next query SHALL hit the database
25
+
26
+ #### Scenario: Cache entry expires after TTL
27
+ - **WHEN** a cached query result ages beyond 60 seconds
28
+ - **THEN** the next identical query SHALL execute against the database
29
+ - **AND** generate a new cache entry
30
+
31
+ ### Requirement: Cache supports all search actions
32
+ The system SHALL apply caching to all read-only fact_store actions.
33
+
34
+ Cached actions:
35
+ - search
36
+ - probe
37
+ - related
38
+ - reason
39
+ - contradict
40
+ - list
41
+
42
+ Non-cached actions:
43
+ - add
44
+ - update
45
+ - remove
46
+
47
+ #### Scenario: Probe query is cached
48
+ - **WHEN** a probe action is executed with entity "TypeScript"
49
+ - **AND** the same probe is executed again within TTL
50
+ - **THEN** the second call SHALL return cached results
51
+
52
+ ### Requirement: Cache hit/miss is trackable
53
+ The system SHALL record cache statistics when debug mode is enabled.
54
+
55
+ Debug metrics:
56
+ - Total queries processed
57
+ - Cache hits and misses
58
+ - Cache hit ratio (hits / total)
59
+ - Average query execution time (cache miss only)
60
+
61
+ #### Scenario: Debug mode logs cache metrics
62
+ - **WHEN** MNEMO_DEBUG=1 is set
63
+ - **AND** a query is executed
64
+ - **THEN** the system SHALL log whether the query was a cache hit or miss
65
+ - **AND** SHALL include execution time for cache misses
@@ -0,0 +1,45 @@
1
+ ## 1. Query Cache Layer
2
+
3
+ - [ ] 1.1 Create `src/cache.ts` with `QueryCache` class
4
+ - [ ] 1.2 Implement cache key generation: hash of query + category + limit + minTrust
5
+ - [ ] 1.3 Implement `get(key)` and `set(key, results)` with TTL (60s)
6
+ - [ ] 1.4 Implement `clear()` for cache invalidation on writes
7
+ - [ ] 1.5 Integrate cache into `FactRetriever.search()` — check cache before DB query
8
+ - [ ] 1.6 Integrate cache into `FactRetriever.probe()`, `related()`, `reason()`, `contradict()`
9
+ - [ ] 1.7 Call `cache.clear()` on add/update/remove operations in server.ts
10
+
11
+ ## 2. Batch Operations
12
+
13
+ - [ ] 2.1 Update `FactStoreArgs` type in `src/types.ts`: `content` accepts `string | string[]`
14
+ - [ ] 2.2 Update `fact_id` type: accepts `number | number[]` for batch remove
15
+ - [ ] 2.3 Implement batch add handler in `server.ts`: iterate array, call `store.addFact()` per item
16
+ - [ ] 2.4 Implement batch remove handler in `server.ts`: iterate array, call `store.removeFact()` per item
17
+ - [ ] 2.5 Update response format: return array of individual results for batch operations
18
+ - [ ] 2.6 Ensure backward compatibility: single string/number still works
19
+
20
+ ## 3. Performance Metrics
21
+
22
+ - [ ] 3.1 Create `src/metrics.ts` with `PerfMetrics` class
23
+ - [ ] 3.2 Implement query timing: record start/end timestamps around retriever calls
24
+ - [ ] 3.3 Implement retrieval path tracking: log which fallback stages were executed
25
+ - [ ] 3.4 Implement cache hit/miss tracking
26
+ - [ ] 3.5 Implement aggregate statistics: totalQueries, cacheHits, cacheMisses, avgQueryTime
27
+ - [ ] 3.6 Add `MNEMO_DEBUG` env var check: only record metrics when set to "1"
28
+ - [ ] 3.7 Add debug log output: print metrics after each query when debug enabled
29
+
30
+ ## 4. Startup Optimization
31
+
32
+ - [ ] 4.1 Remove `auditContradictions()` from startup path in `server.ts`
33
+ - [ ] 4.2 Remove `decayTrustScores()` from startup path in `server.ts`
34
+ - [ ] 4.3 Add lazy initialization: first tool call triggers audit + decay if not yet run
35
+ - [ ] 4.4 Add flag to prevent duplicate lazy initialization
36
+
37
+ ## 5. Testing & Verification
38
+
39
+ - [ ] 5.1 Verify identical query returns cached result within TTL
40
+ - [ ] 5.2 Verify cache is cleared after fact addition
41
+ - [ ] 5.3 Verify batch add works with string array
42
+ - [ ] 5.4 Verify batch remove works with number array
43
+ - [ ] 5.5 Verify single fact add remains backward compatible
44
+ - [ ] 5.6 Verify debug mode logs query timing and cache stats
45
+ - [ ] 5.7 Verify startup is faster (no immediate audit/decay)
@@ -0,0 +1,2 @@
1
+ schema: spec-driven
2
+ created: 2026-05-16
@@ -0,0 +1,117 @@
1
+ ## Context
2
+
3
+ mnemo-mcp 是纯全局记忆 MCP server,服务于 Claude Code / Codex 等客户端。当前架构:
4
+
5
+ ```
6
+ 用户消息 → CLAUDE.md 规则触发 fact_store(search) → MCP tool call → FTS5 检索 → 注入 context
7
+ ```
8
+
9
+ 当前问题:
10
+ - **每条消息**都触发一次 search MCP 调用,90%+ 的消息与记忆无关(如"git status""运行测试")
11
+ - 查询直接使用原始用户消息,"帮我重构 auth 模块"中的"帮我""重构"是噪音 token
12
+ - FTS/Jaccard 权重固定 0.5/0.5,短查询和长查询用同一套评分
13
+ - Category 多样性策略硬性限制每个 category 只取 top1,general 类事实被误伤
14
+
15
+ 事实库现状:70+ 条全局事实,5 个 category(identity/coding_style/tool_pref/workflow/general)。
16
+
17
+ ## Goals / Non-Goals
18
+
19
+ **Goals:**
20
+ - 检索准确率:减少噪音召回,提高 top-K 结果与查询的语义相关性
21
+ - 注入效率:将 MCP 调用频率从"每条消息"降至"会话预热 + 按需补充"
22
+ - 向后兼容:所有变更对现有 tool 调用接口透明
23
+
24
+ **Non-Goals:**
25
+ - 不引入向量数据库或 embedding 模型(保持零依赖、纯本地运行)
26
+ - 不做项目记忆(scope 明确只做全局记忆)
27
+ - 不改 MCP 协议本身,只利用现有 Resource + Tool 机制
28
+
29
+ ## Decisions
30
+
31
+ ### D1: MCP Resource 暴露全局记忆
32
+
33
+ **选择**:为每个 category 注册 MCP Resource URI(`mnemo://global/{category}`),返回该 category 下 trust 排名 top-N 的事实摘要。
34
+
35
+ **替代方案**:
36
+ - A) SessionStart hook 触发 bulk search → 需要客户端支持,且仍有 MCP 调用开销
37
+ - B) 静态文件注入 → 无法动态更新
38
+
39
+ **理由**:MCP Resource 是协议原生的"客户端主动拉取"机制。Claude Code 在 session 启动时自动拉取所有 MCP Resource 并注入 system context。这实现了**零 MCP tool call 的预热注入**——LLM 直接在 system prompt 中看到记忆,不需要主动调 search。
40
+
41
+ Resource URI 设计:
42
+ ```
43
+ mnemo://global/identity → identity 类 top-10
44
+ mnemo://global/coding_style → coding_style 类 top-10
45
+ mnemo://global/tool_pref → tool_pref 类 top-10
46
+ mnemo://global/workflow → workflow 类 top-10
47
+ mnemo://global/general → general 类 top-10
48
+ ```
49
+
50
+ 每个 Resource 返回 JSON 格式,客户端(Claude Code)会自动序列化为文本注入。
51
+
52
+ ### D2: 查询提炼层
53
+
54
+ **选择**:在 `search()` 入口前加 `refineQuery()` 纯函数,做 token 级过滤。
55
+
56
+ **提炼策略**:
57
+ 1. 移除中文虚词(已有 `CN_STOP_WORDS`,复用)
58
+ 2. 移除动作词("帮我""看看""做一下""帮我看看"等)
59
+ 3. 提取实体词(引号内容、大写开头词、书名号内容)
60
+ 4. 如果提炼后为空(纯操作指令如"运行测试"),返回空查询 → 跳过检索
61
+
62
+ **不选 LLM-based 查询重写**:引入模型调用成本,违反零依赖原则。
63
+
64
+ ### D3: 动态评分权重
65
+
66
+ **选择**:根据查询 token 数动态调整 FTS/Jaccard 权重。
67
+
68
+ ```typescript
69
+ // 短查询(≤3 token)→ 更依赖 FTS 精确匹配
70
+ // 长查询(>3 token)→ 更依赖 Jaccard 语义覆盖
71
+ const ftsWeight = tokenCount <= 3 ? 0.7 : 0.3
72
+ const jaccardWeight = tokenCount <= 3 ? 0.3 : 0.7
73
+ ```
74
+
75
+ **不选机器学习权重**:过重,事实库规模不够训练。
76
+
77
+ ### D4: 多样性策略修复
78
+
79
+ **选择**:去掉硬性 category-per-top1 限制,改为 relevance score 去重——如果两条事实的 Jaccard 相似度 > 0.7(内容高度重叠),只保留评分高的那条。
80
+
81
+ **理由**:全局记忆 5 个 category,general 占比通常 > 50%。硬性去重导致 general 只取 1 条,丢掉大量有效记忆。
82
+
83
+ ### D5: 相关性门控
84
+
85
+ **选择**:在 trust 阈值(0.3)之上增加 relevance score 阈值(0.15)。score < 0.15 的结果不返回。
86
+
87
+ **理由**:trust 是事实质量的静态指标,relevance 是与当前查询的匹配度。两者必须同时满足。
88
+
89
+ ### D6: 注入协议
90
+
91
+ **选择**:将 CLAUDE.md 规则 1 从"每条消息都搜"改为:
92
+
93
+ ```
94
+ 会话启动 → MCP Resource 自动预热(系统层,LLM 不参与)
95
+ 用户消息 → LLM 判断是否需要补充查询记忆
96
+ ├─ 涉及个人偏好/习惯/工具选择 → search
97
+ ├─ 纯操作/技术问题 → 不查
98
+ └─ 模糊 → 可查可不查(偏向不查)
99
+ ```
100
+
101
+ **风险**:LLM 可能判断失误,遗漏该查的场景。但 Resource 预热已经覆盖了高频记忆,遗漏的主要是边缘场景。
102
+
103
+ ## Risks / Trade-offs
104
+
105
+ | Risk | Mitigation |
106
+ |------|-----------|
107
+ | Resource 预热数据量过大占用 context window | 每个 category 限 top-10,总共 ≤50 条,约 2000 token |
108
+ | LLM 判断"不需要查"导致遗漏 | Resource 预热覆盖 80%+ 高频场景;边缘 case 通过 fact_feedback 自然淘汰 |
109
+ | 查询提炼过度过滤导致召回不足 | 保留原始查询作为 fallback(提炼为空时用原始查询) |
110
+ | 动态权重在中等长度查询时表现不稳定 | token 阈值 3 是经验值,可通过 fact_feedback 数据调优 |
111
+ | Content-based 去重(Jaccard > 0.7)可能误判 | 去重只影响 top-K 选择,不影响存储;误判只是多返回一条 |
112
+
113
+ ## Open Questions
114
+
115
+ - Resource 返回格式:JSON 数组 vs Markdown 文本?Claude Code 如何渲染 MCP Resource 内容?
116
+ - 是否需要 `mnemo://global/all` 聚合 Resource,还是 5 个独立 Resource 分别拉取?
117
+ - CLAUDE.md 规则变更需要用户手动更新,是否提供自动迁移脚本?
@@ -0,0 +1,30 @@
1
+ ## Why
2
+
3
+ mnemo-mcp 作为纯全局记忆系统(不含项目记忆),当前检索和注入机制存在两个核心问题:**检索准确率不足**(查询直接用原始用户消息、评分权重静态固定、category 多样性策略误伤高密度类),以及**注入成本过高**(CLAUDE.md 规则要求每条用户消息都触发一次 `fact_store(search)` MCP 调用,即使消息与记忆完全无关)。随着事实库增长到 70+ 条,这两个问题将导致噪音召回增加和 token 浪费加剧。
4
+
5
+ ## What Changes
6
+
7
+ - 新增 **MCP Resource** 端点,暴露 5 个全局 category 的 top-N 高信任记忆,实现会话启动时零成本预热注入
8
+ - 新增**查询提炼层**(query refinement),从用户消息中提取记忆相关关键词,过滤动作词和无关 token
9
+ - **评分公式动态化**:根据查询长度和类型自适应调整 FTS/Jaccard 权重比例
10
+ - **注入时机重构**:从"每条消息都搜"改为"MCP Resource 预热 + 按需补充",需配合 CLAUDE.md 规则变更
11
+ - 修复 **category 多样性策略**:对高密度 category(如 general)允许多条入选,改为基于相关性去重而非硬性 category 去重
12
+ - 新增**相关性门控**:检索结果在 trust 阈值之上增加 relevance score 阈值过滤
13
+
14
+ ## Capabilities
15
+
16
+ ### New Capabilities
17
+ - `mcp-resources`: 通过 MCP Resource 协议暴露全局记忆,支持会话预热零调用注入
18
+ - `query-refinement`: 用户消息 → 记忆关键词提炼,过滤动作词/虚词/无关 token
19
+ - `adaptive-scoring`: 查询长度自适应的 FTS/Jaccard 权重分配 + relevance 门控
20
+ - `injection-protocol`: 优化后的注入协议定义(何时查、何时注入、何时跳过),需同步更新 CLAUDE.md 规则
21
+
22
+ ### Modified Capabilities
23
+ <!-- 无既有 spec 需要修改 -->
24
+
25
+ ## Impact
26
+
27
+ - `src/server.ts`:新增 Resource handler,修改 search 入口加查询提炼
28
+ - `src/retriever.ts`:评分公式动态化、多样性策略修复、relevance 门控
29
+ - `CLAUDE.md`(用户侧配置):规则 1 从"每条消息都搜"改为"会话预热 + 按需触发"
30
+ - 向后兼容:所有变更对现有 fact_store/fact_feedback tool 调用透明,不影响已有客户端
@@ -0,0 +1,43 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: 查询长度自适应权重
4
+ 系统 SHALL 根据查询 token 数动态调整 FTS 和 Jaccard 的权重比例。
5
+
6
+ - 短查询(token 数 ≤ 3):FTS 权重 0.7,Jaccard 权重 0.3(偏精确匹配)
7
+ - 长查询(token 数 > 3):FTS 权重 0.3,Jaccard 权重 0.7(偏语义覆盖)
8
+
9
+ #### Scenario: 短查询使用高 FTS 权重
10
+ - **WHEN** 查询为 "深色主题"(2 个 token)
11
+ - **THEN** 评分公式中 FTS 权重为 0.7,Jaccard 权重为 0.3
12
+
13
+ #### Scenario: 长查询使用高 Jaccard 权重
14
+ - **WHEN** 查询为 "为什么 TypeScript 编译报错找不到模块"(7 个 token)
15
+ - **THEN** 评分公式中 FTS 权重为 0.3,Jaccard 权重为 0.7
16
+
17
+ ### Requirement: 相关性评分门控
18
+ 系统 SHALL 在 trust 阈值之上增加 relevance score 阈值。综合评分(relevance × trustScore × temporalDecay)低于 0.15 的结果 SHALL 被过滤。
19
+
20
+ #### Scenario: 低相关性结果被过滤
21
+ - **WHEN** 一条事实 trust_score=0.9 但与查询的 relevance score=0.1
22
+ - **THEN** 综合评分 = 0.1 × 0.9 = 0.09 < 0.15,该结果不返回
23
+
24
+ #### Scenario: 高相关性结果通过
25
+ - **WHEN** 一条事实 trust_score=0.4 且与查询的 relevance score=0.8
26
+ - **THEN** 综合评分 = 0.8 × 0.4 = 0.32 > 0.15,该结果正常返回
27
+
28
+ ### Requirement: 内容相似度去重
29
+ 系统 SHALL 对检索结果中内容高度重叠的事实进行去重——两条事实的 Jaccard 相似度 > 0.7 时,只保留评分高的那条。
30
+
31
+ 替换现有的 category-per-top1 硬性去重策略。
32
+
33
+ #### Scenario: 相似事实去重
34
+ - **WHEN** 检索结果中有两条事实内容 Jaccard 相似度 > 0.7
35
+ - **THEN** 只保留评分高的那条,另一条被移除
36
+
37
+ #### Scenario: 不同 category 的不同事实不被误去重
38
+ - **WHEN** 一条 identity 事实和一条 coding_style 事实内容不相似(Jaccard < 0.7)
39
+ - **THEN** 两者都保留在结果中
40
+
41
+ #### Scenario: general 类允许返回多条
42
+ - **WHEN** general category 有 5 条高相关性事实且内容不重复
43
+ - **THEN** 5 条都保留在结果中(不再受 category-per-top1 限制)
@@ -0,0 +1,48 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: 会话预热注入协议
4
+ 系统 SHALL 通过 MCP Resource 机制实现会话启动时的自动预热注入,无需 LLM 主动调用 tool。
5
+
6
+ - 客户端在 session 启动时自动拉取所有 `mnemo://global/*` Resource
7
+ - Resource 内容作为 system context 注入,LLM 可直接访问
8
+ - 预热注入覆盖 identity/coding_style/tool_pref/workflow/general 全部 5 个分类
9
+
10
+ #### Scenario: 新会话自动获得全局记忆
11
+ - **WHEN** Claude Code 启动新 session
12
+ - **THEN** 系统自动拉取 5 个 category Resource,记忆内容出现在 system context 中
13
+
14
+ #### Scenario: 预热后 LLM 不需要主动 search 即可回答偏好问题
15
+ - **WHEN** 用户问 "我喜欢什么编辑器" 且预热 Resource 中包含 "用户偏好 VS Code 编辑器"
16
+ - **THEN** LLM 直接从预热 context 回答,无需调用 fact_store(search)
17
+
18
+ ### Requirement: 按需补充查询触发规则
19
+ 系统 SHALL 定义何时触发补充 fact_store(search) 调用的规则,替代当前"每条消息都搜"的模式。
20
+
21
+ 触发条件(满足任一即触发):
22
+ - 用户消息包含明确的记忆查询意图("我记得说过""我之前说过""按我的习惯")
23
+ - 用户消息涉及技术选型/工具选择且预热中未覆盖
24
+ - 用户显式要求记住新信息(触发 add 而非 search)
25
+
26
+ 不触发条件:
27
+ - 纯操作指令("创建文件""运行测试""git commit")
28
+ - 通用技术问题("怎么用 Promise""React hooks 语法")
29
+ - 代码审查/解释请求
30
+
31
+ #### Scenario: 技术选型触发补充查询
32
+ - **WHEN** 用户说 "用 React 还是 Vue 开发这个项目" 且预热中无相关偏好
33
+ - **THEN** 触发 fact_store(search, query="React Vue 前端框架 偏好")
34
+
35
+ #### Scenario: 纯操作指令不触发
36
+ - **WHEN** 用户说 "运行测试"
37
+ - **THEN** 不触发 fact_store(search),节省 MCP 调用
38
+
39
+ #### Scenario: 明确记忆查询触发
40
+ - **WHEN** 用户说 "我之前说不喜欢什么颜色来着"
41
+ - **THEN** 触发 fact_store(search, query="不喜欢 颜色")
42
+
43
+ ### Requirement: 注入协议配置说明
44
+ 系统 SHALL 在 README 或文档中提供更新后的 CLAUDE.md 规则模板,用户可直接复制使用。
45
+
46
+ #### Scenario: 用户更新 CLAUDE.md 规则
47
+ - **WHEN** 用户按文档更新 CLAUDE.md 中的记忆系统使用规则
48
+ - **THEN** 规则 1 从"每条消息都搜"变为"会话预热 + 按需触发"
@@ -0,0 +1,39 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: MCP Resource 暴露全局分类记忆
4
+ 系统 SHALL 为每个全局 category 注册 MCP Resource URI,返回该 category 下按 trust 排序的 top-N 事实摘要。
5
+
6
+ - URI 格式:`mnemo://global/{category}`,其中 category 为 identity / coding_style / tool_pref / workflow / general
7
+ - 每个 Resource 返回该 category 下 trust_score 最高的前 10 条事实
8
+ - 返回格式为 JSON 数组,每条包含 fact_id、content、trust_score
9
+ - Resource 内容在服务启动时计算并缓存,写操作(add/update/remove)时失效重算
10
+
11
+ #### Scenario: 客户端拉取 identity Resource
12
+ - **WHEN** MCP 客户端请求 `mnemo://global/identity`
13
+ - **THEN** 返回 identity category 下 trust_score DESC 排序的前 10 条事实 JSON 数组
14
+
15
+ #### Scenario: 写操作后 Resource 刷新
16
+ - **WHEN** 通过 fact_store 执行 add/update/remove 操作
17
+ - **THEN** 所有 Resource 缓存失效,下次拉取时重新从 DB 计算
18
+
19
+ #### Scenario: 空 category 返回空数组
20
+ - **WHEN** 某个 category 下没有任何事实
21
+ - **THEN** 对应 Resource 返回空 JSON 数组 `[]`
22
+
23
+ ### Requirement: MCP Resource 列表发现
24
+ 系统 SHALL 在 MCP `resources/list` 响应中暴露所有 5 个全局 category Resource,包含 name 和 description。
25
+
26
+ #### Scenario: 客户端发现可用 Resource
27
+ - **WHEN** MCP 客户端调用 `resources/list`
28
+ - **THEN** 响应包含 5 个 Resource 条目,每个的 URI 为 `mnemo://global/{category}`,name 为分类名,description 说明内容
29
+
30
+ ### Requirement: Resource 缓存生命周期
31
+ 系统 SHALL 维护 Resource 缓存,避免每次拉取都查询数据库。
32
+
33
+ - 缓存类型:进程内 Map,key 为 category
34
+ - 缓存失效:任何写操作(add/update/remove)触发全部缓存清空
35
+ - 首次访问时惰性计算
36
+
37
+ #### Scenario: 连续拉取命中缓存
38
+ - **WHEN** 短时间内连续两次拉取同一 category Resource,中间无写操作
39
+ - **THEN** 第二次直接返回缓存结果,不触发 DB 查询
@@ -0,0 +1,39 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: 查询提炼函数
4
+ 系统 SHALL 提供 `refineQuery(rawQuery: string): string | null` 纯函数,从用户原始消息中提取记忆相关关键词。
5
+
6
+ 提炼流程:
7
+ 1. 分词(按空格 + 中文字符边界)
8
+ 2. 过滤中文虚词(复用 CN_STOP_WORDS)
9
+ 3. 过滤动作词("帮我""看看""做一下""帮我看看""能不能""为什么""怎么""是什么")
10
+ 4. 提取高信号 token(引号内容、大写开头连续词、书名号内容)
11
+ 5. 剩余 token 作为提炼结果
12
+ 6. 如果提炼后为空(纯操作指令),返回 null
13
+
14
+ #### Scenario: 包含实体的查询成功提炼
15
+ - **WHEN** 输入 "帮我用 TypeScript 重构 auth 模块"
16
+ - **THEN** 提炼结果包含 "TypeScript" "auth" 等关键词(过滤掉"帮我""重构""模块")
17
+
18
+ #### Scenario: 纯操作指令返回 null
19
+ - **WHEN** 输入 "运行测试" 或 "git status"
20
+ - **THEN** 返回 null,表示不需要检索记忆
21
+
22
+ #### Scenario: 引号内容优先保留
23
+ - **WHEN** 输入 "我喜欢「深色主题」"
24
+ - **THEN** 提炼结果包含 "深色主题"
25
+
26
+ #### Scenario: 提炼结果集成到 search
27
+ - **WHEN** search() 接收到原始查询
28
+ - **THEN** 先调用 refineQuery();若返回 null 则直接返回空结果;若返回非空则用提炼结果作为 FTS5 查询词
29
+
30
+ ### Requirement: 提炼为空时的 fallback
31
+ 系统 SHALL 在 refineQuery 返回 null 时保留原始查询作为 fallback,由调用方决定是否跳过检索。
32
+
33
+ #### Scenario: 调用方选择跳过
34
+ - **WHEN** refineQuery 返回 null 且调用方为自动触发(CLAUDE.md 规则 1)
35
+ - **THEN** 跳过检索,返回空结果
36
+
37
+ #### Scenario: 调用方显式搜索
38
+ - **WHEN** 用户显式调用 `fact_store(action="search", query="运行测试")`
39
+ - **THEN** 即使 refineQuery 返回 null,仍用原始查询执行检索
@@ -0,0 +1,33 @@
1
+ ## 1. MCP Resource 注册与缓存
2
+
3
+ - [ ] 1.1 在 `src/server.ts` 中注册 5 个 MCP Resource URI(`mnemo://global/{identity,coding_style,tool_pref,workflow,general}`),每个 Resource 返回对应 category 的 top-10 事实 JSON 数组
4
+ - [ ] 1.2 实现 Resource 缓存层:进程内 Map,写操作时清空,首次访问惰性计算
5
+ - [ ] 1.3 在 `resources/list` 响应中暴露所有 5 个 Resource 条目(含 name + description)
6
+ - [ ] 1.4 验证:启动 server 后用 MCP Inspector 拉取 Resource 确认返回格式正确
7
+
8
+ ## 2. 查询提炼层
9
+
10
+ - [ ] 2.1 在 `src/retriever.ts` 中实现 `refineQuery(rawQuery: string): string | null` 纯函数,过滤虚词 + 动作词 + 提取高信号 token
11
+ - [ ] 2.2 修改 `search()` 入口:先调 refineQuery(),返回 null 时直接返回空结果;返回非空时用提炼结果作为查询词
12
+ - [ ] 2.3 保留原始查询 fallback:当用户显式调用 search action(非自动触发)时,即使 refineQuery 返回 null 也用原始查询
13
+ - [ ] 2.4 验证:测试 "帮我用 TypeScript 重构 auth 模块" → 提炼出 "TypeScript auth";"运行测试" → 返回 null
14
+
15
+ ## 3. 动态评分权重
16
+
17
+ - [ ] 3.1 修改 `search()` 中的评分公式:根据 query token 数动态设置 ftsWeight/jaccardWeight(≤3 token → 0.7/0.3,>3 → 0.3/0.7)
18
+ - [ ] 3.2 新增 relevance score 阈值门控:综合评分 < 0.15 的结果不返回
19
+ - [ ] 3.3 替换 category-per-top1 硬性去重为 Jaccard 相似度去重(> 0.7 的只保留高分)
20
+ - [ ] 3.4 验证:general 类多条不同事实可以同时出现在结果中
21
+
22
+ ## 4. 注入协议文档
23
+
24
+ - [ ] 4.1 编写更新后的 CLAUDE.md 记忆系统使用规则模板(会话预热 + 按需触发 + 写入/反馈规则)
25
+ - [ ] 4.2 更新 README.md 添加注入协议说明和 CLAUDE.md 规则配置示例
26
+ - [ ] 4.3 验证:按新规则配置 CLAUDE.md 后启动 session,确认 Resource 自动拉取且无需每条消息都调 search
27
+
28
+ ## 5. 集成测试
29
+
30
+ - [ ] 5.1 编写 `tests/resource.test.ts`:验证 Resource 返回格式、缓存命中、写操作后缓存失效
31
+ - [ ] 5.2 编写 `tests/refine.test.ts`:验证查询提炼的虚词过滤、动作词剥离、null 返回场景
32
+ - [ ] 5.3 更新 `tests/retriever.test.ts`:验证动态权重、relevance 门控、Jaccard 去重
33
+ - [ ] 5.4 运行全量测试 `npm run test` 确认无回归
@@ -0,0 +1,20 @@
1
+ schema: spec-driven
2
+
3
+ # Project context (optional)
4
+ # This is shown to AI when creating artifacts.
5
+ # Add your tech stack, conventions, style guides, domain knowledge, etc.
6
+ # Example:
7
+ # context: |
8
+ # Tech stack: TypeScript, React, Node.js
9
+ # We use conventional commits
10
+ # Domain: e-commerce platform
11
+
12
+ # Per-artifact rules (optional)
13
+ # Add custom rules for specific artifacts.
14
+ # Example:
15
+ # rules:
16
+ # proposal:
17
+ # - Keep proposals under 500 words
18
+ # - Always include a "Non-goals" section
19
+ # tasks:
20
+ # - Break tasks into chunks of max 2 hours
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morningljn/mnemo",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Structured fact memory MCP server — SQLite + FTS5, trust scoring, entity graph, bilingual retrieval for Claude Code & Codex",
5
5
  "type": "module",
6
6
  "main": "dist/server.js",
package/src/init.ts CHANGED
@@ -23,19 +23,27 @@ const MEMORY_RULES = `
23
23
 
24
24
  你有 mnemo 记忆工具(fact_store / fact_feedback),必须按以下规则使用:
25
25
 
26
- ## 规则 1:搜索记忆(每次回复前)
27
- 收到用户消息后,你必须先调用 \`fact_store(action="search", query="<用户消息的关键词>")\` 检索相关记忆。
28
- query 必须从用户消息中提取关键词,不要用固定模板。例如:
29
- - 用户说"我叫什么" → query="姓名 名字 叫什么"
30
- - 用户说"我喜欢什么语言" → query="编程语言 偏好 喜欢"
31
- 搜索后根据结果自然回复,不要说"根据记忆"
32
-
33
- ## 规则 2:写入记忆
26
+ ## 规则 1:会话预热(自动)
27
+ 会话启动时,mnemo-mcp MCP Resource 会自动注入全局记忆到 system context。
28
+ 你不需要主动调用 fact_store(search) 来获取高频记忆。
29
+
30
+ ## 规则 2:按需补充查询
31
+ 仅在以下情况调用 \`fact_store(action="search")\`:
32
+ - 用户消息涉及个人偏好/习惯/工具选择且预热中未覆盖
33
+ - 用户明确查询记忆("我之前说过什么""按我的习惯")
34
+ - 技术选型时需要确认用户偏好
35
+
36
+ 不触发查询的情况:
37
+ - 纯操作指令("运行测试""git commit")
38
+ - 通用技术问题("Promise 怎么用")
39
+ - 代码审查/解释请求
40
+
41
+ ## 规则 3:写入记忆
34
42
  用户说"记住"、"记下来"时,调用 \`fact_store(action="add", content="...", category="...")\`。
35
43
  - 先 search 检查是否已有相似事实,有则 update
36
44
  - category:identity / coding_style / tool_pref / workflow / general
37
45
 
38
- ## 规则 3:反馈强化
46
+ ## 规则 4:反馈强化
39
47
  成功使用某条记忆时,调用 \`fact_feedback(action="helpful", fact_id=...)\`。
40
48
  `
41
49