@synth-coder/memhub 0.1.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/.eslintrc.cjs +46 -0
- package/.github/workflows/ci.yml +74 -0
- package/.iflow/commands/opsx-apply.md +152 -0
- package/.iflow/commands/opsx-archive.md +157 -0
- package/.iflow/commands/opsx-explore.md +173 -0
- package/.iflow/commands/opsx-propose.md +106 -0
- package/.iflow/skills/openspec-apply-change/SKILL.md +156 -0
- package/.iflow/skills/openspec-archive-change/SKILL.md +114 -0
- package/.iflow/skills/openspec-explore/SKILL.md +288 -0
- package/.iflow/skills/openspec-propose/SKILL.md +110 -0
- package/.prettierrc +11 -0
- package/README.md +171 -0
- package/README.zh-CN.md +169 -0
- package/dist/src/contracts/index.d.ts +7 -0
- package/dist/src/contracts/index.d.ts.map +1 -0
- package/dist/src/contracts/index.js +10 -0
- package/dist/src/contracts/index.js.map +1 -0
- package/dist/src/contracts/mcp.d.ts +194 -0
- package/dist/src/contracts/mcp.d.ts.map +1 -0
- package/dist/src/contracts/mcp.js +112 -0
- package/dist/src/contracts/mcp.js.map +1 -0
- package/dist/src/contracts/schemas.d.ts +1153 -0
- package/dist/src/contracts/schemas.d.ts.map +1 -0
- package/dist/src/contracts/schemas.js +246 -0
- package/dist/src/contracts/schemas.js.map +1 -0
- package/dist/src/contracts/types.d.ts +328 -0
- package/dist/src/contracts/types.d.ts.map +1 -0
- package/dist/src/contracts/types.js +30 -0
- package/dist/src/contracts/types.js.map +1 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +8 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/server/index.d.ts +5 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +5 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/server/mcp-server.d.ts +80 -0
- package/dist/src/server/mcp-server.d.ts.map +1 -0
- package/dist/src/server/mcp-server.js +263 -0
- package/dist/src/server/mcp-server.js.map +1 -0
- package/dist/src/services/index.d.ts +5 -0
- package/dist/src/services/index.d.ts.map +1 -0
- package/dist/src/services/index.js +5 -0
- package/dist/src/services/index.js.map +1 -0
- package/dist/src/services/memory-service.d.ts +105 -0
- package/dist/src/services/memory-service.d.ts.map +1 -0
- package/dist/src/services/memory-service.js +447 -0
- package/dist/src/services/memory-service.js.map +1 -0
- package/dist/src/storage/frontmatter-parser.d.ts +69 -0
- package/dist/src/storage/frontmatter-parser.d.ts.map +1 -0
- package/dist/src/storage/frontmatter-parser.js +207 -0
- package/dist/src/storage/frontmatter-parser.js.map +1 -0
- package/dist/src/storage/index.d.ts +6 -0
- package/dist/src/storage/index.d.ts.map +1 -0
- package/dist/src/storage/index.js +6 -0
- package/dist/src/storage/index.js.map +1 -0
- package/dist/src/storage/markdown-storage.d.ts +76 -0
- package/dist/src/storage/markdown-storage.d.ts.map +1 -0
- package/dist/src/storage/markdown-storage.js +193 -0
- package/dist/src/storage/markdown-storage.js.map +1 -0
- package/dist/src/utils/index.d.ts +5 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +5 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/slugify.d.ts +24 -0
- package/dist/src/utils/slugify.d.ts.map +1 -0
- package/dist/src/utils/slugify.js +56 -0
- package/dist/src/utils/slugify.js.map +1 -0
- package/docs/architecture.md +349 -0
- package/docs/contracts.md +119 -0
- package/docs/prompt-template.md +79 -0
- package/docs/proposal-close-gates.md +58 -0
- package/docs/tool-calling-policy.md +107 -0
- package/package.json +53 -0
- package/src/contracts/index.ts +12 -0
- package/src/contracts/mcp.ts +303 -0
- package/src/contracts/schemas.ts +311 -0
- package/src/contracts/types.ts +414 -0
- package/src/index.ts +8 -0
- package/src/server/index.ts +5 -0
- package/src/server/mcp-server.ts +352 -0
- package/src/services/index.ts +5 -0
- package/src/services/memory-service.ts +548 -0
- package/src/storage/frontmatter-parser.ts +243 -0
- package/src/storage/index.ts +6 -0
- package/src/storage/markdown-storage.ts +236 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/slugify.ts +63 -0
- package/test/contracts/schemas.test.ts +313 -0
- package/test/contracts/types.test.ts +21 -0
- package/test/frontmatter-parser-more.test.ts +94 -0
- package/test/server/mcp-server-internals.test.ts +257 -0
- package/test/server/mcp-server.test.ts +97 -0
- package/test/services/memory-service-edge.test.ts +248 -0
- package/test/services/memory-service.test.ts +279 -0
- package/test/storage/frontmatter-parser.test.ts +223 -0
- package/test/storage/markdown-storage.test.ts +217 -0
- package/test/storage/storage-edge.test.ts +238 -0
- package/test/utils/slugify-edge.test.ts +94 -0
- package/test/utils/slugify.test.ts +68 -0
- package/tsconfig.json +26 -0
- package/tsconfig.test.json +8 -0
- package/vitest.config.ts +27 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# MemHub 架构设计文档
|
|
2
|
+
|
|
3
|
+
## 概述
|
|
4
|
+
|
|
5
|
+
MemHub 是一个基于 Git 友好的记忆存储系统,使用 Markdown 格式存储记忆条目,通过 YAML Front Matter 存储元数据。它实现了 MCP (Model Context Protocol) Server,通过 stdio 进行通信。
|
|
6
|
+
|
|
7
|
+
## 设计原则
|
|
8
|
+
|
|
9
|
+
1. **Git 友好**: 所有数据以纯文本 Markdown 文件存储,天然支持版本控制
|
|
10
|
+
2. **人类可读**: 记忆条目可以直接用文本编辑器打开阅读
|
|
11
|
+
3. **简单优先**: 不使用数据库,避免复杂的迁移和锁定问题
|
|
12
|
+
4. **契约先行**: 接口和类型定义先于实现
|
|
13
|
+
5. **测试驱动**: 严格遵循 TDD (红-绿-重构)
|
|
14
|
+
|
|
15
|
+
## 系统架构
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
19
|
+
│ MCP Client │
|
|
20
|
+
│ (Claude Desktop, etc.) │
|
|
21
|
+
└──────────────────────┬──────────────────────────────────────┘
|
|
22
|
+
│ stdio
|
|
23
|
+
▼
|
|
24
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
25
|
+
│ MemHub MCP Server │
|
|
26
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
|
27
|
+
│ │ MCP Router │ │ Services │ │ Storage Layer │ │
|
|
28
|
+
│ │ │ │ │ │ │ │
|
|
29
|
+
│ │ - list_tools │ │ - create │ │ - read memory │ │
|
|
30
|
+
│ │ - call_tool │ │ - read │ │ - write memory │ │
|
|
31
|
+
│ │ │ │ - update │ │ - search index │ │
|
|
32
|
+
│ │ │ │ - delete │ │ - list memories │ │
|
|
33
|
+
│ │ │ │ - search │ │ │ │
|
|
34
|
+
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
|
|
35
|
+
└──────────────────────┬──────────────────────────────────────┘
|
|
36
|
+
│
|
|
37
|
+
▼
|
|
38
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
39
|
+
│ Markdown Storage │
|
|
40
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
41
|
+
│ │ YYYY-MM-DD-title-slug.md │ │
|
|
42
|
+
│ │ ───────────────────────── │ │
|
|
43
|
+
│ │ --- │ │
|
|
44
|
+
│ │ id: uuid-v4 │ │
|
|
45
|
+
│ │ created_at: ISO8601 │ │
|
|
46
|
+
│ │ updated_at: ISO8601 │ │
|
|
47
|
+
│ │ tags: [tag1, tag2] │ │
|
|
48
|
+
│ │ category: string │ │
|
|
49
|
+
│ │ importance: 1-5 │ │
|
|
50
|
+
│ │ --- │ │
|
|
51
|
+
│ │ │ │
|
|
52
|
+
│ │ # Title │ │
|
|
53
|
+
│ │ │ │
|
|
54
|
+
│ │ Markdown content body... │ │
|
|
55
|
+
│ │ │ │
|
|
56
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
57
|
+
└─────────────────────────────────────────────────────────────┘
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 核心组件
|
|
61
|
+
|
|
62
|
+
### 1. MCP Server (src/server/mcp-server.ts)
|
|
63
|
+
|
|
64
|
+
- 入口点,处理 stdio 通信
|
|
65
|
+
- 实现 MCP 协议的生命周期管理
|
|
66
|
+
- 路由工具调用到对应的服务
|
|
67
|
+
|
|
68
|
+
### 2. Services (src/services/)
|
|
69
|
+
|
|
70
|
+
业务逻辑层,包含:
|
|
71
|
+
|
|
72
|
+
- **MemoryService**: 记忆 CRUD 操作
|
|
73
|
+
- **SearchService**: 搜索和过滤
|
|
74
|
+
- **IndexService**: 索引管理(可选,用于性能)
|
|
75
|
+
|
|
76
|
+
### 3. Storage Layer (src/storage/)
|
|
77
|
+
|
|
78
|
+
数据持久化层:
|
|
79
|
+
|
|
80
|
+
- **MarkdownStorage**: Markdown 文件读写
|
|
81
|
+
- **FrontMatterParser**: YAML Front Matter 解析
|
|
82
|
+
- **FileSystem**: 文件系统抽象(便于测试)
|
|
83
|
+
|
|
84
|
+
### 4. Contracts (src/contracts/)
|
|
85
|
+
|
|
86
|
+
类型定义和 Zod 契约:
|
|
87
|
+
|
|
88
|
+
- **types.ts**: TypeScript 类型
|
|
89
|
+
- **schemas.ts**: Zod 验证模式
|
|
90
|
+
- **mcp.ts**: MCP 协议相关类型
|
|
91
|
+
|
|
92
|
+
## 数据模型
|
|
93
|
+
|
|
94
|
+
### Memory Entry (记忆条目)
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
interface Memory {
|
|
98
|
+
// Identity
|
|
99
|
+
id: string; // UUID v4
|
|
100
|
+
|
|
101
|
+
// Metadata (YAML Front Matter)
|
|
102
|
+
createdAt: string; // ISO 8601
|
|
103
|
+
updatedAt: string; // ISO 8601
|
|
104
|
+
tags: string[]; // 标签数组
|
|
105
|
+
category: string; // 分类
|
|
106
|
+
importance: number; // 1-5 重要性等级
|
|
107
|
+
|
|
108
|
+
// Content (Markdown Body)
|
|
109
|
+
title: string; // Markdown H1 标题
|
|
110
|
+
content: string; // Markdown 正文
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### File Naming Convention
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
{YYYY-MM-DD}-{title-slug}.md
|
|
118
|
+
|
|
119
|
+
Examples:
|
|
120
|
+
- 2024-03-15-project-kickoff.md
|
|
121
|
+
- 2024-03-20-meeting-notes.md
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Markdown Format
|
|
125
|
+
|
|
126
|
+
```markdown
|
|
127
|
+
---
|
|
128
|
+
id: '550e8400-e29b-41d4-a716-446655440000'
|
|
129
|
+
created_at: '2024-03-15T10:30:00Z'
|
|
130
|
+
updated_at: '2024-03-15T14:20:00Z'
|
|
131
|
+
tags:
|
|
132
|
+
- project
|
|
133
|
+
- planning
|
|
134
|
+
category: 'work'
|
|
135
|
+
importance: 4
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
# Project Kickoff
|
|
139
|
+
|
|
140
|
+
Today we started the new project...
|
|
141
|
+
|
|
142
|
+
## Key Decisions
|
|
143
|
+
|
|
144
|
+
- Decision 1
|
|
145
|
+
- Decision 2
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## MCP Tools
|
|
149
|
+
|
|
150
|
+
### 1. `memory_create`
|
|
151
|
+
|
|
152
|
+
创建新记忆条目。
|
|
153
|
+
|
|
154
|
+
**Input:**
|
|
155
|
+
|
|
156
|
+
- title: string (required)
|
|
157
|
+
- content: string (required)
|
|
158
|
+
- tags?: string[]
|
|
159
|
+
- category?: string
|
|
160
|
+
- importance?: number (1-5, default: 3)
|
|
161
|
+
|
|
162
|
+
**Output:**
|
|
163
|
+
|
|
164
|
+
- id: string
|
|
165
|
+
- filePath: string
|
|
166
|
+
|
|
167
|
+
### 2. `memory_read`
|
|
168
|
+
|
|
169
|
+
读取记忆条目。
|
|
170
|
+
|
|
171
|
+
**Input:**
|
|
172
|
+
|
|
173
|
+
- id: string (required)
|
|
174
|
+
|
|
175
|
+
**Output:**
|
|
176
|
+
|
|
177
|
+
- Memory object
|
|
178
|
+
|
|
179
|
+
### 3. `memory_update`
|
|
180
|
+
|
|
181
|
+
更新记忆条目。
|
|
182
|
+
|
|
183
|
+
**Input:**
|
|
184
|
+
|
|
185
|
+
- id: string (required)
|
|
186
|
+
- title?: string
|
|
187
|
+
- content?: string
|
|
188
|
+
- tags?: string[]
|
|
189
|
+
- category?: string
|
|
190
|
+
- importance?: number
|
|
191
|
+
|
|
192
|
+
**Output:**
|
|
193
|
+
|
|
194
|
+
- updated Memory object
|
|
195
|
+
|
|
196
|
+
### 4. `memory_delete`
|
|
197
|
+
|
|
198
|
+
删除记忆条目。
|
|
199
|
+
|
|
200
|
+
**Input:**
|
|
201
|
+
|
|
202
|
+
- id: string (required)
|
|
203
|
+
|
|
204
|
+
**Output:**
|
|
205
|
+
|
|
206
|
+
- success: boolean
|
|
207
|
+
|
|
208
|
+
### 5. `memory_list`
|
|
209
|
+
|
|
210
|
+
列出记忆条目(支持过滤和分页)。
|
|
211
|
+
|
|
212
|
+
**Input:**
|
|
213
|
+
|
|
214
|
+
- category?: string
|
|
215
|
+
- tags?: string[]
|
|
216
|
+
- fromDate?: string (ISO 8601)
|
|
217
|
+
- toDate?: string (ISO 8601)
|
|
218
|
+
- limit?: number (default: 20, max: 100)
|
|
219
|
+
- offset?: number (default: 0)
|
|
220
|
+
|
|
221
|
+
**Output:**
|
|
222
|
+
|
|
223
|
+
- memories: Memory[]
|
|
224
|
+
- total: number
|
|
225
|
+
- hasMore: boolean
|
|
226
|
+
|
|
227
|
+
### 6. `memory_search`
|
|
228
|
+
|
|
229
|
+
全文搜索记忆。
|
|
230
|
+
|
|
231
|
+
**Input:**
|
|
232
|
+
|
|
233
|
+
- query: string (required)
|
|
234
|
+
- limit?: number (default: 10)
|
|
235
|
+
|
|
236
|
+
**Output:**
|
|
237
|
+
|
|
238
|
+
- results: SearchResult[]
|
|
239
|
+
- memory: Memory
|
|
240
|
+
- score: number
|
|
241
|
+
- matches: string[]
|
|
242
|
+
|
|
243
|
+
### 7. `memory_get_categories`
|
|
244
|
+
|
|
245
|
+
获取所有分类。
|
|
246
|
+
|
|
247
|
+
**Output:**
|
|
248
|
+
|
|
249
|
+
- categories: string[]
|
|
250
|
+
|
|
251
|
+
### 8. `memory_get_tags`
|
|
252
|
+
|
|
253
|
+
获取所有标签。
|
|
254
|
+
|
|
255
|
+
**Output:**
|
|
256
|
+
|
|
257
|
+
- tags: string[]
|
|
258
|
+
|
|
259
|
+
## 错误处理
|
|
260
|
+
|
|
261
|
+
所有错误使用标准 MCP 错误格式:
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
interface McpError {
|
|
265
|
+
code: number; // MCP error code
|
|
266
|
+
message: string; // Human readable message
|
|
267
|
+
data?: unknown; // Additional context
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
错误码定义:
|
|
272
|
+
|
|
273
|
+
- `INVALID_PARAMS`: 参数验证失败
|
|
274
|
+
- `NOT_FOUND`: 记忆条目不存在
|
|
275
|
+
- `STORAGE_ERROR`: 存储操作失败
|
|
276
|
+
- `INTERNAL_ERROR`: 内部错误
|
|
277
|
+
|
|
278
|
+
## 配置
|
|
279
|
+
|
|
280
|
+
通过环境变量配置:
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
MEMHUB_STORAGE_PATH=/path/to/memories # 存储目录,默认: ./memories
|
|
284
|
+
MEMHUB_LOG_LEVEL=info # 日志级别: debug, info, warn, error
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## 技术栈
|
|
288
|
+
|
|
289
|
+
- **Runtime**: Node.js 18+
|
|
290
|
+
- **Language**: TypeScript 5.3+
|
|
291
|
+
- **Protocol**: MCP (Model Context Protocol)
|
|
292
|
+
- **Transport**: stdio
|
|
293
|
+
- **Validation**: Zod
|
|
294
|
+
- **Testing**: Vitest (覆盖率 >= 80%)
|
|
295
|
+
- **Linting**: ESLint + Prettier
|
|
296
|
+
|
|
297
|
+
## 目录结构
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
memhub/
|
|
301
|
+
├── docs/
|
|
302
|
+
│ ├── architecture.md # 本文档
|
|
303
|
+
│ └── contracts.md # 契约文档
|
|
304
|
+
├── src/
|
|
305
|
+
│ ├── contracts/ # 类型和契约
|
|
306
|
+
│ │ ├── types.ts
|
|
307
|
+
│ │ ├── schemas.ts
|
|
308
|
+
│ │ └── mcp.ts
|
|
309
|
+
│ ├── server/ # MCP Server
|
|
310
|
+
│ │ └── mcp-server.ts
|
|
311
|
+
│ ├── services/ # 业务逻辑
|
|
312
|
+
│ │ ├── memory-service.ts
|
|
313
|
+
│ │ └── search-service.ts
|
|
314
|
+
│ ├── storage/ # 存储层
|
|
315
|
+
│ │ ├── markdown-storage.ts
|
|
316
|
+
│ │ └── frontmatter-parser.ts
|
|
317
|
+
│ └── utils/ # 工具函数
|
|
318
|
+
│ └── file-system.ts
|
|
319
|
+
├── test/ # 测试
|
|
320
|
+
│ ├── unit/
|
|
321
|
+
│ ├── integration/
|
|
322
|
+
│ └── fixtures/
|
|
323
|
+
├── .github/
|
|
324
|
+
│ └── workflows/
|
|
325
|
+
│ └── ci.yml # CI 配置
|
|
326
|
+
├── package.json
|
|
327
|
+
├── tsconfig.json
|
|
328
|
+
├── vitest.config.ts
|
|
329
|
+
├── .eslintrc.cjs
|
|
330
|
+
├── .prettierrc
|
|
331
|
+
└── README.md
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## 开发流程
|
|
335
|
+
|
|
336
|
+
1. **设计**: 先写架构文档和契约
|
|
337
|
+
2. **契约**: 定义 TypeScript 类型和 Zod Schema
|
|
338
|
+
3. **测试**: 编写红色测试(先失败)
|
|
339
|
+
4. **实现**: 编写最小实现使测试通过(绿色)
|
|
340
|
+
5. **重构**: 优化代码结构
|
|
341
|
+
6. **重复**: 循环 3-5 步
|
|
342
|
+
|
|
343
|
+
## 质量门禁
|
|
344
|
+
|
|
345
|
+
- ✅ ESLint 无错误
|
|
346
|
+
- ✅ Prettier 格式化检查通过
|
|
347
|
+
- ✅ TypeScript 严格类型检查通过
|
|
348
|
+
- ✅ 单元测试全部通过
|
|
349
|
+
- ✅ 代码覆盖率 >= 80%
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# MemHub 契约文档(vNext)
|
|
2
|
+
|
|
3
|
+
当前对外 MCP 工具仅保留两项:
|
|
4
|
+
|
|
5
|
+
1. `memory_load`(首轮)
|
|
6
|
+
2. `memory_update`(末轮)
|
|
7
|
+
|
|
8
|
+
目标是形成稳定闭环:**先读 STM,再回写 STM**。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1) memory_load
|
|
13
|
+
|
|
14
|
+
用于用户输入后第一轮主动加载短期记忆。
|
|
15
|
+
|
|
16
|
+
### 输入
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
interface MemoryLoadInput {
|
|
20
|
+
id?: string; // 指定单条记忆
|
|
21
|
+
sessionId?: string; // 会话 UUID
|
|
22
|
+
date?: string; // YYYY-MM-DD
|
|
23
|
+
query?: string; // 文本检索
|
|
24
|
+
category?: string;
|
|
25
|
+
tags?: string[];
|
|
26
|
+
limit?: number; // 默认 20
|
|
27
|
+
scope?: 'stm' | 'all'; // 默认 stm
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 输出
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
interface MemoryLoadOutput {
|
|
35
|
+
items: Memory[];
|
|
36
|
+
total: number;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 2) memory_update
|
|
43
|
+
|
|
44
|
+
用于本轮结束前主动回写记忆。
|
|
45
|
+
|
|
46
|
+
### 输入
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
type EntryType = 'decision' | 'preference' | 'knowledge' | 'todo' | 'state_change';
|
|
50
|
+
|
|
51
|
+
interface MemoryUpdateInput {
|
|
52
|
+
id?: string; // 有 id 则更新;无 id 则追加
|
|
53
|
+
sessionId?: string; // 无则服务端自动生成并返回
|
|
54
|
+
mode?: 'append' | 'upsert'; // 默认 append
|
|
55
|
+
entryType?: EntryType;
|
|
56
|
+
title?: string;
|
|
57
|
+
content: string; // 必填
|
|
58
|
+
tags?: string[];
|
|
59
|
+
category?: string;
|
|
60
|
+
importance?: number; // 1-5
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 输出
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
interface MemoryUpdateOutput {
|
|
68
|
+
id: string;
|
|
69
|
+
sessionId: string;
|
|
70
|
+
filePath: string;
|
|
71
|
+
created: boolean;
|
|
72
|
+
updated: boolean;
|
|
73
|
+
memory: Memory;
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Memory 数据模型
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
interface Memory {
|
|
83
|
+
id: string;
|
|
84
|
+
createdAt: string;
|
|
85
|
+
updatedAt: string;
|
|
86
|
+
sessionId?: string;
|
|
87
|
+
entryType?: EntryType;
|
|
88
|
+
tags: string[];
|
|
89
|
+
category: string;
|
|
90
|
+
importance: number;
|
|
91
|
+
title: string;
|
|
92
|
+
content: string;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 存储路径契约(并发安全)
|
|
99
|
+
|
|
100
|
+
为避免多个 CLI 同日写入冲突,采用分层目录:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
{storageRoot}/YYYY-MM-DD/{session_uuid}/{timestamp}-{slug}.md
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
例如:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
memories/2026-03-03/550e8400-e29b-41d4-a716-446655440111/2026-03-03T16-40-12-123Z-task-summary.md
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 调用策略契约(强建议)
|
|
115
|
+
|
|
116
|
+
- 用户输入后第一轮:调用 `memory_load`
|
|
117
|
+
- 最终输出前最后一轮:调用 `memory_update`
|
|
118
|
+
|
|
119
|
+
详细策略见:`docs/tool-calling-policy.md`
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Prompt Template for Coding Agents (MemHub STM Loop)
|
|
2
|
+
|
|
3
|
+
Use this template in Codex / Claude Code / OpenCode system prompt or task preamble.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## System Rule: STM Closed Loop
|
|
8
|
+
|
|
9
|
+
You are connected to MemHub MCP.
|
|
10
|
+
|
|
11
|
+
### Mandatory tool-calling behavior
|
|
12
|
+
|
|
13
|
+
1. **First round after receiving user prompt**: call `memory_load`.
|
|
14
|
+
2. **Final round before sending final answer**: call `memory_update`.
|
|
15
|
+
|
|
16
|
+
Do not skip these two calls unless tool is unavailable.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Tool usage policy
|
|
21
|
+
|
|
22
|
+
### On first round (`memory_load`)
|
|
23
|
+
|
|
24
|
+
Call with the most specific context available:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"sessionId": "<session-uuid-if-known>",
|
|
29
|
+
"scope": "stm",
|
|
30
|
+
"limit": 20
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If task is date-scoped, add `date: "YYYY-MM-DD"`.
|
|
35
|
+
If task is keyword-driven, add `query`.
|
|
36
|
+
|
|
37
|
+
### On final round (`memory_update`)
|
|
38
|
+
|
|
39
|
+
Write only high-value context likely reused in next 3 turns:
|
|
40
|
+
|
|
41
|
+
- decisions
|
|
42
|
+
- preference changes
|
|
43
|
+
- constraints
|
|
44
|
+
- task state changes
|
|
45
|
+
- reusable conclusions
|
|
46
|
+
|
|
47
|
+
Example:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"sessionId": "<session-uuid-if-known>",
|
|
52
|
+
"mode": "append",
|
|
53
|
+
"entryType": "decision",
|
|
54
|
+
"title": "Storage architecture decision",
|
|
55
|
+
"content": "Use date/session_uuid nested markdown storage to avoid multi-CLI collision.",
|
|
56
|
+
"tags": ["architecture", "storage", "stm"],
|
|
57
|
+
"category": "engineering",
|
|
58
|
+
"importance": 4
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Minimal execution checklist
|
|
65
|
+
|
|
66
|
+
- [ ] First tool call is `memory_load`
|
|
67
|
+
- [ ] Final tool call is `memory_update`
|
|
68
|
+
- [ ] `memory_update` content is concise and reusable
|
|
69
|
+
- [ ] No sensitive secrets in memory payload
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Failure fallback
|
|
74
|
+
|
|
75
|
+
If tool call fails:
|
|
76
|
+
|
|
77
|
+
1. continue task execution
|
|
78
|
+
2. mention memory tool failure briefly in internal reasoning/logs
|
|
79
|
+
3. still provide final user answer
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Proposal: Close Remaining Quality Gates (Phase 2)
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
Current implementation already has broad functionality and passing test suites, but quality gates are still blocked by:
|
|
5
|
+
|
|
6
|
+
1. ESLint configuration/type-aware parsing issues on test files
|
|
7
|
+
2. TypeScript typecheck errors in server and storage/service imports
|
|
8
|
+
3. Coverage gate failure on function coverage (<80%)
|
|
9
|
+
4. Project path inconsistency (`workspace/workspace/memhub`)
|
|
10
|
+
|
|
11
|
+
## Root Causes
|
|
12
|
+
- ESLint `parserOptions.project` only pointed to `tsconfig.json`, while test files are not included there.
|
|
13
|
+
- Some implementation details introduced strict-mode lint/type mismatches (`any` usage, fallthrough, readonly/no-unused issues).
|
|
14
|
+
- Existing server tests focus on constants/contracts but not internal execution paths, leaving many functions uncovered.
|
|
15
|
+
- Project was scaffolded under a nested directory.
|
|
16
|
+
|
|
17
|
+
## Plan of Record
|
|
18
|
+
|
|
19
|
+
### Step 1 — Fix static quality gates
|
|
20
|
+
- Update ESLint type-aware project references to include test TS config.
|
|
21
|
+
- Update `tsconfig.test.json` include set.
|
|
22
|
+
- Fix strict lint/type issues in server/service/storage/utils modules.
|
|
23
|
+
|
|
24
|
+
### Step 2 — Raise function coverage to >=80%
|
|
25
|
+
- Add focused tests for MCP server runtime paths:
|
|
26
|
+
- JSON parsing failure path
|
|
27
|
+
- invalid request path
|
|
28
|
+
- method dispatch (`initialize`, `tools/list`, `tools/call`, unknown method)
|
|
29
|
+
- error handling (`ServiceError`, validation-like error, generic error)
|
|
30
|
+
- response/error serialization
|
|
31
|
+
- log filtering behavior
|
|
32
|
+
- Preserve existing passing behavior and avoid over-mocking core service logic.
|
|
33
|
+
|
|
34
|
+
### Step 3 — Validate full gate
|
|
35
|
+
Run and require pass for:
|
|
36
|
+
- `npm run lint`
|
|
37
|
+
- `npm run typecheck`
|
|
38
|
+
- `npm run test`
|
|
39
|
+
- `npm run test:coverage` (global lines/functions/branches/statements >= 80)
|
|
40
|
+
|
|
41
|
+
### Step 4 — Normalize repository location
|
|
42
|
+
- Move project to `C:\Users\cloud_user\.openclaw\workspace\memhub` (if missing).
|
|
43
|
+
- Verify scripts still run from new root.
|
|
44
|
+
|
|
45
|
+
## Acceptance Criteria
|
|
46
|
+
- No lint errors
|
|
47
|
+
- No typecheck errors
|
|
48
|
+
- All tests pass
|
|
49
|
+
- Coverage thresholds all >= 80%
|
|
50
|
+
- Repository available at normalized path
|
|
51
|
+
|
|
52
|
+
## Risks and Mitigations
|
|
53
|
+
- **Risk:** Private method tests become brittle.
|
|
54
|
+
- **Mitigation:** Test externally visible behavior and error contracts where possible; keep internals tests focused and minimal.
|
|
55
|
+
- **Risk:** Path migration may break references.
|
|
56
|
+
- **Mitigation:** Move whole directory atomically and rerun full gate.
|
|
57
|
+
- **Risk:** Coverage improvements skew test value.
|
|
58
|
+
- **Mitigation:** Prefer behavior-driven tests over shallow line-hitting.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Tool Calling Policy (STM-first)
|
|
2
|
+
|
|
3
|
+
> 目标:让模型在每轮任务中稳定形成「先加载短期记忆,再产出,再回写记忆」的闭环。
|
|
4
|
+
|
|
5
|
+
## 一、调用时序(强约束)
|
|
6
|
+
|
|
7
|
+
1. **首轮调用 `memory_load`**(在响应用户前)
|
|
8
|
+
- 用于加载当前会话/任务相关短期记忆(STM)
|
|
9
|
+
- 若无命中,继续任务,不阻塞
|
|
10
|
+
|
|
11
|
+
2. **末轮调用 `memory_update`**(在本轮输出结束前)
|
|
12
|
+
- 将本轮新增的关键上下文写回
|
|
13
|
+
- 重点写入:决策、约束变更、待办变化、关键结论
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 二、STM 判据(3 轮复用原则)
|
|
18
|
+
|
|
19
|
+
若信息在未来 **3 轮** 内很可能被再次引用,则纳入 STM:
|
|
20
|
+
|
|
21
|
+
- 当前任务目标/范围
|
|
22
|
+
- 新确认的约束条件
|
|
23
|
+
- 待办项与状态变化(pending / done)
|
|
24
|
+
- 临时变量、参数、文件路径、报错栈
|
|
25
|
+
- 用户明确修正/改口(需求切换)
|
|
26
|
+
|
|
27
|
+
不满足则不强行写入,避免噪音。
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 三、建议工具定义(简化版)
|
|
32
|
+
|
|
33
|
+
## `memory_load`
|
|
34
|
+
**作用**:统一“看记忆”,用于当前轮开头加载上下文。
|
|
35
|
+
|
|
36
|
+
**建议入参**:
|
|
37
|
+
- `session_id`(可选,推荐)
|
|
38
|
+
- `date`(可选,默认今天)
|
|
39
|
+
- `limit`(可选,默认 20)
|
|
40
|
+
- `tags`(可选)
|
|
41
|
+
- `category`(可选)
|
|
42
|
+
- `query`(可选)
|
|
43
|
+
- `scope`(可选:`stm|all`,默认 `stm`)
|
|
44
|
+
|
|
45
|
+
**建议返回**:
|
|
46
|
+
- `items[]`(记忆条目)
|
|
47
|
+
- `summary`(可选摘要)
|
|
48
|
+
- `pending[]` / `done[]`(若可提取)
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## `memory_update`
|
|
53
|
+
**作用**:统一“写记忆”,用于当前轮末尾回写。
|
|
54
|
+
|
|
55
|
+
**建议入参**:
|
|
56
|
+
- `session_id`(可选;无则自动生成并返回)
|
|
57
|
+
- `date`(可选,默认今天)
|
|
58
|
+
- `mode`:`append|upsert`(默认 `append`)
|
|
59
|
+
- `entry_type`:`decision|preference|knowledge|todo|state_change`
|
|
60
|
+
- `title`
|
|
61
|
+
- `content`
|
|
62
|
+
- `tags[]`
|
|
63
|
+
- `category`
|
|
64
|
+
- `importance`(1-5)
|
|
65
|
+
|
|
66
|
+
**建议返回**:
|
|
67
|
+
- `id`
|
|
68
|
+
- `session_id`
|
|
69
|
+
- `file_path`
|
|
70
|
+
- `created|updated`
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 四、并发与目录规范
|
|
75
|
+
|
|
76
|
+
为支持多个 CLI 同时写入,建议目录如下:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
memories/
|
|
80
|
+
YYYY-MM-DD/
|
|
81
|
+
<session_uuid>/
|
|
82
|
+
2026-03-03T16-41-23.123Z-<slug>.md
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
说明:
|
|
86
|
+
- 同一天按 `session_uuid` 分桶,避免并发冲突
|
|
87
|
+
- 每条记录仍保留 YAML + Markdown 正文
|
|
88
|
+
- `session_uuid` 可来自调用方;缺省由服务端生成
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 五、触发更新条件
|
|
93
|
+
|
|
94
|
+
在以下事件发生时,优先触发 `memory_update`:
|
|
95
|
+
|
|
96
|
+
- 用户显式改需求(如“换个方案”)
|
|
97
|
+
- 任务状态切换(分析 → 实现 / 实现 → 验证)
|
|
98
|
+
- 新信息与既有 STM 冲突
|
|
99
|
+
- 本轮产出形成可复用结论
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 六、设计原则
|
|
104
|
+
|
|
105
|
+
- **STM 保留细节,不做过度抽象**
|
|
106
|
+
- **LTM 另层抽取,不与 STM 混存**
|
|
107
|
+
- **先 load,后 update,形成闭环**
|