@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
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@synth-coder/memhub",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A Git-friendly memory hub using Markdown-based storage with YAML Front Matter",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"memhub": "dist/server/mcp-server.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"test:watch": "vitest",
|
|
16
|
+
"test:coverage": "vitest run --coverage",
|
|
17
|
+
"lint": "eslint src test --ext .ts",
|
|
18
|
+
"lint:fix": "eslint src test --ext .ts --fix",
|
|
19
|
+
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" \"docs/**/*.md\"",
|
|
20
|
+
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\" \"docs/**/*.md\"",
|
|
21
|
+
"typecheck": "tsc --noEmit --project tsconfig.json",
|
|
22
|
+
"quality": "npm run lint && npm run typecheck && npm run test:coverage",
|
|
23
|
+
"ci": "npm run quality"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"mcp",
|
|
27
|
+
"memory",
|
|
28
|
+
"markdown",
|
|
29
|
+
"yaml",
|
|
30
|
+
"git-friendly"
|
|
31
|
+
],
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"zod": "^3.22.4",
|
|
36
|
+
"yaml": "^2.3.4"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^20.10.0",
|
|
40
|
+
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
|
41
|
+
"@typescript-eslint/parser": "^6.15.0",
|
|
42
|
+
"@vitest/coverage-v8": "^1.1.0",
|
|
43
|
+
"eslint": "^8.56.0",
|
|
44
|
+
"eslint-config-prettier": "^9.1.0",
|
|
45
|
+
"eslint-plugin-import": "^2.29.1",
|
|
46
|
+
"prettier": "^3.1.1",
|
|
47
|
+
"typescript": "^5.3.3",
|
|
48
|
+
"vitest": "^1.1.0"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=18.0.0"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) specific types and constants
|
|
3
|
+
* Defines the protocol structures for stdio-based communication
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Memory } from './types.js';
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// MCP Protocol Version
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
/** Current MCP protocol version */
|
|
13
|
+
export const MCP_PROTOCOL_VERSION = '2024-11-05';
|
|
14
|
+
|
|
15
|
+
/** Server information */
|
|
16
|
+
export const SERVER_INFO = {
|
|
17
|
+
name: 'memhub',
|
|
18
|
+
version: '0.1.0',
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// MCP Request/Response Types
|
|
23
|
+
// ============================================================================
|
|
24
|
+
|
|
25
|
+
/** JSON-RPC request ID */
|
|
26
|
+
export type RequestId = string | number;
|
|
27
|
+
|
|
28
|
+
/** Base JSON-RPC request structure */
|
|
29
|
+
export interface JsonRpcRequest<T = unknown> {
|
|
30
|
+
jsonrpc: '2.0';
|
|
31
|
+
id?: RequestId;
|
|
32
|
+
method: string;
|
|
33
|
+
params?: T;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Base JSON-RPC response structure */
|
|
37
|
+
export interface JsonRpcResponse<T = unknown> {
|
|
38
|
+
jsonrpc: '2.0';
|
|
39
|
+
id: RequestId | null;
|
|
40
|
+
result?: T;
|
|
41
|
+
error?: JsonRpcError;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** JSON-RPC error structure */
|
|
45
|
+
export interface JsonRpcError {
|
|
46
|
+
code: number;
|
|
47
|
+
message: string;
|
|
48
|
+
data?: unknown;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** JSON-RPC notification (no response expected) */
|
|
52
|
+
export interface JsonRpcNotification<T = unknown> {
|
|
53
|
+
jsonrpc: '2.0';
|
|
54
|
+
method: string;
|
|
55
|
+
params?: T;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ============================================================================
|
|
59
|
+
// MCP Lifecycle Messages
|
|
60
|
+
// ============================================================================
|
|
61
|
+
|
|
62
|
+
/** Initialize request parameters */
|
|
63
|
+
export interface InitializeParams {
|
|
64
|
+
protocolVersion: string;
|
|
65
|
+
capabilities: ClientCapabilities;
|
|
66
|
+
clientInfo: Implementation;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Initialize result */
|
|
70
|
+
export interface InitializeResult {
|
|
71
|
+
protocolVersion: string;
|
|
72
|
+
capabilities: ServerCapabilities;
|
|
73
|
+
serverInfo: Implementation;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Implementation information */
|
|
77
|
+
export interface Implementation {
|
|
78
|
+
name: string;
|
|
79
|
+
version: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Client capabilities */
|
|
83
|
+
export interface ClientCapabilities {
|
|
84
|
+
// Client can handle these features
|
|
85
|
+
readonly experimental?: Record<string, unknown>;
|
|
86
|
+
readonly roots?: { listChanged?: boolean };
|
|
87
|
+
readonly sampling?: Record<string, unknown>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Server capabilities */
|
|
91
|
+
export interface ServerCapabilities {
|
|
92
|
+
// Server provides these features
|
|
93
|
+
readonly experimental?: Record<string, unknown>;
|
|
94
|
+
readonly logging?: Record<string, unknown>;
|
|
95
|
+
readonly prompts?: { listChanged?: boolean };
|
|
96
|
+
readonly resources?: { subscribe?: boolean; listChanged?: boolean };
|
|
97
|
+
readonly tools?: { listChanged?: boolean };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ============================================================================
|
|
101
|
+
// MCP Tool Definitions
|
|
102
|
+
// ============================================================================
|
|
103
|
+
|
|
104
|
+
/** Tool definition for tool/list */
|
|
105
|
+
export interface Tool {
|
|
106
|
+
name: string;
|
|
107
|
+
description: string;
|
|
108
|
+
inputSchema: ToolInputSchema;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Tool input schema (JSON Schema) */
|
|
112
|
+
export interface ToolInputSchema {
|
|
113
|
+
type: 'object';
|
|
114
|
+
properties?: Record<string, unknown>;
|
|
115
|
+
required?: string[];
|
|
116
|
+
additionalProperties?: boolean;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Tool call request */
|
|
120
|
+
export interface ToolCallRequest {
|
|
121
|
+
name: string;
|
|
122
|
+
arguments?: Record<string, unknown>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Tool call result */
|
|
126
|
+
export interface ToolCallResult {
|
|
127
|
+
content: ToolContent[];
|
|
128
|
+
isError?: boolean;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Tool content types */
|
|
132
|
+
export type ToolContent = TextContent | ImageContent;
|
|
133
|
+
|
|
134
|
+
/** Text content */
|
|
135
|
+
export interface TextContent {
|
|
136
|
+
type: 'text';
|
|
137
|
+
text: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Image content */
|
|
141
|
+
export interface ImageContent {
|
|
142
|
+
type: 'image';
|
|
143
|
+
data: string; // base64 encoded
|
|
144
|
+
mimeType: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ============================================================================
|
|
148
|
+
// MCP Tool List
|
|
149
|
+
// ============================================================================
|
|
150
|
+
|
|
151
|
+
/** All available tool names */
|
|
152
|
+
export const TOOL_NAMES = ['memory_load', 'memory_update'] as const;
|
|
153
|
+
|
|
154
|
+
/** Tool name type */
|
|
155
|
+
export type ToolName = (typeof TOOL_NAMES)[number];
|
|
156
|
+
|
|
157
|
+
/** Tool definitions for MCP server */
|
|
158
|
+
export const TOOL_DEFINITIONS: readonly Tool[] = [
|
|
159
|
+
{
|
|
160
|
+
name: 'memory_load',
|
|
161
|
+
description:
|
|
162
|
+
'STM first step. Call at the first turn after receiving user prompt to load short-term memory context for this session/task.',
|
|
163
|
+
inputSchema: {
|
|
164
|
+
type: 'object',
|
|
165
|
+
properties: {
|
|
166
|
+
id: { type: 'string', description: 'Optional memory id for direct fetch' },
|
|
167
|
+
sessionId: {
|
|
168
|
+
type: 'string',
|
|
169
|
+
description: 'Optional session UUID to load current CLI/task context',
|
|
170
|
+
},
|
|
171
|
+
date: { type: 'string', description: 'Optional date filter (YYYY-MM-DD)' },
|
|
172
|
+
query: { type: 'string', description: 'Optional text query for relevant context' },
|
|
173
|
+
category: { type: 'string' },
|
|
174
|
+
tags: { type: 'array', items: { type: 'string' } },
|
|
175
|
+
limit: { type: 'number', description: 'Max results, default 20' },
|
|
176
|
+
scope: {
|
|
177
|
+
type: 'string',
|
|
178
|
+
enum: ['stm', 'all'],
|
|
179
|
+
description: 'stm for short-term context window; all for broader retrieval',
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
additionalProperties: false,
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: 'memory_update',
|
|
187
|
+
description:
|
|
188
|
+
'STM write-back step. Call at the final turn to append/upsert new decisions, preferences, task-state changes, and key outputs.',
|
|
189
|
+
inputSchema: {
|
|
190
|
+
type: 'object',
|
|
191
|
+
properties: {
|
|
192
|
+
id: { type: 'string', description: 'Optional id. Present = update existing record' },
|
|
193
|
+
sessionId: { type: 'string', description: 'Session UUID. Auto-created if omitted' },
|
|
194
|
+
mode: { type: 'string', enum: ['append', 'upsert'], description: 'Default append' },
|
|
195
|
+
entryType: {
|
|
196
|
+
type: 'string',
|
|
197
|
+
enum: ['decision', 'preference', 'knowledge', 'todo', 'state_change'],
|
|
198
|
+
},
|
|
199
|
+
title: { type: 'string', description: 'Optional title' },
|
|
200
|
+
content: { type: 'string', description: 'Required memory body' },
|
|
201
|
+
tags: { type: 'array', items: { type: 'string' } },
|
|
202
|
+
category: { type: 'string' },
|
|
203
|
+
importance: { type: 'number' },
|
|
204
|
+
},
|
|
205
|
+
required: ['content'],
|
|
206
|
+
additionalProperties: false,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
] as const;
|
|
210
|
+
|
|
211
|
+
// ============================================================================
|
|
212
|
+
// MCP Methods
|
|
213
|
+
// ============================================================================
|
|
214
|
+
|
|
215
|
+
/** All MCP method names */
|
|
216
|
+
export const MCP_METHODS = {
|
|
217
|
+
// Lifecycle
|
|
218
|
+
INITIALIZE: 'initialize',
|
|
219
|
+
INITIALIZED: 'notifications/initialized',
|
|
220
|
+
SHUTDOWN: 'shutdown',
|
|
221
|
+
EXIT: 'exit',
|
|
222
|
+
|
|
223
|
+
// Tools
|
|
224
|
+
TOOLS_LIST: 'tools/list',
|
|
225
|
+
TOOLS_CALL: 'tools/call',
|
|
226
|
+
|
|
227
|
+
// Logging
|
|
228
|
+
LOGGING_MESSAGE: 'notifications/message',
|
|
229
|
+
|
|
230
|
+
// Progress
|
|
231
|
+
PROGRESS: 'notifications/progress',
|
|
232
|
+
} as const;
|
|
233
|
+
|
|
234
|
+
// ============================================================================
|
|
235
|
+
// Error Codes (Standard MCP + Custom)
|
|
236
|
+
// ============================================================================
|
|
237
|
+
|
|
238
|
+
/** Standard JSON-RPC error codes */
|
|
239
|
+
export const JSONRPC_ERROR_CODES = {
|
|
240
|
+
PARSE_ERROR: -32700,
|
|
241
|
+
INVALID_REQUEST: -32600,
|
|
242
|
+
METHOD_NOT_FOUND: -32601,
|
|
243
|
+
INVALID_PARAMS: -32602,
|
|
244
|
+
INTERNAL_ERROR: -32603,
|
|
245
|
+
} as const;
|
|
246
|
+
|
|
247
|
+
/** MemHub custom error codes */
|
|
248
|
+
export const MEMHUB_ERROR_CODES = {
|
|
249
|
+
NOT_FOUND: -32001,
|
|
250
|
+
STORAGE_ERROR: -32002,
|
|
251
|
+
VALIDATION_ERROR: -32003,
|
|
252
|
+
DUPLICATE_ERROR: -32004,
|
|
253
|
+
} as const;
|
|
254
|
+
|
|
255
|
+
/** Combined error codes */
|
|
256
|
+
export const ERROR_CODES = {
|
|
257
|
+
...JSONRPC_ERROR_CODES,
|
|
258
|
+
...MEMHUB_ERROR_CODES,
|
|
259
|
+
} as const;
|
|
260
|
+
|
|
261
|
+
// ============================================================================
|
|
262
|
+
// Utility Types
|
|
263
|
+
// ============================================================================
|
|
264
|
+
|
|
265
|
+
/** Helper type to extract result type from a tool name */
|
|
266
|
+
export type ToolResult<T extends ToolName> = T extends 'memory_load'
|
|
267
|
+
? { items: Memory[]; total: number }
|
|
268
|
+
: T extends 'memory_update'
|
|
269
|
+
? {
|
|
270
|
+
id: string;
|
|
271
|
+
sessionId: string;
|
|
272
|
+
filePath: string;
|
|
273
|
+
created: boolean;
|
|
274
|
+
updated: boolean;
|
|
275
|
+
memory: Memory;
|
|
276
|
+
}
|
|
277
|
+
: never;
|
|
278
|
+
|
|
279
|
+
/** Helper type to extract input type from a tool name */
|
|
280
|
+
export type ToolInput<T extends ToolName> = T extends 'memory_load'
|
|
281
|
+
? {
|
|
282
|
+
id?: string;
|
|
283
|
+
sessionId?: string;
|
|
284
|
+
date?: string;
|
|
285
|
+
query?: string;
|
|
286
|
+
category?: string;
|
|
287
|
+
tags?: string[];
|
|
288
|
+
limit?: number;
|
|
289
|
+
scope?: 'stm' | 'all';
|
|
290
|
+
}
|
|
291
|
+
: T extends 'memory_update'
|
|
292
|
+
? {
|
|
293
|
+
id?: string;
|
|
294
|
+
sessionId?: string;
|
|
295
|
+
mode?: 'append' | 'upsert';
|
|
296
|
+
entryType?: 'decision' | 'preference' | 'knowledge' | 'todo' | 'state_change';
|
|
297
|
+
title?: string;
|
|
298
|
+
content: string;
|
|
299
|
+
tags?: string[];
|
|
300
|
+
category?: string;
|
|
301
|
+
importance?: number;
|
|
302
|
+
}
|
|
303
|
+
: never;
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for runtime validation
|
|
3
|
+
* All schemas correspond to types defined in types.ts
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Primitive Schemas
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
/** UUID v4 validation schema */
|
|
13
|
+
export const UUIDSchema = z.string().uuid().brand<'UUID'>();
|
|
14
|
+
|
|
15
|
+
/** ISO 8601 timestamp validation */
|
|
16
|
+
export const ISO8601TimestampSchema = z.string().datetime().brand<'ISO8601'>();
|
|
17
|
+
|
|
18
|
+
/** Slug validation (URL-friendly string) */
|
|
19
|
+
export const SlugSchema = z
|
|
20
|
+
.string()
|
|
21
|
+
.min(1)
|
|
22
|
+
.max(100)
|
|
23
|
+
.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, 'Must be a valid URL slug');
|
|
24
|
+
|
|
25
|
+
/** Tag name validation */
|
|
26
|
+
export const TagSchema = z
|
|
27
|
+
.string()
|
|
28
|
+
.min(1)
|
|
29
|
+
.max(50)
|
|
30
|
+
.regex(/^[a-z0-9-]+$/, 'Tags can only contain lowercase letters, numbers, and hyphens');
|
|
31
|
+
|
|
32
|
+
/** Category name validation */
|
|
33
|
+
export const CategorySchema = z
|
|
34
|
+
.string()
|
|
35
|
+
.min(1)
|
|
36
|
+
.max(50)
|
|
37
|
+
.regex(/^[a-z0-9-]+$/, 'Category can only contain lowercase letters, numbers, and hyphens');
|
|
38
|
+
|
|
39
|
+
/** Importance level validation (1-5) */
|
|
40
|
+
export const ImportanceSchema = z.number().int().min(1).max(5);
|
|
41
|
+
|
|
42
|
+
/** STM memory entry type */
|
|
43
|
+
export const MemoryEntryTypeSchema = z.enum([
|
|
44
|
+
'decision',
|
|
45
|
+
'preference',
|
|
46
|
+
'knowledge',
|
|
47
|
+
'todo',
|
|
48
|
+
'state_change',
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Memory Schemas
|
|
53
|
+
// ============================================================================
|
|
54
|
+
|
|
55
|
+
/** Memory front matter schema (YAML portion) */
|
|
56
|
+
export const MemoryFrontMatterSchema = z.object({
|
|
57
|
+
id: UUIDSchema,
|
|
58
|
+
created_at: ISO8601TimestampSchema,
|
|
59
|
+
updated_at: ISO8601TimestampSchema,
|
|
60
|
+
session_id: UUIDSchema.optional(),
|
|
61
|
+
entry_type: MemoryEntryTypeSchema.optional(),
|
|
62
|
+
tags: z.array(TagSchema).default([]),
|
|
63
|
+
category: CategorySchema.default('general'),
|
|
64
|
+
importance: ImportanceSchema.default(3),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/** Complete memory schema */
|
|
68
|
+
export const MemorySchema = z.object({
|
|
69
|
+
id: UUIDSchema,
|
|
70
|
+
createdAt: ISO8601TimestampSchema,
|
|
71
|
+
updatedAt: ISO8601TimestampSchema,
|
|
72
|
+
sessionId: UUIDSchema.optional(),
|
|
73
|
+
entryType: MemoryEntryTypeSchema.optional(),
|
|
74
|
+
tags: z.array(z.string()).readonly(),
|
|
75
|
+
category: CategorySchema,
|
|
76
|
+
importance: ImportanceSchema,
|
|
77
|
+
title: z.string().min(1).max(200),
|
|
78
|
+
content: z.string().max(100000),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
/** Memory file schema */
|
|
82
|
+
export const MemoryFileSchema = z.object({
|
|
83
|
+
path: z.string().min(1),
|
|
84
|
+
filename: z.string().min(1),
|
|
85
|
+
content: z.string(),
|
|
86
|
+
modifiedAt: ISO8601TimestampSchema,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// Result Schemas
|
|
91
|
+
// ============================================================================
|
|
92
|
+
|
|
93
|
+
/** Search result schema */
|
|
94
|
+
export const SearchResultSchema = z.object({
|
|
95
|
+
memory: MemorySchema,
|
|
96
|
+
score: z.number().min(0).max(1),
|
|
97
|
+
matches: z.array(z.string()),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/** List result schema */
|
|
101
|
+
export const ListResultSchema = z.object({
|
|
102
|
+
memories: z.array(MemorySchema),
|
|
103
|
+
total: z.number().int().nonnegative(),
|
|
104
|
+
hasMore: z.boolean(),
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
/** Create result schema */
|
|
108
|
+
export const CreateResultSchema = z.object({
|
|
109
|
+
id: UUIDSchema,
|
|
110
|
+
filePath: z.string().min(1),
|
|
111
|
+
memory: MemorySchema,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
/** Update result schema */
|
|
115
|
+
export const UpdateResultSchema = z.object({
|
|
116
|
+
memory: MemorySchema,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
/** Delete result schema */
|
|
120
|
+
export const DeleteResultSchema = z.object({
|
|
121
|
+
success: z.boolean(),
|
|
122
|
+
filePath: z.string().min(1),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// ============================================================================
|
|
126
|
+
// Filter and Query Schemas
|
|
127
|
+
// ============================================================================
|
|
128
|
+
|
|
129
|
+
/** Sort field enum */
|
|
130
|
+
export const SortFieldSchema = z.enum(['createdAt', 'updatedAt', 'title', 'importance']);
|
|
131
|
+
|
|
132
|
+
/** Sort order enum */
|
|
133
|
+
export const SortOrderSchema = z.enum(['asc', 'desc']);
|
|
134
|
+
|
|
135
|
+
/** Memory filter schema */
|
|
136
|
+
export const MemoryFilterSchema = z.object({
|
|
137
|
+
category: CategorySchema.optional(),
|
|
138
|
+
tags: z.array(TagSchema).optional(),
|
|
139
|
+
fromDate: ISO8601TimestampSchema.optional(),
|
|
140
|
+
toDate: ISO8601TimestampSchema.optional(),
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
/** Pagination options schema */
|
|
144
|
+
export const PaginationOptionsSchema = z.object({
|
|
145
|
+
limit: z.number().int().min(1).max(100).default(20),
|
|
146
|
+
offset: z.number().int().min(0).default(0),
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
/** Sort options schema */
|
|
150
|
+
export const SortOptionsSchema = z.object({
|
|
151
|
+
sortBy: SortFieldSchema.default('createdAt'),
|
|
152
|
+
sortOrder: SortOrderSchema.default('desc'),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// ============================================================================
|
|
156
|
+
// MCP Tool Input Schemas
|
|
157
|
+
// ============================================================================
|
|
158
|
+
|
|
159
|
+
/** Create memory input schema */
|
|
160
|
+
export const CreateMemoryInputSchema = z.object({
|
|
161
|
+
title: z.string().min(1).max(200),
|
|
162
|
+
content: z.string().max(100000),
|
|
163
|
+
tags: z.array(TagSchema).default([]),
|
|
164
|
+
category: CategorySchema.default('general'),
|
|
165
|
+
importance: ImportanceSchema.default(3),
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
/** Read memory input schema */
|
|
169
|
+
export const ReadMemoryInputSchema = z.object({
|
|
170
|
+
id: UUIDSchema,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
/** Update memory input schema */
|
|
174
|
+
export const UpdateMemoryInputSchema = z.object({
|
|
175
|
+
id: UUIDSchema,
|
|
176
|
+
title: z.string().min(1).max(200).optional(),
|
|
177
|
+
content: z.string().max(100000).optional(),
|
|
178
|
+
tags: z.array(TagSchema).optional(),
|
|
179
|
+
category: CategorySchema.optional(),
|
|
180
|
+
importance: ImportanceSchema.optional(),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
/** Delete memory input schema */
|
|
184
|
+
export const DeleteMemoryInputSchema = z.object({
|
|
185
|
+
id: UUIDSchema,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
/** List memory input schema */
|
|
189
|
+
export const ListMemoryInputSchema = z.object({
|
|
190
|
+
category: CategorySchema.optional(),
|
|
191
|
+
tags: z.array(TagSchema).optional(),
|
|
192
|
+
fromDate: ISO8601TimestampSchema.optional(),
|
|
193
|
+
toDate: ISO8601TimestampSchema.optional(),
|
|
194
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
195
|
+
offset: z.number().int().min(0).optional(),
|
|
196
|
+
sortBy: SortFieldSchema.optional(),
|
|
197
|
+
sortOrder: SortOrderSchema.optional(),
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
/** Search memory input schema */
|
|
201
|
+
export const SearchMemoryInputSchema = z.object({
|
|
202
|
+
query: z.string().min(1).max(1000),
|
|
203
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
204
|
+
category: CategorySchema.optional(),
|
|
205
|
+
tags: z.array(TagSchema).optional(),
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
/** memory_load input schema */
|
|
209
|
+
export const MemoryLoadInputSchema = z.object({
|
|
210
|
+
id: UUIDSchema.optional(),
|
|
211
|
+
sessionId: UUIDSchema.optional(),
|
|
212
|
+
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
213
|
+
query: z.string().min(1).max(1000).optional(),
|
|
214
|
+
category: CategorySchema.optional(),
|
|
215
|
+
tags: z.array(TagSchema).optional(),
|
|
216
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
217
|
+
scope: z.enum(['stm', 'all']).optional(),
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
/** memory_update (upsert/append) input schema */
|
|
221
|
+
export const MemoryUpdateInputV2Schema = z.object({
|
|
222
|
+
id: UUIDSchema.optional(),
|
|
223
|
+
sessionId: UUIDSchema.optional(),
|
|
224
|
+
mode: z.enum(['append', 'upsert']).default('append'),
|
|
225
|
+
entryType: MemoryEntryTypeSchema.optional(),
|
|
226
|
+
title: z.string().min(1).max(200).optional(),
|
|
227
|
+
content: z.string().min(1).max(100000),
|
|
228
|
+
tags: z.array(TagSchema).optional(),
|
|
229
|
+
category: CategorySchema.optional(),
|
|
230
|
+
importance: ImportanceSchema.optional(),
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// ============================================================================
|
|
234
|
+
// MCP Tool Output Schemas
|
|
235
|
+
// ============================================================================
|
|
236
|
+
|
|
237
|
+
/** Create memory output schema */
|
|
238
|
+
export const CreateMemoryOutputSchema = CreateResultSchema;
|
|
239
|
+
|
|
240
|
+
/** Read memory output schema */
|
|
241
|
+
export const ReadMemoryOutputSchema = z.object({
|
|
242
|
+
memory: MemorySchema,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
/** Update memory output schema */
|
|
246
|
+
export const UpdateMemoryOutputSchema = UpdateResultSchema;
|
|
247
|
+
|
|
248
|
+
export const MemoryLoadOutputSchema = z.object({
|
|
249
|
+
items: z.array(MemorySchema),
|
|
250
|
+
total: z.number().int().nonnegative(),
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
export const MemoryUpdateOutputSchema = z.object({
|
|
254
|
+
id: UUIDSchema,
|
|
255
|
+
sessionId: UUIDSchema,
|
|
256
|
+
filePath: z.string().min(1),
|
|
257
|
+
created: z.boolean(),
|
|
258
|
+
updated: z.boolean(),
|
|
259
|
+
memory: MemorySchema,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
/** Delete memory output schema */
|
|
263
|
+
export const DeleteMemoryOutputSchema = DeleteResultSchema;
|
|
264
|
+
|
|
265
|
+
/** List memory output schema */
|
|
266
|
+
export const ListMemoryOutputSchema = ListResultSchema;
|
|
267
|
+
|
|
268
|
+
/** Search memory output schema */
|
|
269
|
+
export const SearchMemoryOutputSchema = z.object({
|
|
270
|
+
results: z.array(SearchResultSchema),
|
|
271
|
+
total: z.number().int().nonnegative(),
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
/** Get categories output schema */
|
|
275
|
+
export const GetCategoriesOutputSchema = z.object({
|
|
276
|
+
categories: z.array(CategorySchema),
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
/** Get tags output schema */
|
|
280
|
+
export const GetTagsOutputSchema = z.object({
|
|
281
|
+
tags: z.array(TagSchema),
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// ============================================================================
|
|
285
|
+
// Configuration Schemas
|
|
286
|
+
// ============================================================================
|
|
287
|
+
|
|
288
|
+
/** Configuration schema */
|
|
289
|
+
export const ConfigSchema = z.object({
|
|
290
|
+
storagePath: z.string().min(1),
|
|
291
|
+
logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// ============================================================================
|
|
295
|
+
// Type Extraction from Schemas
|
|
296
|
+
// ============================================================================
|
|
297
|
+
|
|
298
|
+
/** Inferred Memory type from schema */
|
|
299
|
+
export type MemoryFromSchema = z.infer<typeof MemorySchema>;
|
|
300
|
+
|
|
301
|
+
/** Inferred CreateInput type from schema */
|
|
302
|
+
export type CreateMemoryInputFromSchema = z.infer<typeof CreateMemoryInputSchema>;
|
|
303
|
+
|
|
304
|
+
/** Inferred UpdateInput type from schema */
|
|
305
|
+
export type UpdateMemoryInputFromSchema = z.infer<typeof UpdateMemoryInputSchema>;
|
|
306
|
+
|
|
307
|
+
/** Inferred ListInput type from schema */
|
|
308
|
+
export type ListMemoryInputFromSchema = z.infer<typeof ListMemoryInputSchema>;
|
|
309
|
+
|
|
310
|
+
/** Inferred SearchInput type from schema */
|
|
311
|
+
export type SearchMemoryInputFromSchema = z.infer<typeof SearchMemoryInputSchema>;
|