@synth-coder/memhub 0.2.1 → 0.2.3
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 +45 -45
- package/.factory/commands/opsx-apply.md +150 -0
- package/.factory/commands/opsx-archive.md +155 -0
- package/.factory/commands/opsx-explore.md +171 -0
- package/.factory/commands/opsx-propose.md +104 -0
- package/.factory/skills/openspec-apply-change/SKILL.md +156 -0
- package/.factory/skills/openspec-archive-change/SKILL.md +114 -0
- package/.factory/skills/openspec-explore/SKILL.md +288 -0
- package/.factory/skills/openspec-propose/SKILL.md +110 -0
- package/.github/workflows/ci.yml +74 -74
- package/.iflow/commands/opsx-apply.md +152 -152
- package/.iflow/commands/opsx-archive.md +157 -157
- package/.iflow/commands/opsx-explore.md +173 -173
- package/.iflow/commands/opsx-propose.md +106 -106
- package/.iflow/skills/openspec-apply-change/SKILL.md +156 -156
- package/.iflow/skills/openspec-archive-change/SKILL.md +114 -114
- package/.iflow/skills/openspec-explore/SKILL.md +288 -288
- package/.iflow/skills/openspec-propose/SKILL.md +110 -110
- package/.prettierrc +11 -11
- package/AGENTS.md +169 -26
- package/README.md +195 -195
- package/README.zh-CN.md +193 -193
- package/dist/src/contracts/mcp.js +34 -34
- package/dist/src/server/mcp-server.d.ts +8 -0
- package/dist/src/server/mcp-server.d.ts.map +1 -1
- package/dist/src/server/mcp-server.js +23 -2
- package/dist/src/server/mcp-server.js.map +1 -1
- package/dist/src/services/memory-service.d.ts +1 -0
- package/dist/src/services/memory-service.d.ts.map +1 -1
- package/dist/src/services/memory-service.js +125 -82
- package/dist/src/services/memory-service.js.map +1 -1
- package/docs/architecture-diagrams.md +368 -0
- package/docs/architecture.md +381 -349
- package/docs/contracts.md +190 -119
- package/docs/prompt-template.md +33 -79
- package/docs/proposals/mcp-typescript-sdk-refactor.md +568 -568
- package/docs/proposals/proposal-close-gates.md +58 -58
- package/docs/tool-calling-policy.md +101 -107
- package/docs/vector-search.md +306 -0
- package/package.json +59 -58
- package/src/contracts/index.ts +12 -12
- package/src/contracts/mcp.ts +222 -222
- package/src/contracts/schemas.ts +307 -307
- package/src/contracts/types.ts +410 -410
- package/src/index.ts +8 -8
- package/src/server/index.ts +5 -5
- package/src/server/mcp-server.ts +185 -161
- package/src/services/embedding-service.ts +114 -114
- package/src/services/index.ts +5 -5
- package/src/services/memory-service.ts +663 -621
- package/src/storage/frontmatter-parser.ts +243 -243
- package/src/storage/index.ts +6 -6
- package/src/storage/markdown-storage.ts +236 -236
- package/src/storage/vector-index.ts +160 -160
- package/src/utils/index.ts +5 -5
- package/src/utils/slugify.ts +63 -63
- package/test/contracts/schemas.test.ts +313 -313
- package/test/contracts/types.test.ts +21 -21
- package/test/frontmatter-parser-more.test.ts +94 -94
- package/test/server/mcp-server.test.ts +210 -169
- package/test/services/memory-service-edge.test.ts +248 -248
- package/test/services/memory-service.test.ts +278 -278
- package/test/storage/frontmatter-parser.test.ts +222 -222
- package/test/storage/markdown-storage.test.ts +216 -216
- package/test/storage/storage-edge.test.ts +238 -238
- package/test/storage/vector-index.test.ts +153 -153
- package/test/utils/slugify-edge.test.ts +94 -94
- package/test/utils/slugify.test.ts +68 -68
- package/tsconfig.json +25 -25
- package/tsconfig.test.json +8 -8
- package/vitest.config.ts +29 -29
|
@@ -1,243 +1,243 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FrontMatter Parser - Handles YAML Front Matter and Markdown content
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
6
|
-
import type { Memory, MemoryFrontMatter } from '../contracts/types.js';
|
|
7
|
-
import { slugify } from '../utils/slugify.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Result of parsing a markdown file
|
|
11
|
-
*/
|
|
12
|
-
export interface ParseResult {
|
|
13
|
-
frontMatter: MemoryFrontMatter;
|
|
14
|
-
title: string;
|
|
15
|
-
content: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Custom error for front matter parsing
|
|
20
|
-
*/
|
|
21
|
-
export class FrontMatterError extends Error {
|
|
22
|
-
constructor(
|
|
23
|
-
message: string,
|
|
24
|
-
public readonly cause?: unknown
|
|
25
|
-
) {
|
|
26
|
-
super(message);
|
|
27
|
-
this.name = 'FrontMatterError';
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Parses a markdown file with YAML front matter
|
|
33
|
-
*
|
|
34
|
-
* Expected format:
|
|
35
|
-
* ---
|
|
36
|
-
* id: "uuid"
|
|
37
|
-
* created_at: "ISO8601"
|
|
38
|
-
* updated_at: "ISO8601"
|
|
39
|
-
* tags: ["tag1", "tag2"]
|
|
40
|
-
* category: "category"
|
|
41
|
-
* importance: 3
|
|
42
|
-
* ---
|
|
43
|
-
*
|
|
44
|
-
* # Title
|
|
45
|
-
*
|
|
46
|
-
* Content...
|
|
47
|
-
*
|
|
48
|
-
* @param markdown - The markdown content to parse
|
|
49
|
-
* @returns Parsed front matter, title, and content
|
|
50
|
-
* @throws FrontMatterError if parsing fails
|
|
51
|
-
*/
|
|
52
|
-
export function parseFrontMatter(markdown: string): ParseResult {
|
|
53
|
-
// Check for front matter delimiter
|
|
54
|
-
if (!markdown.startsWith('---')) {
|
|
55
|
-
throw new FrontMatterError('Missing front matter delimiter');
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Find the end of front matter
|
|
59
|
-
const endMatch = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
|
|
60
|
-
if (!endMatch) {
|
|
61
|
-
throw new FrontMatterError('Invalid front matter format');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const frontMatterYaml = endMatch[1];
|
|
65
|
-
const restOfContent = markdown.slice(endMatch[0].length);
|
|
66
|
-
|
|
67
|
-
// Parse YAML front matter
|
|
68
|
-
let frontMatter: unknown;
|
|
69
|
-
try {
|
|
70
|
-
frontMatter = parseYaml(frontMatterYaml);
|
|
71
|
-
} catch (error) {
|
|
72
|
-
throw new FrontMatterError('Invalid YAML in front matter', error);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Validate required fields
|
|
76
|
-
if (!isValidFrontMatter(frontMatter)) {
|
|
77
|
-
throw new FrontMatterError('Missing required fields in front matter');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Parse title and content from markdown body
|
|
81
|
-
const { title, content } = parseMarkdownBody(restOfContent);
|
|
82
|
-
|
|
83
|
-
return {
|
|
84
|
-
frontMatter,
|
|
85
|
-
title,
|
|
86
|
-
content,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Converts front matter and content to markdown string
|
|
92
|
-
*
|
|
93
|
-
* @param frontMatter - The front matter data
|
|
94
|
-
* @param title - The title (H1 heading)
|
|
95
|
-
* @param content - The markdown content
|
|
96
|
-
* @returns Complete markdown string
|
|
97
|
-
*/
|
|
98
|
-
export function stringifyFrontMatter(
|
|
99
|
-
frontMatter: MemoryFrontMatter,
|
|
100
|
-
title: string,
|
|
101
|
-
content: string
|
|
102
|
-
): string {
|
|
103
|
-
// Convert camelCase to snake_case for YAML
|
|
104
|
-
const yamlData = {
|
|
105
|
-
id: frontMatter.id,
|
|
106
|
-
created_at: frontMatter.created_at,
|
|
107
|
-
updated_at: frontMatter.updated_at,
|
|
108
|
-
...(frontMatter.session_id ? { session_id: frontMatter.session_id } : {}),
|
|
109
|
-
...(frontMatter.entry_type ? { entry_type: frontMatter.entry_type } : {}),
|
|
110
|
-
tags: frontMatter.tags.length > 0 ? frontMatter.tags : [],
|
|
111
|
-
category: frontMatter.category,
|
|
112
|
-
importance: frontMatter.importance,
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
// Stringify YAML with specific options for consistent formatting
|
|
116
|
-
const yamlString = stringifyYaml(yamlData, {
|
|
117
|
-
indent: 2,
|
|
118
|
-
defaultKeyType: 'PLAIN',
|
|
119
|
-
defaultStringType: 'QUOTE_DOUBLE',
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// Build the complete markdown
|
|
123
|
-
const parts: string[] = ['---', yamlString.trim(), '---', ''];
|
|
124
|
-
|
|
125
|
-
// Add title if provided
|
|
126
|
-
if (title) {
|
|
127
|
-
parts.push(`# ${title}`, '');
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Add content if provided
|
|
131
|
-
if (content) {
|
|
132
|
-
parts.push(content);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Ensure content ends with a single newline
|
|
136
|
-
let result = parts.join('\n');
|
|
137
|
-
if (!result.endsWith('\n')) {
|
|
138
|
-
result += '\n';
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return result;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Parses the markdown body to extract title and content
|
|
146
|
-
*
|
|
147
|
-
* @param body - The markdown body (after front matter)
|
|
148
|
-
* @returns Title and content
|
|
149
|
-
*/
|
|
150
|
-
function parseMarkdownBody(body: string): { title: string; content: string } {
|
|
151
|
-
const trimmed = body.trim();
|
|
152
|
-
|
|
153
|
-
if (!trimmed) {
|
|
154
|
-
return { title: '', content: '' };
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Try to extract H1 title
|
|
158
|
-
const h1Match = trimmed.match(/^#\s+(.+)$/m);
|
|
159
|
-
if (h1Match) {
|
|
160
|
-
const title = h1Match[1].trim();
|
|
161
|
-
// Remove the H1 line from content
|
|
162
|
-
const content = trimmed.replace(/^#\s+.+$/m, '').trim();
|
|
163
|
-
return { title, content };
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// No H1 found, treat entire body as content
|
|
167
|
-
return { title: '', content: trimmed };
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Type guard to validate front matter structure
|
|
172
|
-
*
|
|
173
|
-
* @param value - The value to check
|
|
174
|
-
* @returns True if valid front matter
|
|
175
|
-
*/
|
|
176
|
-
function isValidFrontMatter(value: unknown): value is MemoryFrontMatter {
|
|
177
|
-
if (typeof value !== 'object' || value === null) {
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const fm = value as Record<string, unknown>;
|
|
182
|
-
|
|
183
|
-
// Check required fields
|
|
184
|
-
if (typeof fm.id !== 'string') return false;
|
|
185
|
-
if (typeof fm.created_at !== 'string') return false;
|
|
186
|
-
if (typeof fm.updated_at !== 'string') return false;
|
|
187
|
-
if (fm.session_id !== undefined && typeof fm.session_id !== 'string') return false;
|
|
188
|
-
if (fm.entry_type !== undefined && typeof fm.entry_type !== 'string') return false;
|
|
189
|
-
if (!Array.isArray(fm.tags)) return false;
|
|
190
|
-
if (typeof fm.category !== 'string') return false;
|
|
191
|
-
if (typeof fm.importance !== 'number') return false;
|
|
192
|
-
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Converts a Memory object to front matter format
|
|
198
|
-
*
|
|
199
|
-
* @param memory - The memory object
|
|
200
|
-
* @returns Memory in front matter format
|
|
201
|
-
*/
|
|
202
|
-
export function memoryToFrontMatter(memory: Memory): MemoryFrontMatter {
|
|
203
|
-
return {
|
|
204
|
-
id: memory.id,
|
|
205
|
-
created_at: memory.createdAt,
|
|
206
|
-
updated_at: memory.updatedAt,
|
|
207
|
-
session_id: memory.sessionId,
|
|
208
|
-
entry_type: memory.entryType,
|
|
209
|
-
tags: memory.tags,
|
|
210
|
-
category: memory.category,
|
|
211
|
-
importance: memory.importance,
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Converts front matter format to Memory object
|
|
217
|
-
*
|
|
218
|
-
* @param frontMatter - The front matter data
|
|
219
|
-
* @param title - The memory title
|
|
220
|
-
* @param content - The memory content
|
|
221
|
-
* @returns Complete Memory object
|
|
222
|
-
*/
|
|
223
|
-
export function frontMatterToMemory(
|
|
224
|
-
frontMatter: MemoryFrontMatter,
|
|
225
|
-
title: string,
|
|
226
|
-
content: string
|
|
227
|
-
): Memory {
|
|
228
|
-
return {
|
|
229
|
-
id: frontMatter.id,
|
|
230
|
-
createdAt: frontMatter.created_at,
|
|
231
|
-
updatedAt: frontMatter.updated_at,
|
|
232
|
-
sessionId: frontMatter.session_id,
|
|
233
|
-
entryType: frontMatter.entry_type,
|
|
234
|
-
tags: frontMatter.tags,
|
|
235
|
-
category: frontMatter.category,
|
|
236
|
-
importance: frontMatter.importance,
|
|
237
|
-
title,
|
|
238
|
-
content,
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Re-export slugify for convenience
|
|
243
|
-
export { slugify };
|
|
1
|
+
/**
|
|
2
|
+
* FrontMatter Parser - Handles YAML Front Matter and Markdown content
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
6
|
+
import type { Memory, MemoryFrontMatter } from '../contracts/types.js';
|
|
7
|
+
import { slugify } from '../utils/slugify.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Result of parsing a markdown file
|
|
11
|
+
*/
|
|
12
|
+
export interface ParseResult {
|
|
13
|
+
frontMatter: MemoryFrontMatter;
|
|
14
|
+
title: string;
|
|
15
|
+
content: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Custom error for front matter parsing
|
|
20
|
+
*/
|
|
21
|
+
export class FrontMatterError extends Error {
|
|
22
|
+
constructor(
|
|
23
|
+
message: string,
|
|
24
|
+
public readonly cause?: unknown
|
|
25
|
+
) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = 'FrontMatterError';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Parses a markdown file with YAML front matter
|
|
33
|
+
*
|
|
34
|
+
* Expected format:
|
|
35
|
+
* ---
|
|
36
|
+
* id: "uuid"
|
|
37
|
+
* created_at: "ISO8601"
|
|
38
|
+
* updated_at: "ISO8601"
|
|
39
|
+
* tags: ["tag1", "tag2"]
|
|
40
|
+
* category: "category"
|
|
41
|
+
* importance: 3
|
|
42
|
+
* ---
|
|
43
|
+
*
|
|
44
|
+
* # Title
|
|
45
|
+
*
|
|
46
|
+
* Content...
|
|
47
|
+
*
|
|
48
|
+
* @param markdown - The markdown content to parse
|
|
49
|
+
* @returns Parsed front matter, title, and content
|
|
50
|
+
* @throws FrontMatterError if parsing fails
|
|
51
|
+
*/
|
|
52
|
+
export function parseFrontMatter(markdown: string): ParseResult {
|
|
53
|
+
// Check for front matter delimiter
|
|
54
|
+
if (!markdown.startsWith('---')) {
|
|
55
|
+
throw new FrontMatterError('Missing front matter delimiter');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Find the end of front matter
|
|
59
|
+
const endMatch = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
|
|
60
|
+
if (!endMatch) {
|
|
61
|
+
throw new FrontMatterError('Invalid front matter format');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const frontMatterYaml = endMatch[1];
|
|
65
|
+
const restOfContent = markdown.slice(endMatch[0].length);
|
|
66
|
+
|
|
67
|
+
// Parse YAML front matter
|
|
68
|
+
let frontMatter: unknown;
|
|
69
|
+
try {
|
|
70
|
+
frontMatter = parseYaml(frontMatterYaml);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
throw new FrontMatterError('Invalid YAML in front matter', error);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Validate required fields
|
|
76
|
+
if (!isValidFrontMatter(frontMatter)) {
|
|
77
|
+
throw new FrontMatterError('Missing required fields in front matter');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Parse title and content from markdown body
|
|
81
|
+
const { title, content } = parseMarkdownBody(restOfContent);
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
frontMatter,
|
|
85
|
+
title,
|
|
86
|
+
content,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Converts front matter and content to markdown string
|
|
92
|
+
*
|
|
93
|
+
* @param frontMatter - The front matter data
|
|
94
|
+
* @param title - The title (H1 heading)
|
|
95
|
+
* @param content - The markdown content
|
|
96
|
+
* @returns Complete markdown string
|
|
97
|
+
*/
|
|
98
|
+
export function stringifyFrontMatter(
|
|
99
|
+
frontMatter: MemoryFrontMatter,
|
|
100
|
+
title: string,
|
|
101
|
+
content: string
|
|
102
|
+
): string {
|
|
103
|
+
// Convert camelCase to snake_case for YAML
|
|
104
|
+
const yamlData = {
|
|
105
|
+
id: frontMatter.id,
|
|
106
|
+
created_at: frontMatter.created_at,
|
|
107
|
+
updated_at: frontMatter.updated_at,
|
|
108
|
+
...(frontMatter.session_id ? { session_id: frontMatter.session_id } : {}),
|
|
109
|
+
...(frontMatter.entry_type ? { entry_type: frontMatter.entry_type } : {}),
|
|
110
|
+
tags: frontMatter.tags.length > 0 ? frontMatter.tags : [],
|
|
111
|
+
category: frontMatter.category,
|
|
112
|
+
importance: frontMatter.importance,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Stringify YAML with specific options for consistent formatting
|
|
116
|
+
const yamlString = stringifyYaml(yamlData, {
|
|
117
|
+
indent: 2,
|
|
118
|
+
defaultKeyType: 'PLAIN',
|
|
119
|
+
defaultStringType: 'QUOTE_DOUBLE',
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Build the complete markdown
|
|
123
|
+
const parts: string[] = ['---', yamlString.trim(), '---', ''];
|
|
124
|
+
|
|
125
|
+
// Add title if provided
|
|
126
|
+
if (title) {
|
|
127
|
+
parts.push(`# ${title}`, '');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Add content if provided
|
|
131
|
+
if (content) {
|
|
132
|
+
parts.push(content);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Ensure content ends with a single newline
|
|
136
|
+
let result = parts.join('\n');
|
|
137
|
+
if (!result.endsWith('\n')) {
|
|
138
|
+
result += '\n';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Parses the markdown body to extract title and content
|
|
146
|
+
*
|
|
147
|
+
* @param body - The markdown body (after front matter)
|
|
148
|
+
* @returns Title and content
|
|
149
|
+
*/
|
|
150
|
+
function parseMarkdownBody(body: string): { title: string; content: string } {
|
|
151
|
+
const trimmed = body.trim();
|
|
152
|
+
|
|
153
|
+
if (!trimmed) {
|
|
154
|
+
return { title: '', content: '' };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Try to extract H1 title
|
|
158
|
+
const h1Match = trimmed.match(/^#\s+(.+)$/m);
|
|
159
|
+
if (h1Match) {
|
|
160
|
+
const title = h1Match[1].trim();
|
|
161
|
+
// Remove the H1 line from content
|
|
162
|
+
const content = trimmed.replace(/^#\s+.+$/m, '').trim();
|
|
163
|
+
return { title, content };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// No H1 found, treat entire body as content
|
|
167
|
+
return { title: '', content: trimmed };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Type guard to validate front matter structure
|
|
172
|
+
*
|
|
173
|
+
* @param value - The value to check
|
|
174
|
+
* @returns True if valid front matter
|
|
175
|
+
*/
|
|
176
|
+
function isValidFrontMatter(value: unknown): value is MemoryFrontMatter {
|
|
177
|
+
if (typeof value !== 'object' || value === null) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const fm = value as Record<string, unknown>;
|
|
182
|
+
|
|
183
|
+
// Check required fields
|
|
184
|
+
if (typeof fm.id !== 'string') return false;
|
|
185
|
+
if (typeof fm.created_at !== 'string') return false;
|
|
186
|
+
if (typeof fm.updated_at !== 'string') return false;
|
|
187
|
+
if (fm.session_id !== undefined && typeof fm.session_id !== 'string') return false;
|
|
188
|
+
if (fm.entry_type !== undefined && typeof fm.entry_type !== 'string') return false;
|
|
189
|
+
if (!Array.isArray(fm.tags)) return false;
|
|
190
|
+
if (typeof fm.category !== 'string') return false;
|
|
191
|
+
if (typeof fm.importance !== 'number') return false;
|
|
192
|
+
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Converts a Memory object to front matter format
|
|
198
|
+
*
|
|
199
|
+
* @param memory - The memory object
|
|
200
|
+
* @returns Memory in front matter format
|
|
201
|
+
*/
|
|
202
|
+
export function memoryToFrontMatter(memory: Memory): MemoryFrontMatter {
|
|
203
|
+
return {
|
|
204
|
+
id: memory.id,
|
|
205
|
+
created_at: memory.createdAt,
|
|
206
|
+
updated_at: memory.updatedAt,
|
|
207
|
+
session_id: memory.sessionId,
|
|
208
|
+
entry_type: memory.entryType,
|
|
209
|
+
tags: memory.tags,
|
|
210
|
+
category: memory.category,
|
|
211
|
+
importance: memory.importance,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Converts front matter format to Memory object
|
|
217
|
+
*
|
|
218
|
+
* @param frontMatter - The front matter data
|
|
219
|
+
* @param title - The memory title
|
|
220
|
+
* @param content - The memory content
|
|
221
|
+
* @returns Complete Memory object
|
|
222
|
+
*/
|
|
223
|
+
export function frontMatterToMemory(
|
|
224
|
+
frontMatter: MemoryFrontMatter,
|
|
225
|
+
title: string,
|
|
226
|
+
content: string
|
|
227
|
+
): Memory {
|
|
228
|
+
return {
|
|
229
|
+
id: frontMatter.id,
|
|
230
|
+
createdAt: frontMatter.created_at,
|
|
231
|
+
updatedAt: frontMatter.updated_at,
|
|
232
|
+
sessionId: frontMatter.session_id,
|
|
233
|
+
entryType: frontMatter.entry_type,
|
|
234
|
+
tags: frontMatter.tags,
|
|
235
|
+
category: frontMatter.category,
|
|
236
|
+
importance: frontMatter.importance,
|
|
237
|
+
title,
|
|
238
|
+
content,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Re-export slugify for convenience
|
|
243
|
+
export { slugify };
|
package/src/storage/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Storage layer exports
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export * from './frontmatter-parser.js';
|
|
6
|
-
export * from './markdown-storage.js';
|
|
1
|
+
/**
|
|
2
|
+
* Storage layer exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export * from './frontmatter-parser.js';
|
|
6
|
+
export * from './markdown-storage.js';
|